| ... | ... | @@ -117,6 +117,11 @@ import { useTurnDiffSummaries } from "../hooks/useTurnDiffSummaries"; |
| 117 | 117 | import { isCommandPaletteOpen } from "../commandPaletteBus"; |
| 118 | 118 | import { buildTemporaryWorktreeBranchName } from "@t3tools/shared/git"; |
| 119 | 119 | import { useMediaQuery } from "../hooks/useMediaQuery"; |
| 120 | import { |
| 121 | clearPlanSidebarDismissal, |
| 122 | dismissPlanSidebarForTurn, |
| 123 | isPlanSidebarDismissedForTurn, |
| 124 | } from "../planSidebarDismissal"; |
| 120 | 125 | import { RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY } from "../rightPanelLayout"; |
| 121 | 126 | import { |
| 122 | 127 | selectActiveRightPanel, |
| ... | ... | @@ -1310,8 +1315,6 @@ function ChatViewContent(props: ChatViewProps) { |
| 1310 | 1315 | const [pendingUserInputQuestionIndexByRequestId, setPendingUserInputQuestionIndexByRequestId] = |
| 1311 | 1316 | useState<Record<string, number>>({}); |
| 1312 | 1317 | const shouldUsePlanSidebarSheet = useMediaQuery(RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY); |
| 1313 | | // Tracks whether the user explicitly dismissed the sidebar for the active turn. |
| 1314 | | const planSidebarDismissedForTurnRef = useRef<string | null>(null); |
| 1315 | 1318 | // When set, the thread-change reset effect will open the sidebar instead of closing it. |
| 1316 | 1319 | // Used by "Implement in a new thread" to carry the sidebar-open intent across navigation. |
| 1317 | 1320 | const planSidebarOpenOnNextThreadRef = useRef(false); |
| ... | ... | @@ -3110,18 +3113,21 @@ function ChatViewContent(props: ChatViewProps) { |
| 3110 | 3113 | handleInteractionModeChange(interactionMode === "plan" ? "default" : "plan"); |
| 3111 | 3114 | }, [handleInteractionModeChange, interactionMode]); |
| 3112 | 3115 | const dismissPlanSidebarForCurrentTurn = useCallback(() => { |
| 3113 | | planSidebarDismissedForTurnRef.current = |
| 3114 | | activePlan?.turnId ?? sidebarProposedPlan?.turnId ?? "__dismissed__"; |
| 3115 | | }, [activePlan?.turnId, sidebarProposedPlan?.turnId]); |
| 3116 | if (!activeThreadKey) return; |
| 3117 | dismissPlanSidebarForTurn( |
| 3118 | activeThreadKey, |
| 3119 | activePlan?.turnId ?? sidebarProposedPlan?.turnId ?? "__dismissed__", |
| 3120 | ); |
| 3121 | }, [activeThreadKey, activePlan?.turnId, sidebarProposedPlan?.turnId]); |
| 3116 | 3122 | const togglePlanSidebar = useCallback(() => { |
| 3117 | 3123 | if (!activeThreadRef) return; |
| 3118 | 3124 | if (planSidebarOpen) { |
| 3119 | 3125 | dismissPlanSidebarForCurrentTurn(); |
| 3120 | | } else { |
| 3121 | | planSidebarDismissedForTurnRef.current = null; |
| 3126 | } else if (activeThreadKey) { |
| 3127 | clearPlanSidebarDismissal(activeThreadKey); |
| 3122 | 3128 | } |
| 3123 | 3129 | useRightPanelStore.getState().toggle(activeThreadRef, "plan"); |
| 3124 | | }, [activeThreadRef, dismissPlanSidebarForCurrentTurn, planSidebarOpen]); |
| 3130 | }, [activeThreadKey, activeThreadRef, dismissPlanSidebarForCurrentTurn, planSidebarOpen]); |
| 3125 | 3131 | const closePlanSidebar = useCallback(() => { |
| 3126 | 3132 | if (!activeThreadRef) return; |
| 3127 | 3133 | setMaximizedRightPanelThreadKey(null); |
| ... | ... | @@ -3283,7 +3289,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 3283 | 3289 | (surface: RightPanelSurface) => { |
| 3284 | 3290 | if (!activeThreadRef) return; |
| 3285 | 3291 | if (surface.kind === "plan") { |
| 3286 | | planSidebarDismissedForTurnRef.current = null; |
| 3292 | clearPlanSidebarDismissal(scopedThreadKey(activeThreadRef)); |
| 3287 | 3293 | } else if (planSidebarOpen) { |
| 3288 | 3294 | dismissPlanSidebarForCurrentTurn(); |
| 3289 | 3295 | } |
| ... | ... | @@ -3852,10 +3858,10 @@ function ChatViewContent(props: ChatViewProps) { |
| 3852 | 3858 | if (planSidebarOpenOnNextThreadRef.current) { |
| 3853 | 3859 | planSidebarOpenOnNextThreadRef.current = false; |
| 3854 | 3860 | if (activeThreadRef) { |
| 3861 | clearPlanSidebarDismissal(scopedThreadKey(activeThreadRef)); |
| 3855 | 3862 | useRightPanelStore.getState().open(activeThreadRef, "plan"); |
| 3856 | 3863 | } |
| 3857 | 3864 | } |
| 3858 | | planSidebarDismissedForTurnRef.current = null; |
| 3859 | 3865 | // activeThreadRef resets transitively with the active thread. |
| 3860 | 3866 | }, [activeThread?.id]); |
| 3861 | 3867 | |
| ... | ... | @@ -3868,10 +3874,9 @@ function ChatViewContent(props: ChatViewProps) { |
| 3868 | 3874 | const latestTurnId = activeLatestTurn?.turnId ?? null; |
| 3869 | 3875 | if (latestTurnId && activePlan.turnId !== latestTurnId) return; |
| 3870 | 3876 | const turnKey = activePlan.turnId ?? sidebarProposedPlan?.turnId ?? "__dismissed__"; |
| 3871 | | if (planSidebarDismissedForTurnRef.current === turnKey) return; |
| 3872 | | if (activeThreadRef) { |
| 3873 | | useRightPanelStore.getState().open(activeThreadRef, "plan"); |
| 3874 | | } |
| 3877 | if (!activeThreadRef) return; |
| 3878 | if (isPlanSidebarDismissedForTurn(scopedThreadKey(activeThreadRef), turnKey)) return; |
| 3879 | useRightPanelStore.getState().open(activeThreadRef, "plan"); |
| 3875 | 3880 | }, [ |
| 3876 | 3881 | activePlan, |
| 3877 | 3882 | activeLatestTurn?.turnId, |
| ... | ... | @@ -5412,8 +5417,8 @@ function ChatViewContent(props: ChatViewProps) { |
| 5412 | 5417 | // "default" mode here means the agent is executing the plan, which produces |
| 5413 | 5418 | // step-tracking activities that the sidebar will display. |
| 5414 | 5419 | if (nextInteractionMode === "default" && autoOpenPlanSidebar) { |
| 5415 | | planSidebarDismissedForTurnRef.current = null; |
| 5416 | 5420 | if (activeThreadRef) { |
| 5421 | clearPlanSidebarDismissal(scopedThreadKey(activeThreadRef)); |
| 5417 | 5422 | useRightPanelStore.getState().open(activeThreadRef, "plan"); |
| 5418 | 5423 | } |
| 5419 | 5424 | } |