Skip to content

feat: add experimental arf headless subcommand for terminal-free IPC operation#119

Merged
eitsupi merged 7 commits intomainfrom
feature/headless-subcommand
Mar 20, 2026
Merged

feat: add experimental arf headless subcommand for terminal-free IPC operation#119
eitsupi merged 7 commits intomainfrom
feature/headless-subcommand

Conversation

@eitsupi
Copy link
Copy Markdown
Owner

@eitsupi eitsupi commented Mar 20, 2026

Summary

  • Add arf headless subcommand that starts R + IPC server without interactive REPL (no reedline/terminal needed)
  • Add shutdown IPC method and arf ipc shutdown CLI for graceful headless termination
  • Extract RArgsBuilder to deduplicate R argument-building logic between REPL and headless modes

Motivation

Windows CI cannot run IPC tests because ConPTY's cursor::position() is incompatible with reedline. Headless mode eliminates terminal dependency entirely, enabling cross-platform IPC testing with just std::process::Command.

Test plan

  • 12 headless integration tests (all pass, no PTY required)
    • IPC eval: value, stdout, error, mixed output, sequential, multiline, visible
    • IPC send (user_input)
    • IPC status
    • IPC shutdown (graceful exit verification)
    • --vanilla flag
    • visible vs silent server output behavior
  • CLI snapshot tests updated
  • cargo clippy clean (no warnings)
  • Verify on Windows CI (primary goal of this change)

🤖 Generated with Claude Code

eitsupi and others added 6 commits March 20, 2026 02:14
Add a new `arf headless` subcommand that starts R with an IPC server
but without the interactive REPL (reedline). This enables IPC testing
on Windows CI where ConPTY cursor::position() is problematic, and
supports AI-agent-only use cases where no terminal is needed.

The headless mode:
- Initializes R with the same flags as the REPL (vanilla, no-environ, etc.)
- Starts the IPC server automatically (no --with-ipc flag needed)
- Polls for IPC requests and R events in a simple loop
- Exits on Ctrl+C

Integration tests use `arf headless` + `arf ipc eval` end-to-end,
requiring only std::process::Command (no PTY).

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The headless handler was ignoring the visible parameter, always using
silent capture. Now visible=true passes through to start_ipc_capture,
so output is written to the headless process's stdout/stderr as well
as being returned in the JSON-RPC response.

Also add test verifying visible output appears on the server side and
silent output does not.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…nput error handling

- Extract shared R argument-building logic into RArgsBuilder struct,
  used by both Cli::r_args() (REPL) and run_headless(). Eliminates
  the duplicated headless_r_args static method.
- Simplify run_headless() from 11 parameters to 4 by passing
  RArgsBuilder directly. Removes the clippy too_many_arguments allow.
- Return accepted=false from headless user_input when eval_string
  fails, so IPC clients can detect evaluation failures.

Addresses roborev review 419 findings.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add a `shutdown` JSON-RPC method that triggers graceful shutdown of
headless mode. The method is handled directly on the server thread
(no main thread round-trip needed) by setting the shared shutdown flag.

In REPL mode, shutdown returns METHOD_NOT_FOUND since the REPL has
its own exit mechanisms (:quit, Ctrl+D, q()).

Also adds `arf ipc shutdown --pid <PID>` CLI subcommand and updates
the headless help text to reference it.

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

Adds a headless execution mode to arf-console so R + the IPC server can run without a terminal/REPL, enabling cross-platform (notably Windows CI) IPC integration testing and adding a graceful shutdown path for headless sessions.

Changes:

  • Add arf headless subcommand that runs R + IPC server without reedline/terminal.
  • Add JSON-RPC shutdown method plus arf ipc shutdown client command.
  • Refactor R init argument construction into a shared RArgsBuilder, and add new headless end-to-end integration tests + updated CLI completion/help snapshots.

Reviewed changes

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

Show a summary per file
File Description
crates/arf-console/tests/headless_tests.rs New terminal-free integration tests covering headless IPC behavior, including shutdown.
crates/arf-console/src/main.rs Wires headless subcommand to a new run_headless event loop and hooks IPC shutdown + Ctrl+C.
crates/arf-console/src/cli.rs Adds Headless subcommand, ipc shutdown, and introduces RArgsBuilder for shared R arg construction.
crates/arf-console/src/ipc/mod.rs Adds headless shutdown flag + headless polling/processing path; updates capture call signature usage.
crates/arf-console/src/ipc/server.rs Implements shutdown JSON-RPC method (headless-only) handled directly on the server thread.
crates/arf-console/src/ipc/client.rs Adds cmd_shutdown for arf ipc shutdown.
crates/arf-console/src/ipc/protocol.rs Introduces ShutdownResult protocol type.
crates/arf-console/src/ipc/capture.rs Extends capture to optionally “tee” output to process stdout/stderr when visible is true.
crates/arf-console/src/snapshots/arf__cli__tests__help_long.snap Updates CLI help snapshot to include headless.
crates/arf-console/src/snapshots/arf__cli__tests__completions_*.snap Updates shell completion snapshots for headless and ipc shutdown.
crates/arf-console/Cargo.toml Adds ctrlc dependency for headless Ctrl+C handling.
Cargo.toml Adds workspace dependency entry for ctrlc.
Cargo.lock Locks ctrlc and its transitive deps.

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

- Fix headless_tests.rs module doc: "session file discovery" → actual
  stderr monitoring mechanism
- Improve cmd_shutdown error handling: treat missing/non-accepted
  result as error with non-zero exit
- Add test_ipc_shutdown_rejected_in_repl: verify shutdown returns
  METHOD_NOT_FOUND in REPL mode

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@eitsupi eitsupi changed the title feat: add arf headless subcommand for terminal-free IPC operation feat: add experimental arf headless subcommand for terminal-free IPC operation Mar 20, 2026
@eitsupi eitsupi merged commit 8d36956 into main Mar 20, 2026
10 checks passed
@eitsupi eitsupi deleted the feature/headless-subcommand branch March 20, 2026 02:59
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