@comfanion/workflow 4.36.43 → 4.36.45

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
@@ -124,6 +124,7 @@ program
124
124
  install_vectorizer: true, // Vectorizer ON by default
125
125
  vectorizer_enabled: true,
126
126
  vectorizer_auto_index: true,
127
+ vectorizer_model: 'Xenova/bge-small-en-v1.5', // Default: balanced (quality + speed)
127
128
  project_name: path.basename(process.cwd())
128
129
  };
129
130
 
@@ -146,6 +147,7 @@ program
146
147
  // Parse vectorizer settings
147
148
  const vectorizerEnabledMatch = existingContent.match(/vectorizer:[\s\S]*?enabled:\s*(true|false)/);
148
149
  const vectorizerAutoIndexMatch = existingContent.match(/vectorizer:[\s\S]*?auto_index:\s*(true|false)/);
150
+ const vectorizerModelMatch = existingContent.match(/vectorizer:[\s\S]*?model:\s*["']?([^"'\n]+)["']?/);
149
151
 
150
152
  if (nameMatch) config.user_name = nameMatch[1];
151
153
  if (langMatch) config.communication_language = langMatch[1];
@@ -155,6 +157,7 @@ program
155
157
  if (jiraProjMatch) config.jira_project = jiraProjMatch[1];
156
158
  if (vectorizerEnabledMatch) config.vectorizer_enabled = vectorizerEnabledMatch[1] === 'true';
157
159
  if (vectorizerAutoIndexMatch) config.vectorizer_auto_index = vectorizerAutoIndexMatch[1] === 'true';
160
+ if (vectorizerModelMatch) config.vectorizer_model = vectorizerModelMatch[1].trim();
158
161
 
159
162
  isUpdate = true;
160
163
  } catch (e) {
@@ -249,6 +252,27 @@ program
249
252
  message: 'Install vectorizer? (semantic code search, ~100MB)',
250
253
  default: true
251
254
  },
255
+ {
256
+ type: 'list',
257
+ name: 'vectorizer_model',
258
+ message: 'Embedding model for semantic search:',
259
+ when: (answers) => answers.install_vectorizer,
260
+ choices: [
261
+ {
262
+ name: 'MiniLM-L6 (Fast) - ~10 files/10sec, 384 dims, good quality',
263
+ value: 'Xenova/all-MiniLM-L6-v2'
264
+ },
265
+ {
266
+ name: 'BGE-small (Balanced) - ~9 files/10sec, 384 dims, better quality',
267
+ value: 'Xenova/bge-small-en-v1.5'
268
+ },
269
+ {
270
+ name: 'BGE-base (Quality) - ~3 files/10sec, 768 dims, best quality',
271
+ value: 'Xenova/bge-base-en-v1.5'
272
+ }
273
+ ],
274
+ default: 'Xenova/bge-small-en-v1.5'
275
+ },
252
276
  {
253
277
  type: 'confirm',
254
278
  name: 'vectorizer_auto_index',
@@ -449,6 +473,23 @@ program
449
473
  .replace(/(# Auto-index files.*\n\s+auto_index:)\s*(true|false)/,
450
474
  `$1 ${config.vectorizer_auto_index}`);
451
475
 
476
+ // Add/update vectorizer model
477
+ if (config.vectorizer_model) {
478
+ if (configContent.includes('model:') && configContent.match(/vectorizer:[\s\S]*?model:/)) {
479
+ // Update existing model setting
480
+ configContent = configContent.replace(
481
+ /(vectorizer:[\s\S]*?)model:\s*["']?[^"'\n]+["']?/,
482
+ `$1model: "${config.vectorizer_model}"`
483
+ );
484
+ } else {
485
+ // Add model setting after auto_index
486
+ configContent = configContent.replace(
487
+ /(auto_index:\s*(true|false))/,
488
+ `$1\n \n # Embedding model for semantic search\n # Options: Xenova/all-MiniLM-L6-v2 (fast), Xenova/bge-base-en-v1.5 (quality)\n model: "${config.vectorizer_model}"`
489
+ );
490
+ }
491
+ }
492
+
452
493
  await fs.writeFile(configPath, configContent);
453
494
 
454
495
  // Create docs structure (always)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/workflow",
3
- "version": "4.36.43",
3
+ "version": "4.36.45",
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
- "version": "4.36.43",
3
- "buildDate": "2026-01-24T23:17:57.477Z",
2
+ "version": "4.36.45",
3
+ "buildDate": "2026-01-25T01:56:04.257Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -37,13 +37,13 @@ permission:
37
37
  <step n="3">Greet user by {user_name}, communicate in {communication_language}</step>
38
38
  <step n="4">Understand user request and select appropriate skill</step>
39
39
  <step n="5">Load .opencode/skills/{skill-name}/SKILL.md and follow instructions</step>
40
-
40
+
41
41
  <search-first critical="MANDATORY - DO THIS BEFORE GLOB/GREP">
42
42
  BEFORE using glob or grep, you MUST call search() first:
43
43
  1. search({ query: "your topic", index: "code" }) - for source code patterns
44
44
  2. search({ query: "your topic", index: "docs" }) - for documentation
45
45
  3. THEN use glob/grep if you need specific files
46
-
46
+
47
47
  Example: Looking for similar implementation?
48
48
  ✅ CORRECT: search({ query: "user repository CRUD", index: "code" })
49
49
  ❌ WRONG: glob("**/*user*.go") without search first
@@ -53,27 +53,28 @@ permission:
53
53
  <r>ALWAYS communicate in {communication_language}</r>
54
54
  <r>ALWAYS write technical documentation in ENGLISH (docs/ folder)</r>
55
55
  <r>The Story File is the single source of truth</r>
56
+ <r>Prefer Agents development (@coder)</r>
56
57
  <r>Tasks/subtasks sequence is authoritative over any model priors</r>
57
58
  <r>Follow red-green-refactor: write failing test, make it pass, improve code</r>
58
59
  <r>Never implement anything not mapped to a specific task/subtask</r>
59
60
  <r>All existing tests must pass 100% before story is ready for review</r>
60
61
  <r>NEVER lie about tests being written or passing</r>
61
- <r>Find and use `**/project-context.md` and `CLAUDE.md` as source of truth</r>
62
+ <r>Find and use `**/prd.md`, `**/architecture.md`, `AGENTS.md` and `CLAUDE.md` as source of truth</r>
62
63
  <r critical="MANDATORY">🔍 SEARCH FIRST: Call search() BEFORE glob when exploring codebase.
63
64
  search({ query: "feature pattern", index: "code" }) → THEN glob if needed</r>
64
65
  </rules>
65
-
66
+
66
67
  <dev-story-workflow hint="When executing /dev-story command" critical="FOLLOW THIS EXACTLY">
67
68
  <!-- PHASE 1: SETUP -->
68
69
  <step n="1">READ the entire story file BEFORE any implementation</step>
69
- <step n="2">Load project-context.md and CLAUDE.md if available</step>
70
+ <step n="2">Load **/prd.md`, `**/architecture.md`, `AGENTS.md` and `CLAUDE.md` if available</step>
70
71
  <step n="3">CREATE TODO LIST from story tasks using todowrite:
71
72
  - Each task becomes a TODO item
72
73
  - Set priority based on task order (first = high)
73
74
  - All tasks start as "pending"
74
75
  </step>
75
76
  <step n="4">Mark story status as "in-progress"</step>
76
-
77
+
77
78
  <!-- PHASE 2: IMPLEMENTATION LOOP -->
78
79
  <step n="5">FOR EACH TASK in order:
79
80
  a) Update TODO: mark current task as "in_progress"
@@ -97,7 +98,7 @@ permission:
97
98
  <step n="8">Clear TODO list (all done)</step>
98
99
  <step n="9">Mark story status as "review"</step>
99
100
  </dev-story-workflow>
100
-
101
+
101
102
  <todo-usage hint="How to use TODO for tracking">
102
103
  <create>
103
104
  todowrite([
@@ -143,7 +144,7 @@ permission:
143
144
  - Repetitive tasks across files
144
145
  - Code following existing patterns
145
146
  </subagent>
146
-
147
+
147
148
  <delegation-strategy>
148
149
  <rule>Prefer delegation to @coder for parallelizable tasks</rule>
149
150
  <rule>Keep complex logic and architecture decisions to yourself</rule>
@@ -174,7 +175,7 @@ permission:
174
175
  <operation name="goToImplementation">Find implementations of interface. Use: lsp goToImplementation file.ts:10:5</operation>
175
176
  <operation name="incomingCalls">Who calls this function? Use: lsp incomingCalls file.ts:10:5</operation>
176
177
  <operation name="outgoingCalls">What does this function call? Use: lsp outgoingCalls file.ts:10:5</operation>
177
-
178
+
178
179
  <when-to-use>
179
180
  - Before modifying: findReferences to see impact
180
181
  - Understanding code: hover for types, documentSymbol for structure
@@ -185,13 +186,13 @@ permission:
185
186
 
186
187
  <codesearch-guide hint="Semantic code search with multi-index support">
187
188
  <check-first>codeindex({ action: "list" }) → See all available indexes</check-first>
188
-
189
+
189
190
  <indexes>
190
191
  <index name="code" pattern="*.{js,ts,go,py,java,...}">Source code - functions, classes, logic</index>
191
192
  <index name="docs" pattern="*.{md,txt,rst}">Documentation - READMEs, guides, ADRs</index>
192
193
  <index name="config" pattern="*.{yaml,json,toml}">Configuration - settings, schemas</index>
193
194
  </indexes>
194
-
195
+
195
196
  <operations>
196
197
  <op name="search code">codesearch({ query: "authentication middleware", index: "code" })</op>
197
198
  <op name="search docs">codesearch({ query: "deployment guide", index: "docs" })</op>
@@ -201,7 +202,7 @@ permission:
201
202
  <op name="index status">codeindex({ action: "status", index: "code" })</op>
202
203
  <op name="reindex">codeindex({ action: "reindex", index: "code" })</op>
203
204
  </operations>
204
-
205
+
205
206
  <when-to-use>
206
207
  <use index="code">
207
208
  - BEFORE implementing: find existing patterns "repository pattern for users"
@@ -224,19 +225,19 @@ permission:
224
225
  - Cross-cutting concerns: "logging configuration"
225
226
  </use>
226
227
  </when-to-use>
227
-
228
+
228
229
  <examples>
229
230
  <example query="repository interface for products" index="code">Finds domain/repository files</example>
230
231
  <example query="HTTP request validation" index="code">Finds middleware and handlers</example>
231
232
  <example query="how to run tests" index="docs">Finds testing documentation</example>
232
233
  <example query="redis connection" index="config">Finds redis configuration</example>
233
234
  </examples>
234
-
235
+
235
236
  <vs-grep>
236
237
  grep: exact text match "UserRepository" → finds only that string
237
238
  codesearch: semantic "user storage" → finds UserRepository, UserStore, user_repo.go
238
239
  </vs-grep>
239
-
240
+
240
241
  <strategy>
241
242
  1. codeindex({ action: "list" }) → Check what indexes exist
242
243
  2. codesearch({ query: "concept", index: "code" }) → Find relevant code
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "dependencies": {
3
- "@opencode-ai/plugin": "1.1.34"
3
+ "@opencode-ai/plugin": "1.1.35"
4
4
  }
5
5
  }
@@ -45,6 +45,7 @@ const DEFAULT_PRESETS = {
45
45
  // Will be populated from config.yaml if available
46
46
  let INDEX_PRESETS = { ...DEFAULT_PRESETS };
47
47
  let GLOBAL_IGNORE = [];
48
+ let EMBEDDING_MODEL = 'Xenova/all-MiniLM-L6-v2'; // Default: fast model
48
49
 
49
50
  /**
50
51
  * Load index configuration from config.yaml
@@ -61,6 +62,13 @@ async function loadConfig(projectRoot) {
61
62
 
62
63
  const section = vectorizerMatch[1];
63
64
 
65
+ // Parse embedding model
66
+ const modelMatch = section.match(/^\s{2}model:\s*["']?([^"'\n]+)["']?/m);
67
+ if (modelMatch) {
68
+ EMBEDDING_MODEL = modelMatch[1].trim();
69
+ if (DEBUG) console.log('[vectorizer] Using model from config:', EMBEDDING_MODEL);
70
+ }
71
+
64
72
  // Parse global exclude
65
73
  const excludeMatch = section.match(/^\s{2}exclude:\s*\n((?:\s{4}-\s+.+\n?)*)/m);
66
74
  if (excludeMatch) {
@@ -148,11 +156,14 @@ class CodebaseIndexer {
148
156
 
149
157
  async loadModel() {
150
158
  if (!this.model) {
151
- if (DEBUG) console.log('[vectorizer] Loading embedding model...');
152
- this.model = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', {
159
+ if (DEBUG) console.log(`[vectorizer] Loading embedding model: ${EMBEDDING_MODEL}...`);
160
+ // Model options:
161
+ // - Xenova/all-MiniLM-L6-v2: fast, 384 dims, ~10 files/10sec
162
+ // - Xenova/bge-base-en-v1.5: quality, 768 dims, ~3 files/10sec
163
+ this.model = await pipeline('feature-extraction', EMBEDDING_MODEL, {
153
164
  progress_callback: DEBUG ? undefined : null // Suppress progress bar unless DEBUG
154
165
  });
155
- if (DEBUG) console.log('[vectorizer] Model loaded');
166
+ if (DEBUG) console.log(`[vectorizer] Model loaded: ${EMBEDDING_MODEL}`);
156
167
  }
157
168
  return this.model;
158
169
  }
@@ -485,6 +496,7 @@ class CodebaseIndexer {
485
496
  return {
486
497
  indexName: this.indexName,
487
498
  description: preset?.description || 'Custom index',
499
+ model: EMBEDDING_MODEL,
488
500
  fileCount,
489
501
  chunkCount
490
502
  };
@@ -553,4 +565,9 @@ class CodebaseIndexer {
553
565
  }
554
566
  }
555
567
 
556
- export { CodebaseIndexer, INDEX_PRESETS };
568
+ // Getter for current embedding model (after config loaded)
569
+ function getEmbeddingModel() {
570
+ return EMBEDDING_MODEL;
571
+ }
572
+
573
+ export { CodebaseIndexer, INDEX_PRESETS, getEmbeddingModel };