@comfanion/workflow 4.10.0 → 4.11.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/workflow",
3
- "version": "4.10.0",
3
+ "version": "4.11.0",
4
4
  "description": "Initialize OpenCode Workflow system for AI-assisted development with semantic code search",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "3.0.0",
3
- "buildDate": "2026-01-24T09:51:33.276Z",
3
+ "buildDate": "2026-01-24T10:06:05.371Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -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) {
@@ -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
  */