33 */
44
55import path from 'path' ;
6- import type { Memory } from './types/index.js' ;
6+ import type { Memory , MemoryScope } from './types/index.js' ;
77import { CODEBASE_CONTEXT_DIRNAME , MEMORY_FILENAME } from './constants/codebase-context.js' ;
88import {
99 appendMemoryFile ,
10+ buildMemoryIdentityParts ,
1011 readMemoriesFile ,
1112 removeMemory ,
1213 filterMemories ,
14+ normalizeMemoryScope ,
1315 withConfidence
1416} from './memory/store.js' ;
1517
@@ -45,7 +47,7 @@ export async function handleMemoryCli(args: string[]): Promise<void> {
4547 const listUsage =
4648 'Usage: codebase-context memory list [--category <cat>] [--type <type>] [--query <text>] [--json]' ;
4749 const addUsage =
48- 'Usage: codebase-context memory add --type <type> --category <category> --memory <text> --reason <text> [--json]' ;
50+ 'Usage: codebase-context memory add --type <type> --category <category> --memory <text> --reason <text> [--scope-kind global|file|symbol] [--scope-file <path>] [--scope-symbol <name>] [-- json]' ;
4951 const removeUsage = 'Usage: codebase-context memory remove <id> [--json]' ;
5052
5153 const exitWithUsageError = ( message : string , usage ?: string ) : never => {
@@ -134,6 +136,13 @@ export async function handleMemoryCli(args: string[]): Promise<void> {
134136 const staleTag = m . stale ? ' [STALE]' : '' ;
135137 console . log ( `[${ m . id } ] ${ m . type } /${ m . category } : ${ m . memory } ${ staleTag } ` ) ;
136138 console . log ( ` Reason: ${ m . reason } ` ) ;
139+ if ( m . scope && m . scope . kind !== 'global' ) {
140+ if ( m . scope . kind === 'file' ) {
141+ console . log ( ` Scope: file ${ m . scope . file } ` ) ;
142+ } else {
143+ console . log ( ` Scope: symbol ${ m . scope . file } #${ m . scope . symbol } ` ) ;
144+ }
145+ }
137146 console . log ( ` Date: ${ m . date } | Confidence: ${ m . effectiveConfidence } ` ) ;
138147 console . log ( '' ) ;
139148 }
@@ -145,6 +154,9 @@ export async function handleMemoryCli(args: string[]): Promise<void> {
145154 let category : CliMemoryCategory | undefined ;
146155 let memory : string | undefined ;
147156 let reason : string | undefined ;
157+ let scopeKind : MemoryScope [ 'kind' ] | undefined ;
158+ let scopeFile : string | undefined ;
159+ let scopeSymbol : string | undefined ;
148160
149161 for ( let i = 1 ; i < args . length ; i ++ ) {
150162 if ( args [ i ] === '--type' ) {
@@ -197,6 +209,34 @@ export async function handleMemoryCli(args: string[]): Promise<void> {
197209 }
198210 reason = value ;
199211 i ++ ;
212+ } else if ( args [ i ] === '--scope-kind' ) {
213+ const value = args [ i + 1 ] ;
214+ if ( ! value || value . startsWith ( '--' ) ) {
215+ exitWithUsageError ( 'Error: --scope-kind requires a value.' , addUsage ) ;
216+ }
217+ if ( value === 'global' || value === 'file' || value === 'symbol' ) {
218+ scopeKind = value ;
219+ } else {
220+ exitWithUsageError (
221+ 'Error: invalid --scope-kind. Allowed: global, file, symbol.' ,
222+ addUsage
223+ ) ;
224+ }
225+ i ++ ;
226+ } else if ( args [ i ] === '--scope-file' ) {
227+ const value = args [ i + 1 ] ;
228+ if ( ! value || value . startsWith ( '--' ) ) {
229+ exitWithUsageError ( 'Error: --scope-file requires a value.' , addUsage ) ;
230+ }
231+ scopeFile = value ;
232+ i ++ ;
233+ } else if ( args [ i ] === '--scope-symbol' ) {
234+ const value = args [ i + 1 ] ;
235+ if ( ! value || value . startsWith ( '--' ) ) {
236+ exitWithUsageError ( 'Error: --scope-symbol requires a value.' , addUsage ) ;
237+ }
238+ scopeSymbol = value ;
239+ i ++ ;
200240 } else if ( args [ i ] === '--json' ) {
201241 // handled above
202242 }
@@ -210,9 +250,30 @@ export async function handleMemoryCli(args: string[]): Promise<void> {
210250 const requiredCategory = category ;
211251 const requiredMemory = memory ;
212252 const requiredReason = reason ;
253+ const scope = normalizeMemoryScope ( {
254+ kind : scopeKind ,
255+ file : scopeFile ,
256+ symbol : scopeSymbol
257+ } ) ;
258+
259+ if ( scopeKind === 'file' && ! scope ) {
260+ exitWithUsageError ( 'Error: --scope-kind file requires --scope-file.' , addUsage ) ;
261+ }
262+ if ( scopeKind === 'symbol' && ! scope ) {
263+ exitWithUsageError (
264+ 'Error: --scope-kind symbol requires --scope-file and --scope-symbol.' ,
265+ addUsage
266+ ) ;
267+ }
213268
214269 const crypto = await import ( 'crypto' ) ;
215- const hashContent = `${ type } :${ requiredCategory } :${ requiredMemory } :${ requiredReason } ` ;
270+ const hashContent = buildMemoryIdentityParts ( {
271+ type,
272+ category : requiredCategory ,
273+ memory : requiredMemory ,
274+ reason : requiredReason ,
275+ scope
276+ } ) ;
216277 const hash = crypto . createHash ( 'sha256' ) . update ( hashContent ) . digest ( 'hex' ) ;
217278 const id = hash . substring ( 0 , 12 ) ;
218279
@@ -222,7 +283,8 @@ export async function handleMemoryCli(args: string[]): Promise<void> {
222283 category : requiredCategory ,
223284 memory : requiredMemory ,
224285 reason : requiredReason ,
225- date : new Date ( ) . toISOString ( )
286+ date : new Date ( ) . toISOString ( ) ,
287+ ...( scope && { scope } )
226288 } ;
227289 const result = await appendMemoryFile ( memoryPath , newMemory ) ;
228290
0 commit comments