Skip to content

Commit 1f4d9e6

Browse files
committed
fix: PlanApprovalAlert bugs + plan mode race condition
- Fix double-fire: handleApprove() now only calls approvePlan(), no longer also sends postMessage - Fix modify: handleModify() now calls modifyPlan() from store (opens PLAN.md in editor) - Remove unused postMessage prop from PlanApprovalAlert interface and BaseChat - Fix race condition: reset chatId/description/chatMetadata atoms on home page navigation so wasNewChat detection works correctly for new chats after navigating away
1 parent 1fa6e72 commit 1f4d9e6

3 files changed

Lines changed: 20 additions & 21 deletions

File tree

‎app/components/chat/BaseChat.tsx‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,11 +470,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
470470
)}
471471
{llmErrorAlert && <LlmErrorAlert alert={llmErrorAlert} clearAlert={() => clearLlmErrorAlert?.()} />}
472472
{/* Plan Approval Alert - shows when a plan is pending approval */}
473-
<PlanApprovalAlert
474-
postMessage={(message) => {
475-
sendMessage?.(undefined, message);
476-
}}
477-
/>
473+
<PlanApprovalAlert />
478474
</div>
479475
{progressAnnotations && <ProgressCompilation data={progressAnnotations} />}
480476

‎app/components/chat/PlanApprovalAlert.tsx‎

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { memo, useCallback } from 'react';
22
import { useStore } from '@nanostores/react';
33
import { motion, AnimatePresence } from 'framer-motion';
4-
import { planStore, planProgress, approvePlan, rejectPlan, type PlanTask } from '~/lib/stores/plan';
4+
import { planStore, planProgress, approvePlan, rejectPlan, modifyPlan, type PlanTask } from '~/lib/stores/plan';
55
import { classNames } from '~/utils/classNames';
66
import { Button } from '~/components/ui/Button';
77
import { Progress } from '~/components/ui/Progress';
@@ -28,35 +28,29 @@ interface PlanApprovalAlertProps {
2828

2929
/** Optional callback when plan is rejected */
3030
onReject?: () => void;
31-
32-
/** Optional callback to send a message to continue execution */
33-
postMessage?: (message: string) => void;
3431
}
3532

3633
/**
37-
* PlanApprovalAlert component - shows in the chat area when a plan is pending approval
34+
* PlanApprovalAlert component - shows in the chat area when a plan is pending approval.
35+
* Buttons delegate to planActionAtom via store functions; Chat.client.tsx handles the rest.
3836
*/
39-
export const PlanApprovalAlert = memo(({ onApprove, onReject, postMessage }: PlanApprovalAlertProps) => {
37+
export const PlanApprovalAlert = memo(({ onApprove, onReject }: PlanApprovalAlertProps) => {
4038
const state = useStore(planStore);
4139
const progress = useStore(planProgress);
4240

4341
const handleApprove = useCallback(() => {
44-
approvePlan();
42+
approvePlan(); // fires planActionAtom('approve') → Chat.client.tsx sends execute message
4543
onApprove?.();
46-
47-
// Send a message to continue execution
48-
postMessage?.('Plan approved. Please proceed with the implementation.');
49-
}, [onApprove, postMessage]);
44+
}, [onApprove]);
5045

5146
const handleReject = useCallback(() => {
52-
rejectPlan();
47+
rejectPlan(); // fires planActionAtom('reject') → Chat.client.tsx shows cancel toast
5348
onReject?.();
5449
}, [onReject]);
5550

5651
const handleModify = useCallback(() => {
57-
// For now, just reject and ask user to clarify
58-
postMessage?.('I would like to modify the plan. Please adjust the following tasks before proceeding...');
59-
}, [postMessage]);
52+
modifyPlan(); // fires planActionAtom('modify') → Chat.client.tsx opens PLAN.md in editor
53+
}, []);
6054

6155
// Don't show if no plan or already approved
6256
if (!state.isActive || state.tasks.length === 0 || state.approvedByUser) {

‎app/lib/persistence/useChatHistory.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,16 @@ export function useChatHistory() {
141141
toast.error('Failed to load chat: ' + error.message); // More specific error
142142
});
143143
} else {
144-
// Handle case where there is no mixedId (e.g., new chat)
144+
/*
145+
* Home page (no mixedId) — reset global atoms so stale values from a
146+
* previous chat don't leak into a fresh session. Without this,
147+
* chatId retains the old value after navigating back to "/", which
148+
* breaks the wasNewChat detection in Chat.client.tsx and causes
149+
* plan-mode carry-over to fail for new chats.
150+
*/
151+
chatId.set(undefined);
152+
description.set(undefined);
153+
chatMetadata.set(undefined);
145154
setReady(true);
146155
}
147156
}, [mixedId, db, navigate, searchParams]); // Added db, navigate, searchParams dependencies

0 commit comments

Comments
 (0)