Summary
--output json is the contract a machine consumer (CI pipeline, coding agent) relies on: on failure, parse stderr as a JSON error envelope. That contract holds for anything that reaches a command action, but not for Commander's own argument-parse errors — unknown command, unknown option, missing/excess argument — which are written as plain text even when --output json is set.
A single malformed invocation therefore crashes any consumer doing JSON.parse(stderr).
Reproduction
$ testsprite --output json frobnicate
error: unknown command 'frobnicate' # plain text, not JSON
$ testsprite --output json project list --bogus
error: unknown option '--bogus' # plain text, not JSON
$ testsprite --output json test code get
error: missing required argument 'test-id' # plain text, not JSON
Contrast with an error that reaches the action, which already does the right thing:
$ testsprite --output json test rerun
{ "error": { "code": "VALIDATION_ERROR", ... } }
All exit with code 5 (correct), but the format is inconsistent.
Suggested fix
In JSON mode, suppress Commander's plain-text error write and emit a structured VALIDATION_ERROR envelope (exit 5) from the central catch instead, carrying the message and the Commander error code. The --output mode must be resolved from argv (a parse error can be thrown before Commander binds the global flag), and the output config applied to every command in the tree (subcommands don't inherit the root's). Text mode, the "Did you mean …?" hints, and --help/--version (exit 0, human-readable) stay unchanged.
I have a PR ready for this.
Summary
--output jsonis the contract a machine consumer (CI pipeline, coding agent) relies on: on failure, parsestderras a JSON error envelope. That contract holds for anything that reaches a command action, but not for Commander's own argument-parse errors — unknown command, unknown option, missing/excess argument — which are written as plain text even when--output jsonis set.A single malformed invocation therefore crashes any consumer doing
JSON.parse(stderr).Reproduction
Contrast with an error that reaches the action, which already does the right thing:
All exit with code 5 (correct), but the format is inconsistent.
Suggested fix
In JSON mode, suppress Commander's plain-text error write and emit a structured
VALIDATION_ERRORenvelope (exit 5) from the central catch instead, carrying the message and the Commander error code. The--outputmode must be resolved from argv (a parse error can be thrown before Commander binds the global flag), and the output config applied to every command in the tree (subcommands don't inherit the root's). Text mode, the "Did you mean …?" hints, and--help/--version(exit 0, human-readable) stay unchanged.I have a PR ready for this.