Two fixes on top of the paged transport:
- Near-limit v2 framing no longer materializes the full base64 transport:
chunk lines are generated lazily from a single serialization, the 64 MiB
reassembly ceiling is enforced via Buffer.byteLength before any
full-payload allocation, and RPC stdout writes drain with backpressure
one physical line at a time. Peak RSS for a 63 MiB response drops
~686 MB -> ~521 MB; a rejected 80 MiB response drops ~507 MB -> ~259 MB
(parity with the v1 path).
- get_messages_page errors now carry a machine-readable code
(session_busy | stale_cursor). Both bundled clients' high-level
getMessages() drains discard partial pages and fall back to the legacy
snapshot on either code — previously a cursor invalidated by a
background mutation (e.g. an appended bash message) threw instead of
falling back. Direct page calls remain strict.
The RPC transport did not treat cancellation as an independent, resettable
control plane, so two lifecycle contract violations shared a root cause:
A. Server-side: the stdin loop in `rpc-mode.ts` awaited each commands
`handleCommand` before pulling the next frame, so `abort_bash` queued
behind the `bash` it must cancel. Extracted `dispatchRpcInputFrame` and
dispatch `bash` in the background: the input loop keeps reading, so
`abort_bash` (or any other command) can preempt an in-flight shell.
Response correlation still rides `command.id`; ordering across
concurrent commands is documented as not guaranteed.
B. Client-side: `RpcClient.stop()` aborted the shared `#abortController`
but never replaced it, so a subsequent `start()` handed a pre-aborted
signal to `readJsonl` and the stdout reader exited immediately with a
spurious "Agent process exited before ready" while the spawned child
leaked in `#process`. Mint a fresh `AbortController` inside `start()`
and clean up the child on any post-spawn failure.
Adds:
- `dispatchRpcInputFrame` unit tests covering the concurrent bash + abort
ordering, serial dispatch of other commands, and background error
reporting.
- `RpcClient` lifecycle tests covering start->stop->start on the same
instance (via a mock fixture agent) and retry after a failed start.
- Documents the bash concurrency contract in `docs/rpc.md`.
Fixes#4079