@comfanion/workflow 4.39.0-dev.0 ā 4.39.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/bin/cli.js +20 -110
- package/package.json +1 -1
- package/src/build-info.json +3 -4
- package/src/opencode/agents/architect.md +8 -3
- package/src/opencode/agents/pm.md +9 -3
- package/src/opencode/gitignore +1 -0
- package/src/opencode/vectorizer.yaml +0 -45
package/bin/cli.js
CHANGED
|
@@ -54,7 +54,6 @@ program
|
|
|
54
54
|
.option('--tdd', 'Use TDD methodology')
|
|
55
55
|
.option('--stub', 'Use STUB methodology')
|
|
56
56
|
.option('--full', 'Create full repo structure')
|
|
57
|
-
.option('--vectorizer', 'Install vectorizer for semantic code search')
|
|
58
57
|
.action(async (options) => {
|
|
59
58
|
console.log(chalk.blue.bold(`\nš OpenCode Workflow v${VERSION}\n`));
|
|
60
59
|
|
|
@@ -70,9 +69,6 @@ program
|
|
|
70
69
|
jira_url: 'https://your-domain.atlassian.net',
|
|
71
70
|
jira_project: 'PROJ',
|
|
72
71
|
create_repo_structure: false,
|
|
73
|
-
vectorizer_enabled: true,
|
|
74
|
-
vectorizer_auto_index: true,
|
|
75
|
-
vectorizer_model: 'Xenova/all-MiniLM-L6-v2',
|
|
76
72
|
project_name: path.basename(process.cwd())
|
|
77
73
|
};
|
|
78
74
|
|
|
@@ -99,19 +95,6 @@ program
|
|
|
99
95
|
if (jiraUrlMatch) config.jira_url = jiraUrlMatch[1];
|
|
100
96
|
if (jiraProjMatch) config.jira_project = jiraProjMatch[1];
|
|
101
97
|
|
|
102
|
-
// Parse vectorizer settings from vectorizer.yaml if exists
|
|
103
|
-
const vecPath = path.join(targetDir, 'vectorizer.yaml');
|
|
104
|
-
if (await fs.pathExists(vecPath)) {
|
|
105
|
-
const vecContent = await fs.readFile(vecPath, 'utf8');
|
|
106
|
-
const vEnabledMatch = vecContent.match(/enabled:\s*(true|false)/);
|
|
107
|
-
const vAutoMatch = vecContent.match(/auto_index:\s*(true|false)/);
|
|
108
|
-
const vModelMatch = vecContent.match(/model:\s*["']?([^"'\n]+)["']?/);
|
|
109
|
-
|
|
110
|
-
if (vEnabledMatch) config.vectorizer_enabled = vEnabledMatch[1] === 'true';
|
|
111
|
-
if (vAutoMatch) config.vectorizer_auto_index = vAutoMatch[1] === 'true';
|
|
112
|
-
if (vModelMatch) config.vectorizer_model = vModelMatch[1].trim();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
98
|
isUpdate = true;
|
|
116
99
|
} catch (e) {
|
|
117
100
|
// Could not parse, use defaults
|
|
@@ -199,40 +182,6 @@ program
|
|
|
199
182
|
message: 'Create full repository structure (README, CONTRIBUTING, .gitignore, docs/)?',
|
|
200
183
|
default: options.full || false
|
|
201
184
|
},
|
|
202
|
-
{
|
|
203
|
-
type: 'confirm',
|
|
204
|
-
name: 'vectorizer_enabled',
|
|
205
|
-
message: 'Enable semantic code search (vectorizer)?',
|
|
206
|
-
default: true
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
type: 'list',
|
|
210
|
-
name: 'vectorizer_model',
|
|
211
|
-
message: 'Embedding model for semantic search:',
|
|
212
|
-
when: (answers) => answers.vectorizer_enabled,
|
|
213
|
-
choices: [
|
|
214
|
-
{
|
|
215
|
-
name: 'MiniLM-L6 (Fast) - ~10 files/10sec, 384 dims, good quality',
|
|
216
|
-
value: 'Xenova/all-MiniLM-L6-v2'
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: 'BGE-small (Balanced) - ~9 files/10sec, 384 dims, better quality',
|
|
220
|
-
value: 'Xenova/bge-small-en-v1.5'
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
name: 'BGE-base (Quality) - ~3 files/10sec, 768 dims, best quality',
|
|
224
|
-
value: 'Xenova/bge-base-en-v1.5'
|
|
225
|
-
}
|
|
226
|
-
],
|
|
227
|
-
default: config.vectorizer_model
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
type: 'confirm',
|
|
231
|
-
name: 'vectorizer_auto_index',
|
|
232
|
-
message: 'Enable auto-indexing? (reindex files on save)',
|
|
233
|
-
when: (answers) => answers.vectorizer_enabled,
|
|
234
|
-
default: true
|
|
235
|
-
},
|
|
236
185
|
{
|
|
237
186
|
type: 'checkbox',
|
|
238
187
|
name: 'mcp_servers',
|
|
@@ -259,7 +208,6 @@ program
|
|
|
259
208
|
if (options.stub) config.methodology = 'stub';
|
|
260
209
|
if (options.jira) config.jira_enabled = true;
|
|
261
210
|
if (options.full) config.create_repo_structure = true;
|
|
262
|
-
if (options.vectorizer) config.install_vectorizer = true;
|
|
263
211
|
}
|
|
264
212
|
|
|
265
213
|
const spinner = ora('Initializing OpenCode Workflow...').start();
|
|
@@ -324,7 +272,6 @@ program
|
|
|
324
272
|
// Update config.yaml with user values
|
|
325
273
|
spinner.text = 'Configuring...';
|
|
326
274
|
const configPath = path.join(targetDir, 'config.yaml');
|
|
327
|
-
const vecPath = path.join(targetDir, 'vectorizer.yaml');
|
|
328
275
|
let configContent;
|
|
329
276
|
|
|
330
277
|
// If we had existing config, use it as base (preserves comments and formatting)
|
|
@@ -354,19 +301,6 @@ program
|
|
|
354
301
|
|
|
355
302
|
await fs.writeFile(configPath, configContent);
|
|
356
303
|
|
|
357
|
-
// Update vectorizer.yaml
|
|
358
|
-
if (await fs.pathExists(vecPath)) {
|
|
359
|
-
let vecContent = await fs.readFile(vecPath, 'utf8');
|
|
360
|
-
vecContent = vecContent
|
|
361
|
-
.replace(/(enabled:)\s*(true|false)/, `$1 ${config.vectorizer_enabled}`)
|
|
362
|
-
.replace(/(auto_index:)\s*(true|false)/, `$1 ${config.vectorizer_auto_index}`);
|
|
363
|
-
|
|
364
|
-
if (config.vectorizer_model) {
|
|
365
|
-
vecContent = vecContent.replace(/(model:)\s*["']?[^"'\n]+["']?/, `$1 "${config.vectorizer_model}"`);
|
|
366
|
-
}
|
|
367
|
-
await fs.writeFile(vecPath, vecContent);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
304
|
// Create docs structure (always)
|
|
371
305
|
spinner.text = 'Creating docs structure...';
|
|
372
306
|
await fs.ensureDir(path.join(process.cwd(), 'docs'));
|
|
@@ -476,24 +410,10 @@ program
|
|
|
476
410
|
console.log(chalk.gray(' Run manually: cd .opencode && bun install'));
|
|
477
411
|
}
|
|
478
412
|
|
|
479
|
-
// Show what was done
|
|
480
|
-
const vectorizerInstalled = await fs.pathExists(path.join(targetDir, 'vectorizer', 'node_modules'));
|
|
481
|
-
if (vectorizerInstalled) {
|
|
482
|
-
console.log(chalk.green('ā
Vectorizer installed (fresh dependencies)'));
|
|
483
|
-
} else if (config.vectorizer_enabled) {
|
|
484
|
-
console.log(chalk.yellow('ā ļø Vectorizer: run `npx @comfanion/workflow vectorizer install`'));
|
|
485
|
-
} else {
|
|
486
|
-
console.log(chalk.gray('ā¹ļø Vectorizer disabled (enable in config.yaml to use semantic search)'));
|
|
487
|
-
}
|
|
488
413
|
if (hadVectors) {
|
|
489
414
|
console.log(chalk.green('ā
Vector indexes preserved'));
|
|
490
415
|
}
|
|
491
416
|
|
|
492
|
-
// Install vectorizer if requested and failed above
|
|
493
|
-
if (config.install_vectorizer && !vectorizerInstalled) {
|
|
494
|
-
await installVectorizer(targetDir);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
417
|
// Show summary
|
|
498
418
|
console.log(chalk.yellow('\nš Created structure:'));
|
|
499
419
|
console.log(`
|
|
@@ -559,9 +479,8 @@ program
|
|
|
559
479
|
|
|
560
480
|
program
|
|
561
481
|
.command('update')
|
|
562
|
-
.description('Update .opencode/ to latest version (preserves config.yaml and
|
|
482
|
+
.description('Update .opencode/ to latest version (preserves config.yaml and vector indexes)')
|
|
563
483
|
.option('--no-backup', 'Skip creating backup')
|
|
564
|
-
.option('--vectorizer', 'Update/install vectorizer too')
|
|
565
484
|
.action(async (options) => {
|
|
566
485
|
const spinner = ora('Updating OpenCode Workflow...').start();
|
|
567
486
|
|
|
@@ -762,27 +681,25 @@ program
|
|
|
762
681
|
console.log(chalk.gray(' ā Jira credentials not set'));
|
|
763
682
|
}
|
|
764
683
|
|
|
765
|
-
// Check
|
|
766
|
-
console.log(chalk.cyan('\
|
|
767
|
-
const vectorsExist = await fs.pathExists(path.join(process.cwd(), '.opencode', 'vectors', 'code', 'hashes.json'));
|
|
768
|
-
|
|
769
|
-
// Check vectorizer config
|
|
770
|
-
let vectorizerEnabled = true;
|
|
771
|
-
let autoIndexEnabled = true;
|
|
684
|
+
// Check Semantic Search plugin
|
|
685
|
+
console.log(chalk.cyan('\nSemantic search (@comfanion/usethis_search):'));
|
|
772
686
|
try {
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
687
|
+
const opcPath = path.join(process.cwd(), 'opencode.json');
|
|
688
|
+
if (await fs.pathExists(opcPath)) {
|
|
689
|
+
const opc = JSON.parse(await fs.readFile(opcPath, 'utf8'));
|
|
690
|
+
const plugins = opc.plugin || [];
|
|
691
|
+
if (plugins.includes('@comfanion/usethis_search')) {
|
|
692
|
+
console.log(chalk.green(' ā
Plugin registered in opencode.json'));
|
|
693
|
+
} else {
|
|
694
|
+
console.log(chalk.yellow(' ā ļø Plugin not in opencode.json (add "@comfanion/usethis_search" to plugin array)'));
|
|
695
|
+
}
|
|
696
|
+
} else {
|
|
697
|
+
console.log(chalk.gray(' ā No opencode.json found'));
|
|
698
|
+
}
|
|
699
|
+
} catch {
|
|
700
|
+
console.log(chalk.gray(' ā Could not check opencode.json'));
|
|
701
|
+
}
|
|
702
|
+
const vectorsExist = await fs.pathExists(path.join(process.cwd(), '.opencode', 'vectors', 'code', 'hashes.json'));
|
|
786
703
|
if (vectorsExist) {
|
|
787
704
|
try {
|
|
788
705
|
const hashes = await fs.readJSON(path.join(process.cwd(), '.opencode', 'vectors', 'code', 'hashes.json'));
|
|
@@ -791,14 +708,7 @@ program
|
|
|
791
708
|
console.log(chalk.gray(' ā Not indexed yet'));
|
|
792
709
|
}
|
|
793
710
|
} else {
|
|
794
|
-
console.log(chalk.gray(' ā Not indexed (will index on startup)'));
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
// Check LSP env
|
|
798
|
-
if (process.env.OPENCODE_EXPERIMENTAL_LSP_TOOL === 'true' || process.env.OPENCODE_EXPERIMENTAL === 'true') {
|
|
799
|
-
console.log(chalk.green(' ā
LSP tool enabled'));
|
|
800
|
-
} else {
|
|
801
|
-
console.log(chalk.gray(' ā LSP tool disabled (set OPENCODE_EXPERIMENTAL_LSP_TOOL=true)'));
|
|
711
|
+
console.log(chalk.gray(' ā Not indexed (will index on first startup with plugin)'));
|
|
802
712
|
}
|
|
803
713
|
|
|
804
714
|
console.log('');
|
package/package.json
CHANGED
package/src/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.39.
|
|
3
|
-
"buildDate": "2026-01-
|
|
2
|
+
"version": "4.39.1",
|
|
3
|
+
"buildDate": "2026-01-29T22:52:34.568Z",
|
|
4
4
|
"files": [
|
|
5
5
|
".gitignore",
|
|
6
6
|
"config.yaml",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"commands",
|
|
13
13
|
"mcp",
|
|
14
14
|
"package.json",
|
|
15
|
-
"opencode.json"
|
|
16
|
-
"vectorizer.yaml"
|
|
15
|
+
"opencode.json"
|
|
17
16
|
]
|
|
18
17
|
}
|
|
@@ -67,6 +67,7 @@ permission:
|
|
|
67
67
|
<r>ALWAYS write technical documentation in ENGLISH (docs/ folder)</r>
|
|
68
68
|
<r>Translations go to docs/confluence/ folder</r>
|
|
69
69
|
<r critical="MANDATORY">š LOAD SKILL FIRST: Before creating any document (architecture/ADR/unit/coding-standards), MUST load appropriate skill</r>
|
|
70
|
+
<r recommended="true">š For large docs (1000+ lines): prefer template ā fill incrementally (better performance & quality)</r>
|
|
70
71
|
<r>Always check existing codebase patterns in CLAUDE.md before proposing new patterns</r>
|
|
71
72
|
<r>Document all decisions with ADRs and clear rationale</r>
|
|
72
73
|
<r>Never skip NFR analysis</r>
|
|
@@ -114,8 +115,12 @@ permission:
|
|
|
114
115
|
- LARGE: 2000-4000 lines, multiple files, DOMAINS
|
|
115
116
|
- ENTERPRISE: 4000+ lines, per-domain files
|
|
116
117
|
|
|
118
|
+
REALITY CHECK: Most projects are TOY (30%) or SMALL (40%), MEDIUM+ (30%)
|
|
119
|
+
Default assumption: TOY/SMALL until proven otherwise
|
|
120
|
+
|
|
117
121
|
Example:
|
|
118
122
|
- PRD says "TOY" ā Write 350 lines, 3 components, NO modules
|
|
123
|
+
- PRD says "SMALL" ā Write 700 lines, simple structure, NO modules
|
|
119
124
|
- PRD says "MEDIUM" ā Write 1500 lines, 3 MODULES with Unit docs
|
|
120
125
|
|
|
121
126
|
DON'T write 2000-line architecture for Tetris!
|
|
@@ -130,9 +135,11 @@ permission:
|
|
|
130
135
|
</phase>
|
|
131
136
|
|
|
132
137
|
<phase name="3. Execution">
|
|
138
|
+
<action>For large docs (1000+ lines): Create template ā fill section by section (better performance)</action>
|
|
139
|
+
<action>For small docs: Can write directly</action>
|
|
133
140
|
<action>Work through tasklist sequentially</action>
|
|
134
141
|
<action>Mark tasks in_progress ā completed</action>
|
|
135
|
-
<action>If uncertain
|
|
142
|
+
<action>If uncertain ā ask, don't assume</action>
|
|
136
143
|
</phase>
|
|
137
144
|
|
|
138
145
|
<phase name="4. Review">
|
|
@@ -142,10 +149,8 @@ permission:
|
|
|
142
149
|
|
|
143
150
|
<never-do>
|
|
144
151
|
- Start creating files WITHOUT loading the skill first
|
|
145
|
-
- Start creating files before user confirms the plan
|
|
146
152
|
- Skip the tasklist for complex work
|
|
147
153
|
- Assume what user wants without asking
|
|
148
|
-
- Create all files at once without progress updates
|
|
149
154
|
</never-do>
|
|
150
155
|
</workflow>
|
|
151
156
|
|
|
@@ -64,6 +64,7 @@ permission:
|
|
|
64
64
|
<r>ALWAYS write technical documentation in ENGLISH (docs/ folder)</r>
|
|
65
65
|
<r>Translations go to docs/confluence/ folder</r>
|
|
66
66
|
<r critical="MANDATORY">š LOAD SKILL FIRST: Before creating any document (PRD/epic/story), MUST load appropriate skill</r>
|
|
67
|
+
<r recommended="true">š For large docs (PRD, epics): prefer template ā fill incrementally (better performance)</r>
|
|
67
68
|
<r>PRDs emerge from user interviews, not template filling</r>
|
|
68
69
|
<r>Ship the smallest thing that validates the assumption</r>
|
|
69
70
|
<r>Every feature must trace to a user problem</r>
|
|
@@ -112,9 +113,12 @@ permission:
|
|
|
112
113
|
</phase>
|
|
113
114
|
|
|
114
115
|
<phase name="3. Execution">
|
|
116
|
+
<action>For large docs (PRD 1000+ lines): Create template ā fill section by section (better performance)</action>
|
|
117
|
+
<action>For PRD: Start with "Project Classification" section FIRST</action>
|
|
118
|
+
<action>For small docs (stories, epics): Can write directly</action>
|
|
115
119
|
<action>Work through tasklist sequentially</action>
|
|
116
120
|
<action>Mark tasks in_progress ā completed</action>
|
|
117
|
-
<action>If uncertain
|
|
121
|
+
<action>If uncertain ā ask, don't assume</action>
|
|
118
122
|
</phase>
|
|
119
123
|
|
|
120
124
|
<phase name="4. Review">
|
|
@@ -124,10 +128,9 @@ permission:
|
|
|
124
128
|
|
|
125
129
|
<never-do>
|
|
126
130
|
- Start writing docs WITHOUT loading the skill first
|
|
127
|
-
- Start writing docs before user confirms the plan
|
|
128
131
|
- Skip the tasklist for complex work
|
|
129
132
|
- Assume what user wants without asking
|
|
130
|
-
-
|
|
133
|
+
- For PRD: Skip "Project Classification" section or fill it last (MUST BE FIRST!)
|
|
131
134
|
</never-do>
|
|
132
135
|
</workflow>
|
|
133
136
|
|
|
@@ -162,6 +165,9 @@ permission:
|
|
|
162
165
|
5. Fill Project Classification table in PRD (first section!)
|
|
163
166
|
6. Then write rest of PRD according to that size
|
|
164
167
|
|
|
168
|
+
REALITY CHECK: Most projects are TOY (30%) or SMALL (40%), MEDIUM+ (30%)
|
|
169
|
+
Default assumption: TOY/SMALL until proven otherwise
|
|
170
|
+
|
|
165
171
|
Example questions:
|
|
166
172
|
- "How many database tables do you expect?" (5-10 = SMALL, 20+ = MEDIUM)
|
|
167
173
|
- "How many external integrations?" (0-2 = SMALL, 3-5 = MEDIUM)
|
package/src/opencode/gitignore
CHANGED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
vectorizer:
|
|
2
|
-
# Enable/disable vectorizer functionality
|
|
3
|
-
enabled: true
|
|
4
|
-
|
|
5
|
-
# Auto-index files when they change (requires file-indexer plugin)
|
|
6
|
-
auto_index: true
|
|
7
|
-
|
|
8
|
-
# Debounce time in ms (wait before indexing after file change)
|
|
9
|
-
debounce_ms: 1000
|
|
10
|
-
|
|
11
|
-
# Indexes to maintain - each has pattern (what to include) and ignore (what to skip)
|
|
12
|
-
indexes:
|
|
13
|
-
|
|
14
|
-
# Documentation index - markdown, text files
|
|
15
|
-
docs:
|
|
16
|
-
enabled: true
|
|
17
|
-
pattern: "docs/**/*.{md,mdx,txt,rst,adoc}"
|
|
18
|
-
ignore: []
|
|
19
|
-
|
|
20
|
-
# Configuration index - yaml, json, toml
|
|
21
|
-
config:
|
|
22
|
-
enabled: false
|
|
23
|
-
pattern: "**/*.{yaml,yml,json,toml,ini}"
|
|
24
|
-
ignore:
|
|
25
|
-
- "**/node_modules/**"
|
|
26
|
-
- "**/.git/**"
|
|
27
|
-
- "**/dist/**"
|
|
28
|
-
- "**/build/**"
|
|
29
|
-
- "**/.opencode/**"
|
|
30
|
-
- "**/docs/**"
|
|
31
|
-
- "**/vendor/**"
|
|
32
|
-
- "**/__pycache__/**"
|
|
33
|
-
- "**/*.min.js"
|
|
34
|
-
- "**/*.bundle.js"
|
|
35
|
-
- "**/package-lock.json"
|
|
36
|
-
- "**/yarn.lock"
|
|
37
|
-
|
|
38
|
-
# Global exclude patterns (applied to ALL indexes, in addition to per-index ignore)
|
|
39
|
-
exclude:
|
|
40
|
-
- node_modules
|
|
41
|
-
- vendor
|
|
42
|
-
- dist
|
|
43
|
-
- build
|
|
44
|
-
- out
|
|
45
|
-
- __pycache__
|