@comfanion/workflow 4.33.0 → 4.34.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/bin/cli.js +1 -1
- package/package.json +1 -1
- package/src/build-info.json +1 -1
- package/src/opencode/plugins/file-indexer.ts +66 -1
package/bin/cli.js
CHANGED
package/package.json
CHANGED
package/src/build-info.json
CHANGED
|
@@ -5,7 +5,9 @@ import fs from "fs/promises"
|
|
|
5
5
|
/**
|
|
6
6
|
* File Indexer Plugin
|
|
7
7
|
*
|
|
8
|
-
* Automatically
|
|
8
|
+
* Automatically manages semantic search indexes:
|
|
9
|
+
* - On session start/resume: freshen existing indexes (update stale files)
|
|
10
|
+
* - On file edit: queue file for reindexing (debounced)
|
|
9
11
|
*
|
|
10
12
|
* Configuration in .opencode/config.yaml:
|
|
11
13
|
* vectorizer:
|
|
@@ -108,6 +110,58 @@ async function isVectorizerInstalled(projectRoot: string): Promise<boolean> {
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
|
|
113
|
+
async function hasIndex(projectRoot: string, indexName: string): Promise<boolean> {
|
|
114
|
+
try {
|
|
115
|
+
await fs.access(path.join(projectRoot, ".opencode", "vectors", indexName, "hashes.json"))
|
|
116
|
+
return true
|
|
117
|
+
} catch {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Ensure index exists and is fresh on session start
|
|
124
|
+
*/
|
|
125
|
+
async function ensureIndexOnSessionStart(projectRoot: string, config: VectorizerConfig): Promise<void> {
|
|
126
|
+
if (!await isVectorizerInstalled(projectRoot)) {
|
|
127
|
+
debug('Session start: vectorizer not installed, skipping')
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const vectorizerModule = path.join(projectRoot, ".opencode", "vectorizer", "index.js")
|
|
133
|
+
const { CodebaseIndexer } = await import(`file://${vectorizerModule}`)
|
|
134
|
+
|
|
135
|
+
// Check each enabled index
|
|
136
|
+
for (const [indexName, indexConfig] of Object.entries(config.indexes)) {
|
|
137
|
+
if (!indexConfig.enabled) continue
|
|
138
|
+
|
|
139
|
+
const indexExists = await hasIndex(projectRoot, indexName)
|
|
140
|
+
|
|
141
|
+
if (!indexExists) {
|
|
142
|
+
// No index - need full indexing (but don't block session, just log)
|
|
143
|
+
debug(`Session start: index "${indexName}" not found, run: npx @comfanion/workflow index --index ${indexName}`)
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Index exists - freshen it (update stale files)
|
|
148
|
+
debug(`Session start: freshening index "${indexName}"...`)
|
|
149
|
+
const indexer = await new CodebaseIndexer(projectRoot, indexName).init()
|
|
150
|
+
const stats = await indexer.freshen()
|
|
151
|
+
|
|
152
|
+
if (stats.updated > 0 || stats.deleted > 0) {
|
|
153
|
+
debug(`Session start: ${indexName} - updated ${stats.updated}, deleted ${stats.deleted}`)
|
|
154
|
+
} else {
|
|
155
|
+
debug(`Session start: ${indexName} - index is fresh`)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await indexer.unloadModel()
|
|
159
|
+
}
|
|
160
|
+
} catch (e) {
|
|
161
|
+
debug(`Session start error: ${(e as Error).message}`)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
111
165
|
async function processPendingFiles(projectRoot: string, config: VectorizerConfig): Promise<void> {
|
|
112
166
|
if (pendingFiles.size === 0) return
|
|
113
167
|
|
|
@@ -196,10 +250,21 @@ export const FileIndexerPlugin: Plugin = async ({ directory }) => {
|
|
|
196
250
|
}, config.debounce_ms + 100)
|
|
197
251
|
}
|
|
198
252
|
|
|
253
|
+
// Track if we've already freshened this session
|
|
254
|
+
let sessionFreshened = false
|
|
255
|
+
|
|
199
256
|
return {
|
|
200
257
|
event: async (ctx) => {
|
|
201
258
|
const event = ctx.event
|
|
202
259
|
|
|
260
|
+
// Freshen index on session start/resume
|
|
261
|
+
if ((event.type === "session.started" || event.type === "session.resumed") && !sessionFreshened) {
|
|
262
|
+
sessionFreshened = true
|
|
263
|
+
debug(`${event.type}: checking indexes...`)
|
|
264
|
+
// Run async, don't block
|
|
265
|
+
ensureIndexOnSessionStart(directory, config).catch(e => debug(`Error: ${e.message}`))
|
|
266
|
+
}
|
|
267
|
+
|
|
203
268
|
if (event.type === "file.edited") {
|
|
204
269
|
const props = (event as any).properties || {}
|
|
205
270
|
const filePath = props.file || props.path || props.filePath
|