@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 CHANGED
@@ -200,7 +200,7 @@ program
200
200
  type: 'confirm',
201
201
  name: 'jira_enabled',
202
202
  message: 'Enable Jira integration?',
203
- default: options.jira || config.jira_enabled
203
+ default: options.jira === true ? true : (config.jira_enabled || false)
204
204
  },
205
205
  {
206
206
  type: 'input',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/workflow",
3
- "version": "4.33.0",
3
+ "version": "4.34.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-24T12:11:50.565Z",
3
+ "buildDate": "2026-01-24T12:20:16.212Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -5,7 +5,9 @@ import fs from "fs/promises"
5
5
  /**
6
6
  * File Indexer Plugin
7
7
  *
8
- * Automatically reindexes changed files for semantic search.
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