@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
@@ -1,37 +1,34 @@
1
1
  import fs from 'node:fs';
2
- import { createHash } from 'node:crypto';
3
- import path from 'node:path';
4
2
 
3
+ import { inspectDecisionDetailDuplicates } from './decision-details.ts';
4
+ import { scanVisibleMarkdown } from './markdown.ts';
5
+ import { parseArtifactName } from './artifact-name.ts';
5
6
  import {
6
- inspectDecisionDetailDuplicates,
7
- scanVisibleMarkdown
8
- } from './decision-details.ts';
9
- import type { VisibleHeading } from './decision-details.ts';
10
- import {
11
- parseArtifactName,
7
+ hasOpenArtifactRound,
8
+ validateArtifactPublication,
12
9
  validateCompletedArtifact
13
10
  } from './artifact-lifecycle.ts';
14
11
  import { resolveTaskRef } from './resolve-ref.ts';
12
+ import { expectedQualificationRelations, validateQualificationAudit } from './qualification-audit.ts';
13
+ import { canonicalSemanticDigest, inspectArtifactPatterns, inspectArtifactStructure, sha256Content } from './artifact-operations.ts';
14
+ import { getArtifactSchema } from './artifact-schema.ts';
15
+ import { readArtifactRepairIntent, writeArtifactRepairIntent } from './artifact-repair-intent.ts';
16
+ import type { ArtifactRepairIntent } from './artifact-repair-intent.ts';
17
+ import {
18
+ consumeLifecycleRecoveryAttestation,
19
+ lifecycleRecoveryAttestationDigest,
20
+ validateLifecycleRecoveryAttestation
21
+ } from './control-authority.ts';
22
+ import type { LifecycleRecoveryAttestationV1 } from './control-authority.ts';
15
23
 
16
24
  type LocalArtifactFamily = 'analysis' | 'plan' | 'code';
17
25
 
18
26
  const LOCAL_ARTIFACT_REQUIRED_SECTIONS: Readonly<Record<LocalArtifactFamily, readonly string[]>> = {
19
- analysis: [
20
- '需求来源', '需求理解', '相关文件', '影响评估', '技术风险',
21
- '工作量和复杂度评估', '状态核对'
22
- ],
23
- plan: [
24
- '问题理解', '约束条件', '方案对比', '技术方法', '实施步骤',
25
- '文件清单', '验证策略', '状态核对'
26
- ],
27
- code: [
28
- '实现输入', '变更文件', '关键代码说明', '测试结果', '与方案的差异',
29
- '供审查关注的内容', '状态核对', '证据原文'
30
- ]
27
+ analysis: getArtifactSchema('analysis')!.sections.map((section) => section.headings.zh),
28
+ plan: getArtifactSchema('plan')!.sections.map((section) => section.headings.zh),
29
+ code: getArtifactSchema('code')!.sections.map((section) => section.headings.zh)
31
30
  };
32
31
 
33
- const LOCAL_ARTIFACT_REQUIRED_PATTERNS = ['^\\$ '];
34
-
35
32
  type LocalArtifactDiagnosticCode =
36
33
  | 'LOCAL_ARTIFACT_EMPTY'
37
34
  | 'LOCAL_ARTIFACT_MISSING_SECTION'
@@ -39,9 +36,11 @@ type LocalArtifactDiagnosticCode =
39
36
  | 'LOCAL_STATUS_COMMAND_MISSING'
40
37
  | 'LOCAL_DECISION_DETAIL_DUPLICATE'
41
38
  | 'LOCAL_REQUIRED_PATTERN_MISSING'
39
+ | 'LOCAL_STRUCTURAL_INVALID'
42
40
  | 'LOCAL_SECTION_HEADING_TRAILING_PUNCTUATION'
43
41
  | 'LOCAL_REPAIR_PROVENANCE_CONFLICT'
44
- | 'LOCAL_REPAIR_BASELINE_MISMATCH';
42
+ | 'LOCAL_REPAIR_BASELINE_MISMATCH'
43
+ | 'LOCAL_QUALIFICATION_AUDIT_INVALID';
45
44
 
46
45
  type LocalArtifactDiagnostic = {
47
46
  code: LocalArtifactDiagnosticCode;
@@ -56,7 +55,8 @@ type LocalArtifactDiagnostic = {
56
55
  type LocalArtifactValidationOptions = {
57
56
  family: LocalArtifactFamily;
58
57
  requiredSections?: readonly string[];
59
- requiredPatterns?: readonly string[];
58
+ taskContent?: string;
59
+ artifact?: string;
60
60
  };
61
61
 
62
62
  type LocalArtifactValidationResult = {
@@ -73,7 +73,6 @@ type LocalArtifactFinalizationRequest = {
73
73
  artifact: string;
74
74
  repoRoot?: string;
75
75
  requiredSections?: readonly string[];
76
- requiredPatterns?: readonly string[];
77
76
  };
78
77
 
79
78
  type LocalArtifactFinalizationResult = {
@@ -90,66 +89,28 @@ type LocalArtifactFinalizationResult = {
90
89
  error: { code: string; message: string } | null;
91
90
  };
92
91
 
93
- type LocalArtifactFinalizationIntent = Readonly<{
94
- version: 1;
95
- taskId: string;
96
- family: LocalArtifactFamily;
97
- artifact: string;
98
- state: 'awaiting-repair' | 'passed' | 'consumed';
99
- baselineSemanticDigest: string | null;
100
- artifactSha256: string;
101
- semanticDigest: string;
102
- }>;
103
-
104
- function finalizationIntentRoot(repoRoot: string): string {
105
- return path.join(repoRoot, '.agents', 'workspace', '.local-artifact-finalization-intents');
106
- }
107
-
108
- function finalizationIntentPath(repoRoot: string, taskId: string, family: LocalArtifactFamily, artifact: string): string {
109
- return path.join(finalizationIntentRoot(repoRoot), `${taskId}-${family}-${artifact}.json`);
110
- }
111
-
112
- function isFinalizationIntent(value: unknown): value is LocalArtifactFinalizationIntent {
113
- if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
114
- const intent = value as Record<string, unknown>;
115
- return intent.version === 1
116
- && typeof intent.taskId === 'string' && intent.taskId.length > 0
117
- && (intent.family === 'analysis' || intent.family === 'plan' || intent.family === 'code')
118
- && typeof intent.artifact === 'string' && intent.artifact.length > 0
119
- && (intent.state === 'awaiting-repair' || intent.state === 'passed' || intent.state === 'consumed')
120
- && (intent.baselineSemanticDigest === null || (typeof intent.baselineSemanticDigest === 'string' && /^[a-f0-9]{64}$/.test(intent.baselineSemanticDigest)))
121
- && typeof intent.artifactSha256 === 'string' && /^[a-f0-9]{64}$/.test(intent.artifactSha256)
122
- && typeof intent.semanticDigest === 'string' && /^[a-f0-9]{64}$/.test(intent.semanticDigest)
123
- && (intent.state === 'awaiting-repair' ? intent.baselineSemanticDigest === intent.semanticDigest : true);
124
- }
92
+ type LocalArtifactFinalizationIntent = ArtifactRepairIntent;
125
93
 
126
- function readLocalArtifactFinalizationIntent(
127
- repoRoot: string,
128
- taskId: string,
129
- family: LocalArtifactFamily,
130
- artifact: string
131
- ): LocalArtifactFinalizationIntent | null {
132
- const target = finalizationIntentPath(repoRoot, taskId, family, artifact);
133
- if (!fs.existsSync(target)) return null;
134
- const value = JSON.parse(fs.readFileSync(target, 'utf8')) as unknown;
135
- if (!isFinalizationIntent(value) || value.taskId !== taskId || value.family !== family || value.artifact !== artifact) {
136
- throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: finalization provenance schema is invalid');
137
- }
138
- return value;
94
+ function authorityDigest(authority: LifecycleRecoveryAttestationV1): string {
95
+ return lifecycleRecoveryAttestationDigest(authority);
139
96
  }
140
97
 
141
- function writeLocalArtifactFinalizationIntent(repoRoot: string, value: LocalArtifactFinalizationIntent): void {
142
- if (!isFinalizationIntent(value)) throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: finalization provenance schema is invalid');
143
- const directory = finalizationIntentRoot(repoRoot);
144
- fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
145
- const target = finalizationIntentPath(repoRoot, value.taskId, value.family, value.artifact);
146
- const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
147
- fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
148
- try { fs.renameSync(temporary, target); }
149
- catch (error) {
150
- try { fs.unlinkSync(temporary); } catch { /* preserve primary error */ }
151
- throw error;
152
- }
98
+ function validFinalizerAuthority(
99
+ authority: LifecycleRecoveryAttestationV1 | undefined,
100
+ request: LocalArtifactFinalizationRequest,
101
+ taskId: string
102
+ ): boolean {
103
+ if (!authority) return false;
104
+ try { validateLifecycleRecoveryAttestation(authority); }
105
+ catch { return false; }
106
+ return authority.version === 1
107
+ && authority.phase === 'artifact.finalize-local'
108
+ && authority.taskId === taskId
109
+ && authority.family === request.family
110
+ && authority.artifact === request.artifact
111
+ && authority.round === (parseArtifactName(request.artifact)?.round ?? 0)
112
+ && authority.requestId.length > 0
113
+ && authority.operationId.length > 0;
153
114
  }
154
115
 
155
116
  function consumeLocalArtifactFinalizationIntent(
@@ -158,68 +119,34 @@ function consumeLocalArtifactFinalizationIntent(
158
119
  ): LocalArtifactFinalizationIntent {
159
120
  if (intent.state === 'consumed') return intent;
160
121
  if (intent.state !== 'passed') throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: only passed provenance can be consumed');
161
- const consumed = { ...intent, state: 'consumed' as const };
162
- writeLocalArtifactFinalizationIntent(repoRoot, consumed);
122
+ const consumed = { ...intent, state: 'consumed' as const, updatedAt: Date.now() };
123
+ writeArtifactRepairIntent(repoRoot, consumed, { expected: intent });
163
124
  return consumed;
164
125
  }
165
126
 
166
- function requiredSections(family: LocalArtifactFamily): readonly string[] {
167
- return LOCAL_ARTIFACT_REQUIRED_SECTIONS[family];
168
- }
169
-
170
- function lineNumber(content: string, offset: number): number {
171
- return content.slice(0, offset).split('\n').length;
172
- }
173
-
174
- function sectionBody(content: string, heading: VisibleHeading): string {
175
- const next = scanVisibleMarkdown(content).headings.find((candidate) => (
176
- candidate.start > heading.start && candidate.level <= 2
177
- ));
178
- return content.slice(heading.end, next?.start ?? content.length);
179
- }
180
-
181
- function semanticDigest(content: string, candidate?: VisibleHeading): string {
182
- let normalized = content;
183
- if (candidate) {
184
- const raw = content.slice(candidate.start, candidate.end);
185
- const marker = raw.match(/([::])\s*$/);
186
- if (marker?.index !== undefined) {
187
- const canonical = raw.slice(0, marker.index) + raw.slice(marker.index + 1);
188
- normalized = `${content.slice(0, candidate.start)}${canonical}${content.slice(candidate.end)}`;
189
- }
190
- }
191
- return createHash('sha256').update(normalized, 'utf8').digest('hex');
192
- }
193
-
194
- function sha256Content(content: string): string {
195
- return createHash('sha256').update(content, 'utf8').digest('hex');
196
- }
197
-
198
- function visibleSectionHeadings(content: string, section: string): VisibleHeading[] {
199
- return scanVisibleMarkdown(content).headings.filter((heading) => (
200
- heading.level === 2 && heading.text === section
201
- ));
202
- }
203
-
204
- function trailingPunctuationCandidates(content: string, section: string): VisibleHeading[] {
205
- return scanVisibleMarkdown(content).headings.filter((heading) => (
206
- heading.level === 2 && (
207
- heading.text === `${section}:` || heading.text === `${section}:`
208
- )
209
- ));
127
+ function localDiagnosticCode(code: string): LocalArtifactDiagnosticCode | null {
128
+ const map: Record<string, LocalArtifactDiagnosticCode> = {
129
+ ARTIFACT_EMPTY: 'LOCAL_ARTIFACT_EMPTY',
130
+ ARTIFACT_MISSING_SECTION: 'LOCAL_ARTIFACT_MISSING_SECTION',
131
+ ARTIFACT_DUPLICATE_SECTION: 'LOCAL_ARTIFACT_DUPLICATE_SECTION',
132
+ ARTIFACT_HEADING_TRAILING_PUNCTUATION: 'LOCAL_SECTION_HEADING_TRAILING_PUNCTUATION'
133
+ };
134
+ return map[code] ?? 'LOCAL_STRUCTURAL_INVALID';
210
135
  }
211
136
 
212
- function diagnostic(
213
- code: LocalArtifactDiagnosticCode,
214
- message: string,
215
- content: string,
216
- heading?: VisibleHeading,
217
- extra: Partial<LocalArtifactDiagnostic> = {}
218
- ): LocalArtifactDiagnostic {
137
+ function localDiagnostic(
138
+ item: { code: string; message: string; line: number | null; repairable: boolean; operation?: { kind: string; from: string; to: string } }
139
+ ): LocalArtifactDiagnostic | null {
140
+ const code = localDiagnosticCode(item.code);
141
+ if (!code) return null;
219
142
  return {
220
- code, message, repairable: false,
221
- line: heading ? lineNumber(content, heading.start) : null,
222
- ...extra
143
+ code,
144
+ message: item.message,
145
+ repairable: item.repairable,
146
+ line: item.line,
147
+ ...(item.operation?.kind === 'replace-line'
148
+ ? { from: item.operation.from, to: item.operation.to, operation: 'replace-line' as const }
149
+ : {})
223
150
  };
224
151
  }
225
152
 
@@ -231,117 +158,70 @@ function validateLocalArtifact(
231
158
  content: string,
232
159
  options: LocalArtifactValidationOptions
233
160
  ): LocalArtifactValidationResult {
234
- const sections = options.requiredSections ?? requiredSections(options.family);
235
- const patterns = options.requiredPatterns ?? LOCAL_ARTIFACT_REQUIRED_PATTERNS;
161
+ const schema = getArtifactSchema(options.family)!;
162
+ const patterns = schema.requiredPatterns;
236
163
  const diagnostics: LocalArtifactDiagnostic[] = [];
237
- const candidates: VisibleHeading[] = [];
238
164
  const scanned = scanVisibleMarkdown(content);
239
-
240
- if (!content.trim()) {
241
- diagnostics.push(diagnostic('LOCAL_ARTIFACT_EMPTY', 'artifact is empty', content));
165
+ const structure = inspectArtifactStructure(content, schema);
166
+ for (const item of structure.diagnostics) {
167
+ const mapped = localDiagnostic(item);
168
+ if (mapped) diagnostics.push(mapped);
242
169
  }
243
170
 
244
- for (const section of sections) {
245
- const exact = scanned.headings.filter((heading) => heading.level === 2 && heading.text === section);
246
- const punctuated = trailingPunctuationCandidates(content, section);
247
- if (exact.length > 1 || punctuated.length > 0 && exact.length > 0 || punctuated.length > 1) {
248
- const first = exact[1] ?? punctuated[0] ?? exact[0];
249
- diagnostics.push(diagnostic(
250
- 'LOCAL_ARTIFACT_DUPLICATE_SECTION',
251
- `required section '${section}' is duplicated or has an ambiguous punctuation variant`,
252
- content, first
253
- ));
254
- } else if (exact.length === 0 && punctuated.length === 1) {
255
- candidates.push(punctuated[0]!);
256
- } else if (exact.length === 0) {
257
- diagnostics.push(diagnostic(
258
- 'LOCAL_ARTIFACT_MISSING_SECTION',
259
- `required section '${section}' is missing`,
260
- content
261
- ));
262
- }
263
- }
264
-
265
- const statusSection = sections.find((section) => section === '状态核对' || section.toLowerCase() === 'state check');
171
+ const statusSection = schema.sections.find((section) => section.id === 'state-check');
266
172
  if (statusSection) {
267
- const statusHeading = visibleSectionHeadings(content, statusSection)[0]
268
- ?? candidates.find((heading) => heading.text === `${statusSection}:` || heading.text === `${statusSection}:`);
173
+ const statusHeading = scanned.headings.find((heading) => (
174
+ heading.level === 2 && [statusSection.headings.zh, statusSection.headings.en].some((name) => (
175
+ heading.text === name || heading.text === `${name}:` || heading.text === `${name}:`
176
+ ))
177
+ ));
269
178
  if (statusHeading) {
270
- const body = sectionBody(content, statusHeading);
179
+ const next = scanned.headings.find((candidate) => candidate.start > statusHeading.start && candidate.level <= 2);
180
+ const body = content.slice(statusHeading.end, next?.start ?? content.length);
271
181
  for (const pattern of patterns.filter(isStatusPattern)) {
272
182
  if (!new RegExp(pattern, 'm').test(body)) {
273
- diagnostics.push(diagnostic(
274
- 'LOCAL_STATUS_COMMAND_MISSING',
275
- `status section '${statusSection}' is missing required command output`,
276
- content, statusHeading
277
- ));
183
+ diagnostics.push({ code: 'LOCAL_STATUS_COMMAND_MISSING', message: `status section '${statusHeading.text}' is missing required command output`, repairable: false, line: content.slice(0, statusHeading.start).split('\n').length });
278
184
  }
279
185
  }
280
186
  }
281
187
  }
282
188
 
283
- for (const pattern of patterns.filter((item) => !isStatusPattern(item))) {
284
- if (!new RegExp(pattern, 'm').test(content)) {
285
- diagnostics.push(diagnostic(
286
- 'LOCAL_REQUIRED_PATTERN_MISSING',
287
- `artifact is missing required pattern '${pattern}'`,
288
- content
289
- ));
290
- }
189
+ const patternInspection = inspectArtifactPatterns(content, {
190
+ ...schema,
191
+ requiredPatterns: patterns.filter((item) => !isStatusPattern(item))
192
+ });
193
+ for (const item of patternInspection.diagnostics) {
194
+ diagnostics.push({ code: 'LOCAL_REQUIRED_PATTERN_MISSING', message: item.message, repairable: false, line: null });
291
195
  }
292
196
 
293
197
  const decisionDetails = inspectDecisionDetailDuplicates(content);
294
198
  if (!decisionDetails.ok) {
295
- diagnostics.push(diagnostic(
296
- 'LOCAL_DECISION_DETAIL_DUPLICATE',
297
- decisionDetails.message,
298
- content,
299
- decisionDetails.duplicates[0]?.blocks[0]
300
- ? scanned.headings.find((heading) => heading.start === decisionDetails.duplicates[0]!.blocks[0]!.start)
301
- : undefined
302
- ));
303
- }
304
-
305
- if (candidates.length === 1 && diagnostics.length === 0) {
306
- const candidate = candidates[0]!;
307
- const section = candidate.text.slice(0, -1);
308
- const repair = diagnostic(
309
- 'LOCAL_SECTION_HEADING_TRAILING_PUNCTUATION',
310
- `visible required H2 '${candidate.text}' may be normalized to '${section}'`,
311
- content,
312
- candidate,
313
- {
314
- repairable: true,
315
- from: candidate.text,
316
- to: section,
317
- operation: 'replace-line'
318
- }
319
- );
320
- return {
321
- ok: false,
322
- family: options.family,
323
- semanticDigest: semanticDigest(content, candidate),
324
- repairable: true,
325
- diagnostics: [repair]
326
- };
199
+ diagnostics.push({ code: 'LOCAL_DECISION_DETAIL_DUPLICATE', message: decisionDetails.message, repairable: false, line: null });
327
200
  }
328
201
 
329
- if (candidates.length > 0) {
330
- for (const candidate of candidates) {
331
- const section = candidate.text.slice(0, -1);
332
- diagnostics.push(diagnostic(
333
- 'LOCAL_ARTIFACT_MISSING_SECTION',
334
- `required section '${section}' is missing and cannot be repaired while other structural defects exist`,
335
- content, candidate
336
- ));
202
+ if (options.taskContent !== undefined) {
203
+ const expected = expectedQualificationRelations(options.taskContent, options.family);
204
+ if (!expected.ok) {
205
+ diagnostics.push({ code: 'LOCAL_QUALIFICATION_AUDIT_INVALID', message: `${expected.code}: ${expected.message}`, repairable: false, line: null });
206
+ }
207
+ const qualification = validateQualificationAudit(options.taskContent, content, {
208
+ family: options.family === 'analysis' ? 'analysis' : options.family === 'plan' ? 'plan' : 'code',
209
+ artifact: options.artifact,
210
+ expectedUpstreamRelations: expected.ok ? expected.relations : undefined
211
+ });
212
+ if (!qualification.ok) {
213
+ diagnostics.push({ code: 'LOCAL_QUALIFICATION_AUDIT_INVALID', message: `${qualification.code}: ${qualification.message}`, repairable: false, line: null });
337
214
  }
338
215
  }
339
216
 
217
+ const repairable = structure.repair !== null && diagnostics.length === 1 && diagnostics[0]?.repairable === true;
218
+ const semanticDigestValue = canonicalSemanticDigest(content, structure.repair);
219
+
340
220
  return {
341
221
  ok: diagnostics.length === 0,
342
222
  family: options.family,
343
- semanticDigest: semanticDigest(content),
344
- repairable: false,
223
+ semanticDigest: semanticDigestValue,
224
+ repairable,
345
225
  diagnostics
346
226
  };
347
227
  }
@@ -360,194 +240,148 @@ function failedFinalization(
360
240
  };
361
241
  }
362
242
 
363
- function provenanceFailure(
243
+ type LocalArtifactPreparation = Readonly<{
244
+ result: LocalArtifactFinalizationResult;
245
+ content: string;
246
+ repoRoot?: string;
247
+ provenance?: ArtifactRepairIntent;
248
+ expectedIntent?: ArtifactRepairIntent | null;
249
+ }>;
250
+
251
+ /** Read and validate once; callers publish this content before committing provenance. */
252
+ function prepareLocalArtifact(
364
253
  request: LocalArtifactFinalizationRequest,
365
- resolved: { taskId: string; taskDir: string },
366
- content: string,
367
- artifactSha256: string,
368
- semanticDigestValue: string,
369
- code: LocalArtifactDiagnosticCode,
370
- message: string
371
- ): LocalArtifactFinalizationResult {
372
- return failedFinalization(request, { code, message }, {
373
- taskId: resolved.taskId,
374
- taskDir: resolved.taskDir,
375
- artifactSha256,
376
- semanticDigest: semanticDigestValue,
377
- diagnostics: [diagnostic(code, message, content)]
254
+ candidate?: string,
255
+ authority?: LifecycleRecoveryAttestationV1
256
+ ): LocalArtifactPreparation {
257
+ const failed = (code: string, message: string): LocalArtifactPreparation => ({
258
+ result: failedFinalization(request, { code, message }), content: candidate ?? ''
378
259
  });
379
- }
380
-
381
- function finalizeLocalArtifact(request: LocalArtifactFinalizationRequest): LocalArtifactFinalizationResult {
382
260
  const resolved = resolveTaskRef(request.taskRef, { repoRoot: request.repoRoot });
383
- if (!resolved.ok) return failedFinalization(request, { code: resolved.code, message: resolved.message });
261
+ if (!resolved.ok) return failed(resolved.code, resolved.message);
384
262
  const parsed = parseArtifactName(request.artifact);
385
- if (!parsed || parsed.family !== request.family) {
386
- return failedFinalization(request, {
387
- code: 'ARTIFACT_IDENTITY_INVALID',
388
- message: `artifact '${request.artifact}' does not match ${request.family}`
389
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir });
390
- }
391
- const validated = validateCompletedArtifact(resolved.taskDir, request.family, request.artifact, parsed.round);
392
- if (!validated.ok) {
393
- return failedFinalization(request, validated.error, { taskId: resolved.taskId, taskDir: resolved.taskDir });
394
- }
263
+ if (!parsed || parsed.family !== request.family) return failed('ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${request.family}`);
395
264
  let content: string;
396
- try { content = fs.readFileSync(validated.artifact.path, 'utf8'); }
397
- catch (error) {
398
- return failedFinalization(request, { code: 'ARTIFACT_NOT_READABLE', message: String(error) }, {
399
- taskId: resolved.taskId, taskDir: resolved.taskDir
400
- });
401
- }
402
- const result = validateLocalArtifact(content, {
403
- family: request.family,
404
- requiredSections: request.requiredSections,
405
- requiredPatterns: request.requiredPatterns
406
- });
407
- const artifactSha256 = sha256Content(content);
408
- let intent: LocalArtifactFinalizationIntent | null;
265
+ let taskContent: string;
409
266
  try {
410
- intent = readLocalArtifactFinalizationIntent(resolved.repoRoot, resolved.taskId, request.family, request.artifact);
411
- } catch (error) {
412
- return failedFinalization(request, {
413
- code: 'LOCAL_FINALIZATION_INTENT_INVALID',
414
- message: error instanceof Error ? error.message : String(error)
415
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
416
- }
417
- if (result.repairable) {
418
- if (intent && (intent.state !== 'awaiting-repair' || intent.baselineSemanticDigest !== result.semanticDigest)) {
419
- return provenanceFailure(
420
- request, resolved, content, artifactSha256, result.semanticDigest,
421
- 'LOCAL_REPAIR_PROVENANCE_CONFLICT',
422
- 'a different local repair baseline is already recorded for this artifact'
423
- );
424
- }
425
- if (!intent) {
426
- try {
427
- writeLocalArtifactFinalizationIntent(resolved.repoRoot, {
428
- version: 1,
429
- taskId: resolved.taskId,
430
- family: request.family,
431
- artifact: request.artifact,
432
- state: 'awaiting-repair',
433
- baselineSemanticDigest: result.semanticDigest,
434
- artifactSha256,
435
- semanticDigest: result.semanticDigest
436
- });
437
- } catch (error) {
438
- return failedFinalization(request, {
439
- code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED',
440
- message: error instanceof Error ? error.message : String(error)
441
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
267
+ taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
268
+ if (candidate !== undefined) {
269
+ const error = validateArtifactPublication(resolved.taskDir, request.family, request.artifact);
270
+ if (error) return failed(error.code, error.message);
271
+ if (resolved.state !== 'active' || !hasOpenArtifactRound(taskContent, request.family, parsed.round)) {
272
+ return failed('ARTIFACT_IDENTITY_INVALID', 'candidate must match one open started round in an active task');
442
273
  }
274
+ content = candidate;
275
+ } else {
276
+ const validated = validateCompletedArtifact(resolved.taskDir, request.family, request.artifact, parsed.round);
277
+ if (!validated.ok) return failed(validated.error.code, validated.error.message);
278
+ content = fs.readFileSync(validated.artifact.path, 'utf8');
443
279
  }
280
+ } catch (error) { return failed('ARTIFACT_NOT_READABLE', String(error)); }
281
+ const validation = validateLocalArtifact(content, {
282
+ family: request.family, requiredSections: request.requiredSections, taskContent, artifact: request.artifact
283
+ });
284
+ const artifactSha256 = sha256Content(content);
285
+ const { semanticDigest, repairable, diagnostics } = validation;
286
+ const result = failedFinalization(request, {
287
+ code: 'LOCAL_ARTIFACT_INVALID', message: diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
288
+ }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest, repairable, diagnostics });
289
+ const preparedBase = { result, content, repoRoot: resolved.repoRoot };
290
+ if (authority !== undefined && !validFinalizerAuthority(authority, request, resolved.taskId)) {
444
291
  return {
445
- status: 'failed',
446
- changed: false,
447
- taskId: resolved.taskId,
448
- taskDir: resolved.taskDir,
449
- family: request.family,
450
- artifact: request.artifact,
451
- artifactSha256,
452
- semanticDigest: result.semanticDigest,
453
- repairable: true,
454
- diagnostics: result.diagnostics,
455
- error: {
456
- code: 'LOCAL_ARTIFACT_INVALID',
457
- message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
458
- }
459
- };
460
- }
461
- if (!result.ok) {
462
- return {
463
- status: 'failed',
464
- changed: false,
465
- taskId: resolved.taskId,
466
- taskDir: resolved.taskDir,
467
- family: request.family,
468
- artifact: request.artifact,
469
- artifactSha256,
470
- semanticDigest: result.semanticDigest,
471
- repairable: false,
472
- diagnostics: result.diagnostics,
473
- error: {
474
- code: 'LOCAL_ARTIFACT_INVALID',
475
- message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
476
- }
292
+ ...preparedBase,
293
+ result: { ...result, repairable: false, error: {
294
+ code: 'LOCAL_EXECUTION_AUTHORITY_INVALID',
295
+ message: 'finalizer authority does not match the artifact tuple'
296
+ }, diagnostics: [] }
477
297
  };
478
298
  }
479
- if (intent?.state === 'awaiting-repair' && intent.baselineSemanticDigest !== result.semanticDigest) {
480
- return provenanceFailure(
481
- request, resolved, content, artifactSha256, result.semanticDigest,
482
- 'LOCAL_REPAIR_BASELINE_MISMATCH',
483
- 'the repaired artifact semantic digest does not match the recorded repair baseline'
484
- );
299
+ const reject = (code: LocalArtifactDiagnosticCode, message: string): LocalArtifactPreparation => ({
300
+ ...prepared, result: { ...result, repairable: false, error: { code, message },
301
+ diagnostics: [{ code, message, repairable: false, line: null }] }
302
+ });
303
+ let intent: ArtifactRepairIntent | null;
304
+ try { intent = readArtifactRepairIntent(resolved.repoRoot, resolved.taskId, request.family, request.artifact); }
305
+ catch (error) {
306
+ return { ...preparedBase, result: { ...result, repairable: false, diagnostics: [],
307
+ error: { code: 'LOCAL_FINALIZATION_INTENT_INVALID', message: String(error) } } };
485
308
  }
486
- if ((intent?.state === 'passed' || intent?.state === 'consumed')
487
- && (intent.artifactSha256 !== artifactSha256 || intent.semanticDigest !== result.semanticDigest)) {
488
- return provenanceFailure(
489
- request, resolved, content, artifactSha256, result.semanticDigest,
490
- 'LOCAL_REPAIR_PROVENANCE_CONFLICT',
491
- 'the artifact changed after its finalization provenance was recorded'
492
- );
309
+ const prepared = { ...preparedBase, expectedIntent: intent };
310
+ if (intent && intent.recoveryOperationId !== null
311
+ && (!authority || intent.recoveryOperationId !== authority.operationId)) {
312
+ return reject('LOCAL_REPAIR_PROVENANCE_CONFLICT', 'local repair provenance is owned by another recovery operation');
493
313
  }
494
- if (intent?.state === 'consumed') {
495
- return {
496
- status: 'passed',
497
- changed: false,
498
- taskId: resolved.taskId,
499
- taskDir: resolved.taskDir,
500
- family: request.family,
501
- artifact: request.artifact,
502
- artifactSha256,
503
- semanticDigest: result.semanticDigest,
504
- repairable: false,
505
- diagnostics: result.diagnostics,
506
- error: null
507
- };
314
+ if (repairable) {
315
+ if (intent && (intent.state !== 'awaiting-repair' || intent.baselineSemanticDigest !== semanticDigest)) {
316
+ return reject('LOCAL_REPAIR_PROVENANCE_CONFLICT', 'a different local repair baseline is already recorded for this artifact');
317
+ }
318
+ if (intent && !authority) return prepared;
319
+ } else {
320
+ if (!validation.ok) return prepared;
321
+ if (intent?.state === 'awaiting-repair' && intent.baselineSemanticDigest !== semanticDigest) {
322
+ return reject('LOCAL_REPAIR_BASELINE_MISMATCH', 'the repaired artifact semantic digest does not match the recorded repair baseline');
323
+ }
324
+ if ((intent?.state === 'passed' || intent?.state === 'consumed')
325
+ && (intent.artifactSha256 !== artifactSha256 || intent.semanticDigest !== semanticDigest)) {
326
+ return reject('LOCAL_REPAIR_PROVENANCE_CONFLICT', 'the artifact changed after its finalization provenance was recorded');
327
+ }
328
+ prepared.result = { ...result, status: 'passed', error: null };
329
+ if (intent?.state === 'consumed') return prepared;
508
330
  }
331
+ const timestamp = Date.now();
332
+ return { ...prepared, provenance: {
333
+ version: 2, taskId: resolved.taskId, family: request.family, artifact: request.artifact,
334
+ state: repairable ? 'awaiting-repair' : 'passed',
335
+ baselineSemanticDigest: repairable ? semanticDigest : intent?.baselineSemanticDigest ?? null,
336
+ artifactSha256, semanticDigest,
337
+ recoveryOperationId: authority?.operationId ?? intent?.recoveryOperationId ?? null,
338
+ phase: authority?.phase ?? intent?.phase ?? null,
339
+ authorityDigest: authority ? authorityDigest(authority) : intent?.authorityDigest ?? null,
340
+ requestId: authority?.lifecycleRequestId ?? intent?.requestId ?? `local-finalize:${resolved.taskId}`,
341
+ createdAt: intent?.createdAt ?? timestamp,
342
+ updatedAt: timestamp
343
+ } };
344
+ }
345
+
346
+ function commitLocalArtifactProvenance(prepared: LocalArtifactPreparation): LocalArtifactFinalizationResult {
509
347
  try {
510
- writeLocalArtifactFinalizationIntent(resolved.repoRoot, {
511
- version: 1,
512
- taskId: resolved.taskId,
513
- family: request.family,
514
- artifact: request.artifact,
515
- state: 'passed',
516
- baselineSemanticDigest: intent?.baselineSemanticDigest ?? null,
517
- artifactSha256,
518
- semanticDigest: result.semanticDigest
519
- });
348
+ if (prepared.provenance) {
349
+ writeArtifactRepairIntent(prepared.repoRoot!, prepared.provenance, { expected: prepared.expectedIntent ?? null });
350
+ }
351
+ return prepared.result;
520
352
  } catch (error) {
521
- return failedFinalization(request, {
522
- code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED',
523
- message: error instanceof Error ? error.message : String(error)
524
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
353
+ return { ...prepared.result, status: 'failed', error: {
354
+ code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED', message: String(error)
355
+ } };
525
356
  }
526
- return {
527
- status: result.ok ? 'passed' : 'failed',
528
- changed: false,
529
- taskId: resolved.taskId,
530
- taskDir: resolved.taskDir,
531
- family: request.family,
532
- artifact: request.artifact,
533
- artifactSha256,
534
- semanticDigest: result.semanticDigest,
535
- repairable: result.repairable,
536
- diagnostics: result.diagnostics,
537
- error: result.ok ? null : {
538
- code: 'LOCAL_ARTIFACT_INVALID',
539
- message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
357
+ }
358
+
359
+ function finalizeLocalArtifact(
360
+ request: LocalArtifactFinalizationRequest,
361
+ authority?: LifecycleRecoveryAttestationV1,
362
+ options: Readonly<{ deferLifecycleRecoveryConsumption?: boolean }> = {}
363
+ ): LocalArtifactFinalizationResult {
364
+ const result = commitLocalArtifactProvenance(prepareLocalArtifact(request, undefined, authority));
365
+ if (authority && !options.deferLifecycleRecoveryConsumption && result.status === 'passed') {
366
+ try { consumeLifecycleRecoveryAttestation(authority); }
367
+ catch (error) {
368
+ return { ...result, status: 'failed', error: {
369
+ code: 'LOCAL_EXECUTION_AUTHORITY_CONSUME_FAILED',
370
+ message: error instanceof Error ? error.message : String(error)
371
+ } };
540
372
  }
541
- };
373
+ }
374
+ return result;
542
375
  }
543
376
 
544
377
  export {
545
- LOCAL_ARTIFACT_REQUIRED_PATTERNS,
546
378
  LOCAL_ARTIFACT_REQUIRED_SECTIONS,
547
379
  consumeLocalArtifactFinalizationIntent,
548
380
  finalizeLocalArtifact,
549
- readLocalArtifactFinalizationIntent,
550
- semanticDigest,
381
+ prepareLocalArtifact,
382
+ commitLocalArtifactProvenance,
383
+ readArtifactRepairIntent as readLocalArtifactFinalizationIntent,
384
+ canonicalSemanticDigest as semanticDigest,
551
385
  sha256Content,
552
386
  validateLocalArtifact
553
387
  };
@@ -558,6 +392,7 @@ export type {
558
392
  LocalArtifactFinalizationRequest,
559
393
  LocalArtifactFinalizationResult,
560
394
  LocalArtifactFinalizationIntent,
395
+ LocalArtifactPreparation,
561
396
  LocalArtifactValidationOptions,
562
397
  LocalArtifactValidationResult
563
398
  };