coding-agent-harness 1.0.1 → 1.0.2

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 (159) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.en-US.md +14 -0
  3. package/README.md +111 -86
  4. package/README.zh-CN.md +270 -0
  5. package/SKILL.md +116 -189
  6. package/docs-release/README.md +72 -5
  7. package/docs-release/architecture/overview.md +286 -28
  8. package/docs-release/architecture/overview.zh-CN.md +288 -0
  9. package/docs-release/assets/dashboard-overview-en.png +0 -0
  10. package/docs-release/assets/harness-architecture.svg +163 -0
  11. package/docs-release/assets/harness-workflow.svg +64 -0
  12. package/docs-release/guides/agent-installation.en-US.md +214 -0
  13. package/docs-release/guides/agent-installation.md +123 -26
  14. package/docs-release/guides/document-audience-and-surfaces.en-US.md +112 -0
  15. package/docs-release/guides/document-audience-and-surfaces.md +112 -0
  16. package/docs-release/guides/full-legacy-migration-subagent-strategy.md +334 -0
  17. package/docs-release/guides/full-legacy-migration-subagent-strategy.zh-CN.md +334 -0
  18. package/docs-release/guides/legacy-migration-agent-prompt.md +384 -0
  19. package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +361 -0
  20. package/docs-release/guides/migration-playbook.en-US.md +325 -0
  21. package/docs-release/guides/migration-playbook.md +329 -0
  22. package/docs-release/guides/parent-control-repository-pattern.en-US.md +252 -0
  23. package/docs-release/guides/parent-control-repository-pattern.md +252 -0
  24. package/docs-release/guides/repository-operating-models.en-US.md +196 -0
  25. package/docs-release/guides/repository-operating-models.md +196 -0
  26. package/docs-release/intl/README.md +15 -0
  27. package/docs-release/intl/de-DE.md +18 -0
  28. package/docs-release/intl/en-US.md +18 -0
  29. package/docs-release/intl/es-ES.md +18 -0
  30. package/docs-release/intl/fr-FR.md +18 -0
  31. package/docs-release/intl/ja-JP.md +18 -0
  32. package/docs-release/intl/ko-KR.md +18 -0
  33. package/docs-release/intl/zh-CN.md +18 -0
  34. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/brief.md +13 -0
  35. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/lesson_candidates.md +24 -0
  36. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/progress.md +1 -1
  37. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/task_plan.md +4 -2
  38. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/{visual_roadmap.md → visual_map.md} +9 -1
  39. package/package.json +3 -1
  40. package/references/agents-md-pattern.md +3 -3
  41. package/references/docs-directory-standard.md +47 -3
  42. package/references/external-source-intake-standard.md +75 -0
  43. package/references/harness-ledger.md +5 -3
  44. package/references/legacy-12-phase-bootstrap.md +41 -0
  45. package/references/lessons-governance.md +23 -6
  46. package/references/planning-loop.md +41 -3
  47. package/references/project-onboarding-audit.md +10 -0
  48. package/references/repo-governance-standard.md +2 -0
  49. package/references/testing-standard.md +50 -0
  50. package/references/walkthrough-closeout.md +6 -5
  51. package/scripts/check-harness.mjs +76 -35
  52. package/scripts/harness.mjs +303 -12
  53. package/scripts/lib/capability-registry.mjs +533 -0
  54. package/scripts/lib/check-profiles.mjs +510 -0
  55. package/scripts/lib/core-shared.mjs +186 -0
  56. package/scripts/lib/dashboard-data.mjs +389 -0
  57. package/scripts/lib/dashboard-workbench.mjs +217 -0
  58. package/scripts/lib/dashboard-writer.mjs +93 -2
  59. package/scripts/lib/harness-core.mjs +10 -1318
  60. package/scripts/lib/lesson-maintenance.mjs +145 -0
  61. package/scripts/lib/markdown-utils.mjs +158 -0
  62. package/scripts/lib/migration-planner.mjs +478 -0
  63. package/scripts/lib/migration-support.mjs +312 -0
  64. package/scripts/lib/task-lifecycle.mjs +755 -0
  65. package/scripts/lib/task-scanner.mjs +682 -0
  66. package/scripts/smoke-dashboard.mjs +22 -0
  67. package/scripts/test-harness.mjs +926 -14
  68. package/templates/AGENTS.md.template +41 -30
  69. package/templates/architecture/Architecture-SSoT.md +21 -0
  70. package/templates/architecture/README.md +49 -0
  71. package/templates/architecture/critical-flows.md +22 -0
  72. package/templates/architecture/local-repo-context.md +20 -0
  73. package/templates/architecture/service-catalog.md +17 -0
  74. package/templates/architecture/services/service-template.md +31 -0
  75. package/templates/architecture/system-map.md +22 -0
  76. package/templates/dashboard/assets/app-src/00-state.js +41 -0
  77. package/templates/dashboard/assets/app-src/10-router.js +76 -0
  78. package/templates/dashboard/assets/app-src/20-overview.js +235 -0
  79. package/templates/dashboard/assets/app-src/30-tasks.js +563 -0
  80. package/templates/dashboard/assets/app-src/40-modules.js +58 -0
  81. package/templates/dashboard/assets/app-src/45-review.js +128 -0
  82. package/templates/dashboard/assets/app-src/50-migration.js +169 -0
  83. package/templates/dashboard/assets/app-src/60-shared.js +61 -0
  84. package/templates/dashboard/assets/app-src/90-bindings.js +382 -0
  85. package/templates/dashboard/assets/app.css +2575 -310
  86. package/templates/dashboard/assets/app.js +1498 -307
  87. package/templates/dashboard/assets/app.manifest.json +11 -0
  88. package/templates/dashboard/assets/i18n.js +429 -44
  89. package/templates/dashboard/assets/mermaid-renderer.js +58 -8
  90. package/templates/development/README.md +52 -0
  91. package/templates/development/codebase-map.md +11 -0
  92. package/templates/development/cross-repo-debugging.md +18 -0
  93. package/templates/development/external-context/service-template.md +33 -0
  94. package/templates/development/external-source-packs/README.md +24 -0
  95. package/templates/development/external-source-packs/digest-template.md +28 -0
  96. package/templates/development/local-setup.md +16 -0
  97. package/templates/development/stubs-and-mocks.md +11 -0
  98. package/templates/integrations/README.md +40 -0
  99. package/templates/integrations/api-contract.md +42 -0
  100. package/templates/integrations/event-contract.md +46 -0
  101. package/templates/integrations/third-party/vendor-template.md +42 -0
  102. package/templates/integrations/webhook-contract.md +41 -0
  103. package/templates/planning/brief.md +32 -0
  104. package/templates/planning/lesson_candidates.md +58 -0
  105. package/templates/planning/long-running-task-contract.md +7 -0
  106. package/templates/planning/module_brief.md +25 -0
  107. package/templates/planning/module_session_prompt.md +6 -0
  108. package/templates/planning/task_plan.md +7 -5
  109. package/templates/planning/{visual_roadmap.md → visual_map.md} +24 -2
  110. package/templates/reference/docs-library-standard.md +31 -0
  111. package/templates/reference/execution-workflow-standard.md +4 -2
  112. package/templates/reference/external-source-intake-standard.md +82 -0
  113. package/templates/reference/harness-ledger-standard.md +1 -0
  114. package/templates/reference/repo-governance-standard.md +6 -4
  115. package/templates/reference/walkthrough-standard.md +2 -1
  116. package/templates/walkthrough/walkthrough-template.md +2 -2
  117. package/templates-zh-CN/AGENTS.md.template +69 -70
  118. package/templates-zh-CN/architecture/Architecture-SSoT.md +21 -0
  119. package/templates-zh-CN/architecture/README.md +51 -0
  120. package/templates-zh-CN/architecture/critical-flows.md +24 -0
  121. package/templates-zh-CN/architecture/local-repo-context.md +20 -0
  122. package/templates-zh-CN/architecture/service-catalog.md +17 -0
  123. package/templates-zh-CN/architecture/services/service-template.md +31 -0
  124. package/templates-zh-CN/architecture/system-map.md +22 -0
  125. package/templates-zh-CN/development/README.md +54 -0
  126. package/templates-zh-CN/development/codebase-map.md +11 -0
  127. package/templates-zh-CN/development/cross-repo-debugging.md +18 -0
  128. package/templates-zh-CN/development/external-context/service-template.md +33 -0
  129. package/templates-zh-CN/development/external-source-packs/README.md +24 -0
  130. package/templates-zh-CN/development/external-source-packs/digest-template.md +28 -0
  131. package/templates-zh-CN/development/local-setup.md +16 -0
  132. package/templates-zh-CN/development/stubs-and-mocks.md +11 -0
  133. package/templates-zh-CN/integrations/README.md +42 -0
  134. package/templates-zh-CN/integrations/api-contract.md +42 -0
  135. package/templates-zh-CN/integrations/event-contract.md +46 -0
  136. package/templates-zh-CN/integrations/third-party/vendor-template.md +42 -0
  137. package/templates-zh-CN/integrations/webhook-contract.md +41 -0
  138. package/templates-zh-CN/planning/brief.md +32 -0
  139. package/templates-zh-CN/planning/lesson_candidates.md +58 -0
  140. package/templates-zh-CN/planning/long-running-task-contract.md +1 -1
  141. package/templates-zh-CN/planning/module_brief.md +25 -0
  142. package/templates-zh-CN/planning/module_plan.md +2 -2
  143. package/templates-zh-CN/planning/module_session_prompt.md +4 -3
  144. package/templates-zh-CN/planning/task_plan.md +10 -4
  145. package/templates-zh-CN/planning/{visual_roadmap.md → visual_map.md} +21 -2
  146. package/templates-zh-CN/reference/docs-library-standard.md +35 -0
  147. package/templates-zh-CN/reference/execution-workflow-standard.md +9 -2
  148. package/templates-zh-CN/reference/external-source-intake-standard.md +82 -0
  149. package/templates-zh-CN/reference/harness-ledger-standard.md +5 -2
  150. package/templates-zh-CN/reference/repo-governance-standard.md +2 -0
  151. package/templates-zh-CN/reference/walkthrough-standard.md +4 -4
  152. package/templates-zh-CN/walkthrough/Closeout-SSoT.md +2 -2
  153. package/templates-zh-CN/walkthrough/walkthrough-template.md +2 -2
  154. package/templates-zh-CN/dashboard/assets/app.css +0 -399
  155. package/templates-zh-CN/dashboard/assets/app.js +0 -435
  156. package/templates-zh-CN/dashboard/assets/i18n.js +0 -47
  157. package/templates-zh-CN/dashboard/assets/markdown-reader.js +0 -116
  158. package/templates-zh-CN/dashboard/assets/mermaid-renderer.js +0 -59
  159. package/templates-zh-CN/dashboard/index.html +0 -18
@@ -1,16 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import fs from "node:fs";
4
+ import os from "node:os";
4
5
  import path from "node:path";
5
6
  import { createInterface } from "node:readline/promises";
6
7
  import {
7
8
  addCapability,
9
+ buildMigrationPlan,
8
10
  buildStatus,
11
+ confirmTaskReview,
12
+ createTask,
9
13
  doctorUserSkill,
10
14
  installUserSkill,
11
- renderDashboard,
15
+ listLifecycleTasks,
12
16
  normalizeLocale,
17
+ promoteLessonCandidate,
18
+ runMigration,
19
+ serveDashboardWorkbench,
20
+ validateSourcePackageBoundary,
21
+ updateModuleStep,
22
+ updateTaskPhase,
23
+ updateTaskLifecycle,
24
+ verifyMigrationSession,
13
25
  writeDashboardFolder,
26
+ writeDashboardSingleFile,
14
27
  writeInitFiles,
15
28
  } from "./lib/harness-core.mjs";
16
29
 
@@ -76,9 +89,24 @@ function printHelp() {
76
89
  Usage:
77
90
  harness check [--profile source-package|private-harness|target-project] [target]
78
91
  harness status [--json] [--strict] [target]
79
- harness dashboard [--out file.html] [--out-dir folder] [target]
80
- harness init [--dry-run] [--locale zh-CN|en-US] [--capabilities core,dashboard] [target]
92
+ harness dev [--no-open] [--out-dir folder] [--host 127.0.0.1] [--port n] [target]
93
+ harness dashboard [--out file.html] [--out-dir folder] [--workbench] [--host 127.0.0.1] [--port n] [target]
94
+ harness init [--dry-run] [--locale zh-CN|en-US] [--capabilities core,dashboard] [--add-npm-scripts] [target]
81
95
  harness add-capability <name> [--dry-run] [--locale zh-CN|en-US] [target]
96
+ harness migrate-plan [--json] [--limit n] [target]
97
+ harness migrate-run [--locale zh-CN|en-US] [--assume-locale] [--allow-dirty] [--plan-only] [--out-dir folder] [--session-dir folder] [target]
98
+ harness migrate-verify [--json] [--full-cutover] <session.json>
99
+ harness new-task <task-id> [--module key] [--budget simple|standard|complex] [--preset legacy-migration] [--from-session session.json] [--long-running] [--title title] [--locale zh-CN|en-US] [--dry-run] [target]
100
+ harness task-start <task-id> [--message text] [target]
101
+ harness task-phase <task-id> <phase-id> [--state done] [--completion 100] [--evidence present] [target]
102
+ harness task-log <task-id> --message text [--evidence type:PATH:summary] [target]
103
+ harness task-block <task-id> [--message text] [target]
104
+ harness task-review <task-id> [--message text] [target]
105
+ harness review-confirm <task-id> --confirm task-id [--reviewer name] [--message text] [target]
106
+ harness lesson-promote <task-id> <candidate-id> [--dry-run] [target]
107
+ harness task-complete <task-id> [--message text] [target]
108
+ harness task-list [--json] [--state state] [--module key] [target]
109
+ harness module-step <module-key> <step-id> [--state done|in-progress|blocked] [target]
82
110
  harness install-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir] [--dry-run] [--force] [--yes]
83
111
  harness doctor-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir]
84
112
 
@@ -106,6 +134,9 @@ if (command === "help" || command === "--help" || command === "-h") {
106
134
  for (const required of ["package.json", "scripts/harness.mjs", "scripts/check-harness.mjs", "templates/planning/task_plan.md"]) {
107
135
  if (!fs.existsSync(path.resolve(target, required))) failures.push(`missing source package file: ${required}`);
108
136
  }
137
+ const boundary = validateSourcePackageBoundary(target);
138
+ failures.push(...boundary.failures);
139
+ warnings.push(...boundary.warnings);
109
140
  }
110
141
 
111
142
  const status = buildStatus(target, { skipLegacyCheck: profile === "source-package", strictLegacy: strict, strict });
@@ -127,27 +158,88 @@ if (command === "help" || command === "--help" || command === "-h") {
127
158
  console.log(`capabilities: ${status.capabilities.map((capability) => `${capability.name}:${capability.state}`).join(", ")}`);
128
159
  console.log(`tasks: ${status.tasks.length}`);
129
160
  }
130
- process.exit(status.checkState.status === "fail" ? 1 : 0);
161
+ process.exitCode = status.checkState.status === "fail" ? 1 : 0;
162
+ } else if (command === "dev") {
163
+ const open = !takeFlag("--no-open");
164
+ const outDir = takeOption("--out-dir", "");
165
+ const host = takeOption("--host", "127.0.0.1");
166
+ const port = takeOption("--port", "0");
167
+ const localeOverride = takeOption("--locale", "");
168
+ const target = targetArg();
169
+ const dashboardOutDir = outDir || defaultDevOutDir(target);
170
+ const opts = localeOverride ? { localeOverride } : {};
171
+ try {
172
+ await serveDashboardWorkbench(dashboardOutDir, target, { ...opts, host, port, autoRefresh: true, open, label: "harness dev" });
173
+ } catch (error) {
174
+ console.error(error.message);
175
+ process.exit(1);
176
+ }
131
177
  } else if (command === "dashboard") {
178
+ const watch = takeFlag("--watch");
179
+ const workbench = takeFlag("--workbench");
132
180
  const out = takeOption("--out", "harness-dashboard.html");
133
181
  const outDir = takeOption("--out-dir", "");
182
+ const host = takeOption("--host", "127.0.0.1");
183
+ const port = takeOption("--port", "0");
184
+ const localeOverride = takeOption("--locale", "");
185
+ const opts = localeOverride ? { localeOverride } : {};
186
+ if (workbench) {
187
+ if (!outDir) {
188
+ console.error("dashboard --workbench requires --out-dir so regenerated data has a stable folder");
189
+ process.exit(2);
190
+ }
191
+ try {
192
+ await serveDashboardWorkbench(outDir, targetArg(), { ...opts, host, port });
193
+ } catch (error) {
194
+ console.error(error.message);
195
+ process.exit(1);
196
+ }
197
+ }
198
+ if (watch) {
199
+ if (!outDir) {
200
+ console.error("dashboard --watch requires --out-dir so updates are written to a stable folder");
201
+ process.exit(2);
202
+ }
203
+ const target = targetArg();
204
+ const docsRoot = path.basename(path.resolve(target)) === "docs" ? path.resolve(target) : path.join(path.resolve(target), "docs");
205
+ const regenerate = () => {
206
+ try {
207
+ console.log(writeDashboardFolder(outDir, target, opts));
208
+ console.log(`dashboard regenerated: ${new Date().toISOString()}`);
209
+ } catch (error) {
210
+ console.error(`dashboard regeneration failed: ${error.message}`);
211
+ }
212
+ };
213
+ regenerate();
214
+ let timer = null;
215
+ const watcher = fs.watch(docsRoot, { recursive: true }, () => {
216
+ clearTimeout(timer);
217
+ timer = setTimeout(regenerate, 300);
218
+ });
219
+ const close = () => {
220
+ watcher.close();
221
+ clearTimeout(timer);
222
+ process.exit(0);
223
+ };
224
+ process.on("SIGINT", close);
225
+ process.on("SIGTERM", close);
226
+ console.log(`watching ${docsRoot}`);
227
+ await new Promise(() => {});
228
+ }
134
229
  if (outDir) {
135
- console.log(writeDashboardFolder(outDir, targetArg()));
230
+ console.log(writeDashboardFolder(outDir, targetArg(), opts));
136
231
  } else {
137
- const status = buildStatus(targetArg());
138
- const html = renderDashboard(status);
139
- fs.mkdirSync(path.dirname(path.resolve(out)), { recursive: true });
140
- fs.writeFileSync(path.resolve(out), html);
141
- console.log(path.resolve(out));
232
+ console.log(writeDashboardSingleFile(out, targetArg(), opts));
142
233
  }
143
234
  process.exit(0);
144
235
  } else if (command === "init") {
145
236
  const dryRun = takeFlag("--dry-run");
237
+ const addNpmScripts = takeFlag("--add-npm-scripts");
146
238
  const locale = await resolveInitLocale(takeOption("--locale", ""));
147
239
  const capabilities = takeOption("--capabilities", "core").split(",").map((item) => item.trim()).filter(Boolean);
148
240
  try {
149
- const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale });
150
- console.log(JSON.stringify({ dryRun, locale: result.locale, capabilities: result.capabilities, changes: result.changes, report: result.report }, null, 2));
241
+ const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale, addNpmScripts });
242
+ console.log(JSON.stringify({ dryRun, locale: result.locale, capabilities: result.capabilities, changes: result.changes, nextCommands: result.nextCommands, report: result.report }, null, 2));
151
243
  } catch (error) {
152
244
  console.error(error.message);
153
245
  process.exit(1);
@@ -167,6 +259,198 @@ if (command === "help" || command === "--help" || command === "-h") {
167
259
  console.error(error.message);
168
260
  process.exit(1);
169
261
  }
262
+ } else if (command === "migrate-plan") {
263
+ const json = takeFlag("--json");
264
+ const limit = Number.parseInt(takeOption("--limit", "20"), 10) || 20;
265
+ try {
266
+ const plan = buildMigrationPlan(targetArg(), { limit });
267
+ if (json) {
268
+ console.log(JSON.stringify(plan, null, 2));
269
+ } else {
270
+ console.log(`Migration Plan: ${plan.target}`);
271
+ console.log(`mode: ${plan.mode}`);
272
+ console.log(`warnings: ${plan.summary.warnings}`);
273
+ console.log(`task actions: ${plan.summary.taskActions}`);
274
+ console.log(`visual map actions: ${plan.summary.visualMapActions}`);
275
+ console.log(`legacy visual-only tasks: ${plan.summary.legacyVisualOnly}`);
276
+ console.log(`weak briefs: ${plan.summary.weakBrief}`);
277
+ console.log(`unknown classifications: ${plan.summary.unknownClassification}`);
278
+ console.log(`full cutover eligible: ${plan.summary.fullCutoverEligible ? "yes" : "no"}`);
279
+ console.log(`review actions: ${plan.summary.reviewSchemaGaps}`);
280
+ console.log(`legacy actions: ${plan.summary.legacyReferenceGaps}`);
281
+ console.log(`legacy residuals: ${plan.summary.legacyResiduals}`);
282
+ console.log(`recommended capabilities: ${plan.summary.recommendedCapabilities.join(", ") || "none"}`);
283
+ console.log("\nPhases:");
284
+ for (const phase of plan.phases) console.log(`- ${phase.id}: ${phase.title}`);
285
+ console.log("\nTop task actions:");
286
+ for (const action of plan.taskActions) console.log(`- ${action.taskId}: add ${action.files.join(", ")}`);
287
+ console.log("\nTop review actions:");
288
+ for (const action of plan.reviewActions) console.log(`- ${action.path}: add ${action.missing.join(", ")}`);
289
+ console.log("\nTop legacy residuals:");
290
+ for (const action of plan.legacyResiduals) console.log(`- ${action.taskId}: ${action.missing} (${action.reason})`);
291
+ console.log("\nNext commands:");
292
+ for (const next of plan.nextCommands) console.log(`- ${next}`);
293
+ }
294
+ } catch (error) {
295
+ console.error(error.message);
296
+ process.exit(1);
297
+ }
298
+ } else if (command === "migrate-run") {
299
+ const locale = takeOption("--locale", "");
300
+ const assumeLocale = takeFlag("--assume-locale");
301
+ const allowDirty = takeFlag("--allow-dirty");
302
+ const planOnly = takeFlag("--plan-only");
303
+ const outDir = takeOption("--out-dir", "");
304
+ const sessionDir = takeOption("--session-dir", "");
305
+ try {
306
+ console.log(
307
+ JSON.stringify(
308
+ runMigration(targetArg(), {
309
+ locale,
310
+ assumeLocale,
311
+ allowDirty,
312
+ planOnly,
313
+ outDir,
314
+ sessionDir,
315
+ }),
316
+ null,
317
+ 2,
318
+ ),
319
+ );
320
+ } catch (error) {
321
+ console.error(error.message);
322
+ process.exit(1);
323
+ }
324
+ } else if (command === "migrate-verify") {
325
+ const json = takeFlag("--json");
326
+ const fullCutover = takeFlag("--full-cutover");
327
+ const sessionPath = args.shift();
328
+ if (!sessionPath) {
329
+ console.error("Missing session.json path");
330
+ process.exit(2);
331
+ }
332
+ const result = verifyMigrationSession(sessionPath, { fullCutover });
333
+ if (json) {
334
+ console.log(JSON.stringify(result, null, 2));
335
+ } else {
336
+ for (const failure of result.failures) console.error(`Failure: ${failure}`);
337
+ for (const warning of result.warnings) console.log(`Warning: ${warning}`);
338
+ console.log(`Migration verify ${result.status}: ${result.sessionPath}`);
339
+ }
340
+ process.exit(result.status === "pass" ? 0 : 1);
341
+ } else if (command === "new-task") {
342
+ const dryRun = takeFlag("--dry-run");
343
+ const locale = takeOption("--locale", "");
344
+ const title = takeOption("--title", "");
345
+ const moduleKey = takeOption("--module", "");
346
+ const budget = takeOption("--budget", "standard");
347
+ const preset = takeOption("--preset", "");
348
+ const fromSession = takeOption("--from-session", "");
349
+ const longRunning = takeFlag("--long-running");
350
+ const taskId = args.shift() || (fromSession ? "harness-v1-migration" : "");
351
+ if (!taskId) {
352
+ console.error("Missing task id");
353
+ process.exit(2);
354
+ }
355
+ try {
356
+ console.log(JSON.stringify(createTask(targetArg(), taskId, { title, locale, dryRun, moduleKey, budget, longRunning, preset, fromSession }), null, 2));
357
+ } catch (error) {
358
+ console.error(error.message);
359
+ process.exit(1);
360
+ }
361
+ } else if (command === "task-phase") {
362
+ const state = takeOption("--state", "");
363
+ const completion = takeOption("--completion", "");
364
+ const evidenceStatus = takeOption("--evidence", "");
365
+ const taskId = args.shift();
366
+ const phaseId = args.shift();
367
+ if (!taskId || !phaseId) {
368
+ console.error("Missing task id or phase id");
369
+ process.exit(2);
370
+ }
371
+ try {
372
+ console.log(JSON.stringify(updateTaskPhase(targetArg(), taskId, phaseId, { state, completion, evidenceStatus }), null, 2));
373
+ } catch (error) {
374
+ console.error(error.message);
375
+ process.exit(1);
376
+ }
377
+ } else if (["task-start", "task-log", "task-block", "task-review", "task-complete"].includes(command)) {
378
+ const message = takeOption("--message", "");
379
+ const evidence = takeOption("--evidence", "");
380
+ const taskId = args.shift();
381
+ if (!taskId) {
382
+ console.error("Missing task id");
383
+ process.exit(2);
384
+ }
385
+ const lifecycle = {
386
+ "task-start": { event: "task-start", state: "in_progress" },
387
+ "task-log": { event: "task-log", state: "" },
388
+ "task-block": { event: "task-block", state: "blocked" },
389
+ "task-review": { event: "task-review", state: "review" },
390
+ "task-complete": { event: "task-complete", state: "done" },
391
+ }[command];
392
+ try {
393
+ console.log(JSON.stringify(updateTaskLifecycle(targetArg(), taskId, { ...lifecycle, message, evidence }), null, 2));
394
+ } catch (error) {
395
+ console.error(error.message);
396
+ process.exit(1);
397
+ }
398
+ } else if (command === "review-confirm") {
399
+ const reviewer = takeOption("--reviewer", "Human Reviewer");
400
+ const message = takeOption("--message", "");
401
+ const evidence = takeOption("--evidence", "");
402
+ const confirmText = takeOption("--confirm", "");
403
+ const taskId = args.shift();
404
+ if (!taskId) {
405
+ console.error("Missing task id");
406
+ process.exit(2);
407
+ }
408
+ try {
409
+ console.log(JSON.stringify(confirmTaskReview(targetArg(), taskId, { reviewer, message, evidence, confirmText }), null, 2));
410
+ } catch (error) {
411
+ console.error(error.message);
412
+ process.exit(1);
413
+ }
414
+ } else if (command === "lesson-promote") {
415
+ const dryRun = takeFlag("--dry-run");
416
+ const taskId = args.shift();
417
+ const candidateId = args.shift();
418
+ if (!taskId || !candidateId) {
419
+ console.error("Missing task id or candidate id");
420
+ process.exit(2);
421
+ }
422
+ try {
423
+ console.log(JSON.stringify(promoteLessonCandidate(targetArg(), taskId, candidateId, { dryRun }), null, 2));
424
+ } catch (error) {
425
+ console.error(error.message);
426
+ process.exit(1);
427
+ }
428
+ } else if (command === "task-list") {
429
+ const json = takeFlag("--json");
430
+ const state = takeOption("--state", "");
431
+ const moduleKey = takeOption("--module", "");
432
+ const result = listLifecycleTasks(targetArg(), { state, moduleKey });
433
+ if (json) {
434
+ console.log(JSON.stringify(result, null, 2));
435
+ } else {
436
+ for (const task of result.tasks) {
437
+ console.log(`${task.id}\t${task.state}\t${task.completion}%\t${task.title}`);
438
+ }
439
+ }
440
+ } else if (command === "module-step") {
441
+ const state = takeOption("--state", "done");
442
+ const moduleKey = args.shift();
443
+ const stepId = args.shift();
444
+ if (!moduleKey || !stepId) {
445
+ console.error("Missing module key or step id");
446
+ process.exit(2);
447
+ }
448
+ try {
449
+ console.log(JSON.stringify(updateModuleStep(targetArg(), moduleKey, stepId, { state }), null, 2));
450
+ } catch (error) {
451
+ console.error(error.message);
452
+ process.exit(1);
453
+ }
170
454
  } else if (command === "install-user") {
171
455
  const dryRun = takeFlag("--dry-run");
172
456
  const force = takeFlag("--force");
@@ -199,3 +483,10 @@ if (command === "help" || command === "--help" || command === "-h") {
199
483
  printHelp();
200
484
  process.exit(2);
201
485
  }
486
+
487
+ function defaultDevOutDir(targetInput) {
488
+ const target = path.resolve(targetInput || ".");
489
+ const name = path.basename(target) || "project";
490
+ const hash = Buffer.from(target).toString("hex").slice(0, 16);
491
+ return path.join(os.tmpdir(), "coding-agent-harness-dev", `${name}-${hash}`);
492
+ }