Skip to content

feat(ipc): add experimental session method and arf ipc session experimental subcommand#125

Merged
eitsupi merged 11 commits intomainfrom
feature/ipc-session
Mar 21, 2026
Merged

feat(ipc): add experimental session method and arf ipc session experimental subcommand#125
eitsupi merged 11 commits intomainfrom
feature/ipc-session

Conversation

@eitsupi
Copy link
Copy Markdown
Owner

@eitsupi eitsupi commented Mar 21, 2026

Summary

  • Add a new JSON-RPC session method and arf ipc session CLI subcommand that returns structured session information as JSON
  • Returns arf-side info (version, pid, os, arch, socket path) always, plus R session info (version, platform, locale, cwd, loaded namespaces, attached packages, library paths) when R is idle
  • When R is busy or in alternate mode, returns arf-only info with r_unavailable_reason and hint fields explaining the situation and suggesting next steps (never errors)
  • Output is pretty-printed to terminals, compact JSON when piped (jq friendly)
  • JSON shape is always consistent — check r for null to determine R info availability

Design decisions

  • Named session (not status) to align with R's sessionInfo() convention and avoid confusion with the existing arf ipc status subcommand
  • Response structure inspired by ncli: always-consistent shape, degradation instead of errors, hint field for agent autonomy
  • R info collected via individual eval_string calls returning raw R values; JSON serialization handled entirely by serde_json on the Rust side (no manual escaping needed)
  • Session metadata (socket_path, started_at) cached in memory in the server thread immediately after bind (before signalling bind success), ensuring it is available before any connection can be served
  • r_unavailable_reason and hint are tailored to the specific cause (alternate mode, R busy, pending operation, timeout, etc.)
  • Motivated by feedback from an AI agent developing an R package, requesting richer context from arf ipc

Example output

# R idle — full info
$ arf ipc session
{
  "arf_version": "0.2.5",
  "pid": 12345,
  "os": "linux",
  "arch": "x86_64",
  "socket_path": "/home/user/.cache/arf/sessions/12345.sock",
  "started_at": "2026-03-21T10:00:00+09:00",
  "r": {
    "version": "4.4.1",
    "platform": "x86_64-pc-linux-gnu",
    "locale": "en_US.UTF-8",
    "cwd": "/home/user/project",
    "loaded_namespaces": ["base", "utils", "stats", ...],
    "attached_packages": ["base", "utils", ...],
    "lib_paths": ["/usr/lib/R/library"]
  },
  "r_unavailable_reason": null,
  "hint": null
}

# R busy — arf-only with explanation
$ arf ipc session
{
  "arf_version": "0.2.5",
  "pid": 12345,
  "os": "linux",
  "arch": "x86_64",
  "socket_path": "...",
  "started_at": "...",
  "r": null,
  "r_unavailable_reason": "R is busy evaluating another expression",
  "hint": "R session information will be available when R returns to the prompt. ..."
}

# Pipe to jq
$ arf ipc session | jq '.r.loaded_namespaces'

Test plan

  • cargo clippy passes
  • All existing tests pass (unit + integration)
  • Shell completion snapshots updated
  • Unit tests for session in alternate mode, R busy, pending operation, and channel failure
  • Manual test: arf ipc session with R idle returns full JSON
  • Manual test: arf ipc session while R is evaluating returns arf-only with hint
  • Manual test: arf ipc session | jq '.' outputs compact JSON (not pretty-printed)

🤖 Generated with Claude Code

eitsupi and others added 3 commits March 21, 2026 04:29
Add a new JSON-RPC `session` method and corresponding CLI subcommand
that returns structured session information as JSON, designed for AI
agents and programmatic consumers.

The response includes arf-side info (version, pid, os, arch, socket
path) which is always available, plus R session info (version, platform,
locale, cwd, loaded namespaces, attached packages, library paths) when
R is idle. When R is busy or in alternate mode, arf-only info is
returned with `r_unavailable_reason` and `hint` fields explaining the
situation and suggesting next steps.

Output is pretty-printed to terminals and compact JSON when piped,
making it suitable for `jq` filtering.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Fix R `esc` function to escape control characters (\n, \r, \t) for
  valid JSON output
- Fix R `jarr` function to return `[]` for empty vectors instead of
  `[""]`
- Handle empty server response in `cmd_session` with an error instead
  of silent success
- Replace `.unwrap()` on session result serialization with fallback
  error responses to avoid panics in recovery paths

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@eitsupi eitsupi changed the title feat(ipc): add session method and arf ipc session subcommand feat(ipc): add experimental session method and arf ipc session experimental subcommand Mar 21, 2026
@eitsupi eitsupi requested a review from Copilot March 21, 2026 05:03
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

Adds an experimental IPC session JSON-RPC method and corresponding arf ipc session CLI subcommand to return structured session information (arf metadata always, plus R session/environment details when available), and updates shell completions accordingly.

Changes:

  • Introduces session IPC method with new protocol types (SessionResult, RSessionInfo) and server dispatch handling.
  • Adds arf ipc session client command with TTY-aware pretty vs compact JSON output.
  • Updates CLI wiring and completion snapshots (bash/fish/zsh/powershell) to include the new subcommand.

Reviewed changes

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

Show a summary per file
File Description
crates/arf-console/src/main.rs Wires the new IpcAction::Session to the IPC client implementation.
crates/arf-console/src/cli.rs Adds arf ipc session subcommand and help text describing expected behavior/output.
crates/arf-console/src/ipc/client.rs Implements cmd_session and TTY-sensitive JSON formatting.
crates/arf-console/src/ipc/protocol.rs Adds protocol structs/enums for the new session method.
crates/arf-console/src/ipc/server.rs Dispatches the session method, adds fallback behavior and a shorter timeout.
crates/arf-console/src/ipc/mod.rs Implements session collection (arf-only + optional R info) and routes requests.
crates/arf-console/src/snapshots/arf__cli__tests__completions_bash.snap Updates bash completions to include ipc session.
crates/arf-console/src/snapshots/arf__cli__tests__completions_fish.snap Updates fish completions to include ipc session.
crates/arf-console/src/snapshots/arf__cli__tests__completions_zsh.snap Updates zsh completions to include ipc session.
crates/arf-console/src/snapshots/arf__cli__tests__completions_powershell.snap Updates PowerShell completions to include ipc session.

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

- Always serialize r/r_unavailable_reason/hint as null instead of
  omitting them, ensuring consistent JSON shape for consumers
- Add guard conditions in handle_request for Session: check
  r_is_at_prompt, pending operations, and alternate mode before
  attempting R info collection
- Pass context-specific reason strings to collect_session_result
  (alternate mode, main thread unavailable, timeout, etc.)
- Update CLI help text to match actual serialization behavior
- Add unit tests for session in alternate mode and channel failure

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 21, 2026 05:31
- Tailor hint messages based on the specific r_unavailable_reason
  (alternate mode, pending operation, timeout, etc.)
- Expand esc() to handle all JSON control characters (U+0000-U+001F),
  not just \n, \r, \t; remaining control chars are stripped
- Cache session metadata (socket_path, started_at) in memory at server
  startup instead of re-reading the session file on every request
- Add unit tests for handle_request Session path covering alternate
  mode, R busy, and pending operation states

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Replace manual JSON construction in R (with fragile gsub-based escaping)
with individual eval_string calls that return raw R values. Each value
is extracted on the Rust side via extract_r_string/extract_r_strings,
and the RSessionInfo struct is built directly. JSON serialization and
escaping are handled entirely by serde_json, eliminating the class of
bugs around control character escaping and empty vector serialization.

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 21, 2026 05:51
- Use blocking lock with poison recovery in current_session_meta()
  instead of try_lock with silent fallback to empty strings
- Generate started_at once in mod::start_server and pass it to
  server::start_server, ensuring the session file and in-memory
  cache always report the same timestamp

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Use unwrap_or_else(into_inner) in set_session_meta for consistency
  with the reader side and other mutex usage in this file
- Add log::debug! to eval_r_scalar/eval_r_character_vector so R
  evaluation failures are visible in debug logs instead of silently
  swallowed

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 3 comments.


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

Move set_session_meta() call from mod.rs into server::start_server(),
right after bind confirmation. This ensures session metadata is
available before the server thread can serve any request, closing the
window where a session request could return empty socket_path/started_at.

Also replace Default::default() (empty strings) with explicit
placeholder strings in current_session_meta() to make uninitialized
state clearly distinguishable.

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 2 comments.


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

eitsupi and others added 2 commits March 21, 2026 10:50
The previous fix still had a race: set_session_meta was called in the
parent thread after bind_rx.recv(), but the server thread was already
accepting connections after bind_tx.send(). Move the call into
run_server() right before bind_tx.send(Ok(())) so metadata is
guaranteed to be initialized before any request can be served.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
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 1 comment.


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

@eitsupi eitsupi merged commit cfd6a1c into main Mar 21, 2026
14 checks passed
@eitsupi eitsupi deleted the feature/ipc-session branch March 21, 2026 11:23
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