coding-agent-harness 1.0.5 → 1.0.7

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 (260) hide show
  1. package/CONTRIBUTING.md +2 -2
  2. package/README.md +63 -3
  3. package/README.zh-CN.md +52 -3
  4. package/SKILL.md +43 -43
  5. package/dist/build-dist.mjs +189 -0
  6. package/dist/check-dist-observation.mjs +428 -0
  7. package/dist/check-harness.mjs +489 -0
  8. package/dist/check-import-graph.mjs +511 -0
  9. package/dist/check-runtime-emit.mjs +304 -0
  10. package/dist/check-type-boundaries.mjs +139 -0
  11. package/dist/commands/dashboard-command.mjs +80 -0
  12. package/dist/commands/migration-command.mjs +152 -0
  13. package/dist/commands/preset-command.mjs +91 -0
  14. package/dist/commands/task-command.mjs +324 -0
  15. package/dist/harness.mjs +304 -0
  16. package/dist/lib/capability-registry.mjs +643 -0
  17. package/dist/lib/check-module-parallel.mjs +227 -0
  18. package/dist/lib/check-profiles.mjs +414 -0
  19. package/dist/lib/check-task-contracts.mjs +54 -0
  20. package/dist/lib/core-shared.mjs +254 -0
  21. package/dist/lib/dashboard-data.mjs +608 -0
  22. package/dist/lib/dashboard-workbench.mjs +334 -0
  23. package/dist/lib/dashboard-writer.mjs +200 -0
  24. package/dist/lib/git-status-summary.mjs +45 -0
  25. package/dist/lib/governance-index-generator.mjs +236 -0
  26. package/dist/lib/governance-sync.mjs +617 -0
  27. package/dist/lib/governance-table-boundary.mjs +161 -0
  28. package/{scripts → dist}/lib/harness-core.mjs +2 -0
  29. package/dist/lib/harness-paths.mjs +338 -0
  30. package/dist/lib/lesson-maintenance.mjs +139 -0
  31. package/dist/lib/markdown-utils.mjs +193 -0
  32. package/dist/lib/migration-planner.mjs +439 -0
  33. package/dist/lib/migration-support.mjs +317 -0
  34. package/dist/lib/phase-kind.mjs +46 -0
  35. package/dist/lib/preset-audit-contracts.mjs +40 -0
  36. package/dist/lib/preset-engine.mjs +516 -0
  37. package/dist/lib/preset-registry.mjs +831 -0
  38. package/dist/lib/preset-resource-contracts.mjs +83 -0
  39. package/dist/lib/review-confirm-git-gate.mjs +244 -0
  40. package/dist/lib/status-builder.mjs +87 -0
  41. package/{scripts → dist}/lib/status-dashboard-renderer.mjs +44 -46
  42. package/dist/lib/structure-migration.mjs +404 -0
  43. package/dist/lib/subagent-authorization-audit.mjs +198 -0
  44. package/dist/lib/task-audit-metadata.mjs +376 -0
  45. package/dist/lib/task-audit-migration.mjs +355 -0
  46. package/dist/lib/task-completion-consistency.mjs +29 -0
  47. package/dist/lib/task-index.mjs +133 -0
  48. package/dist/lib/task-lesson-candidates.mjs +239 -0
  49. package/dist/lib/task-lesson-sedimentation.mjs +300 -0
  50. package/dist/lib/task-lifecycle/create-task-helpers.mjs +84 -0
  51. package/dist/lib/task-lifecycle/phase-sync.mjs +82 -0
  52. package/dist/lib/task-lifecycle/review-confirm.mjs +93 -0
  53. package/dist/lib/task-lifecycle/review-gates.mjs +62 -0
  54. package/dist/lib/task-lifecycle/review-submission.mjs +52 -0
  55. package/dist/lib/task-lifecycle/scaffold-provenance.mjs +54 -0
  56. package/dist/lib/task-lifecycle/template-files.mjs +52 -0
  57. package/dist/lib/task-lifecycle/text-utils.mjs +26 -0
  58. package/dist/lib/task-lifecycle.mjs +611 -0
  59. package/dist/lib/task-metadata.mjs +116 -0
  60. package/dist/lib/task-review-model.mjs +474 -0
  61. package/dist/lib/task-scanner.mjs +439 -0
  62. package/dist/lib/task-tombstone-commands.mjs +125 -0
  63. package/dist/postinstall.mjs +14 -0
  64. package/dist/run-built-tests.mjs +84 -0
  65. package/docs-release/README.md +1 -0
  66. package/docs-release/architecture/overview.md +12 -12
  67. package/docs-release/architecture/overview.zh-CN.md +12 -12
  68. package/docs-release/architecture/system-explainer/01-system-overview.md +15 -14
  69. package/docs-release/architecture/system-explainer/02-module-dependency.md +8 -8
  70. package/docs-release/architecture/system-explainer/03-task-lifecycle.md +3 -3
  71. package/docs-release/architecture/system-explainer/04-check-and-governance.md +9 -7
  72. package/docs-release/architecture/system-explainer/05-data-flow.md +5 -5
  73. package/docs-release/architecture/system-explainer/06-preset-and-migration.md +1 -4
  74. package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +15 -14
  75. package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +8 -8
  76. package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +3 -3
  77. package/docs-release/architecture/system-explainer/en-US/04-check-and-governance.md +10 -8
  78. package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +5 -5
  79. package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +1 -4
  80. package/docs-release/guides/agent-installation.en-US.md +14 -8
  81. package/docs-release/guides/agent-installation.md +14 -8
  82. package/docs-release/guides/contributing.md +3 -3
  83. package/docs-release/guides/contributing.zh-CN.md +3 -3
  84. package/docs-release/guides/document-audience-and-surfaces.en-US.md +10 -10
  85. package/docs-release/guides/document-audience-and-surfaces.md +10 -10
  86. package/docs-release/guides/legacy-migration-agent-prompt.md +25 -2
  87. package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +25 -2
  88. package/docs-release/guides/migration-playbook.en-US.md +63 -1
  89. package/docs-release/guides/migration-playbook.md +59 -1
  90. package/docs-release/guides/parent-control-repository-pattern.en-US.md +25 -25
  91. package/docs-release/guides/parent-control-repository-pattern.md +25 -25
  92. package/docs-release/guides/preset-development.md +2 -2
  93. package/docs-release/guides/repository-operating-models.en-US.md +21 -21
  94. package/docs-release/guides/repository-operating-models.md +21 -21
  95. package/docs-release/guides/task-state-machine.en-US.md +5 -5
  96. package/docs-release/guides/task-state-machine.md +5 -5
  97. package/docs-release/guides/typescript-runtime-migration-closeout.md +96 -0
  98. package/examples/minimal-project/AGENTS.md +2 -2
  99. package/examples/minimal-project/coding-agent-harness/harness.yaml +14 -0
  100. package/examples/minimal-project/coding-agent-harness/planning/tasks/demo-task/progress.md +11 -0
  101. package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/review.md +1 -1
  102. package/package.json +20 -12
  103. package/presets/legacy-migration/preset.yaml +5 -5
  104. package/presets/legacy-migration/templates/execution_strategy.append.md +1 -1
  105. package/presets/lesson-sedimentation/preset.yaml +3 -3
  106. package/presets/module/preset.yaml +2 -2
  107. package/presets/module/templates/execution_strategy.append.md +1 -1
  108. package/presets/module/templates/task_plan.append.md +3 -3
  109. package/presets/standard-task/preset.yaml +2 -2
  110. package/references/adversarial-review-standard.md +2 -2
  111. package/references/agents-md-pattern.md +14 -14
  112. package/references/cadence-ledger.md +1 -1
  113. package/references/ci-cd-standard.md +1 -1
  114. package/references/delivery-operating-model-standard.md +4 -4
  115. package/references/docs-directory-standard.md +65 -159
  116. package/references/external-source-intake-standard.md +10 -10
  117. package/references/harness-ledger.md +5 -5
  118. package/references/legacy-12-phase-bootstrap.md +2 -2
  119. package/references/lessons-governance.md +15 -15
  120. package/references/long-running-task-standard.md +6 -6
  121. package/references/module-parallel-standard.md +34 -34
  122. package/references/planning-loop.md +6 -6
  123. package/references/project-onboarding-audit.md +4 -4
  124. package/references/regression-system.md +2 -2
  125. package/references/repo-governance-standard.md +4 -4
  126. package/references/review-routing-standard.md +1 -1
  127. package/references/ssot-governance.md +19 -19
  128. package/references/taskr-gap-analysis.md +5 -5
  129. package/references/walkthrough-closeout.md +14 -14
  130. package/references/worktree-parallel.md +3 -3
  131. package/skills/preset-creator/references/complex-task-skeleton/task_plan.md +1 -1
  132. package/skills/preset-creator/references/preset-package-skeleton.md +5 -5
  133. package/templates/AGENTS.md.template +26 -26
  134. package/templates/architecture/README.md +4 -4
  135. package/templates/architecture/service-catalog.md +2 -2
  136. package/templates/architecture/services/service-template.md +1 -1
  137. package/templates/dashboard/assets/app-src/20-overview.js +11 -5
  138. package/templates/dashboard/assets/app-src/40-modules.js +1 -1
  139. package/templates/dashboard/assets/app.js +12 -6
  140. package/templates/dashboard/assets/i18n.js +4 -2
  141. package/templates/development/README.md +10 -10
  142. package/templates/development/cross-repo-debugging.md +3 -3
  143. package/templates/development/external-context/service-template.md +2 -2
  144. package/templates/development/external-source-packs/README.md +4 -4
  145. package/templates/integrations/README.md +4 -4
  146. package/templates/integrations/api-contract.md +2 -2
  147. package/templates/integrations/event-contract.md +2 -2
  148. package/templates/integrations/third-party/vendor-template.md +2 -2
  149. package/templates/integrations/webhook-contract.md +2 -2
  150. package/templates/ledger/Harness-Ledger.md +1 -1
  151. package/templates/planning/INDEX.md +1 -0
  152. package/templates/planning/module_session_prompt.md +1 -1
  153. package/templates/planning/task_plan.md +1 -1
  154. package/templates/planning/walkthrough.md +47 -0
  155. package/templates/reference/docs-library-standard.md +8 -8
  156. package/templates/reference/external-source-intake-standard.md +15 -15
  157. package/templates/reference/repo-governance-standard.md +1 -1
  158. package/templates/ssot/Module-Registry.md +1 -1
  159. package/templates/walkthrough/walkthrough-template.md +2 -2
  160. package/templates-zh-CN/AGENTS.md.template +26 -26
  161. package/templates-zh-CN/CLAUDE.md.template +1 -1
  162. package/templates-zh-CN/architecture/README.md +4 -4
  163. package/templates-zh-CN/architecture/service-catalog.md +2 -2
  164. package/templates-zh-CN/architecture/services/service-template.md +1 -1
  165. package/templates-zh-CN/development/README.md +10 -10
  166. package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
  167. package/templates-zh-CN/development/external-context/service-template.md +2 -2
  168. package/templates-zh-CN/development/external-source-packs/README.md +4 -4
  169. package/templates-zh-CN/integrations/README.md +4 -4
  170. package/templates-zh-CN/integrations/api-contract.md +2 -2
  171. package/templates-zh-CN/integrations/event-contract.md +2 -2
  172. package/templates-zh-CN/integrations/third-party/vendor-template.md +2 -2
  173. package/templates-zh-CN/integrations/webhook-contract.md +2 -2
  174. package/templates-zh-CN/ledger/Harness-Ledger.md +1 -1
  175. package/templates-zh-CN/lessons/lesson-arch-process-change.md +1 -1
  176. package/templates-zh-CN/lessons/lesson-new-doc.md +3 -3
  177. package/templates-zh-CN/lessons/lesson-ref-change.md +4 -4
  178. package/templates-zh-CN/planning/module_session_prompt.md +11 -11
  179. package/templates-zh-CN/planning/walkthrough.md +47 -0
  180. package/templates-zh-CN/reference/adversarial-review-standard.md +2 -2
  181. package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
  182. package/templates-zh-CN/reference/docs-library-standard.md +28 -28
  183. package/templates-zh-CN/reference/execution-workflow-standard.md +1 -1
  184. package/templates-zh-CN/reference/external-source-intake-standard.md +16 -16
  185. package/templates-zh-CN/reference/harness-ledger-standard.md +6 -6
  186. package/templates-zh-CN/reference/regression-ssot-governance.md +2 -2
  187. package/templates-zh-CN/reference/repo-governance-standard.md +1 -1
  188. package/templates-zh-CN/reference/review-routing-standard.md +1 -1
  189. package/templates-zh-CN/reference/walkthrough-standard.md +7 -7
  190. package/templates-zh-CN/reference/worktree-standard.md +1 -1
  191. package/templates-zh-CN/regression/Cadence-Ledger.md +2 -2
  192. package/templates-zh-CN/ssot/Delivery-SSoT.md +3 -3
  193. package/templates-zh-CN/ssot/Module-Registry.md +3 -3
  194. package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
  195. package/templates-zh-CN/walkthrough/walkthrough-template.md +5 -5
  196. package/tsconfig.dist.json +16 -0
  197. package/tsconfig.json +25 -0
  198. package/tsconfig.runtime.json +24 -0
  199. package/examples/minimal-project/.harness-capabilities.json +0 -8
  200. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/progress.md +0 -11
  201. package/scripts/check-harness.mjs +0 -508
  202. package/scripts/commands/dashboard-command.mjs +0 -67
  203. package/scripts/commands/migration-command.mjs +0 -126
  204. package/scripts/commands/preset-command.mjs +0 -73
  205. package/scripts/commands/task-command.mjs +0 -328
  206. package/scripts/harness.mjs +0 -291
  207. package/scripts/lib/capability-registry.mjs +0 -587
  208. package/scripts/lib/check-module-parallel.mjs +0 -230
  209. package/scripts/lib/check-profiles.mjs +0 -372
  210. package/scripts/lib/check-task-contracts.mjs +0 -55
  211. package/scripts/lib/core-shared.mjs +0 -249
  212. package/scripts/lib/dashboard-data.mjs +0 -520
  213. package/scripts/lib/dashboard-workbench.mjs +0 -336
  214. package/scripts/lib/dashboard-writer.mjs +0 -202
  215. package/scripts/lib/git-status-summary.mjs +0 -46
  216. package/scripts/lib/governance-index-generator.mjs +0 -174
  217. package/scripts/lib/governance-sync.mjs +0 -611
  218. package/scripts/lib/governance-table-boundary.mjs +0 -175
  219. package/scripts/lib/lesson-maintenance.mjs +0 -152
  220. package/scripts/lib/markdown-utils.mjs +0 -191
  221. package/scripts/lib/migration-planner.mjs +0 -476
  222. package/scripts/lib/migration-support.mjs +0 -312
  223. package/scripts/lib/phase-kind.mjs +0 -50
  224. package/scripts/lib/preset-audit-contracts.mjs +0 -37
  225. package/scripts/lib/preset-engine.mjs +0 -494
  226. package/scripts/lib/preset-registry.mjs +0 -776
  227. package/scripts/lib/preset-resource-contracts.mjs +0 -83
  228. package/scripts/lib/review-confirm-git-gate.mjs +0 -248
  229. package/scripts/lib/status-builder.mjs +0 -88
  230. package/scripts/lib/subagent-authorization-audit.mjs +0 -196
  231. package/scripts/lib/task-audit-metadata.mjs +0 -385
  232. package/scripts/lib/task-audit-migration.mjs +0 -350
  233. package/scripts/lib/task-completion-consistency.mjs +0 -26
  234. package/scripts/lib/task-index.mjs +0 -93
  235. package/scripts/lib/task-lesson-candidates.mjs +0 -242
  236. package/scripts/lib/task-lesson-sedimentation.mjs +0 -326
  237. package/scripts/lib/task-lifecycle/create-task-helpers.mjs +0 -67
  238. package/scripts/lib/task-lifecycle/phase-sync.mjs +0 -88
  239. package/scripts/lib/task-lifecycle/review-confirm.mjs +0 -112
  240. package/scripts/lib/task-lifecycle/review-gates.mjs +0 -73
  241. package/scripts/lib/task-lifecycle/review-submission.mjs +0 -63
  242. package/scripts/lib/task-lifecycle/scaffold-provenance.mjs +0 -49
  243. package/scripts/lib/task-lifecycle/template-files.mjs +0 -53
  244. package/scripts/lib/task-lifecycle/text-utils.mjs +0 -24
  245. package/scripts/lib/task-lifecycle.mjs +0 -616
  246. package/scripts/lib/task-metadata.mjs +0 -118
  247. package/scripts/lib/task-review-model.mjs +0 -455
  248. package/scripts/lib/task-scanner.mjs +0 -503
  249. package/scripts/lib/task-tombstone-commands.mjs +0 -140
  250. package/scripts/postinstall.mjs +0 -14
  251. package/templates/walkthrough/Closeout-SSoT.md +0 -43
  252. package/templates-zh-CN/walkthrough/Closeout-SSoT.md +0 -42
  253. /package/examples/minimal-project/{docs → coding-agent-harness/governance/generated}/Harness-Ledger.md +0 -0
  254. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/INDEX.md +0 -0
  255. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/brief.md +0 -0
  256. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/execution_strategy.md +0 -0
  257. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/findings.md +0 -0
  258. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/lesson_candidates.md +0 -0
  259. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/task_plan.md +0 -0
  260. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/visual_map.md +0 -0
@@ -1,88 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import {
4
- lessonCandidatesFile,
5
- readFileSafe,
6
- todayDate,
7
- toPosix,
8
- visualMapFile,
9
- } from "../core-shared.mjs";
10
- import {
11
- firstColumn,
12
- updateMarkdownTableRow,
13
- } from "../markdown-utils.mjs";
14
- import {
15
- normalizePhaseActor,
16
- normalizePhaseKind,
17
- } from "../phase-kind.mjs";
18
- import { parseLessonCandidateStatus } from "../task-lesson-candidates.mjs";
19
-
20
- export function advanceLifecyclePhase(target, taskDir, event) {
21
- const visualMapPath = path.join(taskDir, visualMapFile);
22
- if (!fs.existsSync(visualMapPath)) return "";
23
- const content = readFileSafe(visualMapPath);
24
- let updated = false;
25
- const phaseUpdate = updateMarkdownTableRow(content, /^Phase ID$/i, (header, row) => {
26
- if (updated || !phaseMatchesLifecycleEvent(header, row, event)) return null;
27
- updated = true;
28
- const next = [...row];
29
- const stateIndex = firstColumn(header, ["State", "状态"]);
30
- const completionIndex = firstColumn(header, ["Completion", "完成度"]);
31
- const evidenceIndex = firstColumn(header, ["Evidence Status", "证据状态"]);
32
- if (stateIndex >= 0) next[stateIndex] = "done";
33
- if (completionIndex >= 0) next[completionIndex] = "100";
34
- if (evidenceIndex >= 0) next[evidenceIndex] = "present";
35
- return next;
36
- });
37
- if (!updated || phaseUpdate.content === content) return "";
38
- fs.writeFileSync(visualMapPath, phaseUpdate.content);
39
- return toPosix(path.relative(target.projectRoot, visualMapPath));
40
- }
41
-
42
- export function autoRecordNoLessonCandidateDecision(target, taskDir) {
43
- const candidatePath = path.join(taskDir, lessonCandidatesFile);
44
- if (!fs.existsSync(candidatePath)) return "";
45
- const content = readFileSafe(candidatePath);
46
- const status = parseLessonCandidateStatus(content);
47
- if (status.rows.length > 0 || status.declaredStatus !== "pending-review") return "";
48
- const next = replaceNoLessonCandidateFields(content);
49
- if (next === content) return "";
50
- fs.writeFileSync(candidatePath, next);
51
- return toPosix(path.relative(target.projectRoot, candidatePath));
52
- }
53
-
54
- function phaseMatchesLifecycleEvent(header, row, event) {
55
- const kindIndex = firstColumn(header, ["Kind", "阶段类型", "类型"]);
56
- if (kindIndex < 0) return false;
57
- const actorIndex = firstColumn(header, ["Actor", "执行者", "角色"]);
58
- const exitCommandIndex = firstColumn(header, ["Exit Command", "出口命令", "退出命令"]);
59
- const outputIndex = firstColumn(header, ["Output", "产出"]);
60
- const kind = normalizePhaseKind(row[kindIndex]);
61
- const actor = actorIndex >= 0 ? normalizePhaseActor(row[actorIndex]) : "agent";
62
- const exitCommand = String(row[exitCommandIndex] || "");
63
- const output = String(row[outputIndex] || "");
64
- if (event === "task-start") return kind === "init" && actor === "agent";
65
- if (event === "task-review") {
66
- return kind === "gate" && actor === "agent" && (/\btask-review\b/.test(exitCommand) || /Agent Review Submission/i.test(output));
67
- }
68
- if (event === "task-complete") {
69
- return kind === "gate" && actor === "agent" && /\btask-complete\b/.test(exitCommand);
70
- }
71
- return false;
72
- }
73
-
74
- function replaceNoLessonCandidateFields(content) {
75
- let next = String(content || "");
76
- const replacements = [
77
- [/(\|\s*Task-level status\s*\|\s*)[^|]+(\|)/i, "$1no-candidate-accepted $2"],
78
- [/(\|\s*Review decision\s*\|\s*)[^|]+(\|)/i, "$1accepted-no-candidate $2"],
79
- [/(\|\s*Closeout token\s*\|\s*)[^|]+(\|)/i, "$1checked-none:auto-no-candidate $2"],
80
- [/(\|\s*Last updated\s*\|\s*)[^|]+(\|)/i, `$1${todayDate()} $2`],
81
- ];
82
- for (const [pattern, replacement] of replacements) next = next.replace(pattern, replacement);
83
- const reason = "Agent review found no reusable lesson candidates in this task; the empty candidate table is recorded as checked for closeout.";
84
- return next.replace(
85
- /(## No-Candidate Reason\s*\n)([\s\S]*?)(?=\n## |\s*$)/,
86
- `$1\n${reason}\n`,
87
- );
88
- }
@@ -1,112 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import {
4
- lessonCandidatesFile,
5
- nowTimestamp,
6
- readFileSafe,
7
- } from "../core-shared.mjs";
8
- import {
9
- parseTaskAuditMetadata,
10
- readGitIdentity,
11
- replaceTaskAuditMetadata,
12
- taskAuditFieldOrder,
13
- } from "../task-audit-metadata.mjs";
14
- import {
15
- collectReviewRisks,
16
- isBlockingReviewRisk,
17
- isLessonCandidateDecisionComplete,
18
- parseLessonCandidateStatus,
19
- parseTaskBudget,
20
- taskIdForDirectory,
21
- } from "../task-scanner.mjs";
22
- import { commitReviewConfirmationGate, prepareReviewConfirmGitGate } from "../review-confirm-git-gate.mjs";
23
- import { validateHumanReviewConfirmation } from "./review-gates.mjs";
24
- import { markdownCell } from "./text-utils.mjs";
25
-
26
- export function confirmTaskReview({ target, taskDir, findTaskByDirectory }, { reviewer = "Human Reviewer", message = "", confirmText = "", evidence = "" } = {}) {
27
- assertTaskDirectoryInsidePlanning(target, taskDir);
28
- const canonicalTaskId = taskIdForDirectory(target, taskDir);
29
- const shortId = path.basename(taskDir);
30
- if (confirmText && ![shortId, canonicalTaskId].includes(confirmText)) {
31
- throw new Error(`Review confirmation text must match task id: ${shortId}`);
32
- }
33
- if (!confirmText) throw new Error(`Missing review confirmation text: ${shortId}`);
34
-
35
- const reviewPath = path.join(taskDir, "review.md");
36
- const indexPath = path.join(taskDir, "INDEX.md");
37
- const reviewContent = readFileSafe(reviewPath);
38
- const indexContent = readFileSafe(indexPath);
39
- const budget = parseTaskBudget(readFileSafe(path.join(taskDir, "task_plan.md")));
40
- const candidateStatus = parseLessonCandidateStatus(readFileSafe(path.join(taskDir, lessonCandidatesFile)));
41
- const blockingRisks = collectReviewRisks(reviewContent).filter(isBlockingReviewRisk);
42
- if (blockingRisks.length > 0) {
43
- const ids = blockingRisks.map((risk) => risk.id || risk.severity).join(", ");
44
- throw new Error(`Open blocking review findings must be closed before confirmation: ${ids}`);
45
- }
46
- validateHumanReviewConfirmation({
47
- task: findTaskByDirectory(target, taskDir),
48
- budget,
49
- });
50
- if (budget !== "simple" && !isLessonCandidateDecisionComplete(candidateStatus)) {
51
- throw new Error(`Human review confirmation requires lesson candidate decision complete; current status is ${candidateStatus.status}.`);
52
- }
53
- const gitGate = prepareReviewConfirmGitGate(target.projectRoot, [indexPath]);
54
-
55
- const timestamp = nowTimestamp();
56
- const confirmationId = `HRC-${timestamp.replace(/[^0-9]/g, "").slice(0, 14)}`;
57
- const identity = readGitIdentity(target.projectRoot);
58
- const baseAuditFields = taskAuditFieldsFromIndex(indexContent);
59
- const buildAuditFields = ({ commitSha = "pending", auditStatus = "commit-pending" } = {}) => ({
60
- ...baseAuditFields,
61
- "Human Review Status": "confirmed",
62
- "Confirmation ID": confirmationId,
63
- "Confirmed At": timestamp,
64
- "Reviewer": reviewer || identity.name || "Human Reviewer",
65
- "Reviewer Email": identity.email || "n/a",
66
- "Confirm Text": markdownCell(confirmText),
67
- "Evidence Checked": evidence || `TARGET:docs/09-PLANNING/${canonicalTaskId}/review.md`,
68
- "Review Commit SHA": commitSha,
69
- "Audit Source": "native-index",
70
- "Audit Status": auditStatus,
71
- "Message": message || "Human review confirmed",
72
- "Migration Status": baseAuditFields["Migration Status"] || "native",
73
- });
74
- fs.writeFileSync(indexPath, ensureTrailingNewline(replaceTaskAuditMetadata(indexContent, buildAuditFields(), { locale: target.locale })));
75
- const audit = commitReviewConfirmationGate(gitGate, {
76
- taskId: canonicalTaskId,
77
- reviewPath: indexPath,
78
- message: message || `Human review confirmed by ${reviewer}`,
79
- writeFinalAudit(commitSha) {
80
- const currentIndex = readFileSafe(indexPath);
81
- const finalIndex = replaceTaskAuditMetadata(currentIndex, buildAuditFields({ commitSha, auditStatus: "committed" }), { locale: target.locale });
82
- fs.writeFileSync(indexPath, ensureTrailingNewline(finalIndex));
83
- },
84
- });
85
- return {
86
- event: "review-confirm",
87
- task: findTaskByDirectory(target, taskDir) || { id: canonicalTaskId, reviewStatus: "confirmed" },
88
- audit,
89
- };
90
- }
91
-
92
- function assertTaskDirectoryInsidePlanning(target, taskDir) {
93
- const realTaskDir = fs.realpathSync(taskDir);
94
- const allowedRoots = [
95
- path.join(target.docsRoot, "09-PLANNING/TASKS"),
96
- path.join(target.docsRoot, "09-PLANNING/MODULES"),
97
- ].filter(fs.existsSync).map((root) => fs.realpathSync(root));
98
- if (!allowedRoots.some((root) => realTaskDir === root || realTaskDir.startsWith(`${root}${path.sep}`))) {
99
- throw new Error(`Task directory outside planning root: ${taskIdForDirectory(target, taskDir)}`);
100
- }
101
- }
102
-
103
- function taskAuditFieldsFromIndex(content) {
104
- const audit = parseTaskAuditMetadata(content, { required: true });
105
- const fields = {};
106
- for (const field of taskAuditFieldOrder) fields[field] = audit.fields.get(field.toLowerCase()) || "n/a";
107
- return fields;
108
- }
109
-
110
- function ensureTrailingNewline(content) {
111
- return content.endsWith("\n") ? content : `${content}\n`;
112
- }
@@ -1,73 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import {
4
- lessonCandidatesFile,
5
- } from "../core-shared.mjs";
6
- import {
7
- collectReviewRisks,
8
- isBlockingReviewRisk,
9
- parseTaskAuditMetadata,
10
- parsePhases,
11
- parseReviewConfirmation,
12
- readVisualMapContractFile,
13
- } from "../task-scanner.mjs";
14
- import {
15
- implementationPhases,
16
- phaseHasRecordedProgress,
17
- } from "../phase-kind.mjs";
18
-
19
- export function validateLifecycleTransition({ event, currentState, budget, reviewContent = "", indexContent = "", reviewTaskKey = "", projectRoot = "", taskDir = "" }) {
20
- if (event === "task-review" && currentState !== "in_progress") {
21
- throw new Error(`task-review requires current state in_progress; current state is ${currentState || "unknown"}`);
22
- }
23
- if (event === "task-complete" && budget !== "simple" && currentState !== "review") {
24
- throw new Error(`task-complete for ${budget} tasks requires current state review. Run task-review first.`);
25
- }
26
- if (event === "task-complete" && budget !== "simple") {
27
- const blockingRisks = collectReviewRisks(reviewContent).filter(isBlockingReviewRisk);
28
- if (blockingRisks.length > 0) {
29
- const ids = blockingRisks.map((risk) => risk.id || risk.severity).join(", ");
30
- throw new Error(`Open blocking review findings must be closed before task-complete: ${ids}`);
31
- }
32
- if (!parseReviewConfirmation(reviewContent, { taskKey: reviewTaskKey, taskAudit: parseTaskAuditMetadata(indexContent), projectRoot, taskDir, indexPath: path.join(taskDir, "INDEX.md") })?.confirmed) {
33
- throw new Error("Human review must be confirmed before task-complete. Run review-confirm first.");
34
- }
35
- }
36
- }
37
-
38
- export function validateReviewEntryGate(taskDir, budget) {
39
- if (budget === "simple") return;
40
- const candidatePath = path.join(taskDir, lessonCandidatesFile);
41
- if (!fs.existsSync(candidatePath)) {
42
- throw new Error(`task-review requires ${lessonCandidatesFile} before entering human review.`);
43
- }
44
- const phases = parsePhases(readVisualMapContractFile(taskDir).content);
45
- const actionablePhases = implementationPhases(phases);
46
- if (phases.length > 0 && actionablePhases.length === 0) {
47
- throw new Error("task-review requires at least one non-skipped Visual Map execution phase.");
48
- }
49
- const hasRecordedPhaseProgress = actionablePhases.some(phaseHasRecordedProgress);
50
- if (actionablePhases.length > 0 && !hasRecordedPhaseProgress) {
51
- throw new Error("task-review requires at least one Visual Map execution phase progress update. Run task-phase before entering human review.");
52
- }
53
- }
54
-
55
- export function validateHumanReviewConfirmation({ task, budget }) {
56
- if (budget === "simple") return;
57
- if (!task?.walkthroughPath) {
58
- throw new Error("Human review confirmation requires a walkthrough linked from Closeout SSoT before review-confirm.");
59
- }
60
- const queueState = task?.reviewQueueState || "not-in-queue";
61
- if (queueState !== "ready-to-confirm") {
62
- const state = task?.state || "unknown";
63
- throw new Error(`Human review confirmation requires canonical ready-to-confirm review queue; current state is ${state}, review queue is ${queueState}.`);
64
- }
65
- if (!Array.isArray(task?.taskQueues) || !task.taskQueues.includes("review")) {
66
- const queues = Array.isArray(task?.taskQueues) ? task.taskQueues.join(", ") : "none";
67
- throw new Error(`Human review confirmation requires the task to be in the Review queue; current queues: ${queues || "none"}.`);
68
- }
69
- if (!task?.lessonCandidateDecisionComplete) {
70
- const status = task?.lessonCandidateStatus || "missing";
71
- throw new Error(`Human review confirmation requires lesson candidate decision complete; current status is ${status}.`);
72
- }
73
- }
@@ -1,63 +0,0 @@
1
- import crypto from "node:crypto";
2
- import fs from "node:fs";
3
- import path from "node:path";
4
- import {
5
- lessonCandidatesFile,
6
- longRunningTaskContractFile,
7
- nowTimestamp,
8
- readFileSafe,
9
- toPosix,
10
- visualMapFile,
11
- } from "../core-shared.mjs";
12
- import {
13
- collectReviewRisks,
14
- isBlockingReviewRisk,
15
- taskScannerVersion,
16
- } from "../task-review-model.mjs";
17
- import { markdownCell } from "./text-utils.mjs";
18
-
19
- export function renderAgentReviewSubmission({ target, taskDir, canonicalTaskId, message, evidence }) {
20
- const timestamp = nowTimestamp();
21
- const submissionId = `ARS-${timestamp.replace(/[^0-9]/g, "").slice(0, 14)}`;
22
- const materialsHash = hashTaskMaterials(taskDir);
23
- const reviewContent = readFileSafe(path.join(taskDir, "review.md"));
24
- const openFindings = collectReviewRisks(reviewContent).filter(isBlockingReviewRisk).length;
25
- const evidenceSummary = evidence || message || "Agent submitted task for human review.";
26
- return [
27
- "## Agent Review Submission",
28
- "",
29
- "| Field | Value |",
30
- "| --- | --- |",
31
- `| Submission ID | ${submissionId} |`,
32
- `| Submitted At | ${timestamp} |`,
33
- "| Submitted By | agent |",
34
- `| Task Key | ${canonicalTaskId} |`,
35
- `| Materials Checklist Hash | ${materialsHash} |`,
36
- `| Evidence Summary | ${markdownCell(evidenceSummary)} |`,
37
- `| Open Findings Count | ${openFindings} |`,
38
- `| Scanner Version | ${taskScannerVersion} |`,
39
- `| Target | TARGET:${toPosix(path.relative(target.projectRoot, taskDir))} |`,
40
- "",
41
- ].join("\n");
42
- }
43
-
44
- export function replaceAgentReviewSubmission(content, block) {
45
- const trimmed = String(content || "").trimEnd();
46
- if (/^##\s*(?:Agent Review Submission|Agent 审查提交|Agent 提交审查)\s*$/im.test(trimmed)) {
47
- return `${trimmed.replace(/^##\s*(?:Agent Review Submission|Agent 审查提交|Agent 提交审查)\s*$[\s\S]*?(?=^##\s+|(?![\s\S]))/im, `${block.trimEnd()}\n\n`)}\n`;
48
- }
49
- return `${trimmed}\n\n${block.trimEnd()}\n`;
50
- }
51
-
52
- function hashTaskMaterials(taskDir) {
53
- const hash = crypto.createHash("sha256");
54
- for (const fileName of ["brief.md", "task_plan.md", visualMapFile, lessonCandidatesFile, "progress.md", "review.md", "findings.md", longRunningTaskContractFile]) {
55
- const filePath = path.join(taskDir, fileName);
56
- if (!fs.existsSync(filePath)) continue;
57
- hash.update(fileName);
58
- hash.update("\0");
59
- hash.update(readFileSafe(filePath));
60
- hash.update("\0");
61
- }
62
- return hash.digest("hex").slice(0, 16);
63
- }
@@ -1,49 +0,0 @@
1
- import path from "node:path";
2
- import { localizedTemplateSource, todayDate } from "../core-shared.mjs";
3
- import { markdownCell } from "./text-utils.mjs";
4
-
5
- function shellArg(value) {
6
- const text = String(value || "");
7
- if (/^[A-Za-z0-9._/:=@+-]+$/.test(text)) return text;
8
- return `'${text.replaceAll("'", "'\\''")}'`;
9
- }
10
-
11
- function commandPathArg(value, fallback) {
12
- const text = String(value || fallback || ".").trim() || ".";
13
- if (text === ".") return ".";
14
- return path.isAbsolute(text) ? fallback : text;
15
- }
16
-
17
- function renderNewTaskCommand({ taskId, title, locale, budget, longRunning, moduleKey, preset, fromSession, targetInput }) {
18
- const parts = ["harness", "new-task"];
19
- if (taskId) parts.push(taskId);
20
- parts.push("--budget", budget, "--locale", locale);
21
- if (title) parts.push("--title", title);
22
- if (moduleKey) parts.push("--module", moduleKey);
23
- if (preset && preset !== "none") parts.push("--preset", preset);
24
- if (fromSession) parts.push("--from-session", commandPathArg(fromSession, "<session.json>"));
25
- if (longRunning) parts.push("--long-running");
26
- parts.push(commandPathArg(targetInput, "<target>"));
27
- return parts.map(shellArg).join(" ");
28
- }
29
-
30
- export function buildScaffoldProvenance({ taskId, normalizedTaskId, title, locale, budget, longRunning, moduleKey, preset, fromSession, targetInput, automaticTaskId = false }) {
31
- return {
32
- createdBy: "harness new-task",
33
- command: markdownCell(renderNewTaskCommand({
34
- taskId: automaticTaskId ? "" : taskId || normalizedTaskId,
35
- title,
36
- locale,
37
- budget,
38
- longRunning,
39
- moduleKey,
40
- preset,
41
- fromSession,
42
- targetInput,
43
- })),
44
- createdAt: todayDate(),
45
- budget,
46
- templateSource: localizedTemplateSource("templates/planning/brief.md", locale),
47
- exceptionReason: "n/a",
48
- };
49
- }
@@ -1,53 +0,0 @@
1
- import { localizedTemplateSource, longRunningTaskContractFile, visualMapFile, lessonCandidatesFile } from "../core-shared.mjs";
2
-
3
- export function taskTemplateFiles({ locale = "en-US" } = {}) {
4
- return [
5
- ["INDEX.md", "templates/planning/INDEX.md"],
6
- ["brief.md", "templates/planning/brief.md"],
7
- ["task_plan.md", "templates/planning/task_plan.md"],
8
- ["execution_strategy.md", "templates/planning/execution_strategy.md"],
9
- [visualMapFile, "templates/planning/visual_map.md"],
10
- ["findings.md", "templates/planning/findings.md"],
11
- [lessonCandidatesFile, "templates/planning/lesson_candidates.md"],
12
- ["progress.md", "templates/planning/progress.md"],
13
- ["review.md", "templates/planning/review.md"],
14
- ].map(([destination, source]) => [destination, localizedTemplateSource(source, locale)]);
15
- }
16
-
17
- export function simpleTaskTemplateFiles({ locale = "en-US" } = {}) {
18
- return [
19
- ["INDEX.md", "templates/planning/INDEX.md"],
20
- ["brief.md", "templates/planning/brief.md"],
21
- ["task_plan.md", "templates/planning/task_plan.md"],
22
- [visualMapFile, "templates/planning/visual_map.simple.md"],
23
- ["progress.md", "templates/planning/progress.md"],
24
- ].map(([destination, source]) => [destination, localizedTemplateSource(source, locale)]);
25
- }
26
-
27
- export function optionalTaskTemplateFiles({ locale = "en-US" } = {}) {
28
- return [
29
- ["references/INDEX.md", "templates/planning/optional/references/INDEX.md"],
30
- ["artifacts/INDEX.md", "templates/planning/optional/artifacts/INDEX.md"],
31
- ].map(([destination, source]) => [destination, localizedTemplateSource(source, locale)]);
32
- }
33
-
34
- export function moduleTemplateFiles({ locale = "en-US" } = {}) {
35
- return [
36
- ["brief.md", "templates/planning/module_brief.md"],
37
- ["module_plan.md", "templates/planning/module_plan.md"],
38
- ["execution_strategy.md", "templates/planning/execution_strategy.md"],
39
- [visualMapFile, "templates/planning/visual_map.md"],
40
- ["session_prompt.md", "templates/planning/module_session_prompt.md"],
41
- ].map(([destination, source]) => [destination, localizedTemplateSource(source, locale)]);
42
- }
43
-
44
- export function taskFilesForBudget({ budget, locale }) {
45
- if (budget === "simple") return simpleTaskTemplateFiles({ locale });
46
- if (budget === "complex") return [...taskTemplateFiles({ locale }), ...optionalTaskTemplateFiles({ locale })];
47
- return taskTemplateFiles({ locale });
48
- }
49
-
50
- export function appendLongRunningContractFile(files, { locale, longRunning }) {
51
- if (!longRunning) return files;
52
- return [...files, [longRunningTaskContractFile, localizedTemplateSource("templates/planning/long-running-task-contract.md", locale)]];
53
- }
@@ -1,24 +0,0 @@
1
- import { nowTimestamp } from "../core-shared.mjs";
2
-
3
- export function appendProgressLog(content, { event, message, evidence, actor = "coordinator" }) {
4
- const timestamp = nowTimestamp();
5
- const safeMessage = String(message || event).replace(/\r?\n/g, " ").trim();
6
- const safeEvidence = String(evidence || "n/a").replace(/\r?\n/g, " ").trim();
7
- if (/^##\s*Log\s*$/im.test(content)) {
8
- return content.replace(
9
- /(^##\s*Log\s*$[\s\S]*?\| --- \| --- \| --- \| --- \| --- \|\n)/im,
10
- `$1| ${timestamp} | ${actor} | ${event}: ${safeMessage} | ${safeEvidence} | ${event === "task-complete" ? "done" : "continue"} |\n`,
11
- );
12
- }
13
- if (/^##\s*进度记录\s*$/im.test(content)) {
14
- return `${content.trimEnd()}\n\n### [${timestamp}] - ${event}\n\n- 做了什么:${safeMessage}\n- 验证结果:已记录\n- 下一步:${event === "task-complete" ? "完成" : "继续执行"}\n- 证据:${safeEvidence}\n`;
15
- }
16
- return `${content.trimEnd()}\n\n## Log\n\n| Time | Actor | Action | Evidence | Next |\n| --- | --- | --- | --- | --- |\n| ${timestamp} | ${actor} | ${event}: ${safeMessage} | ${safeEvidence} | ${event === "task-complete" ? "done" : "continue"} |\n`;
17
- }
18
-
19
- export function markdownCell(value) {
20
- return String(value || "")
21
- .replace(/\r?\n/g, " ")
22
- .replaceAll("|", "\\|")
23
- .trim();
24
- }