create-harness-vibe-coding 0.8.16 → 0.8.18

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 (70) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README-CN.md +100 -127
  3. package/README.md +63 -42
  4. package/package.json +1 -1
  5. package/src/generator.js +628 -121
  6. package/src/index.js +174 -43
  7. package/src/prompts.js +18 -0
  8. package/templates/common/.claude/commands/wf-auto-spark.md +16 -0
  9. package/templates/common/.claude/commands/wf-auto.md +16 -0
  10. package/templates/{optional/skills/browser-e2e/.opencode → common/.claude}/commands/wf-browser.md +1 -1
  11. package/templates/common/.claude/commands/wf-command-create.md +58 -0
  12. package/templates/common/.claude/commands/wf-help.md +13 -6
  13. package/templates/common/.claude/commands/wf-learn.md +16 -0
  14. package/templates/common/.claude/commands/wf-max.md +20 -0
  15. package/templates/common/.claude/commands/wf-readme.md +16 -0
  16. package/templates/common/.claude/commands/wf-remove.md +16 -0
  17. package/templates/common/.claude/commands/wf-review.md +16 -0
  18. package/templates/common/.claude/commands/wf-task-archive.md +26 -0
  19. package/templates/common/.claude/commands/wf-task-list.md +24 -0
  20. package/templates/common/.claude/commands/wf-task-record.md +24 -0
  21. package/templates/common/.claude/commands/wf.md +16 -0
  22. package/templates/common/.claude/rules/ecc/common.md +1 -1
  23. package/templates/common/.claude/skills/wf-agents-docs/SKILL.md +15 -30
  24. package/templates/common/.claude/skills/wf-browser/SKILL.md +176 -0
  25. package/templates/common/.claude/skills/wf-command-create/SKILL.md +37 -0
  26. package/templates/common/.claude/skills/wf-help/SKILL.md +30 -0
  27. package/templates/common/.claude/skills/wf-max/SKILL.md +22 -8
  28. package/templates/common/.claude/skills/wf-review/SKILL.md +29 -2
  29. package/templates/common/.claude/skills/wf-task-archive/SKILL.md +28 -0
  30. package/templates/common/.claude/skills/wf-task-list/SKILL.md +28 -0
  31. package/templates/common/.claude/skills/wf-task-record/SKILL.md +28 -0
  32. package/templates/common/.codex/config.toml +3 -5
  33. package/templates/common/.harness-version +108 -41
  34. package/templates/common/.opencode/agents/architect-manager.md +7 -1
  35. package/templates/common/.opencode/agents/explore-manager.md +10 -1
  36. package/templates/common/.opencode/agents/implement-manager.md +5 -3
  37. package/templates/common/.opencode/agents/review-manager.md +5 -2
  38. package/templates/common/.opencode/commands/wf-browser.md +16 -0
  39. package/templates/common/.opencode/commands/wf-command-create.md +61 -0
  40. package/templates/common/.opencode/commands/wf-help.md +13 -6
  41. package/templates/common/.opencode/commands/wf-max.md +12 -7
  42. package/templates/common/.opencode/commands/wf-task-archive.md +29 -0
  43. package/templates/common/.opencode/commands/wf-task-list.md +27 -0
  44. package/templates/common/.opencode/commands/wf-task-record.md +27 -0
  45. package/templates/common/CLAUDE.md +9 -7
  46. package/templates/common/Harness/MEMORY.md +12 -3
  47. package/templates/common/Harness/README.md +23 -41
  48. package/templates/common/Harness/ownership.manifest.json +162 -14
  49. package/templates/common/Harness/scripts/archive-tasks.mjs +12 -220
  50. package/templates/common/Harness/scripts/scan-clean.mjs +3 -9
  51. package/templates/common/Harness/scripts/task-state.mjs +1279 -0
  52. package/templates/common/Harness/scripts/validate-harness.mjs +635 -65
  53. package/templates/common/Harness/scripts/wf-remove.mjs +37 -5
  54. package/templates/common/Harness/scripts/wf-update-check.mjs +3 -0
  55. package/templates/common/Harness/specs/guides/SETUP.md +10 -2
  56. package/templates/common/Harness/specs/protocols/MEMORY_PROTOCOL.md +15 -0
  57. package/templates/common/Harness/specs/protocols/TASK_ARCHIVE.md +49 -23
  58. package/templates/common/Harness/specs/runtime/command-surface.json +215 -0
  59. package/templates/common/Harness/specs/runtime/dispatch.md +2 -2
  60. package/templates/common/Harness/specs/runtime/subagents.md +15 -5
  61. package/templates/common/Harness/specs/workflows/WF-AUTO.md +6 -6
  62. package/templates/common/Harness/specs/workflows/WF-KERNEL.md +1 -1
  63. package/templates/common/Harness/specs/workflows/WF-MAX.md +35 -2
  64. package/templates/common/Harness/specs/workflows/WF-STATE.md +155 -36
  65. package/templates/common/Harness/tasks/_template/STATE.json +6 -0
  66. package/templates/common/opencode.json +1 -0
  67. package/templates/optional/catalog.json +2 -9
  68. package/templates/optional/skills/browser-e2e/.claude/skills/browser-e2e/SKILL.md +0 -42
  69. package/templates/optional/skills/browser-e2e/.claude/skills/wf-browser/SKILL.md +0 -201
  70. package/templates/optional/skills/browser-e2e/Harness/workflows/browser-e2e.md +0 -119
package/src/index.js CHANGED
@@ -4,7 +4,7 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import pc from 'picocolors';
7
- import { askConflictPolicy, askOptionalSelections, askProjectName, askTargetDir } from './prompts.js';
7
+ import { askConflictPolicy, askInstallScope, askOptionalSelections, askProjectName, askTargetDir } from './prompts.js';
8
8
  import { generate, getOptionalCatalog } from './generator.js';
9
9
 
10
10
  const UPDATE_SUCCESS_STATUSES = new Set(['up-to-date', 'update-available', 'partial-update']);
@@ -45,6 +45,9 @@ if (showHelp) {
45
45
  console.log(' --without <id,id> Remove optional workflow skills selected by --preset or --with');
46
46
  console.log(' --recommend <id,id> Record recommendation-only external capabilities');
47
47
  console.log(' --preset <name> Add a built-in optional workflow preset');
48
+ console.log(' --install-scope <scope> project or global (default: project)');
49
+ console.log(' --global-dir <dir> Global Harness runtime directory for --install-scope global');
50
+ console.log(' --host-global-dir <dir> Base directory for Claude/Codex/OpenCode global copies');
48
51
  console.log(' --list-options Print optional workflow skills and presets');
49
52
  console.log(' --json Output machine-readable JSON (use with --dry-run for planning)');
50
53
  console.log('');
@@ -57,9 +60,10 @@ if (showHelp) {
57
60
  console.log(' npx create-harness-vibe-coding@latest my-project ./dist/my-project -y');
58
61
  console.log(' npx create-harness-vibe-coding@latest legacy ./legacy -y --dry-run');
59
62
  console.log(' npx create-harness-vibe-coding@latest legacy ./legacy -y --on-conflict skip');
60
- console.log(' npx create-harness-vibe-coding@latest web ./web -y --with ts-react-frontend,browser-e2e');
61
- console.log(' npx create-harness-vibe-coding@latest web ./web -y --preset web-app');
62
- console.log(' npx create-harness-vibe-coding@latest api ./api -y --preset fullstack --without github-pr-review');
63
+ console.log(' npx create-harness-vibe-coding@latest web ./web -y --with ts-react-frontend,ui-ux-review');
64
+ console.log(' npx create-harness-vibe-coding@latest web ./web -y --preset web-app');
65
+ console.log(' npx create-harness-vibe-coding@latest api ./api -y --preset fullstack --without github-pr-review');
66
+ console.log(' npx create-harness-vibe-coding@latest app ./app -y --install-scope global');
63
67
  console.log('');
64
68
  process.exit(0);
65
69
  }
@@ -80,6 +84,9 @@ const generationOptions = {
80
84
  withoutOptions: parsed.flags.without || [],
81
85
  externalOptions: parsed.flags.recommend || [],
82
86
  preset: parsed.flags.preset,
87
+ installScope: parsed.flags.installScope || 'project',
88
+ globalDir: parsed.flags.globalDir,
89
+ hostGlobalDir: parsed.flags.hostGlobalDir,
83
90
  json: Boolean(parsed.flags.json),
84
91
  };
85
92
 
@@ -137,9 +144,19 @@ if (argName || skipPrompts) {
137
144
  }
138
145
 
139
146
  console.log(pc.dim('────────────────────────────────────────────'));
140
- console.log(` Project ${pc.green(projectName)}`);
147
+ console.log(` Project ${pc.green(projectName)}`);
141
148
  console.log(` Directory ${pc.green(targetDir)}`);
142
- console.log(` Creates ${pc.cyan('CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, .opencode/, opencode.json, tests/')}`);
149
+ console.log(` Scope ${pc.green(generationOptions.installScope)}`);
150
+ if (generationOptions.globalDir) {
151
+ console.log(` Global dir ${pc.green(generationOptions.globalDir)}`);
152
+ }
153
+ if (generationOptions.hostGlobalDir) {
154
+ console.log(` Host dir ${pc.green(generationOptions.hostGlobalDir)}`);
155
+ }
156
+ const creates = generationOptions.installScope === 'global'
157
+ ? 'project bridge/state/settings + global runtime + Claude/Codex/OpenCode host copies'
158
+ : 'CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, .opencode/, opencode.json, tests/';
159
+ console.log(` Creates ${pc.cyan(creates)}`);
143
160
  if (generationOptions.dryRun) {
144
161
  console.log(` Mode ${pc.yellow('dry-run')}`);
145
162
  }
@@ -176,8 +193,15 @@ if (argName || skipPrompts) {
176
193
  try {
177
194
  targetDir = await askTargetDir(projectName);
178
195
  } catch {
179
- targetDir = `./${projectName}`;
180
- console.log(pc.dim(` Directory: ${targetDir} (default)`));
196
+ targetDir = `./${projectName}`;
197
+ console.log(pc.dim(` Directory: ${targetDir} (default)`));
198
+ }
199
+
200
+ try {
201
+ generationOptions.installScope = await askInstallScope();
202
+ } catch {
203
+ generationOptions.installScope = 'project';
204
+ console.log(pc.dim(' Scope: project (default)'));
181
205
  }
182
206
 
183
207
  const scan = scanTarget(targetDir);
@@ -219,9 +243,19 @@ if (argName || skipPrompts) {
219
243
 
220
244
  console.log('');
221
245
  console.log(pc.dim('────────────────────────────────────────────'));
222
- console.log(` Project ${pc.green(projectName)}`);
246
+ console.log(` Project ${pc.green(projectName)}`);
223
247
  console.log(` Directory ${pc.green(targetDir)}`);
224
- console.log(` Creates ${pc.cyan('CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, .opencode/, opencode.json, tests/')}`);
248
+ console.log(` Scope ${pc.green(generationOptions.installScope)}`);
249
+ if (generationOptions.globalDir) {
250
+ console.log(` Global dir ${pc.green(generationOptions.globalDir)}`);
251
+ }
252
+ if (generationOptions.hostGlobalDir) {
253
+ console.log(` Host dir ${pc.green(generationOptions.hostGlobalDir)}`);
254
+ }
255
+ const creates = generationOptions.installScope === 'global'
256
+ ? 'project bridge/state + global runtime + Claude/Codex/OpenCode host copies'
257
+ : 'CLAUDE.md, README.md, Harness/PROGRESS.md, Harness/, .claude/, .agents/, .opencode/, opencode.json, tests/';
258
+ console.log(` Creates ${pc.cyan(creates)}`);
225
259
  console.log(` Conflicts ${pc.cyan(generationOptions.onConflict)}`);
226
260
  if (generationOptions.withOptions.length > 0) {
227
261
  console.log(` Optional ${pc.cyan(generationOptions.withOptions.join(','))}`);
@@ -237,11 +271,19 @@ if (argName || skipPrompts) {
237
271
  printResult(preview, targetDir);
238
272
  }
239
273
 
240
- console.log(pc.yellow('Planned changes: no files have been written yet.'));
241
- printSummary(preview.summary);
242
- printPlan(preview.plan);
243
- printWarnings(preview);
244
- console.log('');
274
+ console.log(pc.yellow('Planned changes: no files have been written yet.'));
275
+ console.log(pc.bold('Project plan:'));
276
+ printSummary(preview.summary);
277
+ printPlan(preview.plan);
278
+ if (preview.globalPlan) {
279
+ console.log(pc.bold('\nGlobal runtime plan:'));
280
+ console.log(` Directory ${pc.cyan(preview.globalDir)}`);
281
+ printSummary(preview.globalSummary);
282
+ printPlan(preview.globalPlan);
283
+ }
284
+ printHostPlans(preview.hostPlans, preview.hostSummary);
285
+ printWarnings(preview);
286
+ console.log('');
245
287
 
246
288
  if (generationOptions.dryRun) {
247
289
  process.exit(0);
@@ -270,11 +312,19 @@ if (argName || skipPrompts) {
270
312
 
271
313
  function printResult(result, targetDir) {
272
314
  if (result.success) {
273
- if (result.dryRun) {
274
- console.log(pc.yellow('\nDry run: no files or directories were written.'));
275
- printSummary(result.summary);
276
- printPlan(result.plan);
277
- if (result.warnings.length > 0) {
315
+ if (result.dryRun) {
316
+ console.log(pc.yellow('\nDry run: no files or directories were written.'));
317
+ console.log(pc.bold('Project plan:'));
318
+ printSummary(result.summary);
319
+ printPlan(result.plan);
320
+ if (result.globalPlan) {
321
+ console.log(pc.bold('\nGlobal runtime plan:'));
322
+ console.log(` Directory ${pc.cyan(result.globalDir)}`);
323
+ printSummary(result.globalSummary);
324
+ printPlan(result.globalPlan);
325
+ }
326
+ printHostPlans(result.hostPlans, result.hostSummary);
327
+ if (result.warnings.length > 0) {
278
328
  console.log(pc.yellow('\nWarning(s):'));
279
329
  for (const warning of result.warnings) {
280
330
  console.log(pc.yellow(` - ${warning}`));
@@ -283,11 +333,18 @@ function printResult(result, targetDir) {
283
333
  console.log('');
284
334
  return;
285
335
  }
286
-
287
- console.log(pc.green('\nGeneration complete.\n'));
288
- printSummary(result.summary);
289
-
290
- printWarnings(result);
336
+
337
+ console.log(pc.green('\nGeneration complete.\n'));
338
+ console.log(pc.bold('Project install:'));
339
+ printSummary(result.summary);
340
+ if (result.globalSummary) {
341
+ console.log(pc.bold('Global runtime:'));
342
+ console.log(` Directory ${pc.cyan(result.globalDir)}`);
343
+ printSummary(result.globalSummary);
344
+ }
345
+ printHostPlans(result.hostPlans, result.hostSummary, { summaryOnly: true });
346
+
347
+ printWarnings(result);
291
348
 
292
349
  console.log(pc.bold('Next steps:'));
293
350
  console.log(` ${pc.cyan(`cd ${targetDir}`)}`);
@@ -384,13 +441,31 @@ function parseArgs(args) {
384
441
  flags.recommend.push(value);
385
442
  }
386
443
  } else if (arg === '--preset') {
387
- const parsedValue = readValue('--preset', i);
388
- flags.preset = parsedValue.value;
389
- i = parsedValue.nextIndex;
390
- } else if (arg.startsWith('--preset=')) {
391
- flags.preset = readEqualsValue('--preset', arg.slice('--preset='.length));
392
- } else if (arg.startsWith('-')) {
393
- errors.push(`Unknown flag "${arg}"`);
444
+ const parsedValue = readValue('--preset', i);
445
+ flags.preset = parsedValue.value;
446
+ i = parsedValue.nextIndex;
447
+ } else if (arg.startsWith('--preset=')) {
448
+ flags.preset = readEqualsValue('--preset', arg.slice('--preset='.length));
449
+ } else if (arg === '--install-scope') {
450
+ const parsedValue = readValue('--install-scope', i);
451
+ flags.installScope = parsedValue.value;
452
+ i = parsedValue.nextIndex;
453
+ } else if (arg.startsWith('--install-scope=')) {
454
+ flags.installScope = readEqualsValue('--install-scope', arg.slice('--install-scope='.length));
455
+ } else if (arg === '--global-dir') {
456
+ const parsedValue = readValue('--global-dir', i);
457
+ flags.globalDir = parsedValue.value;
458
+ i = parsedValue.nextIndex;
459
+ } else if (arg.startsWith('--global-dir=')) {
460
+ flags.globalDir = readEqualsValue('--global-dir', arg.slice('--global-dir='.length));
461
+ } else if (arg === '--host-global-dir') {
462
+ const parsedValue = readValue('--host-global-dir', i);
463
+ flags.hostGlobalDir = parsedValue.value;
464
+ i = parsedValue.nextIndex;
465
+ } else if (arg.startsWith('--host-global-dir=')) {
466
+ flags.hostGlobalDir = readEqualsValue('--host-global-dir', arg.slice('--host-global-dir='.length));
467
+ } else if (arg.startsWith('-')) {
468
+ errors.push(`Unknown flag "${arg}"`);
394
469
  } else {
395
470
  positionals.push(arg);
396
471
  }
@@ -434,17 +509,30 @@ function printSummary(summary) {
434
509
  console.log('');
435
510
  }
436
511
 
437
- function printPlan(plan) {
438
- for (const [label, files] of Object.entries(plan)) {
439
- if (!files.length) continue;
512
+ function printPlan(plan) {
513
+ for (const [label, files] of Object.entries(plan)) {
514
+ if (!files.length) continue;
440
515
  console.log(` ${label}:`);
441
516
  for (const file of files) {
442
517
  console.log(` - ${file}`);
443
518
  }
444
- }
445
- }
446
-
447
- function printWarnings(result) {
519
+ }
520
+ }
521
+
522
+ function printHostPlans(hostPlans = [], hostSummary = [], { summaryOnly = false } = {}) {
523
+ if (!hostPlans?.length) return;
524
+
525
+ const summariesByHost = new Map((hostSummary || []).map(item => [item.host, item.summary]));
526
+ console.log(pc.bold('\nHost-global copies:'));
527
+ for (const hostPlan of hostPlans) {
528
+ console.log(` ${hostPlan.host} ${pc.cyan(hostPlan.root)}`);
529
+ const summary = summariesByHost.get(hostPlan.host);
530
+ if (summary) printSummary(summary);
531
+ if (!summaryOnly) printPlan(hostPlan.plan);
532
+ }
533
+ }
534
+
535
+ function printWarnings(result) {
448
536
  if (!result.warnings.length) return;
449
537
 
450
538
  console.log(pc.yellow('\nWarning(s):'));
@@ -455,7 +543,7 @@ function printWarnings(result) {
455
543
 
456
544
  function printJsonResult(result) {
457
545
  // Remove `created` array from output — it is already in the plan, avoid duplication
458
- const { created, ...rest } = result;
546
+ const { created, globalCreated, hostCreated, ...rest } = result;
459
547
  console.log(JSON.stringify(rest, null, 2));
460
548
  if (!result.success) {
461
549
  process.exit(1);
@@ -703,12 +791,44 @@ function createJsonScan(scan) {
703
791
  }
704
792
 
705
793
  function createAgentGuidance(result, { projectName, targetDir, options, scan }) {
706
- const attentionFiles = [...new Set([
794
+ const projectAttentionFiles = [...new Set([
707
795
  ...(result.plan?.conflict || []),
708
796
  ...(result.plan?.skip || []),
709
797
  ])].sort();
710
- const aiMergeRequired = attentionFiles.map(file => createFileGuidance(file));
711
- const hasBlockingConflicts = (result.plan?.conflict || []).length > 0;
798
+ const globalAttentionFiles = [...new Set([
799
+ ...(result.globalPlan?.conflict || []),
800
+ ...(result.globalPlan?.skip || []),
801
+ ])].sort();
802
+ const hostAttentionFiles = (result.hostPlans || []).flatMap(hostPlan => (
803
+ [...new Set([
804
+ ...(hostPlan.plan?.conflict || []),
805
+ ...(hostPlan.plan?.skip || []),
806
+ ])].sort().map(file => ({ host: hostPlan.host, root: hostPlan.root, file }))
807
+ ));
808
+ const aiMergeRequired = [
809
+ ...projectAttentionFiles.map(file => createFileGuidance(file)),
810
+ ...globalAttentionFiles.map(file => {
811
+ const guidance = createFileGuidance(file);
812
+ return {
813
+ ...guidance,
814
+ file: `global:${guidance.file}`,
815
+ scope: 'global-runtime',
816
+ reason: `Global runtime file in ${result.globalDir || 'the selected global directory'} needs review. ${guidance.reason}`,
817
+ };
818
+ }),
819
+ ...hostAttentionFiles.map(({ host, root, file }) => {
820
+ const guidance = createFileGuidance(file);
821
+ return {
822
+ ...guidance,
823
+ file: `host:${host}:${guidance.file}`,
824
+ scope: `host-global:${host}`,
825
+ reason: `Host-global ${host} file in ${root} needs review. ${guidance.reason}`,
826
+ };
827
+ }),
828
+ ];
829
+ const hasBlockingConflicts = (result.plan?.conflict || []).length > 0
830
+ || (result.globalPlan?.conflict || []).length > 0
831
+ || (result.hostPlans || []).some(hostPlan => (hostPlan.plan?.conflict || []).length > 0);
712
832
  const safeMergeCommand = commandFor(projectName, targetDir, {
713
833
  ...options,
714
834
  dryRun: false,
@@ -769,6 +889,14 @@ function createAgentGuidance(result, { projectName, targetDir, options, scan })
769
889
  mkdir: result.plan?.mkdir?.length || 0,
770
890
  backup: result.plan?.backup?.length || 0,
771
891
  overwrite: result.plan?.overwrite?.length || 0,
892
+ globalCreate: result.globalPlan?.create?.length || 0,
893
+ globalMkdir: result.globalPlan?.mkdir?.length || 0,
894
+ globalBackup: result.globalPlan?.backup?.length || 0,
895
+ globalOverwrite: result.globalPlan?.overwrite?.length || 0,
896
+ hostCreate: (result.hostPlans || []).reduce((sum, hostPlan) => sum + (hostPlan.plan?.create?.length || 0), 0),
897
+ hostMkdir: (result.hostPlans || []).reduce((sum, hostPlan) => sum + (hostPlan.plan?.mkdir?.length || 0), 0),
898
+ hostBackup: (result.hostPlans || []).reduce((sum, hostPlan) => sum + (hostPlan.plan?.backup?.length || 0), 0),
899
+ hostOverwrite: (result.hostPlans || []).reduce((sum, hostPlan) => sum + (hostPlan.plan?.overwrite?.length || 0), 0),
772
900
  },
773
901
  aiMergeRequired,
774
902
  next,
@@ -839,6 +967,9 @@ function commandFor(projectName, targetDir, options) {
839
967
  if (options.withoutOptions?.length) args.push('--without', options.withoutOptions.join(','));
840
968
  if (options.externalOptions?.length) args.push('--recommend', options.externalOptions.join(','));
841
969
  if (options.preset) args.push('--preset', options.preset);
970
+ if (options.installScope && options.installScope !== 'project') args.push('--install-scope', options.installScope);
971
+ if (options.globalDir) args.push('--global-dir', options.globalDir);
972
+ if (options.hostGlobalDir) args.push('--host-global-dir', options.hostGlobalDir);
842
973
  if (options.json) args.push('--json');
843
974
 
844
975
  return args.map(shellQuoteArg).join(' ');
package/src/prompts.js CHANGED
@@ -40,6 +40,24 @@ export async function askTargetDir(projectName) {
40
40
  return dir.trim();
41
41
  }
42
42
 
43
+ export async function askInstallScope() {
44
+ const scope = await p.select({
45
+ message: 'Harness install scope?',
46
+ initialValue: 'project',
47
+ options: [
48
+ { value: 'project', label: 'Project-local', hint: 'full Harness scaffold in this project' },
49
+ { value: 'global', label: 'Global + project state', hint: 'shared runtime plus project-local tasks/memory' },
50
+ ],
51
+ });
52
+
53
+ if (p.isCancel(scope)) {
54
+ p.cancel('Cancelled');
55
+ process.exit(0);
56
+ }
57
+
58
+ return scope;
59
+ }
60
+
43
61
  export async function askConflictPolicy(scan) {
44
62
  const reason = scan.hasHarness
45
63
  ? 'Target already has Harness/. Choose how to handle existing files.'
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Run perpetual inspiration mode via the wf-auto-spark skill
3
+ ---
4
+
5
+ # /wf-auto-spark
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
+ 3. Execute per the skill adapter `.claude/skills/wf-auto-spark/SKILL.md` (mirror: `.agents/skills/wf-auto-spark/SKILL.md`).
13
+ 4. Do not duplicate the workflow here. The skill adapter and `Harness/specs/workflows/WF-AUTO-SPARK.md` are authoritative.
14
+
15
+ If this runtime cannot invoke the skill directly, read
16
+ `.claude/skills/wf-auto-spark/SKILL.md` and follow it in place.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Run perpetual adaptive auto-optimization via the wf-auto skill
3
+ ---
4
+
5
+ # /wf-auto
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
+ 3. Execute per the skill adapter `.claude/skills/wf-auto/SKILL.md` (mirror: `.agents/skills/wf-auto/SKILL.md`).
13
+ 4. Do not duplicate the workflow here. The skill adapter and `Harness/specs/workflows/WF-AUTO.md` are authoritative.
14
+
15
+ If this runtime cannot invoke the skill directly, read
16
+ `.claude/skills/wf-auto/SKILL.md` and follow it in place.
@@ -10,7 +10,7 @@ static help or script command.
10
10
  1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
11
  2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
12
  3. Execute per the skill adapter `.claude/skills/wf-browser/SKILL.md` (mirror: `.agents/skills/wf-browser/SKILL.md`).
13
- 4. Do not duplicate the workflow here. The skill adapter and `Harness/workflows/browser-e2e.md` are authoritative.
13
+ 4. Do not duplicate the workflow here. The skill adapter and `Harness/specs/protocols/HARNESS_BRIDGE.md` are authoritative.
14
14
 
15
15
  If this runtime cannot invoke the skill directly, read
16
16
  `.claude/skills/wf-browser/SKILL.md` and follow it in place.
@@ -0,0 +1,58 @@
1
+ # /wf-command-create
2
+
3
+ Create or modify a Harness wf-* command surface atomically. Do not invoke a skill or start WF mode.
4
+
5
+ ## Classification
6
+
7
+ DIRECT command. It is a Harness maintenance command: it must create or resume a task capsule, then update every command surface declared by `Harness/specs/runtime/command-surface.json`. Never loads `Harness/MEMORY.md` as part of command routing.
8
+
9
+ ## Usage
10
+
11
+ /wf-command-create <wf-command-id> [--direct|--workflow] [--task <task-id>]
12
+
13
+ - Command id must be `wf` or `wf-*` kebab-case.
14
+ - Use an existing task capsule when `--task` is supplied or when the active task clearly matches.
15
+ - Otherwise create a `task-<verb>-<noun>[-detail]` capsule with `node Harness/scripts/task-state.mjs record <task-id> --create --apply --json`.
16
+ - Record the command id, classification, and validation evidence in the task capsule.
17
+
18
+ ## Required Surface Checklist
19
+
20
+ Update all applicable files before returning:
21
+
22
+ - `Harness/specs/runtime/command-surface.json`
23
+ - `.claude/commands/<id>.md`
24
+ - `.opencode/commands/<id>.md`
25
+ - `.claude/skills/<id>/SKILL.md` when Codex compatibility or workflow routing is needed
26
+ - `.agents/skills/<id>/SKILL.md` mirror when a Claude skill exists
27
+ - Matching `templates/common/...` files
28
+ - `CLAUDE.md` and `templates/common/CLAUDE.md`
29
+ - `.claude/rules/ecc/common.md` and template mirror
30
+ - `.claude/commands/wf-help.md`, `.opencode/commands/wf-help.md`, and template mirrors
31
+ - `Harness/README.md`, `Harness/MEMORY.md`, and template mirrors
32
+ - `Harness/scripts/validate-harness.mjs` and template mirror
33
+ - `Harness/scripts/wf-remove.mjs` and template mirror
34
+ - `tests/generator.test.js`, `tests/anti-drift.test.js`, and `tests/validate-harness.test.js`
35
+ - `Harness/.harness-version`, `templates/common/.harness-version`, and ownership manifests via `node scripts/build-version.mjs`
36
+
37
+ ## Validation
38
+
39
+ Run, at minimum:
40
+
41
+ ```bash
42
+ npm test
43
+ node Harness/scripts/validate-harness.mjs
44
+ node templates/common/Harness/scripts/validate-harness.mjs
45
+ node Harness/scripts/context-budget.mjs --json
46
+ node scripts/build-version.mjs --check
47
+ npm run check:mirrors
48
+ git diff --check
49
+ ```
50
+
51
+ If a check is blocked by an existing unrelated repository issue, record the command, failure, and reason in the task capsule.
52
+
53
+ ## Return
54
+
55
+ - Command id and classification.
56
+ - Task capsule path.
57
+ - Files changed by surface category.
58
+ - Verification results.
@@ -3,6 +3,9 @@
3
3
  Return this help table directly. Do not invoke a skill, do not start WF mode,
4
4
  do not dispatch agents, and do not edit files.
5
5
 
6
+ Codex compatibility: `$wf-help` or `/skills wf-help` loads the `wf-help` shim,
7
+ which returns this same table without loading `Harness/MEMORY.md` or entering WF.
8
+
6
9
  | Command | Type | Usage | Purpose |
7
10
  | --- | --- | --- | --- |
8
11
  | `/wf-help` | direct command | `/wf-help` | Show this command table. |
@@ -12,14 +15,18 @@ do not dispatch agents, and do not edit files.
12
15
  | `/wf-auto-spark` | workflow skill | `/wf-auto-spark` | Perpetual inspiration mode with roadmap anchoring and external spark search. |
13
16
  | `/wf-review <focus>` | workflow skill | `/wf-review security and test coverage` | Peer CLI review through Claude/Codex/OpenCode, with reviewer subagent fallback. |
14
17
  | `/wf-learn` | workflow skill | `/wf-learn` | Force context-master -> memory-master learning cycle after repeated failures or closeout. |
15
- | `/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 when installed. |
18
+ | `/wf-browser <task>` | workflow skill | `/wf-browser verify checkout flow` | Built-in browser automation/E2E workflow with real UI interaction, screenshots, traces, and CDP/network evidence. |
16
19
  | `/wf-readme <task>` | workflow skill | `/wf-readme polish quickstart` | Preserve, merge, or improve README docs without trampling existing project documentation. |
17
20
  | `/wf-update` | direct command | `/wf-update` | Check/apply Harness scaffold updates with safe file classification and conflict handling. |
18
21
  | `/wf-remove` | workflow skill | `/wf-remove` | Safely remove Harness files while preserving project/user data unless explicitly purged. |
22
+ | `/wf-task-record <task-id>` | direct command | `/wf-task-record my-feature --create` | Record user intent into a task capsule (wraps task-state.mjs). |
23
+ | `/wf-task-list` | direct command | `/wf-task-list` | List all task capsules with status, phase, and dependencies. |
24
+ | `/wf-task-archive [--apply]` | direct command | `/wf-task-archive --apply` | Archive completed task capsules (dry-run by default). |
25
+ | `/wf-command-create <wf-command-id>` | direct command | `/wf-command-create wf-report --direct` | Create or modify wf-* command surfaces atomically from the command registry. |
19
26
 
20
27
  Source of truth: `Harness/README.md#Skill Commands` plus installed skills under
21
- `.claude/skills/` (Claude Code) or `.agents/skills/` (Codex). In OpenCode the
22
- same skills load from `.claude/skills/`, `.agents/skills/`, and `.opencode/skills/`.
23
- In OpenCode, every workflow command above is also visible as a thin command
24
- wrapper under `.opencode/commands/` (e.g. `/wf`, `/wf-max`); each wrapper only
25
- routes to the matching skill adapter and does not duplicate the workflow.
28
+ `.claude/skills/` (Claude Code and OpenCode adapters) or `.agents/skills/`
29
+ (Codex). In OpenCode, every workflow command above is visible as a thin command
30
+ wrapper under `.opencode/commands/` (e.g. `/wf`, `/wf-max`); each wrapper routes
31
+ to the matching `.claude/skills/<command>/SKILL.md` adapter and does not
32
+ duplicate the workflow.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Run the context-master -> memory-master learning cycle via the wf-learn skill
3
+ ---
4
+
5
+ # /wf-learn
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
+ 3. Execute per the skill adapter `.claude/skills/wf-learn/SKILL.md` (mirror: `.agents/skills/wf-learn/SKILL.md`).
13
+ 4. Do not duplicate the workflow here. The skill adapter and `Harness/specs/protocols/MEMORY_PROTOCOL.md` are authoritative.
14
+
15
+ If this runtime cannot invoke the skill directly, read
16
+ `.claude/skills/wf-learn/SKILL.md` and follow it in place.
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: Run WF-MAX with mandatory subagent fan-out and recorded degradation
3
+ ---
4
+
5
+ # /wf-max
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Load and follow `.claude/skills/wf-max/SKILL.md` (mirror: `.agents/skills/wf-max/SKILL.md`) and `Harness/specs/workflows/WF-MAX.md`.
12
+ 3. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
13
+ 4. MUST attempt native runtime subagent fan-out before planning is considered complete:
14
+ - start `task-scribe` when available for task ledger/state;
15
+ - start W0 exploration through manager/explorer/researcher roles with disjoint read sets;
16
+ - when running in OpenCode, require project `opencode.json` to have `subagent_depth >= 2` and manager agents to have `permission.task` allowlists for manager -> worker fan-out;
17
+ - if nested manager fan-out is unavailable, dispatch leaf workers directly from the primary agent with exact WF-MAX dispatch packets.
18
+ 5. In every runtime, MUST attempt native subagent fan-out before implementation planning is considered complete; never silently continue as a solo controller.
19
+ 6. If native fan-out fails, record `fanoutAttempted: true`, runtime, channel tried, agents requested, failure/degradation reason, and the fallback path in `Harness/tasks/<task-id>/PLAN.md` or `PROGRESS.md`.
20
+ 7. Continue with WF-Max-Useful by default or WF-Max-Strict only when the user explicitly requests strict mode.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Run the README preservation and improvement workflow via the wf-readme skill
3
+ ---
4
+
5
+ # /wf-readme
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
+ 3. Execute per the skill adapter `.claude/skills/wf-readme/SKILL.md` (mirror: `.agents/skills/wf-readme/SKILL.md`).
13
+ 4. Do not duplicate the workflow here. The skill adapter and the project root \`README.md\` ownership rules are authoritative.
14
+
15
+ If this runtime cannot invoke the skill directly, read
16
+ `.claude/skills/wf-readme/SKILL.md` and follow it in place.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Run safe harness removal via the wf-remove skill
3
+ ---
4
+
5
+ # /wf-remove
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
+ 3. Execute per the skill adapter `.claude/skills/wf-remove/SKILL.md` (mirror: `.agents/skills/wf-remove/SKILL.md`).
13
+ 4. Do not duplicate the workflow here. The skill adapter and `Harness/scripts/wf-remove.mjs` are authoritative.
14
+
15
+ If this runtime cannot invoke the skill directly, read
16
+ `.claude/skills/wf-remove/SKILL.md` and follow it in place.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Run peer CLI or reviewer-subagent review via the wf-review skill
3
+ ---
4
+
5
+ # /wf-review
6
+
7
+ This is a **workflow command**, not a direct command. Do not execute it as a
8
+ static help or script command.
9
+
10
+ 1. Load `CLAUDE.md`, `Harness/MEMORY.md` (index only per Memory Preflight), then `Harness/README.md`.
11
+ 2. Preserve cache-first order per `Harness/specs/runtime/context-loading.md#Cache-First Context Contract`.
12
+ 3. Execute per the skill adapter `.claude/skills/wf-review/SKILL.md` (mirror: `.agents/skills/wf-review/SKILL.md`).
13
+ 4. Do not duplicate the workflow here. The skill adapter and the wf-review peer-review contract are authoritative.
14
+
15
+ If this runtime cannot invoke the skill directly, read
16
+ `.claude/skills/wf-review/SKILL.md` and follow it in place.
@@ -0,0 +1,26 @@
1
+ # /wf-task-archive
2
+
3
+ Archive completed/obsolete task capsules to `Harness/tasks/_archive/`. Do not invoke a skill or start WF mode.
4
+
5
+ ## Classification
6
+
7
+ DIRECT command. Wraps `node Harness/scripts/task-state.mjs archive`. Never loads Harness/MEMORY.md.
8
+
9
+ ## Usage
10
+
11
+ /wf-task-archive [--dry-run] [--apply] [--task <id>] [--keep <n>]
12
+
13
+ - Defaults to dry-run (`--dry-run`) without `--apply`.
14
+ - With `--apply`: moves eligible task directories into yearly subdirectories under `_archive/`.
15
+ - With `--task <id>`: targets a specific task for archive eligibility check.
16
+ - With `--keep <n>`: keeps N most recent non-archived task capsules (default 5).
17
+ - Tasks with active, blocked, in_progress, running, pending, or needs-user-decision status are never auto-archived.
18
+
19
+ ## Execution
20
+
21
+ Run: `node Harness/scripts/task-state.mjs archive [--dry-run] [--apply] [--task <id>] [--keep <n>] [--json]`
22
+
23
+ ## Return
24
+
25
+ - JSON output with archive plan: scanned, archiveable, toArchive, kept, skipped counts and per-task results.
26
+ - If the command fails, report the error and do not retry.
@@ -0,0 +1,24 @@
1
+ # /wf-task-list
2
+
3
+ List Harness task capsules with state, phase, status, and dependency info. Do not invoke a skill or start WF mode.
4
+
5
+ ## Classification
6
+
7
+ DIRECT command. Wraps `node Harness/scripts/task-state.mjs list --json`. Never loads Harness/MEMORY.md.
8
+
9
+ ## Usage
10
+
11
+ /wf-task-list [--json]
12
+
13
+ - By default, returns a human-readable listing of all task capsules.
14
+ - With --json, returns structured JSON output.
15
+ - Shows active, open, blocked, verified tasks with dependency info.
16
+
17
+ ## Execution
18
+
19
+ Run: `node Harness/scripts/task-state.mjs list --json`
20
+
21
+ ## Return
22
+
23
+ - JSON output of all task capsules with status, phase, dependencies, and archive eligibility.
24
+ - If the command fails, report the error and do not retry.