Files
boocode/openspec/changes/pty-exit-notifications/specs/pty-exit-notification/spec.md
indifferentketchup b18de2a331 chore: snapshot working tree - pty_exited notifications + in-flight inference WIP
feat(booterm): structured pty_exited WS notifications. Plan-validated, impl-validated, code-reviewed green (contracts build clean, contracts test 29/29, booterm + web typecheck clean).

wip: in-progress inference/provider refactor (agents.ts, provider.ts, new llama-providers.ts, removed llama-args-validator), plus arena, dispatcher, compaction, schema changes.

openspec: pty-exit-notifications complete; x-agent-flags planned (not yet implemented).
2026-06-14 12:48:47 +00:00

59 lines
3.4 KiB
Markdown

## ADDED Requirements
### Requirement: Structured pty_exited frame on WS protocol
The system MUST send a structured exit notification when a PTY process exits.
- **WHEN** a process running in a booterm terminal pane exits (via `handle.onExit`)
- **THEN** booterm MUST send a structured `pty_exited` JSON text frame on the WS connection containing: `type`, `exit_code`, `last_lines` (array of recent output lines from the ring buffer), `session_id`, `session_title`, `session_description`, `parent_agent`, `timed_out` (boolean)
#### Scenario: Normal process exit with metadata
- **WHEN** a user's SSH shell process exits with code 0 after producing output
- **AND** the terminal pane was registered with title "build", description "run tests", parentAgent "claude"
- **THEN** the `pty_exited` frame MUST contain `exit_code: 0`, at least one `last_lines` entry, `session_title: "build"`, `session_description: "run tests"`, `parent_agent: "claude"`, and `timed_out: false`
#### Scenario: Process exit with no output
- **WHEN** a process exits immediately without producing output
- **THEN** the `pty_exited` frame MUST contain an empty `last_lines` array and valid session metadata
#### Scenario: Timeout-triggered exit
- **WHEN** a process is killed by the idle timeout sweep (requires sweepExpired to be wired to an interval, which is a separate change)
- **THEN** the `pty_exited` frame MUST contain `timed_out: true` and the exit code from the tmux kill
### Requirement: pty_exited frame type in WsFrame contract
The system MUST register `pty_exited` as a valid frame type in the cross-app wire contract.
- **WHEN** the `pty_exited` frame schema is added to `WsFrameSchema` in `packages/contracts/src/ws-frames.ts`
- **THEN** it MUST be included in `KNOWN_FRAME_TYPES` and validate against the discriminated union
#### Scenario: Frame validates against schema
- **WHEN** a `pty_exited` frame with all required fields is parsed
- **THEN** the Zod validation MUST pass and the frame MUST NOT be dropped
#### Scenario: Frame missing required fields
- **WHEN** a `pty_exited` frame is missing the `exit_code` field
- **THEN** the Zod validation MUST fail and the frame MUST be dropped with a log warning
### Requirement: Client parse of pty_exited frame
The web frontend MUST recognize and parse `pty_exited` frames from the booterm WS.
- **WHEN** the web frontend receives a `pty_exited` frame over the terminal WS
- **THEN** `parseServerFrame` MUST recognize it and return a structured object with `session_id`, `pane_id`, `exit_code`, `last_lines`, and session metadata
#### Scenario: Client receives pty_exited
- **WHEN** the browser receives a `pty_exited` frame
- **THEN** the terminal MUST display a styled exit notification with the exit code and last output line(s)
#### Scenario: Client receives pty_exited with timeout
- **WHEN** the browser receives a `pty_exited` frame with `timed_out: true`
- **THEN** the terminal MUST display a timeout-specific notification message
### Requirement: Backward compatibility with bare exit frame
The client MUST NOT break when receiving the legacy bare exit frame.
- **WHEN** a booterm instance sends the old `{type: 'exit', code: N}` frame (pre-upgrade)
- **THEN** the client MUST gracefully handle it as before (display exit message, no crash)
#### Scenario: Legacy exit frame received
- **WHEN** the client receives `{type: 'exit', code: 1}`
- **THEN** the terminal MUST display the exit code message without throwing