History

Prevent duplicate sends and sync worktree branch state

- Guard `onSend` with an in-flight ref to block double submits - Set send phase before worktree prep and always clear in-flight state in `finally` - Sync thread branch/worktree path immediately and await setup script execution

Julius Marminge committed 8 months ago

Commit 7b0ae431 parent 69dbc5d1 file · +15 −2Browse files

Unified · Split

apps/web/src/components/ChatView.tsx+15−2
@@ -368,6 +368,7 @@ export default function ChatView({ threadId }: ChatViewProps) { · 367 unmodified lines
368368 const textareaRef = useRef<HTMLTextAreaElement>(null);
369369 const composerCommandInputRef = useRef<HTMLInputElement>(null);
370370 const composerImagesRef = useRef<ComposerImageAttachment[]>([]);
371+ const sendInFlightRef = useRef(false);
371372 const dragDepthRef = useRef(0);
372373 const terminalOpenByThreadRef = useRef<Record<string, boolean>>({});
373374
@@ -1391,7 +1392,7 @@ export default function ChatView({ threadId }: ChatViewProps) { · 1017 unmodified lines
13911392 const onSend = async (e: React.SubmitEvent | React.KeyboardEvent) => {
13921393 e.preventDefault();
13931394 const api = readNativeApi();
1394− if (!api || !activeThread || isSendBusy || isConnecting) return;
1395+ if (!api || !activeThread || isSendBusy || isConnecting || sendInFlightRef.current) return;
13951396 const trimmed = prompt.trim();
13961397 if (!trimmed && composerImages.length === 0) return;
13971398 if (!activeProject) return;
@@ -1415,6 +1416,9 @@ export default function ChatView({ threadId }: ChatViewProps) { · 17 unmodified lines
14151416 return;
14161417 }
14171418
1419+ sendInFlightRef.current = true;
1420+ setSendPhase(baseBranchForWorktree ? "preparing-worktree" : "sending-turn");
1421+
14181422 const composerImagesSnapshot = [...composerImages];
14191423 const messageIdForSend = newMessageId();
14201424 const messageCreatedAt = new Date().toISOString();
@@ -1463,9 +1467,17 @@ export default function ChatView({ threadId }: ChatViewProps) { · 42 unmodified lines
14631467 branch: result.worktree.branch,
14641468 worktreePath: result.worktree.path,
14651469 });
1470+ // Keep local thread state in sync immediately so terminal drawer opens
1471+ // with the worktree cwd/env instead of briefly using the project root.
1472+ dispatch({
1473+ type: "SET_THREAD_BRANCH",
1474+ threadId: threadIdForSend,
1475+ branch: result.worktree.branch,
1476+ worktreePath: result.worktree.path,
1477+ });
14661478 const setupScript = setupProjectScript(activeProject.scripts);
14671479 if (setupScript) {
1468− void runProjectScript(setupScript, {
1480+ await runProjectScript(setupScript, {
14691481 cwd: result.worktree.path,
14701482 worktreePath: result.worktree.path,
14711483 rememberAsLastInvoked: false,
@@ -1544,6 +1556,7 @@ export default function ChatView({ threadId }: ChatViewProps) { · 72 unmodified lines
15441556 err instanceof Error ? err.message : "Failed to send message.",
15451557 );
15461558 } finally {
1559+ sendInFlightRef.current = false;
15471560 setSendPhase("idle");
15481561 }
15491562 };