feat(cli): exit-code map + structured JSON error envelopes#1583
Conversation
|
@claude review |
|
Claude finished @cliffhall's task in 2m 37s —— View job Review: CLI exit-code map + structured JSON error envelopes
Nice, focused Wave-1 foundation. The 🟠 Main concern: numeric
|
Address @claude review of #1583: - statusOf() now only treats a numeric `.code` as an HTTP status when it is in the 100-599 range, so an MCP SDK McpError JSON-RPC code (e.g. -32601 MethodNotFound) is no longer leaked into the envelope `status` or misclassified as AUTH_REQUIRED (it falls back to USAGE). - causeOf() now carries a depth cap (MAX_CAUSE_DEPTH) so a cyclic/ self-referential `error.cause` chain terminates instead of recursing infinitely. - Add tests for both: a -32601 McpError-shaped error (status undefined, exit USAGE) and a self-referential cause chain (finite string). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S3fTN8H3R8YV4yUGvZjYnX
|
Thanks for the review — addressed in fa5514a. 🟠 Main concern — numeric 🟡 Note 3 — 🟡 Note 1 — 🟡 Note 2 — auth-message regex over-match: keeping as-is. Agreed it's a broad substring match, but as you noted it's acceptable given the intent: for an auth-focused CLI, biasing an ambiguous 🟡 Note 4 — double stderr on usage errors: out of scope here. This pre-dates the PR (commander writes its own usage text before throwing) and isn't a regression; the trailing JSON line remains the parseable one for |
|
@claude review |
|
Claude finished @cliffhall's task in 58s —— View job Re-review: fixes in
|
|
📋 Smoke test & AGENTS.md audit for this PR: #1564 (comment) (posted on the linked issue #1564). |
…ase change; tree unchanged)
Closes #1564
Summary
Wave 1 of the PR #1510 decomposition (tracking issue #1579). Gives the CLI a stable, machine-readable failure surface so a programmatic driver (CI, scripts, agents) can branch on why the CLI failed without regex-scraping prose stderr.
EXIT_CODES):0ok ·1usage ·2no-app ·3auth-required ·4unreachable ·5tool-error.ErrorEnvelopeinterface — one JSON line on stderr:{"error":{code,message,cause?,status?,url?}}.CliExitCodeError— thrown by the CLI to request a specific exit code up front, carrying a partial envelope thatclassifyError()fills in.classifyError()— heuristics over HTTP status (.status/.response.status/ numeric SDK.code), anError.causechain, and message/cause patterns (401/403/WWW-Authenticate/OAuth → auth;ENOTFOUND/ECONNREFUSED/fetch failed/… → unreachable). Unit-testable in isolation.formatErrorOutput()/handleError()— single source of truth for{exitCode, stderr}; the binary sink and the in-process test runner both call it, so tests observe exactly what the real binary emits.cli-runnertest helper now mirrors the binary viaformatErrorOutput(dropping the redundantconsole.error/console.warnoverrides, since those route throughprocess.stderr.write).clients/cli/README.md.Kept well-typed and dependency-free for reuse — this is a Wave 3 dependency and the foundation for the CLI lane (
--app-info→ exit 2, stored-auth → exit 3,--format json).Testing
clients/clinpm run validate— 127 tests pass (format:check + lint + build + test).clients/clinpm run test:coverage— gate passes;error-handler.ts100% stmts/funcs/lines, 94.44% branches (all ≥ 90).🤖 Generated with Claude Code
https://claude.ai/code/session_01S3fTN8H3R8YV4yUGvZjYnX