Commit graph

13 commits

Author SHA1 Message Date
jedarden
ab1e9d6d64 Fix clippy warnings: upper_case_acronyms and manual_range_contains
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:10:43 -04:00
jedarden
59e170ed03 Implement Phase 6: Stop Poller (bf-64s)
Add src/poller.rs with FIFO O_NONBLOCK open (read-end + keeper write-end),
Stop hook JSON payload parsing, transcript path derivation via cwd slug,
and StopInfo resolution. Wire poller into EventLoop via add_fifo_fd() which
was already present in event_loop.rs from Phase 3.

Update mock-claude to emit proper JSON Stop payloads (with and without
transcript_path via MOCK_OMIT_TRANSCRIPT_PATH=1) and update the pty_integration
assertion to match.

Tests test_stop_hook_fires and test_missing_transcript_path_derived both pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:05:14 -04:00
jedarden
71a4cb9f96 Implement large-prompt file relay in startup.rs (bf-1cx)
Prompts exceeding INLINE_PROMPT_MAX (32 KB) are written to a NamedTempFile
and a shell $(< path) read command is injected via bracketed paste instead
of the raw bytes, avoiding PTY pipe-buffer saturation.

Adds four unit tests: threshold boundary (inline), threshold+1 (file relay),
temp-file content verification, and end-to-end state-machine coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 10:26:16 -04:00
jedarden
adaf26e523 Add idle-gap detection to startup.rs (bf-54m)
After trust-dismiss fires, the post-dismiss wait is now an idle-gap:
injection fires only after idle_gap_ms of uninterrupted silence.
Any PTY output chunk resets the gap via last_output_at, preventing
premature injection during TUI redraws after the dismiss CR.

- Rename POST_DISMISS_IDLE_MS → DEFAULT_POST_DISMISS_IDLE_MS (pub const)
- Add idle_gap_ms field to StartupSeq; expose via with_idle_gap() ctor
- TrustDismissed timer now uses last_output_at instead of trust_dismiss_at
- Reset last_output_at when entering TrustDismissed via idle-fallback path
- Add three unit tests: resets on output, fires after silence, no double-fire

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 10:10:46 -04:00
jedarden
edd9470038 Add startup.rs: trust-keyword scanner with test_trust_dialog_* integration tests (Phase 5)
Implements StartupSeq with scan_line() that detects 2+ trust keywords
("trust", "Allow", "continue", "folder", "permission", "proceed") on a
PTY output line and returns CR to dismiss the dialog.  Includes idle
fallback (0.8 s after 200+ bytes) and hard timeout (45 s / <200 bytes →
HardTimeout).  Phase 2 injects the prompt via bracketed paste after a
2 s post-dismiss idle.

11 test_trust_dialog_* integration tests cover keyword match, threshold,
case sensitivity, chunk-boundary assembly, one-shot dismiss, and CR- vs
LF-terminated lines.  12 unit tests in startup::tests cover scan_line
and feed() in isolation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 10:05:27 -04:00
jedarden
7b64f5b340 Add terminal.rs: probe scanner with response table, dedup bitmask, unknown-probe passthrough (Phase 4)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:25:54 -04:00
jedarden
78b06ed27f Add event_loop.rs: poll() loop with dynamic fd set and EIO detection (Phase 3)
Implements EventLoop with master_fd + self_pipe_read as the initial 2-fd
pollfd Vec. add_fifo_fd() pushes the stop FIFO fd at PROMPT_INJECTED. run()
dispatches PTY output chunks to a callback and returns ExitReason on child
exit (EIO), FIFO payload, or self-pipe interrupt. Both required tests pass:
test_event_loop_reads_pty_output and test_event_loop_detects_child_exit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:18:54 -04:00
jedarden
17c35f40a7 Add mock-claude fixture, test_pty_spawns_tty integration test, and hook module export
- test-fixtures/mock-claude: implement mock binary that writes 'stop' to FIFO then checks isatty(stdin), exiting 0 on TTY
- tests/pty_integration.rs: test_pty_spawns_tty uses HookInstaller + PtySpawner to verify controlling TTY is established
- src/lib.rs: expose hook module publicly
- Cargo.lock: add libc dependency for mock-claude

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 08:56:36 -04:00
jedarden
a1e74b59fa Add signal forwarding, I/O relay, and wait to PtySpawner
- Install a SIGWINCH handler that sets a static AtomicBool; the relay loop
  re-issues TIOCSWINSZ on the master fd each time it fires.
- relay() poll-loops over the master fd and stdin, copying master output to
  stdout and stdin input to the master fd, with 100 ms timeout so SIGWINCH
  is handled promptly on EINTR.
- Loop exits on EIO/EOF/POLLHUP from the master fd (slave side closed).
- waitpid() at the end of relay() surfaces the child exit code (or
  128+signum for signal termination).
- New tests: master_fd_carries_child_stdout (acceptance criterion),
  relay_echo_exits_zero_and_produces_output, relay_surfaces_nonzero_exit_code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:47:09 -04:00
jedarden
ffbe0f298e Add execvp and TIOCSWINSZ to PtySpawner::spawn
Change spawn() to spawn(cmd, args): on the parent side set the PTY
window size via TIOCSWINSZ mirroring stdin or defaulting to 80x24; on
the child side call execvp with the given command after login_tty.
Update the test to exercise /bin/true through the full exec path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:42:00 -04:00
jedarden
1ff77156db Add hook.rs and update bead state for Phase 2 completion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:38:45 -04:00
jedarden
4a38e8f6a3 Phase 2: implement PTY open and fork in pty.rs
Adds PtySpawner struct that calls openpty() for master/slave fds, forks,
and runs login_tty on the child side before it exits. Fixes nix feature
flag (pty module is gated by `term`, not a `pty` feature in nix 0.29).
Adds mock-claude workspace stub so the workspace resolves cleanly.

Unit test: fork_and_login_tty_does_not_panic passes (child exits 0).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:38:14 -04:00
jedarden
6f67cd5b00 Phase 1: crate scaffold with CLI, config, and error types
Adds Cargo.toml with pinned deps (clap, anyhow, serde, thiserror,
toml), src/{main,lib,cli,config,error}.rs. --version prints
"claude-print <ver> (wrapping claude <ver>)". All lib tests pass.
Builds clean for x86_64-unknown-linux-musl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:00:19 -04:00