@fitlab-ai/agent-infra 0.9.11 → 0.9.13

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 (356) hide show
  1. package/README.md +13 -13
  2. package/README.zh-CN.md +13 -13
  3. package/dist/bin/internal-cli.js +29 -19
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
  5. package/dist/lib/agent-clients/next-steps.js +6 -1
  6. package/dist/lib/decide.js +3 -3
  7. package/dist/lib/defaults.json +4 -0
  8. package/dist/lib/git/workflow.js +43 -1
  9. package/dist/lib/init.js +1 -0
  10. package/dist/lib/internal/git-workflow.js +8 -1
  11. package/dist/lib/internal/platform-checks.js +3 -3
  12. package/dist/lib/internal/platform-comment.js +9 -9
  13. package/dist/lib/internal/platform-context.js +2 -2
  14. package/dist/lib/internal/platform-issue.js +8 -9
  15. package/dist/lib/internal/platform-pr-review.js +10 -10
  16. package/dist/lib/internal/platform-pr.js +68 -23
  17. package/dist/lib/internal/platform-release-notes.js +3 -3
  18. package/dist/lib/internal/pr-review-grade.js +11 -9
  19. package/dist/lib/internal/release-workflow.js +4 -4
  20. package/dist/lib/internal/sandbox-control.js +30 -4
  21. package/dist/lib/internal/task-activity.js +3 -3
  22. package/dist/lib/internal/task-artifact.js +76 -24
  23. package/dist/lib/internal/task-create.js +2 -2
  24. package/dist/lib/internal/task-delivery.js +59 -0
  25. package/dist/lib/internal/task-event.js +6 -3
  26. package/dist/lib/internal/task-finalization.js +2 -2
  27. package/dist/lib/internal/task-invalidation.js +60 -0
  28. package/dist/lib/internal/task-ledger.js +9 -6
  29. package/dist/lib/internal/task-lifecycle.js +2 -2
  30. package/dist/lib/internal/task-override.js +4 -4
  31. package/dist/lib/internal/task-review.js +3 -3
  32. package/dist/lib/internal/task-verify.js +6 -6
  33. package/dist/lib/internal/task-warning.js +3 -3
  34. package/dist/lib/platform/adapters.js +1 -3
  35. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  36. package/dist/lib/platform/completion-backfill.js +6 -5
  37. package/dist/lib/platform/context.js +70 -130
  38. package/dist/lib/platform/github-client.js +8 -2
  39. package/dist/lib/platform/github-provider.js +903 -0
  40. package/dist/lib/platform/in-label-sync.js +143 -0
  41. package/dist/lib/platform/issue-comments.js +94 -41
  42. package/dist/lib/platform/issues.js +335 -189
  43. package/dist/lib/platform/metadata-labels.js +6 -2
  44. package/dist/lib/platform/none-provider.js +28 -0
  45. package/dist/lib/platform/pr-change-report.js +551 -0
  46. package/dist/lib/platform/pr-checks.js +124 -106
  47. package/dist/lib/platform/pr-review.js +88 -72
  48. package/dist/lib/platform/pr-summary.js +523 -49
  49. package/dist/lib/platform/provider-bridge.js +45 -0
  50. package/dist/lib/platform/provider-contract.d.ts +487 -0
  51. package/dist/lib/platform/provider-contract.js +95 -0
  52. package/dist/lib/platform/provider-loader.js +251 -0
  53. package/dist/lib/platform/provider-validation.js +504 -0
  54. package/dist/lib/platform/pull-request-metadata.js +8 -6
  55. package/dist/lib/platform/pull-requests.js +1050 -502
  56. package/dist/lib/platform/release-notes.js +78 -55
  57. package/dist/lib/platform/releases.js +79 -50
  58. package/dist/lib/platform/resource-identity.d.ts +26 -0
  59. package/dist/lib/platform/resource-identity.js +92 -0
  60. package/dist/lib/platform/task-identities.js +31 -0
  61. package/dist/lib/platform/verification-required.js +22 -12
  62. package/dist/lib/platform/verification-sync.js +118 -239
  63. package/dist/lib/pr-review/evidence-grading.js +30 -9
  64. package/dist/lib/run/index.js +63 -23
  65. package/dist/lib/sandbox/config.js +5 -0
  66. package/dist/lib/sandbox/control/client.js +96 -15
  67. package/dist/lib/sandbox/control/executor.js +3 -3
  68. package/dist/lib/sandbox/control/lifecycle.js +29 -7
  69. package/dist/lib/sandbox/control/protocol.js +77 -0
  70. package/dist/lib/sandbox/control/server.js +398 -25
  71. package/dist/lib/sandbox/control/state.js +204 -1
  72. package/dist/lib/server/process-state.js +2 -2
  73. package/dist/lib/server/protocol.js +38 -1
  74. package/dist/lib/task/activity-log.js +8 -1
  75. package/dist/lib/task/artifact-lifecycle.js +35 -7
  76. package/dist/lib/task/capabilities.js +239 -0
  77. package/dist/lib/task/commands/status.js +32 -0
  78. package/dist/lib/task/commit-intent.js +100 -0
  79. package/dist/lib/task/commit-operation.js +207 -102
  80. package/dist/lib/task/control-authority.js +8 -5
  81. package/dist/lib/task/create-service.js +8 -8
  82. package/dist/lib/task/create.js +33 -7
  83. package/dist/lib/task/current-contract.js +5 -1
  84. package/dist/lib/task/decision-details.js +3 -48
  85. package/dist/lib/task/delivery-target.js +97 -0
  86. package/dist/lib/task/delivery.js +153 -0
  87. package/dist/lib/task/events.js +297 -17
  88. package/dist/lib/task/finalization.js +37 -13
  89. package/dist/lib/task/human-override.js +61 -36
  90. package/dist/lib/task/invalidation-command.js +86 -0
  91. package/dist/lib/task/invalidation.js +260 -0
  92. package/dist/lib/task/ledger-intents.js +37 -0
  93. package/dist/lib/task/lifecycle.js +106 -9
  94. package/dist/lib/task/local-artifact-finalization.js +374 -0
  95. package/dist/lib/task/orchestration.js +100 -151
  96. package/dist/lib/task/pr-delivery-fact.js +183 -0
  97. package/dist/lib/task/review-finalization.js +4 -8
  98. package/dist/lib/task/review-fingerprint.js +32 -2
  99. package/dist/lib/task/rework-intent.js +138 -0
  100. package/dist/lib/task/skill-scope.js +23 -0
  101. package/dist/lib/task/task-execution-lock.js +27 -17
  102. package/dist/lib/task/verification-engine.js +89 -38
  103. package/dist/lib/task/verification-review.js +1 -1
  104. package/dist/lib/task/verification.js +3 -3
  105. package/dist/lib/task/workflow-warning-intents.js +1 -1
  106. package/dist/lib/task/write.js +11 -0
  107. package/dist/lib/update.js +9 -0
  108. package/dist/lib/version.js +11 -1
  109. package/dist/lifecycle-build-manifest.json +3 -3
  110. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
  111. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
  112. package/lib/agent-clients/next-steps.ts +6 -1
  113. package/lib/decide.ts +3 -3
  114. package/lib/defaults.json +4 -0
  115. package/lib/git/workflow.ts +38 -1
  116. package/lib/init.ts +4 -1
  117. package/lib/internal/git-workflow.ts +7 -1
  118. package/lib/internal/platform-checks.ts +3 -3
  119. package/lib/internal/platform-comment.ts +8 -8
  120. package/lib/internal/platform-context.ts +2 -2
  121. package/lib/internal/platform-issue.ts +7 -8
  122. package/lib/internal/platform-pr-review.ts +9 -9
  123. package/lib/internal/platform-pr.ts +53 -21
  124. package/lib/internal/platform-release-notes.ts +3 -3
  125. package/lib/internal/pr-review-grade.ts +10 -8
  126. package/lib/internal/release-workflow.ts +4 -4
  127. package/lib/internal/sandbox-control.ts +27 -3
  128. package/lib/internal/task-activity.ts +3 -3
  129. package/lib/internal/task-artifact.ts +65 -22
  130. package/lib/internal/task-create.ts +2 -2
  131. package/lib/internal/task-delivery.ts +53 -0
  132. package/lib/internal/task-event.ts +6 -3
  133. package/lib/internal/task-finalization.ts +3 -3
  134. package/lib/internal/task-invalidation.ts +39 -0
  135. package/lib/internal/task-ledger.ts +11 -8
  136. package/lib/internal/task-lifecycle.ts +2 -2
  137. package/lib/internal/task-override.ts +6 -6
  138. package/lib/internal/task-review.ts +3 -3
  139. package/lib/internal/task-verify.ts +6 -6
  140. package/lib/internal/task-warning.ts +3 -3
  141. package/lib/platform/adapters.ts +3 -2
  142. package/lib/platform/change-request-git-evidence.ts +36 -9
  143. package/lib/platform/completion-backfill.ts +9 -8
  144. package/lib/platform/context.ts +97 -134
  145. package/lib/platform/github-client.ts +10 -3
  146. package/lib/platform/github-provider.ts +910 -0
  147. package/lib/platform/in-label-sync.ts +208 -0
  148. package/lib/platform/issue-comments.ts +97 -47
  149. package/lib/platform/issues.ts +344 -174
  150. package/lib/platform/metadata-labels.ts +5 -2
  151. package/lib/platform/none-provider.ts +35 -0
  152. package/lib/platform/pr-change-report.ts +645 -0
  153. package/lib/platform/pr-checks.ts +129 -107
  154. package/lib/platform/pr-review.ts +88 -85
  155. package/lib/platform/pr-summary.ts +562 -52
  156. package/lib/platform/provider-bridge.ts +82 -0
  157. package/lib/platform/provider-contract.ts +536 -0
  158. package/lib/platform/provider-loader.ts +307 -0
  159. package/lib/platform/provider-validation.ts +529 -0
  160. package/lib/platform/pull-request-metadata.ts +10 -7
  161. package/lib/platform/pull-requests.ts +1126 -505
  162. package/lib/platform/release-notes.ts +76 -59
  163. package/lib/platform/releases.ts +77 -43
  164. package/lib/platform/resource-identity.ts +121 -0
  165. package/lib/platform/task-identities.ts +40 -0
  166. package/lib/platform/types.ts +4 -2
  167. package/lib/platform/verification-required.ts +21 -13
  168. package/lib/platform/verification-sync.ts +118 -293
  169. package/lib/pr-review/evidence-grading.ts +31 -11
  170. package/lib/run/index.ts +57 -22
  171. package/lib/sandbox/config.ts +7 -0
  172. package/lib/sandbox/control/client.ts +105 -15
  173. package/lib/sandbox/control/executor.ts +4 -4
  174. package/lib/sandbox/control/lifecycle.ts +30 -8
  175. package/lib/sandbox/control/protocol.ts +113 -0
  176. package/lib/sandbox/control/server.ts +431 -23
  177. package/lib/sandbox/control/state.ts +251 -1
  178. package/lib/server/process-state.ts +2 -2
  179. package/lib/server/protocol.ts +36 -1
  180. package/lib/task/activity-log.ts +8 -0
  181. package/lib/task/artifact-lifecycle.ts +34 -8
  182. package/lib/task/capabilities.ts +262 -0
  183. package/lib/task/commands/status.ts +38 -0
  184. package/lib/task/commit-intent.ts +137 -0
  185. package/lib/task/commit-operation.ts +186 -88
  186. package/lib/task/control-authority.ts +11 -8
  187. package/lib/task/create-service.ts +8 -8
  188. package/lib/task/create.ts +34 -9
  189. package/lib/task/current-contract.ts +6 -1
  190. package/lib/task/decision-details.ts +8 -64
  191. package/lib/task/delivery-target.ts +130 -0
  192. package/lib/task/delivery.ts +160 -0
  193. package/lib/task/events.ts +296 -16
  194. package/lib/task/finalization.ts +50 -14
  195. package/lib/task/human-override.ts +73 -46
  196. package/lib/task/invalidation-command.ts +86 -0
  197. package/lib/task/invalidation.ts +332 -0
  198. package/lib/task/ledger-intents.ts +35 -1
  199. package/lib/task/lifecycle.ts +93 -4
  200. package/lib/task/local-artifact-finalization.ts +563 -0
  201. package/lib/task/orchestration.ts +110 -146
  202. package/lib/task/pr-delivery-fact.ts +237 -0
  203. package/lib/task/review-finalization.ts +4 -14
  204. package/lib/task/review-fingerprint.ts +33 -2
  205. package/lib/task/rework-intent.ts +165 -0
  206. package/lib/task/skill-scope.ts +24 -0
  207. package/lib/task/task-execution-lock.ts +23 -14
  208. package/lib/task/verification-engine.ts +95 -43
  209. package/lib/task/verification-review.ts +2 -0
  210. package/lib/task/verification.ts +4 -4
  211. package/lib/task/workflow-warning-intents.ts +1 -1
  212. package/lib/task/write.ts +19 -0
  213. package/lib/update.ts +11 -1
  214. package/lib/version.ts +15 -1
  215. package/package.json +7 -1
  216. package/templates/.agents/rules/README.en.md +4 -2
  217. package/templates/.agents/rules/README.zh-CN.md +4 -2
  218. package/templates/.agents/rules/create-issue.en.md +11 -2
  219. package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
  220. package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
  221. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  222. package/templates/.agents/rules/issue-sync.en.md +28 -5
  223. package/templates/.agents/rules/issue-sync.zh-CN.md +64 -5
  224. package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
  225. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
  226. package/templates/.agents/rules/local-artifact-repair.en.md +53 -0
  227. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +53 -0
  228. package/templates/.agents/rules/milestone-inference.en.md +12 -2
  229. package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
  230. package/templates/.agents/rules/pr-sync.en.md +28 -13
  231. package/templates/.agents/rules/pr-sync.zh-CN.md +39 -5
  232. package/templates/.agents/rules/release-commands.en.md +42 -3
  233. package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
  234. package/templates/.agents/rules/security-alerts.en.md +17 -2
  235. package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
  236. package/templates/.agents/rules/sync-content-generation.en.md +8 -0
  237. package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
  238. package/templates/.agents/rules/task-management.en.md +1 -1
  239. package/templates/.agents/rules/task-management.zh-CN.md +1 -1
  240. package/templates/.agents/rules/task-short-id.en.md +1 -4
  241. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  242. package/templates/.agents/scripts/security-alerts.github.sh +151 -0
  243. package/templates/.agents/scripts/security-alerts.sh +31 -0
  244. package/templates/.agents/skills/analyze-task/SKILL.en.md +14 -3
  245. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -3
  246. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  247. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  248. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  249. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  250. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  251. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  252. package/templates/.agents/skills/code-task/SKILL.en.md +32 -10
  253. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +35 -13
  254. package/templates/.agents/skills/code-task/config/verify.en.json +1 -0
  255. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -0
  256. package/templates/.agents/skills/commit/SKILL.en.md +3 -3
  257. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
  258. package/templates/.agents/skills/commit/config/verify.json +1 -1
  259. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
  260. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
  261. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  262. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  263. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +4 -4
  264. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +4 -4
  265. package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
  266. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
  267. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +7 -4
  268. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +7 -4
  269. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  270. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  271. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +5 -4
  272. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +5 -4
  273. package/templates/.agents/skills/complete-task/SKILL.en.md +31 -13
  274. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +30 -13
  275. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
  276. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
  277. package/templates/.agents/skills/create-pr/SKILL.en.md +11 -10
  278. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +11 -11
  279. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  280. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  281. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  282. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  283. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  284. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  285. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  286. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  287. package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
  288. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
  289. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  290. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  291. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  292. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  293. package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
  294. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
  295. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
  296. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
  297. package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
  298. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
  299. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -3
  300. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +11 -3
  301. package/templates/.agents/skills/review-analysis/SKILL.en.md +6 -5
  302. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +6 -5
  303. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
  304. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
  305. package/templates/.agents/skills/review-code/SKILL.en.md +10 -9
  306. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +10 -9
  307. package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
  308. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
  309. package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
  310. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
  311. package/templates/.agents/skills/review-plan/SKILL.en.md +6 -5
  312. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +6 -5
  313. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
  314. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
  315. package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
  316. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
  317. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
  318. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
  319. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -2
  320. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -2
  321. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  322. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  323. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
  324. package/templates/.agents/skills/watch-pr/SKILL.en.md +6 -6
  325. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +6 -6
  326. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  327. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  328. package/templates/.agents/templates/task.en.md +23 -2
  329. package/templates/.agents/templates/task.zh-CN.md +23 -2
  330. package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
  331. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
  332. package/templates/.agents/workflows/feature-development.en.yaml +9 -8
  333. package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
  334. package/templates/.agents/workflows/refactoring.en.yaml +9 -8
  335. package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
  336. package/templates/.github/workflows/pr-label.yml +7 -26
  337. package/templates/.agents/rules/create-issue.github.en.md +0 -14
  338. package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
  339. package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
  340. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
  341. package/templates/.agents/rules/issue-sync.github.en.md +0 -40
  342. package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
  343. package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
  344. package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
  345. package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
  346. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
  347. package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
  348. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
  349. package/templates/.agents/rules/pr-sync.github.en.md +0 -43
  350. package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
  351. package/templates/.agents/rules/release-commands.github.en.md +0 -44
  352. package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
  353. package/templates/.agents/rules/security-alerts.github.en.md +0 -43
  354. package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
  355. /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
  356. /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
@@ -1,10 +1,12 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { createHash } from 'node:crypto';
3
4
  import { declareImplementationInput, IMPLEMENTATION_INPUT_ALIASES, parseImplementationInputs, renderImplementationInputs } from './implementation-inputs.js';
4
5
  import { LEDGER_COLUMNS, LEDGER_HEADINGS, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, nextHdId, parseLedgerDocument, validateLedgerRows } from './ledger.js';
5
6
  import { resolveTaskRef } from './resolve-ref.js';
6
7
  import { writeTask } from './write.js';
7
8
  import { allowsManualOverride } from './guard-override.js';
9
+ import { parseReworkIntentDocument, reworkIntentMutation, upsertReworkIntent } from './rework-intent.js';
8
10
  const PREFIX = { analysis: 'AN', plan: 'PL', code: 'CD' };
9
11
  const RESPONSE = new Set(['accepted', 'adjusted', 'refuted', 'cannot-judge']);
10
12
  const DISPOSITION = new Set(['confirmed', 'closed', 'open', 'needs-human-decision']);
@@ -102,6 +104,41 @@ function applyLedgerIntent(intent, options = {}) {
102
104
  if (intent.kind === 'decision-next-id') {
103
105
  return { status: 'no-op', changed: false, intent: intent.kind, taskId: resolved.taskId, entityId: nextHdId(rows), before: null, after: null, operations: [], error: null };
104
106
  }
107
+ if (intent.kind === 'rework-intent-upsert') {
108
+ if (!/^RI-[1-9]\d*$/.test(intent.intentId) || !/^(AN|PL|CD)-[1-9]\d*$/.test(intent.findingId) || !['analysis', 'plan', 'code'].includes(intent.target) || !/^[a-f0-9]{64}$/.test(intent.sourceSha256)) {
109
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', 'rework intent identity, target, or source hash is invalid', resolved.taskId, intent.intentId);
110
+ }
111
+ const finding = rows.find((row) => row.id === intent.findingId);
112
+ if (!finding || finding.severity === 'decision')
113
+ return failed(intent, 'LEDGER_NOT_FOUND', `finding '${intent.findingId}' was not found`, resolved.taskId, intent.findingId);
114
+ const sourceFromEvidence = finding.evidence.split('#')[0];
115
+ if (sourceFromEvidence !== intent.sourceArtifact || !REVIEW_ARTIFACT[finding.stage]?.test(intent.sourceArtifact)) {
116
+ return failed(intent, 'LEDGER_IDENTITY_CONFLICT', 'rework intent source artifact does not match finding evidence', resolved.taskId, intent.intentId);
117
+ }
118
+ try {
119
+ const actualHash = createHash('sha256').update(fs.readFileSync(path.join(resolved.taskDir, intent.sourceArtifact))).digest('hex');
120
+ if (actualHash !== intent.sourceSha256)
121
+ return failed(intent, 'LEDGER_IDENTITY_CONFLICT', 'rework intent source artifact hash does not match', resolved.taskId, intent.intentId);
122
+ const parsed = parseReworkIntentDocument(content);
123
+ if (!parsed.ok)
124
+ return failed(intent, parsed.code, parsed.message, resolved.taskId, intent.intentId);
125
+ const nextIntent = {
126
+ intentId: intent.intentId, findingId: intent.findingId, sourceArtifact: intent.sourceArtifact,
127
+ sourceSha256: intent.sourceSha256, target: intent.target, status: 'pending',
128
+ declaredAt: new Date().toISOString(), consumedAt: ''
129
+ };
130
+ const next = upsertReworkIntent(parsed.intents, nextIntent);
131
+ if (!next.changed)
132
+ return { status: 'no-op', changed: false, intent: intent.kind, taskId: resolved.taskId, entityId: intent.intentId, before: null, after: null, operations: [], error: null };
133
+ const result = writeTask({ taskRef: intent.taskRef, expectedState: 'active', dryRun: intent.dryRun, mutations: [reworkIntentMutation(content, next.intents)] }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state } });
134
+ if (result.status === 'failed')
135
+ return failed(intent, result.error.code, result.error.message, result.taskId, intent.intentId);
136
+ return { status: result.status, changed: result.changed, intent: intent.kind, taskId: result.taskId, entityId: intent.intentId, before: null, after: null, operations: result.operations, error: null };
137
+ }
138
+ catch (error) {
139
+ return failed(intent, 'LEDGER_IDENTITY_CONFLICT', error instanceof Error ? error.message : String(error), resolved.taskId, intent.intentId);
140
+ }
141
+ }
105
142
  let before = null;
106
143
  let after;
107
144
  if (intent.kind === 'finding-upsert') {
@@ -14,6 +14,7 @@ const lifecycleIntentCatalog = [
14
14
  ];
15
15
  const lifecycleFailureCatalog = [
16
16
  'LIFECYCLE_DIRECTORY_RENAME_FAILED',
17
+ 'LIFECYCLE_DIRECTORY_COPY_FAILED',
17
18
  'LIFECYCLE_DOCUMENT_INVALID',
18
19
  'LIFECYCLE_FINAL_STATE_INVALID',
19
20
  'LIFECYCLE_IDENTITY_CONFLICT',
@@ -295,6 +296,65 @@ function parseJournal(content) {
295
296
  }
296
297
  return value;
297
298
  }
299
+ function directoryManifest(root) {
300
+ const entries = [];
301
+ const visit = (current, relative = '') => {
302
+ for (const entry of fs.readdirSync(current, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
303
+ const relativePath = relative ? path.join(relative, entry.name) : entry.name;
304
+ const absolute = path.join(current, entry.name);
305
+ const stat = fs.lstatSync(absolute);
306
+ if (stat.isSymbolicLink())
307
+ throw new Error(`symbolic link is not allowed in lifecycle directory: ${relativePath}`);
308
+ if (entry.isDirectory()) {
309
+ entries.push({ relativePath, kind: 'directory', size: 0, digest: '' });
310
+ visit(absolute, relativePath);
311
+ }
312
+ else if (entry.isFile()) {
313
+ const digest = createHash('sha256').update(fs.readFileSync(absolute)).digest('hex');
314
+ entries.push({ relativePath, kind: 'file', size: stat.size, digest });
315
+ }
316
+ else {
317
+ throw new Error(`unsupported lifecycle directory entry: ${relativePath}`);
318
+ }
319
+ }
320
+ };
321
+ visit(root);
322
+ return entries;
323
+ }
324
+ function copyDirectoryVerified(source, target) {
325
+ if (fs.existsSync(target))
326
+ throw new Error(`target directory already exists: ${target}`);
327
+ const copy = (currentSource, currentTarget) => {
328
+ fs.mkdirSync(currentTarget);
329
+ for (const entry of fs.readdirSync(currentSource, { withFileTypes: true })) {
330
+ const sourcePath = path.join(currentSource, entry.name);
331
+ const targetPath = path.join(currentTarget, entry.name);
332
+ const stat = fs.lstatSync(sourcePath);
333
+ if (stat.isSymbolicLink())
334
+ throw new Error(`symbolic link is not allowed in lifecycle directory: ${entry.name}`);
335
+ if (entry.isDirectory())
336
+ copy(sourcePath, targetPath);
337
+ else if (entry.isFile())
338
+ fs.copyFileSync(sourcePath, targetPath);
339
+ else
340
+ throw new Error(`unsupported lifecycle directory entry: ${entry.name}`);
341
+ }
342
+ };
343
+ copy(source, target);
344
+ const sourceManifest = directoryManifest(source);
345
+ const targetManifest = directoryManifest(target);
346
+ if (JSON.stringify(sourceManifest) !== JSON.stringify(targetManifest)) {
347
+ throw new Error('copied lifecycle directory failed manifest verification');
348
+ }
349
+ }
350
+ function removeCopiedSource(source, target) {
351
+ const sourceManifest = directoryManifest(source);
352
+ const targetManifest = directoryManifest(target);
353
+ if (JSON.stringify(sourceManifest) !== JSON.stringify(targetManifest)) {
354
+ throw new Error('lifecycle source and target diverged before source cleanup');
355
+ }
356
+ fs.rmSync(source, { recursive: true, force: false });
357
+ }
298
358
  function applyTaskLifecycle(requestInput, options = {}) {
299
359
  const normalized = normalizedRequest(requestInput);
300
360
  if ('code' in normalized)
@@ -356,7 +416,7 @@ function applyTaskLifecycle(requestInput, options = {}) {
356
416
  if (!spec.sources.includes(sourceState) && !existingJournal && !allowsManualOverride(options, 'LIFECYCLE_SOURCE_INVALID')) {
357
417
  return failed(request, { code: 'LIFECYCLE_SOURCE_INVALID', message: `${request.intent} is not allowed from ${sourceState}` }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
358
418
  }
359
- if (sourcePath !== targetPath && fs.existsSync(targetPath)) {
419
+ if (sourcePath !== targetPath && fs.existsSync(targetPath) && !existingJournal) {
360
420
  return failed(request, { code: 'LIFECYCLE_TARGET_CONFLICT', message: `target directory already exists: ${targetPath}` }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
361
421
  }
362
422
  const content = io.readFileSync(currentTaskFile);
@@ -501,18 +561,55 @@ function applyTaskLifecycle(requestInput, options = {}) {
501
561
  (options.directoryRenameSync ?? io.renameSync)(sourcePath, targetPath);
502
562
  }
503
563
  catch (error) {
504
- const failure = { code: 'LIFECYCLE_DIRECTORY_RENAME_FAILED', message: String(error) };
505
- rememberJournalFailure(journalPath, journal, io, failure);
506
- return failed(request, failure, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath, task: { operations: taskOperations }, changed: true, completedSteps: [...completed], timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
564
+ if (error.code === 'EXDEV') {
565
+ try {
566
+ copyDirectoryVerified(sourcePath, targetPath);
567
+ completed.add('directory-moved');
568
+ journal.completedSteps = [...completed];
569
+ const copiedJournalPath = path.join(targetPath, '.task-lifecycle.json');
570
+ writeJournal(initialJournalPath, journal, io);
571
+ writeJournal(copiedJournalPath, journal, io);
572
+ removeCopiedSource(sourcePath, targetPath);
573
+ journalPath = copiedJournalPath;
574
+ }
575
+ catch (copyError) {
576
+ if (fs.existsSync(targetPath))
577
+ fs.rmSync(targetPath, { recursive: true, force: false });
578
+ const failure = { code: 'LIFECYCLE_DIRECTORY_COPY_FAILED', message: String(copyError) };
579
+ rememberJournalFailure(initialJournalPath, journal, io, failure);
580
+ return failed(request, failure, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath: initialJournalPath, task: { operations: taskOperations }, changed: true, completedSteps: [...completed], timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
581
+ }
582
+ }
583
+ else {
584
+ const failure = { code: 'LIFECYCLE_DIRECTORY_RENAME_FAILED', message: String(error) };
585
+ rememberJournalFailure(journalPath, journal, io, failure);
586
+ return failed(request, failure, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath, task: { operations: taskOperations }, changed: true, completedSteps: [...completed], timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
587
+ }
507
588
  }
508
- completed.add('directory-moved');
509
- journal.completedSteps = [...completed];
510
- journalPath = path.join(targetPath, '.task-lifecycle.json');
589
+ if (completed.has('directory-moved') && !fs.existsSync(sourcePath)) {
590
+ journalPath = path.join(targetPath, '.task-lifecycle.json');
591
+ }
592
+ else if (!completed.has('directory-moved')) {
593
+ completed.add('directory-moved');
594
+ journal.completedSteps = [...completed];
595
+ journalPath = path.join(targetPath, '.task-lifecycle.json');
596
+ try {
597
+ writeJournal(journalPath, journal, io);
598
+ }
599
+ catch (error) {
600
+ return failed(request, { code: 'LIFECYCLE_JOURNAL_WRITE_FAILED', message: String(error) }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath, task: { operations: taskOperations }, directory: { effect: 'move', changed: true }, changed: true, completedSteps: [...completed], timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
601
+ }
602
+ }
603
+ }
604
+ if (completed.has('directory-moved') && sourcePath !== targetPath && fs.existsSync(sourcePath) && fs.existsSync(targetPath)) {
511
605
  try {
512
- writeJournal(journalPath, journal, io);
606
+ removeCopiedSource(sourcePath, targetPath);
607
+ journalPath = path.join(targetPath, '.task-lifecycle.json');
513
608
  }
514
609
  catch (error) {
515
- return failed(request, { code: 'LIFECYCLE_JOURNAL_WRITE_FAILED', message: String(error) }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath, task: { operations: taskOperations }, directory: { effect: 'move', changed: true }, changed: true, completedSteps: [...completed], timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
610
+ const failure = { code: 'LIFECYCLE_DIRECTORY_COPY_FAILED', message: String(error) };
611
+ rememberJournalFailure(journalPath, journal, io, failure);
612
+ return failed(request, failure, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath, task: { operations: taskOperations }, changed: true, completedSteps: [...completed], timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
516
613
  }
517
614
  }
518
615
  let shortId = { effect: 'unchanged', shortId: null, changed: false };
@@ -0,0 +1,374 @@
1
+ import fs from 'node:fs';
2
+ import { createHash } from 'node:crypto';
3
+ import path from 'node:path';
4
+ import { inspectDecisionDetailDuplicates, scanVisibleMarkdown } from './decision-details.js';
5
+ import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
6
+ import { resolveTaskRef } from './resolve-ref.js';
7
+ const LOCAL_ARTIFACT_REQUIRED_SECTIONS = {
8
+ analysis: [
9
+ '需求来源', '需求理解', '相关文件', '影响评估', '技术风险',
10
+ '工作量和复杂度评估', '状态核对'
11
+ ],
12
+ plan: [
13
+ '问题理解', '约束条件', '方案对比', '技术方法', '实施步骤',
14
+ '文件清单', '验证策略', '状态核对'
15
+ ],
16
+ code: [
17
+ '实现输入', '变更文件', '关键代码说明', '测试结果', '与方案的差异',
18
+ '供审查关注的内容', '状态核对', '证据原文'
19
+ ]
20
+ };
21
+ const LOCAL_ARTIFACT_REQUIRED_PATTERNS = ['^\\$ '];
22
+ function finalizationIntentRoot(repoRoot) {
23
+ return path.join(repoRoot, '.agents', 'workspace', '.local-artifact-finalization-intents');
24
+ }
25
+ function finalizationIntentPath(repoRoot, taskId, family, artifact) {
26
+ return path.join(finalizationIntentRoot(repoRoot), `${taskId}-${family}-${artifact}.json`);
27
+ }
28
+ function isFinalizationIntent(value) {
29
+ if (!value || typeof value !== 'object' || Array.isArray(value))
30
+ return false;
31
+ const intent = value;
32
+ return intent.version === 1
33
+ && typeof intent.taskId === 'string' && intent.taskId.length > 0
34
+ && (intent.family === 'analysis' || intent.family === 'plan' || intent.family === 'code')
35
+ && typeof intent.artifact === 'string' && intent.artifact.length > 0
36
+ && (intent.state === 'awaiting-repair' || intent.state === 'passed' || intent.state === 'consumed')
37
+ && (intent.baselineSemanticDigest === null || (typeof intent.baselineSemanticDigest === 'string' && /^[a-f0-9]{64}$/.test(intent.baselineSemanticDigest)))
38
+ && typeof intent.artifactSha256 === 'string' && /^[a-f0-9]{64}$/.test(intent.artifactSha256)
39
+ && typeof intent.semanticDigest === 'string' && /^[a-f0-9]{64}$/.test(intent.semanticDigest)
40
+ && (intent.state === 'awaiting-repair' ? intent.baselineSemanticDigest === intent.semanticDigest : true);
41
+ }
42
+ function readLocalArtifactFinalizationIntent(repoRoot, taskId, family, artifact) {
43
+ const target = finalizationIntentPath(repoRoot, taskId, family, artifact);
44
+ if (!fs.existsSync(target))
45
+ return null;
46
+ const value = JSON.parse(fs.readFileSync(target, 'utf8'));
47
+ if (!isFinalizationIntent(value) || value.taskId !== taskId || value.family !== family || value.artifact !== artifact) {
48
+ throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: finalization provenance schema is invalid');
49
+ }
50
+ return value;
51
+ }
52
+ function writeLocalArtifactFinalizationIntent(repoRoot, value) {
53
+ if (!isFinalizationIntent(value))
54
+ throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: finalization provenance schema is invalid');
55
+ const directory = finalizationIntentRoot(repoRoot);
56
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
57
+ const target = finalizationIntentPath(repoRoot, value.taskId, value.family, value.artifact);
58
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
59
+ fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
60
+ try {
61
+ fs.renameSync(temporary, target);
62
+ }
63
+ catch (error) {
64
+ try {
65
+ fs.unlinkSync(temporary);
66
+ }
67
+ catch { /* preserve primary error */ }
68
+ throw error;
69
+ }
70
+ }
71
+ function consumeLocalArtifactFinalizationIntent(repoRoot, intent) {
72
+ if (intent.state === 'consumed')
73
+ return intent;
74
+ if (intent.state !== 'passed')
75
+ throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: only passed provenance can be consumed');
76
+ const consumed = { ...intent, state: 'consumed' };
77
+ writeLocalArtifactFinalizationIntent(repoRoot, consumed);
78
+ return consumed;
79
+ }
80
+ function requiredSections(family) {
81
+ return LOCAL_ARTIFACT_REQUIRED_SECTIONS[family];
82
+ }
83
+ function lineNumber(content, offset) {
84
+ return content.slice(0, offset).split('\n').length;
85
+ }
86
+ function sectionBody(content, heading) {
87
+ const next = scanVisibleMarkdown(content).headings.find((candidate) => (candidate.start > heading.start && candidate.level <= 2));
88
+ return content.slice(heading.end, next?.start ?? content.length);
89
+ }
90
+ function semanticDigest(content, candidate) {
91
+ let normalized = content;
92
+ if (candidate) {
93
+ const raw = content.slice(candidate.start, candidate.end);
94
+ const marker = raw.match(/([::])\s*$/);
95
+ if (marker?.index !== undefined) {
96
+ const canonical = raw.slice(0, marker.index) + raw.slice(marker.index + 1);
97
+ normalized = `${content.slice(0, candidate.start)}${canonical}${content.slice(candidate.end)}`;
98
+ }
99
+ }
100
+ return createHash('sha256').update(normalized, 'utf8').digest('hex');
101
+ }
102
+ function sha256Content(content) {
103
+ return createHash('sha256').update(content, 'utf8').digest('hex');
104
+ }
105
+ function visibleSectionHeadings(content, section) {
106
+ return scanVisibleMarkdown(content).headings.filter((heading) => (heading.level === 2 && heading.text === section));
107
+ }
108
+ function trailingPunctuationCandidates(content, section) {
109
+ return scanVisibleMarkdown(content).headings.filter((heading) => (heading.level === 2 && (heading.text === `${section}:` || heading.text === `${section}:`)));
110
+ }
111
+ function diagnostic(code, message, content, heading, extra = {}) {
112
+ return {
113
+ code, message, repairable: false,
114
+ line: heading ? lineNumber(content, heading.start) : null,
115
+ ...extra
116
+ };
117
+ }
118
+ function isStatusPattern(pattern) {
119
+ return pattern === '^\\$ ';
120
+ }
121
+ function validateLocalArtifact(content, options) {
122
+ const sections = options.requiredSections ?? requiredSections(options.family);
123
+ const patterns = options.requiredPatterns ?? LOCAL_ARTIFACT_REQUIRED_PATTERNS;
124
+ const diagnostics = [];
125
+ const candidates = [];
126
+ const scanned = scanVisibleMarkdown(content);
127
+ if (!content.trim()) {
128
+ diagnostics.push(diagnostic('LOCAL_ARTIFACT_EMPTY', 'artifact is empty', content));
129
+ }
130
+ for (const section of sections) {
131
+ const exact = scanned.headings.filter((heading) => heading.level === 2 && heading.text === section);
132
+ const punctuated = trailingPunctuationCandidates(content, section);
133
+ if (exact.length > 1 || punctuated.length > 0 && exact.length > 0 || punctuated.length > 1) {
134
+ const first = exact[1] ?? punctuated[0] ?? exact[0];
135
+ diagnostics.push(diagnostic('LOCAL_ARTIFACT_DUPLICATE_SECTION', `required section '${section}' is duplicated or has an ambiguous punctuation variant`, content, first));
136
+ }
137
+ else if (exact.length === 0 && punctuated.length === 1) {
138
+ candidates.push(punctuated[0]);
139
+ }
140
+ else if (exact.length === 0) {
141
+ diagnostics.push(diagnostic('LOCAL_ARTIFACT_MISSING_SECTION', `required section '${section}' is missing`, content));
142
+ }
143
+ }
144
+ const statusSection = sections.find((section) => section === '状态核对' || section.toLowerCase() === 'state check');
145
+ if (statusSection) {
146
+ const statusHeading = visibleSectionHeadings(content, statusSection)[0]
147
+ ?? candidates.find((heading) => heading.text === `${statusSection}:` || heading.text === `${statusSection}:`);
148
+ if (statusHeading) {
149
+ const body = sectionBody(content, statusHeading);
150
+ for (const pattern of patterns.filter(isStatusPattern)) {
151
+ if (!new RegExp(pattern, 'm').test(body)) {
152
+ diagnostics.push(diagnostic('LOCAL_STATUS_COMMAND_MISSING', `status section '${statusSection}' is missing required command output`, content, statusHeading));
153
+ }
154
+ }
155
+ }
156
+ }
157
+ for (const pattern of patterns.filter((item) => !isStatusPattern(item))) {
158
+ if (!new RegExp(pattern, 'm').test(content)) {
159
+ diagnostics.push(diagnostic('LOCAL_REQUIRED_PATTERN_MISSING', `artifact is missing required pattern '${pattern}'`, content));
160
+ }
161
+ }
162
+ const decisionDetails = inspectDecisionDetailDuplicates(content);
163
+ if (!decisionDetails.ok) {
164
+ diagnostics.push(diagnostic('LOCAL_DECISION_DETAIL_DUPLICATE', decisionDetails.message, content, decisionDetails.duplicates[0]?.blocks[0]
165
+ ? scanned.headings.find((heading) => heading.start === decisionDetails.duplicates[0].blocks[0].start)
166
+ : undefined));
167
+ }
168
+ if (candidates.length === 1 && diagnostics.length === 0) {
169
+ const candidate = candidates[0];
170
+ const section = candidate.text.slice(0, -1);
171
+ const repair = diagnostic('LOCAL_SECTION_HEADING_TRAILING_PUNCTUATION', `visible required H2 '${candidate.text}' may be normalized to '${section}'`, content, candidate, {
172
+ repairable: true,
173
+ from: candidate.text,
174
+ to: section,
175
+ operation: 'replace-line'
176
+ });
177
+ return {
178
+ ok: false,
179
+ family: options.family,
180
+ semanticDigest: semanticDigest(content, candidate),
181
+ repairable: true,
182
+ diagnostics: [repair]
183
+ };
184
+ }
185
+ if (candidates.length > 0) {
186
+ for (const candidate of candidates) {
187
+ const section = candidate.text.slice(0, -1);
188
+ diagnostics.push(diagnostic('LOCAL_ARTIFACT_MISSING_SECTION', `required section '${section}' is missing and cannot be repaired while other structural defects exist`, content, candidate));
189
+ }
190
+ }
191
+ return {
192
+ ok: diagnostics.length === 0,
193
+ family: options.family,
194
+ semanticDigest: semanticDigest(content),
195
+ repairable: false,
196
+ diagnostics
197
+ };
198
+ }
199
+ function failedFinalization(request, error, extra = {}) {
200
+ return {
201
+ status: 'failed', changed: false,
202
+ taskId: null, taskDir: null,
203
+ family: request.family, artifact: request.artifact,
204
+ artifactSha256: null, semanticDigest: null,
205
+ repairable: false, diagnostics: [], error, ...extra
206
+ };
207
+ }
208
+ function provenanceFailure(request, resolved, content, artifactSha256, semanticDigestValue, code, message) {
209
+ return failedFinalization(request, { code, message }, {
210
+ taskId: resolved.taskId,
211
+ taskDir: resolved.taskDir,
212
+ artifactSha256,
213
+ semanticDigest: semanticDigestValue,
214
+ diagnostics: [diagnostic(code, message, content)]
215
+ });
216
+ }
217
+ function finalizeLocalArtifact(request) {
218
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: request.repoRoot });
219
+ if (!resolved.ok)
220
+ return failedFinalization(request, { code: resolved.code, message: resolved.message });
221
+ const parsed = parseArtifactName(request.artifact);
222
+ if (!parsed || parsed.family !== request.family) {
223
+ return failedFinalization(request, {
224
+ code: 'ARTIFACT_IDENTITY_INVALID',
225
+ message: `artifact '${request.artifact}' does not match ${request.family}`
226
+ }, { taskId: resolved.taskId, taskDir: resolved.taskDir });
227
+ }
228
+ const validated = validateCompletedArtifact(resolved.taskDir, request.family, request.artifact, parsed.round);
229
+ if (!validated.ok) {
230
+ return failedFinalization(request, validated.error, { taskId: resolved.taskId, taskDir: resolved.taskDir });
231
+ }
232
+ let content;
233
+ try {
234
+ content = fs.readFileSync(validated.artifact.path, 'utf8');
235
+ }
236
+ catch (error) {
237
+ return failedFinalization(request, { code: 'ARTIFACT_NOT_READABLE', message: String(error) }, {
238
+ taskId: resolved.taskId, taskDir: resolved.taskDir
239
+ });
240
+ }
241
+ const result = validateLocalArtifact(content, {
242
+ family: request.family,
243
+ requiredSections: request.requiredSections,
244
+ requiredPatterns: request.requiredPatterns
245
+ });
246
+ const artifactSha256 = sha256Content(content);
247
+ let intent;
248
+ try {
249
+ intent = readLocalArtifactFinalizationIntent(resolved.repoRoot, resolved.taskId, request.family, request.artifact);
250
+ }
251
+ catch (error) {
252
+ return failedFinalization(request, {
253
+ code: 'LOCAL_FINALIZATION_INTENT_INVALID',
254
+ message: error instanceof Error ? error.message : String(error)
255
+ }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
256
+ }
257
+ if (result.repairable) {
258
+ if (intent && (intent.state !== 'awaiting-repair' || intent.baselineSemanticDigest !== result.semanticDigest)) {
259
+ return provenanceFailure(request, resolved, content, artifactSha256, result.semanticDigest, 'LOCAL_REPAIR_PROVENANCE_CONFLICT', 'a different local repair baseline is already recorded for this artifact');
260
+ }
261
+ if (!intent) {
262
+ try {
263
+ writeLocalArtifactFinalizationIntent(resolved.repoRoot, {
264
+ version: 1,
265
+ taskId: resolved.taskId,
266
+ family: request.family,
267
+ artifact: request.artifact,
268
+ state: 'awaiting-repair',
269
+ baselineSemanticDigest: result.semanticDigest,
270
+ artifactSha256,
271
+ semanticDigest: result.semanticDigest
272
+ });
273
+ }
274
+ catch (error) {
275
+ return failedFinalization(request, {
276
+ code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED',
277
+ message: error instanceof Error ? error.message : String(error)
278
+ }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
279
+ }
280
+ }
281
+ return {
282
+ status: 'failed',
283
+ changed: false,
284
+ taskId: resolved.taskId,
285
+ taskDir: resolved.taskDir,
286
+ family: request.family,
287
+ artifact: request.artifact,
288
+ artifactSha256,
289
+ semanticDigest: result.semanticDigest,
290
+ repairable: true,
291
+ diagnostics: result.diagnostics,
292
+ error: {
293
+ code: 'LOCAL_ARTIFACT_INVALID',
294
+ message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
295
+ }
296
+ };
297
+ }
298
+ if (!result.ok) {
299
+ return {
300
+ status: 'failed',
301
+ changed: false,
302
+ taskId: resolved.taskId,
303
+ taskDir: resolved.taskDir,
304
+ family: request.family,
305
+ artifact: request.artifact,
306
+ artifactSha256,
307
+ semanticDigest: result.semanticDigest,
308
+ repairable: false,
309
+ diagnostics: result.diagnostics,
310
+ error: {
311
+ code: 'LOCAL_ARTIFACT_INVALID',
312
+ message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
313
+ }
314
+ };
315
+ }
316
+ if (intent?.state === 'awaiting-repair' && intent.baselineSemanticDigest !== result.semanticDigest) {
317
+ return provenanceFailure(request, resolved, content, artifactSha256, result.semanticDigest, 'LOCAL_REPAIR_BASELINE_MISMATCH', 'the repaired artifact semantic digest does not match the recorded repair baseline');
318
+ }
319
+ if ((intent?.state === 'passed' || intent?.state === 'consumed')
320
+ && (intent.artifactSha256 !== artifactSha256 || intent.semanticDigest !== result.semanticDigest)) {
321
+ return provenanceFailure(request, resolved, content, artifactSha256, result.semanticDigest, 'LOCAL_REPAIR_PROVENANCE_CONFLICT', 'the artifact changed after its finalization provenance was recorded');
322
+ }
323
+ if (intent?.state === 'consumed') {
324
+ return {
325
+ status: 'passed',
326
+ changed: false,
327
+ taskId: resolved.taskId,
328
+ taskDir: resolved.taskDir,
329
+ family: request.family,
330
+ artifact: request.artifact,
331
+ artifactSha256,
332
+ semanticDigest: result.semanticDigest,
333
+ repairable: false,
334
+ diagnostics: result.diagnostics,
335
+ error: null
336
+ };
337
+ }
338
+ try {
339
+ writeLocalArtifactFinalizationIntent(resolved.repoRoot, {
340
+ version: 1,
341
+ taskId: resolved.taskId,
342
+ family: request.family,
343
+ artifact: request.artifact,
344
+ state: 'passed',
345
+ baselineSemanticDigest: intent?.baselineSemanticDigest ?? null,
346
+ artifactSha256,
347
+ semanticDigest: result.semanticDigest
348
+ });
349
+ }
350
+ catch (error) {
351
+ return failedFinalization(request, {
352
+ code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED',
353
+ message: error instanceof Error ? error.message : String(error)
354
+ }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
355
+ }
356
+ return {
357
+ status: result.ok ? 'passed' : 'failed',
358
+ changed: false,
359
+ taskId: resolved.taskId,
360
+ taskDir: resolved.taskDir,
361
+ family: request.family,
362
+ artifact: request.artifact,
363
+ artifactSha256,
364
+ semanticDigest: result.semanticDigest,
365
+ repairable: result.repairable,
366
+ diagnostics: result.diagnostics,
367
+ error: result.ok ? null : {
368
+ code: 'LOCAL_ARTIFACT_INVALID',
369
+ message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
370
+ }
371
+ };
372
+ }
373
+ export { LOCAL_ARTIFACT_REQUIRED_PATTERNS, LOCAL_ARTIFACT_REQUIRED_SECTIONS, consumeLocalArtifactFinalizationIntent, finalizeLocalArtifact, readLocalArtifactFinalizationIntent, semanticDigest, sha256Content, validateLocalArtifact };
374
+ //# sourceMappingURL=local-artifact-finalization.js.map