@@ -14,47 +14,59 @@ import { searchSnippets } from '../retriv/index.ts'
1414/** Collect search.db paths for packages installed in the current project (from skilld-lock.yaml) */
1515export function findPackageDbs ( packageFilter ?: string ) : string [ ] {
1616 const cwd = process . cwd ( )
17+ const lock = readProjectLock ( cwd )
18+ if ( ! lock )
19+ return [ ]
20+ return filterLockDbs ( lock , packageFilter )
21+ }
1722
18- // Try shared dir first
23+ /** Read the project's skilld-lock.yaml (shared dir or agent skills dir) */
24+ function readProjectLock ( cwd : string ) : ReturnType < typeof readLock > {
1925 const shared = getSharedSkillsDir ( cwd )
2026 if ( shared ) {
2127 const lock = readLock ( shared )
2228 if ( lock )
23- return filterLockDbs ( lock , packageFilter )
29+ return lock
2430 }
25-
2631 const agent = detectTargetAgent ( )
2732 if ( ! agent )
28- return [ ]
33+ return null
34+ return readLock ( `${ cwd } /${ agents [ agent ] . skillsDir } ` )
35+ }
2936
30- const skillsDir = `${ cwd } /${ agents [ agent ] . skillsDir } `
31- const lock = readLock ( skillsDir )
37+ /** List installed package names from the project lockfile */
38+ export function listLockPackages ( cwd : string = process . cwd ( ) ) : string [ ] {
39+ const lock = readProjectLock ( cwd )
3240 if ( ! lock )
3341 return [ ]
34-
35- return filterLockDbs ( lock , packageFilter )
42+ return [ ...new Set ( Object . values ( lock . skills ) . map ( s => s . packageName ) . filter ( Boolean ) as string [ ] ) ]
3643}
3744
3845function filterLockDbs ( lock : ReturnType < typeof readLock > , packageFilter ?: string ) : string [ ] {
3946 if ( ! lock )
4047 return [ ]
41- const normalize = ( s : string ) => s . toLowerCase ( ) . replace ( / [ - _ @ / ] / g, '' )
48+ const tokenize = ( s : string ) => s . toLowerCase ( ) . replace ( / @ / g, '' ) . split ( / [ - _ / ] + / ) . filter ( Boolean )
4249
4350 return Object . values ( lock . skills )
4451 . filter ( ( info ) => {
4552 if ( ! info . packageName || ! info . version )
4653 return false
4754 if ( ! packageFilter )
4855 return true
49- const f = normalize ( packageFilter )
50- return normalize ( info . packageName ) . includes ( f ) || normalize ( info . packageName ) === f
56+ // All tokens from filter must appear in package name tokens
57+ const filterTokens = tokenize ( packageFilter )
58+ const nameTokens = tokenize ( info . packageName )
59+ return filterTokens . every ( ft => nameTokens . some ( nt => nt . includes ( ft ) || ft . includes ( nt ) ) )
5160 } )
5261 . map ( ( info ) => {
5362 const exact = getPackageDbPath ( info . packageName ! , info . version ! )
5463 if ( existsSync ( exact ) )
5564 return exact
5665 // Fallback: find any cached version's search.db for this package
57- return findAnyPackageDb ( info . packageName ! )
66+ const fallback = findAnyPackageDb ( info . packageName ! )
67+ if ( fallback )
68+ p . log . warn ( `Using cached search index for ${ info . packageName } (v${ info . version } not indexed). Run \`skilld update ${ info . packageName } \` to re-index.` )
69+ return fallback
5870 } )
5971 . filter ( ( db ) : db is string => ! ! db )
6072}
@@ -112,10 +124,16 @@ export async function searchCommand(rawQuery: string, packageFilter?: string): P
112124 const dbs = findPackageDbs ( packageFilter )
113125
114126 if ( dbs . length === 0 ) {
115- if ( packageFilter )
116- p . log . warn ( `No docs indexed for "${ packageFilter } ". Run \`skilld add ${ packageFilter } \` first.` )
117- else
127+ if ( packageFilter ) {
128+ const available = listLockPackages ( )
129+ if ( available . length > 0 )
130+ p . log . warn ( `No docs indexed for "${ packageFilter } ". Available: ${ available . join ( ', ' ) } ` )
131+ else
132+ p . log . warn ( `No docs indexed for "${ packageFilter } ". Run \`skilld add ${ packageFilter } \` first.` )
133+ }
134+ else {
118135 p . log . warn ( 'No docs indexed yet. Run `skilld add <package>` first.' )
136+ }
119137 return
120138 }
121139
0 commit comments