@comfanion/workflow 4.36.13 → 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/README.md CHANGED
@@ -1,15 +1,61 @@
1
1
  # @comfanion/workflow
2
2
 
3
- Initialize OpenCode Workflow system for AI-assisted development.
3
+ AI-assisted development workflow with **semantic code search**, agents, and structured documentation.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@comfanion/workflow.svg)](https://www.npmjs.com/package/@comfanion/workflow)
6
6
 
7
+ ## Features
8
+
9
+ - 🔍 **Semantic Code Search** - Find code by meaning, not just text (`"authentication logic"` → finds auth handlers)
10
+ - 🤖 **AI Agents** - Specialized personas (Analyst, PM, Architect, Developer) with skills
11
+ - 📝 **Structured Workflow** - PRD → Architecture → Epics → Stories → Implementation
12
+ - 🔄 **Auto-indexing** - Background indexing on startup with fun toast notifications
13
+ - 🎯 **Jira Integration** - Bidirectional sync with your project
14
+
7
15
  ## Quick Start
8
16
 
9
17
  ```bash
10
18
  npx @comfanion/workflow init
11
19
  ```
12
20
 
21
+ ## Semantic Code Search
22
+
23
+ Search your codebase by **meaning**, not just text matching:
24
+
25
+ ```bash
26
+ # In Claude Code / AI assistant:
27
+ /search "user authentication middleware" # Finds auth-related code
28
+ /search "database connection handling" # Finds DB setup
29
+ /search "error handling patterns" # Finds error handlers
30
+ ```
31
+
32
+ ### How It Works
33
+
34
+ 1. **Vectorizer** converts code into embeddings using local AI model
35
+ 2. **Indexes** are stored in `.opencode/vectors/` (code, docs, config)
36
+ 3. **Search** finds semantically similar code chunks
37
+ 4. **Auto-indexer** keeps indexes fresh on startup
38
+
39
+ ### Available Indexes
40
+
41
+ | Index | Files | Use Case |
42
+ |-------|-------|----------|
43
+ | `code` | `*.js, *.ts, *.py, *.go...` | Find functions, classes, logic |
44
+ | `docs` | `*.md, *.txt` | Find documentation, guides |
45
+ | `config` | `*.yaml, *.json` | Find configuration, settings |
46
+
47
+ ### Commands
48
+
49
+ ```bash
50
+ # Manual indexing
51
+ npx @comfanion/workflow index # Index all
52
+ npx @comfanion/workflow index --code # Index code only
53
+ npx @comfanion/workflow index --docs # Index docs only
54
+
55
+ # Check index status
56
+ npx @comfanion/workflow index --status
57
+ ```
58
+
13
59
  ## Installation
14
60
 
15
61
  ### NPX (recommended)
@@ -22,11 +68,15 @@ npx @comfanion/workflow init
22
68
 
23
69
  ```bash
24
70
  npm install -g @comfanion/workflow
25
- comfanion-workflow init
26
- # or
27
71
  opencode-workflow init
28
72
  ```
29
73
 
74
+ ### Alternative Package Name
75
+
76
+ ```bash
77
+ npx create-opencode-workflow init
78
+ ```
79
+
30
80
  ## Commands
31
81
 
32
82
  ### `init`
@@ -40,21 +90,13 @@ npx @comfanion/workflow init
40
90
  **Interactive prompts:**
41
91
 
42
92
  1. **Your name** - For personalized agent communication
43
- 2. **Communication language** - Ukrainian or English
93
+ 2. **Communication language** - Ukrainian, English, Russian
44
94
  3. **Development methodology** - TDD or STUB
45
- 4. **Jira integration** - Enable/disable
46
- 5. **Repository structure** - Create README, CONTRIBUTING, etc.
95
+ 4. **Vectorizer** - Enable semantic search
96
+ 5. **Jira integration** - Enable/disable
47
97
 
48
98
  **Flags:**
49
99
 
50
- ```bash
51
- # Skip prompts, use defaults
52
- npx @comfanion/workflow init -y
53
-
54
- # With specific options
55
- npx @comfanion/workflow init --tdd --jira --full
56
- ```
57
-
58
100
  | Flag | Description |
59
101
  |------|-------------|
60
102
  | `-y, --yes` | Skip prompts, use defaults |
@@ -65,12 +107,17 @@ npx @comfanion/workflow init --tdd --jira --full
65
107
 
66
108
  ### `update`
67
109
 
68
- Update `.opencode/` to latest version while preserving `config.yaml`.
110
+ Update `.opencode/` to latest version.
69
111
 
70
112
  ```bash
71
113
  npx @comfanion/workflow update
72
114
  ```
73
115
 
116
+ **Preserves:**
117
+ - ✅ Your `config.yaml` (with comments!)
118
+ - ✅ Vector indexes (`.opencode/vectors/`)
119
+ - ✅ Custom settings
120
+
74
121
  ### `doctor`
75
122
 
76
123
  Check installation health.
@@ -79,49 +126,102 @@ Check installation health.
79
126
  npx @comfanion/workflow doctor
80
127
  ```
81
128
 
82
- ### `config`
129
+ ### `vectorizer`
83
130
 
84
- Show current configuration.
131
+ Manage semantic search vectorizer.
85
132
 
86
133
  ```bash
87
- npx @comfanion/workflow config
134
+ npx @comfanion/workflow vectorizer install # Install dependencies
135
+ npx @comfanion/workflow vectorizer status # Check status
136
+ ```
137
+
138
+ ## Configuration
139
+
140
+ ### `config.yaml`
141
+
142
+ ```yaml
143
+ # User settings
144
+ user_name: "Developer"
145
+ communication_language: "en" # en, uk, ru
146
+
147
+ # Development
148
+ development:
149
+ methodology: tdd # tdd or stub
150
+
151
+ # Semantic Search
152
+ vectorizer:
153
+ enabled: true
154
+ auto_index: true # Auto-index on startup
155
+ debounce_ms: 5000
156
+ indexes:
157
+ code: { enabled: true }
158
+ docs: { enabled: true }
159
+ config: { enabled: false }
160
+ exclude:
161
+ - "node_modules/**"
162
+ - "dist/**"
163
+ - "*.min.js"
164
+
165
+ # Jira Integration
166
+ jira:
167
+ enabled: false
168
+ url: "https://your-domain.atlassian.net"
169
+ project_key: "PROJ"
88
170
  ```
89
171
 
90
172
  ## What Gets Created
91
173
 
92
- ### `.opencode/` (always)
174
+ ### `.opencode/`
93
175
 
94
176
  ```
95
177
  .opencode/
96
178
  ├── config.yaml # Your configuration
97
- ├── FLOW.yaml # Workflow definition (v3.0)
98
- ├── agents/ # Agent personas
99
- ├── skills/ # Knowledge modules with templates (25+)
100
- ├── workflows/ # Workflow instructions
101
- ├── checklists/ # Validation checklists
179
+ ├── FLOW.yaml # Workflow definition
180
+ ├── agents/ # AI agent personas
181
+ ├── analyst.md # Business Analyst
182
+ ├── pm.md # Product Manager
183
+ ├── architect.md # Solution Architect
184
+ │ └── dev.md # Senior Developer
185
+ ├── skills/ # Knowledge modules (25+)
186
+ ├── plugins/ # Auto-indexer plugin
187
+ ├── vectorizer/ # Semantic search engine
188
+ │ ├── index.js
189
+ │ └── package.json
190
+ ├── vectors/ # Vector indexes (auto-created)
191
+ │ ├── code/
192
+ │ ├── docs/
193
+ │ └── config/
194
+ ├── tools/ # MCP tools
195
+ │ ├── search.ts # Semantic search tool
196
+ │ └── codeindex.ts # Index management tool
102
197
  └── commands/ # Slash commands
103
198
  ```
104
199
 
105
- ### `docs/` (always)
200
+ ### `docs/`
106
201
 
107
202
  ```
108
203
  docs/
109
204
  ├── sprint-artifacts/ # Epics, stories, sprints
110
205
  ├── requirements/ # Requirements documents
111
206
  ├── architecture/ # Architecture + ADRs
112
- ├── api/ # API documentation
113
- ├── coding-standards/ # Coding standards
114
- └── confluence/ # Translations (Ukrainian)
207
+ └── coding-standards/ # Coding patterns
115
208
  ```
116
209
 
117
- ### Repository files (with `--full`)
210
+ ## Auto-Indexer Plugin
118
211
 
119
- ```
120
- README.md # Project readme
121
- CONTRIBUTING.md # Git workflow, commit conventions
122
- CHANGELOG.md # Change history
123
- .gitignore # Git ignore patterns
124
- .gitattributes # Git attributes
212
+ The auto-indexer runs on Claude Code / AI assistant startup:
213
+
214
+ - 🔍 Checks if indexes need updating
215
+ - 📊 Shows toast notification with file count
216
+ - Shows fun message while indexing ("Grab a coffee!")
217
+ - 📝 Logs to `.opencode/indexer.log`
218
+
219
+ **Disable auto-indexing:**
220
+
221
+ ```yaml
222
+ # config.yaml
223
+ vectorizer:
224
+ auto_index: false
125
225
  ```
126
226
 
127
227
  ## Methodologies
@@ -129,9 +229,9 @@ CHANGELOG.md # Change history
129
229
  ### TDD (Test-Driven Development)
130
230
 
131
231
  ```
132
- 1. Write failing test
133
- 2. Write minimal code to pass
134
- 3. Refactor
232
+ 1. Write failing test (RED)
233
+ 2. Write minimal code to pass (GREEN)
234
+ 3. Refactor (BLUE)
135
235
  4. Repeat
136
236
  ```
137
237
 
@@ -146,13 +246,18 @@ CHANGELOG.md # Change history
146
246
 
147
247
  ## Jira Integration
148
248
 
149
- If enabled, set credentials:
249
+ Set credentials:
150
250
 
151
251
  ```bash
152
252
  export JIRA_EMAIL="your-email@company.com"
153
253
  export JIRA_API_TOKEN="your-api-token"
154
254
  ```
155
255
 
256
+ ## Requirements
257
+
258
+ - **Node.js** >= 18
259
+ - **~100MB disk** for vectorizer dependencies
260
+
156
261
  ## Links
157
262
 
158
263
  - **npm:** https://www.npmjs.com/package/@comfanion/workflow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/workflow",
3
- "version": "4.36.13",
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:30:55.138Z",
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,