Skip to content

feat(ipc)!: unify all subcommand output to JSON#137

Merged
eitsupi merged 12 commits intomainfrom
feat/ipc-json-output
Mar 29, 2026
Merged

feat(ipc)!: unify all subcommand output to JSON#137
eitsupi merged 12 commits intomainfrom
feat/ipc-json-output

Conversation

@eitsupi
Copy link
Copy Markdown
Owner

@eitsupi eitsupi commented Mar 29, 2026

Summary

  • Convert all arf ipc subcommands to output structured JSON (pretty-printed on terminal, compact when piped)
    • list: text table → {"sessions": [...]}
    • eval: mixed stdout/stderr → {"stdout", "stderr", "value", "error"}
    • send/shutdown: text messages → {"accepted": true}
    • session/history: unchanged (already JSON)
  • Fixed JSON schema: all fields are always present (null when not applicable), no field omission
  • Remove arf ipc status subcommand (superseded by session)
  • Add structured JSON error output to stderr with string error codes (R_BUSY, SESSION_NOT_FOUND, TRANSPORT_ERROR, etc.) and actionable hint field
  • Error JSON always includes all fields: code, message, hint, data (null when not applicable)
  • USER_IS_TYPING error includes editor buffer in error.data.buffer for AI agent awareness
  • R evaluation errors now exit 0 with error in JSON response (distinguishes IPC failures from R errors)
  • Distinct process exit codes by category: 2 (transport), 3 (session), 4 (protocol)
  • R_NOT_AT_PROMPT hint improved with actionable debugger exit instruction
  • arf ipc --help now includes a quick-start workflow example

Test plan

  • All existing integration tests updated and passing
  • cargo fmt / cargo clippy clean
  • Shell completion snapshots updated
  • Manual test: arf ipc list returns JSON {"sessions": [...]}
  • Manual test: arf ipc eval '1+1' returns {"stdout":"","stderr":"","value":"[1] 2","error":null}
  • Manual test: arf ipc eval 'stop("err")' exits 0 with {"error":"...","value":null,...}
  • Manual test: arf ipc send returns {"accepted":true}
  • Manual test: arf ipc session returns full session JSON
  • Manual test: arf ipc history returns entries JSON with all fields (null when not available)
  • Manual test: wrong PID outputs {"error":{"code":"SESSION_NOT_FOUND","hint":"...","data":null,...}} to stderr, exit 3
  • Manual test: arf ipc shutdown returns {"accepted":true}

🤖 Generated with Claude Code

eitsupi and others added 3 commits March 29, 2026 09:42
Convert all IPC client commands to output structured JSON:
- list: JSON array of sessions instead of text table
- eval: structured JSON with stdout/stderr/value/error fields
- send: JSON {accepted: bool}
- shutdown: JSON {accepted: bool}
- session/history: already JSON (no change)

Remove the `status` subcommand (superseded by `session` which
returns a superset of the same information via IPC).

Add structured error handling:
- Errors output as JSON to stderr with code/message/hint fields
- Distinct exit codes by error category (2=transport, 3=session,
  4=protocol)
- R evaluation errors are returned as normal JSON responses
  (exit 0) to distinguish from IPC failures

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Remove `arf ipc status` from docs and CHANGELOG
- Update `arf ipc list` docs with JSON output example
- Add eval/send/shutdown output format descriptions
- Document structured error format and exit codes
- Update CLI help text to describe JSON output
- Update integration tests for new JSON output:
  - R errors now exit 0 (error in JSON response)
  - send/shutdown check JSON instead of text
  - Replace ipc_status() with ipc_session()
- Update shell completion snapshots

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Address roborev 565 findings:

- Extract handle_response() helper to deduplicate the 5 identical
  response-handling blocks (error check + print result + empty check)
- Replace numeric error codes in JSON output with string identifiers
  for stable matching by consumers:
  - JSON-RPC codes: R_BUSY, R_NOT_AT_PROMPT, INPUT_ALREADY_PENDING,
    USER_IS_TYPING, PARSE_ERROR, etc.
  - Application codes: TRANSPORT_ERROR, SESSION_NOT_FOUND,
    SESSION_AMBIGUOUS, EMPTY_RESPONSE
- Merge hint_for_rpc_error() and code-to-string mapping into a
  single rpc_error_info() function
- Document all error code strings in docs/ipc.md

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@eitsupi eitsupi requested a review from Copilot March 29, 2026 09:56
@eitsupi eitsupi changed the title feat(ipc): unify all subcommand output to JSON feat(ipc)!: unify all subcommand output to JSON Mar 29, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Unifies arf ipc CLI subcommand output into structured JSON (pretty on TTY, compact when piped), adds structured JSON error output on stderr with categorized exit codes, and removes the deprecated ipc status subcommand in favor of ipc session.

Changes:

  • Convert ipc list/eval/send/shutdown outputs from human text to structured JSON.
  • Add structured JSON error output (with string error codes + hints) and introduce distinct exit code categories.
  • Remove arf ipc status and update tests, docs, changelog, and shell completion snapshots accordingly.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/ipc.md Documents JSON stdout/stderr format, error codes, exit codes, and updates subcommand docs (incl. removing status).
crates/arf-console/src/ipc/client.rs Implements JSON output for all client commands and structured JSON error handling with new exit codes.
crates/arf-console/src/cli.rs Updates CLI help text/examples to describe JSON outputs and removes Status subcommand.
crates/arf-console/src/main.rs Removes dispatch for IpcAction::Status.
crates/arf-console/tests/headless_tests.rs Updates integration tests to use ipc session and validate JSON outputs / new eval error semantics.
crates/arf-console/src/snapshots/completions.snap Updates shell completion snapshots (removes status, updates help text).
CHANGELOG.md Notes breaking JSON output changes, new exit codes, and removal of ipc status.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot review:
- Distinguish protocol errors (malformed JSON-RPC response) from
  transport errors (connection refused, timeout) in send_request(),
  using appropriate exit codes and error codes
- Fix eval output format docs: value/error are omitted when not
  applicable (not present as null), clarify silent mode behavior

Agent review (bd task 31tr):
1. cmd_list: use serde_json::to_value(SessionInfo) instead of manual
   JSON construction to prevent field sync issues
2. cmd_* return types: change from Result<()> to () since all error
   paths use exit_error (never return Err)
3. exit_error testability: add doc comment explaining the design
   trade-off (process::exit prevents in-process testing; covered by
   integration tests)
4. Deduplicate expect messages: extract format_json() helper, use
   distinct message prefix
5. Remove misleading "exit code 1 reserved" comment
6. EMPTY_RESPONSE: clarify message indicates possible server bug
7. Test JSON parse errors: add parse_ipc_json() helper that includes
   stdout/stderr in panic message for debugging

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Use e.chain().any() to find serde_json::Error through anyhow's
  context wrapper, replacing fragile string matching
- Fix format_json expect message to match function name

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

eitsupi and others added 2 commits March 29, 2026 10:24
When an IPC request is rejected because the user is typing, include
the current editor buffer content in the error message. This lets
AI agents see what the user is typing and decide whether to retry
or abort.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- CLI help: value/error fields are optional (omitted), not nullable
- CHANGELOG: clarify error JSON shape as {"error": {"code", ...}}

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

eitsupi and others added 2 commits March 29, 2026 10:42
- Move editor buffer from error message to JSON-RPC error.data field
  ({"buffer": "..."}) to keep message stable for pattern matching
- Add IpcResponse::error() and error_with_data() constructors, use
  throughout to avoid struct literal repetition
- Thread error.data through server to JsonRpcResponse
- Replace cmd_list expect with exit_error for structured error output
- Add integration tests for exit codes and structured JSON errors:
  - SESSION_NOT_FOUND (exit 3) with JSON stderr
  - list always returns valid JSON (even with no sessions)
  - Protocol error / timeout (exit 4) with JSON stderr

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Remove skip_serializing_if from all public-facing types (EvaluateResult,
HistoryEntry, HistoryResult) so that all fields are always present with
null values instead of being omitted. This gives consumers a predictable
schema they can rely on without checking field existence.

Also:
- Always include hint and data fields in error JSON output (null when
  not applicable)
- Pass through JSON-RPC error.data to client error output (e.g.
  USER_IS_TYPING buffer)
- Improve R_NOT_AT_PROMPT hint with actionable debugger exit instruction
- Add workflow quick-start to arf ipc --help

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Cap editor buffer in USER_IS_TYPING error data at 1024 characters to
  prevent excessively large payloads. Include buffer_truncated and
  buffer_original_length fields for completeness.
- Clarify docs/CHANGELOG distinction between transport-level timeouts
  (exit 2, socket/pipe failures) and server-side request timeouts from
  --timeout (exit 4, JSON-RPC error).
- Document USER_IS_TYPING data fields in ipc.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Fix module doc comment to include data field in error format
- Add history_session_id to list help text and docs example
- Use runtime-derived PID in session_not_found test to avoid flakiness

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@eitsupi eitsupi merged commit 1cec3d1 into main Mar 29, 2026
10 checks passed
@eitsupi eitsupi deleted the feat/ipc-json-output branch March 29, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants