@comfanion/workflow 4.6.0 → 4.6.1

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.6.0",
3
+ "version": "4.6.1",
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:20:56.596Z",
3
+ "buildDate": "2026-01-24T09:22:58.323Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -14,27 +14,13 @@
14
14
  import { tool } from "@opencode-ai/plugin"
15
15
  import path from "path"
16
16
  import fs from "fs/promises"
17
- import { glob } from "glob"
18
- import ignore from "ignore"
17
+ import { execSync } from "child_process"
19
18
 
20
- // Index presets (duplicated from vectorizer for independence)
19
+ // Index presets for documentation
21
20
  const INDEX_PRESETS: Record<string, { pattern: string; description: string }> = {
22
- code: {
23
- pattern: '**/*.{js,ts,jsx,tsx,mjs,cjs,py,go,rs,java,kt,swift,c,cpp,h,hpp,cs,rb,php,scala,clj}',
24
- description: 'Source code files'
25
- },
26
- docs: {
27
- pattern: '**/*.{md,mdx,txt,rst,adoc}',
28
- description: 'Documentation files'
29
- },
30
- config: {
31
- pattern: '**/*.{yaml,yml,json,toml,ini,env,xml}',
32
- description: 'Configuration files'
33
- },
34
- all: {
35
- pattern: '**/*.{js,ts,jsx,tsx,mjs,cjs,py,go,rs,java,kt,swift,c,cpp,h,hpp,cs,rb,php,scala,clj,md,mdx,txt,rst,adoc,yaml,yml,json,toml}',
36
- description: 'All supported files'
37
- }
21
+ code: { pattern: '**/*.{js,ts,go,py,...}', description: 'Source code files' },
22
+ docs: { pattern: '**/*.{md,txt,...}', description: 'Documentation files' },
23
+ config: { pattern: '**/*.{yaml,json,...}', description: 'Configuration files' },
38
24
  }
39
25
 
40
26
  export default tool({
@@ -54,7 +40,7 @@ Note: Initial indexing takes ~30s to load the embedding model.`,
54
40
 
55
41
  args: {
56
42
  action: tool.schema.enum(["status", "list", "reindex"]).describe("Action to perform"),
57
- index: tool.schema.string().optional().default("code").describe("Index name for status/reindex: code, docs, config"),
43
+ index: tool.schema.string().optional().default("code").describe("Index name: code, docs, config"),
58
44
  },
59
45
 
60
46
  async execute(args, context) {
@@ -72,83 +58,93 @@ Note: Initial indexing takes ~30s to load the embedding model.`,
72
58
 
73
59
  To install:
74
60
  \`\`\`bash
75
- npx opencode-workflow vectorizer install
61
+ npx @comfanion/workflow vectorizer install
76
62
  \`\`\`
77
63
 
78
64
  This will download the embedding model (~100MB) and set up the vector database.`
79
65
  }
80
66
 
81
- try {
82
- const vectorizerModule = path.join(vectorizerDir, "index.js")
83
- const { CodebaseIndexer, INDEX_PRESETS: PRESETS } = await import(`file://${vectorizerModule}`)
84
-
85
- // LIST: Show all indexes
86
- if (args.action === "list") {
87
- const tempIndexer = await new CodebaseIndexer(projectRoot, "code").init()
88
- const allStats = await tempIndexer.getAllStats()
67
+ const indexName = args.index || "code"
89
68
 
69
+ // LIST: Show all indexes
70
+ if (args.action === "list") {
71
+ try {
72
+ const result = execSync("node .opencode/vectorizer/list-indexes.js 2>/dev/null || echo '{}'", {
73
+ cwd: projectRoot,
74
+ encoding: "utf8",
75
+ timeout: 30000
76
+ })
77
+
78
+ // Fallback: read hashes files directly
90
79
  let output = `## Codebase Index Overview\n\n`
91
80
  output += `✅ **Vectorizer installed**\n\n`
92
-
93
- if (allStats.length === 0) {
81
+
82
+ const indexes: string[] = []
83
+ try {
84
+ const entries = await fs.readdir(vectorsDir, { withFileTypes: true })
85
+ for (const entry of entries) {
86
+ if (entry.isDirectory()) {
87
+ indexes.push(entry.name)
88
+ }
89
+ }
90
+ } catch {}
91
+
92
+ if (indexes.length === 0) {
94
93
  output += `⚠️ **No indexes created yet**\n\n`
95
94
  output += `Create indexes with:\n`
96
95
  output += `\`\`\`bash\n`
97
- output += `npx opencode-workflow index --index code # Source code\n`
98
- output += `npx opencode-workflow index --index docs # Documentation\n`
99
- output += `npx opencode-workflow index --index config # Config files\n`
100
- output += `\`\`\`\n\n`
96
+ output += `npx opencode-workflow index --index code\n`
97
+ output += `npx opencode-workflow index --index docs --dir docs/\n`
98
+ output += `\`\`\`\n`
101
99
  } else {
102
100
  output += `### Active Indexes\n\n`
103
- for (const stat of allStats) {
104
- output += `**📁 ${stat.indexName}** - ${stat.description}\n`
105
- output += ` Files: ${stat.fileCount}, Chunks: ${stat.chunkCount}\n\n`
101
+ for (const idx of indexes) {
102
+ try {
103
+ const hashesPath = path.join(vectorsDir, idx, "hashes.json")
104
+ const hashes = JSON.parse(await fs.readFile(hashesPath, "utf8"))
105
+ const fileCount = Object.keys(hashes).length
106
+ const desc = INDEX_PRESETS[idx]?.description || "Custom index"
107
+ output += `**📁 ${idx}** - ${desc}\n`
108
+ output += ` Files: ${fileCount}\n\n`
109
+ } catch {}
106
110
  }
107
111
  }
108
-
109
- output += `### Available Presets\n\n`
110
- for (const [name, preset] of Object.entries(PRESETS || INDEX_PRESETS) as [string, any][]) {
111
- const exists = allStats.find((s: any) => s.indexName === name)
112
- const status = exists ? "✅" : "⬜"
113
- output += `${status} **${name}**: ${preset.description}\n`
114
- }
115
-
116
- output += `\n### Usage\n`
112
+
113
+ output += `### Usage\n`
117
114
  output += `\`\`\`\n`
118
115
  output += `codesearch({ query: "your query", index: "code" })\n`
119
- output += `codesearch({ query: "deployment guide", index: "docs" })\n`
120
- output += `codesearch({ query: "api keys", searchAll: true })\n`
116
+ output += `codesearch({ query: "how to deploy", index: "docs" })\n`
121
117
  output += `\`\`\``
122
-
118
+
123
119
  return output
120
+
121
+ } catch (error: any) {
122
+ return `❌ Error listing indexes: ${error.message}`
124
123
  }
124
+ }
125
125
 
126
- // STATUS: Show specific index status
127
- if (args.action === "status") {
128
- const indexName = args.index || "code"
129
- const hashesFile = path.join(vectorsDir, indexName, "hashes.json")
130
-
131
- try {
132
- const indexer = await new CodebaseIndexer(projectRoot, indexName).init()
133
- const stats = await indexer.getStats()
134
-
135
- // Get sample files
136
- const hashesContent = await fs.readFile(hashesFile, "utf8")
137
- const hashes = JSON.parse(hashesContent)
138
- const sampleFiles = Object.keys(hashes).slice(0, 5)
126
+ // STATUS: Show specific index status
127
+ if (args.action === "status") {
128
+ const hashesFile = path.join(vectorsDir, indexName, "hashes.json")
129
+
130
+ try {
131
+ const hashesContent = await fs.readFile(hashesFile, "utf8")
132
+ const hashes = JSON.parse(hashesContent)
133
+ const fileCount = Object.keys(hashes).length
134
+ const sampleFiles = Object.keys(hashes).slice(0, 5)
135
+ const desc = INDEX_PRESETS[indexName]?.description || "Custom index"
139
136
 
140
- return `## Index Status: "${indexName}"
137
+ return `## Index Status: "${indexName}"
141
138
 
142
139
  ✅ **Vectorizer installed**
143
140
  ✅ **Index active**
144
141
 
145
- **Description:** ${stats.description}
146
- **Files indexed:** ${stats.fileCount}
147
- **Chunks:** ${stats.chunkCount}
142
+ **Description:** ${desc}
143
+ **Files indexed:** ${fileCount}
148
144
 
149
145
  **Sample indexed files:**
150
146
  ${sampleFiles.map(f => `- ${f}`).join("\n")}
151
- ${stats.fileCount > 5 ? `- ... and ${stats.fileCount - 5} more` : ""}
147
+ ${fileCount > 5 ? `- ... and ${fileCount - 5} more` : ""}
152
148
 
153
149
  **Usage:**
154
150
  \`\`\`
@@ -156,12 +152,12 @@ codesearch({ query: "your search query", index: "${indexName}" })
156
152
  \`\`\`
157
153
 
158
154
  To re-index:
159
- \`\`\`
160
- codeindex({ action: "reindex", index: "${indexName}" })
155
+ \`\`\`bash
156
+ npx opencode-workflow index --index ${indexName}
161
157
  \`\`\``
162
158
 
163
- } catch {
164
- return `## Index Status: "${indexName}"
159
+ } catch {
160
+ return `## Index Status: "${indexName}"
165
161
 
166
162
  ✅ **Vectorizer installed**
167
163
  ⚠️ **Index "${indexName}" not created yet**
@@ -169,87 +165,47 @@ codeindex({ action: "reindex", index: "${indexName}" })
169
165
  To create this index:
170
166
  \`\`\`bash
171
167
  npx opencode-workflow index --index ${indexName}
172
- \`\`\`
173
-
174
- Or use:
175
- \`\`\`
176
- codeindex({ action: "reindex", index: "${indexName}" })
168
+ # Or with specific directory:
169
+ npx opencode-workflow index --index ${indexName} --dir src/
177
170
  \`\`\``
178
- }
179
171
  }
172
+ }
180
173
 
181
- // REINDEX: Re-index specific index (do it directly, no shell)
182
- if (args.action === "reindex") {
183
- const indexName = args.index || "code"
184
-
185
- try {
186
- const indexer = await new CodebaseIndexer(projectRoot, indexName).init()
187
-
188
- // Get pattern from preset
189
- const preset = (PRESETS || INDEX_PRESETS)[indexName]
190
- const pattern = preset?.pattern || '**/*.{js,ts,py,go,md,yaml,json}'
191
-
192
- // Load .gitignore
193
- let ig = ignore()
194
- try {
195
- const gitignore = await fs.readFile(path.join(projectRoot, '.gitignore'), 'utf8')
196
- ig = ig.add(gitignore)
197
- } catch {}
198
- ig.add(['node_modules', '.git', 'dist', 'build', '.opencode/vectors', '.opencode/vectorizer'])
199
-
200
- // Find files
201
- const files = await glob(pattern, { cwd: projectRoot, nodir: true })
202
- const filtered = files.filter((f: string) => !ig.ignores(f))
203
-
204
- let indexed = 0
205
- let skipped = 0
206
-
207
- for (const file of filtered) {
208
- const filePath = path.join(projectRoot, file)
209
- try {
210
- const wasIndexed = await indexer.indexFile(filePath)
211
- if (wasIndexed) {
212
- indexed++
213
- } else {
214
- skipped++
215
- }
216
- } catch {
217
- // Skip files that can't be read
218
- }
219
- }
220
-
221
- // Unload model to free memory
222
- await indexer.unloadModel()
223
-
224
- const stats = await indexer.getStats()
174
+ // REINDEX: Re-index using CLI
175
+ if (args.action === "reindex") {
176
+ try {
177
+ execSync(`npx opencode-workflow index --index ${indexName}`, {
178
+ cwd: projectRoot,
179
+ encoding: "utf8",
180
+ timeout: 300000, // 5 min
181
+ stdio: "pipe"
182
+ })
183
+
184
+ // Get stats after indexing
185
+ const hashesFile = path.join(vectorsDir, indexName, "hashes.json")
186
+ const hashes = JSON.parse(await fs.readFile(hashesFile, "utf8"))
187
+ const fileCount = Object.keys(hashes).length
225
188
 
226
- return `## Re-indexing Complete ✅
189
+ return `## Re-indexing Complete ✅
227
190
 
228
191
  **Index:** ${indexName}
229
- **Description:** ${stats.description}
230
- **Files found:** ${filtered.length}
231
- **Files indexed:** ${indexed}
232
- **Files unchanged:** ${skipped}
233
- **Total chunks:** ${stats.chunkCount}
192
+ **Files indexed:** ${fileCount}
234
193
 
235
194
  You can now use semantic search:
236
195
  \`\`\`
237
196
  codesearch({ query: "your search query", index: "${indexName}" })
238
197
  \`\`\``
239
198
 
240
- } catch (error: any) {
241
- return `❌ Re-indexing failed: ${error.message}
199
+ } catch (error: any) {
200
+ return `❌ Re-indexing failed: ${error.message}
242
201
 
243
- Try:
244
- 1. Check if vectorizer is installed: \`npx opencode-workflow vectorizer status\`
245
- 2. Re-install vectorizer: \`npx opencode-workflow vectorizer install\``
246
- }
202
+ Try manually:
203
+ \`\`\`bash
204
+ npx opencode-workflow index --index ${indexName} --force
205
+ \`\`\``
247
206
  }
248
-
249
- return `Unknown action: ${args.action}. Use: status, list, or reindex`
250
-
251
- } catch (error: any) {
252
- return `❌ Error: ${error.message}`
253
207
  }
208
+
209
+ return `Unknown action: ${args.action}. Use: status, list, or reindex`
254
210
  },
255
211
  })