@@ -50,7 +50,7 @@ import { supportPrompt } from "../../shared/support-prompt"
5050import { GlobalFileNames } from "../../shared/globalFileNames"
5151import type { ExtensionMessage , ExtensionState , MarketplaceInstalledMetadata } from "../../shared/ExtensionMessage"
5252import { Mode , defaultModeSlug , getModeBySlug } from "../../shared/modes"
53- import { experimentDefault } from "../../shared/experiments"
53+ import { experimentDefault , EXPERIMENT_IDS } from "../../shared/experiments"
5454import { formatLanguage } from "../../shared/language"
5555import { WebviewMessage } from "../../shared/WebviewMessage"
5656import { EMBEDDING_MODEL_PROFILES } from "../../shared/embeddingModels"
@@ -93,6 +93,7 @@ import type { ClineMessage } from "@roo-code/types"
9393import { readApiMessages , saveApiMessages , saveTaskMessages } from "../task-persistence"
9494import { getNonce } from "./getNonce"
9595import { getUri } from "./getUri"
96+ import { FilesChangedMessageHandler } from "../../services/files-changed/FilesChangedMessageHandler"
9697
9798/**
9899 * https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -136,6 +137,9 @@ export class ClineProvider
136137 private taskCreationCallback : ( task : Task ) => void
137138 private taskEventListeners : WeakMap < Task , Array < ( ) => void > > = new WeakMap ( )
138139 private currentWorkspacePath : string | undefined
140+ private lastCheckpointByTaskId : Map < string , string > = new Map ( )
141+ // Files Changed handler
142+ private filesChangedHandler : FilesChangedMessageHandler
139143
140144 private recentTasksCache ?: string [ ]
141145 private pendingOperations : Map < string , PendingEditOperation > = new Map ( )
@@ -177,6 +181,9 @@ export class ClineProvider
177181 await this . postStateToWebview ( )
178182 } )
179183
184+ // Initialize Files Changed handler
185+ this . filesChangedHandler = new FilesChangedMessageHandler ( this )
186+
180187 // Initialize MCP Hub through the singleton manager
181188 McpServerManager . getInstance ( this . context , this )
182189 . then ( ( hub ) => {
@@ -481,12 +488,16 @@ export class ClineProvider
481488 // This is used when a subtask is finished and the parent task needs to be
482489 // resumed.
483490 async finishSubTask ( lastMessage : string ) {
484- // Remove the last cline instance from the stack (this is the finished
485- // subtask).
491+ const childTask = this . getCurrentTask ( )
492+ const parentFromStack = this . clineStack . length > 1 ? this . clineStack [ this . clineStack . length - 2 ] : undefined
493+ await this . filesChangedHandler . handleChildTaskCompletion ( childTask , parentFromStack )
494+
495+ const previousTask = this . getCurrentTask ( )
486496 await this . removeClineFromStack ( )
487- // Resume the last cline instance in the stack (if it exists - this is
488- // the 'parent' calling task).
489- await this . getCurrentTask ( ) ?. completeSubtask ( lastMessage )
497+ const parentTask = this . getCurrentTask ( )
498+
499+ await parentTask ?. completeSubtask ( lastMessage )
500+ await this . filesChangedHandler . applyExperimentsToTask ( parentTask )
490501 }
491502 // Pending Edit Operations Management
492503
@@ -588,6 +599,7 @@ export class ClineProvider
588599 }
589600
590601 this . clearWebviewResources ( )
602+ this . filesChangedHandler ?. dispose ( this . getCurrentTask ( ) )
591603
592604 // Clean up cloud service event listener
593605 if ( CloudService . hasInstance ( ) ) {
@@ -845,6 +857,8 @@ export class ClineProvider
845857 }
846858
847859 public async createTaskWithHistoryItem ( historyItem : HistoryItem & { rootTask ?: Task ; parentTask ?: Task } ) {
860+ // Capture current task before removal for potential FCO state transfer
861+ const previousTask = this . getCurrentTask ( )
848862 await this . removeClineFromStack ( )
849863
850864 // If the history item has a saved mode, restore it and its associated API configuration.
@@ -919,10 +933,17 @@ export class ClineProvider
919933
920934 await this . addClineToStack ( task )
921935
936+ if ( previousTask && previousTask . taskId === task . taskId ) {
937+ this . filesChangedHandler . transferStateBetweenTasks ( previousTask , task )
938+ }
939+
922940 this . log (
923941 `[createTaskWithHistoryItem] ${ task . parentTask ? "child" : "parent" } task ${ task . taskId } .${ task . instanceId } instantiated` ,
924942 )
925943
944+ // Initialize Files Changed state for this task if setting is enabled
945+ await this . filesChangedHandler . applyExperimentsToTask ( task )
946+
926947 // Check if there's a pending edit after checkpoint restoration
927948 const operationId = `task-${ task . taskId } `
928949 const pendingEdit = this . getPendingEditOperation ( operationId )
@@ -1149,8 +1170,14 @@ export class ClineProvider
11491170 * @param webview A reference to the extension webview
11501171 */
11511172 private setWebviewMessageListener ( webview : vscode . Webview ) {
1152- const onReceiveMessage = async ( message : WebviewMessage ) =>
1153- webviewMessageHandler ( this , message , this . marketplaceManager )
1173+ const onReceiveMessage = async ( message : WebviewMessage ) => {
1174+ // Route Files Changed Overview messages first
1175+ if ( this . filesChangedHandler . shouldHandleMessage ( message ) ) {
1176+ await this . filesChangedHandler . handleMessage ( message )
1177+ return
1178+ }
1179+ await webviewMessageHandler ( this , message , this . marketplaceManager )
1180+ }
11541181
11551182 const messageDisposable = webview . onDidReceiveMessage ( onReceiveMessage )
11561183 this . webviewDisposables . push ( messageDisposable )
@@ -2211,6 +2238,23 @@ export class ClineProvider
22112238 return this . contextProxy . getValue ( key )
22122239 }
22132240
2241+ // FilesChanged Message Handler access
2242+ public getFilesChangedHandler ( ) : FilesChangedMessageHandler {
2243+ return this . filesChangedHandler
2244+ }
2245+
2246+ // Track last checkpoint per task for delta-based FilesChanged updates
2247+ public setLastCheckpointForTask ( taskId : string , commitHash : string ) {
2248+ this . lastCheckpointByTaskId . set ( taskId , commitHash )
2249+ }
2250+
2251+ /**
2252+ * Check if a message should be handled by Files Changed service
2253+ */
2254+ public getLastCheckpointForTask ( taskId : string ) : string | undefined {
2255+ return this . lastCheckpointByTaskId . get ( taskId )
2256+ }
2257+
22142258 public async setValue < K extends keyof RooCodeSettings > ( key : K , value : RooCodeSettings [ K ] ) {
22152259 await this . contextProxy . setValue ( key , value )
22162260 }
@@ -2543,6 +2587,9 @@ export class ClineProvider
25432587 `[createTask] ${ task . parentTask ? "child" : "parent" } task ${ task . taskId } .${ task . instanceId } instantiated` ,
25442588 )
25452589
2590+ // Initialize Files Changed state for this task if setting is enabled
2591+ await this . filesChangedHandler . applyExperimentsToTask ( task )
2592+
25462593 return task
25472594 }
25482595
@@ -2567,6 +2614,9 @@ export class ClineProvider
25672614 // Capture the current instance to detect if rehydrate already occurred elsewhere
25682615 const originalInstanceId = task . instanceId
25692616
2617+ // Capture FCO state before task disposal (task.abortTask() will dispose it)
2618+ const fcoState = task . getFilesChangedState ( )
2619+
25702620 // Begin abort (non-blocking)
25712621 task . abortTask ( )
25722622
@@ -2611,6 +2661,20 @@ export class ClineProvider
26112661
26122662 // Clears task again, so we need to abortTask manually above.
26132663 await this . createTaskWithHistoryItem ( { ...historyItem , rootTask, parentTask } )
2664+
2665+ // Restore FCO state to the new task if we captured it
2666+ if ( fcoState ) {
2667+ const newTask = this . getCurrentTask ( )
2668+ if ( newTask && newTask . taskId === task . taskId ) {
2669+ const newTaskState = newTask . ensureFilesChangedState ( )
2670+ newTaskState . cloneFrom ( fcoState )
2671+ // Ensure the restored task is not waiting (prevents clearFilesChangedDisplay)
2672+ newTaskState . setWaiting ( false )
2673+ console . log ( `[cancelTask] restored FCO state to recreated task ${ newTask . taskId } .${ newTask . instanceId } ` )
2674+ // Re-trigger FCO display since applyExperimentsToTask may have cleared it
2675+ await this . filesChangedHandler . applyExperimentsToTask ( newTask )
2676+ }
2677+ }
26142678 }
26152679
26162680 // Clear the current task without treating it as a subtask.
0 commit comments