@comfanion/workflow 4.36.14 → 4.36.15

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.36.14",
3
+ "version": "4.36.15",
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-24T15:35:20.846Z",
3
+ "buildDate": "2026-01-24T15:52:25.533Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -235,28 +235,50 @@ vectorizer:
235
235
  # Debounce time in ms (wait before indexing after file change)
236
236
  debounce_ms: 1000
237
237
 
238
- # Indexes to maintain
238
+ # Indexes to maintain - each has pattern (what to include) and ignore (what to skip)
239
239
  indexes:
240
+ # Code index - source code files
240
241
  code:
241
242
  enabled: true
242
- extensions: ['.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs', '.java']
243
+ # Glob pattern for files to index
244
+ pattern: "**/*.{js,ts,jsx,tsx,mjs,cjs,py,go,rs,java,kt,swift,c,cpp,h,hpp,cs,rb,php,scala,clj}"
245
+ # Glob patterns to ignore
246
+ ignore:
247
+ - "**/node_modules/**"
248
+ - "**/.git/**"
249
+ - "**/dist/**"
250
+ - "**/build/**"
251
+ - "**/.opencode/**"
252
+ - "**/docs/**"
253
+ - "**/vendor/**"
254
+ - "**/__pycache__/**"
255
+ - "**/*.min.js"
256
+ - "**/*.bundle.js"
257
+
258
+ # Documentation index - markdown, text files
243
259
  docs:
244
260
  enabled: true
245
- extensions: ['.md', '.mdx', '.txt', '.rst']
261
+ # Only docs folder by default (change to "**/*.md" for all markdown)
262
+ pattern: "docs/**/*.{md,mdx,txt,rst,adoc}"
263
+ ignore: []
264
+
265
+ # Configuration index - yaml, json, toml
246
266
  config:
247
- enabled: false # Usually not needed
248
- extensions: ['.yaml', '.yml', '.json', '.toml']
267
+ enabled: false # Disabled by default
268
+ pattern: "**/*.{yaml,yml,json,toml,ini}"
269
+ ignore:
270
+ - "**/node_modules/**"
271
+ - "**/.git/**"
272
+ - "**/.opencode/**"
273
+ - "**/package-lock.json"
274
+ - "**/yarn.lock"
249
275
 
250
- # Directories to exclude from indexing
276
+ # Global exclude patterns (applied to ALL indexes, in addition to per-index ignore)
251
277
  exclude:
252
278
  - node_modules
253
279
  - .git
254
- - dist
255
- - build
256
280
  - .opencode/vectors
257
281
  - .opencode/vectorizer
258
- - vendor
259
- - __pycache__
260
282
 
261
283
  # =============================================================================
262
284
  # LSP (Language Server Protocol) - Code Intelligence
@@ -17,9 +17,9 @@ if (!DEBUG) {
17
17
  }
18
18
 
19
19
  /**
20
- * Index presets for different content types
20
+ * Default index presets (can be overridden by config.yaml)
21
21
  */
22
- const INDEX_PRESETS = {
22
+ const DEFAULT_PRESETS = {
23
23
  code: {
24
24
  pattern: '**/*.{js,ts,jsx,tsx,mjs,cjs,py,go,rs,java,kt,swift,c,cpp,h,hpp,cs,rb,php,scala,clj}',
25
25
  ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**', '**/.opencode/**', '**/docs/**', '**/vendor/**', '**/__pycache__/**'],
@@ -42,6 +42,82 @@ const INDEX_PRESETS = {
42
42
  }
43
43
  };
44
44
 
45
+ // Will be populated from config.yaml if available
46
+ let INDEX_PRESETS = { ...DEFAULT_PRESETS };
47
+ let GLOBAL_IGNORE = [];
48
+
49
+ /**
50
+ * Load index configuration from config.yaml
51
+ * @param {string} projectRoot - Project root directory
52
+ */
53
+ async function loadConfig(projectRoot) {
54
+ try {
55
+ const configPath = path.join(projectRoot, '.opencode', 'config.yaml');
56
+ const content = await fs.readFile(configPath, 'utf8');
57
+
58
+ // Parse vectorizer section from YAML
59
+ const vectorizerMatch = content.match(/^vectorizer:([\s\S]*?)(?=^[a-z]|\Z)/m);
60
+ if (!vectorizerMatch) return;
61
+
62
+ const section = vectorizerMatch[1];
63
+
64
+ // Parse global exclude
65
+ const excludeMatch = section.match(/^\s{2}exclude:\s*\n((?:\s{4}-\s+.+\n?)*)/m);
66
+ if (excludeMatch) {
67
+ GLOBAL_IGNORE = excludeMatch[1]
68
+ .split('\n')
69
+ .map(line => line.replace(/^\s*-\s*/, '').trim())
70
+ .filter(Boolean)
71
+ .map(p => p.includes('*') ? p : `**/${p}/**`);
72
+ }
73
+
74
+ // Parse indexes section
75
+ const indexesMatch = section.match(/^\s{2}indexes:\s*\n([\s\S]*?)(?=^\s{2}[a-z]|\s{2}exclude:|\Z)/m);
76
+ if (!indexesMatch) return;
77
+
78
+ const indexesSection = indexesMatch[1];
79
+
80
+ // Parse each index (code, docs, config)
81
+ for (const indexName of ['code', 'docs', 'config']) {
82
+ const indexRegex = new RegExp(`^\\s{4}${indexName}:\\s*\\n([\\s\\S]*?)(?=^\\s{4}[a-z]|\\Z)`, 'm');
83
+ const indexMatch = indexesSection.match(indexRegex);
84
+ if (!indexMatch) continue;
85
+
86
+ const indexSection = indexMatch[1];
87
+
88
+ // Parse enabled
89
+ const enabledMatch = indexSection.match(/^\s+enabled:\s*(true|false)/m);
90
+ const enabled = enabledMatch ? enabledMatch[1] === 'true' : true;
91
+
92
+ // Parse pattern
93
+ const patternMatch = indexSection.match(/^\s+pattern:\s*["']?([^"'\n]+)["']?/m);
94
+ const pattern = patternMatch ? patternMatch[1].trim() : DEFAULT_PRESETS[indexName]?.pattern;
95
+
96
+ // Parse ignore array
97
+ const ignoreMatch = indexSection.match(/^\s+ignore:\s*\n((?:\s+-\s+.+\n?)*)/m);
98
+ let ignore = [];
99
+ if (ignoreMatch) {
100
+ ignore = ignoreMatch[1]
101
+ .split('\n')
102
+ .map(line => line.replace(/^\s*-\s*/, '').replace(/["']/g, '').trim())
103
+ .filter(Boolean);
104
+ }
105
+
106
+ if (enabled && pattern) {
107
+ INDEX_PRESETS[indexName] = {
108
+ pattern,
109
+ ignore,
110
+ description: `${indexName} files from config.yaml`
111
+ };
112
+ }
113
+ }
114
+
115
+ if (DEBUG) console.log('[vectorizer] Loaded config:', { INDEX_PRESETS, GLOBAL_IGNORE });
116
+ } catch (e) {
117
+ if (DEBUG) console.log('[vectorizer] Using default presets (no config.yaml)');
118
+ }
119
+ }
120
+
45
121
  class CodebaseIndexer {
46
122
  /**
47
123
  * @param {string} projectRoot - Project root directory
@@ -55,9 +131,15 @@ class CodebaseIndexer {
55
131
  this.model = null;
56
132
  this.db = null;
57
133
  this.hashes = {};
134
+ this.configLoaded = false;
58
135
  }
59
136
 
60
137
  async init() {
138
+ // Load config on first init
139
+ if (!this.configLoaded) {
140
+ await loadConfig(this.root);
141
+ this.configLoaded = true;
142
+ }
61
143
  await fs.mkdir(this.cacheDir, { recursive: true });
62
144
  this.db = await lancedb.connect(path.join(this.cacheDir, 'lancedb'));
63
145
  await this.loadHashes();
@@ -219,10 +301,14 @@ class CodebaseIndexer {
219
301
  */
220
302
  async checkHealth(extraIgnore = []) {
221
303
  const { glob } = await import('glob');
222
- const preset = INDEX_PRESETS[this.indexName] || INDEX_PRESETS.code;
304
+ const preset = INDEX_PRESETS[this.indexName] || DEFAULT_PRESETS.code;
223
305
 
224
- // Combine preset ignore with extra ignore patterns
225
- const ignore = [...(preset.ignore || []), ...extraIgnore.map(p => `**/${p}/**`)];
306
+ // Combine: preset ignore + global ignore + extra ignore
307
+ const ignore = [
308
+ ...(preset.ignore || []),
309
+ ...GLOBAL_IGNORE,
310
+ ...extraIgnore.map(p => p.includes('*') ? p : `**/${p}/**`)
311
+ ];
226
312
 
227
313
  const expectedFiles = await glob(preset.pattern, {
228
314
  cwd: this.root,
@@ -295,10 +381,14 @@ class CodebaseIndexer {
295
381
  */
296
382
  async indexAll(onProgress = null, extraIgnore = []) {
297
383
  const { glob } = await import('glob');
298
- const preset = INDEX_PRESETS[this.indexName] || INDEX_PRESETS.code;
384
+ const preset = INDEX_PRESETS[this.indexName] || DEFAULT_PRESETS.code;
299
385
 
300
- // Combine preset ignore with extra ignore patterns
301
- const ignore = [...(preset.ignore || []), ...extraIgnore.map(p => `**/${p}/**`)];
386
+ // Combine: preset ignore + global ignore + extra ignore
387
+ const ignore = [
388
+ ...(preset.ignore || []),
389
+ ...GLOBAL_IGNORE,
390
+ ...extraIgnore.map(p => p.includes('*') ? p : `**/${p}/**`)
391
+ ];
302
392
 
303
393
  const files = await glob(preset.pattern, {
304
394
  cwd: this.root,