Documentation
¶
Overview ¶
Package cli is PayCLI's command tree and the only place in the program that is allowed to see the process itself.
Everything ambient — argv, the environment, the three standard streams, the wall clock, the HTTP transport and the on-disk directory layout — enters through App and is carried to every command by Runtime. That is what makes whole-command golden tests possible in-process (§17.3): a test builds an App over bytes.Buffers and a fixture server's RoundTripper and asserts on the captured stdout, stderr and the returned exit code.
§3.1 makes this a CI-enforced rule: app.go is the only file outside cmd/ that may reference os.Stdout, os.Stderr, os.Stdin, os.Args, os.Getenv, os.Exit or time.Now.
Index ¶
- Constants
- Variables
- func CompleteCollections(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
- func CompleteEntities(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
- func CompleteEnum(values ...string) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
- func CompleteFieldPaths(rt *Runtime, mode FieldMode) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
- func CompleteGlobals(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
- func CompleteProfiles(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
- func Handle(rt *Runtime, name string, h Handler) func(*cobra.Command, []string) error
- func Main() int
- func Register(f factory)
- func Run(ctx context.Context, app App) (code int)
- func SetHelp(cmd *cobra.Command, h *Help)
- func UpdateHint(statePath, currentVersion string) string
- func WhereOperatorAliases() []string
- type App
- type ArgSpec
- type Check
- type CommandSpec
- type Deps
- type DiscoverOptions
- type Example
- type FieldMode
- type FlagInfo
- type FlagSpec
- type Handler
- type Help
- type Mistake
- type OutputSpec
- type Runtime
- func (rt *Runtime) Audit() *audit.Logger
- func (rt *Runtime) Cache() *cache.Store
- func (rt *Runtime) CachedManifest() (*discovery.Manifest, bool)
- func (rt *Runtime) CachedShard(slug string, kind cache.EntityKind) (*discovery.Shard, bool)
- func (rt *Runtime) Client(ctx context.Context) (*payload.Client, error)
- func (rt *Runtime) Confirmer() *safety.Confirmer
- func (rt *Runtime) Credential(ctx context.Context) (*secret.Credential, error)
- func (rt *Runtime) Discovery(ctx context.Context) (*discovery.Manifest, error)
- func (rt *Runtime) Elapsed() time.Duration
- func (rt *Runtime) Meta() output.Meta
- func (rt *Runtime) NoRaw() bool
- func (rt *Runtime) Now() time.Time
- func (rt *Runtime) RunDiscovery(ctx context.Context, opts DiscoverOptions) (*discovery.Manifest, error)
- func (rt *Runtime) Scope() (cache.Scope, error)
- func (rt *Runtime) SecretStore() *secret.Store
- func (rt *Runtime) Secrets() []string
- func (rt *Runtime) Session() *cache.Session
- func (rt *Runtime) SetDataBytes(n int64)
- func (rt *Runtime) Shard(ctx context.Context, slug string, kind cache.EntityKind) (*discovery.Shard, bool)
- func (rt *Runtime) Stderr() io.Writer
- func (rt *Runtime) Stdin() io.Reader
- func (rt *Runtime) Warn(w ...output.Warning)
- func (rt *Runtime) Warnf(code, format string, args ...any)
- func (rt *Runtime) Warnings() []output.Warning
Constants ¶
const ( CheckOK = "ok" CheckWarn = "warn" CheckFail = "fail" CheckUnknown = "unknown" CheckSkipped = "skipped" )
Check statuses. `unknown` is a first-class answer: a fact PayCLI could not establish is never reported as a pass or a failure (§7.6).
const ( // DetailCap is how many per-collection detail entries the default tier // emits. The SLUG LIST IS NEVER TRUNCATED — data.collection_slugs always // holds every slug, because it is the single most load-bearing thing this // command returns. DetailCap = 40 // DefaultMaxBytes is --max-bytes' default: above it, --full refuses. DefaultMaxBytes = 400 << 10 )
§18's tiers.
const ( GroupDiscovery = "discovery" GroupRead = "read" GroupWrite = "write" GroupFiles = "files" GroupAdmin = "admin" GroupOther = "other" )
Command groups, so `pay --help` reads as a map of the tool rather than an alphabetical wall. A command that sets no GroupID lands in "other".
const CompletionBudget = 100 * time.Millisecond
CompletionBudget is §9.9's hard limit. A shell that hangs on TAB is worse than one that suggests nothing, so every completion function checks the budget before and after the one cache read it is allowed to make.
Variables ¶
var BulkExitCodes = []int{ apierr.ExitOK, apierr.ExitInternal, apierr.ExitAuth, apierr.ExitThrottled, apierr.ExitNotFound, apierr.ExitValidation, apierr.ExitNetwork, apierr.ExitPartial, apierr.ExitAccessDenied, apierr.ExitConfig, apierr.ExitCapability, apierr.ExitConfirmationRequired, }
BulkExitCodes adds §12.5's partial commit and §12's confirmation gate. 7 is the one an agent must never auto-retry.
var DestructiveExitCodes = []int{ apierr.ExitOK, apierr.ExitInternal, apierr.ExitAuth, apierr.ExitThrottled, apierr.ExitNotFound, apierr.ExitValidation, apierr.ExitNetwork, apierr.ExitAccessDenied, apierr.ExitConfig, apierr.ExitCapability, apierr.ExitConfirmationRequired, }
DestructiveExitCodes adds §12's confirmation gate to a single-document write.
var ReadExitCodes = []int{ apierr.ExitOK, apierr.ExitInternal, apierr.ExitAuth, apierr.ExitThrottled, apierr.ExitNotFound, apierr.ExitValidation, apierr.ExitNetwork, apierr.ExitAccessDenied, apierr.ExitConfig, apierr.ExitCapability, }
ReadExitCodes is what any command that reads from the server can return.
var WriteExitCodes = ReadExitCodes
WriteExitCodes is ReadExitCodes for a single-document write: same failures, and nothing bulk-specific.
Functions ¶
func CompleteCollections ¶
func CompleteCollections(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
CompleteCollections completes a collection slug from the cached index.
func CompleteEntities ¶
func CompleteEntities(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
CompleteEntities completes a collection OR global slug, for `pay describe`.
func CompleteEnum ¶
func CompleteEnum(values ...string) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
CompleteEnum completes a fixed value set, for --output and friends.
func CompleteFieldPaths ¶
func CompleteFieldPaths(rt *Runtime, mode FieldMode) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
CompleteFieldPaths completes a field path for the collection already on the command line. It decodes at most the single shard for that collection (§9.9); a missing or generation-mismatched shard yields nothing.
func CompleteGlobals ¶
func CompleteGlobals(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
CompleteGlobals completes a global slug from the cached index.
func CompleteProfiles ¶
func CompleteProfiles(rt *Runtime) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)
CompleteProfiles completes --profile from the two config files. It reads no credentials and never touches the keychain.
func Handle ¶
Handle adapts a Handler to cobra's RunE. `name` is the envelope's `command` field and the audit log's command name; it is the space-joined command path without the "pay" prefix ("auth login", "find").
Handle is the ONLY place a command's output reaches a stream. A Handler that returns (nil, nil) is a programming error and surfaces as exit 1.
func Main ¶
func Main() int
Main is the entry point cmd/pay/main.go calls. It returns the exit status instead of taking it, so nothing below cmd/ ever calls os.Exit.
func Register ¶
func Register(f factory)
Register adds a subcommand factory to the root tree.
Every command file calls this from an init(), so root.go never has to name the individual commands and several agents can add commands to the same package without editing a shared switch. Registration order does not matter: the tree is sorted by command name before assembly, which makes `pay --help` and the alias-resolution order deterministic.
func Run ¶
Run executes one PayCLI invocation and returns its exit status. It never panics out to the caller: a panic in a command is converted to exit 1 with an `internal` envelope, because an agent parsing stdout must always get an envelope.
func UpdateHint ¶
UpdateHint is the one-line notice `pay version` and `pay doctor` print when a newer release was recorded by an earlier --check. It never performs I/O beyond reading the state file, so it is safe on every command path.
func WhereOperatorAliases ¶
func WhereOperatorAliases() []string
WhereOperatorAliases is the flat alias list §10.4 puts on the --where flag.
Types ¶
type App ¶
type App struct {
// Args is os.Args[1:] — the program name is not included.
Args []string
// Env is os.Environ()'s "NAME=value" form.
Env []string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// Now is the only clock the program has. Tests pin it.
Now func() time.Time
// HTTP replaces the transport internal/payload would otherwise build. A
// test points it at an httptest.Server; production leaves it nil.
HTTP http.RoundTripper
// Dirs overrides the §4.1 directory layout wholesale. A zero value is
// derived from Env.
Dirs config.Paths
// WorkDir is the directory project discovery (§4.3) walks up from.
WorkDir string
// Terminal facts. False is the safe answer: PayCLI never changes output
// shape based on a TTY (§10), it only uses these for the interactive
// confirmation prompt (§12.2) and the "you typed a key on a terminal"
// warning (§5.1 step 3).
StdinIsTTY bool
StdoutIsTTY bool
StderrIsTTY bool
// NoSignals disables the SIGINT/SIGTERM handler. Tests set it; the
// in-process handler would otherwise leak across `go test`.
NoSignals bool
}
App is the injected process surface. A zero value is unusable; Run substitutes inert defaults (io.Discard, a fixed clock) for anything left nil so that a malformed App can never panic mid-command.
type ArgSpec ¶
type ArgSpec struct {
Name string `json:"name"`
Required bool `json:"required"`
Type string `json:"type"`
ValuesFrom string `json:"values_from,omitempty"`
Values []string `json:"values,omitempty"`
Example string `json:"example,omitempty"`
}
ArgSpec documents one positional argument (§10.4).
type Check ¶
type Check struct {
Name string `json:"name"`
Status string `json:"status"`
Detail string `json:"detail"`
Hint string `json:"hint,omitempty"`
Value any `json:"value,omitempty"`
}
Check is one diagnostic line.
type CommandSpec ¶
type CommandSpec struct {
Path []string `json:"path"`
Short string `json:"short"`
Args []ArgSpec `json:"args"`
Flags []FlagSpec `json:"flags"`
Subcommands []string `json:"subcommands,omitempty"`
Output OutputSpec `json:"output"`
ExitCodes []int `json:"exit_codes"`
Examples []Example `json:"examples"`
Mistakes []Mistake `json:"common_mistakes,omitempty"`
SeeAlso []string `json:"see_also,omitempty"`
}
CommandSpec is §10.4's machine-readable help.
type Deps ¶
type Deps struct {
// RT is the shared runtime.
RT *Runtime
// Client is the configured Payload REST client.
Client *payload.Client
// Manifest is the discovery index, or nil when discovery could not answer.
// A nil manifest disables every client-side rejection rather than inventing
// one, which is §9.3's tri-state rule applied at the top.
Manifest *discovery.Manifest
// FetchURL downloads a remote upload source (§13). It is a field so unit
// tests never reach the network.
FetchURL func(ctx context.Context, rawurl string) (body io.ReadCloser, contentType string, size int64, err error)
// contains filtered or unexported fields
}
Deps is one data command's resolved dependencies.
type DiscoverOptions ¶
DiscoverOptions are the knobs `pay discover` exposes. The zero value is what every other command uses.
type FieldMode ¶
type FieldMode string
FieldMode selects which field-path projection a completion offers.
const ( // FieldQueryable completes --where / --or paths. FieldQueryable FieldMode = "queryable" // FieldSortable completes --sort. FieldSortable FieldMode = "sortable" // FieldSelectable completes --select / --select-exclude. FieldSelectable FieldMode = "selectable" // FieldDate completes --date-field. FieldDate FieldMode = "date" )
type FlagInfo ¶
type FlagInfo struct {
Grammar string `json:"grammar,omitempty"`
Operators []string `json:"operators,omitempty"`
Values []string `json:"values,omitempty"`
Repeatable bool `json:"repeatable,omitempty"`
Min *int `json:"min,omitempty"`
Max *int `json:"max,omitempty"`
// Note is printed in the FLAGS section, e.g. "no-op on this project:
// localization is disabled".
Note string `json:"note,omitempty"`
}
FlagInfo is the §10.4 detail for one flag.
type FlagSpec ¶
type FlagSpec struct {
Name string `json:"name"`
Shorthand string `json:"shorthand,omitempty"`
Type string `json:"type"`
Repeatable bool `json:"repeatable"`
Default any `json:"default"`
Usage string `json:"usage"`
Grammar string `json:"grammar,omitempty"`
Operators []string `json:"operators,omitempty"`
Values []string `json:"values,omitempty"`
Min *int `json:"min,omitempty"`
Max *int `json:"max,omitempty"`
}
FlagSpec is one flag of a CommandSpec.
type Handler ¶
Handler is the shape every PayCLI command implements. Returning an envelope and an error is deliberate: the envelope is rendered when err is nil, and the error is normalised into an error envelope otherwise, so no command has to know about exit codes, --path, --output or meta.
type Help ¶
type Help struct {
// Synopsis lines are printed verbatim under SYNOPSIS, metavariables and
// all.
Synopsis []string
// Long is optional prose printed under the one-line Short.
Long string
// Discovered renders section 3 for this command. Returning nil falls back
// to the shared collection inventory when Collections is true.
Discovered func(rt *Runtime, m *discovery.Manifest) []string
// Collections asks for the shared "collections in this project" block in
// section 3.
Collections bool
// Globals asks for the globals inventory in section 3.
Globals bool
// Where and Sort switch on sections 4 and 5. They belong on any command
// that accepts --where or --sort.
Where bool
Sort bool
// Args documents the positional arguments for §10.4.
Args []ArgSpec
// FlagInfo adds §10.4 detail (grammar, operators, bounds) that pflag
// cannot express, keyed by flag name.
FlagInfo map[string]FlagInfo
Output OutputSpec
ExitCodes []int
Examples []Example
Mistakes []Mistake
SeeAlso []string
// Notes are extra bullet lines printed after FLAGS. Use them for the
// "this flag is a no-op on this project" callouts §10.5 item 6 requires.
Notes []string
}
Help is the §10.5 model for one command's help text. Every command supplies the parts that cannot be derived from its cobra definition; the flag table, the command path and the subcommand list are read off cobra itself so the two can never drift.
A command with no Help still renders all eleven sections — it simply has no examples and no mistakes to show. That is a visible hole rather than a silent one, which is the point.
type Mistake ¶
Mistake is one numbered anti-pattern and its correction. §10.5's hard rule: every "you cannot X" is followed by "do Y instead", which is why Right is not optional.
type OutputSpec ¶
type OutputSpec struct {
Kind output.DataKind `json:"data_kind"`
Paginated bool `json:"paginated,omitempty"`
Skeleton string `json:"skeleton,omitempty"`
}
OutputSpec is §10.4's output block.
type Runtime ¶
type Runtime struct {
App App
// Env is the environment snapshot every layer reads from.
Env config.Env
// Paths is the resolved §4.1 layout.
Paths config.Paths
// Project is the detected Payload project (§4.3), never nil.
Project *config.Project
// UserFile and ProjectFile are the two config layers, never nil.
UserFile *config.File
ProjectFile *config.File
// Cfg is the resolved configuration. Nil until the persistent pre-run has
// executed, which is why every command handler receives it already set.
Cfg *config.Resolved
// Command is the dotted command path of the command being run ("auth
// login"), used for envelope.command and the audit log.
Command string
// Out renders envelopes. Commands must not write to App.Stdout directly.
Out *output.Writer
// Log is the structured logger; never nil.
Log *slog.Logger
// Flags is the parsed root flag state, exposed so a command can tell
// "flag not given" from "flag given the default value".
Flags *rootFlags
// contains filtered or unexported fields
}
Runtime is the per-invocation world every command is handed. It owns the resolved configuration, the lazily built client, the cache session, the logger, the audit log and the renderer.
Everything expensive is lazy and memoised: `pay version` must work on a machine with no config, no network and no cache, so a Runtime that never resolves a credential never touches the keychain.
func (*Runtime) Cache ¶
Cache is the discovery cache store. It is permanently disabled (every read a miss, every write a no-op) under --no-cache.
func (*Runtime) CachedManifest ¶
CachedManifest returns the discovery index from disk without any possibility of a network call. Help text (§10.5) and shell completion (§9.9) use this and nothing else: both must render instantly on a cold cache rather than block.
func (*Runtime) CachedShard ¶
CachedShard is the offline form used by completion and help, which may never trigger discovery.
func (*Runtime) Client ¶
Client builds the Payload client for the resolved profile and credential.
It never hands out a client whose auth-collection slug is still §7.0's "auto" placeholder: in api-key mode the slug is part of the Authorization header, and a wrong slug answers HTTP 200 with the anonymous view rather than an error. resolveAuthCollection runs the §7.0 ladder (configured → cached → Stage -1) before the client escapes this function.
func (*Runtime) Credential ¶
Credential resolves §5.1's chain once per invocation.
func (*Runtime) Discovery ¶
Discovery returns the discovery index, running §7's pipeline when the cache cannot answer. It is memoised per invocation.
func (*Runtime) RunDiscovery ¶
func (rt *Runtime) RunDiscovery(ctx context.Context, opts DiscoverOptions) (*discovery.Manifest, error)
RunDiscovery executes §7's pipeline and persists the result (§8.7).
func (*Runtime) SecretStore ¶
SecretStore is the credentials.json + keychain store for this profile set.
func (*Runtime) Secrets ¶
Secrets returns the literal credential values that must be scrubbed from every log line and every rendered byte (§5.3). It never resolves a credential on its own.
func (*Runtime) SetDataBytes ¶
SetDataBytes makes meta.bytes report the size of the rendered payload rather than the bytes read from the network. `pay explain` is the case §18 names.
func (*Runtime) Shard ¶
func (rt *Runtime) Shard(ctx context.Context, slug string, kind cache.EntityKind) (*discovery.Shard, bool)
Shard returns one entity's field schema, decoding it from the cache when the current invocation did not produce it.
func (*Runtime) Warn ¶
Warn records an envelope warning. Duplicates (same code and message) are collapsed so a fan-out cannot emit the same advice a hundred times.
Source Files
¶
- access.go
- app.go
- audit.go
- auth.go
- cache.go
- can.go
- collections.go
- complete.go
- completion.go
- config.go
- count.go
- create.go
- delete.go
- describe.go
- discover.go
- doctor.go
- download.go
- duplicate.go
- explain.go
- find.go
- get.go
- globals.go
- help.go
- opmemo.go
- profile.go
- publish.go
- raw.go
- restore.go
- root.go
- selfupdate.go
- skills.go
- update.go
- upload.go
- version.go
- versions.go
- whoami.go