Documentation
¶
Overview ¶
Package output writes command results and errors for humans and machines.
It is the one writer of contract:cli.json-envelope v1 and the one renderer of the human error block (EPIC P7-REG decisions D7-D9). Every surface that prints a machine result (help --json, the pilot commands, main, and later MCP and HTTP) goes through it, so the envelope cannot drift.
Success envelope: {"schema_version":"1","command":"<path>","data":<value>} Error envelope: {"schema_version":"1","command":"<path>","error":<Detail>} Exactly one of data/error is present. An optional last member "meta" carries deprecation notices and warnings recorded with AddDeprecation/AddWarning and is omitted when empty. Encoding is 2-space indent, trailing newline, HTML escaping off.
Files: envelope.go (types), writer.go (Writer, EmitData, EmitError), legacy.go (EmitLegacyCompatible, ADR 0021), redact.go (error text redaction), state.go (invocation and meta process state), args.go (JSONRequestedFromArgs), render.go (RenderError).
Error text is redacted before it is written (redact.go), in the envelope and in the human block.
Layer: L0. Imports the standard library, golang.org/x/term, internal/errs, internal/ui, internal/compat and internal/observability (Redact; it imports no other cli package). It never imports cmd/, cobra or a domain package and never calls os.Exit.
Index ¶
- Constants
- func AddDeprecation(old, new, removalAt string)
- func AddWarning(msg string)
- func EmitData(w Writer, command string, data any) error
- func EmitError(w Writer, command string, err error) error
- func EmitLegacyCompatible(w Writer, command string, data any) error
- func Invocation() (command string, json bool, known bool)
- func IsolateStdout() (restore func())
- func JSONRequestedFromArgs(args []string) bool
- func RenderError(w io.Writer, err error)
- func ResetState()
- func SetInvocation(command string, json bool)
- type Deprecation
- type Envelope
- type ErrorEnvelope
- type Meta
- type Writer
Constants ¶
const LegacyEnvVar = "NSELF_JSON_LEGACY"
LegacyEnvVar restores the pre-contract bare JSON in v1.5 mode for commands that printed one (EmitLegacyCompatible only). Removal at v1.6.0.
const SchemaVersion = "1"
SchemaVersion is the envelope version, the string "1". It versions the envelope only; the shape of Data is each command's own schema.
Variables ¶
This section is empty.
Functions ¶
func AddDeprecation ¶
func AddDeprecation(old, new, removalAt string)
AddDeprecation records a deprecation notice for the envelope meta member. A notice identical to one already recorded is ignored; order of first insertion is kept.
func AddWarning ¶
func AddWarning(msg string)
AddWarning records a warning for the envelope meta member. A message already recorded is ignored; order of first insertion is kept.
func EmitData ¶
EmitData writes the v1 success envelope for command to w.Out and nothing to w.Err. data nil is written as `"data": null`. The document is built in full before anything is written, so a marshal failure writes nothing and is returned. Recorded meta notices (AddDeprecation, AddWarning) are attached.
func EmitError ¶
EmitError writes the v1 error envelope for err to w.Out, using errs.Describe for the error object, with message, cause and remediation redacted (see redactText). The envelope has no data key. A nil err is a caller bug and is returned as an error without writing a document.
func EmitLegacyCompatible ¶
EmitLegacyCompatible writes the result of a command that printed a pre-contract JSON shape (status, doctor, config show --format json).
v1.4 mode: data bare, byte-identical to ui.PrintJSON, nothing on w.Err. v1.5 mode: the v1 envelope (same as EmitData). v1.5 mode with NSELF_JSON_LEGACY=1 (or "true"): data bare as above, plus the deprecation warning once per process on w.Err. In v1.4 mode NSELF_JSON_LEGACY has no effect. EmitData and EmitError never consult it.
func Invocation ¶
Invocation returns what SetInvocation recorded. known is false when no invocation was recorded yet; callers then fall back to JSONRequestedFromArgs on the raw arguments.
func IsolateStdout ¶
func IsolateStdout() (restore func())
IsolateStdout redirects incidental stdout to stderr until restore is called. Call only in a decorator's single-threaded command body window, and defer restore in that same invocation. No goroutine may read or write os.Stdout across the window: swapping this process-global pointer is not synchronized. The first call retains the real stdout for Default; nested calls are no-ops.
func JSONRequestedFromArgs ¶
JSONRequestedFromArgs reports whether raw command-line arguments ask for JSON mode: `--json`, `--json=true` and `--json=1` are true, `--json=false` is false. Scanning stops at a `--` terminator; the last occurrence wins, as it does for a pflag bool. An unparsable value counts as false.
It exists for failures that happen before cobra resolves a command (an unknown command or flag), where Invocation has nothing recorded yet.
func RenderError ¶
RenderError writes the human form of err to w (stderr in practice).
An error that carries a code other than E400 (a *errs.CLIError or a wrapped coded sentinel) prints
Error: [CODE] message Why: <cause> Fix: <remediation> Docs: <url>
where the three indented lines appear only when non-empty. Every other error prints exactly `Error: <message>`, as main did before. Message, cause and remediation are redacted (URL credentials, tokens, e-mail, IPs; see redactText), so a plain error changes only when it carries such a value. Colour is decided from w's own terminal state (colorFor); the plain line is never coloured. A nil err writes nothing. Write errors are ignored: there is no better stream to report a failure to write the error stream.
func ResetState ¶
func ResetState()
ResetState clears the invocation, the recorded meta notices and the once-per-process legacy warning. Tests call it between cases; a host that serves many invocations in one process (MCP, HTTP) calls it between them.
func SetInvocation ¶
SetInvocation records the resolved command path (without "nself ", "" when none) and whether JSON mode is on, so a failure reported later by main knows how to render. Calling it again replaces the earlier value.
Types ¶
type Deprecation ¶
type Deprecation struct {
Old string `json:"old"`
New string `json:"new"`
RemovalAt string `json:"removal_at"`
}
Deprecation is one deprecation notice: the old invocation, its replacement and the release at which the old form is removed.
type Envelope ¶
type Envelope struct {
SchemaVersion string `json:"schema_version"`
Command string `json:"command"`
Data any `json:"data"`
Meta *Meta `json:"meta,omitempty"`
}
Envelope is the v1 success document: schema_version, command, data, then the optional meta. Data is written as null when the command's data is nil. Exported so tools/schemagen can generate the schema from it.
type ErrorEnvelope ¶
type ErrorEnvelope struct {
SchemaVersion string `json:"schema_version"`
Command string `json:"command"`
Error *errs.Detail `json:"error"`
Meta *Meta `json:"meta,omitempty"`
}
ErrorEnvelope is the v1 error document: schema_version, command, error, then the optional meta. It has no data key, so exactly one of data/error exists in any document. Exported so tools/schemagen can generate the schema.
type Meta ¶
type Meta struct {
Deprecations []Deprecation `json:"deprecations,omitempty"`
Warnings []string `json:"warnings,omitempty"`
}
Meta is the optional last member of an envelope. Both lists are omitted when empty and the whole member is omitted when both are empty.