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