@@ -15,11 +15,8 @@ import {
1515 mergeProjectFactsUpdate ,
1616 projectFactsFromSnapshot ,
1717} from './facts-merge-helpers.js' ;
18- import {
19- formatFilesenseNavigationContext ,
20- normalizeFilesenseNavigation ,
21- parentDirectoriesForPath ,
22- } from './helpers.js' ;
18+ import { updateFilesystemFactsFromToolResult } from './filesystem-facts-update.js' ;
19+ import { formatFilesenseNavigationContext , normalizeFilesenseNavigation } from './helpers.js' ;
2320import { updateModuleDependencyGraphFromToolResult } from './module-dependency-graph.js' ;
2421
2522/**
@@ -91,19 +88,6 @@ export class ContextManager {
9188 return set . delete ( value ) ;
9289 }
9390
94- private setStringArrayMap ( map : Map < string , string [ ] > , key : string , value : string [ ] ) : boolean {
95- const previous = map . get ( key ) ;
96- if (
97- previous &&
98- previous . length === value . length &&
99- previous . every ( ( item , idx ) => item === value [ idx ] )
100- ) {
101- return false ;
102- }
103- map . set ( key , value ) ;
104- return true ;
105- }
106-
10791 /**
10892 * 更新执行计划
10993 */
@@ -326,169 +310,8 @@ export class ContextManager {
326310 const context = this . contexts . get ( taskId ) ;
327311 if ( ! context ) return ;
328312
329- const { facts } = context ;
330- let changed = false ;
331-
332- // Handle filesense navigation results - consume explicit factsDelta instead of guessing result shape.
333- if ( toolName . startsWith ( 'filesense_' ) ) {
334- const data = result . data as
335- | { factsDelta ?: { existingFiles ?: string [ ] ; existingDirectories ?: string [ ] } }
336- | undefined ;
337- const factsDelta = data ?. factsDelta ;
338- if ( result . success && factsDelta ) {
339- for ( const file of factsDelta . existingFiles ?? [ ] ) {
340- changed = this . addToSet ( facts . filesystem . existingFiles , file ) || changed ;
341- changed = this . removeFromSet ( facts . filesystem . nonExistentPaths , file ) || changed ;
342- }
343- for ( const dir of factsDelta . existingDirectories ?? [ ] ) {
344- changed = this . addToSet ( facts . filesystem . existingDirectories , dir ) || changed ;
345- changed = this . removeFromSet ( facts . filesystem . nonExistentPaths , dir ) || changed ;
346- }
347- }
348- }
349-
350- // Handle filesense tool results - enrich ProjectFacts from index data
351- if (
352- toolName === 'filesense_sync' ||
353- toolName === 'filesense_sync_and_summarize' ||
354- toolName === 'filesense_query'
355- ) {
356- if ( result . success && result . data ) {
357- const data = result . data as Record < string , unknown > ;
358-
359- // For query results, extract file/directory existence from the index
360- const index = ( data . index ?? ( data as { sync ?: unknown } ) . sync ) as
361- | { children ?: Array < { name : string ; path : string ; type : string } > }
362- | undefined ;
363- if ( index ?. children ) {
364- for ( const child of index . children ) {
365- if ( child . type === 'file' ) {
366- changed = this . addToSet ( facts . filesystem . existingFiles , child . path ) || changed ;
367- changed =
368- this . removeFromSet ( facts . filesystem . nonExistentPaths , child . path ) || changed ;
369- } else if ( child . type === 'dir' ) {
370- changed = this . addToSet ( facts . filesystem . existingDirectories , child . path ) || changed ;
371- changed =
372- this . removeFromSet ( facts . filesystem . nonExistentPaths , child . path ) || changed ;
373- }
374- }
375- }
376-
377- // For sync results, mark the root as existing directory
378- const root = data . root as string | undefined ;
379- if ( root ) {
380- changed = this . addToSet ( facts . filesystem . existingDirectories , root ) || changed ;
381- }
382- }
383- }
384-
385- switch ( toolName ) {
386- case 'create_file' :
387- case 'apply_patch' : {
388- const path = params . path as string ;
389- if ( result . success ) {
390- changed = this . addToSet ( facts . filesystem . existingFiles , path ) || changed ;
391- changed = this . removeFromSet ( facts . filesystem . nonExistentPaths , path ) || changed ;
392- } else if ( result . error ?. includes ( 'not found' ) ) {
393- changed = this . addToSet ( facts . filesystem . nonExistentPaths , path ) || changed ;
394- }
395- break ;
396- }
397- case 'read_file' : {
398- const path = params . path as string ;
399- // 🔧 修复:检查 skipped 和 exists 字段,正确记录不存在的文件
400- if ( result . success && ! result . skipped ) {
401- // 真正成功读取了文件
402- changed = this . addToSet ( facts . filesystem . existingFiles , path ) || changed ;
403- changed = this . removeFromSet ( facts . filesystem . nonExistentPaths , path ) || changed ;
404- } else if ( result . skipped && result . exists === false ) {
405- // 步骤被跳过且文件不存在
406- changed = this . addToSet ( facts . filesystem . nonExistentPaths , path ) || changed ;
407- changed = this . removeFromSet ( facts . filesystem . existingFiles , path ) || changed ;
408- } else if (
409- result . error ?. includes ( 'not found' ) ||
410- result . error ?. includes ( 'does not exist' )
411- ) {
412- // 明确的文件不存在错误
413- changed = this . addToSet ( facts . filesystem . nonExistentPaths , path ) || changed ;
414- changed = this . removeFromSet ( facts . filesystem . existingFiles , path ) || changed ;
415- }
416- break ;
417- }
418- case 'list_directory' : {
419- const path = params . path as string ;
420- // 🔧 修复:同样检查 skipped 字段
421- if ( result . success && ! result . skipped && Array . isArray ( result . entries ) ) {
422- changed = this . addToSet ( facts . filesystem . existingDirectories , path ) || changed ;
423-
424- // 🔧 关键修复:从目录内容推断文件存在性
425- // list_directory 返回的 entries 是 FileInfo[] 对象数组
426- // FileInfo = { name: string, path: string, type: 'file' | 'directory', size?, modifiedAt? }
427- const entries = result . entries as Array < { name : string ; path : string ; type : string } > ;
428-
429- // 存储路径字符串用于 directoryContents
430- changed =
431- this . setStringArrayMap (
432- facts . filesystem . directoryContents ,
433- path ,
434- entries . map ( ( e ) => e . path ) ,
435- ) || changed ;
436-
437- // 将目录中的文件/子目录添加到相应的集合
438- for ( const entry of entries ) {
439- if ( entry . type === 'file' ) {
440- changed = this . addToSet ( facts . filesystem . existingFiles , entry . path ) || changed ;
441- changed =
442- this . removeFromSet ( facts . filesystem . nonExistentPaths , entry . path ) || changed ;
443- } else if ( entry . type === 'directory' ) {
444- changed = this . addToSet ( facts . filesystem . existingDirectories , entry . path ) || changed ;
445- changed =
446- this . removeFromSet ( facts . filesystem . nonExistentPaths , entry . path ) || changed ;
447- }
448- }
449- } else if ( result . skipped || result . error ?. includes ( 'not found' ) ) {
450- changed = this . addToSet ( facts . filesystem . nonExistentPaths , path ) || changed ;
451- }
452- break ;
453- }
454- case 'search_code' : {
455- if ( ! result . success ) {
456- break ;
457- }
458-
459- const files = new Set < string > ( ) ;
460-
461- if ( Array . isArray ( result . files ) ) {
462- for ( const file of result . files ) {
463- if ( typeof file === 'string' ) {
464- files . add ( file ) ;
465- }
466- }
467- }
468-
469- if ( Array . isArray ( result . matches ) ) {
470- for ( const match of result . matches as Array < { file ?: unknown } > ) {
471- if ( typeof match . file === 'string' ) {
472- files . add ( match . file ) ;
473- }
474- }
475- }
476-
477- for ( const file of files ) {
478- changed = this . addToSet ( facts . filesystem . existingFiles , file ) || changed ;
479- changed = this . removeFromSet ( facts . filesystem . nonExistentPaths , file ) || changed ;
480-
481- for ( const parent of parentDirectoriesForPath ( file ) ) {
482- changed = this . addToSet ( facts . filesystem . existingDirectories , parent ) || changed ;
483- changed = this . removeFromSet ( facts . filesystem . nonExistentPaths , parent ) || changed ;
484- }
485- }
486- break ;
487- }
488- }
489-
490- if ( changed ) {
491- this . bumpFactsRevision ( facts ) ;
313+ if ( updateFilesystemFactsFromToolResult ( context . facts , toolName , params , result ) ) {
314+ this . bumpFactsRevision ( context . facts ) ;
492315 }
493316 }
494317
0 commit comments