@@ -75,7 +75,6 @@ import {
7575 findSidebarProposedPlan ,
7676 findLatestProposedPlan ,
7777 deriveWorkLogEntries ,
78- deriveTodoItems ,
7978 hasActionableProposedPlan ,
8079 hasToolActivityForTurn ,
8180 isLatestTurnSettled ,
@@ -237,7 +236,6 @@ import { ComposerPrimaryActions } from "./chat/ComposerPrimaryActions";
237236import { ComposerPendingApprovalPanel } from "./chat/ComposerPendingApprovalPanel" ;
238237import { ComposerPendingUserInputPanel } from "./chat/ComposerPendingUserInputPanel" ;
239238import { ComposerPlanFollowUpBanner } from "./chat/ComposerPlanFollowUpBanner" ;
240- import { ComposerTodoListPanel } from "./chat/ComposerActiveTasksPanel" ;
241239import { SubagentDetailDrawer } from "./chat/SubagentDetailDrawer" ;
242240import {
243241 getComposerProviderState ,
@@ -748,7 +746,6 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
748746 ( store ) => store . setStickyModelSelection ,
749747 ) ;
750748 const timestampFormat = settings . timestampFormat ;
751- const showTodosInComposer = settings . showTodosInComposer ;
752749 const navigate = useNavigate ( ) ;
753750 const queryClient = useQueryClient ( ) ;
754751 const rawSearch = useSearch ( {
@@ -1296,20 +1293,12 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
12961293 const phase = derivePhase ( activeThread ?. session ?? null ) ;
12971294 const threadActivities = activeThread ?. activities ?? EMPTY_ACTIVITIES ;
12981295 const timelineThreadActivities = timelineThread ?. activities ?? EMPTY_ACTIVITIES ;
1299- const activeTodoItems = useMemo (
1300- ( ) =>
1301- showTodosInComposer
1302- ? deriveTodoItems ( threadActivities , activeLatestTurn ?. turnId ?? undefined )
1303- : [ ] ,
1304- [ showTodosInComposer , threadActivities , activeLatestTurn ?. turnId ] ,
1305- ) ;
13061296 const workLogEntries = useMemo (
13071297 ( ) =>
13081298 deriveWorkLogEntries ( timelineThreadActivities , timelineLatestTurn ?. turnId ?? undefined , {
1309- excludeTodoToolCalls : showTodosInComposer ,
13101299 isSessionRunning : phase === "running" ,
13111300 } ) ,
1312- [ timelineLatestTurn ?. turnId , timelineThreadActivities , showTodosInComposer , phase ] ,
1301+ [ timelineLatestTurn ?. turnId , timelineThreadActivities , phase ] ,
13131302 ) ;
13141303 const timelineLatestTurnHasToolActivity = useMemo (
13151304 ( ) => hasToolActivityForTurn ( timelineThreadActivities , timelineLatestTurn ?. turnId ) ,
@@ -1383,6 +1372,7 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
13831372 ( ) => deriveActivePlanState ( threadActivities , activeLatestTurn ?. turnId ?? undefined ) ,
13841373 [ activeLatestTurn ?. turnId , threadActivities ] ,
13851374 ) ;
1375+ const planSidebarLabel = sidebarProposedPlan || interactionMode === "plan" ? "Plan" : "Tasks" ;
13861376 const showPlanFollowUpPrompt =
13871377 pendingUserInputs . length === 0 &&
13881378 interactionMode === "plan" &&
@@ -1403,7 +1393,9 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
14031393 activePendingUserInput : activePendingUserInput ?. requestId ?? null ,
14041394 threadError : activeThread ?. error ,
14051395 } ) ;
1406- const isWorking = phase === "running" || isSendBusy || isConnecting || isRevertingCheckpoint ;
1396+ const hasInFlightTurn = Boolean ( activeLatestTurn && ! activeLatestTurn . completedAt ) ;
1397+ const isWorking =
1398+ phase === "running" || isSendBusy || isConnecting || isRevertingCheckpoint || hasInFlightTurn ;
14071399 const isCompacting = activeThread ?. session ?. compacting === true ;
14081400 const isThreadHydrating = activeThread !== undefined && ! isThreadHydrated ( activeThread ) ;
14091401 const nowIso = new Date ( nowTick ) . toISOString ( ) ;
@@ -1416,8 +1408,7 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
14161408 const hasComposerHeader =
14171409 isComposerApprovalState ||
14181410 pendingUserInputs . length > 0 ||
1419- ( showPlanFollowUpPrompt && activeProposedPlan !== null ) ||
1420- activeTodoItems . length > 0 ;
1411+ ( showPlanFollowUpPrompt && activeProposedPlan !== null ) ;
14211412 const composerFooterHasWideActions = showPlanFollowUpPrompt || activePendingProgress !== null ;
14221413 const composerFooterActionLayoutKey = useMemo ( ( ) => {
14231414 if ( activePendingProgress ) {
@@ -2353,10 +2344,8 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
23532344 const togglePlanSidebar = useCallback ( ( ) => {
23542345 setPlanSidebarOpen ( ( open ) => {
23552346 if ( open ) {
2356- const turnKey = activePlan ?. turnId ?? sidebarProposedPlan ?. turnId ?? null ;
2357- if ( turnKey ) {
2358- planSidebarDismissedForTurnRef . current = turnKey ;
2359- }
2347+ planSidebarDismissedForTurnRef . current =
2348+ activePlan ?. turnId ?? sidebarProposedPlan ?. turnId ?? "__dismissed__" ;
23602349 } else {
23612350 planSidebarDismissedForTurnRef . current = null ;
23622351 }
@@ -2739,6 +2728,18 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
27392728 planSidebarDismissedForTurnRef . current = null ;
27402729 } , [ activeThread ?. id ] ) ;
27412730
2731+ // Auto-open the plan sidebar when plan/todo steps arrive for the current turn.
2732+ // Don't auto-open for plans carried over from a previous turn (the user can open manually).
2733+ useEffect ( ( ) => {
2734+ if ( ! activePlan ) return ;
2735+ if ( planSidebarOpen ) return ;
2736+ const latestTurnId = activeLatestTurn ?. turnId ?? null ;
2737+ if ( latestTurnId && activePlan . turnId !== latestTurnId ) return ;
2738+ const turnKey = activePlan . turnId ?? sidebarProposedPlan ?. turnId ?? "__dismissed__" ;
2739+ if ( planSidebarDismissedForTurnRef . current === turnKey ) return ;
2740+ setPlanSidebarOpen ( true ) ;
2741+ } , [ activePlan , activeLatestTurn ?. turnId , planSidebarOpen , sidebarProposedPlan ?. turnId ] ) ;
2742+
27422743 useEffect ( ( ) => {
27432744 if ( ! composerMenuOpen ) {
27442745 setComposerHighlightedItemId ( null ) ;
@@ -4838,6 +4839,7 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
48384839 diffOpen = { diffOpen }
48394840 hasPlan = { Boolean ( activePlan || sidebarProposedPlan ) }
48404841 planSidebarOpen = { planSidebarOpen }
4842+ planSidebarLabel = { planSidebarLabel }
48414843 onRunProjectScript = { runProjectScript }
48424844 onAddProjectScript = { saveProjectScript }
48434845 onUpdateProjectScript = { updateProjectScript }
@@ -4986,10 +4988,6 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
49864988 planTitle = { proposedPlanTitle ( activeProposedPlan . planMarkdown ) ?? null }
49874989 />
49884990 </ div >
4989- ) : activeTodoItems . length > 0 ? (
4990- < div className = "rounded-t-[19px] border-b border-border/65 bg-muted/20" >
4991- < ComposerTodoListPanel items = { activeTodoItems } />
4992- </ div >
49934991 ) : null }
49944992 < div
49954993 className = { cn (
@@ -5158,7 +5156,7 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
51585156 data-chat-composer-footer = "true"
51595157 data-chat-composer-footer-compact = { isComposerFooterCompact ? "true" : "false" }
51605158 className = { cn (
5161- "flex min-w-0 flex-nowrap items-center justify-between gap-2 overflow-hidden px-2.5 pb-2.5 sm:px-3 sm:pb-3" ,
5159+ "flex min-w-0 flex-nowrap items-center justify-between gap-2 overflow-visible px-2.5 pb-2.5 sm:px-3 sm:pb-3" ,
51625160 isComposerFooterCompact ? "gap-1.5" : "gap-2 sm:gap-0" ,
51635161 ) }
51645162 >
@@ -5209,6 +5207,7 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
52095207 activePlan = { activePlan !== null }
52105208 interactionMode = { interactionMode }
52115209 planSidebarOpen = { planSidebarOpen }
5210+ planSidebarLabel = { planSidebarLabel }
52125211 traitsMenuContent = { providerTraitsMenuContent }
52135212 onToggleInteractionMode = { toggleInteractionMode }
52145213 onTogglePlanSidebar = { togglePlanSidebar }
@@ -5339,16 +5338,15 @@ export default function ChatView({ threadId, environmentId: environmentIdProp }:
53395338 environmentId = { activeThreadEnvironmentId ! }
53405339 activePlan = { activePlan }
53415340 activeProposedPlan = { sidebarProposedPlan }
5341+ label = { planSidebarLabel }
53425342 markdownCwd = { gitCwd ?? undefined }
53435343 workspaceRoot = { activeWorkspaceRoot }
53445344 timestampFormat = { timestampFormat }
53455345 onClose = { ( ) => {
53465346 setPlanSidebarOpen ( false ) ;
53475347 // Track that the user explicitly dismissed for this turn so auto-open won't fight them.
5348- const turnKey = activePlan ?. turnId ?? sidebarProposedPlan ?. turnId ?? null ;
5349- if ( turnKey ) {
5350- planSidebarDismissedForTurnRef . current = turnKey ;
5351- }
5348+ planSidebarDismissedForTurnRef . current =
5349+ activePlan ?. turnId ?? sidebarProposedPlan ?. turnId ?? "__dismissed__" ;
53525350 } }
53535351 />
53545352 ) : null }
0 commit comments