@comfanion/workflow 4.10.0 → 4.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/src/build-info.json
CHANGED
|
@@ -43,17 +43,25 @@ permission:
|
|
|
43
43
|
|
|
44
44
|
<activation critical="MANDATORY">
|
|
45
45
|
<step n="1">Receive exploration request from parent agent or user</step>
|
|
46
|
-
<step n="2">
|
|
47
|
-
<step n="3">
|
|
48
|
-
<step n="4">
|
|
46
|
+
<step n="2">codeindex({ action: "list" }) → Check if semantic indexes exist</step>
|
|
47
|
+
<step n="3">IF indexes exist → codesearch({ query: "concept" }) → Get 5-10 relevant files</step>
|
|
48
|
+
<step n="4">Read top results from codesearch</step>
|
|
49
|
+
<step n="5">ONLY if needed: use grep for exact string matches</step>
|
|
50
|
+
<step n="6">Return structured findings with file:line references</step>
|
|
49
51
|
|
|
50
52
|
<rules>
|
|
53
|
+
<r>CODESEARCH FIRST - Use semantic search before grep/glob!</r>
|
|
51
54
|
<r>READ-ONLY - Cannot write or edit files</r>
|
|
52
55
|
<r>No external calls - No network, no APIs</r>
|
|
53
56
|
<r>Fast response - Return findings quickly, don't over-analyze</r>
|
|
54
57
|
<r>Always cite file:line for findings</r>
|
|
55
58
|
<r>Return structured output format</r>
|
|
56
59
|
</rules>
|
|
60
|
+
|
|
61
|
+
<anti-pattern>
|
|
62
|
+
❌ WRONG: codeindex list → grep → glob → read 20 files
|
|
63
|
+
✅ RIGHT: codeindex list → codesearch → read 3-5 files
|
|
64
|
+
</anti-pattern>
|
|
57
65
|
</activation>
|
|
58
66
|
|
|
59
67
|
<persona>
|
|
@@ -119,14 +127,24 @@ permission:
|
|
|
119
127
|
</prefer-lsp-when>
|
|
120
128
|
</lsp-exploration>
|
|
121
129
|
|
|
122
|
-
<codesearch-exploration hint="
|
|
123
|
-
<critical>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
<codesearch-exploration hint="MANDATORY - USE SEMANTIC SEARCH FIRST">
|
|
131
|
+
<critical priority="HIGHEST">
|
|
132
|
+
⚠️ DO NOT USE grep/glob UNTIL you've tried codesearch!
|
|
133
|
+
|
|
134
|
+
WRONG: codeindex({ action: "list" }) → see indexes → grep anyway
|
|
135
|
+
RIGHT: codeindex({ action: "list" }) → see indexes → codesearch({ query: "..." })
|
|
136
|
+
|
|
137
|
+
codesearch returns 5-10 RELEVANT files
|
|
138
|
+
grep returns 100+ UNFILTERED matches - SLOW!
|
|
127
139
|
</critical>
|
|
128
140
|
|
|
129
|
-
<
|
|
141
|
+
<mandatory-workflow>
|
|
142
|
+
STEP 1: codeindex({ action: "list" }) → Check indexes
|
|
143
|
+
STEP 2: IF indexes exist → codesearch({ query: "your concept" }) → READ results
|
|
144
|
+
STEP 3: ONLY if codesearch fails → fall back to grep
|
|
145
|
+
|
|
146
|
+
NEVER skip step 2!
|
|
147
|
+
</mandatory-workflow>
|
|
130
148
|
|
|
131
149
|
<indexes hint="Different indexes for different content types">
|
|
132
150
|
<index name="code">Source code (*.go, *.ts, *.py) - functions, classes, logic</index>
|
|
@@ -181,16 +199,27 @@ permission:
|
|
|
181
199
|
- Regex pattern matching needed
|
|
182
200
|
</use-grep-when>
|
|
183
201
|
|
|
184
|
-
<exploration-strategy priority="MANDATORY">
|
|
185
|
-
1.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
202
|
+
<exploration-strategy priority="MANDATORY - FOLLOW THIS ORDER">
|
|
203
|
+
1. codeindex({ action: "list" }) → See what indexes exist
|
|
204
|
+
|
|
205
|
+
2. IMMEDIATELY after seeing indexes, USE THEM:
|
|
206
|
+
codesearch({ query: "category mapping logic", index: "code" })
|
|
207
|
+
→ Returns 5-10 relevant files with code snippets!
|
|
208
|
+
|
|
209
|
+
3. Read the codesearch results (top 3-5 files)
|
|
210
|
+
→ You now have the answer. Done!
|
|
211
|
+
|
|
212
|
+
4. ONLY use grep/glob for:
|
|
213
|
+
- Exact function name: grep "func CreateUser"
|
|
214
|
+
- Counting occurrences: grep -c "pattern"
|
|
215
|
+
- TODO/FIXME search
|
|
216
|
+
|
|
217
|
+
5. IF no indexes exist:
|
|
218
|
+
- Suggest: codeindex({ action: "reindex", index: "code" })
|
|
219
|
+
- Fall back to grep as last resort
|
|
220
|
+
|
|
221
|
+
⚠️ ANTI-PATTERN: codeindex list → grep → glob → read 20 files = WRONG!
|
|
222
|
+
✅ CORRECT: codeindex list → codesearch → read 5 files = FAST!
|
|
194
223
|
</exploration-strategy>
|
|
195
224
|
|
|
196
225
|
<efficiency-comparison>
|
|
@@ -43,6 +43,7 @@ Prerequisites: Run 'npx @comfanion/workflow index --index <name>' first.`,
|
|
|
43
43
|
index: tool.schema.string().optional().default("code").describe("Index to search: code, docs, config, or custom name"),
|
|
44
44
|
limit: tool.schema.number().optional().default(5).describe("Number of results to return (default: 5)"),
|
|
45
45
|
searchAll: tool.schema.boolean().optional().default(false).describe("Search all indexes instead of just one"),
|
|
46
|
+
freshen: tool.schema.boolean().optional().default(true).describe("Auto-update stale files before searching (default: true)"),
|
|
46
47
|
},
|
|
47
48
|
|
|
48
49
|
async execute(args, context) {
|
|
@@ -65,6 +66,14 @@ Prerequisites: Run 'npx @comfanion/workflow index --index <name>' first.`,
|
|
|
65
66
|
const limit = args.limit || 5
|
|
66
67
|
const indexName = args.index || "code"
|
|
67
68
|
|
|
69
|
+
// Auto-freshen stale files before searching
|
|
70
|
+
let freshenStats = { updated: 0 }
|
|
71
|
+
if (args.freshen !== false) {
|
|
72
|
+
const tempIndexer = await new CodebaseIndexer(projectRoot, args.index || "code").init()
|
|
73
|
+
freshenStats = await tempIndexer.freshen()
|
|
74
|
+
await tempIndexer.unloadModel() // Free memory after freshen
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
if (args.searchAll) {
|
|
69
78
|
// Search all indexes
|
|
70
79
|
const tempIndexer = await new CodebaseIndexer(projectRoot, "code").init()
|
|
@@ -76,8 +85,12 @@ Prerequisites: Run 'npx @comfanion/workflow index --index <name>' first.`,
|
|
|
76
85
|
|
|
77
86
|
for (const idx of indexes) {
|
|
78
87
|
const indexer = await new CodebaseIndexer(projectRoot, idx).init()
|
|
88
|
+
if (args.freshen !== false) {
|
|
89
|
+
await indexer.freshen()
|
|
90
|
+
}
|
|
79
91
|
const results = await indexer.search(args.query, limit)
|
|
80
92
|
allResults.push(...results.map((r: any) => ({ ...r, _index: idx })))
|
|
93
|
+
await indexer.unloadModel() // Free memory after each index search
|
|
81
94
|
}
|
|
82
95
|
|
|
83
96
|
// Sort by distance and take top N
|
|
@@ -96,6 +109,7 @@ Prerequisites: Run 'npx @comfanion/workflow index --index <name>' first.`,
|
|
|
96
109
|
const indexer = await new CodebaseIndexer(projectRoot, indexName).init()
|
|
97
110
|
const results = await indexer.search(args.query, limit)
|
|
98
111
|
allResults = results.map((r: any) => ({ ...r, _index: indexName }))
|
|
112
|
+
await indexer.unloadModel() // Free memory after search
|
|
99
113
|
}
|
|
100
114
|
|
|
101
115
|
if (allResults.length === 0) {
|
package/src/vectorizer/index.js
CHANGED
|
@@ -196,6 +196,54 @@ class CodebaseIndexer {
|
|
|
196
196
|
return results;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Freshen index - check for stale files and reindex only changed ones
|
|
201
|
+
* Returns { checked, updated, deleted } counts
|
|
202
|
+
*/
|
|
203
|
+
async freshen() {
|
|
204
|
+
let checked = 0;
|
|
205
|
+
let updated = 0;
|
|
206
|
+
let deleted = 0;
|
|
207
|
+
|
|
208
|
+
const indexedFiles = Object.keys(this.hashes);
|
|
209
|
+
|
|
210
|
+
for (const relPath of indexedFiles) {
|
|
211
|
+
checked++;
|
|
212
|
+
const filePath = path.join(this.root, relPath);
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
216
|
+
const currentHash = this.fileHash(content);
|
|
217
|
+
|
|
218
|
+
if (this.hashes[relPath] !== currentHash) {
|
|
219
|
+
// File changed - reindex it
|
|
220
|
+
await this.indexFile(filePath);
|
|
221
|
+
updated++;
|
|
222
|
+
}
|
|
223
|
+
} catch (e) {
|
|
224
|
+
// File deleted or unreadable - remove from index
|
|
225
|
+
delete this.hashes[relPath];
|
|
226
|
+
deleted++;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (deleted > 0) {
|
|
231
|
+
await this.saveHashes();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return { checked, updated, deleted };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Index a single file by path (convenience method)
|
|
239
|
+
*/
|
|
240
|
+
async indexSingleFile(filePath) {
|
|
241
|
+
const absPath = path.isAbsolute(filePath)
|
|
242
|
+
? filePath
|
|
243
|
+
: path.join(this.root, filePath);
|
|
244
|
+
return await this.indexFile(absPath);
|
|
245
|
+
}
|
|
246
|
+
|
|
199
247
|
/**
|
|
200
248
|
* Get indexing statistics for this index
|
|
201
249
|
*/
|