fix(tui): deliver buffered double-Esc as two events and re-arm loader after task completion

StdinBuffer held a bare `\x1b\x1b` chunk and timer-flushed it as one
sequence. `parseKey("\x1b\x1b")` returns undefined, so CustomEditor
fell through to the base editor and never fired the configured `onEscape` —
the double-escape gesture and the second-press single-Esc handler both went
dead whenever the terminal batched the two presses into one stdin read.

Split an exact bare `\x1b\x1b` into two ESC events only after the
flush window proves no follower arrived. If a follower does arrive, emit the
first ESC and restart parsing at the second ESC so legacy Alt chords
(`\x1bd`, `\x1b\x7f`) remain one downstream keypress. Meta-CSI/SS3
chords (`\x1b\x1b[A`, `\x1b\x1bO…`) still emit as one combined
sequence.

EventController.tool_execution_update re-armed the working loader when a
transient overlay (auto-compaction / auto-retry / handoff) had torn it down
mid-tool; tool_execution_end did not. A subagent (`task`) call only fires
_end, so a task result landing after such an overlay left the UI looking
idle even though the session was still streaming. Mirror the reconciler
call in #handleToolExecutionEnd.

Fixes #3857
This commit is contained in:
roboomp
2026-06-30 04:30:42 +00:00
parent 64734021a7
commit c2d6c8cf18
5 changed files with 32 additions and 34 deletions
@@ -124,7 +124,6 @@ const TASK_TOOL_EXECUTION_END = {
isError: false,
} as unknown as AgentSessionEvent;
describe("EventController loader recovery after overflow maintenance", () => {
beforeAll(async () => {
await initTheme(false);