Skip to content

v2.2.3 — --json now honours the failure contract on every command

Choose a tag to compare

@n1byn1kt n1byn1kt released this 25 Jul 22:59
· 32 commits to main since this release

Closes #79.

--json on every command is a stated design decision ("CLI is the API"), but only the success half was honoured. Usage and validation errors printed human text to stderr and left stdout empty — so an agent parsing stdout, the documented machine-output channel, saw nothing at all and had only the exit code to work with.

Before

$ apitap show --json
# stdout: (nothing)
# stderr: Error: Domain required. Usage: apitap show <domain>

Now

$ apitap show --json
{
  "success": false,
  "error": "Domain required",
  "usage": "apitap show <domain>"
}

Every error exit in src/cli.ts routes through a single failCli() helper, so the shape cannot drift per command. usage is its own field rather than baked into error, and longer guidance goes in an optional hint — an agent surfacing error alone gets the defect, not a lecture.

The human-readable line still goes to stderr in both modes, so interactive use is unchanged and apitap … --json > out.json captures only the envelope.

Also fixed

A failed apitap refresh --json printed success: false but exited 0, so callers keying on the exit code read it as a success.

Notes for consumers

  • Anyone reading .error on discover/read failures still works; those envelopes gained success: false.
  • apitap serve is the one channel exception — its stdout is the MCP stdio transport, so its failure envelope goes to stderr, and the human line is suppressed there so the stream parses as JSON.
  • apitap doctor keeps exit 2 for "the run itself broke" vs 1 for "findings remain".
  • Human stderr wording changed for read, index and extension install.

1815 tests passing.

Full changelog: v2.2.2...v2.2.3