@comfanion/workflow 4.1.3 → 4.5.0

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.
Files changed (58) hide show
  1. package/README.md +1 -2
  2. package/bin/cli.js +343 -5
  3. package/package.json +8 -3
  4. package/src/build-info.json +2 -1
  5. package/src/opencode/ARCHITECTURE.md +7 -6
  6. package/src/opencode/FLOW.yaml +157 -102
  7. package/src/opencode/agents/analyst.md +24 -20
  8. package/src/opencode/agents/architect.md +104 -39
  9. package/src/opencode/agents/change-manager.md +112 -250
  10. package/src/opencode/agents/coder.md +36 -19
  11. package/src/opencode/agents/crawler.md +180 -97
  12. package/src/opencode/agents/dev.md +117 -29
  13. package/src/opencode/agents/pm.md +25 -32
  14. package/src/opencode/agents/researcher.md +116 -241
  15. package/src/opencode/commands/architecture.md +1 -1
  16. package/src/opencode/commands/dev-story.md +1 -5
  17. package/src/opencode/commands/prd.md +1 -1
  18. package/src/opencode/commands/unit-docs.md +170 -0
  19. package/src/opencode/config.yaml +29 -0
  20. package/src/opencode/opencode.json +5 -0
  21. package/src/opencode/skills/adr-writing/SKILL.md +122 -159
  22. package/src/opencode/skills/adr-writing/template.md +130 -0
  23. package/src/opencode/skills/architecture-design/SKILL.md +113 -107
  24. package/src/opencode/skills/architecture-design/template.md +212 -0
  25. package/src/opencode/skills/architecture-validation/SKILL.md +1 -1
  26. package/src/opencode/skills/changelog/template.md +23 -0
  27. package/src/opencode/{workflows/dev-story/instructions.md → skills/dev-story/SKILL.md} +2 -2
  28. package/src/opencode/skills/epic-writing/SKILL.md +116 -264
  29. package/src/opencode/skills/epic-writing/template.md +119 -0
  30. package/src/opencode/skills/prd-validation/SKILL.md +1 -1
  31. package/src/opencode/skills/prd-writing/SKILL.md +79 -43
  32. package/src/opencode/skills/prd-writing/template.md +147 -0
  33. package/src/opencode/skills/requirements-gathering/SKILL.md +128 -78
  34. package/src/opencode/skills/requirements-gathering/template.md +156 -0
  35. package/src/opencode/skills/story-writing/SKILL.md +106 -464
  36. package/src/opencode/skills/story-writing/template.md +214 -0
  37. package/src/opencode/skills/unit-writing/SKILL.md +185 -0
  38. package/src/opencode/skills/unit-writing/template.md +136 -0
  39. package/src/opencode/tools/codeindex.ts +255 -0
  40. package/src/opencode/tools/codesearch.ts +134 -0
  41. package/src/repo-structure/docs/README.md +5 -5
  42. package/src/repo-structure/docs/requirements/README.md +1 -1
  43. package/src/opencode/templates/CHANGELOG.md +0 -82
  44. package/src/opencode/templates/adr-template.md +0 -115
  45. package/src/opencode/templates/architecture-template.md +0 -362
  46. package/src/opencode/templates/epic-template.md +0 -166
  47. package/src/opencode/templates/prd-template.md +0 -479
  48. package/src/opencode/templates/requirements-template.md +0 -132
  49. package/src/opencode/templates/story-template.md +0 -182
  50. /package/src/opencode/{templates/prd-acceptance-criteria-template.md → skills/acceptance-criteria/template.md} +0 -0
  51. /package/src/opencode/{templates/change-proposal-template.md → skills/archiving/template-change-proposal.md} +0 -0
  52. /package/src/opencode/{templates/git-workflow-template.md → skills/coding-standards/template-git.md} +0 -0
  53. /package/src/opencode/{templates/testing-standards-template.md → skills/coding-standards/template-testing.md} +0 -0
  54. /package/src/opencode/{templates/jira-cache-template.yaml → skills/jira-integration/template-cache.yaml} +0 -0
  55. /package/src/opencode/{templates/module-index-template.md → skills/module-documentation/template.md} +0 -0
  56. /package/src/opencode/{templates/sprint-status-template.yaml → skills/sprint-planning/template.yaml} +0 -0
  57. /package/src/opencode/{templates/integration-tests-template.md → skills/test-design/template-integration.md} +0 -0
  58. /package/src/opencode/{templates/module-test-cases-template.md → skills/test-design/template-module.md} +0 -0
package/README.md CHANGED
@@ -96,8 +96,7 @@ npx @comfanion/workflow config
96
96
  ├── config.yaml # Your configuration
97
97
  ├── FLOW.yaml # Workflow definition (v3.0)
98
98
  ├── agents/ # Agent personas
99
- ├── skills/ # Knowledge modules (25+)
100
- ├── templates/ # Document templates
99
+ ├── skills/ # Knowledge modules with templates (25+)
101
100
  ├── workflows/ # Workflow instructions
102
101
  ├── checklists/ # Validation checklists
103
102
  └── commands/ # Slash commands
package/bin/cli.js CHANGED
@@ -7,11 +7,63 @@ import ora from 'ora';
7
7
  import fs from 'fs-extra';
8
8
  import path from 'path';
9
9
  import { fileURLToPath } from 'url';
10
+ import { execSync } from 'child_process';
10
11
 
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
13
  const PACKAGE_DIR = path.join(__dirname, '..');
13
14
  const OPENCODE_SRC = path.join(PACKAGE_DIR, 'src', 'opencode');
14
15
  const REPO_TEMPLATES_SRC = path.join(PACKAGE_DIR, 'src', 'repo-structure');
16
+ const VECTORIZER_SRC = path.join(PACKAGE_DIR, 'src', 'vectorizer');
17
+
18
+ /**
19
+ * Install vectorizer module with dependencies
20
+ */
21
+ async function installVectorizer(opencodeDir) {
22
+ console.log('');
23
+ const spinner = ora('Installing vectorizer & caching...').start();
24
+
25
+ try {
26
+ const vectorizerDir = path.join(opencodeDir, 'vectorizer');
27
+
28
+ // Copy vectorizer source files
29
+ spinner.text = 'Copying vectorizer files...';
30
+ await fs.ensureDir(vectorizerDir);
31
+ await fs.copy(VECTORIZER_SRC, vectorizerDir);
32
+
33
+ // Run npm install
34
+ spinner.text = 'Installing dependencies (~100MB, may take a minute)...';
35
+ execSync('npm install --no-audit --no-fund', {
36
+ cwd: vectorizerDir,
37
+ stdio: 'pipe',
38
+ timeout: 300000 // 5 min timeout
39
+ });
40
+
41
+ // Add to .gitignore
42
+ const gitignorePath = path.join(opencodeDir, '.gitignore');
43
+ let gitignore = '';
44
+ try { gitignore = await fs.readFile(gitignorePath, 'utf8'); } catch {}
45
+ if (!gitignore.includes('vectors/')) {
46
+ gitignore += '\n# Vectorizer cache\nvectors/\nvectorizer/node_modules/\n';
47
+ await fs.writeFile(gitignorePath, gitignore);
48
+ }
49
+
50
+ spinner.succeed(chalk.green('Vectorizer installed!'));
51
+
52
+ console.log(chalk.cyan('\n🔍 Vectorizer ready:'));
53
+ console.log(`
54
+ Index codebase: ${chalk.cyan('npx opencode-workflow index')}
55
+ Search code: ${chalk.cyan('npx opencode-workflow search "your query"')}
56
+ `);
57
+
58
+ return true;
59
+
60
+ } catch (error) {
61
+ spinner.fail(chalk.yellow('Vectorizer installation failed (optional)'));
62
+ console.log(chalk.gray(` Error: ${error.message}`));
63
+ console.log(chalk.gray(' You can install later with: npx opencode-workflow vectorizer install'));
64
+ return false;
65
+ }
66
+ }
15
67
 
16
68
  const program = new Command();
17
69
 
@@ -28,6 +80,7 @@ program
28
80
  .option('--tdd', 'Use TDD methodology')
29
81
  .option('--stub', 'Use STUB methodology')
30
82
  .option('--full', 'Create full repo structure')
83
+ .option('--vectorizer', 'Install vectorizer for semantic code search')
31
84
  .action(async (options) => {
32
85
  console.log(chalk.blue.bold('\n🚀 OpenCode Workflow v3.7\n'));
33
86
 
@@ -43,6 +96,7 @@ program
43
96
  jira_url: 'https://your-domain.atlassian.net',
44
97
  jira_project: 'PROJ',
45
98
  create_repo_structure: false,
99
+ install_vectorizer: false,
46
100
  project_name: path.basename(process.cwd())
47
101
  };
48
102
 
@@ -155,6 +209,12 @@ program
155
209
  name: 'create_repo_structure',
156
210
  message: 'Create full repository structure (README, CONTRIBUTING, .gitignore, docs/)?',
157
211
  default: options.full || false
212
+ },
213
+ {
214
+ type: 'confirm',
215
+ name: 'install_vectorizer',
216
+ message: 'Install vectorizer & caching? (semantic code search, ~100MB)',
217
+ default: false
158
218
  }
159
219
  ]);
160
220
 
@@ -165,6 +225,7 @@ program
165
225
  if (options.stub) config.methodology = 'stub';
166
226
  if (options.jira) config.jira_enabled = true;
167
227
  if (options.full) config.create_repo_structure = true;
228
+ if (options.vectorizer) config.install_vectorizer = true;
168
229
  }
169
230
 
170
231
  const spinner = ora('Initializing OpenCode Workflow...').start();
@@ -259,7 +320,7 @@ program
259
320
  // Create CHANGELOG.md if not exists
260
321
  const changelogPath = path.join(process.cwd(), 'CHANGELOG.md');
261
322
  if (!await fs.pathExists(changelogPath)) {
262
- const changelogTemplate = path.join(targetDir, 'templates/CHANGELOG.md');
323
+ const changelogTemplate = path.join(targetDir, 'skills/changelog/template.md');
263
324
  if (await fs.pathExists(changelogTemplate)) {
264
325
  await fs.copy(changelogTemplate, changelogPath);
265
326
  }
@@ -267,6 +328,11 @@ program
267
328
 
268
329
  spinner.succeed(chalk.green('OpenCode Workflow initialized!'));
269
330
 
331
+ // Install vectorizer if requested
332
+ if (config.install_vectorizer) {
333
+ await installVectorizer(targetDir);
334
+ }
335
+
270
336
  // Show summary
271
337
  console.log(chalk.yellow('\n📁 Created structure:'));
272
338
  console.log(`
@@ -274,8 +340,7 @@ program
274
340
  ├── config.yaml # Your configuration
275
341
  ├── FLOW.yaml # Workflow definition
276
342
  ├── agents/ # Agent personas (analyst, pm, architect, sm, dev)
277
- ├── skills/ # Knowledge modules
278
- ├── templates/ # Document templates
343
+ ├── skills/ # Knowledge modules (with templates)
279
344
  ├── workflows/ # Workflow instructions
280
345
  └── checklists/ # Validation checklists
281
346
 
@@ -400,7 +465,6 @@ program
400
465
  { name: 'FLOW.yaml', path: '.opencode/FLOW.yaml', required: true },
401
466
  { name: 'agents/', path: '.opencode/agents', required: true },
402
467
  { name: 'skills/', path: '.opencode/skills', required: true },
403
- { name: 'templates/', path: '.opencode/templates', required: true },
404
468
  { name: 'docs/', path: 'docs', required: true },
405
469
  { name: 'docs/sprint-artifacts/', path: 'docs/sprint-artifacts', required: true },
406
470
  { name: 'docs/requirements/', path: 'docs/requirements', required: true },
@@ -463,10 +527,38 @@ program
463
527
  console.log(chalk.gray(' ○ Jira credentials not set'));
464
528
  }
465
529
 
530
+ // Check Vectorizer
531
+ console.log(chalk.cyan('\nVectorizer (semantic search):'));
532
+ const vectorizerInstalled = await fs.pathExists(path.join(process.cwd(), '.opencode', 'vectorizer', 'node_modules'));
533
+ const vectorsExist = await fs.pathExists(path.join(process.cwd(), '.opencode', 'vectors', 'hashes.json'));
534
+
535
+ if (vectorizerInstalled) {
536
+ console.log(chalk.green(' ✅ Installed'));
537
+ if (vectorsExist) {
538
+ try {
539
+ const hashes = await fs.readJSON(path.join(process.cwd(), '.opencode', 'vectors', 'hashes.json'));
540
+ console.log(chalk.green(` ✅ Indexed (${Object.keys(hashes).length} files)`));
541
+ } catch {
542
+ console.log(chalk.gray(' ○ Not indexed yet'));
543
+ }
544
+ } else {
545
+ console.log(chalk.gray(' ○ Not indexed (run: npx opencode-workflow index)'));
546
+ }
547
+ } else {
548
+ console.log(chalk.gray(' ○ Not installed (run: npx opencode-workflow vectorizer install)'));
549
+ }
550
+
551
+ // Check LSP env
552
+ if (process.env.OPENCODE_EXPERIMENTAL_LSP_TOOL === 'true' || process.env.OPENCODE_EXPERIMENTAL === 'true') {
553
+ console.log(chalk.green(' ✅ LSP tool enabled'));
554
+ } else {
555
+ console.log(chalk.gray(' ○ LSP tool disabled (set OPENCODE_EXPERIMENTAL_LSP_TOOL=true)'));
556
+ }
557
+
466
558
  console.log('');
467
559
 
468
560
  if (hasErrors) {
469
- console.log(chalk.yellow('💡 Run `npx create-opencode-workflow init` to fix missing files.\n'));
561
+ console.log(chalk.yellow('💡 Run `npx opencode-workflow init` to fix missing files.\n'));
470
562
  } else {
471
563
  console.log(chalk.green.bold('✅ All checks passed!\n'));
472
564
  }
@@ -486,4 +578,250 @@ program
486
578
  }
487
579
  });
488
580
 
581
+ // =============================================================================
582
+ // VECTORIZER COMMANDS
583
+ // =============================================================================
584
+
585
+ program
586
+ .command('vectorizer')
587
+ .description('Manage vectorizer for semantic code search')
588
+ .argument('<action>', 'install | status | uninstall')
589
+ .action(async (action) => {
590
+ const opencodeDir = path.join(process.cwd(), '.opencode');
591
+ const vectorizerDir = path.join(opencodeDir, 'vectorizer');
592
+
593
+ if (action === 'install') {
594
+ if (!await fs.pathExists(opencodeDir)) {
595
+ console.log(chalk.red('\n❌ .opencode/ not found. Run `init` first.\n'));
596
+ process.exit(1);
597
+ }
598
+ await installVectorizer(opencodeDir);
599
+
600
+ } else if (action === 'status') {
601
+ const installed = await fs.pathExists(path.join(vectorizerDir, 'node_modules'));
602
+ const indexed = await fs.pathExists(path.join(process.cwd(), '.opencode', 'vectors', 'lancedb'));
603
+
604
+ console.log(chalk.blue.bold('\n🔍 Vectorizer Status\n'));
605
+ console.log(installed
606
+ ? chalk.green(' ✅ Installed')
607
+ : chalk.gray(' ○ Not installed (run: npx opencode-workflow vectorizer install)'));
608
+ console.log(indexed
609
+ ? chalk.green(' ✅ Codebase indexed')
610
+ : chalk.gray(' ○ Not indexed (run: npx opencode-workflow index)'));
611
+
612
+ if (indexed) {
613
+ try {
614
+ const hashes = await fs.readJSON(path.join(process.cwd(), '.opencode', 'vectors', 'hashes.json'));
615
+ console.log(chalk.cyan(` 📁 ${Object.keys(hashes).length} files indexed`));
616
+ } catch {}
617
+ }
618
+ console.log('');
619
+
620
+ } else if (action === 'uninstall') {
621
+ const spinner = ora('Removing vectorizer...').start();
622
+ await fs.remove(vectorizerDir);
623
+ await fs.remove(path.join(process.cwd(), '.opencode', 'vectors'));
624
+ spinner.succeed(chalk.green('Vectorizer removed'));
625
+
626
+ } else {
627
+ console.log(chalk.red(`Unknown action: ${action}`));
628
+ console.log('Available: install, status, uninstall');
629
+ }
630
+ });
631
+
632
+ program
633
+ .command('index')
634
+ .description('Index codebase for semantic search')
635
+ .option('-i, --index <name>', 'Index name: code, docs, config, all, or custom', 'code')
636
+ .option('-p, --pattern <glob>', 'File pattern (overrides preset)')
637
+ .option('--force', 'Re-index all files (ignore cache)')
638
+ .option('--list', 'List all indexes and their stats')
639
+ .action(async (options) => {
640
+ const vectorizerDir = path.join(process.cwd(), '.opencode', 'vectorizer');
641
+
642
+ if (!await fs.pathExists(path.join(vectorizerDir, 'node_modules'))) {
643
+ console.log(chalk.red('\n❌ Vectorizer not installed.'));
644
+ console.log(chalk.yellow('Run: npx opencode-workflow vectorizer install\n'));
645
+ process.exit(1);
646
+ }
647
+
648
+ const spinner = ora('Initializing indexer...').start();
649
+
650
+ try {
651
+ // Dynamic import of the vectorizer (need file:// URL for ESM)
652
+ const vectorizerPath = path.join(vectorizerDir, 'index.js');
653
+ const { CodebaseIndexer, INDEX_PRESETS } = await import(`file://${vectorizerPath}`);
654
+
655
+ // List all indexes
656
+ if (options.list) {
657
+ spinner.stop();
658
+ const indexer = await new CodebaseIndexer(process.cwd(), 'code').init();
659
+ const allStats = await indexer.getAllStats();
660
+
661
+ console.log(chalk.blue.bold('\n📊 Index Statistics\n'));
662
+
663
+ if (allStats.length === 0) {
664
+ console.log(chalk.gray(' No indexes found. Create one with:'));
665
+ console.log(chalk.cyan(' npx opencode-workflow index --index code'));
666
+ console.log(chalk.cyan(' npx opencode-workflow index --index docs\n'));
667
+ } else {
668
+ for (const stat of allStats) {
669
+ console.log(chalk.cyan(` 📁 ${stat.indexName}`));
670
+ console.log(chalk.gray(` ${stat.description}`));
671
+ console.log(` Files: ${stat.fileCount}, Chunks: ${stat.chunkCount}\n`);
672
+ }
673
+ }
674
+
675
+ console.log(chalk.yellow('Available presets:'));
676
+ for (const [name, preset] of Object.entries(INDEX_PRESETS)) {
677
+ console.log(` ${chalk.cyan(name)}: ${preset.description}`);
678
+ console.log(chalk.gray(` Pattern: ${preset.pattern}\n`));
679
+ }
680
+ return;
681
+ }
682
+
683
+ const indexName = options.index;
684
+ const indexer = await new CodebaseIndexer(process.cwd(), indexName).init();
685
+
686
+ // Get pattern from options or preset
687
+ const preset = INDEX_PRESETS[indexName];
688
+ const pattern = options.pattern || preset?.pattern || '**/*.{js,ts,jsx,tsx,py,go,rs,java,md,yaml,yml}';
689
+
690
+ spinner.text = `Initializing index: ${indexName}...`;
691
+
692
+ if (options.force) {
693
+ spinner.text = `Clearing index: ${indexName}...`;
694
+ await indexer.clear();
695
+ }
696
+
697
+ // Find files to index
698
+ spinner.text = 'Finding files...';
699
+ const { glob } = await import('glob');
700
+ const { default: ignore } = await import('ignore');
701
+
702
+ // Load .gitignore
703
+ let ig = ignore();
704
+ try {
705
+ const gitignore = await fs.readFile(path.join(process.cwd(), '.gitignore'), 'utf8');
706
+ ig = ig.add(gitignore);
707
+ } catch {}
708
+ ig.add(['node_modules', '.git', 'dist', 'build', '.opencode/vectors', '.opencode/vectorizer']);
709
+
710
+ const files = await glob(pattern, { cwd: process.cwd(), nodir: true });
711
+ const filtered = files.filter(f => !ig.ignores(f));
712
+
713
+ spinner.succeed(`Found ${filtered.length} files for index "${indexName}"`);
714
+
715
+ let indexed = 0;
716
+ let skipped = 0;
717
+
718
+ for (const file of filtered) {
719
+ const filePath = path.join(process.cwd(), file);
720
+ spinner.start(`[${indexName}] Indexing: ${file}`);
721
+
722
+ try {
723
+ const wasIndexed = await indexer.indexFile(filePath);
724
+ if (wasIndexed) {
725
+ indexed++;
726
+ } else {
727
+ skipped++;
728
+ }
729
+ } catch (e) {
730
+ spinner.warn(`Skipped ${file}: ${e.message}`);
731
+ }
732
+ }
733
+
734
+ spinner.succeed(chalk.green(`Index "${indexName}": ${indexed} indexed, ${skipped} unchanged`));
735
+
736
+ } catch (error) {
737
+ spinner.fail(chalk.red('Indexing failed'));
738
+ console.error(error);
739
+ }
740
+ });
741
+
742
+ program
743
+ .command('search')
744
+ .description('Semantic search in codebase')
745
+ .argument('<query>', 'Search query')
746
+ .option('-i, --index <name>', 'Index to search: code, docs, config, or custom', 'code')
747
+ .option('-n, --limit <number>', 'Number of results', '5')
748
+ .option('-a, --all', 'Search all indexes')
749
+ .action(async (query, options) => {
750
+ const vectorizerDir = path.join(process.cwd(), '.opencode', 'vectorizer');
751
+
752
+ if (!await fs.pathExists(path.join(vectorizerDir, 'node_modules'))) {
753
+ console.log(chalk.red('\n❌ Vectorizer not installed.'));
754
+ console.log(chalk.yellow('Run: npx opencode-workflow vectorizer install\n'));
755
+ process.exit(1);
756
+ }
757
+
758
+ const spinner = ora('Searching...').start();
759
+
760
+ try {
761
+ // Dynamic import of the vectorizer (need file:// URL for ESM)
762
+ const vectorizerPath = path.join(vectorizerDir, 'index.js');
763
+ const { CodebaseIndexer } = await import(`file://${vectorizerPath}`);
764
+
765
+ let allResults = [];
766
+ const limit = parseInt(options.limit);
767
+
768
+ if (options.all) {
769
+ // Search all indexes
770
+ const tempIndexer = await new CodebaseIndexer(process.cwd(), 'code').init();
771
+ const indexes = await tempIndexer.listIndexes();
772
+
773
+ if (indexes.length === 0) {
774
+ spinner.stop();
775
+ console.log(chalk.yellow('\nNo indexes found. Run `npx opencode-workflow index` first.\n'));
776
+ return;
777
+ }
778
+
779
+ for (const indexName of indexes) {
780
+ spinner.text = `Searching index: ${indexName}...`;
781
+ const indexer = await new CodebaseIndexer(process.cwd(), indexName).init();
782
+ const results = await indexer.search(query, limit);
783
+ allResults.push(...results.map(r => ({ ...r, _index: indexName })));
784
+ }
785
+
786
+ // Sort by distance and take top N
787
+ allResults.sort((a, b) => (a._distance || 0) - (b._distance || 0));
788
+ allResults = allResults.slice(0, limit);
789
+
790
+ } else {
791
+ // Search specific index
792
+ const indexer = await new CodebaseIndexer(process.cwd(), options.index).init();
793
+ const results = await indexer.search(query, limit);
794
+ allResults = results.map(r => ({ ...r, _index: options.index }));
795
+ }
796
+
797
+ spinner.stop();
798
+
799
+ if (allResults.length === 0) {
800
+ const indexInfo = options.all ? 'any index' : `index "${options.index}"`;
801
+ console.log(chalk.yellow(`\nNo results found in ${indexInfo}.`));
802
+ console.log(chalk.gray('Try: npx opencode-workflow index --index code\n'));
803
+ return;
804
+ }
805
+
806
+ const searchScope = options.all ? 'all indexes' : `index "${options.index}"`;
807
+ console.log(chalk.blue.bold(`\n🔍 Results for: "${query}" (${searchScope})\n`));
808
+
809
+ for (let i = 0; i < allResults.length; i++) {
810
+ const r = allResults[i];
811
+ const score = r._distance ? (1 - r._distance).toFixed(3) : 'N/A';
812
+ const indexLabel = options.all ? chalk.magenta(`[${r._index}] `) : '';
813
+ console.log(chalk.cyan(`${i + 1}. ${indexLabel}${r.file}`) + chalk.gray(` (score: ${score})`));
814
+ console.log(chalk.gray('─'.repeat(60)));
815
+ // Show first 5 lines of content
816
+ const preview = r.content.split('\n').slice(0, 5).join('\n');
817
+ console.log(preview);
818
+ console.log('');
819
+ }
820
+
821
+ } catch (error) {
822
+ spinner.fail(chalk.red('Search failed'));
823
+ console.error(error);
824
+ }
825
+ });
826
+
489
827
  program.parse();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comfanion/workflow",
3
- "version": "4.1.3",
4
- "description": "Initialize OpenCode Workflow system for AI-assisted development",
3
+ "version": "4.5.0",
4
+ "description": "Initialize OpenCode Workflow system for AI-assisted development with semantic code search",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "comfanion-workflow": "./bin/cli.js",
@@ -25,7 +25,10 @@
25
25
  "prd",
26
26
  "architecture",
27
27
  "tdd",
28
- "agile"
28
+ "agile",
29
+ "rag",
30
+ "vector-search",
31
+ "embeddings"
29
32
  ],
30
33
  "author": "OpenCode Team",
31
34
  "license": "MIT",
@@ -44,6 +47,8 @@
44
47
  "chalk": "^5.3.0",
45
48
  "commander": "^11.0.0",
46
49
  "fs-extra": "^11.1.0",
50
+ "glob": "^10.5.0",
51
+ "ignore": "^5.3.0",
47
52
  "inquirer": "^9.2.0",
48
53
  "ora": "^7.0.0"
49
54
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "3.0.0",
3
- "buildDate": "2026-01-23T19:00:59.869Z",
3
+ "buildDate": "2026-01-24T09:15:13.601Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -11,6 +11,7 @@
11
11
  "workflows",
12
12
  "checklists",
13
13
  "commands",
14
+ "tools",
14
15
  "opencode.json"
15
16
  ]
16
17
  }
@@ -186,12 +186,13 @@ prd-writing:
186
186
  │ └── integration-testing/
187
187
  │ └── SKILL.md
188
188
 
189
- └── templates/ # Referenced by skills
190
- ├── requirements-template.md
191
- ├── prd-template.md
192
- ├── architecture-template.md
193
- ├── epic-template.md
194
- ├── story-template.md
189
+ └── skills/ # Skills with co-located templates
190
+ ├── prd-writing/
191
+ ├── SKILL.md
192
+ │ └── template.md
193
+ ├── architecture-design/
194
+ ├── SKILL.md
195
+ │ └── template.md
195
196
  └── ...
196
197
  ```
197
198