dev-harness-cli 1.1.0 → 2.1.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 (41) hide show
  1. package/README.md +515 -135
  2. package/cli/commands/checkpoint.mjs +2 -2
  3. package/cli/commands/config.mjs +12 -12
  4. package/cli/commands/contract.mjs +10 -10
  5. package/cli/commands/detect-tool.mjs +3 -3
  6. package/cli/commands/init.mjs +1 -1
  7. package/cli/commands/learn.mjs +3 -3
  8. package/cli/commands/pause.mjs +1 -1
  9. package/cli/commands/phase.mjs +6 -6
  10. package/cli/commands/resume.mjs +3 -3
  11. package/cli/commands/rollback.mjs +6 -6
  12. package/cli/commands/set-mode.mjs +5 -5
  13. package/cli/commands/status.mjs +7 -7
  14. package/cli/commands/validate.mjs +7 -7
  15. package/cli/commands/worktree.mjs +6 -6
  16. package/cli/{harness-dev.mjs → dev-harness.mjs} +2 -2
  17. package/cli/lib/config-registry.mjs +2 -2
  18. package/cli/lib/constants.mjs +19 -2
  19. package/cli/lib/contract.mjs +3 -3
  20. package/cli/lib/gates.mjs +1 -1
  21. package/cli/lib/help.mjs +28 -28
  22. package/cli/lib/ralph-inner.mjs +2 -2
  23. package/cli/lib/ralph-outer.mjs +3 -3
  24. package/cli/lib/ralph-output.mjs +1 -1
  25. package/cli/lib/scaffold.mjs +1 -1
  26. package/cli/lib/state.mjs +1 -1
  27. package/package.json +13 -4
  28. package/templates/AGENTS.md +5 -5
  29. package/templates/ci/github-actions.yml +1 -1
  30. package/templates/ci/gitlab-ci.yml +1 -1
  31. package/templates/docs/agents/generator.md +1 -1
  32. package/templates/docs/agents/simplifier.md +1 -1
  33. package/templates/docs/phases/build.md +3 -3
  34. package/templates/docs/phases/define.md +3 -3
  35. package/templates/docs/phases/plan.md +3 -3
  36. package/templates/docs/phases/review.md +2 -2
  37. package/templates/docs/phases/ship.md +3 -3
  38. package/templates/docs/phases/simplify.md +3 -3
  39. package/templates/docs/phases/verify.md +2 -2
  40. package/templates/init.ps1 +1 -1
  41. package/templates/progress.md +1 -1
@@ -9,7 +9,7 @@
9
9
  * save named recovery points (e.g. "before-refactor") that appear
10
10
  * in `rollback list` and can be used with `rollback to/branch`.
11
11
  *
12
- * Usage: harness-dev checkpoint create <label>
12
+ * Usage: dev-harness checkpoint create <label>
13
13
  */
14
14
  import { die, CliError, EXIT } from '../lib/errors.mjs';
15
15
  import { execGit, getGitRoot, gitTagExists, createGitTag } from '../lib/git.mjs';
@@ -21,7 +21,7 @@ export default async function checkpointCommand(args) {
21
21
  const label = args.positionals[0];
22
22
 
23
23
  if (sub !== 'create' || !label) {
24
- die(new CliError('Usage: harness-dev checkpoint create <label> [--force]', EXIT.USAGE_ERROR), json);
24
+ die(new CliError('Usage: dev-harness checkpoint create <label> [--force]', EXIT.USAGE_ERROR), json);
25
25
  return;
26
26
  }
27
27
 
@@ -4,16 +4,16 @@
4
4
  * Uses state.mjs for dot-notation read/write with persistence.
5
5
  *
6
6
  * Usage:
7
- * harness-dev config list — list all parameters with descriptions
8
- * harness-dev config get [key] — get a value or all config
9
- * harness-dev config set <key> <value> — set a value
7
+ * dev-harness config list — list all parameters with descriptions
8
+ * dev-harness config get [key] — get a value or all config
9
+ * dev-harness config set <key> <value> — set a value
10
10
  *
11
11
  * Examples:
12
- * harness-dev config list
13
- * harness-dev config list --json
14
- * harness-dev config get gates.enabled
15
- * harness-dev config set gates.enabled true
16
- * harness-dev config set maxRetries 5
12
+ * dev-harness config list
13
+ * dev-harness config list --json
14
+ * dev-harness config get gates.enabled
15
+ * dev-harness config set gates.enabled true
16
+ * dev-harness config set maxRetries 5
17
17
  */
18
18
  import { resolve } from 'node:path';
19
19
  import { die, CliError, EXIT } from '../lib/errors.mjs';
@@ -29,7 +29,7 @@ export default async function configCommand(args) {
29
29
 
30
30
  if (!sub || (sub !== 'get' && sub !== 'set' && sub !== 'list')) {
31
31
  die(new CliError(
32
- 'Usage: harness-dev config list | config get [key] | config set <key> <value>',
32
+ 'Usage: dev-harness config list | config get [key] | config set <key> <value>',
33
33
  EXIT.USAGE_ERROR,
34
34
  ), json);
35
35
  return;
@@ -75,7 +75,7 @@ export default async function configCommand(args) {
75
75
  // Human output — grouped table
76
76
  process.stdout.write('═══ Harness Configuration ═══\n\n');
77
77
  if (!ok) {
78
- process.stdout.write(' No harness/config.json found. Run: harness-dev init\n\n');
78
+ process.stdout.write(' No harness/config.json found. Run: dev-harness init\n\n');
79
79
  return;
80
80
  }
81
81
 
@@ -102,7 +102,7 @@ export default async function configCommand(args) {
102
102
  process.stdout.write('\n');
103
103
  }
104
104
 
105
- process.stdout.write('Edit with: harness-dev config set <key> <value>\n');
105
+ process.stdout.write('Edit with: dev-harness config set <key> <value>\n');
106
106
  process.stdout.write('Full docs: docs/CONFIGURATION.md\n');
107
107
  return;
108
108
  }
@@ -141,7 +141,7 @@ export default async function configCommand(args) {
141
141
  if (sub === 'set') {
142
142
  if (pos.length < 2) {
143
143
  die(new CliError(
144
- 'Usage: harness-dev config set <key> <value>\n' +
144
+ 'Usage: dev-harness config set <key> <value>\n' +
145
145
  ' String values: config set mode copilot\n' +
146
146
  ' Boolean values: config set gates.enabled true\n' +
147
147
  ' Numeric values: config set maxRetries 5',
@@ -4,10 +4,10 @@
4
4
  * Manages the generator-evaluator agreement loop.
5
5
  *
6
6
  * Usage:
7
- * harness-dev contract propose [--scope "msg"] [--exclusions "msg"]
8
- * harness-dev contract review [--agreed|--needs-revision]
9
- * harness-dev contract status
10
- * harness-dev contract escalate [--reason "msg"]
7
+ * dev-harness contract propose [--scope "msg"] [--exclusions "msg"]
8
+ * dev-harness contract review [--agreed|--needs-revision]
9
+ * dev-harness contract status
10
+ * dev-harness contract escalate [--reason "msg"]
11
11
  */
12
12
  import { resolve } from 'node:path';
13
13
  import { die, CliError, EXIT } from '../lib/errors.mjs';
@@ -22,7 +22,7 @@ export default async function contractCommand(args) {
22
22
  const sub = args.subcommand;
23
23
 
24
24
  if (!sub || !SUBCOMMANDS.includes(sub)) {
25
- die(new CliError(`Usage: harness-dev contract ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
25
+ die(new CliError(`Usage: dev-harness contract ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
26
26
  return;
27
27
  }
28
28
 
@@ -34,7 +34,7 @@ export default async function contractCommand(args) {
34
34
 
35
35
  if (!scope) {
36
36
  die(new CliError(
37
- 'Usage: harness-dev contract propose --scope "I will build X" [--exclusions "W"] [--criteria "test1|test2"]',
37
+ 'Usage: dev-harness contract propose --scope "I will build X" [--exclusions "W"] [--criteria "test1|test2"]',
38
38
  EXIT.USAGE_ERROR,
39
39
  ), json);
40
40
  return;
@@ -53,7 +53,7 @@ export default async function contractCommand(args) {
53
53
  }
54
54
 
55
55
  if (result.ok) {
56
- process.stdout.write('✓ Contract proposed. Run: harness-dev contract review\n');
56
+ process.stdout.write('✓ Contract proposed. Run: dev-harness contract review\n');
57
57
  } else {
58
58
  process.stderr.write(`✗ ${result.error}\n`);
59
59
  }
@@ -68,7 +68,7 @@ export default async function contractCommand(args) {
68
68
 
69
69
  if (!agreed && !needsRevision) {
70
70
  die(new CliError(
71
- 'Usage: harness-dev contract review --agreed [--notes "msg"] OR --needs-revision [--notes "msg"]',
71
+ 'Usage: dev-harness contract review --agreed [--notes "msg"] OR --needs-revision [--notes "msg"]',
72
72
  EXIT.USAGE_ERROR,
73
73
  ), json);
74
74
  return;
@@ -116,7 +116,7 @@ export default async function contractCommand(args) {
116
116
  rounds,
117
117
  message: status
118
118
  ? `Contract ${status} (round ${rounds}/5)`
119
- : 'No sprint-contract.md found. Run: harness-dev contract propose',
119
+ : 'No sprint-contract.md found. Run: dev-harness contract propose',
120
120
  }) + '\n');
121
121
  return;
122
122
  }
@@ -124,7 +124,7 @@ export default async function contractCommand(args) {
124
124
  if (status) {
125
125
  process.stdout.write(`Contract status: ${status} (round ${rounds}/5)\n`);
126
126
  } else {
127
- process.stdout.write('No sprint-contract.md found. Run: harness-dev contract propose\n');
127
+ process.stdout.write('No sprint-contract.md found. Run: dev-harness contract propose\n');
128
128
  }
129
129
  return;
130
130
  }
@@ -12,7 +12,7 @@
12
12
  * Also reads harness-config.json agentTool field if present.
13
13
  *
14
14
  * Usage:
15
- * harness-dev detect-tool [--target <dir>] [--json]
15
+ * dev-harness detect-tool [--target <dir>] [--json]
16
16
  */
17
17
  import { existsSync } from 'node:fs';
18
18
  import { resolve } from 'node:path';
@@ -80,7 +80,7 @@ export default async function detectToolCommand(args) {
80
80
  status: 'ok',
81
81
  message: detected.length > 0
82
82
  ? `Detected ${detected.length} agent tool(s): ${detected.join(', ')}`
83
- : 'No agent tools detected. Run: harness-dev init',
83
+ : 'No agent tools detected. Run: dev-harness init',
84
84
  available: detected,
85
85
  configured: configuredTool,
86
86
  recommended,
@@ -104,7 +104,7 @@ export default async function detectToolCommand(args) {
104
104
  }
105
105
  } else {
106
106
  emitHuman(` No agent tools detected.\n`);
107
- emitHuman(` Run: harness-dev init to scaffold a project.\n`);
107
+ emitHuman(` Run: dev-harness init to scaffold a project.\n`);
108
108
  }
109
109
  if (hasAgentsMd) {
110
110
  emitHuman(`\n AGENTS.md present — tools that read it natively are available.\n`);
@@ -6,7 +6,7 @@
6
6
  * init.sh, progress.md, sprint-contract.md) plus project files (feature_list.json,
7
7
  * feature-list.schema.json, session-handoff.md, etc.), git init, .gitignore.
8
8
  *
9
- * Usage: harness-dev init [--stack <name>] [--target <dir>] [--agent-tool <name>] [--force] [--no-git] [--json]
9
+ * Usage: dev-harness init [--stack <name>] [--target <dir>] [--agent-tool <name>] [--force] [--no-git] [--json]
10
10
  */
11
11
  import { resolve, join } from 'node:path';
12
12
  import {
@@ -2,8 +2,8 @@
2
2
  * learn — Append a lesson to progress.md.
3
3
  *
4
4
  * Usage:
5
- * harness-dev learn "Lesson text here"
6
- * harness-dev learn "Lesson text" --json
5
+ * dev-harness learn "Lesson text here"
6
+ * dev-harness learn "Lesson text" --json
7
7
  */
8
8
  import { CliError, EXIT, die } from '../lib/errors.mjs';
9
9
  import { appendLesson } from '../lib/progress.mjs';
@@ -17,7 +17,7 @@ export default async function learnCommand(args) {
17
17
  if (!message) {
18
18
  die(
19
19
  new CliError(
20
- 'Lesson message required.\n Example: harness-dev learn "Token refresh gotcha — accepts access_token in body"',
20
+ 'Lesson message required.\n Example: dev-harness learn "Token refresh gotcha — accepts access_token in body"',
21
21
  EXIT.USAGE_ERROR,
22
22
  ),
23
23
  json,
@@ -4,7 +4,7 @@
4
4
  * Sets config.paused = true. The outer loop checks this
5
5
  * before starting a new phase in autopilot mode.
6
6
  *
7
- * Usage: harness-dev pause [--json]
7
+ * Usage: dev-harness pause [--json]
8
8
  */
9
9
  import { set } from '../lib/state.mjs';
10
10
  import { parseCommandArgs } from '../lib/command-helpers.mjs';
@@ -5,8 +5,8 @@
5
5
  * then triggers the outer loop for autopilot advancement.
6
6
  *
7
7
  * Usage:
8
- * harness-dev phase <name>
9
- * harness-dev phase <name> --json
8
+ * dev-harness phase <name>
9
+ * dev-harness phase <name> --json
10
10
  */
11
11
  import { CliError, EXIT, die } from '../lib/errors.mjs';
12
12
  import { transitionPhase, getPhaseOrder, loadConfig } from '../lib/state.mjs';
@@ -51,7 +51,7 @@ export default async function phaseCommand(args) {
51
51
  const { config: preConfig, ok: preOk } = loadConfig(targetDir);
52
52
  const preMode = preOk ? (preConfig.mode ?? 'copilot') : 'copilot';
53
53
  if (preOk && preConfig.paused && preMode === 'autopilot') {
54
- const msg = 'Pipeline is paused. Run: harness-dev resume';
54
+ const msg = 'Pipeline is paused. Run: dev-harness resume';
55
55
  if (json) {
56
56
  process.stdout.write(JSON.stringify({
57
57
  command: 'phase',
@@ -140,11 +140,11 @@ export default async function phaseCommand(args) {
140
140
  if (pipelineResult.status === 'complete') {
141
141
  process.stdout.write(`\n✓ Pipeline complete. All phases done.\n`);
142
142
  } else if (pipelineResult.status === 'instruction') {
143
- process.stdout.write(`\nNext: harness-dev phase ${pipelineResult.nextPhase}\n`);
143
+ process.stdout.write(`\nNext: dev-harness phase ${pipelineResult.nextPhase}\n`);
144
144
  }
145
145
  } else if (nextPhase) {
146
146
  // Copilot: print next step
147
- process.stdout.write(`Next: harness-dev phase ${nextPhase}\n`);
147
+ process.stdout.write(`Next: dev-harness phase ${nextPhase}\n`);
148
148
  // Auto-prompt: controlled by two independent flags:
149
149
  // autoPrompt=true → show the prompt
150
150
  // confirmGates=true → require y/n answer before continuing
@@ -158,7 +158,7 @@ export default async function phaseCommand(args) {
158
158
  process.stdout.write(`\n✓ Pipeline complete. All phases done.\n`);
159
159
  }
160
160
  } else if (answer === false) {
161
- process.stdout.write(` Staying in ${phase.toUpperCase()}. Run: harness-dev phase ${nextPhase} when ready.\n`);
161
+ process.stdout.write(` Staying in ${phase.toUpperCase()}. Run: dev-harness phase ${nextPhase} when ready.\n`);
162
162
  }
163
163
  // null = no TTY, skipped
164
164
  } else {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Sets config.paused = false. Allows autopilot to continue.
5
5
  *
6
- * Usage: harness-dev resume [--json]
6
+ * Usage: dev-harness resume [--json]
7
7
  */
8
8
  import { set } from '../lib/state.mjs';
9
9
  import { parseCommandArgs } from '../lib/command-helpers.mjs';
@@ -19,14 +19,14 @@ export default async function resumeCommand(args) {
19
19
  command: 'resume',
20
20
  status: result.ok ? 'ok' : 'error',
21
21
  message: result.ok
22
- ? 'Pipeline resumed. Run: harness-dev phase <name> to continue.'
22
+ ? 'Pipeline resumed. Run: dev-harness phase <name> to continue.'
23
23
  : (result.error || 'Failed to resume'),
24
24
  });
25
25
  return;
26
26
  }
27
27
 
28
28
  if (result.ok) {
29
- emitHuman('✓ Pipeline resumed. Run: harness-dev phase <name> to continue.\n');
29
+ emitHuman('✓ Pipeline resumed. Run: dev-harness phase <name> to continue.\n');
30
30
  } else {
31
31
  emitHumanError(`✗ ${result.error}\n`);
32
32
  }
@@ -13,7 +13,7 @@
13
13
  * manual/<label> — User-created manual checkpoints
14
14
  * recovery/* — Recovery branches (for informational display)
15
15
  *
16
- * Usage: harness-dev rollback <subcommand> [checkpoint]
16
+ * Usage: dev-harness rollback <subcommand> [checkpoint]
17
17
  */
18
18
  import { die, CliError, EXIT } from '../lib/errors.mjs';
19
19
  import { execGit, getGitRoot } from '../lib/git.mjs';
@@ -67,12 +67,12 @@ export default async function rollbackCommand(args) {
67
67
  const sub = args.subcommand;
68
68
 
69
69
  if (!sub || !SUBCOMMANDS.includes(sub)) {
70
- die(new CliError(`Usage: harness-dev rollback ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
70
+ die(new CliError(`Usage: dev-harness rollback ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
71
71
  return;
72
72
  }
73
73
 
74
74
  if (sub !== 'list' && args.positionals.length < 1) {
75
- die(new CliError(`Usage: harness-dev rollback ${sub} <checkpoint>`, EXIT.USAGE_ERROR), json);
75
+ die(new CliError(`Usage: dev-harness rollback ${sub} <checkpoint>`, EXIT.USAGE_ERROR), json);
76
76
  return;
77
77
  }
78
78
 
@@ -118,7 +118,7 @@ export default async function rollbackCommand(args) {
118
118
  } else {
119
119
  if (checkpoints.length === 0 && recoveryBranches.length === 0) {
120
120
  process.stdout.write('No checkpoints found. Phase tags (phase/*) and iteration tags (iter/*) are created automatically when auto-tagging is enabled.\n');
121
- process.stdout.write('Manual checkpoints: harness-dev checkpoint create <label>\n');
121
+ process.stdout.write('Manual checkpoints: dev-harness checkpoint create <label>\n');
122
122
  } else {
123
123
  if (checkpoints.length > 0) {
124
124
  process.stdout.write('Checkpoints:\n');
@@ -146,7 +146,7 @@ export default async function rollbackCommand(args) {
146
146
  // Verify the tag exists
147
147
  const tagCheck = execGit(`git rev-parse --verify "${checkpoint}^{commit}"`, gitRoot);
148
148
  if (!tagCheck.ok) {
149
- const msg = `Checkpoint "${checkpoint}" not found. Run: harness-dev rollback list`;
149
+ const msg = `Checkpoint "${checkpoint}" not found. Run: dev-harness rollback list`;
150
150
  if (json) {
151
151
  process.stdout.write(JSON.stringify({ command: 'rollback', subcommand: 'to', checkpoint, status: 'error', message: msg }) + '\n');
152
152
  } else {
@@ -205,7 +205,7 @@ export default async function rollbackCommand(args) {
205
205
  // Verify the tag exists
206
206
  const tagCheck = execGit(`git rev-parse --verify "${checkpoint}^{commit}"`, gitRoot);
207
207
  if (!tagCheck.ok) {
208
- const msg = `Checkpoint "${checkpoint}" not found. Run: harness-dev rollback list`;
208
+ const msg = `Checkpoint "${checkpoint}" not found. Run: dev-harness rollback list`;
209
209
  if (json) {
210
210
  process.stdout.write(JSON.stringify({ command: 'rollback', subcommand: 'branch', checkpoint, status: 'error', message: msg }) + '\n');
211
211
  } else {
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * set-mode — Switch between copilot and autopilot.
3
3
  *
4
- * Usage: harness-dev set-mode <mode>
5
- * harness-dev set-mode autopilot
6
- * harness-dev set-mode copilot
7
- * harness-dev set-mode autopilot --json
4
+ * Usage: dev-harness set-mode <mode>
5
+ * dev-harness set-mode autopilot
6
+ * dev-harness set-mode copilot
7
+ * dev-harness set-mode autopilot --json
8
8
  */
9
9
  import { die, CliError, EXIT } from '../lib/errors.mjs';
10
10
  import { set, loadConfig, getPhaseOrder } from '../lib/state.mjs';
@@ -19,7 +19,7 @@ export default async function setModeCommand(args) {
19
19
  if (!mode || !valid.includes(mode)) {
20
20
  die(
21
21
  new CliError(
22
- `Mode required. Valid: ${valid.join(', ')}.\n Example: harness-dev set-mode autopilot`,
22
+ `Mode required. Valid: ${valid.join(', ')}.\n Example: dev-harness set-mode autopilot`,
23
23
  EXIT.USAGE_ERROR,
24
24
  ),
25
25
  json,
@@ -4,7 +4,7 @@
4
4
  * Reads harness-config.json via state.mjs for live project state,
5
5
  * plus runs stack detection and gate checks for current status.
6
6
  *
7
- * Usage: harness-dev status [--json] [--target <dir>]
7
+ * Usage: dev-harness status [--json] [--target <dir>]
8
8
  */
9
9
  import { resolve, basename } from 'node:path';
10
10
  import { detectStack } from '../lib/detect-stack.mjs';
@@ -61,7 +61,7 @@ export default async function statusCommand(args) {
61
61
  status: 'ok',
62
62
  message: configOk
63
63
  ? `Phase: ${phase || 'not started'}, Stack: ${stack.label}`
64
- : 'No harness/config.json found — run harness-dev init',
64
+ : 'No harness/config.json found — run dev-harness init',
65
65
  project: basename(targetDir),
66
66
  stack: stack.name,
67
67
  stackLabel: stack.label,
@@ -150,19 +150,19 @@ function gateStatusLabel(status, passing, total) {
150
150
 
151
151
  function determineNextAction(targetDir, configOk, config, phase, gateStatus) {
152
152
  if (!configOk) {
153
- return 'Run: harness-dev init';
153
+ return 'Run: dev-harness init';
154
154
  }
155
155
  if (!phase) {
156
- return 'Run: harness-dev phase define to start';
156
+ return 'Run: dev-harness phase define to start';
157
157
  }
158
158
  if (gateStatus === 'fail') {
159
- return 'Run: harness-dev validate to re-check';
159
+ return 'Run: dev-harness validate to re-check';
160
160
  }
161
161
  // Determine next phase
162
162
  const order = ['define', 'plan', 'build', 'verify', 'review', 'ship'];
163
163
  const idx = order.indexOf(phase);
164
164
  if (idx >= 0 && idx < order.length - 1) {
165
- return `Run: harness-dev phase ${order[idx + 1]}`;
165
+ return `Run: dev-harness phase ${order[idx + 1]}`;
166
166
  }
167
- return `Run: harness-dev validate`;
167
+ return `Run: dev-harness validate`;
168
168
  }
@@ -5,15 +5,15 @@
5
5
  * Otherwise runs phase-specific checks and reports results.
6
6
  *
7
7
  * Usage:
8
- * harness-dev validate — check current phase
9
- * harness-dev validate --json — machine-readable output
10
- * harness-dev validate --phase X — check specific phase
8
+ * dev-harness validate — check current phase
9
+ * dev-harness validate --json — machine-readable output
10
+ * dev-harness validate --phase X — check specific phase
11
11
  *
12
12
  * Examples:
13
- * harness-dev validate
13
+ * dev-harness validate
14
14
  * # → BUILD Gate: PASS — 3/3 checks pass
15
15
  *
16
- * harness-dev validate --json
16
+ * dev-harness validate --json
17
17
  * # → {"phase":"build","checks":[...],"overall":false,"failures":["lint"]}
18
18
  */
19
19
  import { resolve } from 'node:path';
@@ -53,7 +53,7 @@ export default async function validateCommand(args) {
53
53
  if (task) { out.task = task; }
54
54
  process.stdout.write(JSON.stringify(out) + '\n');
55
55
  } else {
56
- process.stdout.write('Gates disabled. Enable with: harness-dev config set gates.enabled true\n');
56
+ process.stdout.write('Gates disabled. Enable with: dev-harness config set gates.enabled true\n');
57
57
  }
58
58
  return;
59
59
  }
@@ -62,7 +62,7 @@ export default async function validateCommand(args) {
62
62
  if (!phase) {
63
63
  die(
64
64
  new CliError(
65
- 'No phase found in config. Run: harness-dev init or harness-dev phase <name>',
65
+ 'No phase found in config. Run: dev-harness init or dev-harness phase <name>',
66
66
  EXIT.VALIDATION_FAILURE,
67
67
  ),
68
68
  json,
@@ -8,7 +8,7 @@
8
8
  * prune — git worktree prune (remove orphaned metadata)
9
9
  * remove <name> — git worktree remove + optionally delete branch
10
10
  *
11
- * Usage: harness-dev worktree <subcommand> [name] [options]
11
+ * Usage: dev-harness worktree <subcommand> [name] [options]
12
12
  */
13
13
  import { existsSync } from 'node:fs';
14
14
  import { resolve, dirname } from 'node:path';
@@ -25,13 +25,13 @@ export default async function worktreeCommand(args) {
25
25
  const sub = args.subcommand;
26
26
 
27
27
  if (!sub || !SUBCOMMANDS.includes(sub)) {
28
- die(new CliError(`Usage: harness-dev worktree ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
28
+ die(new CliError(`Usage: dev-harness worktree ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
29
29
  return;
30
30
  }
31
31
 
32
32
  const gitRoot = getGitRoot(targetDir);
33
33
  if (!gitRoot) {
34
- const msg = 'Not inside a git repository. Run: git init first or harness-dev init';
34
+ const msg = 'Not inside a git repository. Run: git init first or dev-harness init';
35
35
  if (json) {
36
36
  process.stdout.write(JSON.stringify({ command: 'worktree', subcommand: sub, status: 'error', message: msg }) + '\n');
37
37
  } else {
@@ -44,7 +44,7 @@ export default async function worktreeCommand(args) {
44
44
  if (sub === 'create') {
45
45
  const name = args.positionals[0];
46
46
  if (!name) {
47
- die(new CliError('Usage: harness-dev worktree create <name>', EXIT.USAGE_ERROR), json);
47
+ die(new CliError('Usage: dev-harness worktree create <name>', EXIT.USAGE_ERROR), json);
48
48
  return;
49
49
  }
50
50
 
@@ -88,7 +88,7 @@ export default async function worktreeCommand(args) {
88
88
 
89
89
  // Scaffold harness in the new worktree — run full init with parent's detected stack
90
90
  const stack = detectStack(worktreePath).name;
91
- const harnessDevPath = new URL('../harness-dev.mjs', import.meta.url).pathname;
91
+ const harnessDevPath = new URL('../dev-harness.mjs', import.meta.url).pathname;
92
92
  const initResult = execGit(
93
93
  `node "${harnessDevPath}" init --stack "${stack}" --force --no-git --json`,
94
94
  worktreePath,
@@ -232,7 +232,7 @@ export default async function worktreeCommand(args) {
232
232
  if (sub === 'remove') {
233
233
  const name = args.positionals[0];
234
234
  if (!name) {
235
- die(new CliError('Usage: harness-dev worktree remove <name>', EXIT.USAGE_ERROR), json);
235
+ die(new CliError('Usage: dev-harness worktree remove <name>', EXIT.USAGE_ERROR), json);
236
236
  return;
237
237
  }
238
238
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * harness-dev — Agent-agnostic development harness CLI.
3
+ * dev-harness — Agent-agnostic development harness CLI.
4
4
  *
5
5
  * Entry point. Parses args, routes to command handler,
6
6
  * formats output (human or JSON), handles errors.
@@ -68,7 +68,7 @@ async function main() {
68
68
  const loader = COMMANDS[args.command];
69
69
  if (!loader) {
70
70
  throw new CliError(
71
- `Unknown command "${args.command}". See harness-dev --help`,
71
+ `Unknown command "${args.command}". See dev-harness --help`,
72
72
  EXIT.USAGE_ERROR
73
73
  );
74
74
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Single source of truth for parameter descriptions, types, allowed values,
5
5
  * and defaults. Used by:
6
- * - `harness-dev config list` — interactive parameter listing
6
+ * - `dev-harness config list` — interactive parameter listing
7
7
  * - docs/CONFIGURATION.md — generated documentation
8
8
  * - config command — validation of set values
9
9
  *
@@ -198,7 +198,7 @@ export const CONFIG_PARAMS = [
198
198
  group: 'Runtime State',
199
199
  label: 'Current Phase',
200
200
  type: 'string',
201
- description: 'Current pipeline phase. Managed by harness-dev phase — do not edit.',
201
+ description: 'Current pipeline phase. Managed by dev-harness phase — do not edit.',
202
202
  default: null,
203
203
  editable: false,
204
204
  },
@@ -8,8 +8,11 @@
8
8
  * import { GATE_TIMEOUT, COVERAGE_TIMEOUT, MAX_NEGOTIATION_ROUNDS } from './constants.mjs';
9
9
  */
10
10
 
11
- /** Default max retries per phase before escalating to human. */
12
- export const DEFAULT_MAX_RETRIES = 3;
11
+ /** Default max retries per task before escalating to human.
12
+ * Retry scope is per-task (not per-phase) — each task gets its own retry budget.
13
+ * Configurable via: dev-harness config set maxRetries <N>
14
+ */
15
+ export const DEFAULT_MAX_RETRIES = 10;
13
16
 
14
17
  /** Timeout (ms) for standard git/shell commands. */
15
18
  export const COMMAND_TIMEOUT = 30000;
@@ -28,3 +31,17 @@ export const STACK_SCAN_DEPTH = 2;
28
31
 
29
32
  /** File mode for executable scripts (init.sh). */
30
33
  export const EXECUTABLE_MODE = 0o755;
34
+
35
+ // ── Supervisor / Orchestrator constants ─────────────────────────────────────
36
+
37
+ /** Default max API retry attempts before pausing pipeline. */
38
+ export const API_MAX_RETRIES = 5;
39
+
40
+ /** Base backoff delay in ms for API retries (exponential: 60s, 120s, 240s, ...). */
41
+ export const API_BACKOFF_MS = 60000;
42
+
43
+ /** Supervisor heartbeat interval in ms. */
44
+ export const SUPERVISOR_INTERVAL_MS = 60000;
45
+
46
+ /** Max heartbeat staleness before stall detection (5 min). */
47
+ export const SUPERVISOR_MAX_STALLS = 3;
@@ -168,7 +168,7 @@ ${existingStatus || `## Agreement Status
168
168
  export function reviewContract(targetDir, decision, notes) {
169
169
  const path = CONTRACT_PATH(targetDir);
170
170
  if (!existsSync(path)) {
171
- return { ok: false, error: 'No sprint-contract.md found. Run: harness-dev contract propose first', escalated: false };
171
+ return { ok: false, error: 'No sprint-contract.md found. Run: dev-harness contract propose first', escalated: false };
172
172
  }
173
173
 
174
174
  try {
@@ -276,7 +276,7 @@ export function validateContract(targetDir) {
276
276
  return {
277
277
  name: 'contract-agreed',
278
278
  pass: false,
279
- detail: 'Sprint contract not yet proposed. Run: harness-dev contract propose',
279
+ detail: 'Sprint contract not yet proposed. Run: dev-harness contract propose',
280
280
  };
281
281
  }
282
282
 
@@ -301,6 +301,6 @@ export function validateContract(targetDir) {
301
301
  return {
302
302
  name: 'contract-agreed',
303
303
  pass: false,
304
- detail: `Sprint contract ${noun} (round ${rounds}/${MAX_NEGOTIATION_ROUNDS}). Run: harness-dev contract review`,
304
+ detail: `Sprint contract ${noun} (round ${rounds}/${MAX_NEGOTIATION_ROUNDS}). Run: dev-harness contract review`,
305
305
  };
306
306
  }
package/cli/lib/gates.mjs CHANGED
@@ -5,7 +5,7 @@
5
5
  * that return { name, pass, detail }.
6
6
  *
7
7
  * Phase gates are disabled by default (gates.enabled: false).
8
- * Run via: harness-dev validate
8
+ * Run via: dev-harness validate
9
9
  *
10
10
  * Usage:
11
11
  * import { runChecks, getPhase } from './gates.mjs';