create-harness-vibe-coding 0.8.6 → 0.8.8

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 (93) hide show
  1. package/README-CN.md +157 -105
  2. package/README.md +160 -244
  3. package/bin/create-harness-vibe-coding.js +2 -2
  4. package/docs/images/harness-architecture-light.png +0 -0
  5. package/docs/images/harness-architecture.drawio +164 -0
  6. package/package.json +46 -44
  7. package/src/generator.js +30 -11
  8. package/src/index.js +143 -14
  9. package/src/prompts.js +37 -37
  10. package/templates/common/.claude/agents/architect-manager.md +45 -45
  11. package/templates/common/.claude/agents/context-master.md +75 -75
  12. package/templates/common/.claude/agents/debugger.md +41 -41
  13. package/templates/common/.claude/agents/explore-manager.md +41 -41
  14. package/templates/common/.claude/agents/implement-manager.md +49 -49
  15. package/templates/common/.claude/agents/implementer.md +40 -40
  16. package/templates/common/.claude/agents/memory-master.md +64 -64
  17. package/templates/common/.claude/agents/planner.md +34 -34
  18. package/templates/common/.claude/agents/reflector.md +35 -0
  19. package/templates/common/.claude/agents/researcher.md +41 -41
  20. package/templates/common/.claude/agents/review-manager.md +56 -56
  21. package/templates/common/.claude/agents/verifier.md +34 -32
  22. package/templates/common/.claude/commands/wf-help.md +2 -3
  23. package/templates/common/.claude/rules/ecc/common.md +44 -44
  24. package/templates/common/.claude/skills/subagent-orchestrator/SKILL.md +10 -4
  25. package/templates/common/.claude/skills/wf/SKILL.md +7 -3
  26. package/templates/common/.claude/skills/wf-auto/SKILL.md +61 -107
  27. package/templates/common/.claude/skills/wf-auto-spark/SKILL.md +19 -17
  28. package/templates/common/.claude/skills/wf-max/SKILL.md +40 -21
  29. package/templates/common/.claude/skills/wf-readme/SKILL.md +49 -49
  30. package/templates/common/.claude/skills/wf-remove/SKILL.md +7 -7
  31. package/templates/common/.claude/skills/wf-update/SKILL.md +9 -4
  32. package/templates/common/.codex/config.toml +5 -0
  33. package/templates/common/.harness-version +78 -36
  34. package/templates/common/.opencode/agents/architect-manager.md +52 -0
  35. package/templates/common/.opencode/agents/architect.md +35 -0
  36. package/templates/common/.opencode/agents/context-master.md +81 -0
  37. package/templates/common/.opencode/agents/debugger.md +43 -0
  38. package/templates/common/.opencode/agents/docs-researcher.md +42 -0
  39. package/templates/common/.opencode/agents/explore-manager.md +49 -0
  40. package/templates/common/.opencode/agents/implement-manager.md +56 -0
  41. package/templates/common/.opencode/agents/implementer.md +42 -0
  42. package/templates/common/.opencode/agents/memory-master.md +70 -0
  43. package/templates/common/.opencode/agents/planner.md +38 -0
  44. package/templates/common/.opencode/agents/reflector.md +39 -0
  45. package/templates/common/.opencode/agents/researcher.md +42 -0
  46. package/templates/common/.opencode/agents/review-manager.md +63 -0
  47. package/templates/common/.opencode/agents/reviewer.md +37 -0
  48. package/templates/common/.opencode/agents/tdd-guide.md +83 -0
  49. package/templates/common/.opencode/agents/test-writer.md +54 -0
  50. package/templates/common/.opencode/agents/verifier.md +37 -0
  51. package/templates/common/.opencode/commands/wf-help.md +23 -0
  52. package/templates/common/AGENTS.md +26 -25
  53. package/templates/common/CLAUDE.md +86 -88
  54. package/templates/common/Harness/ACCEPTANCE_PROTOCOL.md +12 -4
  55. package/templates/common/Harness/PROGRESS.md +17 -17
  56. package/templates/common/Harness/README.md +26 -16
  57. package/templates/common/Harness/WF-AUTO-ANGLES.md +170 -0
  58. package/templates/common/Harness/WF-AUTO-SPARK.md +23 -6
  59. package/templates/common/Harness/WF-AUTO.md +508 -493
  60. package/templates/common/Harness/WF-MAX.md +284 -232
  61. package/templates/common/Harness/WF.md +47 -29
  62. package/templates/common/Harness/agent-workflow.md +108 -76
  63. package/templates/common/Harness/architecture.md +124 -124
  64. package/templates/common/Harness/context-loading.md +111 -111
  65. package/templates/common/Harness/dispatch.md +96 -95
  66. package/templates/common/Harness/extension.md +67 -67
  67. package/templates/common/Harness/lifecycle.md +20 -20
  68. package/templates/common/Harness/research/PRD.md +56 -56
  69. package/templates/common/Harness/research/README.md +169 -169
  70. package/templates/common/Harness/research/research-results.md +66 -66
  71. package/templates/common/Harness/subagents.md +192 -170
  72. package/templates/common/Harness/tasks/_template/ARTIFACTS.md +3 -3
  73. package/templates/common/Harness/tasks/_template/NOTES.md +3 -3
  74. package/templates/common/Harness/tasks/_template/PLAN.md +53 -60
  75. package/templates/common/Harness/tasks/_template/PROGRESS.md +26 -29
  76. package/templates/common/MEMORY.md +27 -30
  77. package/templates/common/README.md +36 -36
  78. package/templates/common/SETUP.md +1 -1
  79. package/templates/common/memory/agent-lessons-patterns.md +21 -21
  80. package/templates/common/memory/tool-usage-reflections.md +21 -21
  81. package/templates/common/memory/user-corrections-preferences.md +21 -21
  82. package/templates/common/opencode.json +19 -0
  83. package/templates/common/scripts/scan-clean.mjs +487 -448
  84. package/templates/common/scripts/validate-harness.mjs +245 -146
  85. package/templates/common/scripts/wf-remove.mjs +311 -293
  86. package/templates/common/scripts/wf-update-check.mjs +511 -311
  87. package/templates/optional/catalog.json +41 -33
  88. package/templates/optional/skills/browser-e2e/.claude/skills/wf-browser/SKILL.md +194 -194
  89. package/templates/optional/skills/browser-e2e/Harness/workflows/browser-e2e.md +105 -69
  90. package/templates/optional/skills/github-pr-review/Harness/workflows/github-pr-review.md +28 -28
  91. package/templates/optional/skills/python-backend/Harness/workflows/python-backend.md +34 -34
  92. package/templates/optional/skills/ts-react-frontend/Harness/workflows/ts-react-frontend.md +34 -34
  93. package/templates/optional/skills/ui-ux-review/Harness/workflows/ui-ux-review.md +26 -26
package/package.json CHANGED
@@ -1,44 +1,46 @@
1
- {
2
- "name": "create-harness-vibe-coding",
3
- "version": "0.8.6",
4
- "description": "Scaffold a 0-1 product harness for AI-assisted research, PRD, planning, architecture, build, test, and feedback loops",
5
- "type": "module",
6
- "bin": {
7
- "create-harness-vibe-coding": "bin/create-harness-vibe-coding.js"
8
- },
9
- "files": [
10
- "bin/",
11
- "src/",
12
- "templates/",
13
- "README-CN.md"
14
- ],
15
- "scripts": {
16
- "start": "node src/index.js",
17
- "build:version": "node scripts/build-version.mjs",
18
- "prepush": "node scripts/pre-push-check.mjs",
19
- "test": "node --test tests/*.test.js",
20
- "test:smoke": "node --test tests/cli-smoke.test.js",
21
- "pack:smoke": "node --test tests/pack-smoke.test.js"
22
- },
23
- "dependencies": {
24
- "@clack/prompts": "^0.7.0",
25
- "picocolors": "^1.1.0"
26
- },
27
- "engines": {
28
- "node": ">=18"
29
- },
30
- "repository": {
31
- "type": "git",
32
- "url": "git+https://github.com/zingspark/create-harness-vibe-coding.git"
33
- },
34
- "keywords": [
35
- "claude-code",
36
- "harness",
37
- "scaffold",
38
- "vibe-coding",
39
- "agentic",
40
- "ecc",
41
- "superpowers"
42
- ],
43
- "license": "MIT"
44
- }
1
+ {
2
+ "name": "create-harness-vibe-coding",
3
+ "version": "0.8.8",
4
+ "description": "Scaffold a 0-1 product harness for AI-assisted research, PRD, planning, architecture, build, test, and feedback loops",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-harness-vibe-coding": "bin/create-harness-vibe-coding.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "src/",
12
+ "templates/",
13
+ "docs/images/harness-architecture-light.png",
14
+ "docs/images/harness-architecture.drawio",
15
+ "README-CN.md"
16
+ ],
17
+ "scripts": {
18
+ "start": "node src/index.js",
19
+ "build:version": "node scripts/build-version.mjs",
20
+ "prepush": "node scripts/pre-push-check.mjs",
21
+ "test": "node --test tests/*.test.js",
22
+ "test:smoke": "node --test tests/cli-smoke.test.js",
23
+ "pack:smoke": "node --test tests/pack-smoke.test.js"
24
+ },
25
+ "dependencies": {
26
+ "@clack/prompts": "^0.7.0",
27
+ "picocolors": "^1.1.0"
28
+ },
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/zingspark/create-harness-vibe-coding.git"
35
+ },
36
+ "keywords": [
37
+ "claude-code",
38
+ "harness",
39
+ "scaffold",
40
+ "vibe-coding",
41
+ "agentic",
42
+ "ecc",
43
+ "superpowers"
44
+ ],
45
+ "license": "MIT"
46
+ }
package/src/generator.js CHANGED
@@ -350,8 +350,9 @@ function nextBackupPath(destPath) {
350
350
  }
351
351
 
352
352
  function registerOptionalContent(file, content, selectedSkills) {
353
- if (!selectedSkills.length) return content;
354
-
353
+ if (!selectedSkills.length) return content;
354
+ const hasBrowserE2e = selectedSkills.some(skill => skill.id === 'browser-e2e');
355
+
355
356
  if (file === 'Harness/MEMORY.md') {
356
357
  const lines = selectedSkills.map(skill => (
357
358
  `- [${skill.id}](../.claude/skills/${skill.id}/SKILL.md) - ${skill.description} Codex mirror: [${skill.id}](../.agents/skills/${skill.id}/SKILL.md). Workflow: [workflows/${skill.id}.md](workflows/${skill.id}.md)`
@@ -360,15 +361,33 @@ function registerOptionalContent(file, content, selectedSkills) {
360
361
  'Stack-specific skills can be added after the product shape is known.',
361
362
  `Installed optional skills:\n\n${lines.join('\n')}\n\nStack-specific skills can be added after the product shape is known.`,
362
363
  );
363
- }
364
-
365
- if (file === 'Harness/README.md') {
366
- const lines = selectedSkills.map(skill => (
367
- `- [${skill.title}](workflows/${skill.id}.md) - ${skill.description}`
368
- ));
369
- return `${content.trimEnd()}\n\n## Installed Optional Workflows\n\n${lines.join('\n')}\n`;
370
- }
371
-
364
+ }
365
+
366
+ if (file === 'Harness/README.md') {
367
+ const lines = selectedSkills.map(skill => (
368
+ `- [${skill.title}](workflows/${skill.id}.md) - ${skill.description}`
369
+ ));
370
+ let next = content;
371
+ if (hasBrowserE2e) {
372
+ next = next.replace(
373
+ '| Optional workflow installed |',
374
+ '| Browser E2E testing or automation | /wf-browser, $wf-browser, browser, e2e, web automation, screenshot verify, page test, browser test, Playwright, CDP | [workflows/browser-e2e.md](workflows/browser-e2e.md), [HARNESS_BRIDGE.md](HARNESS_BRIDGE.md) | UI/API contract, CLI commands, screenshots, traces, validation matrix |\n| Optional workflow installed |',
375
+ );
376
+ next = next.replace(
377
+ '| `/wf-readme [task]` |',
378
+ '| `/wf-browser [task]` | `$wf-browser [task]` | Optional browser automation/E2E workflow when `browser-e2e` is installed |\n| `/wf-readme [task]` |',
379
+ );
380
+ }
381
+ return `${next.trimEnd()}\n\n## Installed Optional Workflows\n\n${lines.join('\n')}\n`;
382
+ }
383
+
384
+ if ((file === '.claude/commands/wf-help.md' || file === '.opencode/commands/wf-help.md') && hasBrowserE2e) {
385
+ return content.replace(
386
+ '| `/wf-readme <task>` |',
387
+ '| `/wf-browser <task>` | optional workflow skill | `/wf-browser verify checkout flow` | Browser automation/E2E workflow with real UI interaction, screenshots, traces, and CDP/network evidence. |\n| `/wf-readme <task>` |',
388
+ );
389
+ }
390
+
372
391
  return content;
373
392
  }
374
393
 
package/src/index.js CHANGED
@@ -2,9 +2,13 @@
2
2
  import * as p from '@clack/prompts';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
+ import { spawnSync } from 'node:child_process';
5
6
  import pc from 'picocolors';
6
7
  import { askConflictPolicy, askOptionalSelections, askProjectName, askTargetDir } from './prompts.js';
7
8
  import { generate, getOptionalCatalog } from './generator.js';
9
+
10
+ const UPDATE_SUCCESS_STATUSES = new Set(['up-to-date', 'update-available', 'partial-update']);
11
+ const UPDATE_FAILURE_STATUSES = new Set(['error', 'offline', 'template-remote', 'downgrade-refused']);
8
12
 
9
13
  // ── CLI flags ──────────────────────────────────────────────
10
14
  const raw = process.argv.slice(2);
@@ -85,6 +89,10 @@ if (generationOptions.json) {
85
89
  const projectName = argName || DEFAULT_NAME;
86
90
  const targetDir = argDir || `./${projectName}`;
87
91
  const scan = scanTarget(targetDir);
92
+ if (scan.hasHarness) {
93
+ printJsonResult(createUpdateSwitchResult(scan, { json: true }));
94
+ process.exit(0);
95
+ }
88
96
  const result = generate({ projectName, targetDir, ...generationOptions });
89
97
  result.scan = createJsonScan(scan);
90
98
  result.agent = createAgentGuidance(result, {
@@ -108,16 +116,21 @@ console.log('');
108
116
  let projectName, targetDir;
109
117
 
110
118
  // Non-interactive: positionals provided OR -y/--yes flag set
111
- if (argName || skipPrompts) {
112
- projectName = argName || DEFAULT_NAME;
113
- targetDir = argDir || `./${projectName}`;
114
-
115
- console.log(pc.dim('────────────────────────────────────────────'));
119
+ if (argName || skipPrompts) {
120
+ projectName = argName || DEFAULT_NAME;
121
+ targetDir = argDir || `./${projectName}`;
122
+ const scan = scanTarget(targetDir);
123
+
124
+ if (scan.hasHarness) {
125
+ process.exit(runUpdateSwitch(scan, { json: false }));
126
+ }
127
+
128
+ console.log(pc.dim('────────────────────────────────────────────'));
116
129
  console.log(` Project ${pc.green(projectName)}`);
117
130
  console.log(` Directory ${pc.green(targetDir)}`);
118
- console.log(` Creates ${pc.cyan('CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, tests/')}`);
131
+ console.log(` Creates ${pc.cyan('CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, .opencode/, opencode.json, tests/')}`);
119
132
  if (generationOptions.dryRun) {
120
- console.log(` Mode ${pc.yellow('dry-run')}`);
133
+ console.log(` Mode ${pc.yellow('dry-run')}`);
121
134
  }
122
135
  console.log(` Conflicts ${pc.cyan(generationOptions.onConflict)}`);
123
136
  if (generationOptions.withOptions.length > 0) {
@@ -159,6 +172,10 @@ if (argName || skipPrompts) {
159
172
  const scan = scanTarget(targetDir);
160
173
  printScan(scan);
161
174
 
175
+ if (scan.hasHarness) {
176
+ process.exit(runUpdateSwitch(scan, { json: false }));
177
+ }
178
+
162
179
  if (!generationOptions.dryRun && !conflictPolicyProvided && scan.needsConflictPolicy) {
163
180
  try {
164
181
  generationOptions.onConflict = await askConflictPolicy(scan);
@@ -189,7 +206,7 @@ if (argName || skipPrompts) {
189
206
  console.log(pc.dim('────────────────────────────────────────────'));
190
207
  console.log(` Project ${pc.green(projectName)}`);
191
208
  console.log(` Directory ${pc.green(targetDir)}`);
192
- console.log(` Creates ${pc.cyan('CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, tests/')}`);
209
+ console.log(` Creates ${pc.cyan('CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, .opencode/, opencode.json, tests/')}`);
193
210
  console.log(` Conflicts ${pc.cyan(generationOptions.onConflict)}`);
194
211
  if (generationOptions.withOptions.length > 0) {
195
212
  console.log(` Optional ${pc.cyan(generationOptions.withOptions.join(','))}`);
@@ -259,8 +276,9 @@ function printResult(result, targetDir) {
259
276
 
260
277
  console.log(pc.bold('Next steps:'));
261
278
  console.log(` ${pc.cyan(`cd ${targetDir}`)}`);
262
- console.log(` ${pc.cyan('claude')} # Start Claude Code`);
263
- console.log(` ${pc.cyan('codex')} # Or start Codex`);
279
+ console.log(` ${pc.cyan('claude')} # Start Claude Code`);
280
+ console.log(` ${pc.cyan('codex')} # Or start Codex`);
281
+ console.log(` ${pc.cyan('opencode')} # Or start OpenCode`);
264
282
  console.log(` Tell your agent: "${pc.yellow('Read Harness/SETUP.md. Bootstrap this project from idea to first vertical slice.')}"`);
265
283
  console.log('');
266
284
  console.log(pc.dim(' Harness/SETUP.md is temporary. Delete it after initialization.'));
@@ -429,6 +447,113 @@ function printJsonResult(result) {
429
447
  }
430
448
  }
431
449
 
450
+ function runUpdateSwitch(scan, { json }) {
451
+ const updateResult = createUpdateSwitchResult(scan, { json });
452
+ if (json) {
453
+ printJsonResult(updateResult);
454
+ return updateResult.success ? 0 : 1;
455
+ }
456
+
457
+ console.log('');
458
+ console.log(pc.yellow('Existing Harness detected. Switching to wf-update check.'));
459
+ console.log(pc.dim(`Directory ${scan.resolvedDir}`));
460
+ console.log(pc.dim('Command node Harness/scripts/wf-update-check.mjs'));
461
+ console.log('');
462
+
463
+ if (!updateResult.success && updateResult.error) {
464
+ console.error(pc.red(updateResult.error));
465
+ return 1;
466
+ }
467
+
468
+ if (updateResult.stdout) process.stdout.write(updateResult.stdout);
469
+ if (updateResult.stderr) process.stderr.write(updateResult.stderr);
470
+ return updateResult.exitCode ?? 0;
471
+ }
472
+
473
+ function getUpdateStatusError(update) {
474
+ if (!update || typeof update !== 'object' || typeof update.status !== 'string') {
475
+ return 'Update checker did not return a machine-readable status.';
476
+ }
477
+ if (UPDATE_FAILURE_STATUSES.has(update.status)) {
478
+ return `Update checker reported ${update.status}${update.message ? `: ${update.message}` : ''}`;
479
+ }
480
+ if (!UPDATE_SUCCESS_STATUSES.has(update.status)) {
481
+ return `Update checker returned unrecognized status: ${update.status}`;
482
+ }
483
+ return null;
484
+ }
485
+
486
+ function createUpdateSwitchResult(scan, { json }) {
487
+ const args = ['Harness/scripts/wf-update-check.mjs'];
488
+ if (json) args.push('--json');
489
+
490
+ const scriptPath = path.join(scan.resolvedDir, 'Harness', 'scripts', 'wf-update-check.mjs');
491
+ const command = `node ${args.join(' ')}`;
492
+ const base = {
493
+ success: false,
494
+ mode: 'update',
495
+ scan: createJsonScan(scan),
496
+ agent: {
497
+ sourceOfTruth: 'Existing Harness detected; install automatically switched to the target update checker. Do not continue install writes.',
498
+ updateCommand: json
499
+ ? 'node Harness/scripts/wf-update-check.mjs --json'
500
+ : 'node Harness/scripts/wf-update-check.mjs',
501
+ next: [
502
+ {
503
+ action: 'update',
504
+ command: json
505
+ ? 'node Harness/scripts/wf-update-check.mjs --json'
506
+ : 'node Harness/scripts/wf-update-check.mjs',
507
+ reason: 'Harness already exists, so updates must use the installed Harness update flow.',
508
+ },
509
+ ],
510
+ },
511
+ };
512
+
513
+ if (!fs.existsSync(scriptPath)) {
514
+ return {
515
+ ...base,
516
+ error: 'Existing Harness detected, but Harness/scripts/wf-update-check.mjs was not found. Install writes were skipped; inspect the existing Harness before updating manually.',
517
+ errors: ['Harness/scripts/wf-update-check.mjs not found'],
518
+ };
519
+ }
520
+
521
+ const result = spawnSync(process.execPath, args, {
522
+ cwd: scan.resolvedDir,
523
+ encoding: 'utf8',
524
+ });
525
+ const stdout = result.stdout || '';
526
+ const stderr = result.stderr || '';
527
+ const status = result.status ?? 1;
528
+
529
+ let update = undefined;
530
+ if (json && stdout.trim()) {
531
+ try {
532
+ update = JSON.parse(stdout.trim());
533
+ } catch {
534
+ update = { rawOutput: stdout };
535
+ }
536
+ }
537
+
538
+ const errors = [];
539
+ if (status !== 0) errors.push(`Update checker exited with status ${status}`);
540
+ if (json) {
541
+ const statusError = getUpdateStatusError(update);
542
+ if (statusError) errors.push(statusError);
543
+ }
544
+
545
+ return {
546
+ ...base,
547
+ success: errors.length === 0,
548
+ exitCode: status,
549
+ command,
550
+ stdout,
551
+ stderr,
552
+ ...(json ? { update } : {}),
553
+ ...(errors.length === 0 ? {} : { error: errors[0], errors }),
554
+ };
555
+ }
556
+
432
557
  function scanTarget(targetDir) {
433
558
  const resolvedDir = path.resolve(process.cwd(), targetDir);
434
559
  const exists = fs.existsSync(resolvedDir);
@@ -440,7 +565,8 @@ function scanTarget(targetDir) {
440
565
  const hasClaude = isDirectory && fs.existsSync(path.join(resolvedDir, 'CLAUDE.md'));
441
566
  const hasAgents = isDirectory && fs.existsSync(path.join(resolvedDir, 'AGENTS.md'));
442
567
  const hasAgentSkills = isDirectory && fs.existsSync(path.join(resolvedDir, '.agents'));
443
- const hasCodex = isDirectory && fs.existsSync(path.join(resolvedDir, '.codex'));
568
+ const hasCodex = isDirectory && fs.existsSync(path.join(resolvedDir, '.codex'));
569
+ const hasOpencode = isDirectory && (fs.existsSync(path.join(resolvedDir, '.opencode')) || fs.existsSync(path.join(resolvedDir, 'opencode.json')));
444
570
  const hasDocs = isDirectory && fs.existsSync(path.join(resolvedDir, 'docs'));
445
571
  const hasReadme = isDirectory && fs.existsSync(path.join(resolvedDir, 'README.md'));
446
572
  const hasPackageJson = isDirectory && fs.existsSync(path.join(resolvedDir, 'package.json'));
@@ -458,7 +584,8 @@ function scanTarget(targetDir) {
458
584
  hasClaude,
459
585
  hasAgents,
460
586
  hasAgentSkills,
461
- hasCodex,
587
+ hasCodex,
588
+ hasOpencode,
462
589
  hasDocs,
463
590
  hasReadme,
464
591
  hasPackageJson,
@@ -486,7 +613,8 @@ function createJsonScan(scan) {
486
613
  hasClaude: scan.hasClaude,
487
614
  hasAgents: scan.hasAgents,
488
615
  hasAgentSkills: scan.hasAgentSkills,
489
- hasCodex: scan.hasCodex,
616
+ hasCodex: scan.hasCodex,
617
+ hasOpencode: scan.hasOpencode,
490
618
  hasDocs: scan.hasDocs,
491
619
  hasReadme: scan.hasReadme,
492
620
  hasPackageJson: scan.hasPackageJson,
@@ -660,6 +788,7 @@ function printScan(scan) {
660
788
  if (scan.hasClaude) console.log(` CLAUDE.md ${pc.yellow('exists')}`);
661
789
  if (scan.hasAgents) console.log(` AGENTS.md ${pc.yellow('exists')}`);
662
790
  if (scan.hasAgentSkills) console.log(` .agents/ ${pc.yellow('exists')}`);
663
- if (scan.hasCodex) console.log(` .codex/ ${pc.yellow('exists')}`);
791
+ if (scan.hasCodex) console.log(` .codex/ ${pc.yellow('exists')}`);
792
+ if (scan.hasOpencode) console.log(` opencode ${pc.yellow('exists')} ${pc.dim('(.opencode/ or opencode.json)')}`);
664
793
  if (scan.hasDocs) console.log(` docs/ ${pc.dim('project-owned; Harness stays in Harness/')}`);
665
794
  }
package/src/prompts.js CHANGED
@@ -1,41 +1,41 @@
1
- import * as p from '@clack/prompts';
2
- import pc from 'picocolors';
3
-
4
- export async function askProjectName() {
5
- const name = await p.text({
6
- message: 'Project name?',
7
- placeholder: 'my-vibe-project',
8
- defaultValue: 'my-vibe-project',
9
- validate(value) {
10
- if (!value.trim()) return 'Project name is required';
11
- if (!/^[a-zA-Z0-9_-]+$/.test(value)) return 'Only letters, numbers, hyphens, and underscores allowed';
12
- return;
13
- },
14
- });
15
-
16
- if (p.isCancel(name)) {
17
- p.cancel('Cancelled');
18
- process.exit(0);
19
- }
20
-
21
- return name.trim();
22
- }
23
-
1
+ import * as p from '@clack/prompts';
2
+ import pc from 'picocolors';
3
+
4
+ export async function askProjectName() {
5
+ const name = await p.text({
6
+ message: 'Project name?',
7
+ placeholder: 'my-vibe-project',
8
+ defaultValue: 'my-vibe-project',
9
+ validate(value) {
10
+ if (!value.trim()) return 'Project name is required';
11
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) return 'Only letters, numbers, hyphens, and underscores allowed';
12
+ return;
13
+ },
14
+ });
15
+
16
+ if (p.isCancel(name)) {
17
+ p.cancel('Cancelled');
18
+ process.exit(0);
19
+ }
20
+
21
+ return name.trim();
22
+ }
23
+
24
24
  export async function askTargetDir(projectName) {
25
- const dir = await p.text({
26
- message: 'Target directory?',
27
- placeholder: `./${projectName}`,
28
- defaultValue: `./${projectName}`,
29
- validate(value) {
30
- if (!value.trim()) return 'Directory is required';
31
- return;
32
- },
33
- });
34
-
35
- if (p.isCancel(dir)) {
36
- p.cancel('Cancelled');
37
- process.exit(0);
38
- }
25
+ const dir = await p.text({
26
+ message: 'Target directory?',
27
+ placeholder: `./${projectName}`,
28
+ defaultValue: `./${projectName}`,
29
+ validate(value) {
30
+ if (!value.trim()) return 'Directory is required';
31
+ return;
32
+ },
33
+ });
34
+
35
+ if (p.isCancel(dir)) {
36
+ p.cancel('Cancelled');
37
+ process.exit(0);
38
+ }
39
39
 
40
40
  return dir.trim();
41
41
  }
@@ -1,45 +1,45 @@
1
- ---
2
- name: architect-manager
3
- description: WF-MAX Manager for W1 architecture wave. Spawns 3 boundary/interface/data-flow architects, synthesizes interface contracts, reports to CEO. Read-only + Agent spawn; no Edit/Write.
4
- tools: Read, Grep, Glob, Agent, Bash(git *), Bash(ls *), Bash(dir *)
5
- model: sonnet
6
- ---
7
-
8
- # Architect Manager — W1 Architecture Wave
9
-
10
- You are an Architect Manager in the WF-MAX hierarchy. You report to the CEO.
11
-
12
- ## Role
13
-
14
- Cross-file interface design → parallel dispatch of 3 architects → synthesize boundary decisions + interface contract → report to CEO for approval.
15
-
16
- ## What You Do
17
-
18
- 1. Receive architecture scope from the CEO (which modules/layers need boundaries defined)
19
- 2. Spawn 3 parallel architects:
20
- - **boundary-researcher**: study existing interfaces, dependencies, import graphs
21
- - **interface-designer**: propose new interface contracts, ports, adapters
22
- - **data-flow-mapper**: trace data through the system, identify state ownership
23
- 3. ALL 3 spawned in ONE message
24
- 4. Synthesize: reconcile interface proposals, flag conflicts, produce one interface contract
25
- 5. Report to CEO with recommended decisions and trade-offs
26
-
27
- ## What You NEVER Do
28
-
29
- - Write or edit source code
30
- - Implement interfaces (that's W2)
31
- - Make final architecture decisions (present options with trade-offs)
32
- - Write to task files
33
-
34
- ## Synthesis Format
35
-
36
- ```
37
- Boundary decisions (proposed):
38
- Interface contract:
39
- - Port A: <signature, owner, consumers>
40
- - Port B: <signature, owner, consumers>
41
- Data flow:
42
- State ownership:
43
- Conflicts/risks:
44
- Open questions for CEO:
45
- ```
1
+ ---
2
+ name: architect-manager
3
+ description: WF-MAX Manager for W1 architecture wave. Spawns 3 boundary/interface/data-flow architects, synthesizes interface contracts, reports to CEO. Read-only + Agent spawn; no Edit/Write.
4
+ tools: Read, Grep, Glob, Agent, Bash(git *), Bash(ls *), Bash(dir *)
5
+ model: sonnet
6
+ ---
7
+
8
+ # Architect Manager — W1 Architecture Wave
9
+
10
+ You are an Architect Manager in the WF-MAX hierarchy. You report to the CEO.
11
+
12
+ ## Role
13
+
14
+ Cross-file interface design → parallel dispatch of 3 architects → synthesize boundary decisions + interface contract → report to CEO for approval.
15
+
16
+ ## What You Do
17
+
18
+ 1. Receive architecture scope from the CEO (which modules/layers need boundaries defined)
19
+ 2. Spawn 3 parallel architects:
20
+ - **boundary-researcher**: study existing interfaces, dependencies, import graphs
21
+ - **interface-designer**: propose new interface contracts, ports, adapters
22
+ - **data-flow-mapper**: trace data through the system, identify state ownership
23
+ 3. ALL 3 spawned in ONE message
24
+ 4. Synthesize: reconcile interface proposals, flag conflicts, produce one interface contract
25
+ 5. Report to CEO with recommended decisions and trade-offs
26
+
27
+ ## What You NEVER Do
28
+
29
+ - Write or edit source code
30
+ - Implement interfaces (that's W2)
31
+ - Make final architecture decisions (present options with trade-offs)
32
+ - Write to task files
33
+
34
+ ## Synthesis Format
35
+
36
+ ```
37
+ Boundary decisions (proposed):
38
+ Interface contract:
39
+ - Port A: <signature, owner, consumers>
40
+ - Port B: <signature, owner, consumers>
41
+ Data flow:
42
+ State ownership:
43
+ Conflicts/risks:
44
+ Open questions for CEO:
45
+ ```