@@ -51,6 +51,8 @@ export interface MemoryCatalogPayload {
5151 defaultIncludedFileIds : string [ ]
5252}
5353
54+ const MEMORY_INCLUDE_STATE_PATH = path . join ( os . homedir ( ) , '.openclaw' , 'agentclick-memory-includes.json' )
55+
5456function walkMarkdownFiles ( baseDir : string , options ?: { maxFiles ?: number } ) : string [ ] {
5557 const maxFiles = options ?. maxFiles ?? 200
5658 const output : string [ ] = [ ]
@@ -91,6 +93,23 @@ function safeRead(filePath: string, maxChars = 12000): string {
9193 }
9294}
9395
96+ function readIncludedMemoryPaths ( ) : string [ ] {
97+ try {
98+ if ( ! fs . existsSync ( MEMORY_INCLUDE_STATE_PATH ) ) return [ ]
99+ const raw = fs . readFileSync ( MEMORY_INCLUDE_STATE_PATH , 'utf-8' )
100+ const parsed = JSON . parse ( raw ) as { includedPaths ?: string [ ] }
101+ return ( parsed . includedPaths ?? [ ] ) . filter ( Boolean )
102+ } catch {
103+ return [ ]
104+ }
105+ }
106+
107+ function writeIncludedMemoryPaths ( paths : string [ ] ) : void {
108+ const dir = path . dirname ( MEMORY_INCLUDE_STATE_PATH )
109+ if ( ! fs . existsSync ( dir ) ) fs . mkdirSync ( dir , { recursive : true } )
110+ fs . writeFileSync ( MEMORY_INCLUDE_STATE_PATH , JSON . stringify ( { includedPaths : paths } , null , 2 ) , 'utf-8' )
111+ }
112+
94113function parseSections ( markdown : string ) : Array < { id : string ; title : string } > {
95114 const out : Array < { id : string ; title : string } > = [ ]
96115 const lines = markdown . split ( '\n' )
@@ -134,7 +153,11 @@ export function buildMemoryCatalog(input: {
134153 currentContextFiles ?: string [ ]
135154} ) : MemoryCatalogPayload {
136155 const projectRoot = input . projectRoot
137- const currentContextSet = new Set ( ( input . currentContextFiles ?? [ ] ) . map ( p => path . resolve ( projectRoot , p ) ) )
156+ const persistedIncludes = readIncludedMemoryPaths ( ) . map ( p => path . resolve ( p ) )
157+ const currentContextSet = new Set ( [
158+ ...persistedIncludes ,
159+ ...( input . currentContextFiles ?? [ ] ) . map ( p => path . resolve ( projectRoot , p ) ) ,
160+ ] )
138161 const relatedMarkdown = walkMarkdownFiles ( projectRoot , { maxFiles : 220 } )
139162 const projectMemoryFiles = relatedMarkdown . filter ( p => path . basename ( p ) . toLowerCase ( ) . includes ( 'memory' ) )
140163 const agentCacheFiles = collectAgentCacheMemoryFiles ( )
@@ -239,6 +262,43 @@ export function readMemoryFileContent(input: {
239262 }
240263}
241264
265+ export function includeMemoryFileInContext ( input : { projectRoot : string ; filePath : string } ) : { ok : boolean ; includedPaths : string [ ] } {
266+ const catalog = buildMemoryCatalog ( { projectRoot : input . projectRoot } )
267+ const target = catalog . files . find ( f => path . resolve ( f . path ) === path . resolve ( input . filePath ) )
268+ if ( ! target ) return { ok : false , includedPaths : readIncludedMemoryPaths ( ) }
269+ const current = new Set ( readIncludedMemoryPaths ( ) . map ( p => path . resolve ( p ) ) )
270+ current . add ( path . resolve ( target . path ) )
271+ const next = Array . from ( current . values ( ) ) . sort ( )
272+ writeIncludedMemoryPaths ( next )
273+ return { ok : true , includedPaths : next }
274+ }
275+
276+ export function removeMemoryFileFromContext ( input : { projectRoot : string ; filePath : string } ) : { ok : boolean ; includedPaths : string [ ] } {
277+ const catalog = buildMemoryCatalog ( { projectRoot : input . projectRoot } )
278+ const target = catalog . files . find ( f => path . resolve ( f . path ) === path . resolve ( input . filePath ) )
279+ if ( ! target ) return { ok : false , includedPaths : readIncludedMemoryPaths ( ) }
280+ const current = new Set ( readIncludedMemoryPaths ( ) . map ( p => path . resolve ( p ) ) )
281+ current . delete ( path . resolve ( target . path ) )
282+ const next = Array . from ( current . values ( ) ) . sort ( )
283+ writeIncludedMemoryPaths ( next )
284+ return { ok : true , includedPaths : next }
285+ }
286+
287+ export function deleteMemoryFile ( input : { projectRoot : string ; filePath : string } ) : { ok : boolean ; deletedPath ?: string ; reason ?: string } {
288+ const catalog = buildMemoryCatalog ( { projectRoot : input . projectRoot } )
289+ const target = catalog . files . find ( f => path . resolve ( f . path ) === path . resolve ( input . filePath ) )
290+ if ( ! target ) return { ok : false , reason : 'File not found in memory catalog' }
291+ try {
292+ fs . unlinkSync ( target . path )
293+ } catch ( err ) {
294+ return { ok : false , reason : err instanceof Error ? err . message : String ( err ) }
295+ }
296+ const current = new Set ( readIncludedMemoryPaths ( ) . map ( p => path . resolve ( p ) ) )
297+ current . delete ( path . resolve ( target . path ) )
298+ writeIncludedMemoryPaths ( Array . from ( current . values ( ) ) . sort ( ) )
299+ return { ok : true , deletedPath : target . path }
300+ }
301+
242302export function buildMemoryReviewPayload ( input : {
243303 projectRoot : string
244304 currentContextFiles ?: string [ ]
0 commit comments