@@ -163,7 +163,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
163163 } ) ,
164164 )
165165 const autoApproveTimeoutRef = useRef < NodeJS . Timeout | null > ( null )
166- const [ followUpAnswered , setFollowUpAnswered ] = useState < Set < number > > ( new Set ( ) )
166+ const [ currentFollowUpTs , setCurrentFollowUpTs ] = useState < number | null > ( null )
167167
168168 const clineAskRef = useRef ( clineAsk )
169169 useEffect ( ( ) => {
@@ -416,7 +416,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
416416 useEffect ( ( ) => {
417417 setExpandedRows ( { } )
418418 everVisibleMessagesTsRef . current . clear ( ) // Clear for new task
419- setFollowUpAnswered ( new Set ( ) ) // Clear follow-up answered state for new task
419+ setCurrentFollowUpTs ( null ) // Clear follow-up answered state for new task
420420 } , [ task ?. ts ] )
421421
422422 useEffect ( ( ) => {
@@ -488,6 +488,13 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
488488 return false
489489 } , [ modifiedMessages , clineAsk , enableButtons , primaryButtonText ] )
490490
491+ const markFollowUpAsAnswered = useCallback ( ( ) => {
492+ const lastFollowUpMessage = messagesRef . current . findLast ( ( msg ) => msg . ask === "followup" )
493+ if ( lastFollowUpMessage ) {
494+ setCurrentFollowUpTs ( lastFollowUpMessage . ts )
495+ }
496+ } , [ ] )
497+
491498 const handleChatReset = useCallback ( ( ) => {
492499 // Clear any pending auto-approval timeout to prevent race conditions
493500 if ( autoApproveTimeoutRef . current ) {
@@ -515,19 +522,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
515522 if ( messagesRef . current . length === 0 ) {
516523 vscode . postMessage ( { type : "newTask" , text, images } )
517524 } else if ( clineAskRef . current ) {
518- // Clear auto-approval timeout when user sends a message for follow-up questions
525+ // Clear auto-approval timeout FIRST to prevent race conditions
519526 // This ensures the countdown timer is properly dismounted when users submit custom responses
520- if ( clineAskRef . current === "followup" ) {
521- if ( autoApproveTimeoutRef . current ) {
522- clearTimeout ( autoApproveTimeoutRef . current )
523- autoApproveTimeoutRef . current = null
524- }
527+ if ( autoApproveTimeoutRef . current ) {
528+ clearTimeout ( autoApproveTimeoutRef . current )
529+ autoApproveTimeoutRef . current = null
530+ }
525531
526- // Mark the current follow-up question as answered
527- const lastFollowUpMessage = messagesRef . current . findLast ( ( msg ) => msg . ask === "followup" )
528- if ( lastFollowUpMessage ) {
529- setFollowUpAnswered ( ( prev ) => new Set ( prev ) . add ( lastFollowUpMessage . ts ) )
530- }
532+ if ( clineAskRef . current === "followup" ) {
533+ markFollowUpAsAnswered ( )
531534 }
532535
533536 // Use clineAskRef.current
@@ -553,7 +556,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
553556 handleChatReset ( )
554557 }
555558 } ,
556- [ handleChatReset ] , // messagesRef and clineAskRef are stable
559+ [ handleChatReset , markFollowUpAsAnswered ] , // messagesRef and clineAskRef are stable
557560 )
558561
559562 const handleSetChatBoxMessage = useCallback (
@@ -1237,12 +1240,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12371240
12381241 const handleSuggestionClickInRow = useCallback (
12391242 ( suggestion : SuggestionItem , event ?: React . MouseEvent ) => {
1243+ // Clear auto-approval timeout to prevent race conditions when suggestion is clicked
1244+ if ( autoApproveTimeoutRef . current ) {
1245+ clearTimeout ( autoApproveTimeoutRef . current )
1246+ autoApproveTimeoutRef . current = null
1247+ }
1248+
12401249 // Mark the current follow-up question as answered when a suggestion is clicked
12411250 if ( clineAsk === "followup" && ! event ?. shiftKey ) {
1242- const lastFollowUpMessage = messagesRef . current . findLast ( ( msg ) => msg . ask === "followup" )
1243- if ( lastFollowUpMessage ) {
1244- setFollowUpAnswered ( ( prev ) => new Set ( prev ) . add ( lastFollowUpMessage . ts ) )
1245- }
1251+ markFollowUpAsAnswered ( )
12461252 }
12471253
12481254 // Check if we need to switch modes
@@ -1264,7 +1270,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12641270 handleSendMessage ( suggestion . answer , [ ] )
12651271 }
12661272 } ,
1267- [ handleSendMessage , setInputValue , switchToMode , alwaysAllowModeSwitch , clineAsk ] ,
1273+ [ handleSendMessage , setInputValue , switchToMode , alwaysAllowModeSwitch , clineAsk , markFollowUpAsAnswered ] ,
12681274 )
12691275
12701276 const handleBatchFileResponse = useCallback ( ( response : { [ key : string ] : boolean } ) => {
@@ -1317,7 +1323,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13171323 onSuggestionClick = { handleSuggestionClickInRow } // This was already stabilized
13181324 onBatchFileResponse = { handleBatchFileResponse }
13191325 onFollowUpUnmount = { handleFollowUpUnmount }
1320- isFollowUpAnswered = { followUpAnswered . has ( messageOrGroup . ts ) }
1326+ isFollowUpAnswered = { messageOrGroup . ts === currentFollowUpTs }
13211327 />
13221328 )
13231329 } ,
@@ -1331,7 +1337,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13311337 handleSuggestionClickInRow ,
13321338 handleBatchFileResponse ,
13331339 handleFollowUpUnmount ,
1334- followUpAnswered ,
1340+ currentFollowUpTs ,
13351341 ] ,
13361342 )
13371343
@@ -1364,6 +1370,11 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13641370 autoApproveTimeoutRef . current = setTimeout ( resolve , followupAutoApproveTimeoutMs )
13651371 } )
13661372
1373+ // Check if timeout was cleared (user responded manually)
1374+ if ( ! autoApproveTimeoutRef . current ) {
1375+ return
1376+ }
1377+
13671378 // Get the first suggestion
13681379 const firstSuggestion = followUpData . suggest [ 0 ]
13691380
0 commit comments