1313
1414import * as fs from "fs/promises" ;
1515import * as path from "path" ;
16- import { execFile } from "child_process" ;
1716import { fileURLToPath } from "url" ;
17+ import { execFile } from "child_process" ;
1818import type winston from "winston" ;
1919
2020export interface TrackedFileChange {
@@ -110,28 +110,25 @@ export class AgentFileTracker {
110110 this . pendingToolFiles . set ( callId , absPath ) ;
111111 }
112112
113- if ( this . originalContentCache . has ( absPath ) ) {
113+ if ( this . originalContentCache . has ( absPath ) || this . inflightReads . has ( absPath ) ) {
114114 return ;
115115 }
116116
117- // Track the in-flight read so scanners can await it before comparing
118- if ( ! this . inflightReads . has ( absPath ) ) {
119- const readPromise = fs
120- . readFile ( absPath , "utf-8" )
121- . then ( ( content ) => {
122- if ( ! this . originalContentCache . has ( absPath ) ) {
123- this . originalContentCache . set ( absPath , content ) ;
124- this . logger . debug ( "Cached original for tool-targeted file" , { path : absPath } ) ;
125- }
126- } )
127- . catch ( ( ) => {
128- // File may not exist yet (new file) — that's fine
129- } )
130- . finally ( ( ) => {
131- this . inflightReads . delete ( absPath ) ;
132- } ) ;
133- this . inflightReads . set ( absPath , readPromise ) ;
134- }
117+ const readPromise = fs . readFile ( absPath , "utf-8" )
118+ . then ( ( content ) => {
119+ if ( ! this . originalContentCache . has ( absPath ) ) {
120+ this . originalContentCache . set ( absPath , content ) ;
121+ this . logger . debug ( "Cached original for tool-targeted file" , { path : absPath } ) ;
122+ }
123+ } )
124+ . catch ( ( ) => {
125+ // File may not exist yet (new file) — that's fine
126+ } )
127+ . finally ( ( ) => {
128+ this . inflightReads . delete ( absPath ) ;
129+ } ) ;
130+
131+ this . inflightReads . set ( absPath , readPromise ) ;
135132 }
136133
137134 /**
@@ -155,7 +152,7 @@ export class AgentFileTracker {
155152 }
156153
157154 private async doScan ( ) : Promise < TrackedFileChange [ ] > {
158- // Wait for any in-flight reads to complete before comparing
155+ // Wait for any inflight reads to complete before comparing
159156 if ( this . inflightReads . size > 0 ) {
160157 await Promise . allSettled ( this . inflightReads . values ( ) ) ;
161158 }
@@ -187,8 +184,10 @@ export class AgentFileTracker {
187184
188185 /** Mark a file as already routed to batch review. */
189186 markAsRouted ( absPath : string ) : void {
190- if ( absPath . startsWith ( "file://" ) || absPath . startsWith ( "file:" ) ) {
187+ if ( absPath . startsWith ( "file://" ) ) {
191188 absPath = fileURLToPath ( absPath ) ;
189+ } else if ( absPath . startsWith ( "file:" ) ) {
190+ absPath = absPath . slice ( "file:" . length ) ;
192191 }
193192 this . routedFiles . add ( absPath ) ;
194193 }
@@ -201,8 +200,10 @@ export class AgentFileTracker {
201200 */
202201 async getOriginalContent ( absPath : string , workspaceRoot ?: string ) : Promise < string | undefined > {
203202 // Normalize absPath — it may arrive as a file: or file:// URI
204- if ( absPath . startsWith ( "file://" ) || absPath . startsWith ( "file:" ) ) {
203+ if ( absPath . startsWith ( "file://" ) ) {
205204 absPath = fileURLToPath ( absPath ) ;
205+ } else if ( absPath . startsWith ( "file:" ) ) {
206+ absPath = absPath . slice ( "file:" . length ) ;
206207 }
207208
208209 const cached = this . originalContentCache . get ( absPath ) ;
@@ -212,8 +213,10 @@ export class AgentFileTracker {
212213
213214 // Normalize workspaceRoot — it may arrive as a file:// URI
214215 let normalizedRoot = workspaceRoot ;
215- if ( normalizedRoot ?. startsWith ( "file://" ) || normalizedRoot ?. startsWith ( "file:" ) ) {
216- normalizedRoot = fileURLToPath ( normalizedRoot ) ;
216+ if ( normalizedRoot ?. startsWith ( "file://" ) ) {
217+ normalizedRoot = new URL ( normalizedRoot ) . pathname ;
218+ } else if ( normalizedRoot ?. startsWith ( "file:" ) ) {
219+ normalizedRoot = normalizedRoot . slice ( "file:" . length ) ;
217220 }
218221
219222 // Fall back to git for files not in the cache
@@ -306,13 +309,12 @@ export class AgentFileTracker {
306309 this . originalContentCache . clear ( ) ;
307310 this . routedFiles . clear ( ) ;
308311 this . pendingToolFiles . clear ( ) ;
309- this . inflightReads . clear ( ) ;
310312 this . scanPromise = null ;
311313 }
312314
313315 private uriToAbsolute ( uri : string , workspaceRoot : string ) : string | undefined {
314316 try {
315- if ( uri . startsWith ( "file://" ) || uri . startsWith ( "file:" ) ) {
317+ if ( uri . startsWith ( "file://" ) ) {
316318 return fileURLToPath ( uri ) ;
317319 }
318320 if ( path . isAbsolute ( uri ) ) {
0 commit comments