## 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