diff --git a/src/ui/ink/App.tsx b/src/ui/ink/App.tsx index ce6d7c9..3902524 100644 --- a/src/ui/ink/App.tsx +++ b/src/ui/ink/App.tsx @@ -776,6 +776,11 @@ export function App({ } async function handleSubmit(raw: string) { + // A turn is already in flight (streaming output or waiting for the first chunk). Keep the + // input box mounted so the user can type ahead, but ignore Enter so a second turn can't + // overlap onto the same session. The in-flight turn is the source of truth; the typed text + // stays in the box for when the turn finishes. + if (isThinking || streamingText !== null) return; setInputValue(""); const trimmed = raw.trim(); if (!trimmed) return; @@ -1198,25 +1203,18 @@ export function App({ gitInfo={gitInfo} /> )} - {isThinking || streamingText !== null ? ( - // Swapped in for ChatInput while a turn is in flight. Closes a real (if rare) race: - // handleSubmit had no guard against firing while a turn was already running, so - // typing and hitting Enter mid-stream could submit a second overlapping turn onto - // the same session. - - Waiting for response… (esc to interrupt) - - ) : ( - + {(isThinking || streamingText !== null) && ( + Waiting for response… (esc to interrupt) — type ahead, Enter sends when done. )} + )}