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.
)}
+
>
)}