@@ -37,6 +37,7 @@ import {
3737 shouldDockDraftHeroForSubmission ,
3838 shouldReleaseTimelineAnchorForToolActivity ,
3939 shouldShowBranchMismatchBanner ,
40+ shouldShowPlanFollowUpPrompt ,
4041 shouldWriteThreadErrorToCurrentServerThread ,
4142} from "./ChatView.logic" ;
4243
@@ -636,6 +637,31 @@ describe("shouldShowBranchMismatchBanner", () => {
636637 } ) ;
637638} ) ;
638639
640+ describe ( "shouldShowPlanFollowUpPrompt" , ( ) => {
641+ const base = {
642+ pendingUserInputCount : 0 ,
643+ interactionMode : "plan" as const ,
644+ latestTurnSettled : true ,
645+ hasActionableProposedPlan : true ,
646+ hasComposerAttachments : false ,
647+ } ;
648+
649+ it ( "shows plan actions for a settled actionable plan without attachments" , ( ) => {
650+ expect ( shouldShowPlanFollowUpPrompt ( base ) ) . toBe ( true ) ;
651+ } ) ;
652+
653+ it ( "hides plan actions while the composer has staged attachments" , ( ) => {
654+ expect ( shouldShowPlanFollowUpPrompt ( { ...base , hasComposerAttachments : true } ) ) . toBe ( false ) ;
655+ } ) ;
656+
657+ it ( "preserves the existing plan follow-up gates" , ( ) => {
658+ expect ( shouldShowPlanFollowUpPrompt ( { ...base , pendingUserInputCount : 1 } ) ) . toBe ( false ) ;
659+ expect ( shouldShowPlanFollowUpPrompt ( { ...base , interactionMode : "default" } ) ) . toBe ( false ) ;
660+ expect ( shouldShowPlanFollowUpPrompt ( { ...base , latestTurnSettled : false } ) ) . toBe ( false ) ;
661+ expect ( shouldShowPlanFollowUpPrompt ( { ...base , hasActionableProposedPlan : false } ) ) . toBe ( false ) ;
662+ } ) ;
663+ } ) ;
664+
639665describe ( "session branch mismatch dismissal" , ( ) => {
640666 it ( "tracks dismissed keys and treats other keys as active" , ( ) => {
641667 expect ( isBranchMismatchDismissedForSession ( "t1:a:b" ) ) . toBe ( false ) ;
0 commit comments