@fitlab-ai/agent-infra 0.9.13 → 0.9.15

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 (428) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/cli.ts +26 -9
  4. package/bin/internal-cli.sh +45 -0
  5. package/dist/bin/cli.js +173 -157
  6. package/dist/bin/internal-cli.js +126 -42
  7. package/dist/lib/agent-client.js +5 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  10. package/dist/lib/defaults.json +103 -103
  11. package/dist/lib/fs/durable-write.js +37 -0
  12. package/dist/lib/fs/file-lock.js +111 -0
  13. package/dist/lib/host-control/audit.js +19 -0
  14. package/dist/lib/host-control/client.js +142 -0
  15. package/dist/lib/host-control/command.js +49 -0
  16. package/dist/lib/host-control/path.js +160 -0
  17. package/dist/lib/host-control/secure-fs.js +140 -0
  18. package/dist/lib/host-control/server.js +159 -0
  19. package/dist/lib/host-control/service.js +112 -0
  20. package/dist/lib/init.js +11 -2
  21. package/dist/lib/internal/agent-client.js +5 -2
  22. package/dist/lib/internal/cli-route-inventory.js +154 -0
  23. package/dist/lib/internal/codex-lifecycle.js +15 -12
  24. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  25. package/dist/lib/internal/demo-promotion.js +322 -0
  26. package/dist/lib/internal/demo-transcript.js +454 -0
  27. package/dist/lib/internal/git-workflow.js +10 -6
  28. package/dist/lib/internal/host-control.js +28 -0
  29. package/dist/lib/internal/manual-validation.js +322 -0
  30. package/dist/lib/internal/platform-checks.js +16 -4
  31. package/dist/lib/internal/platform-comment.js +16 -4
  32. package/dist/lib/internal/platform-context.js +4 -1
  33. package/dist/lib/internal/platform-issue.js +12 -4
  34. package/dist/lib/internal/platform-metadata.js +88 -0
  35. package/dist/lib/internal/platform-pr-review.js +16 -3
  36. package/dist/lib/internal/platform-pr.js +42 -14
  37. package/dist/lib/internal/platform-release-notes.js +6 -3
  38. package/dist/lib/internal/platform-security.js +93 -0
  39. package/dist/lib/internal/pr-review-grade.js +14 -3
  40. package/dist/lib/internal/release-workflow.js +82 -89
  41. package/dist/lib/internal/sandbox-control.js +171 -7
  42. package/dist/lib/internal/task-activity.js +13 -4
  43. package/dist/lib/internal/task-artifact.js +19 -107
  44. package/dist/lib/internal/task-context.js +4 -1
  45. package/dist/lib/internal/task-create.js +48 -14
  46. package/dist/lib/internal/task-delivery.js +4 -1
  47. package/dist/lib/internal/task-event.js +38 -35
  48. package/dist/lib/internal/task-finalization.js +4 -1
  49. package/dist/lib/internal/task-invalidation.js +4 -1
  50. package/dist/lib/internal/task-ledger.js +12 -1
  51. package/dist/lib/internal/task-lifecycle.js +4 -1
  52. package/dist/lib/internal/task-operation-registry.js +519 -0
  53. package/dist/lib/internal/task-orchestration.js +12 -0
  54. package/dist/lib/internal/task-override.js +10 -3
  55. package/dist/lib/internal/task-qualification.js +90 -0
  56. package/dist/lib/internal/task-review.js +10 -52
  57. package/dist/lib/internal/task-short-id.js +11 -1
  58. package/dist/lib/internal/task-snapshot.js +4 -1
  59. package/dist/lib/internal/task-validate.js +37 -12
  60. package/dist/lib/internal/task-verify.js +5 -1
  61. package/dist/lib/internal/task-warning.js +8 -1
  62. package/dist/lib/owned-path.js +33 -0
  63. package/dist/lib/platform/check-status.js +11 -0
  64. package/dist/lib/platform/comment-safety.js +229 -0
  65. package/dist/lib/platform/completion-backfill.js +1 -1
  66. package/dist/lib/platform/github-data.js +241 -0
  67. package/dist/lib/platform/github-provider.js +248 -26
  68. package/dist/lib/platform/issue-comments.js +146 -34
  69. package/dist/lib/platform/issues.js +1 -179
  70. package/dist/lib/platform/pr-change-report.js +6 -12
  71. package/dist/lib/platform/pr-checks.js +12 -65
  72. package/dist/lib/platform/pr-summary.js +83 -10
  73. package/dist/lib/platform/provider-contract.d.ts +67 -1
  74. package/dist/lib/platform/provider-contract.js +6 -2
  75. package/dist/lib/platform/provider-validation.js +76 -3
  76. package/dist/lib/platform/pull-requests.js +117 -275
  77. package/dist/lib/platform/repository-metadata.js +377 -0
  78. package/dist/lib/platform/security-alerts.js +155 -0
  79. package/dist/lib/platform/snapshots.js +2 -0
  80. package/dist/lib/platform/verification-sync.js +154 -162
  81. package/dist/lib/process-data/index.js +7 -0
  82. package/dist/lib/release/workflow.js +1 -1
  83. package/dist/lib/run/index.js +5 -0
  84. package/dist/lib/sandbox/commands/control-status.js +22 -0
  85. package/dist/lib/sandbox/commands/create.js +39 -8
  86. package/dist/lib/sandbox/commands/ls.js +5 -0
  87. package/dist/lib/sandbox/commands/rm.js +3 -807
  88. package/dist/lib/sandbox/commands/show.js +16 -0
  89. package/dist/lib/sandbox/control/audit.js +203 -0
  90. package/dist/lib/sandbox/control/client.js +125 -12
  91. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  92. package/dist/lib/sandbox/control/container-identity.js +28 -31
  93. package/dist/lib/sandbox/control/executor.js +233 -34
  94. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  95. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  96. package/dist/lib/sandbox/control/lifecycle.js +656 -128
  97. package/dist/lib/sandbox/control/native-file-lock.js +85 -0
  98. package/dist/lib/sandbox/control/protocol.js +55 -4
  99. package/dist/lib/sandbox/control/server.js +720 -79
  100. package/dist/lib/sandbox/control/state.js +63 -3
  101. package/dist/lib/sandbox/control/task-view.js +183 -0
  102. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  103. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  104. package/dist/lib/sandbox/engines/authority.js +289 -0
  105. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  106. package/dist/lib/sandbox/index.js +7 -2
  107. package/dist/lib/sandbox/recovery.js +49 -5
  108. package/dist/lib/sandbox/removal.js +1717 -0
  109. package/dist/lib/sandbox/task-cleanup.js +217 -0
  110. package/dist/lib/sandbox/workspace-view.js +15 -15
  111. package/dist/lib/sandbox/worktree-safety.js +4 -1
  112. package/dist/lib/server/index.js +8 -0
  113. package/dist/lib/task/activity-intent.js +2 -1
  114. package/dist/lib/task/activity-log.js +30 -24
  115. package/dist/lib/task/artifact-command.js +101 -0
  116. package/dist/lib/task/artifact-lifecycle.js +71 -40
  117. package/dist/lib/task/artifact-name.js +36 -0
  118. package/dist/lib/task/artifact-operations.js +474 -0
  119. package/dist/lib/task/artifact-receipts.js +3 -15
  120. package/dist/lib/task/artifact-repair-intent.js +130 -0
  121. package/dist/lib/task/artifact-schema.js +127 -0
  122. package/dist/lib/task/capabilities.js +83 -19
  123. package/dist/lib/task/codex-orchestration.js +71 -25
  124. package/dist/lib/task/commit-identity.js +28 -0
  125. package/dist/lib/task/commit-operation.js +2 -16
  126. package/dist/lib/task/control-authority.js +375 -5
  127. package/dist/lib/task/control-recovery.js +128 -0
  128. package/dist/lib/task/create-service.js +103 -4
  129. package/dist/lib/task/create.js +80 -2
  130. package/dist/lib/task/decision-details.js +2 -46
  131. package/dist/lib/task/events.js +306 -76
  132. package/dist/lib/task/finalization-state.js +9 -0
  133. package/dist/lib/task/human-override.js +3 -6
  134. package/dist/lib/task/implementation-inputs.js +3 -3
  135. package/dist/lib/task/index.js +11 -3
  136. package/dist/lib/task/intermediate-cleanup.js +383 -0
  137. package/dist/lib/task/invalidation.js +18 -65
  138. package/dist/lib/task/ledger-intents.js +7 -22
  139. package/dist/lib/task/ledger.js +1 -3
  140. package/dist/lib/task/lifecycle.js +19 -1
  141. package/dist/lib/task/local-artifact-finalization.js +190 -290
  142. package/dist/lib/task/manual-validation-completion.js +26 -0
  143. package/dist/lib/task/manual-validation-evidence.js +130 -0
  144. package/dist/lib/task/manual-validation-receipt.js +101 -0
  145. package/dist/lib/task/manual-validation-shared.js +40 -0
  146. package/dist/lib/task/manual-validation-transaction.js +243 -0
  147. package/dist/lib/task/markdown.js +47 -0
  148. package/dist/lib/task/orchestration.js +206 -69
  149. package/dist/lib/task/qualification-audit.js +476 -0
  150. package/dist/lib/task/qualification-confirmation.js +109 -0
  151. package/dist/lib/task/qualification-intents.js +148 -0
  152. package/dist/lib/task/review-artifacts.js +23 -40
  153. package/dist/lib/task/review-command.js +25 -0
  154. package/dist/lib/task/review-finalization.js +146 -97
  155. package/dist/lib/task/review-fingerprint.js +2 -2
  156. package/dist/lib/task/sections.js +34 -54
  157. package/dist/lib/task/verification-config.js +11 -0
  158. package/dist/lib/task/verification-engine.js +170 -327
  159. package/dist/lib/task/verification.js +1 -1
  160. package/dist/lib/task/workflow-command.js +17 -0
  161. package/dist/lib/task/workflow-warning-intents.js +0 -16
  162. package/dist/lib/task/workflow-warnings.js +28 -2
  163. package/dist/lib/update.js +2 -0
  164. package/dist/lifecycle-build-manifest.json +3 -3
  165. package/lib/agent-client.ts +9 -0
  166. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  167. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  168. package/lib/fs/durable-write.ts +29 -0
  169. package/lib/fs/file-lock.ts +113 -0
  170. package/lib/host-control/audit.ts +22 -0
  171. package/lib/host-control/client.ts +172 -0
  172. package/lib/host-control/command.ts +60 -0
  173. package/lib/host-control/path.ts +167 -0
  174. package/lib/host-control/secure-fs.ts +135 -0
  175. package/lib/host-control/server.ts +180 -0
  176. package/lib/host-control/service.ts +133 -0
  177. package/lib/init.ts +15 -2
  178. package/lib/internal/agent-client.ts +4 -2
  179. package/lib/internal/cli-route-inventory.ts +142 -0
  180. package/lib/internal/codex-lifecycle.ts +14 -12
  181. package/lib/internal/codex-sandbox-controller.ts +7 -2
  182. package/lib/internal/demo-promotion.ts +354 -0
  183. package/lib/internal/demo-transcript.ts +419 -0
  184. package/lib/internal/git-workflow.ts +9 -6
  185. package/lib/internal/host-control.ts +28 -0
  186. package/lib/internal/manual-validation.ts +306 -0
  187. package/lib/internal/platform-checks.ts +12 -4
  188. package/lib/internal/platform-comment.ts +12 -4
  189. package/lib/internal/platform-context.ts +3 -1
  190. package/lib/internal/platform-issue.ts +11 -4
  191. package/lib/internal/platform-metadata.ts +70 -0
  192. package/lib/internal/platform-pr-review.ts +14 -3
  193. package/lib/internal/platform-pr.ts +38 -14
  194. package/lib/internal/platform-release-notes.ts +5 -3
  195. package/lib/internal/platform-security.ts +83 -0
  196. package/lib/internal/pr-review-grade.ts +10 -3
  197. package/lib/internal/release-workflow.ts +91 -87
  198. package/lib/internal/sandbox-control.ts +181 -6
  199. package/lib/internal/task-activity.ts +12 -4
  200. package/lib/internal/task-artifact.ts +15 -79
  201. package/lib/internal/task-context.ts +3 -1
  202. package/lib/internal/task-create.ts +76 -15
  203. package/lib/internal/task-delivery.ts +3 -1
  204. package/lib/internal/task-event.ts +21 -10
  205. package/lib/internal/task-finalization.ts +3 -1
  206. package/lib/internal/task-invalidation.ts +3 -1
  207. package/lib/internal/task-ledger.ts +11 -1
  208. package/lib/internal/task-lifecycle.ts +3 -1
  209. package/lib/internal/task-operation-registry.ts +590 -0
  210. package/lib/internal/task-orchestration.ts +12 -0
  211. package/lib/internal/task-override.ts +9 -3
  212. package/lib/internal/task-qualification.ts +61 -0
  213. package/lib/internal/task-review.ts +7 -50
  214. package/lib/internal/task-short-id.ts +10 -1
  215. package/lib/internal/task-snapshot.ts +3 -1
  216. package/lib/internal/task-validate.ts +32 -12
  217. package/lib/internal/task-verify.ts +4 -1
  218. package/lib/internal/task-warning.ts +7 -1
  219. package/lib/owned-path.ts +26 -0
  220. package/lib/platform/check-status.ts +9 -0
  221. package/lib/platform/comment-safety.ts +255 -0
  222. package/lib/platform/completion-backfill.ts +1 -1
  223. package/lib/platform/github-data.ts +322 -0
  224. package/lib/platform/github-provider.ts +244 -27
  225. package/lib/platform/issue-comments.ts +159 -35
  226. package/lib/platform/issues.ts +4 -245
  227. package/lib/platform/pr-change-report.ts +6 -12
  228. package/lib/platform/pr-checks.ts +13 -77
  229. package/lib/platform/pr-summary.ts +88 -11
  230. package/lib/platform/provider-contract.ts +78 -3
  231. package/lib/platform/provider-validation.ts +85 -3
  232. package/lib/platform/pull-requests.ts +129 -348
  233. package/lib/platform/repository-metadata.ts +453 -0
  234. package/lib/platform/security-alerts.ts +191 -0
  235. package/lib/platform/snapshots.ts +53 -0
  236. package/lib/platform/verification-sync.ts +171 -177
  237. package/lib/process-data/index.ts +7 -0
  238. package/lib/release/workflow.ts +3 -3
  239. package/lib/run/index.ts +5 -0
  240. package/lib/sandbox/commands/control-status.ts +26 -0
  241. package/lib/sandbox/commands/create.ts +53 -12
  242. package/lib/sandbox/commands/ls.ts +7 -0
  243. package/lib/sandbox/commands/rm.ts +3 -996
  244. package/lib/sandbox/commands/show.ts +16 -0
  245. package/lib/sandbox/control/audit.ts +253 -0
  246. package/lib/sandbox/control/client.ts +150 -13
  247. package/lib/sandbox/control/completed-reentry.ts +98 -0
  248. package/lib/sandbox/control/container-identity.ts +27 -43
  249. package/lib/sandbox/control/executor.ts +262 -37
  250. package/lib/sandbox/control/finalization-response.ts +29 -0
  251. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  252. package/lib/sandbox/control/lifecycle.ts +672 -18
  253. package/lib/sandbox/control/native-file-lock.ts +108 -0
  254. package/lib/sandbox/control/protocol.ts +80 -8
  255. package/lib/sandbox/control/server.ts +779 -82
  256. package/lib/sandbox/control/state.ts +84 -3
  257. package/lib/sandbox/control/task-view.ts +240 -0
  258. package/lib/sandbox/control/task-workflow.ts +95 -0
  259. package/lib/sandbox/control/workflow-executor.ts +102 -0
  260. package/lib/sandbox/engines/authority.ts +365 -0
  261. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  262. package/lib/sandbox/index.ts +9 -2
  263. package/lib/sandbox/recovery.ts +49 -6
  264. package/lib/sandbox/removal.ts +2144 -0
  265. package/lib/sandbox/task-cleanup.ts +209 -0
  266. package/lib/sandbox/workspace-view.ts +26 -18
  267. package/lib/sandbox/worktree-safety.ts +4 -1
  268. package/lib/server/index.ts +10 -0
  269. package/lib/task/activity-intent.ts +2 -2
  270. package/lib/task/activity-log.ts +27 -19
  271. package/lib/task/artifact-command.ts +104 -0
  272. package/lib/task/artifact-lifecycle.ts +66 -39
  273. package/lib/task/artifact-name.ts +55 -0
  274. package/lib/task/artifact-operations.ts +580 -0
  275. package/lib/task/artifact-receipts.ts +3 -14
  276. package/lib/task/artifact-repair-intent.ts +152 -0
  277. package/lib/task/artifact-schema.ts +163 -0
  278. package/lib/task/capabilities.ts +82 -22
  279. package/lib/task/codex-orchestration.ts +85 -24
  280. package/lib/task/commit-identity.ts +31 -0
  281. package/lib/task/commit-operation.ts +2 -16
  282. package/lib/task/control-authority.ts +513 -6
  283. package/lib/task/control-recovery.ts +174 -0
  284. package/lib/task/create-service.ts +131 -6
  285. package/lib/task/create.ts +83 -1
  286. package/lib/task/decision-details.ts +3 -71
  287. package/lib/task/events.ts +292 -75
  288. package/lib/task/finalization-state.ts +11 -0
  289. package/lib/task/human-override.ts +3 -8
  290. package/lib/task/implementation-inputs.ts +3 -3
  291. package/lib/task/index.ts +16 -3
  292. package/lib/task/intermediate-cleanup.ts +455 -0
  293. package/lib/task/invalidation.ts +18 -62
  294. package/lib/task/ledger-intents.ts +7 -24
  295. package/lib/task/ledger.ts +1 -3
  296. package/lib/task/lifecycle.ts +17 -1
  297. package/lib/task/local-artifact-finalization.ts +223 -388
  298. package/lib/task/manual-validation-completion.ts +40 -0
  299. package/lib/task/manual-validation-evidence.ts +209 -0
  300. package/lib/task/manual-validation-receipt.ts +152 -0
  301. package/lib/task/manual-validation-shared.ts +50 -0
  302. package/lib/task/manual-validation-transaction.ts +304 -0
  303. package/lib/task/markdown.ts +70 -0
  304. package/lib/task/orchestration.ts +191 -68
  305. package/lib/task/qualification-audit.ts +588 -0
  306. package/lib/task/qualification-confirmation.ts +117 -0
  307. package/lib/task/qualification-intents.ts +150 -0
  308. package/lib/task/review-artifacts.ts +21 -41
  309. package/lib/task/review-command.ts +23 -0
  310. package/lib/task/review-finalization.ts +154 -153
  311. package/lib/task/review-fingerprint.ts +2 -2
  312. package/lib/task/sections.ts +33 -52
  313. package/lib/task/verification-config.ts +12 -0
  314. package/lib/task/verification-engine.ts +165 -370
  315. package/lib/task/verification-types.ts +17 -0
  316. package/lib/task/verification.ts +1 -1
  317. package/lib/task/workflow-command.ts +18 -0
  318. package/lib/task/workflow-warning-intents.ts +0 -13
  319. package/lib/task/workflow-warnings.ts +21 -2
  320. package/lib/update.ts +6 -0
  321. package/package.json +7 -2
  322. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  323. package/templates/.agents/rules/README.en.md +2 -0
  324. package/templates/.agents/rules/README.zh-CN.md +2 -0
  325. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  326. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  327. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  328. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  329. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  330. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  331. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  332. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  333. package/templates/.agents/rules/security-alerts.en.md +8 -8
  334. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  335. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  336. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  337. package/templates/.agents/scripts/package.json +3 -0
  338. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  339. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  340. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  341. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  342. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  343. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  344. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  345. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  346. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  347. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  348. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  349. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  350. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  351. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  352. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  353. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  354. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  355. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  356. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  357. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  358. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
  359. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
  360. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  361. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  362. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
  363. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
  364. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  365. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  366. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
  367. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
  368. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  369. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  370. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  371. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  372. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  373. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  374. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  375. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  376. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  377. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  378. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  379. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  380. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  381. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  382. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  383. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  384. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  385. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  386. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  387. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  388. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  389. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  390. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  391. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  392. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  393. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  394. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  395. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  396. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  397. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  398. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  399. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  400. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  401. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  402. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  403. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  404. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  405. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  406. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
  407. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
  408. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  409. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  410. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
  411. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
  412. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  413. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  414. package/templates/.agents/skills/test/SKILL.en.md +29 -7
  415. package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
  416. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  417. package/templates/.agents/templates/task.en.md +6 -0
  418. package/templates/.agents/templates/task.zh-CN.md +6 -0
  419. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  420. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  421. package/dist/lib/platform/adapters.js +0 -56
  422. package/lib/platform/adapters.ts +0 -197
  423. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  424. package/templates/.agents/scripts/security-alerts.sh +0 -31
  425. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  426. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  427. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  428. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,148 @@
1
+ import fs from 'node:fs';
2
+ import { CONSTRAINT_COLUMNS, CANDIDATE_COLUMNS, parseTaskQualification } from './qualification-audit.js';
3
+ import { resolveTaskRef } from './resolve-ref.js';
4
+ import { captureTaskWriteMetadata, writeTask } from './write.js';
5
+ function failed(code, message, taskId = null) {
6
+ return { status: 'failed', changed: false, taskId, operations: [], error: { code, message } };
7
+ }
8
+ function validSingleLine(value) {
9
+ return typeof value === 'string' && Boolean(value.trim()) && !/[\r\n]/.test(value);
10
+ }
11
+ function assertProposalKeys(value, keys, label) {
12
+ if (!value || typeof value !== 'object' || Array.isArray(value))
13
+ throw new Error(`${label} must be an object`);
14
+ const record = value;
15
+ const unexpected = Object.keys(record).find((key) => !keys.includes(key));
16
+ if (unexpected)
17
+ throw new Error(`${label} does not accept '${unexpected}'`);
18
+ return record;
19
+ }
20
+ function parseConstraintProposal(value) {
21
+ const row = assertProposalKeys(value, ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'derivedFrom', 'approvalEvidence'], 'constraint proposal');
22
+ for (const key of ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'approvalEvidence']) {
23
+ if (typeof row[key] !== 'string' || /[\r\n]/.test(row[key]))
24
+ throw new Error(`constraint proposal '${key}' must be a single-line string`);
25
+ }
26
+ if (!/^C-[1-9]\d*$/.test(row.constraintId))
27
+ throw new Error(`constraint proposal id '${row.constraintId}' is invalid`);
28
+ if (row.status === 'confirmed' || !['derived', 'assumption', 'open', 'conflicted', 'superseded'].includes(row.status))
29
+ throw new Error('proposal cannot write confirmed constraint status');
30
+ if (row.approvalEvidence !== '')
31
+ throw new Error('proposal cannot write approval_evidence');
32
+ if (!Array.isArray(row.derivedFrom) || row.derivedFrom.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item)))
33
+ throw new Error('constraint proposal derivedFrom is invalid');
34
+ return {
35
+ constraintId: row.constraintId, statement: row.statement, status: row.status,
36
+ authority: row.authority, source: row.source, evidence: row.evidence,
37
+ derivedFrom: [...row.derivedFrom], approvalEvidence: ''
38
+ };
39
+ }
40
+ function parseCandidateProposal(value) {
41
+ const row = assertProposalKeys(value, ['candidateId', 'statement', 'status', 'constraintIds', 'impact', 'evidence'], 'candidate proposal');
42
+ for (const key of ['candidateId', 'statement', 'status', 'impact', 'evidence'])
43
+ if (!validSingleLine(row[key]))
44
+ throw new Error(`candidate proposal '${key}' must be a non-empty single-line string`);
45
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(row.candidateId))
46
+ throw new Error(`candidate proposal id '${row.candidateId}' is invalid`);
47
+ if (row.status !== 'pending')
48
+ throw new Error('proposal can only write pending candidate status');
49
+ if (!Array.isArray(row.constraintIds) || row.constraintIds.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item)))
50
+ throw new Error('candidate proposal constraintIds is invalid');
51
+ return row;
52
+ }
53
+ function proposalValues(request) {
54
+ if (!/^[a-f0-9]{64}$/i.test(request.expectedTaskInputDigest))
55
+ throw new Error('expectedTaskInputDigest must be a sha256 digest');
56
+ if (Object.keys(request).some((key) => !['taskRef', 'expectedTaskInputDigest', 'constraints', 'candidates', 'dryRun'].includes(key)))
57
+ throw new Error('proposal contains an unsupported field');
58
+ if (!Array.isArray(request.constraints) && request.constraints !== undefined)
59
+ throw new Error('constraints must be an array');
60
+ if (!Array.isArray(request.candidates) && request.candidates !== undefined)
61
+ throw new Error('candidates must be an array');
62
+ return {
63
+ constraints: (request.constraints ?? []).map(parseConstraintProposal),
64
+ candidates: (request.candidates ?? []).map(parseCandidateProposal)
65
+ };
66
+ }
67
+ function applyQualificationProposal(request, options = {}) {
68
+ if (!request || typeof request !== 'object' || !validSingleLine(request.taskRef))
69
+ return failed('QUALIFICATION_PROPOSAL_INVALID', 'taskRef is required');
70
+ let values;
71
+ try {
72
+ values = proposalValues(request);
73
+ }
74
+ catch (error) {
75
+ return failed('QUALIFICATION_PROPOSAL_INVALID', error instanceof Error ? error.message : String(error));
76
+ }
77
+ if (values.constraints.length === 0 && values.candidates.length === 0)
78
+ return failed('QUALIFICATION_PROPOSAL_INVALID', 'proposal must contain a constraint or candidate');
79
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
80
+ if (!resolved.ok)
81
+ return failed(resolved.code, resolved.message, resolved.taskId);
82
+ if (resolved.state !== 'active')
83
+ return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
84
+ let content;
85
+ try {
86
+ content = fs.readFileSync(resolved.taskMdPath, 'utf8');
87
+ }
88
+ catch (error) {
89
+ return failed('TASK_READ_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
90
+ }
91
+ const parsed = parseTaskQualification(content);
92
+ if (!parsed.ok)
93
+ return failed(parsed.code, parsed.message, resolved.taskId);
94
+ if (!parsed.qualification.present)
95
+ return failed('QUALIFICATION_TASK_CONTRACT_MISSING', 'task qualification contract is missing', resolved.taskId);
96
+ const currentConstraintMap = new Map(parsed.qualification.constraints.map((row) => [row.constraintId, row]));
97
+ const currentCandidateMap = new Map(parsed.qualification.candidates.map((row) => [row.candidateId, row]));
98
+ const proposalAlreadyApplied = values.constraints.every((row) => {
99
+ const current = currentConstraintMap.get(row.constraintId);
100
+ return current && current.statement === row.statement && current.status === row.status && current.authority === row.authority
101
+ && current.source === row.source && current.evidence === row.evidence && current.derivedFrom.join(',') === row.derivedFrom.join(',') && current.approvalEvidence === '';
102
+ }) && values.candidates.every((row) => {
103
+ const current = currentCandidateMap.get(row.candidateId);
104
+ return current && current.statement === row.statement && current.status === row.status && current.constraintIds.join(',') === row.constraintIds.join(',')
105
+ && current.impact === row.impact && current.evidence === row.evidence;
106
+ });
107
+ if (parsed.qualification.taskInputDigest !== request.expectedTaskInputDigest) {
108
+ return proposalAlreadyApplied
109
+ ? { status: 'no-op', changed: false, taskId: resolved.taskId, operations: [], error: null }
110
+ : failed('QUALIFICATION_DIGEST_CONFLICT', 'task qualification input changed before proposal was applied', resolved.taskId);
111
+ }
112
+ for (const row of values.constraints) {
113
+ const current = currentConstraintMap.get(row.constraintId);
114
+ if (current?.status === 'confirmed')
115
+ return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `confirmed constraint '${row.constraintId}' must be superseded or revoked through task-qualification`, resolved.taskId);
116
+ }
117
+ const knownConstraintIds = new Set([...parsed.qualification.constraints.map((row) => row.constraintId), ...values.constraints.map((row) => row.constraintId)]);
118
+ for (const row of values.constraints)
119
+ for (const parent of row.derivedFrom)
120
+ if (!knownConstraintIds.has(parent))
121
+ return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `constraint proposal '${row.constraintId}' references unknown '${parent}'`, resolved.taskId);
122
+ for (const row of values.candidates)
123
+ for (const id of row.constraintIds)
124
+ if (!knownConstraintIds.has(id))
125
+ return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `candidate proposal '${row.candidateId}' references unknown '${id}'`, resolved.taskId);
126
+ const mutations = [];
127
+ for (const row of values.constraints) {
128
+ mutations.push({ kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: CONSTRAINT_COLUMNS, keyColumn: 'constraint_id', key: row.constraintId, values: { statement: row.statement, status: row.status, authority: row.authority, source: row.source, evidence: row.evidence, derived_from: row.derivedFrom.join(','), approval_evidence: '' } });
129
+ }
130
+ for (const row of values.candidates) {
131
+ mutations.push({ kind: 'table-row', action: 'upsert', sectionAliases: ['候选与否决方案', 'Candidate and Rejected Options', 'Candidates and Rejected Options', 'Candidates and Rejected Alternatives'], columns: CANDIDATE_COLUMNS, keyColumn: 'candidate_id', key: row.candidateId, values: { statement: row.statement, status: row.status, constraint_ids: row.constraintIds.join(','), impact: row.impact, evidence: row.evidence } });
132
+ }
133
+ // Only the submitted rows are mutated; no actor, confirmation, or QCR fields
134
+ // can be smuggled into this internal proposal operation.
135
+ let metadata;
136
+ try {
137
+ metadata = (options.metadataProvider ?? captureTaskWriteMetadata)();
138
+ }
139
+ catch (error) {
140
+ return failed('METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
141
+ }
142
+ const result = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state }, metadataProvider: () => metadata });
143
+ if (result.status === 'failed')
144
+ return failed(result.error.code, result.error.message, result.taskId);
145
+ return { status: result.status, changed: result.changed, taskId: result.taskId, operations: result.operations, error: null };
146
+ }
147
+ export { applyQualificationProposal };
148
+ //# sourceMappingURL=qualification-intents.js.map
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { scanVisibleMarkdown } from './markdown.js';
3
4
  const SUMMARY_HEADINGS = new Set(['审查摘要', 'Review Summary']);
4
5
  const PLACEHOLDERS = [
5
6
  '{unresolved-blockers}',
@@ -9,22 +10,6 @@ const PLACEHOLDERS = [
9
10
  function escapeRegExp(value) {
10
11
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
11
12
  }
12
- function maxRound(entries, stem) {
13
- let max = 0;
14
- for (const entry of entries) {
15
- if (entry === `${stem}.md`) {
16
- max = Math.max(max, 1);
17
- continue;
18
- }
19
- const match = entry.match(new RegExp(`^${escapeRegExp(stem)}-r(\\d+)\\.md$`));
20
- if (match)
21
- max = Math.max(max, Number(match[1]));
22
- }
23
- return max;
24
- }
25
- function artifactName(stem, round) {
26
- return round === 1 ? `${stem}.md` : `${stem}-r${round}.md`;
27
- }
28
13
  function normalizeVerdict(raw) {
29
14
  const value = String(raw).trim().toLowerCase();
30
15
  if (value === '通过' || value === 'approved')
@@ -36,42 +21,40 @@ function normalizeVerdict(raw) {
36
21
  return '';
37
22
  }
38
23
  function extractSection(content, names) {
39
- const lines = content.split(/\r?\n/);
40
24
  const nameSet = new Set(names);
41
- const start = lines.findIndex((line) => {
42
- const match = line.trim().match(/^##\s+(.+?)\s*$/);
43
- return match ? nameSet.has(match[1]) : false;
44
- });
45
- if (start === -1)
25
+ const scanned = scanVisibleMarkdown(content);
26
+ const heading = scanned.headings.find((item) => item.level === 2 && nameSet.has(item.text));
27
+ if (!heading)
46
28
  return '';
47
- const sectionLines = [];
48
- for (let index = start + 1; index < lines.length; index += 1) {
49
- if (/^##\s+/.test(lines[index]))
50
- break;
51
- sectionLines.push(lines[index]);
52
- }
53
- return sectionLines.join('\n');
29
+ const next = scanned.headings.find((item) => item.start > heading.start && item.level <= 2);
30
+ return content.slice(heading.end, next?.start ?? content.length);
54
31
  }
55
32
  function summaryBounds(content) {
56
- const headings = [...content.matchAll(/^##\s+(.+?)\s*$/gm)]
57
- .map((match) => ({ index: match.index, end: match.index + match[0].length, name: match[1] }));
58
- const summaries = headings.filter((heading) => SUMMARY_HEADINGS.has(heading.name));
33
+ const scanned = scanVisibleMarkdown(content);
34
+ const summaries = scanned.headings.filter((heading) => heading.level === 2 && SUMMARY_HEADINGS.has(heading.text));
59
35
  if (summaries.length !== 1)
60
36
  return null;
61
37
  const summary = summaries[0];
62
- const next = headings.find((heading) => heading.index > summary.index);
63
- return { start: summary.end, end: next?.index ?? content.length };
38
+ const next = scanned.headings.find((heading) => heading.start > summary.start && heading.level <= 2);
39
+ return { start: summary.end, end: next?.start ?? content.length };
64
40
  }
65
41
  function uniqueLine(content, bounds, pattern) {
66
- const section = content.slice(bounds.start, bounds.end);
67
- const matches = [...section.matchAll(pattern)];
42
+ const matches = [];
43
+ for (const line of scanVisibleMarkdown(content).lines) {
44
+ if (line.start < bounds.start || line.start >= bounds.end)
45
+ continue;
46
+ pattern.lastIndex = 0;
47
+ const match = pattern.exec(line.text);
48
+ if (match)
49
+ matches.push({ value: match[1], index: line.start + match.index, length: match[0].length });
50
+ }
68
51
  if (matches.length !== 1)
69
52
  return null;
70
53
  const match = matches[0];
71
54
  return {
72
- value: match[1],
73
- start: bounds.start + match.index,
74
- end: bounds.start + match.index + match[0].length
55
+ value: match.value,
56
+ start: match.index,
57
+ end: match.index + match.length
75
58
  };
76
59
  }
77
60
  function parseCounts(value) {
@@ -200,5 +183,5 @@ function parseVerdict(reviewPath) {
200
183
  }
201
184
  return resolveCanonicalVerdict(parsed.summary);
202
185
  }
203
- export { artifactName, equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, maxRound, normalizeVerdict, parseReviewSummary, parseVerdict, resolveCanonicalVerdict };
186
+ export { equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, normalizeVerdict, parseReviewSummary, parseVerdict, resolveCanonicalVerdict };
204
187
  //# sourceMappingURL=review-artifacts.js.map
@@ -0,0 +1,25 @@
1
+ export function parseReviewCommand(args) {
2
+ if (!args[0] || args[1] !== 'finalize-summary')
3
+ throw new Error('task ref and finalize-summary are required');
4
+ const values = {};
5
+ const flags = {
6
+ '--stage': 'stage', '--artifact': 'artifact', '--orchestrated': 'orchestrated', '--dry-run': 'dryRun',
7
+ '--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
8
+ };
9
+ for (let index = 2; index < args.length; index += 1) {
10
+ const flag = args[index];
11
+ if (!Object.hasOwn(flags, flag))
12
+ throw new Error(`unknown option '${flag}'`);
13
+ const key = flags[flag];
14
+ if (Object.hasOwn(values, key))
15
+ throw new Error(`duplicate option '${flag}'`);
16
+ const value = flag === '--orchestrated' || flag === '--dry-run' ? true : args[++index];
17
+ if (!value || typeof value === 'string' && value.startsWith('--'))
18
+ throw new Error(`option '${flag}' requires a value`);
19
+ values[key] = value;
20
+ }
21
+ if (!values.stage || !values.artifact)
22
+ throw new Error("options '--stage' and '--artifact' are required");
23
+ return { taskRef: args[0], ...values };
24
+ }
25
+ //# sourceMappingURL=review-command.js.map
@@ -1,8 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { locateActivityLog, pairEntries, startedBackedRows } from './activity-log.js';
5
- import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
4
+ import { parseArtifactName } from './artifact-name.js';
5
+ import { validateCompletedArtifact, hasOpenArtifactRound, validateArtifactPublication } from './artifact-lifecycle.js';
6
6
  import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
7
7
  import { finalizeReviewSummaryContent } from './review-artifacts.js';
8
8
  import { inspectDecisionDetailDuplicates } from './decision-details.js';
@@ -10,10 +10,13 @@ import { resolveTaskRef } from './resolve-ref.js';
10
10
  import { validateLifecycleExecution } from './lifecycle-execution.js';
11
11
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
12
12
  import { allowsManualOverride } from './guard-override.js';
13
+ import { getArtifactSchema } from './artifact-schema.js';
14
+ import { canonicalSemanticDigest, inspectArtifactContract, sha256Content } from './artifact-operations.js';
15
+ import { readArtifactRepairIntent, writeArtifactRepairIntent } from './artifact-repair-intent.js';
13
16
  const STAGES = {
14
- analysis: { family: 'review-analysis', action: 'Review Analysis' },
15
- plan: { family: 'review-plan', action: 'Review Plan' },
16
- code: { family: 'review-code', action: 'Review Code' }
17
+ analysis: { family: 'review-analysis' },
18
+ plan: { family: 'review-plan' },
19
+ code: { family: 'review-code' }
17
20
  };
18
21
  const DEFAULT_FILE_SYSTEM = {
19
22
  readFileSync: (file) => fs.readFileSync(file, 'utf8'),
@@ -22,7 +25,7 @@ const DEFAULT_FILE_SYSTEM = {
22
25
  renameSync: (from, to) => fs.renameSync(from, to),
23
26
  unlinkSync: (file) => fs.unlinkSync(file)
24
27
  };
25
- function failed(request, code, message, taskId = null, stageStatus = null) {
28
+ function failed(request, code, message, taskId = null, stageStatus = null, extra = {}) {
26
29
  return {
27
30
  status: 'failed',
28
31
  changed: false,
@@ -32,17 +35,15 @@ function failed(request, code, message, taskId = null, stageStatus = null) {
32
35
  stage: request.stage,
33
36
  artifact: request.artifact,
34
37
  stageStatus,
38
+ artifactSha256: null,
39
+ semanticDigest: null,
40
+ repairable: false,
41
+ operation: null,
35
42
  operations: [],
36
- error: { code, message }
43
+ error: { code, message },
44
+ ...extra
37
45
  };
38
46
  }
39
- function openReviewRound(content, action, round) {
40
- const section = locateActivityLog(content);
41
- if (!section)
42
- return false;
43
- const expected = `${action} (Round ${round})`;
44
- return startedBackedRows(pairEntries(section.entries)).filter((row) => (row.step === expected && !row.done)).length === 1;
45
- }
46
47
  function cleanupTemp(fileSystem, tempPath) {
47
48
  try {
48
49
  fileSystem.unlinkSync(tempPath);
@@ -51,131 +52,179 @@ function cleanupTemp(fileSystem, tempPath) {
51
52
  // Best-effort cleanup preserves the primary failure.
52
53
  }
53
54
  }
54
- function finalizeReviewSummaryUnlocked(request, options = {}) {
55
+ /** Prepare domain validation, summary bytes and provenance before any publication. */
56
+ function prepareReviewSummaryCandidate(request, artifactContent, options = {}) {
57
+ let taskId = null;
58
+ let stageStatus = null;
59
+ const reject = (code, message, extra = {}) => ({
60
+ result: failed(request, code, message, taskId, stageStatus, extra), content: artifactContent
61
+ });
55
62
  const stage = request.stage;
56
63
  const spec = STAGES[stage];
57
64
  if (!spec)
58
- return failed(request, 'REVIEW_STAGE_INVALID', `unsupported review stage '${request.stage}'`);
59
- if (!request.taskRef || !request.artifact) {
60
- return failed(request, 'REVIEW_PAYLOAD_INVALID', 'taskRef, stage, and artifact are required');
61
- }
65
+ return reject('REVIEW_STAGE_INVALID', `unsupported review stage '${request.stage}'`);
66
+ if (!request.taskRef || !request.artifact)
67
+ return reject('REVIEW_PAYLOAD_INVALID', 'taskRef, stage, and artifact are required');
62
68
  const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
69
+ taskId = resolved.taskId ?? null;
63
70
  if (!resolved.ok)
64
- return failed(request, resolved.code, resolved.message, resolved.taskId);
71
+ return reject(resolved.code, resolved.message);
65
72
  if (resolved.state !== 'active' && !allowsManualOverride(options.manualOverride, 'review-finalization', 'TASK_STATE_MISMATCH')) {
66
- return failed(request, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
67
- }
68
- const parsedArtifact = parseArtifactName(request.artifact);
69
- if (!parsedArtifact || parsedArtifact.family !== spec.family) {
70
- return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${spec.family}`, resolved.taskId);
73
+ return reject('TASK_STATE_MISMATCH', `task ${taskId} is ${resolved.state}, expected active`);
74
+ }
75
+ const parsed = parseArtifactName(request.artifact);
76
+ if (!parsed || parsed.family !== spec.family)
77
+ return reject('REVIEW_ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${spec.family}`);
78
+ const publicationError = validateArtifactPublication(resolved.taskDir, spec.family, request.artifact);
79
+ if (publicationError)
80
+ return reject('REVIEW_ARTIFACT_IDENTITY_INVALID', publicationError.message);
81
+ let taskContent;
82
+ try {
83
+ taskContent = (options.fileSystem?.readFileSync ?? DEFAULT_FILE_SYSTEM.readFileSync)(resolved.taskMdPath);
71
84
  }
72
- const validated = validateCompletedArtifact(resolved.taskDir, spec.family, request.artifact, parsedArtifact.round);
73
- if (!validated.ok) {
74
- const code = validated.error.code === 'ARTIFACT_NOT_REGULAR'
75
- ? 'REVIEW_ARTIFACT_NOT_REGULAR'
76
- : 'REVIEW_ARTIFACT_IDENTITY_INVALID';
77
- return failed(request, code, validated.error.message, resolved.taskId);
85
+ catch (error) {
86
+ return reject('REVIEW_ARTIFACT_NOT_REGULAR', String(error));
78
87
  }
79
- const fileSystem = { ...DEFAULT_FILE_SYSTEM, ...options.fileSystem };
80
- let taskContent;
81
- let artifactContent;
88
+ const artifactSha256 = sha256Content(artifactContent);
89
+ const semanticDigest = canonicalSemanticDigest(artifactContent);
90
+ const digests = { artifactSha256, semanticDigest };
91
+ let repairIntent;
82
92
  try {
83
- taskContent = fileSystem.readFileSync(resolved.taskMdPath);
84
- artifactContent = fileSystem.readFileSync(validated.artifact.path);
93
+ repairIntent = readArtifactRepairIntent(resolved.repoRoot, taskId, spec.family, request.artifact);
85
94
  }
86
95
  catch (error) {
87
- return failed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId);
96
+ return reject('REVIEW_PROVENANCE_INVALID', String(error), digests);
97
+ }
98
+ const schema = getArtifactSchema(spec.family);
99
+ const structure = inspectArtifactContract(artifactContent, schema);
100
+ if (!structure.ok) {
101
+ const repairable = structure.repair !== null && structure.diagnostics.length === 1 && structure.diagnostics[0]?.repairable === true;
102
+ if (repairable && repairIntent && (repairIntent.state !== 'awaiting-repair'
103
+ || repairIntent.artifactSha256 !== artifactSha256 || repairIntent.semanticDigest !== structure.semanticDigest)) {
104
+ return reject('REVIEW_PROVENANCE_INVALID', 'a different review repair baseline is already recorded for this artifact', digests);
105
+ }
106
+ return {
107
+ ...reject('REVIEW_ARTIFACT_STRUCTURE_INVALID', structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; '), {
108
+ artifactSha256, semanticDigest: structure.semanticDigest, repairable, operation: structure.repair
109
+ }),
110
+ ...(repairable && !repairIntent ? { provenance: {
111
+ version: 2, taskId: taskId, family: spec.family, artifact: request.artifact,
112
+ state: 'awaiting-repair', baselineSemanticDigest: structure.semanticDigest,
113
+ artifactSha256, semanticDigest: structure.semanticDigest,
114
+ recoveryOperationId: null, phase: null, authorityDigest: null,
115
+ requestId: `review-finalize:${taskId}`, createdAt: Date.now(), updatedAt: Date.now()
116
+ }, expectedIntent: null } : {})
117
+ };
118
+ }
119
+ if (repairIntent?.state === 'awaiting-repair' && repairIntent.baselineSemanticDigest !== semanticDigest) {
120
+ return reject('REVIEW_PROVENANCE_INVALID', 'the repaired review artifact semantic digest does not match the recorded repair baseline', digests);
121
+ }
122
+ if ((repairIntent?.state === 'passed' || repairIntent?.state === 'consumed')
123
+ && (repairIntent.artifactSha256 !== artifactSha256 || repairIntent.semanticDigest !== semanticDigest)) {
124
+ return reject('REVIEW_PROVENANCE_INVALID', 'the review artifact changed after its finalization provenance was recorded', digests);
88
125
  }
89
- if (!openReviewRound(taskContent, spec.action, parsedArtifact.round)) {
90
- return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`, resolved.taskId);
126
+ if (!hasOpenArtifactRound(taskContent, spec.family, parsed.round)) {
127
+ return reject('REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`);
91
128
  }
92
129
  const execution = validateLifecycleExecution(request.taskRef, {
93
130
  mode: request.orchestrated ? 'orchestrated' : 'standalone',
94
- identity: {
95
- stage: spec.family,
96
- round: parsedArtifact.round,
97
- artifact: request.artifact,
98
- role: 'reviewer'
99
- },
131
+ identity: { stage: spec.family, round: parsed.round, artifact: request.artifact, role: 'reviewer' },
100
132
  dryRun: request.dryRun
101
133
  }, { repoRoot: options.repoRoot });
102
134
  if (!execution.ok) {
103
- return failed(request, 'REVIEW_PROVENANCE_INVALID', `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`, resolved.taskId);
135
+ return reject('REVIEW_PROVENANCE_INVALID', `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`);
104
136
  }
105
- let rows;
106
137
  try {
107
138
  const ledger = parseLedgerDocument(taskContent);
108
- if (!ledger.present) {
109
- return failed(request, 'REVIEW_LEDGER_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`, resolved.taskId);
110
- }
111
- rows = ledger.rows;
139
+ if (!ledger.present)
140
+ return reject('REVIEW_LEDGER_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
141
+ const error = validateLedgerRows(ledger.rows);
142
+ if (error)
143
+ return reject('REVIEW_LEDGER_INVALID', `${error.code}: ${error.message}`);
144
+ stageStatus = summarizeLedgerStage(ledger.rows, stage);
112
145
  }
113
146
  catch (error) {
114
- return failed(request, 'REVIEW_LEDGER_INVALID', String(error), resolved.taskId);
147
+ return reject('REVIEW_LEDGER_INVALID', String(error));
115
148
  }
116
- const ledgerError = validateLedgerRows(rows);
117
- if (ledgerError) {
118
- return failed(request, 'REVIEW_LEDGER_INVALID', `${ledgerError.code}: ${ledgerError.message}`, resolved.taskId);
149
+ const detail = inspectDecisionDetailDuplicates(artifactContent);
150
+ if (!detail.ok)
151
+ return reject('REVIEW_DECISION_DETAIL_INVALID', `${detail.code}: ${detail.message}`);
152
+ const transformed = finalizeReviewSummaryContent(artifactContent, stageStatus.unresolvedFindingCounts);
153
+ if (!transformed.ok)
154
+ return reject(transformed.code, transformed.message);
155
+ const finalDigests = { artifactSha256: sha256Content(transformed.content), semanticDigest: canonicalSemanticDigest(transformed.content) };
156
+ return {
157
+ content: transformed.content,
158
+ result: {
159
+ ...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', taskId, stageStatus, finalDigests),
160
+ status: transformed.changed ? request.dryRun ? 'planned' : 'applied' : 'no-op',
161
+ changed: transformed.changed,
162
+ operations: transformed.changed ? [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }] : [],
163
+ error: null
164
+ },
165
+ ...(repairIntent?.state === 'awaiting-repair' ? {
166
+ provenance: { ...repairIntent, state: 'passed', ...finalDigests },
167
+ expectedIntent: repairIntent
168
+ } : {})
169
+ };
170
+ }
171
+ function commitReviewSummaryProvenance(prepared, repoRoot) {
172
+ try {
173
+ if (prepared.provenance) {
174
+ writeArtifactRepairIntent(repoRoot, prepared.provenance, { expected: prepared.expectedIntent ?? null });
175
+ }
176
+ return prepared.result;
119
177
  }
120
- const stageStatus = summarizeLedgerStage(rows, stage);
121
- const detailInspection = inspectDecisionDetailDuplicates(artifactContent);
122
- if (!detailInspection.ok) {
123
- return failed(request, 'REVIEW_DECISION_DETAIL_INVALID', `${detailInspection.code}: ${detailInspection.message}`, resolved.taskId, stageStatus);
178
+ catch (error) {
179
+ return { ...prepared.result, status: 'failed', error: {
180
+ code: 'REVIEW_PROVENANCE_INVALID', message: `cannot record review provenance: ${String(error)}`
181
+ } };
124
182
  }
125
- const transformed = finalizeReviewSummaryContent(artifactContent, stageStatus.unresolvedFindingCounts);
126
- if (!transformed.ok) {
127
- return failed(request, transformed.code, transformed.message, resolved.taskId, stageStatus);
183
+ }
184
+ function finalizeReviewSummaryUnlocked(request, options = {}) {
185
+ const spec = STAGES[request.stage];
186
+ if (!spec || !request.taskRef || !request.artifact)
187
+ return prepareReviewSummaryCandidate(request, '', options).result;
188
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
189
+ if (!resolved.ok)
190
+ return failed(request, resolved.code, resolved.message, resolved.taskId);
191
+ const validated = validateCompletedArtifact(resolved.taskDir, spec.family, request.artifact);
192
+ if (!validated.ok) {
193
+ return failed(request, validated.error.code === 'ARTIFACT_NOT_REGULAR' ? 'REVIEW_ARTIFACT_NOT_REGULAR' : 'REVIEW_ARTIFACT_IDENTITY_INVALID', validated.error.message, resolved.taskId);
128
194
  }
129
- if (!transformed.changed) {
130
- return {
131
- ...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
132
- status: 'no-op',
133
- error: null
134
- };
195
+ const fileSystem = { ...DEFAULT_FILE_SYSTEM, ...options.fileSystem };
196
+ let content;
197
+ try {
198
+ content = fileSystem.readFileSync(validated.artifact.path);
135
199
  }
136
- const operations = [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }];
137
- if (request.dryRun) {
138
- return {
139
- ...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
140
- status: 'planned',
141
- changed: true,
142
- operations,
143
- error: null
144
- };
200
+ catch (error) {
201
+ return failed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId);
145
202
  }
203
+ const prepared = prepareReviewSummaryCandidate(request, content, options);
204
+ if (request.dryRun)
205
+ return prepared.result;
206
+ if (prepared.result.status !== 'applied')
207
+ return commitReviewSummaryProvenance(prepared, resolved.repoRoot);
146
208
  const tempPath = path.join(resolved.taskDir, `.${request.artifact}.tmp-${process.pid}-${(options.randomSuffix ?? randomUUID)()}`);
147
- let mode;
148
209
  try {
149
- mode = fileSystem.statModeSync(validated.artifact.path);
150
- fileSystem.writeFileSync(tempPath, transformed.content, mode);
210
+ fileSystem.writeFileSync(tempPath, prepared.content, fileSystem.statModeSync(validated.artifact.path));
151
211
  }
152
212
  catch (error) {
153
213
  cleanupTemp(fileSystem, tempPath);
154
- return failed(request, 'REVIEW_TEMP_WRITE_FAILED', String(error), resolved.taskId, stageStatus);
214
+ return failed(request, 'REVIEW_TEMP_WRITE_FAILED', String(error), resolved.taskId, prepared.result.stageStatus);
155
215
  }
156
216
  try {
157
- if (fileSystem.readFileSync(validated.artifact.path) !== artifactContent) {
217
+ if (fileSystem.readFileSync(validated.artifact.path) !== content) {
158
218
  cleanupTemp(fileSystem, tempPath);
159
- return failed(request, 'REVIEW_ARTIFACT_CONFLICT', `${request.artifact} changed during finalization`, resolved.taskId, stageStatus);
219
+ return failed(request, 'REVIEW_ARTIFACT_CONFLICT', `${request.artifact} changed during finalization`, resolved.taskId, prepared.result.stageStatus);
160
220
  }
161
221
  fileSystem.renameSync(tempPath, validated.artifact.path);
162
222
  }
163
223
  catch (error) {
164
224
  cleanupTemp(fileSystem, tempPath);
165
- return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, stageStatus);
225
+ return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, prepared.result.stageStatus);
166
226
  }
167
- return {
168
- status: 'applied',
169
- changed: true,
170
- intent: 'finalize-summary',
171
- requestRef: request.taskRef,
172
- taskId: resolved.taskId,
173
- stage,
174
- artifact: request.artifact,
175
- stageStatus,
176
- operations,
177
- error: null
178
- };
227
+ return commitReviewSummaryProvenance(prepared, resolved.repoRoot);
179
228
  }
180
229
  function finalizeReviewSummary(request, options = {}) {
181
230
  if (request.dryRun || options.lockAlreadyHeld)
@@ -192,5 +241,5 @@ function finalizeReviewSummary(request, options = {}) {
192
241
  return failed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
193
242
  }
194
243
  }
195
- export { finalizeReviewSummary };
244
+ export { finalizeReviewSummary, prepareReviewSummaryCandidate, commitReviewSummaryProvenance };
196
245
  //# sourceMappingURL=review-finalization.js.map
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { artifactName, maxRound } from "./review-artifacts.js";
3
+ import { artifactName, maxArtifactRound } from "./artifact-name.js";
4
4
  import { invalidationBlocks, isArtifactInvalidated, parseInvalidationDocument } from "./invalidation.js";
5
5
  const REVIEWED_TREE_RE = /^[a-f0-9]{40,64}$/;
6
6
  export function parseReviewedGitTree(value) {
@@ -29,7 +29,7 @@ export function resolvePostReviewGlobs(config = {}, reviewConfig = {}) {
29
29
  }
30
30
  export function findAuthoritativeReviewCodeArtifact(taskDir) {
31
31
  const entries = fs.existsSync(taskDir) ? fs.readdirSync(taskDir) : [];
32
- const round = maxRound(entries, "review-code");
32
+ const round = maxArtifactRound(entries, "review-code");
33
33
  if (round === 0) {
34
34
  return { ok: false, round: 0, fileName: null, path: null, error: null };
35
35
  }