coding-agent-harness 1.0.7 → 1.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 (238) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/CONTRIBUTING.md +9 -5
  3. package/README.md +12 -2
  4. package/README.zh-CN.md +10 -2
  5. package/SKILL.md +14 -3
  6. package/dist/build-dist.mjs +32 -6
  7. package/dist/check-dist-observation.mjs +73 -28
  8. package/dist/check-harness.mjs +0 -1
  9. package/dist/check-import-graph.mjs +44 -27
  10. package/dist/check-lite-forbidden-surfaces.mjs +121 -0
  11. package/dist/check-no-ts-nocheck.mjs +88 -0
  12. package/dist/check-runtime-emit.mjs +10 -3
  13. package/dist/check-type-boundaries.mjs +67 -8
  14. package/dist/commands/dashboard-command.mjs +52 -14
  15. package/dist/commands/migration-command.mjs +18 -8
  16. package/dist/commands/module-command.mjs +142 -0
  17. package/dist/commands/preset-command.mjs +65 -4
  18. package/dist/commands/registry.mjs +483 -0
  19. package/dist/commands/task-command.mjs +111 -53
  20. package/dist/harness.mjs +6 -303
  21. package/dist/lib/capability-registry.mjs +229 -53
  22. package/dist/lib/check-module-parallel.mjs +1 -6
  23. package/dist/lib/check-profiles.mjs +39 -46
  24. package/dist/lib/check-task-contracts.mjs +6 -4
  25. package/dist/lib/command-registry.mjs +248 -0
  26. package/dist/lib/core-shared.mjs +78 -3
  27. package/dist/lib/dashboard-data.mjs +203 -22
  28. package/dist/lib/dashboard-workbench.mjs +245 -21
  29. package/dist/lib/dashboard-writer.mjs +4 -1
  30. package/dist/lib/git-status-summary.mjs +0 -1
  31. package/dist/lib/governance-index-generator.mjs +7 -5
  32. package/dist/lib/governance-sync.mjs +46 -121
  33. package/dist/lib/governance-table-boundary.mjs +1 -14
  34. package/dist/lib/harness-core.mjs +5 -1
  35. package/dist/lib/harness-paths.mjs +115 -1
  36. package/dist/lib/impact-classifier.mjs +420 -0
  37. package/dist/lib/lesson-maintenance.mjs +1 -2
  38. package/dist/lib/markdown-utils.mjs +50 -1
  39. package/dist/lib/migration-planner.mjs +31 -16
  40. package/dist/lib/migration-support.mjs +5 -4
  41. package/dist/lib/module-registry.mjs +296 -0
  42. package/dist/lib/preset-audit-contracts.mjs +24 -1
  43. package/dist/lib/preset-engine.mjs +68 -29
  44. package/dist/lib/preset-registry.mjs +374 -72
  45. package/dist/lib/preset-runner.mjs +560 -0
  46. package/dist/lib/review-confirm-git-gate.mjs +73 -19
  47. package/dist/lib/status-builder.mjs +23 -8
  48. package/dist/lib/structure-migration.mjs +6 -4
  49. package/dist/lib/subagent-authorization-audit.mjs +8 -2
  50. package/dist/lib/task-archive-eligibility.mjs +65 -0
  51. package/dist/lib/task-audit-metadata.mjs +25 -11
  52. package/dist/lib/task-audit-migration.mjs +21 -14
  53. package/dist/lib/task-discovery-contract.mjs +32 -0
  54. package/dist/lib/task-index.mjs +4 -2
  55. package/dist/lib/task-lesson-candidates.mjs +1 -2
  56. package/dist/lib/task-lesson-sedimentation.mjs +310 -9
  57. package/dist/lib/task-lifecycle/create-task-helpers.mjs +6 -3
  58. package/dist/lib/task-lifecycle/phase-sync.mjs +0 -1
  59. package/dist/lib/task-lifecycle/preset-interop.mjs +16 -0
  60. package/dist/lib/task-lifecycle/review-confirm.mjs +34 -2
  61. package/dist/lib/task-lifecycle/review-gates.mjs +12 -5
  62. package/dist/lib/task-lifecycle/review-submission.mjs +1 -2
  63. package/dist/lib/task-lifecycle/scaffold-provenance.mjs +0 -1
  64. package/dist/lib/task-lifecycle/template-files.mjs +2 -5
  65. package/dist/lib/task-lifecycle.mjs +117 -159
  66. package/dist/lib/task-metadata.mjs +10 -5
  67. package/dist/lib/task-preset-contract-drift.mjs +45 -0
  68. package/dist/lib/task-repository.mjs +192 -0
  69. package/dist/lib/task-review-model.mjs +38 -17
  70. package/dist/lib/task-scanner.mjs +75 -23
  71. package/dist/lib/task-template-materials.mjs +131 -0
  72. package/dist/lib/task-tombstone-commands.mjs +187 -18
  73. package/dist/lib/types/check-profiles.js +1 -0
  74. package/dist/lib/types/impact.js +1 -0
  75. package/dist/lib/types/preset.js +1 -0
  76. package/dist/lib/types/task-lifecycle.js +1 -0
  77. package/dist/lib/types/task-scanner.js +1 -0
  78. package/dist/postinstall.mjs +2 -2
  79. package/dist/run-built-tests.mjs +10 -3
  80. package/docs-release/README.md +2 -1
  81. package/docs-release/architecture/document-contract-kernel/README.md +150 -0
  82. package/docs-release/architecture/document-contract-kernel/products/full-skill-overlay.md +29 -0
  83. package/docs-release/architecture/document-contract-kernel/products/lite-forbidden-surfaces.txt +26 -0
  84. package/docs-release/architecture/document-contract-kernel/products/lite-skill-overlay.md +37 -0
  85. package/docs-release/architecture/overview.md +2 -2
  86. package/docs-release/architecture/overview.zh-CN.md +2 -2
  87. package/docs-release/architecture/system-explainer/01-system-overview.md +11 -7
  88. package/docs-release/architecture/system-explainer/02-module-dependency.md +4 -4
  89. package/docs-release/architecture/system-explainer/03-task-lifecycle.md +17 -12
  90. package/docs-release/architecture/system-explainer/05-data-flow.md +6 -6
  91. package/docs-release/architecture/system-explainer/06-preset-and-migration.md +2 -2
  92. package/docs-release/architecture/system-explainer/README.md +1 -1
  93. package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +12 -8
  94. package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +5 -5
  95. package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +19 -11
  96. package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +5 -5
  97. package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +2 -2
  98. package/docs-release/architecture/system-explainer/en-US/README.md +1 -1
  99. package/docs-release/guides/agent-installation.en-US.md +4 -6
  100. package/docs-release/guides/agent-installation.md +11 -8
  101. package/docs-release/guides/contributing.md +10 -3
  102. package/docs-release/guides/contributing.zh-CN.md +10 -3
  103. package/docs-release/guides/legacy-migration-agent-prompt.md +1 -1
  104. package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +1 -1
  105. package/docs-release/guides/migration-playbook.en-US.md +9 -6
  106. package/docs-release/guides/migration-playbook.md +9 -6
  107. package/docs-release/guides/preset-development.md +68 -2
  108. package/docs-release/guides/task-state-machine.en-US.md +8 -8
  109. package/docs-release/guides/task-state-machine.md +7 -7
  110. package/docs-release/guides/typescript-runtime-migration-closeout.md +17 -13
  111. package/package.json +19 -11
  112. package/postinstall.mjs +37 -0
  113. package/presets/legacy-migration/preset.yaml +5 -5
  114. package/presets/legacy-migration/templates/execution_strategy.append.md +1 -1
  115. package/presets/lesson-sedimentation/preset.yaml +3 -3
  116. package/presets/module/preset.yaml +2 -2
  117. package/presets/module/templates/execution_strategy.append.md +1 -1
  118. package/presets/module/templates/task_plan.append.md +3 -3
  119. package/presets/release-closeout/checks/check-release-package.mjs +29 -0
  120. package/presets/release-closeout/preset.yaml +100 -0
  121. package/presets/release-closeout/scripts/generate-release-package.mjs +572 -0
  122. package/presets/release-closeout/templates/execution_strategy.append.md +7 -0
  123. package/presets/release-closeout/templates/findings.seed.md +5 -0
  124. package/presets/release-closeout/templates/review.seed.md +3 -0
  125. package/presets/release-closeout/templates/task_plan.append.md +24 -0
  126. package/presets/standard-task/preset.yaml +2 -2
  127. package/references/agents-md-pattern.md +23 -17
  128. package/references/lessons-governance.md +2 -2
  129. package/references/module-parallel-standard.md +3 -6
  130. package/references/pull-request-standard.md +2 -2
  131. package/references/ssot-governance.md +2 -2
  132. package/references/taskr-gap-analysis.md +3 -3
  133. package/run-dist.mjs +34 -0
  134. package/skills/preset-creator/SKILL.md +40 -8
  135. package/skills/preset-creator/references/complex-task-skeleton/brief.md +32 -8
  136. package/skills/preset-creator/references/preset-package-skeleton.md +15 -5
  137. package/skills/preset-creator/references/structure-aware-paths.md +112 -0
  138. package/templates/AGENTS.md.template +28 -26
  139. package/templates/architecture/README.md +2 -2
  140. package/templates/architecture/service-catalog.md +2 -2
  141. package/templates/architecture/services/service-template.md +1 -1
  142. package/templates/dashboard/assets/app-src/00-state.js +5 -1
  143. package/templates/dashboard/assets/app-src/10-router.js +7 -0
  144. package/templates/dashboard/assets/app-src/20-overview.js +8 -8
  145. package/templates/dashboard/assets/app-src/30-tasks.js +132 -40
  146. package/templates/dashboard/assets/app-src/32-task-swimlane.js +314 -0
  147. package/templates/dashboard/assets/app-src/35-task-detail.js +35 -5
  148. package/templates/dashboard/assets/app-src/40-modules.js +257 -41
  149. package/templates/dashboard/assets/app-src/45-review.js +127 -1
  150. package/templates/dashboard/assets/app-src/90-bindings.js +185 -2
  151. package/templates/dashboard/assets/app.css +928 -53
  152. package/templates/dashboard/assets/app.css.manifest.json +2 -0
  153. package/templates/dashboard/assets/app.js +1071 -98
  154. package/templates/dashboard/assets/app.manifest.json +1 -0
  155. package/templates/dashboard/assets/css-src/00-foundation.css +12 -6
  156. package/templates/dashboard/assets/css-src/10-panels-flow.css +2 -2
  157. package/templates/dashboard/assets/css-src/30-task-index.css +21 -13
  158. package/templates/dashboard/assets/css-src/31-archive.css +94 -0
  159. package/templates/dashboard/assets/css-src/32-task-swimlane.css +487 -0
  160. package/templates/dashboard/assets/css-src/35-review-workspace.css +78 -0
  161. package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +191 -14
  162. package/templates/dashboard/assets/css-src/50-responsive-overrides.css +23 -0
  163. package/templates/dashboard/assets/i18n.js +166 -2
  164. package/templates/development/README.md +9 -9
  165. package/templates/development/cross-repo-debugging.md +3 -3
  166. package/templates/development/external-context/service-template.md +1 -1
  167. package/templates/development/external-source-packs/README.md +2 -2
  168. package/templates/integrations/README.md +4 -4
  169. package/templates/integrations/api-contract.md +1 -1
  170. package/templates/integrations/event-contract.md +1 -1
  171. package/templates/integrations/third-party/vendor-template.md +1 -1
  172. package/templates/integrations/webhook-contract.md +1 -1
  173. package/templates/ledger/Harness-Ledger.md +1 -1
  174. package/templates/modules/module_brief.md +50 -0
  175. package/templates/modules/module_plan.md +49 -0
  176. package/templates/modules/registry_view.md +9 -0
  177. package/templates/modules/session_prompt_pack.md +55 -0
  178. package/templates/planning/brief.md +32 -8
  179. package/templates/planning/module_brief.md +28 -3
  180. package/templates/planning/module_plan.md +26 -11
  181. package/templates/planning/module_session_prompt.md +11 -2
  182. package/templates/planning/optional/slices/_slice-template/brief.md +28 -0
  183. package/templates/planning/review.md +1 -1
  184. package/templates/planning/visual_map.md +1 -1
  185. package/templates/reference/docs-library-standard.md +7 -7
  186. package/templates/reference/execution-workflow-standard.md +13 -0
  187. package/templates/reference/external-source-intake-standard.md +10 -10
  188. package/templates/reference/pull-request-standard.md +2 -2
  189. package/templates/reference/repo-governance-standard.md +1 -1
  190. package/templates/reference/review-routing-standard.md +4 -0
  191. package/templates/ssot/Module-Registry.md +4 -38
  192. package/templates/walkthrough/walkthrough-template.md +1 -1
  193. package/templates-zh-CN/AGENTS.md.template +27 -25
  194. package/templates-zh-CN/CLAUDE.md.template +1 -1
  195. package/templates-zh-CN/architecture/README.md +2 -2
  196. package/templates-zh-CN/architecture/service-catalog.md +2 -2
  197. package/templates-zh-CN/architecture/services/service-template.md +1 -1
  198. package/templates-zh-CN/development/README.md +9 -9
  199. package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
  200. package/templates-zh-CN/development/external-context/service-template.md +1 -1
  201. package/templates-zh-CN/development/external-source-packs/README.md +2 -2
  202. package/templates-zh-CN/integrations/README.md +4 -4
  203. package/templates-zh-CN/integrations/api-contract.md +1 -1
  204. package/templates-zh-CN/integrations/event-contract.md +1 -1
  205. package/templates-zh-CN/integrations/third-party/vendor-template.md +1 -1
  206. package/templates-zh-CN/integrations/webhook-contract.md +1 -1
  207. package/templates-zh-CN/ledger/Harness-Ledger.md +1 -1
  208. package/templates-zh-CN/lessons/lesson-arch-process-change.md +1 -1
  209. package/templates-zh-CN/lessons/lesson-new-doc.md +3 -3
  210. package/templates-zh-CN/lessons/lesson-ref-change.md +4 -4
  211. package/templates-zh-CN/modules/module_brief.md +47 -0
  212. package/templates-zh-CN/modules/module_plan.md +48 -0
  213. package/templates-zh-CN/modules/registry_view.md +9 -0
  214. package/templates-zh-CN/modules/session_prompt_pack.md +50 -0
  215. package/templates-zh-CN/planning/INDEX.md +1 -0
  216. package/templates-zh-CN/planning/brief.md +26 -7
  217. package/templates-zh-CN/planning/module_brief.md +24 -2
  218. package/templates-zh-CN/planning/module_plan.md +35 -29
  219. package/templates-zh-CN/planning/module_session_prompt.md +15 -11
  220. package/templates-zh-CN/planning/optional/slices/_slice-template/brief.md +28 -11
  221. package/templates-zh-CN/planning/review.md +1 -1
  222. package/templates-zh-CN/reference/adversarial-review-standard.md +1 -1
  223. package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
  224. package/templates-zh-CN/reference/docs-library-standard.md +27 -27
  225. package/templates-zh-CN/reference/execution-workflow-standard.md +12 -2
  226. package/templates-zh-CN/reference/external-source-intake-standard.md +10 -10
  227. package/templates-zh-CN/reference/harness-ledger-standard.md +3 -3
  228. package/templates-zh-CN/reference/pull-request-standard.md +1 -1
  229. package/templates-zh-CN/reference/regression-ssot-governance.md +2 -2
  230. package/templates-zh-CN/reference/repo-governance-standard.md +1 -1
  231. package/templates-zh-CN/reference/review-routing-standard.md +3 -0
  232. package/templates-zh-CN/reference/walkthrough-standard.md +2 -2
  233. package/templates-zh-CN/reference/worktree-standard.md +1 -1
  234. package/templates-zh-CN/regression/Cadence-Ledger.md +2 -2
  235. package/templates-zh-CN/ssot/Delivery-SSoT.md +2 -2
  236. package/templates-zh-CN/ssot/Module-Registry.md +5 -44
  237. package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
  238. package/templates-zh-CN/walkthrough/walkthrough-template.md +4 -4
@@ -1,21 +1,35 @@
1
- // @ts-nocheck
2
- import { confirmTaskReview, createTask, readPresetPackage, buildTaskIndex, createLessonSedimentationTask, archiveTask, listLifecycleTasks, promoteLessonCandidate, reopenTask, softDeleteTask, supersedeTask, updateModuleStep, updateTaskPhase, updateTaskLifecycle, } from "../lib/harness-core.mjs";
1
+ import { createTask, readPresetPackage, buildTaskIndex, createLessonSedimentationTask, archiveTask, deleteTask, listLifecycleTasks, promoteLessonCandidate, reopenTask, supersedeTask, updateModuleStep, updateTaskPhase, updateTaskLifecycle, } from "../lib/harness-core.mjs";
2
+ import { takeRepeatedOptionsFromArgs } from "../lib/command-registry.mjs";
3
3
  export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg }) {
4
4
  if (command === "new-task") {
5
5
  const dryRun = takeFlag("--dry-run");
6
6
  const locale = takeOption("--locale", "");
7
7
  const title = takeOption("--title", "");
8
8
  const moduleKey = takeOption("--module", "");
9
+ const registerModule = takeFlag("--register-module");
10
+ const moduleRegistration = {
11
+ title: takeOption("--module-title", ""),
12
+ prefix: takeOption("--module-prefix", ""),
13
+ status: takeOption("--module-status", "planned"),
14
+ branch: takeOption("--module-branch", ""),
15
+ owner: takeOption("--module-owner", "coordinator"),
16
+ currentStep: takeOption("--module-current-step", ""),
17
+ locale,
18
+ scope: takeRepeatedOptionsFromArgs(args, "--module-scope"),
19
+ shared: takeRepeatedOptionsFromArgs(args, "--module-shared"),
20
+ dependsOn: takeRepeatedOptionsFromArgs(args, "--module-depends-on"),
21
+ };
9
22
  const budget = takeOption("--budget", "standard");
10
23
  const preset = takeOption("--preset", "");
11
24
  const fromSession = takeOption("--from-session", "");
12
25
  const longRunning = takeFlag("--long-running");
13
26
  try {
14
27
  const parsed = parseNewTaskArgs(args, { preset, fromSession });
15
- console.log(JSON.stringify(createTask(parsed.target, parsed.taskId, { title, locale, dryRun, moduleKey, budget, longRunning, preset, fromSession, presetArgs: parsed.presetArgs, automaticTaskId: parsed.automaticTaskId }), null, 2));
28
+ const createOptions = { title, locale, dryRun, moduleKey, budget, longRunning, preset, fromSession, presetArgs: parsed.presetArgs, automaticTaskId: parsed.automaticTaskId, registerModule, moduleRegistration };
29
+ console.log(JSON.stringify(invokeCreateTask(parsed.target, parsed.taskId, createOptions), null, 2));
16
30
  }
17
31
  catch (error) {
18
- console.error(error.message);
32
+ console.error(errorMessage(error));
19
33
  process.exit(1);
20
34
  }
21
35
  return;
@@ -34,7 +48,7 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
34
48
  console.log(JSON.stringify(updateTaskPhase(targetArg(), taskId, phaseId, { state, completion, evidenceStatus }), null, 2));
35
49
  }
36
50
  catch (error) {
37
- console.error(error.message);
51
+ console.error(errorMessage(error));
38
52
  process.exit(1);
39
53
  }
40
54
  return;
@@ -47,37 +61,19 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
47
61
  console.error("Missing task id");
48
62
  process.exit(2);
49
63
  }
50
- const lifecycle = {
64
+ const lifecycleByCommand = {
51
65
  "task-start": { event: "task-start", state: "in_progress" },
52
66
  "task-log": { event: "task-log", state: "" },
53
67
  "task-block": { event: "task-block", state: "blocked" },
54
68
  "task-review": { event: "task-review", state: "review" },
55
69
  "task-complete": { event: "task-complete", state: "done" },
56
- }[command];
70
+ };
71
+ const lifecycle = lifecycleByCommand[command];
57
72
  try {
58
73
  console.log(JSON.stringify(updateTaskLifecycle(targetArg(), taskId, { ...lifecycle, message, evidence }), null, 2));
59
74
  }
60
75
  catch (error) {
61
- console.error(error.message);
62
- process.exit(1);
63
- }
64
- return;
65
- }
66
- if (command === "review-confirm") {
67
- const reviewer = takeOption("--reviewer", "Human Reviewer");
68
- const message = takeOption("--message", "");
69
- const evidence = takeOption("--evidence", "");
70
- const confirmText = takeOption("--confirm", "");
71
- const taskId = args.shift();
72
- if (!taskId) {
73
- console.error("Missing task id");
74
- process.exit(2);
75
- }
76
- try {
77
- console.log(JSON.stringify(confirmTaskReview(targetArg(), taskId, { reviewer, message, evidence, confirmText }), null, 2));
78
- }
79
- catch (error) {
80
- console.error(formatTaskCommandError(error));
76
+ console.error(errorMessage(error));
81
77
  process.exit(1);
82
78
  }
83
79
  return;
@@ -95,7 +91,7 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
95
91
  console.log(JSON.stringify(promoteLessonCandidate(targetArg(), taskId, candidateId, { dryRun, apply }), null, 2));
96
92
  }
97
93
  catch (error) {
98
- console.error(error.message);
94
+ console.error(errorMessage(error));
99
95
  process.exit(1);
100
96
  }
101
97
  return;
@@ -113,7 +109,7 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
113
109
  console.log(JSON.stringify(createLessonSedimentationTask(targetArg(), taskId, candidateId, { dryRun, title }), null, 2));
114
110
  }
115
111
  catch (error) {
116
- console.error(error.message);
112
+ console.error(errorMessage(error));
117
113
  process.exit(1);
118
114
  }
119
115
  return;
@@ -128,7 +124,8 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
128
124
  const lesson = takeOption("--lesson", "");
129
125
  const search = takeOption("--search", "");
130
126
  const missingMaterials = takeFlag("--missing-materials");
131
- const result = listLifecycleTasks(targetArg(), { state, moduleKey, queue, preset, review, lesson, search, missingMaterials });
127
+ const includeArchived = takeFlag("--include-archived");
128
+ const result = listLifecycleTasks(targetArg(), { state, moduleKey, queue, preset, review, lesson, search, missingMaterials, includeArchived });
132
129
  if (json) {
133
130
  console.log(JSON.stringify(result, null, 2));
134
131
  }
@@ -151,40 +148,49 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
151
148
  if (command === "task-supersede") {
152
149
  const by = takeOption("--by", "");
153
150
  const reason = takeOption("--reason", "");
151
+ const deletedBy = takeOption("--deleted-by", "");
152
+ const confirm = takeOption("--confirm", "");
153
+ const allowOpenFindings = takeFlag("--allow-open-findings");
154
154
  const taskId = args.shift();
155
155
  if (!taskId) {
156
156
  console.error("Missing task id");
157
157
  process.exit(2);
158
158
  }
159
159
  try {
160
- console.log(JSON.stringify(supersedeTask(targetArg(), taskId, { by, reason }), null, 2));
160
+ console.log(JSON.stringify(supersedeTask(targetArg(), taskId, { by, reason, deletedBy, confirm, allowOpenFindings }), null, 2));
161
161
  }
162
162
  catch (error) {
163
- console.error(error.message);
163
+ console.error(errorMessage(error));
164
164
  process.exit(1);
165
165
  }
166
166
  return;
167
167
  }
168
168
  if (["task-delete", "task-archive", "task-reopen"].includes(command)) {
169
169
  const soft = takeFlag("--soft");
170
+ const hard = takeFlag("--hard");
170
171
  const reason = takeOption("--reason", "");
172
+ const deletedBy = command === "task-delete" ? takeOption("--deleted-by", "") : "";
173
+ const confirm = command === "task-delete" ? takeOption("--confirm", "") : "";
174
+ const allowOpenFindings = command === "task-delete" ? takeFlag("--allow-open-findings") : false;
175
+ const archivedBy = command === "task-archive" ? takeOption("--archived-by", "") : "";
176
+ const archiveFields = command === "task-archive" ? takeRepeatedKeyValueOptions(args, "--archive-field") : {};
171
177
  const taskId = args.shift();
172
178
  if (!taskId) {
173
179
  console.error("Missing task id");
174
180
  process.exit(2);
175
181
  }
176
182
  try {
177
- if (command === "task-delete" && !soft)
178
- throw new Error("task-delete only supports --soft; hard delete is intentionally disabled.");
183
+ if (command === "task-delete" && soft && hard)
184
+ throw new Error("task-delete accepts only one of --soft or --hard");
179
185
  const result = command === "task-delete"
180
- ? softDeleteTask(targetArg(), taskId, { reason })
186
+ ? deleteTask(targetArg(), taskId, { hard, reason, deletedBy, confirm, allowOpenFindings })
181
187
  : command === "task-archive"
182
- ? archiveTask(targetArg(), taskId, { reason })
188
+ ? archiveTask(targetArg(), taskId, { reason, archivedBy, archiveFields })
183
189
  : reopenTask(targetArg(), taskId, { reason });
184
190
  console.log(JSON.stringify(result, null, 2));
185
191
  }
186
192
  catch (error) {
187
- console.error(error.message);
193
+ console.error(errorMessage(error));
188
194
  process.exit(1);
189
195
  }
190
196
  return;
@@ -201,14 +207,15 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
201
207
  console.log(JSON.stringify(updateModuleStep(targetArg(), moduleKey, stepId, { state }), null, 2));
202
208
  }
203
209
  catch (error) {
204
- console.error(error.message);
210
+ console.error(errorMessage(error));
205
211
  process.exit(1);
206
212
  }
207
213
  return;
208
214
  }
209
215
  throw new Error(`Unsupported task command: ${command}`);
210
216
  }
211
- function parseNewTaskArgs(args, { preset = "" } = {}) {
217
+ function parseNewTaskArgs(args, { preset = "", fromSession = "" } = {}) {
218
+ void fromSession;
212
219
  const values = [...args];
213
220
  const presetPackage = preset ? readPresetPackageForNewTask(preset, values) : null;
214
221
  const parsed = splitPresetArgsAndPositionals(values, presetPackage);
@@ -220,6 +227,9 @@ function parseNewTaskArgs(args, { preset = "" } = {}) {
220
227
  presetArgs: parsed.presetArgs,
221
228
  };
222
229
  }
230
+ function invokeCreateTask(target, taskId, options) {
231
+ return Reflect.apply(createTask, undefined, [target, taskId, options]);
232
+ }
223
233
  function readPresetPackageForNewTask(preset, values) {
224
234
  const candidates = presetDiscoveryTargetCandidates(values);
225
235
  let fallbackPackage = null;
@@ -300,25 +310,73 @@ function resolveNewTaskPositionals(positionals) {
300
310
  throw new Error(`Too many positional arguments for new-task: ${positionals.join(", ")}`);
301
311
  }
302
312
  function formatTaskCommandError(error) {
303
- const lines = [error.message];
304
- if (Array.isArray(error.recovery) && error.recovery.length > 0) {
313
+ const recovery = readArrayProperty(error, "recovery");
314
+ const details = readRecordProperty(error, "details");
315
+ const lines = [errorMessage(error)];
316
+ if (recovery.length > 0) {
305
317
  lines.push("", "Recovery:");
306
- for (const item of error.recovery)
307
- lines.push(`- ${item}`);
318
+ for (const item of recovery)
319
+ lines.push(`- ${String(item)}`);
308
320
  }
309
- if (error.details?.entries?.length) {
321
+ const entries = readArrayProperty(details, "entries");
322
+ if (entries.length) {
310
323
  lines.push("", "Blocking Git status:");
311
- for (const entry of error.details.entries)
312
- lines.push(`- ${entry.raw || entry.path}`);
324
+ for (const entry of entries) {
325
+ const raw = readProperty(entry, "raw");
326
+ const entryPath = readProperty(entry, "path");
327
+ lines.push(`- ${String(raw || entryPath || "")}`);
328
+ }
313
329
  }
314
- if (error.details?.disallowed?.length) {
330
+ const disallowed = readArrayProperty(details, "disallowed");
331
+ if (disallowed.length) {
315
332
  lines.push("", "Disallowed paths:");
316
- for (const item of error.details.disallowed)
317
- lines.push(`- ${item}`);
333
+ for (const item of disallowed)
334
+ lines.push(`- ${String(item)}`);
318
335
  }
319
- if (error.details?.stderr)
320
- lines.push("", error.details.stderr);
321
- if (error.details?.stdout)
322
- lines.push("", error.details.stdout);
336
+ const stderr = readProperty(details, "stderr");
337
+ const stdout = readProperty(details, "stdout");
338
+ if (stderr)
339
+ lines.push("", String(stderr));
340
+ if (stdout)
341
+ lines.push("", String(stdout));
323
342
  return lines.join("\n");
324
343
  }
344
+ function takeRepeatedKeyValueOptions(args, flag) {
345
+ const fields = {};
346
+ for (let index = 0; index < args.length;) {
347
+ if (args[index] !== flag) {
348
+ index += 1;
349
+ continue;
350
+ }
351
+ const raw = args[index + 1] || "";
352
+ args.splice(index, 2);
353
+ const separator = raw.indexOf("=");
354
+ if (separator <= 0)
355
+ throw new Error(`${flag} requires key=value`);
356
+ const key = raw.slice(0, separator).trim();
357
+ const value = raw.slice(separator + 1).trim();
358
+ if (!key || /[\r\n|]/.test(key))
359
+ throw new Error(`${flag} has invalid field key: ${key || "<empty>"}`);
360
+ if (Object.prototype.hasOwnProperty.call(fields, key))
361
+ throw new Error(`${flag} duplicate field key: ${key}`);
362
+ fields[key] = value;
363
+ }
364
+ return fields;
365
+ }
366
+ function readArrayProperty(value, key) {
367
+ const property = readProperty(value, key);
368
+ return Array.isArray(property) ? property : [];
369
+ }
370
+ function readRecordProperty(value, key) {
371
+ const property = readProperty(value, key);
372
+ return isRecord(property) ? property : null;
373
+ }
374
+ function readProperty(value, key) {
375
+ return isRecord(value) ? value[key] : undefined;
376
+ }
377
+ function isRecord(value) {
378
+ return typeof value === "object" && value !== null;
379
+ }
380
+ function errorMessage(error) {
381
+ return error instanceof Error ? error.message : String(error);
382
+ }
package/dist/harness.mjs CHANGED
@@ -1,304 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // @ts-nocheck
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- import { createInterface } from "node:readline/promises";
7
- import { addCapability, buildStatus, doctorUserSkill, installUserSkill, normalizeLocale, rebuildGovernanceIndexes, serveDashboardWorkbench, validateSourcePackageBoundary, writeInitFiles, } from "./lib/harness-core.mjs";
8
- import { runDashboardCommand } from "./commands/dashboard-command.mjs";
9
- import { runMigrationCommand } from "./commands/migration-command.mjs";
10
- import { runPresetCommand } from "./commands/preset-command.mjs";
11
- import { runTaskCommand } from "./commands/task-command.mjs";
12
- const args = process.argv.slice(2);
13
- const command = args.shift() || "help";
14
- function takeFlag(name, fallback = false) {
15
- const index = args.indexOf(name);
16
- if (index < 0)
17
- return fallback;
18
- args.splice(index, 1);
19
- return true;
20
- }
21
- function takeOption(name, fallback = "") {
22
- const index = args.indexOf(name);
23
- if (index < 0)
24
- return fallback;
25
- const value = args[index + 1] || fallback;
26
- args.splice(index, 2);
27
- return value;
28
- }
29
- async function resolveInitLocale(requestedLocale) {
30
- if (requestedLocale)
31
- return normalizeLocale(requestedLocale);
32
- if (!process.stdin.isTTY || !process.stdout.isTTY)
33
- return "en-US";
34
- const prompt = [
35
- "Select harness language / 选择初始化语言:",
36
- " 1. 中文 (zh-CN)",
37
- " 2. English (en-US)",
38
- "Language [1/2, default 2]: ",
39
- ].join("\n");
40
- const reader = createInterface({ input: process.stdin, output: process.stdout });
41
- try {
42
- const answer = (await reader.question(prompt)).trim().toLowerCase();
43
- if (["1", "zh", "zh-cn", "cn", "中文"].includes(answer))
44
- return "zh-CN";
45
- if (["2", "en", "en-us", "english", "英文", ""].includes(answer))
46
- return "en-US";
47
- console.error(`Unknown language selection: ${answer}. Falling back to en-US.`);
48
- return "en-US";
49
- }
50
- finally {
51
- reader.close();
52
- }
53
- }
54
- async function confirmUserInstall({ yes = false, dryRun = false, agent = "codex" } = {}) {
55
- if (yes || dryRun)
56
- return true;
57
- if (!process.stdin.isTTY || !process.stdout.isTTY)
58
- return false;
59
- const reader = createInterface({ input: process.stdin, output: process.stdout });
60
- try {
61
- const answer = (await reader.question(`Install Coding Agent Harness into user skill directory for ${agent}? [y/N] `)).trim().toLowerCase();
62
- return ["y", "yes"].includes(answer);
63
- }
64
- finally {
65
- reader.close();
66
- }
67
- }
68
- function targetArg() {
69
- return args[args.length - 1] && !args[args.length - 1].startsWith("-") ? args[args.length - 1] : ".";
70
- }
71
- function printHelp() {
72
- console.log(`Coding Agent Harness
73
-
74
- Usage:
75
- harness check [--profile source-package|private-harness|target-project] [target]
76
- harness status [--json] [--strict] [target]
77
- harness dev [--no-open] [--out-dir folder] [--host 127.0.0.1] [--port n] [target]
78
- harness dashboard [--out file.html] [--out-dir folder] [--workbench] [--host 127.0.0.1] [--port n] [target]
79
- harness init [--dry-run] [--locale zh-CN|en-US] [--capabilities core,dashboard] [--add-npm-scripts] [target]
80
- harness add-capability <name> [--dry-run] [--locale zh-CN|en-US] [target]
81
- harness migrate-plan [--json] [--limit n] [target]
82
- harness migrate-structure [--plan|--apply] [--force] [--json] [target]
83
- harness migrate-task-audit-index [--plan] [--apply] [--json] [target]
84
- harness migrate-run [--locale zh-CN|en-US] [--assume-locale] [--allow-dirty] [--plan-only] [--out-dir folder] [--session-dir folder] [target]
85
- harness migrate-verify [--json] [--full-cutover] <session.json>
86
- harness governance rebuild [--dry-run] [--archive] [--apply] [target]
87
- harness preset list [--json] [target]
88
- harness preset inspect <id> [--json] [target]
89
- harness preset check <id> [--json] [target]
90
- harness preset install <folder|zip|builtin-id> [--project] [--force] [--json] [target]
91
- harness preset seed [--project] [--force] [--dry-run] [--json] [target]
92
- harness preset uninstall <id> [--project] [--json] [target]
93
- harness new-task [task-id] [--module key] [--budget simple|standard|complex] [--preset id] [--from-session session.json] [--long-running] [--title title] [--locale zh-CN|en-US] [--dry-run] [target]
94
- harness task-start <task-id> [--message text] [target]
95
- harness task-phase <task-id> <phase-id> [--state done] [--completion 100] [--evidence present] [target]
96
- harness task-log <task-id> --message text [--evidence type:PATH:summary] [target]
97
- harness task-block <task-id> [--message text] [target]
98
- harness task-review <task-id> [--message text] [target]
99
- harness review-confirm <task-id> --confirm task-id [--reviewer name] [--message text] [target]
100
- harness lesson-promote <task-id> <candidate-id> [--dry-run|--apply] [target]
101
- harness lesson-sediment <task-id> <candidate-id> [--dry-run] [--title title] [target]
102
- harness task-complete <task-id> [--message text] [target]
103
- harness task-list [--json] [--state state] [--module key] [--queue queue] [--preset id] [--review status] [--lesson status] [--missing-materials] [--search text] [target]
104
- harness task-index [--json] [target]
105
- harness task-supersede <old-task-id> --by <new-task-id> [--reason text] [target]
106
- harness task-delete <task-id> --soft [--reason text] [target]
107
- harness task-archive <task-id> [--reason text] [target]
108
- harness task-reopen <task-id> [--reason text] [target]
109
- harness module-step <module-key> <step-id> [--state done|in-progress|blocked] [target]
110
- harness install-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir] [--dry-run] [--force] [--skip-presets] [--yes]
111
- harness doctor-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir]
112
-
113
- If init runs in an interactive terminal and --locale is omitted, it asks for a
114
- language. Non-interactive init defaults to en-US.
115
-
116
- Preset discovery:
117
- Project presets live in <target>/.coding-agent-harness/presets/<preset-id>/.
118
- User presets live in ~/.coding-agent-harness/presets/<preset-id>/.
119
- Harness discovers project presets first when a target is supplied, then user
120
- presets, then bundled package presets under presets/<preset-id>/.
121
- "harness init" seeds bundled presets into the target project. "harness
122
- install-user" and npm postinstall seed bundled presets into the user root.
123
- Use "harness preset seed" to repair or re-run preset seeding.
124
- Use "harness preset install" with a local preset folder, .zip archive, or
125
- bundled preset id. Preset archives must contain preset.yaml at the archive
126
- root or inside one top-level folder.
127
- Use "harness preset list --json" to see available presets, their source,
128
- purpose, compatible budgets, and manifest path. Use "harness preset inspect
129
- <id> --json" for the full preset manifest summary.
130
- `);
131
- }
132
- function exitWithReport(report) {
133
- for (const warning of report.warnings || [])
134
- console.log(`Warning: ${warning}`);
135
- for (const failure of report.failures || [])
136
- console.error(`Failure: ${failure}`);
137
- process.exit((report.failures || []).length > 0 ? 1 : 0);
138
- }
139
- if (command === "help" || command === "--help" || command === "-h") {
140
- printHelp();
141
- }
142
- else if (args[0] === "help" || args.includes("--help") || args.includes("-h")) {
143
- printHelp();
144
- }
145
- else if (command === "check") {
146
- const profile = takeOption("--profile", "target-project");
147
- const strict = takeFlag("--strict");
148
- const target = targetArg();
149
- const failures = [];
150
- const warnings = [];
151
- if (profile === "source-package") {
152
- for (const required of ["package.json", "dist/harness.mjs", "dist/check-harness.mjs", "templates/planning/task_plan.md"]) {
153
- if (!fs.existsSync(path.resolve(target, required)))
154
- failures.push(`missing source package file: ${required}`);
155
- }
156
- const boundary = validateSourcePackageBoundary(target);
157
- failures.push(...boundary.failures);
158
- warnings.push(...boundary.warnings);
159
- }
160
- const status = buildStatus(target, { skipLegacyCheck: profile === "source-package", strictLegacy: strict, strict, allowLegacyTarget: profile === "source-package" });
161
- failures.push(...status.checkState.details.failures);
162
- warnings.push(...status.checkState.details.warnings);
163
- if (!["source-package", "private-harness", "target-project"].includes(profile))
164
- failures.push(`unknown profile: ${profile}`);
165
- if (failures.length === 0)
166
- console.log(`Harness check passed (${profile}): ${path.resolve(target)}`);
167
- exitWithReport({ failures: [...new Set(failures)], warnings: [...new Set(warnings)] });
168
- }
169
- else if (command === "status") {
170
- const json = takeFlag("--json");
171
- const strict = takeFlag("--strict");
172
- const status = buildStatus(targetArg(), { strictLegacy: strict, strict });
173
- if (json) {
174
- console.log(JSON.stringify(status, null, 2));
175
- }
176
- else {
177
- console.log(`${status.project.name}: ${status.checkState.status} (${status.checkState.failures} failures, ${status.checkState.warnings} warnings)`);
178
- console.log(`mode: ${status.mode}`);
179
- console.log(`capabilities: ${status.capabilities.map((capability) => `${capability.name}:${capability.state}`).join(", ")}`);
180
- console.log(`tasks: ${status.tasks.length}`);
181
- }
182
- process.exitCode = status.checkState.status === "fail" ? 1 : 0;
183
- }
184
- else if (command === "dev") {
185
- const open = !takeFlag("--no-open");
186
- const outDir = takeOption("--out-dir", "");
187
- const host = takeOption("--host", "127.0.0.1");
188
- const port = takeOption("--port", "0");
189
- const localeOverride = takeOption("--locale", "");
190
- const target = targetArg();
191
- const usesDefaultOutDir = !outDir;
192
- const dashboardOutDir = outDir || defaultDevOutDir(target);
193
- const opts = { ...(localeOverride ? { localeOverride } : {}), recoverGeneratedDashboard: usesDefaultOutDir };
194
- try {
195
- await serveDashboardWorkbench(dashboardOutDir, target, { ...opts, host, port, autoRefresh: true, open, label: "harness dev" });
196
- }
197
- catch (error) {
198
- console.error(error.message);
199
- process.exit(1);
200
- }
201
- }
202
- else if (command === "dashboard") {
203
- await runDashboardCommand({ takeFlag, takeOption, targetArg });
204
- }
205
- else if (command === "init") {
206
- const dryRun = takeFlag("--dry-run");
207
- const addNpmScripts = takeFlag("--add-npm-scripts");
208
- const locale = await resolveInitLocale(takeOption("--locale", ""));
209
- const capabilities = takeOption("--capabilities", "core").split(",").map((item) => item.trim()).filter(Boolean);
210
- try {
211
- const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale, addNpmScripts });
212
- console.log(JSON.stringify({ dryRun, locale: result.locale, capabilities: result.capabilities, changes: result.changes, presetSeed: result.presetSeed, nextCommands: result.nextCommands, report: result.report }, null, 2));
213
- }
214
- catch (error) {
215
- console.error(error.message);
216
- process.exit(1);
217
- }
218
- }
219
- else if (command === "add-capability") {
220
- const dryRun = takeFlag("--dry-run");
221
- const locale = normalizeLocale(takeOption("--locale", ""));
222
- const capability = args.shift();
223
- if (!capability) {
224
- console.error("Missing capability name");
225
- process.exit(2);
226
- }
227
- try {
228
- const result = addCapability(targetArg(), capability, { dryRun, locale });
229
- console.log(JSON.stringify({ dryRun, registry: result.registry, changes: result.changes, report: result.report }, null, 2));
230
- }
231
- catch (error) {
232
- console.error(error.message);
233
- process.exit(1);
234
- }
235
- }
236
- else if (["migrate-plan", "migrate-structure", "migrate-run", "migrate-verify", "migrate-task-audit-index"].includes(command)) {
237
- runMigrationCommand(command, { args, takeFlag, takeOption, targetArg });
238
- }
239
- else if (command === "governance") {
240
- const subcommand = args.shift() || "";
241
- if (subcommand !== "rebuild") {
242
- console.error(`Unknown governance subcommand: ${subcommand || "(missing)"}`);
243
- process.exit(2);
244
- }
245
- const dryRun = takeFlag("--dry-run");
246
- const archive = takeFlag("--archive");
247
- const apply = takeFlag("--apply");
248
- try {
249
- console.log(JSON.stringify(rebuildGovernanceIndexes(targetArg(), { dryRun, archive, apply }), null, 2));
250
- }
251
- catch (error) {
252
- console.error(error.message);
253
- process.exit(1);
254
- }
255
- }
256
- else if (command === "preset") {
257
- runPresetCommand({ args, takeFlag, targetArg });
258
- }
259
- else if (["new-task", "task-phase", "task-start", "task-log", "task-block", "task-review", "task-complete", "review-confirm", "lesson-promote", "lesson-sediment", "task-list", "task-index", "task-supersede", "task-delete", "task-archive", "task-reopen", "module-step"].includes(command)) {
260
- runTaskCommand(command, { args, takeFlag, takeOption, targetArg });
261
- }
262
- else if (command === "install-user") {
263
- const dryRun = takeFlag("--dry-run");
264
- const force = takeFlag("--force");
265
- const yes = takeFlag("--yes") || takeFlag("-y");
266
- const skipPresets = takeFlag("--skip-presets");
267
- takeFlag("--global");
268
- const agent = takeOption("--agent", "codex");
269
- const home = takeOption("--home", "");
270
- if (!(await confirmUserInstall({ yes, dryRun, agent }))) {
271
- console.error("Refusing to write user skill files without confirmation. Re-run with --yes or --dry-run.");
272
- process.exit(2);
273
- }
274
- try {
275
- console.log(JSON.stringify(installUserSkill({ agent, home, dryRun, force, seedPresets: !skipPresets }), null, 2));
276
- }
277
- catch (error) {
278
- console.error(error.message);
279
- process.exit(1);
280
- }
281
- }
282
- else if (command === "doctor-user") {
283
- const agent = takeOption("--agent", "codex");
284
- const home = takeOption("--home", "");
285
- try {
286
- const report = doctorUserSkill({ agent, home });
287
- console.log(JSON.stringify(report, null, 2));
288
- process.exit(report.status === "pass" ? 0 : 1);
289
- }
290
- catch (error) {
291
- console.error(error.message);
292
- process.exit(1);
293
- }
294
- }
295
- else {
296
- printHelp();
297
- process.exit(2);
298
- }
299
- function defaultDevOutDir(targetInput) {
300
- const target = path.resolve(targetInput || ".");
301
- const name = path.basename(target) || "project";
302
- const hash = Buffer.from(target).toString("hex").slice(0, 16);
303
- return path.join(os.tmpdir(), "coding-agent-harness-dev", `${name}-${hash}`);
304
- }
2
+ import { commandRegistry } from "./commands/registry.mjs";
3
+ import { dispatchCommand } from "./lib/command-registry.mjs";
4
+ await Promise.resolve(dispatchCommand(commandRegistry, process.argv.slice(2))).catch((error) => {
5
+ console.error(error instanceof Error ? error.message : String(error));
6
+ process.exit(1);
7
+ });