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
@@ -0,0 +1,376 @@
1
+ // @ts-nocheck
2
+ // Dynamic audit metadata parsing stays behavior-first until the metadata domain model PR.
3
+ import { spawnSync } from "node:child_process";
4
+ import path from "node:path";
5
+ import { toPosix } from "./core-shared.mjs";
6
+ import { firstColumn, markdownTableRows } from "./markdown-utils.mjs";
7
+ export const taskAuditHeadingPattern = /^##\s*(?:Task Audit Metadata|任务审计元数据)\s*$/im;
8
+ export const scaffoldProvenanceHeadingPattern = /^##\s*(?:Scaffold Provenance|脚手架来源)\s*$/im;
9
+ export const humanReviewConfirmationHeadingPattern = /^##\s*(?:Human Review Confirmation|人工审查确认)\s*$/im;
10
+ export const taskAuditFieldOrder = [
11
+ "Created By",
12
+ "Created At",
13
+ "Command Shape",
14
+ "Budget",
15
+ "Template Source",
16
+ "Task Creator",
17
+ "Task Creator Source",
18
+ "Human Review Status",
19
+ "Confirmation ID",
20
+ "Confirmed At",
21
+ "Reviewer",
22
+ "Reviewer Email",
23
+ "Confirm Text",
24
+ "Evidence Checked",
25
+ "Review Commit SHA",
26
+ "Audit Source",
27
+ "Audit Status",
28
+ "Exception Reason",
29
+ "Message",
30
+ "Migration Status",
31
+ "Migrated From",
32
+ "Legacy Extra Fields",
33
+ "Migration Notes",
34
+ ];
35
+ export function readGitIdentity(projectRoot) {
36
+ const gitRoot = spawnSync("git", ["rev-parse", "--show-toplevel"], { cwd: projectRoot, encoding: "utf8" });
37
+ if (gitRoot.status !== 0) {
38
+ return { name: "n/a", email: "n/a", display: "n/a", source: "git-unavailable" };
39
+ }
40
+ const name = spawnSync("git", ["config", "--get", "user.name"], { cwd: projectRoot, encoding: "utf8" }).stdout.trim();
41
+ const email = spawnSync("git", ["config", "--get", "user.email"], { cwd: projectRoot, encoding: "utf8" }).stdout.trim();
42
+ if (!name && !email)
43
+ return { name: "n/a", email: "n/a", display: "n/a", source: "git-config-missing" };
44
+ const display = name && email ? `${name} <${email}>` : name || email;
45
+ return { name: name || "n/a", email: email || "n/a", display, source: "git-config" };
46
+ }
47
+ export function buildCreationTaskAudit(scaffoldProvenance, { projectRoot }) {
48
+ const creator = readGitIdentity(projectRoot);
49
+ return {
50
+ "Created By": scaffoldProvenance.createdBy || "harness new-task",
51
+ "Created At": scaffoldProvenance.createdAt || "",
52
+ "Command Shape": scaffoldProvenance.command || "",
53
+ "Budget": scaffoldProvenance.budget || "",
54
+ "Template Source": scaffoldProvenance.templateSource || "",
55
+ "Task Creator": creator.display,
56
+ "Task Creator Source": creator.source,
57
+ "Human Review Status": "not-confirmed",
58
+ "Confirmation ID": "n/a",
59
+ "Confirmed At": "n/a",
60
+ "Reviewer": "n/a",
61
+ "Reviewer Email": "n/a",
62
+ "Confirm Text": "n/a",
63
+ "Evidence Checked": "n/a",
64
+ "Review Commit SHA": "n/a",
65
+ "Audit Source": "native-index",
66
+ "Audit Status": "created",
67
+ "Exception Reason": scaffoldProvenance.exceptionReason || "n/a",
68
+ "Message": "n/a",
69
+ "Migration Status": "native",
70
+ "Migrated From": "n/a",
71
+ "Legacy Extra Fields": "{}",
72
+ "Migration Notes": "n/a",
73
+ };
74
+ }
75
+ export function taskAuditTemplateValues(fields = {}) {
76
+ const values = {};
77
+ for (const field of taskAuditFieldOrder) {
78
+ const key = `TASK_AUDIT_${field.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_|_$/g, "")}`;
79
+ values[key] = markdownCell(fields[field] || "n/a");
80
+ }
81
+ return values;
82
+ }
83
+ export function renderTaskAuditMetadata(fields = {}, { locale = "en-US" } = {}) {
84
+ const heading = locale === "zh-CN" ? "## 任务审计元数据" : "## Task Audit Metadata";
85
+ const rows = taskAuditFieldOrder.map((field) => `| ${field} | ${markdownCell(fields[field] ?? "n/a")} |`);
86
+ return `${heading}\n\n| Field | Value |\n| --- | --- |\n${rows.join("\n")}\n`;
87
+ }
88
+ export function replaceTaskAuditMetadata(content, fields, options = {}) {
89
+ const rendered = renderTaskAuditMetadata(fields, options).trimEnd();
90
+ const text = String(content || "").trimEnd();
91
+ const match = findHeadingBlock(text, taskAuditHeadingPattern);
92
+ if (match)
93
+ return `${text.slice(0, match.start)}${rendered}\n${text.slice(match.end).replace(/^\n+/, "\n")}`;
94
+ const identityMatch = findHeadingBlock(text, /^##\s*(?:Task Identity|任务身份)\s*$/im);
95
+ if (identityMatch) {
96
+ return `${text.slice(0, identityMatch.end).trimEnd()}\n\n${rendered}\n\n${text.slice(identityMatch.end).trimStart()}`;
97
+ }
98
+ return `${text}\n\n${rendered}\n`;
99
+ }
100
+ export function parseTaskAuditMetadata(content, { required = false } = {}) {
101
+ const block = extractTaskAuditBlock(content);
102
+ const fields = block ? fieldsFromMarkdownBlock(block.body) : new Map();
103
+ const issues = [];
104
+ if (required && fields.size === 0)
105
+ issues.push({ code: "missing-task-audit-metadata", message: "missing Task Audit Metadata section" });
106
+ if (fields.size > 0) {
107
+ for (const field of ["Created By", "Created At", "Budget", "Template Source", "Task Creator Source", "Human Review Status", "Audit Status"]) {
108
+ if (!isConcreteAuditField(fields.get(field.toLowerCase())))
109
+ issues.push({ code: `missing-task-audit-${slugField(field)}`, message: `Task Audit Metadata missing ${field}` });
110
+ }
111
+ const createdBy = normalizeToken(fields.get("created by"));
112
+ const createdAt = fields.get("created at") || "";
113
+ const budget = normalizeToken(fields.get("budget"));
114
+ const creatorSource = normalizeToken(fields.get("task creator source"));
115
+ const reviewStatus = normalizeToken(fields.get("human review status"));
116
+ const auditStatus = normalizeToken(fields.get("audit status"));
117
+ if (isConcreteAuditField(fields.get("created by")) && !["harness-new-task", "manual-exception", "historical-backfill"].includes(createdBy)) {
118
+ issues.push({ code: "invalid-task-audit-created-by", message: `Task Audit Metadata invalid Created By: ${fields.get("created by")}` });
119
+ }
120
+ if (createdBy === "manual-exception" && !isConcreteAuditField(fields.get("exception reason"))) {
121
+ issues.push({ code: "missing-task-audit-exception-reason", message: "Task Audit Metadata manual-exception requires Exception Reason" });
122
+ }
123
+ if (isConcreteAuditField(createdAt) && normalizeToken(createdAt) !== "legacy-unavailable" && !isValidDateOnly(createdAt)) {
124
+ issues.push({ code: "invalid-task-audit-created-at", message: `Task Audit Metadata invalid Created At: ${createdAt}` });
125
+ }
126
+ if (isConcreteAuditField(fields.get("budget")) && !["simple", "standard", "complex", "legacy-unavailable"].includes(budget)) {
127
+ issues.push({ code: "invalid-task-audit-budget", message: `Task Audit Metadata invalid Budget: ${fields.get("budget")}` });
128
+ }
129
+ if (isConcreteAuditField(fields.get("task creator source")) && !["git-config", "git-config-missing", "git-unavailable", "legacy-unavailable"].includes(creatorSource)) {
130
+ issues.push({ code: "invalid-task-audit-task-creator-source", message: `Task Audit Metadata invalid Task Creator Source: ${fields.get("task creator source")}` });
131
+ }
132
+ if (isConcreteAuditField(fields.get("human review status")) && !["not-confirmed", "confirmed"].includes(reviewStatus)) {
133
+ issues.push({ code: "invalid-task-audit-human-review-status", message: `Task Audit Metadata invalid Human Review Status: ${fields.get("human review status")}` });
134
+ }
135
+ if (isConcreteAuditField(fields.get("audit status")) && !["created", "committed", "migrated"].includes(auditStatus)) {
136
+ issues.push({ code: "invalid-task-audit-audit-status", message: `Task Audit Metadata invalid Audit Status: ${fields.get("audit status")}` });
137
+ }
138
+ if (reviewStatus === "confirmed") {
139
+ for (const field of ["Confirmation ID", "Confirmed At", "Reviewer", "Reviewer Email", "Confirm Text", "Evidence Checked", "Review Commit SHA"]) {
140
+ if (!isConcreteAuditField(fields.get(field.toLowerCase())))
141
+ issues.push({ code: `missing-task-audit-${slugField(field)}`, message: `Task Audit Metadata confirmed review missing ${field}` });
142
+ }
143
+ }
144
+ }
145
+ return {
146
+ present: fields.size > 0,
147
+ fields,
148
+ issues,
149
+ summary: taskAuditSummary(fields, issues),
150
+ };
151
+ }
152
+ export function legacyAuditIssues(target, taskDir, { briefContent = "", reviewContent = "" } = {}) {
153
+ const issues = [];
154
+ const relativeDir = toPosix(path.relative(target.projectRoot, taskDir));
155
+ if (scaffoldProvenanceHeadingPattern.test(briefContent)) {
156
+ issues.push(legacyIssue(`${relativeDir}/brief.md`, "legacy-scaffold-provenance", "legacy Scaffold Provenance must be migrated to INDEX.md"));
157
+ }
158
+ if (humanReviewConfirmationHeadingPattern.test(reviewContent)) {
159
+ issues.push(legacyIssue(`${relativeDir}/review.md`, "legacy-human-review-confirmation", "legacy Human Review Confirmation must be migrated to INDEX.md"));
160
+ }
161
+ return issues;
162
+ }
163
+ export function taskAuditMaterialIssues(target, taskDir, audit) {
164
+ const relativeIndexPath = `${toPosix(path.relative(target.projectRoot, taskDir))}/INDEX.md`;
165
+ return (audit.issues || []).map((issue) => ({
166
+ code: issue.code,
167
+ severity: "P1",
168
+ queue: "missing-materials",
169
+ sourcePath: `TARGET:${relativeIndexPath}`,
170
+ sourceLine: 0,
171
+ owner: "agent",
172
+ message: issue.message,
173
+ allowedWritePaths: [relativeIndexPath],
174
+ forbiddenActions: ["human-confirm", "edit-unrelated-task", "fabricate-evidence"],
175
+ validationCommands: ["node dist/harness.mjs check --profile target-project <target>"],
176
+ confidence: "exact",
177
+ repairable: true,
178
+ }));
179
+ }
180
+ export function scaffoldProvenanceSummaryFromTaskAudit(audit) {
181
+ const fields = audit?.fields || new Map();
182
+ return {
183
+ required: true,
184
+ present: Boolean(audit?.present),
185
+ createdBy: normalizeToken(fields.get("created by")),
186
+ command: fields.get("command shape") || "",
187
+ createdAt: fields.get("created at") || "",
188
+ budget: normalizeToken(fields.get("budget")),
189
+ templateSource: fields.get("template source") || "",
190
+ exceptionReason: fields.get("exception reason") || "",
191
+ issues: audit?.issues || [],
192
+ };
193
+ }
194
+ export function reviewConfirmationFromTaskAudit(audit, { taskKey = "" } = {}) {
195
+ const fields = audit?.fields || new Map();
196
+ if (!audit?.present)
197
+ return null;
198
+ const status = normalizeToken(fields.get("human review status"));
199
+ if (status !== "confirmed")
200
+ return { confirmed: false, missingFields: [] };
201
+ const required = ["Confirmation ID", "Confirmed At", "Reviewer", "Reviewer Email", "Confirm Text", "Evidence Checked", "Review Commit SHA", "Audit Status"];
202
+ const missing = required.filter((field) => !isConcreteAuditField(fields.get(field.toLowerCase())));
203
+ const confirmText = fields.get("confirm text") || "";
204
+ const commitSha = fields.get("review commit sha") || "";
205
+ const auditStatus = fields.get("audit status") || "";
206
+ const auditSource = fields.get("audit source") || "";
207
+ const migratedLegacy = auditSource === "migrated-legacy-review";
208
+ const confirmTextMismatch = Boolean(!migratedLegacy && taskKey && isConcreteAuditField(confirmText) && !taskKeysMatch(confirmText, taskKey));
209
+ const commitShaInvalid = Boolean(!migratedLegacy && isConcreteAuditField(commitSha) && !/^[0-9a-f]{7,40}$/i.test(commitSha));
210
+ const auditStatusInvalid = Boolean(isConcreteAuditField(auditStatus) && auditStatus.trim().toLowerCase() !== "committed");
211
+ const invalidFields = [
212
+ ...(confirmTextMismatch ? ["Confirm Text match"] : []),
213
+ ...(commitShaInvalid ? ["Review Commit SHA valid"] : []),
214
+ ...(auditStatusInvalid ? ["Audit Status committed"] : []),
215
+ ];
216
+ return {
217
+ confirmed: missing.length === 0 && invalidFields.length === 0,
218
+ missingFields: [...missing, ...invalidFields],
219
+ confirmationId: fields.get("confirmation id") || "",
220
+ confirmedAt: fields.get("confirmed at") || "",
221
+ reviewer: fields.get("reviewer") || "",
222
+ reviewerEmail: fields.get("reviewer email") || "",
223
+ taskKey,
224
+ taskKeyMismatch: false,
225
+ confirmText,
226
+ confirmTextMismatch,
227
+ evidenceChecked: fields.get("evidence checked") || "",
228
+ commitSha,
229
+ commitShaInvalid,
230
+ auditStatus,
231
+ auditStatusInvalid,
232
+ auditSource,
233
+ migratedFrom: fields.get("migrated from") || "",
234
+ gitAudit: migratedLegacy ? { valid: true, migrated: true } : null,
235
+ gitAuditInvalid: false,
236
+ };
237
+ }
238
+ export function stripLegacyAuditBlocks(content) {
239
+ return stripHeadingBlock(stripHeadingBlock(content, scaffoldProvenanceHeadingPattern), humanReviewConfirmationHeadingPattern);
240
+ }
241
+ export function extractLegacyBlock(content, pattern) {
242
+ const block = findHeadingBlock(content, pattern);
243
+ if (!block)
244
+ return null;
245
+ return {
246
+ ...block,
247
+ body: String(content || "").slice(block.headingEnd, block.end),
248
+ raw: String(content || "").slice(block.start, block.end),
249
+ };
250
+ }
251
+ export function fieldsFromMarkdownBlock(block) {
252
+ const fields = new Map();
253
+ const tableRows = markdownTableRows(block);
254
+ const header = tableRows[0] || [];
255
+ const fieldIndex = firstColumn(header, ["Field", "字段"]);
256
+ const valueIndex = firstColumn(header, ["Value", "值"]);
257
+ if (fieldIndex >= 0 && valueIndex >= 0) {
258
+ for (const row of tableRows.slice(1).filter((candidate) => !candidate.every((cell) => /^:?-{3,}:?$/.test(cell)))) {
259
+ const key = String(row[fieldIndex] || "").replace(/`/g, "").trim();
260
+ if (key)
261
+ fields.set(key.toLowerCase(), String(row[valueIndex] || "").replace(/`/g, "").trim());
262
+ }
263
+ }
264
+ for (const line of String(block || "").split(/\r?\n/)) {
265
+ if (line.trim().startsWith("|"))
266
+ continue;
267
+ const match = line.match(/^\s*(?:[-*]\s*)?([^::|]+?)\s*[::]\s*(.+?)\s*$/);
268
+ if (match)
269
+ fields.set(match[1].trim().toLowerCase(), match[2].trim());
270
+ }
271
+ return fields;
272
+ }
273
+ export function isConcreteAuditField(value) {
274
+ const raw = String(value || "").replace(/`/g, "").trim();
275
+ return Boolean(raw) && !/^(n\/a|na|none|pending(?:[-_ ].*)?|todo|tbd|\[.*\]|-|—|–|不适用|无|待定|\{\})$/i.test(raw) && !/\{\{[^}]+\}\}/.test(raw);
276
+ }
277
+ export function legacyExtraFieldsJson(entries) {
278
+ const extra = {};
279
+ for (const [field, value] of entries) {
280
+ if (!field || !isConcreteAuditField(value))
281
+ continue;
282
+ extra[field] = value;
283
+ }
284
+ return JSON.stringify(extra);
285
+ }
286
+ function extractTaskAuditBlock(content) {
287
+ const block = findHeadingBlock(content, taskAuditHeadingPattern);
288
+ if (!block)
289
+ return null;
290
+ return { ...block, body: String(content || "").slice(block.headingEnd, block.end) };
291
+ }
292
+ function findHeadingBlock(content, pattern) {
293
+ const text = String(content || "");
294
+ const match = text.match(pattern);
295
+ if (!match || match.index === undefined)
296
+ return null;
297
+ const headingEnd = text.indexOf("\n", match.index);
298
+ const bodyStart = headingEnd < 0 ? text.length : headingEnd + 1;
299
+ const next = text.slice(bodyStart).search(/^##\s+/m);
300
+ const end = next < 0 ? text.length : bodyStart + next;
301
+ return { start: match.index, headingEnd: bodyStart, end };
302
+ }
303
+ function stripHeadingBlock(content, pattern) {
304
+ const text = String(content || "");
305
+ const block = findHeadingBlock(text, pattern);
306
+ if (!block)
307
+ return text;
308
+ return `${text.slice(0, block.start).trimEnd()}\n\n${text.slice(block.end).trimStart()}`.replace(/\n{3,}/g, "\n\n");
309
+ }
310
+ function taskAuditSummary(fields, issues) {
311
+ return {
312
+ present: fields.size > 0,
313
+ createdBy: normalizeToken(fields.get("created by")),
314
+ command: fields.get("command shape") || "",
315
+ createdAt: fields.get("created at") || "",
316
+ budget: normalizeToken(fields.get("budget")),
317
+ templateSource: fields.get("template source") || "",
318
+ taskCreator: fields.get("task creator") || "",
319
+ taskCreatorSource: fields.get("task creator source") || "",
320
+ humanReviewStatus: normalizeToken(fields.get("human review status")),
321
+ confirmationId: fields.get("confirmation id") || "",
322
+ confirmedAt: fields.get("confirmed at") || "",
323
+ reviewer: fields.get("reviewer") || "",
324
+ reviewerEmail: fields.get("reviewer email") || "",
325
+ confirmText: fields.get("confirm text") || "",
326
+ evidenceChecked: fields.get("evidence checked") || "",
327
+ reviewCommitSha: fields.get("review commit sha") || "",
328
+ auditSource: fields.get("audit source") || "",
329
+ auditStatus: normalizeToken(fields.get("audit status")),
330
+ exceptionReason: fields.get("exception reason") || "",
331
+ message: fields.get("message") || "",
332
+ migrationStatus: normalizeToken(fields.get("migration status")),
333
+ migratedFrom: fields.get("migrated from") || "",
334
+ legacyExtraFields: fields.get("legacy extra fields") || "{}",
335
+ migrationNotes: fields.get("migration notes") || "",
336
+ issues,
337
+ };
338
+ }
339
+ function legacyIssue(relativePath, code, message) {
340
+ return {
341
+ code,
342
+ severity: "P1",
343
+ queue: "missing-materials",
344
+ sourcePath: `TARGET:${relativePath}`,
345
+ sourceLine: 0,
346
+ owner: "agent",
347
+ message,
348
+ allowedWritePaths: [relativePath],
349
+ forbiddenActions: ["human-confirm", "edit-unrelated-task", "fabricate-evidence"],
350
+ validationCommands: ["node dist/harness.mjs migrate-task-audit-index --apply <target>"],
351
+ confidence: "exact",
352
+ repairable: true,
353
+ };
354
+ }
355
+ function markdownCell(value) {
356
+ return String(value ?? "").replace(/\r?\n/g, "<br>").replace(/\|/g, "\\|");
357
+ }
358
+ function normalizeToken(value) {
359
+ return String(value || "").replace(/`/g, "").trim().toLowerCase().replaceAll("_", "-").replace(/\s+/g, "-");
360
+ }
361
+ function slugField(value) {
362
+ return String(value || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
363
+ }
364
+ function taskKeysMatch(candidate, expected) {
365
+ const left = String(candidate || "").replace(/`/g, "").trim();
366
+ const right = String(expected || "").replace(/`/g, "").trim();
367
+ return left === right || right.endsWith(`/${left}`);
368
+ }
369
+ function isValidDateOnly(value) {
370
+ const raw = String(value || "").trim();
371
+ const match = raw.match(/^(\d{4})-(\d{2})-(\d{2})$/);
372
+ if (!match)
373
+ return false;
374
+ const date = new Date(`${raw}T00:00:00.000Z`);
375
+ return !Number.isNaN(date.getTime()) && date.toISOString().slice(0, 10) === raw;
376
+ }