@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
@@ -0,0 +1,262 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import type { InvalidationDocument } from './invalidation.ts';
5
+ import { invalidationBlocks, isArtifactInvalidated, parseInvalidationDocument } from './invalidation.ts';
6
+ import { receiptForOutput } from './artifact-receipts.ts';
7
+ import { parseTypedTaskFrontmatter } from './frontmatter.ts';
8
+ import { parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.ts';
9
+ import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.ts';
10
+ import { parseReworkIntentDocument } from './rework-intent.ts';
11
+ import type { ReworkIntent } from './rework-intent.ts';
12
+ import { sha256File } from './artifact-receipts.ts';
13
+ import { hasOpenLifecycleExecution } from './activity-log.ts';
14
+
15
+ type LifecycleAction =
16
+ | 'analysis' | 'review-analysis' | 'plan' | 'review-plan'
17
+ | 'code' | 'review-code' | 'manual-validation' | 'validation-run';
18
+ type TriggerInitiator = 'human' | 'model' | 'orchestrator';
19
+ type TriggerReason = 'user-request' | 'new-requirement' | 'upstream-fact-doubt' | 'review-finding' | 'retry' | 'validation-rerun';
20
+ type ExplicitTrigger = {
21
+ initiator: TriggerInitiator;
22
+ requestId: string;
23
+ requestedAction: LifecycleAction;
24
+ reasonCode: TriggerReason;
25
+ sourceFinding?: string;
26
+ sourceArtifact?: string;
27
+ sourceSha256?: string;
28
+ implementationInput?: string;
29
+ /** False marks the ordinary recommended workflow event; it is not an authorization fact. */
30
+ explicitRequest?: boolean;
31
+ };
32
+ type LifecycleFacts = {
33
+ taskState: string;
34
+ currentStep: string;
35
+ artifacts: Partial<Record<LifecycleAction, readonly string[]>>;
36
+ staleArtifacts?: Partial<Record<LifecycleAction, readonly string[]>>;
37
+ reviewedInputs?: Partial<Record<'review-analysis' | 'review-plan' | 'review-code', string>>;
38
+ artifactHashes: Readonly<Record<string, string>>;
39
+ reviews: Partial<Record<'review-analysis' | 'review-plan' | 'review-code', 'approved' | 'changes-requested' | 'rejected'>>;
40
+ invalidation: InvalidationDocument;
41
+ reworkIntents?: readonly ReworkIntent[];
42
+ unresolvedLedger: Record<'analysis' | 'plan' | 'code', number>;
43
+ executionBusy: boolean;
44
+ recommendedAction?: LifecycleAction | null;
45
+ };
46
+ type CapabilityResult = {
47
+ allowed: boolean;
48
+ reasonCode: string;
49
+ evidence: readonly string[];
50
+ };
51
+ type LifecycleRecommendation = {
52
+ action: LifecycleAction | null;
53
+ reasonCode: string;
54
+ evidence: readonly string[];
55
+ };
56
+ type LifecycleFactsResult =
57
+ | { ok: true; facts: LifecycleFacts }
58
+ | { ok: false; code: 'TASK_CAPABILITY_FACTS_INVALID'; message: string };
59
+
60
+ const REASONS = new Set<TriggerReason>([
61
+ 'user-request', 'new-requirement', 'upstream-fact-doubt', 'review-finding', 'retry', 'validation-rerun'
62
+ ]);
63
+
64
+ function deny(reasonCode: string, ...evidence: string[]): CapabilityResult {
65
+ return { allowed: false, reasonCode, evidence };
66
+ }
67
+
68
+ function allow(...evidence: string[]): CapabilityResult {
69
+ return { allowed: true, reasonCode: 'CAPABILITY_ALLOWED', evidence };
70
+ }
71
+
72
+ function hasArtifact(facts: LifecycleFacts, action: LifecycleAction): boolean {
73
+ return (facts.artifacts[action]?.length ?? 0) > 0;
74
+ }
75
+
76
+ function canStart(action: LifecycleAction, facts: LifecycleFacts, trigger: ExplicitTrigger): CapabilityResult {
77
+ if (!trigger || trigger.requestedAction !== action) return deny('TRIGGER_ACTION_MISMATCH', `requested=${trigger?.requestedAction ?? 'missing'}`);
78
+ if (!trigger.requestId || !trigger.requestId.trim()) return deny('TRIGGER_REQUEST_ID_REQUIRED');
79
+ if (!REASONS.has(trigger.reasonCode)) return deny('TRIGGER_REASON_INVALID');
80
+ if (trigger.sourceArtifact && !trigger.sourceSha256) return deny('SOURCE_ARTIFACT_HASH_REQUIRED');
81
+ if (trigger.sourceSha256 && !trigger.sourceArtifact) return deny('SOURCE_ARTIFACT_REQUIRED');
82
+ if (trigger.sourceArtifact && trigger.sourceSha256) {
83
+ const actual = facts.artifactHashes[trigger.sourceArtifact];
84
+ if (!actual) return deny('SOURCE_ARTIFACT_MISSING', trigger.sourceArtifact);
85
+ if (actual !== trigger.sourceSha256) return deny('SOURCE_ARTIFACT_HASH_MISMATCH', trigger.sourceArtifact);
86
+ }
87
+ if (facts.taskState !== 'active') return deny('TASK_NOT_ACTIVE', `state=${facts.taskState}`);
88
+ if (invalidationBlocks(facts.invalidation)) return deny('INVALIDATION_INCOMPLETE');
89
+ if (facts.executionBusy) return deny('EXECUTION_BUSY');
90
+
91
+ const implicit = trigger.explicitRequest === false;
92
+ if (action === 'analysis') {
93
+ if (!implicit || hasArtifact(facts, 'analysis') || facts.recommendedAction === 'analysis') return allow('analysis-capability');
94
+ return deny('ANALYSIS_REQUEST_REQUIRES_EXPLICIT_TRIGGER');
95
+ }
96
+ if (action === 'review-analysis') {
97
+ return hasArtifact(facts, 'analysis') ? allow('analysis-artifact') : deny('ANALYSIS_ARTIFACT_REQUIRED');
98
+ }
99
+ if (action === 'plan') {
100
+ if (!hasArtifact(facts, 'review-analysis')) return deny('ANALYSIS_REVIEW_REQUIRED');
101
+ if (!reviewMatchesLatest(facts, 'analysis', 'review-analysis')) return deny('ANALYSIS_REVIEW_NOT_LATEST');
102
+ if (facts.reviews['review-analysis'] !== 'approved') return deny('ANALYSIS_REVIEW_NOT_APPROVED');
103
+ if (facts.unresolvedLedger.analysis > 0) return deny('ANALYSIS_LEDGER_BLOCKED', `unresolved=${facts.unresolvedLedger.analysis}`);
104
+ return allow('analysis-review-approved');
105
+ }
106
+ if (action === 'review-plan') {
107
+ return hasArtifact(facts, 'plan') ? allow('plan-artifact') : deny('PLAN_ARTIFACT_REQUIRED');
108
+ }
109
+ if (action === 'code') {
110
+ if (trigger.implementationInput) {
111
+ if (!hasArtifact(facts, 'review-code')) return deny('CODE_REVIEW_REQUIRED');
112
+ if (!reviewMatchesLatest(facts, 'code', 'review-code')) return deny('CODE_REVIEW_NOT_LATEST');
113
+ if (facts.reviews['review-code'] !== 'approved') return deny('CODE_REVIEW_NOT_APPROVED');
114
+ return allow('implementation-input');
115
+ }
116
+ if (!hasArtifact(facts, 'review-plan')) return deny('PLAN_REVIEW_REQUIRED');
117
+ if (!reviewMatchesLatest(facts, 'plan', 'review-plan')) return deny('PLAN_REVIEW_NOT_LATEST');
118
+ if (facts.reviews['review-plan'] !== 'approved') return deny('PLAN_REVIEW_NOT_APPROVED');
119
+ if (facts.unresolvedLedger.plan > 0) return deny('PLAN_LEDGER_BLOCKED', `unresolved=${facts.unresolvedLedger.plan}`);
120
+ return allow('plan-review-approved');
121
+ }
122
+ if (action === 'review-code') {
123
+ return hasArtifact(facts, 'code') ? allow('code-artifact') : deny('CODE_ARTIFACT_REQUIRED');
124
+ }
125
+ if (action === 'manual-validation' || action === 'validation-run') {
126
+ if (!hasArtifact(facts, 'review-code')) return deny('CODE_REVIEW_REQUIRED');
127
+ if (!reviewMatchesLatest(facts, 'code', 'review-code')) return deny('CODE_REVIEW_NOT_LATEST');
128
+ if (facts.reviews['review-code'] !== 'approved') return deny('CODE_REVIEW_NOT_APPROVED');
129
+ if (facts.unresolvedLedger.code > 0) return deny('CODE_LEDGER_BLOCKED', `unresolved=${facts.unresolvedLedger.code}`);
130
+ return allow('code-review-approved');
131
+ }
132
+ return deny('CAPABILITY_ACTION_UNKNOWN');
133
+ }
134
+
135
+ function artifactRound(name: string): number {
136
+ const match = /-r(\d+)\.md$/.exec(name);
137
+ return match ? Number(match[1]) : 1;
138
+ }
139
+
140
+ function latestArtifact(names: readonly string[]): string | null {
141
+ return [...names].sort((left, right) => artifactRound(right) - artifactRound(left) || left.localeCompare(right))[0] ?? null;
142
+ }
143
+
144
+ function reviewedInputName(content: string, expectedFamily: 'analysis' | 'plan' | 'code'): string | null {
145
+ const header = content.split(/\r?\n/).findIndex((line) => /\*\*(?:审查输入|Review Input)\*\*[::]/.test(line));
146
+ if (header < 0) return null;
147
+ const referenceBlock = content.split(/\r?\n/).slice(header, header + 12).join('\n');
148
+ const expected = new RegExp('`' + expectedFamily + '(?:-r[2-9]|-r[1-9]\\d+)?\\.md`');
149
+ return expected.exec(referenceBlock)?.[0].slice(1, -1) ?? null;
150
+ }
151
+
152
+ function reviewMatchesLatest(facts: LifecycleFacts, source: 'analysis' | 'plan' | 'code', review: 'review-analysis' | 'review-plan' | 'review-code'): boolean {
153
+ const latestSource = latestArtifact(facts.artifacts[source] ?? []);
154
+ return Boolean(latestSource && facts.reviewedInputs?.[review] === latestSource);
155
+ }
156
+
157
+ function recommendNext(facts: LifecycleFacts): LifecycleRecommendation {
158
+ if (invalidationBlocks(facts.invalidation)) return { action: null, reasonCode: 'INVALIDATION_INCOMPLETE', evidence: ['reconcile task invalidation before routing'] };
159
+ const pendingIntent = (facts.reworkIntents ?? []).find((intent) => intent.status === 'pending');
160
+ if (pendingIntent) return { action: pendingIntent.target, reasonCode: 'REWORK_INTENT_PENDING', evidence: [pendingIntent.intentId, pendingIntent.findingId] };
161
+ if (!hasArtifact(facts, 'analysis')) return { action: 'analysis', reasonCode: 'ANALYSIS_ARTIFACT_MISSING', evidence: ['analysis artifact is absent'] };
162
+ if (!hasArtifact(facts, 'review-analysis') || !reviewMatchesLatest(facts, 'analysis', 'review-analysis')) {
163
+ return { action: 'review-analysis', reasonCode: 'ANALYSIS_REVIEW_MISSING', evidence: ['analysis review does not bind the latest analysis artifact'] };
164
+ }
165
+ if (facts.reviews['review-analysis'] !== 'approved' || facts.unresolvedLedger.analysis > 0) {
166
+ return { action: 'analysis', reasonCode: 'ANALYSIS_REWORK_REQUIRED', evidence: ['analysis review or ledger is not clear'] };
167
+ }
168
+ if (!hasArtifact(facts, 'plan')) return { action: 'plan', reasonCode: 'PLAN_ARTIFACT_MISSING', evidence: ['plan artifact is absent'] };
169
+ if (!hasArtifact(facts, 'review-plan') || !reviewMatchesLatest(facts, 'plan', 'review-plan')) {
170
+ return { action: 'review-plan', reasonCode: 'PLAN_REVIEW_MISSING', evidence: ['plan review does not bind the latest plan artifact'] };
171
+ }
172
+ if (facts.reviews['review-plan'] !== 'approved' || facts.unresolvedLedger.plan > 0) {
173
+ return { action: 'plan', reasonCode: 'PLAN_REWORK_REQUIRED', evidence: ['plan review or ledger is not clear'] };
174
+ }
175
+ if (!hasArtifact(facts, 'code')) return { action: 'code', reasonCode: 'CODE_ARTIFACT_MISSING', evidence: ['code artifact is absent'] };
176
+ if (!hasArtifact(facts, 'review-code') || !reviewMatchesLatest(facts, 'code', 'review-code')) {
177
+ return { action: 'review-code', reasonCode: 'CODE_REVIEW_MISSING', evidence: ['code review does not bind the latest code artifact'] };
178
+ }
179
+ if (facts.reviews['review-code'] !== 'approved') {
180
+ return { action: 'code', reasonCode: 'CODE_REWORK_REQUIRED', evidence: ['code review or ledger is not clear'] };
181
+ }
182
+ return { action: null, reasonCode: 'LIFECYCLE_REVIEWED', evidence: ['latest code review is approved'] };
183
+ }
184
+
185
+ function buildLifecycleFacts(taskDir: string, content: string, taskState = 'active', executionBusy = false): LifecycleFactsResult {
186
+ try {
187
+ const metadata = parseTypedTaskFrontmatter(content);
188
+ const invalidation = parseInvalidationDocument(content);
189
+ if (!invalidation.ok) return { ok: false, code: 'TASK_CAPABILITY_FACTS_INVALID', message: invalidation.message };
190
+ const rework = parseReworkIntentDocument(content);
191
+ if (!rework.ok) return { ok: false, code: 'TASK_CAPABILITY_FACTS_INVALID', message: rework.message };
192
+ const ledger = parseLedgerDocument(content);
193
+ if (ledger.present) {
194
+ const invalid = validateLedgerRows(ledger.rows);
195
+ if (invalid) return { ok: false, code: 'TASK_CAPABILITY_FACTS_INVALID', message: invalid.message };
196
+ }
197
+ const files = fs.readdirSync(taskDir).filter((name) => {
198
+ if (!name.endsWith('.md')) return false;
199
+ const stat = fs.lstatSync(path.join(taskDir, name));
200
+ return stat.isFile() && !stat.isSymbolicLink();
201
+ });
202
+ const artifactFamilies = {
203
+ analysis: /^analysis(?:-r\d+)?\.md$/,
204
+ 'review-analysis': /^review-analysis(?:-r\d+)?\.md$/,
205
+ plan: /^plan(?:-r\d+)?\.md$/,
206
+ 'review-plan': /^review-plan(?:-r\d+)?\.md$/,
207
+ code: /^code(?:-r\d+)?\.md$/,
208
+ 'review-code': /^review-code(?:-r\d+)?\.md$/
209
+ } as const;
210
+ const familyFor = (name: string): keyof typeof artifactFamilies | null =>
211
+ (Object.keys(artifactFamilies) as Array<keyof typeof artifactFamilies>)
212
+ .find((family) => artifactFamilies[family].test(name)) ?? null;
213
+ const activeFiles = files.filter((name) => {
214
+ const family = familyFor(name);
215
+ return !family || !isArtifactInvalidated(invalidation.document, family, name);
216
+ });
217
+ const artifactHashes: Record<string, string> = {};
218
+ for (const name of activeFiles) artifactHashes[name] = sha256File(path.join(taskDir, name));
219
+ const artifacts: Partial<Record<LifecycleAction, readonly string[]>> = Object.fromEntries(
220
+ (Object.keys(artifactFamilies) as Array<keyof typeof artifactFamilies>).map((family) => [
221
+ family, activeFiles.filter((name) => artifactFamilies[family].test(name))
222
+ ])
223
+ ) as Partial<Record<LifecycleAction, readonly string[]>>;
224
+ const staleArtifacts: Partial<Record<LifecycleAction, readonly string[]>> = Object.fromEntries(
225
+ (Object.keys(artifactFamilies) as Array<keyof typeof artifactFamilies>).map((family) => [
226
+ family, files.filter((name) => artifactFamilies[family].test(name) && isArtifactInvalidated(invalidation.document, family, name))
227
+ ])
228
+ ) as Partial<Record<LifecycleAction, readonly string[]>>;
229
+ const reviews: LifecycleFacts['reviews'] = {};
230
+ const reviewedInputs: NonNullable<LifecycleFacts['reviewedInputs']> = {};
231
+ for (const family of ['review-analysis', 'review-plan', 'review-code'] as const) {
232
+ const latest = latestArtifact(artifacts[family] ?? []);
233
+ if (!latest) continue;
234
+ const reviewContent = fs.readFileSync(path.join(taskDir, latest), 'utf8');
235
+ const expectedFamily = family === 'review-analysis' ? 'analysis' : family === 'review-plan' ? 'plan' : 'code';
236
+ const input = reviewedInputName(reviewContent, expectedFamily);
237
+ const receipt = input ? receiptForOutput(content, latest) : null;
238
+ if (input && receipt?.input === input && artifactHashes[input] === receipt.inputSha256) reviewedInputs[family] = input;
239
+ const parsed = parseReviewSummary(reviewContent);
240
+ if (!parsed.ok) continue;
241
+ const verdict = resolveCanonicalVerdict(parsed.summary);
242
+ if (verdict.ok) reviews[family] = verdict.verdict === 'Approved' ? 'approved' : verdict.verdict === 'Changes Requested' ? 'changes-requested' : 'rejected';
243
+ }
244
+ const unresolvedLedger = { analysis: 0, plan: 0, code: 0 };
245
+ if (ledger.present) {
246
+ for (const stage of ['analysis', 'plan', 'code'] as const) unresolvedLedger[stage] = summarizeLedgerStage(ledger.rows, stage).unresolved.length;
247
+ }
248
+ const facts: LifecycleFacts = {
249
+ taskState, currentStep: String(metadata.current_step ?? ''), artifacts, reviews,
250
+ staleArtifacts, reviewedInputs, artifactHashes,
251
+ invalidation: invalidation.document, reworkIntents: rework.intents,
252
+ unresolvedLedger, executionBusy: executionBusy || hasOpenLifecycleExecution(content), recommendedAction: null
253
+ };
254
+ facts.recommendedAction = recommendNext(facts).action;
255
+ return { ok: true, facts };
256
+ } catch (error) {
257
+ return { ok: false, code: 'TASK_CAPABILITY_FACTS_INVALID', message: error instanceof Error ? error.message : String(error) };
258
+ }
259
+ }
260
+
261
+ export { buildLifecycleFacts, canStart, recommendNext };
262
+ export type { CapabilityResult, ExplicitTrigger, LifecycleAction, LifecycleFacts, LifecycleFactsResult, LifecycleRecommendation, TriggerInitiator, TriggerReason };
@@ -12,6 +12,9 @@ import { parseActivityLog, pairEntries, startedBackedRows } from '../activity-lo
12
12
  import { readRun, type OrchestrationRun } from '../orchestration.ts';
13
13
  import type { DelegationReceipt } from '../delegation-receipts.ts';
14
14
  import { statusCard, type DisplayMessage } from '../../server/display.ts';
15
+ import { invalidationBlocks, parseInvalidationDocument } from '../invalidation.ts';
16
+ import { parseReworkIntentDocument } from '../rework-intent.ts';
17
+ import { buildLifecycleFacts, recommendNext } from '../capabilities.ts';
15
18
 
16
19
  const USAGE = `Usage: ai task status [--task <ref> | -t <ref>]
17
20
 
@@ -381,6 +384,8 @@ type StatusModel = {
381
384
  workflow: WorkflowInfo;
382
385
  runtime: RuntimeInfo;
383
386
  orchestration: OrchestrationInfo;
387
+ invalidation?: { status: string; processed: number; total: number; pendingIntents: number };
388
+ recommendation?: string;
384
389
  git: GitInfo;
385
390
  };
386
391
 
@@ -429,6 +434,18 @@ function renderStatus(model: StatusModel): string[] {
429
434
  lines.push(...renderPairs(model.artifacts.groups.map((group) => [group.stage, group.files.join(', ')])));
430
435
  }
431
436
 
437
+ lines.push(
438
+ '',
439
+ 'Invalidation',
440
+ ...renderPairs([
441
+ ['status', model.invalidation?.status ?? 'unknown'],
442
+ ['processed', `${model.invalidation?.processed ?? 0}/${model.invalidation?.total ?? 0}`],
443
+ ['pending_intents', String(model.invalidation?.pendingIntents ?? 0)]
444
+ ])
445
+ );
446
+
447
+ lines.push('', 'Recommendation', ...renderPairs([['action', model.recommendation ?? DASH]]));
448
+
432
449
  lines.push(
433
450
  '',
434
451
  'Orchestration',
@@ -494,6 +511,8 @@ function renderStatus(model: StatusModel): string[] {
494
511
  }
495
512
 
496
513
  function modelTone(model: StatusModel): 'info' | 'success' | 'warning' | 'danger' | 'running' {
514
+ if (model.invalidation?.status === 'invalid') return 'danger';
515
+ if (model.invalidation?.status === 'pending' || model.invalidation?.status === 'in-progress') return 'warning';
497
516
  if (model.orchestration.status === 'paused') return 'warning';
498
517
  if (model.orchestration.status === 'running') return 'running';
499
518
  if (model.orchestration.status === 'completed') return 'success';
@@ -511,6 +530,23 @@ function buildFromResolved(input: BuildStatusModelInput): StatusModel {
511
530
  const run = input.run ?? makeRunner(input.repoRoot);
512
531
  const artifacts = enumerateArtifacts(input.taskDir);
513
532
  const workflow = collectWorkflow(content, input.now);
533
+ const invalidation = parseInvalidationDocument(content);
534
+ const rework = parseReworkIntentDocument(content);
535
+ const pendingIntents = rework.ok ? rework.intents.filter((intent) => intent.status === 'pending').length : 0;
536
+ const invalidationInfo = !invalidation.ok
537
+ ? { status: 'invalid', processed: 0, total: 0, pendingIntents }
538
+ : {
539
+ status: invalidation.present
540
+ ? invalidationBlocks(invalidation.document)
541
+ ? invalidation.document.operations.some((operation) => operation.status === 'in-progress') ? 'in-progress' : 'pending'
542
+ : 'completed'
543
+ : 'none',
544
+ processed: invalidation.document.operations.reduce((sum, operation) => sum + operation.processed, 0),
545
+ total: invalidation.document.operations.reduce((sum, operation) => sum + operation.total, 0),
546
+ pendingIntents
547
+ };
548
+ const facts = buildLifecycleFacts(input.taskDir, content, fm.status ?? 'active');
549
+ const recommendation = facts.ok ? (recommendNext(facts.facts).action ?? DASH) : DASH;
514
550
 
515
551
  return {
516
552
  taskId: input.taskId,
@@ -522,6 +558,8 @@ function buildFromResolved(input: BuildStatusModelInput): StatusModel {
522
558
  workflow,
523
559
  runtime: collectRuntime(input.taskDir, workflow, run),
524
560
  orchestration: collectOrchestration(input.taskDir),
561
+ invalidation: invalidationInfo,
562
+ recommendation,
525
563
  git: collectGit(fm.branch ?? '', run)
526
564
  };
527
565
  }
@@ -0,0 +1,137 @@
1
+ import { createHash } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ export type CheckpointIntentState = 'prepared' | 'committed' | 'synced';
6
+
7
+ export type CheckpointIntent = Readonly<{
8
+ version: 1;
9
+ taskId: string;
10
+ branch: string;
11
+ mode: 'local';
12
+ expectedHead: string;
13
+ expectedTree: string;
14
+ paths: readonly string[];
15
+ message: string;
16
+ round: number;
17
+ digest: string;
18
+ state: CheckpointIntentState;
19
+ committedHead: string | null;
20
+ createdAt: string;
21
+ updatedAt: string;
22
+ }>;
23
+
24
+ type IntentIdentity = Readonly<{
25
+ taskId: string;
26
+ branch: string;
27
+ mode: 'local';
28
+ expectedHead: string;
29
+ expectedTree: string;
30
+ paths: readonly string[];
31
+ message: string;
32
+ round: number;
33
+ }>;
34
+
35
+ function intentRoot(repoRoot: string): string {
36
+ return path.join(repoRoot, '.agents', 'workspace', '.task-commit-intents');
37
+ }
38
+
39
+ function intentPath(repoRoot: string, taskId: string): string {
40
+ return path.join(intentRoot(repoRoot), `${taskId}.json`);
41
+ }
42
+
43
+ function checkpointIntentDigest(identity: IntentIdentity): string {
44
+ return createHash('sha256').update(JSON.stringify({
45
+ taskId: identity.taskId,
46
+ branch: identity.branch,
47
+ mode: identity.mode,
48
+ expectedHead: identity.expectedHead,
49
+ expectedTree: identity.expectedTree,
50
+ paths: [...identity.paths],
51
+ message: identity.message,
52
+ round: identity.round
53
+ })).digest('hex');
54
+ }
55
+
56
+ function isIntent(value: unknown): value is CheckpointIntent {
57
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
58
+ const intent = value as Record<string, unknown>;
59
+ return intent.version === 1
60
+ && typeof intent.taskId === 'string' && intent.taskId.length > 0
61
+ && typeof intent.branch === 'string' && intent.branch.length > 0
62
+ && intent.mode === 'local'
63
+ && typeof intent.expectedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedHead)
64
+ && typeof intent.expectedTree === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedTree)
65
+ && Array.isArray(intent.paths) && intent.paths.every((item) => typeof item === 'string' && item.length > 0)
66
+ && typeof intent.message === 'string' && intent.message.length > 0
67
+ && Number.isSafeInteger(intent.round) && Number(intent.round) > 0
68
+ && typeof intent.digest === 'string' && /^[a-f0-9]{64}$/.test(intent.digest)
69
+ && ['prepared', 'committed', 'synced'].includes(String(intent.state))
70
+ && (intent.committedHead === null || (typeof intent.committedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.committedHead)))
71
+ && typeof intent.createdAt === 'string' && intent.createdAt.length > 0
72
+ && typeof intent.updatedAt === 'string' && intent.updatedAt.length > 0
73
+ && intent.digest === checkpointIntentDigest(intent as unknown as IntentIdentity);
74
+ }
75
+
76
+ function readCheckpointIntent(repoRoot: string, taskId: string): CheckpointIntent | null {
77
+ const target = intentPath(repoRoot, taskId);
78
+ if (!fs.existsSync(target)) return null;
79
+ const value = JSON.parse(fs.readFileSync(target, 'utf8')) as unknown;
80
+ if (!isIntent(value)) throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
81
+ return value;
82
+ }
83
+
84
+ function writeCheckpointIntent(repoRoot: string, value: CheckpointIntent): void {
85
+ if (!isIntent(value)) throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
86
+ const directory = intentRoot(repoRoot);
87
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
88
+ const target = intentPath(repoRoot, value.taskId);
89
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
90
+ fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
91
+ try { fs.renameSync(temporary, target); }
92
+ catch (error) {
93
+ try { fs.unlinkSync(temporary); } catch { /* preserve primary error */ }
94
+ throw error;
95
+ }
96
+ }
97
+
98
+ function updateCheckpointIntent(
99
+ value: CheckpointIntent,
100
+ patch: Partial<Pick<CheckpointIntent, 'state' | 'committedHead' | 'updatedAt'>>
101
+ ): CheckpointIntent {
102
+ const next = { ...value, ...patch };
103
+ if (next.state === 'prepared' && next.committedHead !== null) throw new Error('COMMIT_INTENT_INVALID: prepared intent cannot have a committed head');
104
+ if (next.state !== 'prepared' && !next.committedHead) throw new Error('COMMIT_INTENT_INVALID: committed intent requires a committed head');
105
+ return next;
106
+ }
107
+
108
+ function removeCheckpointIntent(repoRoot: string, taskId: string): void {
109
+ const target = intentPath(repoRoot, taskId);
110
+ try { fs.unlinkSync(target); } catch (error) {
111
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
112
+ }
113
+ }
114
+
115
+ function sameCheckpointIntent(left: CheckpointIntent, right: IntentIdentity): boolean {
116
+ return left.digest === checkpointIntentDigest(right)
117
+ && left.taskId === right.taskId
118
+ && left.branch === right.branch
119
+ && left.mode === right.mode
120
+ && left.expectedHead === right.expectedHead
121
+ && left.expectedTree === right.expectedTree
122
+ && left.message === right.message
123
+ && left.round === right.round
124
+ && JSON.stringify(left.paths) === JSON.stringify(right.paths);
125
+ }
126
+
127
+ export {
128
+ checkpointIntentDigest,
129
+ intentPath,
130
+ intentRoot,
131
+ isIntent,
132
+ readCheckpointIntent,
133
+ removeCheckpointIntent,
134
+ sameCheckpointIntent,
135
+ updateCheckpointIntent,
136
+ writeCheckpointIntent
137
+ };