CLI --json parity across subcommands
Problem
Global --json is parsed on the root CLI, but machine-readable stdout only applies when both are true:
- The user passed
--json, and - The subcommand is listed in
COMMANDS_WITH_JSON_OUTPUT(packages/cli/src/constants/jsonoutput.ts).
If a command was missing from that set, ctx.run.json stayed false even though argv recorded the flag for config/bootstrap. Outcomes:
- Human UI still ran (banner,
logger,printCommandSummary) — including a secondkind: "summary"JSON line when summary printing assumed JSON mode, which breaksjqexpecting a single document. - Integrators saw stderr and prose instead of one
CliJsonEnvelopewithok,data,issues[],meta.
fill was a sharp example: it shares the translation pipeline with generate, but until parity work it did not opt into COMMANDS_WITH_JSON_OUTPUT, so fill --json did not behave like generate --json.
What we do
- Source of truth:
COMMANDS_WITH_JSON_OUTPUT— keep it aligned with commands that implement a primary stdout envelope (see JSON output). - Thin command
run.ts: For JSON mode, print onlystringifyEnvelope(...)(and setprocess.exitCodewhen!ok). Do not callprintCommandSummaryon the JSON path (that helper emits an extrakind: summaryline whenrun.jsonis true).cleanup --jsonis an exception only in naming: it merges footer timing intodata.summaryon the samekind: cleanupenvelope — still one stdout JSON document. - Core helpers: Prefer
run<Command>inpackages/cli/src/core/**(e.g.runFill,runGenerate,runValidate) that returnCliJsonEnvelopeand usebuildIoReadFailureEnvelope(and command-specific builders) so I/O failures still produce one JSON object on stdout (no logger-only errors for--json). - Issues: Use stable
issues[]codes (issue codes);enrichIssuesWithDocHrefsattachesdocHreffori18nprune.*codes.
Related files (non-exhaustive)
| Area | Path |
|---|---|
| Commands that emit JSON | packages/cli/src/constants/jsonoutput.ts |
Root argv / run.json | packages/cli/bin/cli.ts (preAction, COMMANDS_WITH_JSON_OUTPUT.has(cmdName)) |
Envelope + docHref | packages/cli/src/core/result/cliJson.ts, issueDocLinks.ts, ioEnvelope.ts |
| Per-command JSON path | packages/cli/src/commands/*/run.ts (e.g. fill, generate, sync, config, doctor) |
Programmatic run* | packages/cli/src/exports/namespaces/programmatic.ts, packages/cli/src/core/**/run*.ts |
See also
- JSON output (
--json) — contract and command list - Issue codes — stable
issues[]registry - Command behaviors — snapshot table
- Prompts & CLI boundaries — why
--jsonskips interactive prompts