fix(host-service): send follow-up Enter as a separate delayed write so terminals send submits reliably
Summary
Fixes #6243: superset terminals send to a busy/laggy Claude Code session typed the text into the agent's input box but left it as an unsubmitted draft, while the CLI reported submitted: true. Multi-line text (bracketed paste) was the biggest trigger.
Cause: writeFramedInputToSession bundled the submit Enter into the same PTY write as the pasted text (\x1b[200~text\x1b[201~\r). TUI agents aggregate bytes that arrive together into one paste burst, so on a slow session the trailing \r gets folded into the draft instead of acting as a keypress.
Fix: write the framed text first, then the Enter as its own write FOLLOW_UP_ENTER_DELAY_MS (500ms) later — the same class of fix as #6026's INITIAL_COMMAND_ENTER_DELAY_MS for initial commands. In its own read, a \r can only be an Enter keypress. If the session exits during the gap, the send now returns an error instead of pretending. --no-submit and bare-Enter (empty text) behavior unchanged. All callers (CLI, MCP tool, SDK) inherit the fix through the terminal.send mutation.
Tests
- New node test "submit Enter is a separate write, delayed past the paste burst" in
terminal.send-snapshot.node-test.ts— uses canonical-modecat > fileline buffering as the oracle for whether the Enter has been written. Verified it fails against the old bundled write (delay mutated to 0 → fail) and passes with the fix. - Full send/snapshot suite green: 13/13 under Electron-as-Node.
E2E verification (dev desktop + real CLI + live Claude Code, driven over CDP)
- Multi-line idle send → submitted, answered.
- Multi-line send into a busy mid-turn session → queued, auto-submitted after the turn, answered.
- Single-line, 8KB payload, and boot-race sends → all submit.
Known limitation (unchanged by this PR, tracked in #6243's remaining asks): if the agent process is dead or suspended, bytes go to whatever owns the pty and submitted: true still only means "bytes written" — programmatic submission verification is a follow-up.
Summary by cubic
Reliably submit text in host-service by sending Enter as a separate delayed write, serializing follow-up sends per session, and deduping in-flight adoptions so concurrent sends share one session. Fixes #6243 where multi-line sends could stay as drafts while the CLI reported submitted.
- Bug Fixes
- In
writeFramedInputToSession, write framed text first, then send\rafter 500ms (FOLLOW_UP_ENTER_DELAY_MS) whensubmit: true, so TUIs treat it as a keypress. - Return an error if the session exits during the delay;
--no-submitand empty-text behavior are unchanged. - Serialize follow-up sends per session so text + Enter are atomic; a draft cannot ride another send’s Enter.
- Dedupe in-flight headless adoptions in
getOrAdoptSessionso racing sends after a restart share oneTerminalSessionand respect send serialization.
- In
Summary by CodeRabbit
- Bug Fixes
- Improved terminal command submission by separating text input from the Enter key.
- Added a brief delay before submitting commands to ensure terminal input is processed reliably.
- Non-submitting terminal writes remain immediate.
- Improved handling of concurrent terminal actions to preserve command order and prevent staged text from being submitted unexpectedly.
- Added safeguards to ensure terminal actions are sent only while the session remains active.