@fitlab-ai/agent-infra 0.9.12 → 0.9.14

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 (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -55,6 +55,7 @@ type TaskFinalizationRequest = Readonly<{
55
55
 
56
56
  type TaskFinalizationOptions = Readonly<{
57
57
  repoRoot: string;
58
+ controlBinding?: Readonly<{ generation: string; requestId: string }>;
58
59
  metadataProvider?: TaskLifecycleOptions['metadataProvider'];
59
60
  lifecycle?: typeof applyTaskLifecycle;
60
61
  commentSync?: typeof syncPlatformComment;
@@ -73,6 +74,7 @@ type TaskFinalizationReceipt = Readonly<{
73
74
  verification: FinalizationStepState;
74
75
  warningProjection: WarningProjectionState;
75
76
  warnings: readonly FinalizationWarning[];
77
+ controlBinding?: Readonly<{ generation: string; requestId: string }>;
76
78
  updatedAt: string;
77
79
  lastError: FinalizationError | null;
78
80
  }>;
@@ -146,7 +148,7 @@ function failed(
146
148
  };
147
149
  }
148
150
 
149
- function emptyReceipt(taskId: string): TaskFinalizationReceipt {
151
+ function emptyReceipt(taskId: string, controlBinding?: Readonly<{ generation: string; requestId: string }>): TaskFinalizationReceipt {
150
152
  return {
151
153
  version: RECEIPT_VERSION,
152
154
  taskId,
@@ -158,6 +160,7 @@ function emptyReceipt(taskId: string): TaskFinalizationReceipt {
158
160
  verification: 'pending',
159
161
  warningProjection: 'done',
160
162
  warnings: [],
163
+ ...(controlBinding ? { controlBinding } : {}),
161
164
  updatedAt: now(),
162
165
  lastError: null
163
166
  };
@@ -182,6 +185,7 @@ function validWarning(value: unknown): value is FinalizationWarning {
182
185
  function validateReceipt(value: unknown, taskId: string): TaskFinalizationReceipt {
183
186
  if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('receipt must be an object');
184
187
  const receipt = value as Record<string, unknown>;
188
+ const controlBinding = receipt.controlBinding as Record<string, unknown> | null | undefined;
185
189
  const states = ['pending', 'done', 'skipped'];
186
190
  if (
187
191
  receipt.version !== RECEIPT_VERSION || receipt.taskId !== taskId || receipt.intent !== 'complete'
@@ -194,6 +198,10 @@ function validateReceipt(value: unknown, taskId: string): TaskFinalizationReceip
194
198
  || !Array.isArray(receipt.warnings) || receipt.warnings.some((warning) => !validWarning(warning))
195
199
  || typeof receipt.updatedAt !== 'string'
196
200
  || (receipt.lastError !== null && (typeof receipt.lastError !== 'object' || Array.isArray(receipt.lastError)))
201
+ || (receipt.controlBinding !== undefined && (!controlBinding || typeof controlBinding !== 'object'
202
+ || Array.isArray(controlBinding)
203
+ || typeof controlBinding.generation !== 'string' || controlBinding.generation.length === 0
204
+ || typeof controlBinding.requestId !== 'string' || !/^[a-f0-9-]{16,64}$/u.test(controlBinding.requestId)))
197
205
  ) throw new Error('receipt schema is invalid');
198
206
  return receipt as TaskFinalizationReceipt;
199
207
  }
@@ -205,6 +213,18 @@ function readReceipt(repoRoot: string, taskId: string): TaskFinalizationReceipt
205
213
  return validateReceipt(value, taskId);
206
214
  }
207
215
 
216
+ function readTaskFinalizationReceipt(repoRoot: string, taskId: string): TaskFinalizationReceipt | null {
217
+ return readReceipt(path.resolve(repoRoot), taskId);
218
+ }
219
+
220
+ function controlBindingMatches(
221
+ receipt: TaskFinalizationReceipt,
222
+ binding: Readonly<{ generation: string; requestId: string }>
223
+ ): boolean {
224
+ return receipt.controlBinding?.generation === binding.generation
225
+ && receipt.controlBinding.requestId === binding.requestId;
226
+ }
227
+
208
228
  function writeReceipt(repoRoot: string, receipt: TaskFinalizationReceipt): void {
209
229
  const directory = finalizationRoot(repoRoot);
210
230
  fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
@@ -486,14 +506,14 @@ function reconcileWarningProjection(repoRoot: string, taskId: string, receipt: T
486
506
  catch { return receipt; }
487
507
  }
488
508
 
489
- function syncPendingTaskComment(input: {
509
+ async function syncPendingTaskComment(input: {
490
510
  repoRoot: string;
491
511
  taskId: string;
492
512
  agent: string;
493
513
  receipt: TaskFinalizationReceipt;
494
514
  commentSync: typeof syncPlatformComment;
495
515
  consumedCapabilities: Set<string>;
496
- }): TaskCommentSyncOutcome {
516
+ }): Promise<TaskCommentSyncOutcome> {
497
517
  const { repoRoot, taskId, agent, commentSync, consumedCapabilities } = input;
498
518
  let receipt = input.receipt;
499
519
  if (receipt.taskComment !== 'pending') {
@@ -505,7 +525,7 @@ function syncPendingTaskComment(input: {
505
525
  };
506
526
  }
507
527
  try {
508
- const result = commentSync(taskId, { kind: 'task', agent, cwd: repoRoot });
528
+ const result = await commentSync(taskId, { kind: 'task', agent, cwd: repoRoot });
509
529
  const step = commentStep(result);
510
530
  if (result.status === 'applied' || result.status === 'no-op') {
511
531
  const skipped = result.error?.code === 'ISSUE_NOT_LINKED';
@@ -569,11 +589,11 @@ function terminalResult(
569
589
  };
570
590
  }
571
591
 
572
- function applyUnderLock(
592
+ async function applyUnderLock(
573
593
  request: TaskFinalizationRequest,
574
594
  taskId: string,
575
595
  options: TaskFinalizationOptions
576
- ): TaskFinalizationResult {
596
+ ): Promise<TaskFinalizationResult> {
577
597
  const repoRoot = path.resolve(options.repoRoot);
578
598
  const lifecycle = options.lifecycle ?? applyTaskLifecycle;
579
599
  const commentSync = options.commentSync ?? syncPlatformComment;
@@ -583,16 +603,27 @@ function applyUnderLock(
583
603
  try {
584
604
  const file = receiptPath(repoRoot, taskId);
585
605
  const existed = fs.existsSync(file);
586
- receipt = readReceipt(repoRoot, taskId) ?? emptyReceipt(taskId);
606
+ receipt = readReceipt(repoRoot, taskId) ?? emptyReceipt(taskId, options.controlBinding);
587
607
  if (!existed) writeReceipt(repoRoot, receipt);
588
608
  } catch (error) {
589
609
  return failed(taskId, errorOf(error, 'TASK_FINALIZATION_RECEIPT_INVALID'));
590
610
  }
611
+ if (options.controlBinding && !controlBindingMatches(receipt, options.controlBinding)) {
612
+ const error: FinalizationError = {
613
+ code: 'TASK_FINALIZATION_CONTROL_BINDING_CONFLICT',
614
+ message: 'finalization receipt belongs to a different sandbox request or generation',
615
+ retryable: false
616
+ };
617
+ return failed(taskId, error, {
618
+ completedSteps: completedSteps(receipt),
619
+ pendingSteps: pendingSteps(receipt)
620
+ });
621
+ }
591
622
 
592
623
  const preflightState = resolveTaskRef(taskId, { repoRoot });
593
624
  if (options.preflight && preflightState.ok && preflightState.state === 'active') {
594
625
  try {
595
- const preflight = options.preflight(
626
+ const preflight = await options.preflight(
596
627
  { taskRef: taskId, event: 'complete-task.preflight' },
597
628
  { repoRoot }
598
629
  );
@@ -668,7 +699,7 @@ function applyUnderLock(
668
699
 
669
700
  let taskComment: TaskFinalizationStep | null = null;
670
701
  receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
671
- const initialComment = syncPendingTaskComment({
702
+ const initialComment = await syncPendingTaskComment({
672
703
  repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities
673
704
  });
674
705
  receipt = initialComment.receipt;
@@ -684,7 +715,7 @@ function applyUnderLock(
684
715
  if (receipt.verification !== 'pending') {
685
716
  verification = { status: 'no-op', changed: false, error: null };
686
717
  } else {
687
- const result = verify(
718
+ const result = await verify(
688
719
  { taskRef: taskId, event: 'complete-task.completed' },
689
720
  { repoRoot }
690
721
  );
@@ -695,7 +726,7 @@ function applyUnderLock(
695
726
  scope: 'verification', operation: 'succeeded'
696
727
  }, consumedCapabilities);
697
728
  receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
698
- const finalComment = syncPendingTaskComment({
729
+ const finalComment = await syncPendingTaskComment({
699
730
  repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities
700
731
  });
701
732
  receipt = finalComment.receipt;
@@ -729,7 +760,7 @@ function applyUnderLock(
729
760
  return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification }, changed);
730
761
  }
731
762
 
732
- function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): TaskFinalizationResult {
763
+ async function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
733
764
  if (request.intent !== 'complete' || !request.taskRef || !request.agent) {
734
765
  return failed(null, { code: 'TASK_FINALIZATION_PAYLOAD_INVALID', message: 'complete finalization requires taskRef and agent', retryable: false });
735
766
  }
@@ -737,7 +768,7 @@ function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFi
737
768
  const resolved = resolveTaskRef(request.taskRef, { repoRoot });
738
769
  if (!resolved.ok) return failed(resolved.taskId, { code: resolved.code, message: resolved.message, retryable: false });
739
770
  try {
740
- return withTaskExecutionLock(repoRoot, resolved.taskId, 'task-finalization.complete', () => applyUnderLock(request, resolved.taskId, options));
771
+ return await withTaskExecutionLock(repoRoot, resolved.taskId, 'task-finalization.complete', () => applyUnderLock(request, resolved.taskId, options));
741
772
  } catch (error) {
742
773
  const detail = error instanceof TaskExecutionLockError
743
774
  ? { code: error.code, message: error.message, retryable: error.code === 'ORCHESTRATION_LOCK_BUSY' }
@@ -746,7 +777,12 @@ function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFi
746
777
  }
747
778
  }
748
779
 
749
- export { applyFinalizationReceiptMutation, applyTaskFinalization, issueCapability as createFinalizationCapability };
780
+ export {
781
+ applyFinalizationReceiptMutation,
782
+ applyTaskFinalization,
783
+ issueCapability as createFinalizationCapability,
784
+ readTaskFinalizationReceipt
785
+ };
750
786
  export type {
751
787
  FinalizationError,
752
788
  FinalizationCapability,
@@ -15,7 +15,7 @@ import { inspectLifecycleExecution } from './lifecycle-execution.ts';
15
15
  import { applyLedgerIntent } from './ledger-intents.ts';
16
16
  import { bindPlatformIssue } from '../platform/issues.ts';
17
17
  import { bindPlatformPullRequest } from '../platform/pull-requests.ts';
18
- import type { GitHubClient } from '../platform/github-client.ts';
18
+ import type { PlatformClient } from '../platform/context.ts';
19
19
  import { finalizeReviewSummary } from './review-finalization.ts';
20
20
  import { resolveTaskRef } from './resolve-ref.ts';
21
21
  import { DocumentMutationError, parseTable } from './sections.ts';
@@ -25,6 +25,9 @@ import { verifyInProcess } from './verification-engine.ts';
25
25
  import { canonicalTimestamp, writeTask } from './write.ts';
26
26
  import type { TaskFileSystem, TaskWriteMetadata, TaskWriteResult } from './write.ts';
27
27
  import { readPrDeliveryFact } from './pr-delivery-fact.ts';
28
+ import { resourceIdentity, resourceIdentityNumber } from '../platform/provider-bridge.ts';
29
+ import type { ResourceIdentity } from '../platform/resource-identity.ts';
30
+ import { taskIssueIdentity } from '../platform/task-identities.ts';
28
31
 
29
32
  type Eligibility = 'eligible' | 'repair-only' | 'runtime-recovery-only' | 'never-overridable';
30
33
  type OutcomeEffect = 'apply-target' | 'retry-same-intent' | 'record-only' | 'no-write';
@@ -96,8 +99,8 @@ type HumanOverrideOptions = Readonly<{
96
99
  probeIssueNumber?: number;
97
100
  probePullRequestNumber?: number;
98
101
  probeStagingDir?: string;
99
- platformClient?: GitHubClient;
100
- effectExecutor?: (capability: ManualOverrideCapability) => OverrideError | null;
102
+ platformClient?: PlatformClient;
103
+ effectExecutor?: (capability: ManualOverrideCapability) => OverrideError | null | Promise<OverrideError | null>;
101
104
  }>;
102
105
 
103
106
  type FailureSnapshot = Readonly<{
@@ -584,7 +587,7 @@ function snapshotEvidence(
584
587
  content: string,
585
588
  frontmatter: Record<string, unknown> | null,
586
589
  producer: ProducerFailure,
587
- resource: Readonly<{ kind: 'issue' | 'pull-request'; number: number }> | null
590
+ resource: Readonly<{ kind: 'issue' | 'pull-request'; identity: ResourceIdentity; number: number | null }> | null
588
591
  ): string {
589
592
  const stableFrontmatter = frontmatter
590
593
  ? Object.fromEntries(Object.entries(frontmatter).filter(([key]) => !['updated_at', 'agent_infra_version', 'status', 'blocked_at', 'completed_at', 'cancelled_at'].includes(key)))
@@ -609,15 +612,22 @@ function resourceForSnapshot(
609
612
  policy: FailurePolicy,
610
613
  options: HumanOverrideOptions,
611
614
  frontmatter: Record<string, unknown> | null
612
- ): Readonly<{ kind: 'issue' | 'pull-request'; number: number }> | null {
615
+ ): Readonly<{ kind: 'issue' | 'pull-request'; identity: ResourceIdentity; number: number | null }> | null {
613
616
  if (policy.producerId === 'platform.issue') {
614
- const number = options.probeIssueNumber ?? toPositiveInteger(frontmatter?.issue_number);
615
- return number === null ? null : { kind: 'issue', number };
617
+ const identity = options.probeIssueNumber !== undefined
618
+ ? resourceIdentity(options.probeIssueNumber)
619
+ : taskIssueIdentity((frontmatter || {}) as Record<string, string | number | boolean | null>) || (() => {
620
+ const number = toPositiveInteger(frontmatter?.issue_number);
621
+ return number === null ? null : resourceIdentity(number);
622
+ })();
623
+ return identity ? { kind: 'issue', identity, number: resourceIdentityNumber(identity) } : null;
616
624
  }
617
625
  if (policy.producerId === 'platform.pull-request') {
618
626
  const fact = frontmatter ? readPrDeliveryFact(frontmatter) : null;
619
- const number = options.probePullRequestNumber ?? (fact?.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null);
620
- return number === null ? null : { kind: 'pull-request', number };
627
+ const identity = options.probePullRequestNumber !== undefined
628
+ ? resourceIdentity(options.probePullRequestNumber)
629
+ : fact?.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
630
+ return identity ? { kind: 'pull-request', identity, number: resourceIdentityNumber(identity) } : null;
621
631
  }
622
632
  return null;
623
633
  }
@@ -694,41 +704,52 @@ function probeNotObserved(policy: FailurePolicy): OverrideError {
694
704
  return error('OVERRIDE_FAILURE_NOT_PRESENT', `producer ${policy.producerId} did not produce ${policy.code}`);
695
705
  }
696
706
 
697
- function probePlatformFailure(
707
+ async function probePlatformFailure(
698
708
  taskRef: string,
699
709
  policy: FailurePolicy,
700
710
  resolved: ProbeTask,
701
711
  options: HumanOverrideOptions
702
- ): ProducerFailure | OverrideError {
712
+ ): Promise<ProducerFailure | OverrideError> {
703
713
  let frontmatter: ReturnType<typeof parseTypedTaskFrontmatter>;
704
714
  try {
705
715
  frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(path.join(resolved.taskDir, 'task.md'), 'utf8'));
706
716
  } catch (cause) {
707
717
  return error('OVERRIDE_DOCUMENT_INVALID', cause instanceof Error ? cause.message : String(cause));
708
718
  }
709
- const issueNumber = options.probeIssueNumber ?? toPositiveInteger(frontmatter.issue_number);
719
+ const issueIdentity = options.probeIssueNumber !== undefined
720
+ ? resourceIdentity(options.probeIssueNumber)
721
+ : taskIssueIdentity(frontmatter) || (() => {
722
+ const number = toPositiveInteger(frontmatter.issue_number);
723
+ return number === null ? null : resourceIdentity(number);
724
+ })();
710
725
  const fact = readPrDeliveryFact(frontmatter);
711
- const pullRequestNumber = options.probePullRequestNumber ?? (fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null);
712
- const operation = policy.producerId === 'platform.issue'
713
- ? issueNumber === null
726
+ const pullRequestIdentity = options.probePullRequestNumber !== undefined
727
+ ? resourceIdentity(options.probePullRequestNumber)
728
+ : fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
729
+ const token = (identity: ResourceIdentity | null): string | null => identity ? String(identity.value) : null;
730
+ const issueToken = token(issueIdentity);
731
+ const pullRequestToken = token(pullRequestIdentity);
732
+ const operation = await (policy.producerId === 'platform.issue'
733
+ ? issueToken === null
714
734
  ? null
715
735
  : bindPlatformIssue(taskRef, {
716
- issue: issueNumber,
736
+ issue: issueToken,
717
737
  agent: options.probeOperator ?? 'local-operator',
718
738
  dryRun: true,
719
739
  cwd: resolved.repoRoot,
720
740
  ...(options.platformClient ? { client: options.platformClient } : {})
721
741
  })
722
- : pullRequestNumber === null
742
+ : pullRequestToken === null
723
743
  ? null
724
744
  : bindPlatformPullRequest(taskRef, {
725
- pr: pullRequestNumber,
745
+ pr: pullRequestToken,
726
746
  agent: options.probeOperator ?? 'local-operator',
727
747
  dryRun: true,
728
748
  cwd: resolved.repoRoot,
729
749
  ...(options.platformClient ? { client: options.platformClient } : {})
730
- });
731
- if (!operation) return error('OVERRIDE_PROBE_INPUT_MISSING', `${policy.producerId} requires a bound issue or pull request number`);
750
+ })
751
+ );
752
+ if (!operation) return error('OVERRIDE_PROBE_INPUT_MISSING', `${policy.producerId} requires a bound issue or pull request identity`);
732
753
  if (operation.status !== 'failed' && operation.status !== 'blocked') return probeNotObserved(policy);
733
754
  if (!operation.error) return error('OVERRIDE_PROBE_INPUT_MISSING', `${policy.producerId} returned no platform error evidence`);
734
755
  return {
@@ -766,6 +787,9 @@ function probeTaskEventFailure(taskRef: string, policy: FailurePolicy, resolved:
766
787
  event: candidate.event,
767
788
  agent: 'codex',
768
789
  dryRun: true,
790
+ initiator: 'model',
791
+ requestId: `override-probe:${taskRef}:${candidate.event}`,
792
+ reasonCode: 'user-request',
769
793
  ...(candidate.artifact ? { artifact: candidate.artifact } : {})
770
794
  }, { repoRoot: resolved.repoRoot, lockAlreadyHeld: true });
771
795
  const matched = probeResult(policy, result, resolved.state);
@@ -774,8 +798,8 @@ function probeTaskEventFailure(taskRef: string, policy: FailurePolicy, resolved:
774
798
  return probeNotObserved(policy);
775
799
  }
776
800
 
777
- function probeVerificationFailure(taskRef: string, policy: FailurePolicy, resolved: ProbeTask): ProducerFailure | OverrideError {
778
- const result = verifyTaskEvent(
801
+ async function probeVerificationFailure(taskRef: string, policy: FailurePolicy, resolved: ProbeTask): Promise<ProducerFailure | OverrideError> {
802
+ const result = await verifyTaskEvent(
779
803
  {
780
804
  taskRef,
781
805
  event: 'review-code.completed',
@@ -795,12 +819,12 @@ function latestArtifact(taskDir: string, family: string): string | undefined {
795
819
  ));
796
820
  candidates.sort((a, b) => {
797
821
  const round = (name: string) => Number(/-r(\d+)\.md$/.exec(name)?.[1] ?? 1);
798
- return round(b) - round(a);
799
- });
822
+ return round(b) - round(a);
823
+ });
800
824
  return candidates[0];
801
825
  }
802
826
 
803
- function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTask): ProducerFailure | OverrideError {
827
+ async function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTask): Promise<ProducerFailure | OverrideError> {
804
828
  const candidates = [
805
829
  { skillName: 'review-code', family: 'review-code' },
806
830
  { skillName: 'review-plan', family: 'review-plan' },
@@ -814,7 +838,7 @@ function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTa
814
838
  const artifactFile = candidate.family ? latestArtifact(resolved.taskDir, candidate.family) : undefined;
815
839
  if (candidate.family && !artifactFile) continue;
816
840
  try {
817
- const payload = verifyInProcess({
841
+ const payload = await verifyInProcess({
818
842
  mode: 'gate',
819
843
  skillName: candidate.skillName,
820
844
  taskDir: resolved.taskDir,
@@ -838,12 +862,12 @@ function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTa
838
862
  return probeNotObserved(policy);
839
863
  }
840
864
 
841
- function probeGenericFailure(
865
+ async function probeGenericFailure(
842
866
  taskRef: string,
843
867
  policy: FailurePolicy,
844
868
  resolved: ProbeTask,
845
869
  options: HumanOverrideOptions = {}
846
- ): ProducerFailure | OverrideError {
870
+ ): Promise<ProducerFailure | OverrideError> {
847
871
  switch (policy.producerId) {
848
872
  case 'task.resolve':
849
873
  return probeNotObserved(policy);
@@ -852,9 +876,9 @@ function probeGenericFailure(
852
876
  case 'task-event':
853
877
  return probeTaskEventFailure(taskRef, policy, resolved);
854
878
  case 'task-verify':
855
- return probeVerificationFailure(taskRef, policy, resolved);
879
+ return await probeVerificationFailure(taskRef, policy, resolved);
856
880
  case 'verification-engine':
857
- return probeVerificationEngineFailure(policy, resolved);
881
+ return await probeVerificationEngineFailure(policy, resolved);
858
882
  case 'activity-intent':
859
883
  return probeResult(policy, applyPrReviewActivityIntent({
860
884
  kind: 'pr-review-start', taskRef, agent: 'codex', artifact: 'pr-review.md', head: '0'.repeat(40), dryRun: true
@@ -889,7 +913,7 @@ function probeGenericFailure(
889
913
  }
890
914
  case 'platform.issue':
891
915
  case 'platform.pull-request':
892
- return probePlatformFailure(taskRef, policy, resolved, options);
916
+ return await probePlatformFailure(taskRef, policy, resolved, options);
893
917
  default:
894
918
  return error('OVERRIDE_PROBE_INPUT_MISSING', `no producer probe is registered for ${policy.producerId}`);
895
919
  }
@@ -899,7 +923,7 @@ function isProducerFailure(value: ProducerFailure | OverrideError): value is Pro
899
923
  return 'observedFacts' in value && 'state' in value && Array.isArray(value.observedFacts);
900
924
  }
901
925
 
902
- function captureFailureSnapshot(taskRef: string, failureIdValue: string, target: string, options: HumanOverrideOptions = {}): FailureSnapshot | OverrideError {
926
+ async function captureFailureSnapshot(taskRef: string, failureIdValue: string, target: string, options: HumanOverrideOptions = {}): Promise<FailureSnapshot | OverrideError> {
903
927
  const policy = policyFor(failureIdValue);
904
928
  if (!policy) return error('OVERRIDE_FAILURE_UNKNOWN', `failure policy '${failureIdValue}' is not registered`);
905
929
  if (!policy.targets.includes(target)) return error('OVERRIDE_TARGET_INVALID', `target '${target}' is not registered for ${failureIdValue}`);
@@ -915,7 +939,7 @@ function captureFailureSnapshot(taskRef: string, failureIdValue: string, target:
915
939
  try { frontmatter = parseTypedTaskFrontmatter(content); } catch { /* probe reports an unconfirmed identity */ }
916
940
  const producer: ProducerFailure | OverrideError = policy.producerId === LIFECYCLE_PRODUCER
917
941
  ? probeLifecycleFailure(taskRef, policy, resolved, options)
918
- : probeGenericFailure(taskRef, policy, resolved, options);
942
+ : await probeGenericFailure(taskRef, policy, resolved, options);
919
943
  if (!isProducerFailure(producer)) return producer;
920
944
  const digest = computeFailureDigest(snapshotEvidence(
921
945
  resolved.taskId,
@@ -984,7 +1008,7 @@ function validateResourceNumbers(request: HumanOverrideRequest): OverrideError |
984
1008
  return null;
985
1009
  }
986
1010
 
987
- function issueHumanOverride(request: HumanOverrideRequest, options: HumanOverrideOptions = {}): HumanOverrideIssueResult {
1011
+ async function issueHumanOverride(request: HumanOverrideRequest, options: HumanOverrideOptions = {}): Promise<HumanOverrideIssueResult> {
988
1012
  const invalid = validateCommon(request);
989
1013
  if (invalid) return failedIssue(invalid.code, invalid.message);
990
1014
  const policy = policyFor(request.failureId);
@@ -1005,7 +1029,7 @@ function issueHumanOverride(request: HumanOverrideRequest, options: HumanOverrid
1005
1029
  const document = readTask(resolved.taskMdPath);
1006
1030
  if ('code' in document) return failedIssue(document.code, document.message, resolved.taskId);
1007
1031
  if (document.frontmatter.id !== resolved.taskId) return failedIssue('OVERRIDE_DOCUMENT_INVALID', 'task frontmatter id does not match resolved task', resolved.taskId);
1008
- const snapshotResult = captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
1032
+ const snapshotResult = await captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
1009
1033
  ...options,
1010
1034
  probeIntent: request.intent,
1011
1035
  probeOperator: request.operator,
@@ -1127,18 +1151,18 @@ function lifecycleRequestFor(
1127
1151
  return { taskRef, intent: 'restore', agent: operator, stagingDir, issueNumber };
1128
1152
  }
1129
1153
 
1130
- function applyOutcomeEffect(
1154
+ async function applyOutcomeEffect(
1131
1155
  request: ConsumeHumanOverrideRequest,
1132
1156
  row: Readonly<Record<string, string>>,
1133
1157
  snapshot: FailureSnapshot,
1134
1158
  outcome: Outcome,
1135
1159
  options: HumanOverrideOptions
1136
- ): OverrideError | null {
1160
+ ): Promise<OverrideError | null> {
1137
1161
  if (outcome.effect === 'no-write' || outcome.effect === 'record-only') return null;
1138
1162
  const intent = outcome.target === 'safe-close' ? 'cancel' : row.intent || request.intent;
1139
1163
  if (!intent && outcome.target === 'continue-local') {
1140
1164
  if (!options.effectExecutor) return error('OVERRIDE_EFFECT_EXECUTOR_MISSING', 'the producer must supply an effect executor for a continue-local outcome');
1141
- return options.effectExecutor({
1165
+ return await options.effectExecutor({
1142
1166
  failureId: request.failureId,
1143
1167
  operator: row.operator ?? 'local-operator',
1144
1168
  reason: row.reason ?? snapshot.message
@@ -1242,7 +1266,7 @@ function snapshotFromTicket(taskId: string, row: Readonly<Record<string, string>
1242
1266
  };
1243
1267
  }
1244
1268
 
1245
- function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: HumanOverrideOptions = {}): HumanOverrideConsumeResult {
1269
+ async function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: HumanOverrideOptions = {}): Promise<HumanOverrideConsumeResult> {
1246
1270
  const values = [request.taskRef, request.ticketId, request.failureId, request.target, request.scope];
1247
1271
  if (values.some((value) => !singleLine(value))) {
1248
1272
  return failedConsume('OVERRIDE_PAYLOAD_INVALID', 'consume fields must be non-empty single-line values', request.ticketId || null);
@@ -1278,7 +1302,7 @@ function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: Hum
1278
1302
  if (isOverrideError(recoverySnapshot)) return failedConsume(recoverySnapshot.code, recoverySnapshot.message, request.ticketId, resolved.taskId);
1279
1303
  snapshot = recoverySnapshot;
1280
1304
  } else {
1281
- const snapshotResult = captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
1305
+ const snapshotResult = await captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
1282
1306
  ...options,
1283
1307
  probeIntent: row.values.intent ? row.values.intent as TaskLifecycleIntent : request.intent,
1284
1308
  probeOperator: row.values.operator,
@@ -1323,7 +1347,7 @@ function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: Hum
1323
1347
  if (staged.status === 'planned') return failedConsume('OVERRIDE_WRITE_INVALID', 'override writes cannot be planned', request.ticketId, resolved.taskId);
1324
1348
  effectRow = { ...row.values, status: 'consuming', effect: outcome.effect, result: outcome.result, context_id: outcome.contextId, residual: `effect pending: ${outcome.residual}` };
1325
1349
  }
1326
- const effectError = applyOutcomeEffect(request, effectRow, snapshot, outcome, options);
1350
+ const effectError = await applyOutcomeEffect(request, effectRow, snapshot, outcome, options);
1327
1351
  if (effectError) return failedConsume(effectError.code, effectError.message, request.ticketId, resolved.taskId);
1328
1352
  const after = resolveTask(request.taskRef, options);
1329
1353
  if (!after.ok) return failedConsume(after.code, after.message, request.ticketId, after.taskId);
@@ -1359,7 +1383,7 @@ function diagnoseHumanOverride(failure: string, target?: string) {
1359
1383
  };
1360
1384
  }
1361
1385
 
1362
- function diagnoseHumanOverrideForTask(
1386
+ async function diagnoseHumanOverrideForTask(
1363
1387
  taskRef: string,
1364
1388
  failure?: string,
1365
1389
  target?: string,
@@ -1403,12 +1427,12 @@ function diagnoseHumanOverrideForTask(
1403
1427
  error: error('OVERRIDE_FAILURE_UNKNOWN', `failure policy '${failure}' is not registered`)
1404
1428
  };
1405
1429
  }
1406
- const probes = policies
1430
+ const probes = await Promise.all(policies
1407
1431
  .filter((policy) => !target || policy.targets.includes(target))
1408
- .map((policy) => {
1432
+ .map(async (policy) => {
1409
1433
  const producer = policy.producerId === LIFECYCLE_PRODUCER
1410
1434
  ? probeLifecycleFailure(taskRef, policy, resolved, options)
1411
- : probeGenericFailure(taskRef, policy, resolved, options);
1435
+ : await probeGenericFailure(taskRef, policy, resolved, options);
1412
1436
  const observed = isProducerFailure(producer);
1413
1437
  return {
1414
1438
  failureId: policy.id,
@@ -1422,7 +1446,7 @@ function diagnoseHumanOverrideForTask(
1422
1446
  message: observed ? producer.message : producer.message,
1423
1447
  errorCode: observed ? null : producer.code
1424
1448
  };
1425
- });
1449
+ }));
1426
1450
  const blockedBy = probes.filter((probe) => probe.status === 'observed');
1427
1451
  return {
1428
1452
  status: 'ready' as const,
package/lib/task/index.ts CHANGED
@@ -1,3 +1,8 @@
1
+ import {
2
+ PUBLIC_CLI_ROUTE_SELECTORS,
3
+ PUBLIC_CLI_SELECTOR_ALIASES
4
+ } from '../internal/cli-route-inventory.ts';
5
+
1
6
  const USAGE = `Usage: ai task <command> [options]
2
7
 
3
8
  Commands:
@@ -30,6 +35,7 @@ Examples:
30
35
  ai task status --task 11
31
36
 
32
37
  Run 'ai task <command> --help' for details.`;
38
+ const TASK_OPERATIONS = PUBLIC_CLI_ROUTE_SELECTORS.task;
33
39
 
34
40
  export async function runTask(args: string[]): Promise<void> {
35
41
  const [subcommand, ...rest] = args;
@@ -45,14 +51,21 @@ export async function runTask(args: string[]): Promise<void> {
45
51
  return;
46
52
  }
47
53
 
48
- switch (subcommand) {
54
+ const routeSelector: string = PUBLIC_CLI_SELECTOR_ALIASES.task[subcommand as keyof typeof PUBLIC_CLI_SELECTOR_ALIASES.task] ?? subcommand;
55
+ if (!TASK_OPERATIONS.includes(routeSelector as typeof TASK_OPERATIONS[number])) {
56
+ process.stderr.write(`Unknown task command: ${subcommand}\n\n`);
57
+ process.stdout.write(`${USAGE}\n`);
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+
62
+ switch (routeSelector) {
49
63
  case 'cat': {
50
64
  const { cat } = await import('./commands/cat.ts');
51
65
  cat(rest);
52
66
  break;
53
67
  }
54
- case 'decisions':
55
- case 'd': {
68
+ case 'decisions': {
56
69
  const { decisions } = await import('./commands/decisions.ts');
57
70
  decisions(rest);
58
71
  break;
@@ -0,0 +1,86 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import { parseArtifactReceipts, sha256File } from './artifact-receipts.ts';
5
+ import { invalidationMutation, parseInvalidationDocument, reconcileInvalidation } from './invalidation.ts';
6
+ import { resolveTaskRef } from './resolve-ref.ts';
7
+ import { writeTask } from './write.ts';
8
+ import type { TaskWriteOptions } from './write.ts';
9
+
10
+ type InvalidationCommandOptions = TaskWriteOptions & { now?: () => string; maxTargets?: number; dryRun?: boolean };
11
+ type InvalidationCommandResult = {
12
+ status: 'applied' | 'planned' | 'no-op' | 'failed';
13
+ changed: boolean;
14
+ taskId: string | null;
15
+ processed: number;
16
+ remaining: number;
17
+ error: { code: string; message: string } | null;
18
+ };
19
+
20
+ function reconcileTaskInvalidation(taskRef: string, options: InvalidationCommandOptions = {}): InvalidationCommandResult {
21
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
22
+ if (!resolved.ok) return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: { code: resolved.code, message: resolved.message } };
23
+ let content: string;
24
+ try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); }
25
+ catch (error) { return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: { code: 'TASK_READ_FAILED', message: error instanceof Error ? error.message : String(error) } }; }
26
+ const parsed = parseInvalidationDocument(content);
27
+ if (!parsed.ok) return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: { code: parsed.code, message: parsed.message } };
28
+ if (!parsed.present) return { status: 'no-op', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: null };
29
+ const beforePending = parsed.document.targets.filter((target) => target.status !== 'completed').length;
30
+ let receipts;
31
+ try { receipts = parseArtifactReceipts(content).rows; }
32
+ catch (error) {
33
+ if (parsed.document.targets.some((target) => target.status !== 'completed' && target.targetKind === 'receipt')) {
34
+ return {
35
+ status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
36
+ error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: error instanceof Error ? error.message : String(error) }
37
+ };
38
+ }
39
+ receipts = [];
40
+ }
41
+ for (const target of parsed.document.targets) {
42
+ if (target.status === 'completed') continue;
43
+ if (target.targetKind === 'receipt') {
44
+ const receipt = receipts.find((candidate) => candidate.output === target.targetArtifact);
45
+ if (!receipt || receipt.inputSha256 !== target.targetSha256) {
46
+ return {
47
+ status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
48
+ error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: `invalidation receipt target '${target.targetArtifact}' changed before reconcile` }
49
+ };
50
+ }
51
+ continue;
52
+ }
53
+ const targetPath = path.join(resolved.taskDir, target.targetArtifact);
54
+ try {
55
+ const stat = fs.lstatSync(targetPath);
56
+ if (!stat.isFile() || stat.isSymbolicLink() || sha256File(targetPath) !== target.targetSha256) {
57
+ return {
58
+ status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
59
+ error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: `invalidation target '${target.targetArtifact}' changed before reconcile` }
60
+ };
61
+ }
62
+ } catch {
63
+ return {
64
+ status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
65
+ error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: `invalidation target '${target.targetArtifact}' is unavailable before reconcile` }
66
+ };
67
+ }
68
+ }
69
+ const reconciled = reconcileInvalidation(parsed.document, (options.now ?? (() => new Date().toISOString()))(), options.maxTargets);
70
+ if (!reconciled.ok) return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending, error: { code: reconciled.code, message: reconciled.message } };
71
+ if (!reconciled.changed) return { status: 'no-op', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending, error: null };
72
+ const result = writeTask({
73
+ taskRef, expectedState: resolved.state, dryRun: options.dryRun,
74
+ mutations: [invalidationMutation(content, reconciled.document)]
75
+ }, { ...options, invalidationContext: 'reconcile', taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state } });
76
+ if (result.status === 'failed') return { status: 'failed', changed: false, taskId: resolved.taskId, processed: beforePending - reconciled.document.targets.filter((target) => target.status !== 'completed').length, remaining: reconciled.document.targets.filter((target) => target.status !== 'completed').length, error: result.error };
77
+ return {
78
+ status: result.status, changed: result.changed, taskId: resolved.taskId,
79
+ processed: beforePending - reconciled.document.targets.filter((target) => target.status !== 'completed').length,
80
+ remaining: reconciled.document.targets.filter((target) => target.status !== 'completed').length,
81
+ error: null
82
+ };
83
+ }
84
+
85
+ export { reconcileTaskInvalidation };
86
+ export type { InvalidationCommandOptions, InvalidationCommandResult };