@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
@@ -0,0 +1,165 @@
1
+ const REWORK_INTENT_HEADINGS = ['返工意图', 'Rework Intent'] as const;
2
+ const REWORK_INTENT_COLUMNS = [
3
+ 'intent_id', 'finding_id', 'source_artifact', 'source_sha256', 'target',
4
+ 'status', 'declared_at', 'consumed_at'
5
+ ] as const;
6
+ type ReworkTarget = 'analysis' | 'plan' | 'code';
7
+ type ReworkIntentStatus = 'pending' | 'consumed' | 'superseded';
8
+ type ReworkIntent = {
9
+ intentId: string;
10
+ findingId: string;
11
+ sourceArtifact: string;
12
+ sourceSha256: string;
13
+ target: ReworkTarget;
14
+ status: ReworkIntentStatus;
15
+ declaredAt: string;
16
+ consumedAt: string;
17
+ };
18
+ type ReworkIntentParseResult =
19
+ | { ok: true; present: boolean; intents: readonly ReworkIntent[] }
20
+ | { ok: false; code: 'TASK_REWORK_INTENT_INVALID'; message: string };
21
+
22
+ function cells(line: string): string[] | null {
23
+ const first = line.indexOf('|');
24
+ const last = line.lastIndexOf('|');
25
+ if (first < 0 || first === last || line.slice(0, first).trim() || line.slice(last + 1).trim()) return null;
26
+ const inner = line.slice(first + 1, last);
27
+ const result: string[] = [];
28
+ let start = 0;
29
+ let escaped = false;
30
+ for (let index = 0; index < inner.length; index += 1) {
31
+ const char = inner[index]!;
32
+ if (char === '|' && !escaped) {
33
+ result.push(inner.slice(start, index));
34
+ start = index + 1;
35
+ }
36
+ escaped = char === '\\' && !escaped;
37
+ if (char !== '\\') escaped = false;
38
+ }
39
+ result.push(inner.slice(start));
40
+ return result.map((cell) => cell.replace(/\\([\\|])/g, '$1').trim());
41
+ }
42
+
43
+ function sectionBody(content: string): string | null {
44
+ const heading = REWORK_INTENT_HEADINGS.map((value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
45
+ const match = new RegExp(`^##\\s+(${heading})\\s*$`, 'm').exec(content);
46
+ if (!match) return null;
47
+ const start = (match.index ?? 0) + match[0].length;
48
+ const rest = content.slice(start);
49
+ const end = rest.search(/^##\s+/m);
50
+ return rest.slice(0, end < 0 ? rest.length : end);
51
+ }
52
+
53
+ function parseReworkIntentDocument(content: string): ReworkIntentParseResult {
54
+ const body = sectionBody(content);
55
+ if (body === null) return { ok: true, present: false, intents: [] };
56
+ const lines = body.split(/\r?\n/).filter((line) => line.trim());
57
+ const header = lines[0] ? cells(lines[0]) : null;
58
+ const separator = lines[1] ? cells(lines[1]) : null;
59
+ if (!header || !separator || header.length !== REWORK_INTENT_COLUMNS.length || !header.every((value, index) => value === REWORK_INTENT_COLUMNS[index]) || !separator.every((value) => /^:?-{3,}:?$/.test(value))) {
60
+ return { ok: false, code: 'TASK_REWORK_INTENT_INVALID', message: 'rework intent section must contain its canonical table' };
61
+ }
62
+ try {
63
+ const intents = lines.slice(2).map((line) => {
64
+ const values = cells(line);
65
+ if (!values || values.length !== REWORK_INTENT_COLUMNS.length) throw new Error('rework intent row has the wrong column count');
66
+ const row = Object.fromEntries(REWORK_INTENT_COLUMNS.map((column, index) => [column, values[index]!])) as Record<string, string>;
67
+ if (!/^RI-[1-9]\d*$/.test(row.intent_id!)) throw new Error(`invalid intent id '${row.intent_id}'`);
68
+ if (!/^(AN|PL|CD)-[1-9]\d*$/.test(row.finding_id!)) throw new Error(`invalid finding id '${row.finding_id}'`);
69
+ if (!['analysis', 'plan', 'code'].includes(row.target!)) throw new Error(`invalid rework target '${row.target}'`);
70
+ if (!['pending', 'consumed', 'superseded'].includes(row.status!)) throw new Error(`invalid rework status '${row.status}'`);
71
+ if (!/^[a-f0-9]{64}$/.test(row.source_sha256!)) throw new Error(`invalid source hash for '${row.intent_id}'`);
72
+ if (!row.source_artifact || !row.declared_at) throw new Error(`rework intent '${row.intent_id}' has invalid required fields`);
73
+ const terminal = row.status === 'consumed' || row.status === 'superseded';
74
+ if (terminal !== Boolean(row.consumed_at)) throw new Error(`rework intent '${row.intent_id}' has invalid consumed_at`);
75
+ return {
76
+ intentId: row.intent_id!, findingId: row.finding_id!, sourceArtifact: row.source_artifact!,
77
+ sourceSha256: row.source_sha256!, target: row.target as ReworkTarget,
78
+ status: row.status as ReworkIntentStatus, declaredAt: row.declared_at!, consumedAt: row.consumed_at!
79
+ } satisfies ReworkIntent;
80
+ });
81
+ const ids = new Set<string>();
82
+ for (const intent of intents) {
83
+ if (ids.has(intent.intentId)) throw new Error(`duplicate intent '${intent.intentId}'`);
84
+ ids.add(intent.intentId);
85
+ }
86
+ return { ok: true, present: true, intents };
87
+ } catch (error) {
88
+ return { ok: false, code: 'TASK_REWORK_INTENT_INVALID', message: error instanceof Error ? error.message : String(error) };
89
+ }
90
+ }
91
+
92
+ function renderReworkIntents(intents: readonly ReworkIntent[]): string {
93
+ const escape = (value: string) => value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/[\r\n]/g, ' ');
94
+ return [
95
+ `| ${REWORK_INTENT_COLUMNS.join(' | ')} |`,
96
+ `| ${REWORK_INTENT_COLUMNS.map(() => '---').join(' | ')} |`,
97
+ ...intents.map((intent) => `| ${[
98
+ intent.intentId, intent.findingId, intent.sourceArtifact, intent.sourceSha256,
99
+ intent.target, intent.status, intent.declaredAt, intent.consumedAt
100
+ ].map(escape).join(' | ')} |`)
101
+ ].join('\n');
102
+ }
103
+
104
+ function upsertReworkIntent(intents: readonly ReworkIntent[], intent: ReworkIntent): { changed: boolean; intents: readonly ReworkIntent[] } {
105
+ const existing = intents.find((candidate) => candidate.intentId === intent.intentId);
106
+ if (!existing) return { changed: true, intents: [...intents, intent] };
107
+ const identity = (value: ReworkIntent) => [value.intentId, value.findingId, value.sourceArtifact, value.sourceSha256, value.target];
108
+ if (JSON.stringify(identity(existing)) !== JSON.stringify(identity(intent))) throw new Error(`intent '${intent.intentId}' identity conflicts with existing state`);
109
+ return { changed: false, intents };
110
+ }
111
+
112
+ function consumeReworkIntents(
113
+ intents: readonly ReworkIntent[],
114
+ target: ReworkTarget,
115
+ sourceHashes: Readonly<Record<string, string>>,
116
+ consumedAt: string
117
+ ): { changed: boolean; intents: readonly ReworkIntent[] } {
118
+ let changed = false;
119
+ const next = intents.map((intent) => {
120
+ if (
121
+ intent.status !== 'pending'
122
+ || intent.target !== target
123
+ || sourceHashes[intent.sourceArtifact] !== intent.sourceSha256
124
+ ) return intent;
125
+ changed = true;
126
+ return { ...intent, status: 'consumed' as const, consumedAt };
127
+ });
128
+ return { changed, intents: next };
129
+ }
130
+
131
+ function supersedeReworkIntents(
132
+ intents: readonly ReworkIntent[],
133
+ sourceArtifact: string,
134
+ sourceSha256: string,
135
+ supersededAt: string
136
+ ): { changed: boolean; intents: readonly ReworkIntent[] } {
137
+ let changed = false;
138
+ const next = intents.map((intent) => {
139
+ if (intent.status !== 'pending' || intent.sourceArtifact !== sourceArtifact || intent.sourceSha256 === sourceSha256) return intent;
140
+ changed = true;
141
+ return { ...intent, status: 'superseded' as const, consumedAt: supersededAt };
142
+ });
143
+ return { changed, intents: next };
144
+ }
145
+
146
+ function reworkIntentMutation(content: string, intents: readonly ReworkIntent[]) {
147
+ return {
148
+ kind: 'section' as const,
149
+ aliases: REWORK_INTENT_HEADINGS,
150
+ heading: /^##\s+Rework Intent\s*$/m.test(content) ? REWORK_INTENT_HEADINGS[1] : REWORK_INTENT_HEADINGS[0],
151
+ body: renderReworkIntents(intents)
152
+ };
153
+ }
154
+
155
+ export {
156
+ REWORK_INTENT_COLUMNS,
157
+ REWORK_INTENT_HEADINGS,
158
+ parseReworkIntentDocument,
159
+ renderReworkIntents,
160
+ reworkIntentMutation,
161
+ consumeReworkIntents,
162
+ supersedeReworkIntents,
163
+ upsertReworkIntent
164
+ };
165
+ export type { ReworkIntent, ReworkIntentParseResult, ReworkIntentStatus, ReworkTarget };
@@ -175,16 +175,18 @@ function matchingSections(content: string, aliases: readonly string[]) {
175
175
  const allowed = new Set(aliases);
176
176
  return linesOf(content)
177
177
  .map((line, index, lines) => {
178
- const match = /^##\s+(.+?)\s*$/.exec(line.text);
179
- if (!match?.[1] || !allowed.has(match[1])) return null;
178
+ const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line.text);
179
+ if (!match?.[2] || !allowed.has(match[2])) return null;
180
+ const level = match[1]!.length;
180
181
  let end = content.length;
181
182
  for (let i = index + 1; i < lines.length; i += 1) {
182
- if (/^##\s+/.test(lines[i]!.text)) {
183
+ const nextHeading = /^(#{2,3})\s+/.exec(lines[i]!.text);
184
+ if (nextHeading && nextHeading[1]!.length <= level) {
183
185
  end = lines[i]!.start;
184
186
  break;
185
187
  }
186
188
  }
187
- return { heading: match[1], line, bodyStart: line.end, end };
189
+ return { heading: match[2]!, line, bodyStart: line.end, end };
188
190
  })
189
191
  .filter((match): match is NonNullable<typeof match> => match !== null);
190
192
  }
@@ -0,0 +1,24 @@
1
+ const TASK_SCOPE_SKILLS: ReadonlySet<string> = new Set([
2
+ 'analyze-task',
3
+ 'block-task',
4
+ 'cancel-task',
5
+ 'check-task',
6
+ 'code-task',
7
+ 'commit',
8
+ 'complete-manual-validation',
9
+ 'complete-task',
10
+ 'create-pr',
11
+ 'plan-task',
12
+ 'review-analysis',
13
+ 'review-code',
14
+ 'review-plan',
15
+ 'run-manual-validation',
16
+ 'run-task',
17
+ 'watch-pr'
18
+ ]);
19
+
20
+ function isTaskScopeSkill(skillName: string): boolean {
21
+ return TASK_SCOPE_SKILLS.has(skillName);
22
+ }
23
+
24
+ export { TASK_SCOPE_SKILLS, isTaskScopeSkill };
@@ -224,6 +224,22 @@ function withTaskExecutionLock<T>(
224
224
  };
225
225
  const serialized = `${JSON.stringify(owner)}\n`;
226
226
  let ownsFixed = false;
227
+ let deferRelease = false;
228
+ const release = (): void => {
229
+ try {
230
+ unlinkIfPresent(candidate);
231
+ } catch {
232
+ // Candidate cleanup is best-effort and must not replace the primary result.
233
+ }
234
+ if (ownsFixed) {
235
+ try {
236
+ const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
237
+ if (current.token === token) unlinkIfPresent(fixed);
238
+ } catch {
239
+ // A missing or replaced fixed lock is not owned by this invocation.
240
+ }
241
+ }
242
+ };
227
243
  try {
228
244
  fs.mkdirSync(lockRoot, { recursive: true });
229
245
  cleanStaleCandidates(lockRoot, key, options.identityMatches ?? processIdentityMatches);
@@ -269,7 +285,12 @@ function withTaskExecutionLock<T>(
269
285
  );
270
286
  }
271
287
  unlinkIfPresent(candidate);
272
- return callback();
288
+ const value = callback();
289
+ if (value && typeof (value as { then?: unknown }).then === 'function') {
290
+ deferRelease = true;
291
+ return (value as unknown as Promise<unknown>).finally(release) as T;
292
+ }
293
+ return value;
273
294
  } catch (error) {
274
295
  if (error instanceof TaskExecutionLockError) throw error;
275
296
  if (error instanceof Error && error.name === 'OrchestrationStateError') throw error;
@@ -279,19 +300,7 @@ function withTaskExecutionLock<T>(
279
300
  { operation: ownsFixed ? 'callback' : 'acquire', errno: errno(error), key }
280
301
  );
281
302
  } finally {
282
- try {
283
- unlinkIfPresent(candidate);
284
- } catch {
285
- // Candidate cleanup is best-effort and must not replace the primary result.
286
- }
287
- if (ownsFixed) {
288
- try {
289
- const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
290
- if (current.token === token) unlinkIfPresent(fixed);
291
- } catch {
292
- // A missing or replaced fixed lock is not owned by this invocation.
293
- }
294
- }
303
+ if (!deferRelease) release();
295
304
  }
296
305
  }
297
306
 
@@ -1,6 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ import { getArtifactSchema } from './artifact-schema.ts';
5
+
4
6
  type VerificationConfig = {
5
7
  skill?: string;
6
8
  checks: Record<string, Record<string, unknown> | null>;
@@ -13,6 +15,16 @@ function loadVerificationConfig(repositoryRoot: string, skillName: string): Veri
13
15
  if (!parsed.checks || typeof parsed.checks !== 'object' || Array.isArray(parsed.checks)) {
14
16
  throw new Error(`config/verify.json has invalid checks for skill '${skillName}'`);
15
17
  }
18
+ const artifact = parsed.checks.artifact;
19
+ if (artifact && typeof artifact === 'object' && !Array.isArray(artifact)) {
20
+ const schema = artifact.schema;
21
+ if (schema !== undefined && (typeof schema !== 'string' || !getArtifactSchema(schema))) {
22
+ throw new Error(`config/verify.json has unknown artifact schema '${String(schema)}' for skill '${skillName}'`);
23
+ }
24
+ if (schema !== undefined && 'required_patterns' in artifact) {
25
+ throw new Error(`config/verify.json must not duplicate required_patterns for schema '${String(schema)}' in skill '${skillName}'`);
26
+ }
27
+ }
16
28
  return { ...(parsed.skill ? { skill: parsed.skill } : {}), checks: parsed.checks };
17
29
  }
18
30
 
@@ -34,6 +34,10 @@ import { snapshotReview } from "../git/review-snapshot.ts";
34
34
  import { OrchestrationStateError, readRun } from "./orchestration.ts";
35
35
  import { resolveDeliveryTarget } from "./delivery-target.ts";
36
36
  import { readPrDeliveryFact } from "./pr-delivery-fact.ts";
37
+ import { validateLocalArtifact } from "./local-artifact-finalization.ts";
38
+ import { validateQualificationAudit } from "./qualification-audit.ts";
39
+ import { getArtifactSchema } from "./artifact-schema.ts";
40
+ import { inspectArtifactContract } from "./artifact-operations.ts";
37
41
 
38
42
  const TASK_ENUMS = {
39
43
  type: ["feature", "bugfix", "refactor", "docs", "chore"],
@@ -88,7 +92,7 @@ let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
88
92
 
89
93
  const PLATFORM_ADAPTERS: Record<string, (context: any, shared: any) => any> = {
90
94
  "platform-sync": checkPlatformSync,
91
- "platform-sync-preflight": (context: any, shared: any) => ({ ...checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
95
+ "platform-sync-preflight": async (context: any, shared: any) => ({ ...await checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
92
96
  "required-checks": checkRequiredChecks
93
97
  };
94
98
  const OPTIONAL_PLATFORM_CHECKS = new Set(["platform-sync"]);
@@ -107,7 +111,7 @@ const sharedUtils = {
107
111
  parsePrNumber
108
112
  };
109
113
 
110
- function runCheck(type: any, context: any, shared: any): any {
114
+ async function runCheck(type: any, context: any, shared: any): Promise<any> {
111
115
  switch (type) {
112
116
  case "task-meta":
113
117
  return checkTaskMeta(context);
@@ -147,7 +151,7 @@ function runCheck(type: any, context: any, shared: any): any {
147
151
  return failResult(type, `Unsupported check type '${type}'.`);
148
152
  }
149
153
 
150
- return adapter(context, shared);
154
+ return await adapter(context, shared);
151
155
  }
152
156
  }
153
157
  }
@@ -488,7 +492,7 @@ function checkTaskMeta({ taskDir, config }: any): any {
488
492
  );
489
493
  }
490
494
 
491
- function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
495
+ async function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): Promise<any> {
492
496
  const task = loadTask(taskDir);
493
497
  if (!task.ok) return failResult('required-pr-delivery', task.message);
494
498
  let projectConfig: any = {};
@@ -503,9 +507,10 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
503
507
  if (factRead.status === 'invalid') return failResult('required-pr-delivery', factRead.error.message);
504
508
  const fact = factRead.status === 'valid' ? factRead.fact : null;
505
509
  const status = fact?.state || 'unbound';
506
- const prNumber = fact?.state === 'bound' ? fact.identity.number : null;
510
+ const prIdentity = fact?.state === 'bound' ? fact.identity.resource : null;
511
+ const prNumber = prIdentity?.kind === 'number' ? prIdentity.value : null;
507
512
  if (flow === 'disabled') return passResult('required-pr-delivery', 'Pull request delivery is disabled by project policy');
508
- if (flow === 'required' && (status !== 'bound' || prNumber === null)) {
513
+ if (flow === 'required' && (status !== 'bound' || !prIdentity)) {
509
514
  return failResult('required-pr-delivery', 'Project policy requires a bound pull request before completion');
510
515
  }
511
516
  if (flow !== 'required' && status === 'unbound') {
@@ -515,7 +520,7 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
515
520
  if (mode === 'gate') {
516
521
  return passResult('required-pr-delivery', 'Bound pull request shape is valid; merged-state inspection is reserved for hard preflight');
517
522
  }
518
- const inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
523
+ const inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
519
524
  if (inspected.status === 'blocked') {
520
525
  return blockedResult(
521
526
  'required-pr-delivery',
@@ -527,7 +532,7 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
527
532
  const repository = inspected.platform.repository?.toLowerCase() || '';
528
533
  const taskBranch = String(task.metadata.branch || '').trim();
529
534
  const deliveryBaseRef = String(task.metadata.delivery_base_ref || projectConfig.delivery?.baseRef || '').trim();
530
- if (inspected.status !== 'no-op' || !pullRequest || pullRequest.number !== prNumber) {
535
+ if (inspected.status !== 'no-op' || !pullRequest) {
531
536
  return failResult('required-pr-delivery', 'Bound pull request identity could not be verified');
532
537
  }
533
538
  if (
@@ -542,7 +547,7 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
542
547
  if (pullRequest.state !== 'closed' || !pullRequest.mergedAt || !pullRequest.mergeCommitSha) {
543
548
  return failResult('required-pr-delivery', 'Project policy requires the bound pull request to be merged');
544
549
  }
545
- return passResult('required-pr-delivery', `Pull request delivery policy satisfied (merged PR #${prNumber})`);
550
+ return passResult('required-pr-delivery', `Pull request delivery policy satisfied (merged PR ${prNumber === null ? 'identity' : `#${prNumber}`})`);
546
551
  }
547
552
  return passResult('required-pr-delivery', `Pull request delivery policy satisfied (${status})`);
548
553
  }
@@ -581,7 +586,7 @@ function loadProjectName(): any {
581
586
  }
582
587
  }
583
588
 
584
- function checkArtifact({ taskDir, config, artifactFile }: any): any {
589
+ function checkArtifact({ taskDir, config, artifactFile, skillName }: any): any {
585
590
  const resolvedArtifact = resolveArtifactPath(taskDir, config.file_pattern, artifactFile);
586
591
  if (!resolvedArtifact.ok) {
587
592
  return failResult("artifact", resolvedArtifact.message);
@@ -598,6 +603,63 @@ function checkArtifact({ taskDir, config, artifactFile }: any): any {
598
603
  }
599
604
 
600
605
  const content = fs.readFileSync(artifactPath, "utf8");
606
+ let taskContent = "";
607
+ const taskPath = path.join(taskDir, "task.md");
608
+ if (fs.existsSync(taskPath)) {
609
+ try {
610
+ taskContent = fs.readFileSync(taskPath, "utf8");
611
+ } catch (error) {
612
+ return failResult("artifact", `Cannot read task qualification contract: ${error instanceof Error ? error.message : String(error)}`);
613
+ }
614
+ }
615
+ if (taskContent && /^review-(?:analysis|plan|code)$/.test(skillName)) {
616
+ const qualification = validateQualificationAudit(taskContent, content, { artifact: path.basename(artifactPath) });
617
+ if (!qualification.ok) return failResult("artifact", `${path.basename(artifactPath)} has qualification audit errors: ${qualification.code}: ${qualification.message}`);
618
+ }
619
+ const schemaFamily = skillName === "analyze-task"
620
+ ? "analysis"
621
+ : skillName === "review-analysis"
622
+ ? "review-analysis"
623
+ : skillName === "plan-task"
624
+ ? "plan"
625
+ : skillName === "review-plan"
626
+ ? "review-plan"
627
+ : skillName === "code-task"
628
+ ? "code"
629
+ : skillName === "review-code" ? "review-code" : null;
630
+ const schema = schemaFamily ? getArtifactSchema(schemaFamily) : null;
631
+ const localFamily = skillName === "analyze-task"
632
+ ? "analysis"
633
+ : skillName === "plan-task" ? "plan" : skillName === "code-task" ? "code" : null;
634
+ if (schema) {
635
+ const structure = inspectArtifactContract(content, schema);
636
+ if (!structure.ok && !localFamily) {
637
+ return failResult("artifact", `${path.basename(artifactPath)} has shared structural errors: ${structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`);
638
+ }
639
+ }
640
+ if (localFamily) {
641
+ const local = validateLocalArtifact(content, {
642
+ family: localFamily,
643
+ ...(taskContent ? { taskContent } : {}),
644
+ artifact: path.basename(artifactPath)
645
+ });
646
+ if (!local.ok) {
647
+ return failResult(
648
+ "artifact",
649
+ `${path.basename(artifactPath)} has local structural errors: ${local.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`
650
+ );
651
+ }
652
+ return passResult(
653
+ "artifact",
654
+ `${path.basename(artifactPath)} passed (${schema?.sections.length ?? 0} sections)`
655
+ );
656
+ }
657
+ if (schema) {
658
+ return passResult(
659
+ "artifact",
660
+ `${path.basename(artifactPath)} passed (${schema.sections.length} sections)`
661
+ );
662
+ }
601
663
  const requiredSections = config.required_sections || [];
602
664
  const missingSections = requiredSections.filter(
603
665
  (section: any) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content)
@@ -764,6 +826,7 @@ function checkActivityLog({ taskDir, config }: any): any {
764
826
  let previousTimestamp = "";
765
827
  let latestAction = "";
766
828
  let latestTimestamp = "";
829
+ const doneActions: string[] = [];
767
830
 
768
831
  for (const entry of entries) {
769
832
  const match = entry.match(ACTIVITY_LOG_PATTERN);
@@ -783,6 +846,16 @@ function checkActivityLog({ taskDir, config }: any): any {
783
846
  if (!ACTIVITY_LOG_STARTED_RE.test(action)) {
784
847
  latestTimestamp = timestamp;
785
848
  latestAction = action;
849
+ doneActions.push(action);
850
+ }
851
+ }
852
+
853
+ if (config.expected_action_pattern && !new RegExp(config.expected_action_pattern).test(latestAction)) {
854
+ const expected = new RegExp(config.expected_action_pattern);
855
+ let index = doneActions.length - 1;
856
+ while (index >= 0 && doneActions[index] === 'Commit' && !expected.test(doneActions[index]!)) index -= 1;
857
+ if (index >= 0 && expected.test(doneActions[index]!)) {
858
+ latestAction = doneActions[index]!;
786
859
  }
787
860
  }
788
861
 
@@ -1031,6 +1104,7 @@ function checkManualValidation({ taskDir }: any): any {
1031
1104
  // 1. Latest review-code artifact; none -> pass (no review, check not applicable).
1032
1105
  const review = findAuthoritativeReviewCodeArtifact(taskDir);
1033
1106
  if (!review.ok) {
1107
+ if (review.error) return failResult("manual-validation", `Review-code artifact is unavailable: ${review.error}`);
1034
1108
  return passResult("manual-validation", "No review-code artifact; manual validation not applicable");
1035
1109
  }
1036
1110
  // 2. Parse the numeric manual-validation count; unparseable/null -> fail closed
@@ -1096,9 +1170,10 @@ function checkManualValidation({ taskDir }: any): any {
1096
1170
  return passResult("manual-validation", `Manual validation completed → ${artifactName}`);
1097
1171
  }
1098
1172
 
1099
- function checkPostReviewCommit({ taskDir, config }: any): any {
1173
+ async function checkPostReviewCommit({ taskDir, config }: any): Promise<any> {
1100
1174
  const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
1101
1175
  if (!reviewArtifact.ok) {
1176
+ if (reviewArtifact.error) return failResult("post-review-commit", `Review-code artifact is unavailable: ${reviewArtifact.error}`);
1102
1177
  return passResult("post-review-commit", "No review-code artifact; check inactive");
1103
1178
  }
1104
1179
 
@@ -1117,9 +1192,9 @@ function checkPostReviewCommit({ taskDir, config }: any): any {
1117
1192
  const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
1118
1193
  const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repoRoot));
1119
1194
  const hasPullRequest = fact?.state === 'bound';
1120
- let inspected: ReturnType<typeof inspectPlatformPullRequest> | null = null;
1195
+ let inspected: Awaited<ReturnType<typeof inspectPlatformPullRequest>> | null = null;
1121
1196
  if (hasPullRequest) {
1122
- inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
1197
+ inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
1123
1198
  if (!inspected.pullRequest) {
1124
1199
  const message = inspected.error?.message || "PR merge snapshot is unavailable";
1125
1200
  const code = inspected.error?.code || "PR_INSPECTION_INVALID";
@@ -1132,7 +1207,7 @@ function checkPostReviewCommit({ taskDir, config }: any): any {
1132
1207
  inspected.pullRequest.mergedAt &&
1133
1208
  inspected.pullRequest.mergeCommitSha
1134
1209
  ) {
1135
- const relation = resolveMaterializedReviewedHeadRelation({
1210
+ const relation = await resolveMaterializedReviewedHeadRelation({
1136
1211
  cwd: gitRoot,
1137
1212
  platformType: inspected.platform.type,
1138
1213
  lastReviewedCommit,
@@ -1299,6 +1374,17 @@ function checkReviewFact({ taskDir, artifactFile }: any): any {
1299
1374
  return failResult("review-fact", resolvedArtifact.message);
1300
1375
  }
1301
1376
 
1377
+ const authoritative = findAuthoritativeReviewCodeArtifact(taskDir);
1378
+ if (!authoritative.ok) {
1379
+ return failResult("review-fact", authoritative.error ?? "No active review-code artifact is available");
1380
+ }
1381
+ if (path.basename(resolvedArtifact.path) !== authoritative.fileName) {
1382
+ return failResult(
1383
+ "review-fact",
1384
+ `review-code artifact ${path.basename(resolvedArtifact.path)} is not the current active artifact ${authoritative.fileName}; re-run review-code`
1385
+ );
1386
+ }
1387
+
1302
1388
  const task = loadTask(taskDir);
1303
1389
  if (!task.ok) {
1304
1390
  return failResult("review-fact", task.message);
@@ -1655,7 +1741,7 @@ function isBlank(value: any): any {
1655
1741
  return value === undefined || value === null || String(value).trim() === "";
1656
1742
  }
1657
1743
 
1658
- function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): any {
1744
+ async function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): Promise<any> {
1659
1745
  if (repositoryRoot) repoRoot = path.resolve(repositoryRoot);
1660
1746
  else {
1661
1747
  let cursor = path.resolve(taskDir);
@@ -1668,7 +1754,7 @@ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: reque
1668
1754
  const checks = [];
1669
1755
  for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
1670
1756
  if (checkConfig === null) continue;
1671
- const result = runCheck(type, {
1757
+ const result = await runCheck(type, {
1672
1758
  mode,
1673
1759
  skillName,
1674
1760
  taskDir: path.resolve(taskDir),
@@ -1688,7 +1774,7 @@ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: reque
1688
1774
  if (config === null) return { skill: skillName, ...passResult(type, `Check '${type}' is disabled for skill '${skillName}'.`) };
1689
1775
  return {
1690
1776
  skill: skillName,
1691
- ...runCheck(type, {
1777
+ ...await runCheck(type, {
1692
1778
  skillName,
1693
1779
  taskDir: path.resolve(taskDir),
1694
1780
  artifactFile,
@@ -49,7 +49,7 @@ type TaskVerificationResult = {
49
49
  };
50
50
  type VerificationOptions = {
51
51
  repoRoot?: string;
52
- engine?: typeof verifyInProcess;
52
+ engine?: (input: Parameters<typeof verifyInProcess>[0]) => Record<string, unknown> | Promise<Record<string, unknown>>;
53
53
  manualOverride?: ManualOverrideCapability;
54
54
  };
55
55
 
@@ -91,7 +91,7 @@ function failure(request: { taskRef: string; event: string; artifact?: string },
91
91
  };
92
92
  }
93
93
 
94
- function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: string }, options: VerificationOptions = {}): TaskVerificationResult {
94
+ async function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: string }, options: VerificationOptions = {}): Promise<TaskVerificationResult> {
95
95
  const spec = VERIFICATION_CATALOG[request.event as VerificationEvent];
96
96
  if (!spec) return failure(request, 'VERIFY_EVENT_UNKNOWN', `unknown verification event '${request.event}'`);
97
97
  const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
@@ -113,7 +113,7 @@ function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: s
113
113
  const invocations: VerificationInvocation[] = [];
114
114
  const engine = options.engine ?? verifyInProcess;
115
115
  if (spec.mode === 'gate') {
116
- const payload = engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot }) as Record<string, unknown>;
116
+ const payload = await engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot });
117
117
  const status = payload.gate as 'pass' | 'fail' | 'blocked';
118
118
  if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
119
119
  invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, gate: 'pass', humanOverride: 'human-approved', originalGate: status } });
@@ -125,7 +125,7 @@ function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: s
125
125
  invocations.push({ status, exitCode: ({ pass: 0, fail: 1, blocked: 2 } as const)[status], payload });
126
126
  } else {
127
127
  for (const check of spec.checks ?? []) {
128
- const payload = engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot }) as Record<string, unknown>;
128
+ const payload = await engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot });
129
129
  const status = payload.status as 'pass' | 'fail' | 'blocked';
130
130
  if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
131
131
  invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, status: 'pass', humanOverride: 'human-approved', originalStatus: status } });
@@ -68,7 +68,7 @@ function sectionMutation(content: string): TaskMutation[] {
68
68
  const english = /^##\s+Activity Log\s*$/m.test(content);
69
69
  return [{
70
70
  kind: 'section', aliases: WORKFLOW_WARNING_HEADINGS, heading: english ? 'Workflow Warnings' : '工作流告警',
71
- body: `| ${WORKFLOW_WARNING_COLUMNS.join(' | ')} |\n|----|------|------|----------|------|--------|--------|---------|--------|-------------|------------|`
71
+ body: `| ${WORKFLOW_WARNING_COLUMNS.join(' | ')} |\n|----|------|------|----------|------|--------|---------|--------|-------------|------------|------------|`
72
72
  }];
73
73
  }
74
74
 
package/lib/task/write.ts CHANGED
@@ -16,6 +16,7 @@ import { allowsManualOverride } from './guard-override.ts';
16
16
  import type { ManualOverrideCapability } from './guard-override.ts';
17
17
  import { mutateTableRow, upsertSection } from './sections.ts';
18
18
  import { validateCurrentTaskContract } from './current-contract.ts';
19
+ import { invalidationBlocks, parseInvalidationDocument } from './invalidation.ts';
19
20
  import type {
20
21
  TableRowDeleteMutation,
21
22
  TableRowUpsertMutation
@@ -86,6 +87,8 @@ type TaskWriteErrorCode =
86
87
  | ResolveTaskRefErrorCode
87
88
  | 'TASK_STATE_MISMATCH'
88
89
  | 'TASK_CURRENT_CONTRACT_INVALID'
90
+ | 'TASK_INVALIDATION_INVALID'
91
+ | 'TASK_INVALIDATION_BLOCKED'
89
92
  | 'TASK_READ_FAILED'
90
93
  | 'TASK_DOCUMENT_INVALID'
91
94
  | 'MUTATION_INVALID'
@@ -161,6 +164,7 @@ type TaskWriteOptions = {
161
164
  randomSuffix?: () => string;
162
165
  fileSystem?: Partial<TaskFileSystem>;
163
166
  manualOverride?: ManualOverrideCapability;
167
+ invalidationContext?: 'standard' | 'source-completion' | 'reconcile';
164
168
  };
165
169
 
166
170
  const DEFAULT_FILE_SYSTEM: TaskFileSystem = {
@@ -275,6 +279,21 @@ function writeTask(request: TaskWriteRequest, options: TaskWriteOptions = {}): T
275
279
  if (!contract.ok) {
276
280
  return failure(request, identity, contract.code, contract.message);
277
281
  }
282
+ if (
283
+ invalidationBlocks(contract.invalidation)
284
+ && options.invalidationContext !== 'source-completion'
285
+ && options.invalidationContext !== 'reconcile'
286
+ ) {
287
+ return failure(
288
+ request,
289
+ identity,
290
+ 'TASK_INVALIDATION_BLOCKED',
291
+ 'task has an incomplete artifact invalidation operation; reconcile it before writing downstream state'
292
+ );
293
+ }
294
+ } else {
295
+ const invalidation = parseInvalidationDocument(original);
296
+ if (!invalidation.ok) return failure(request, identity, 'TASK_INVALIDATION_INVALID', invalidation.message);
278
297
  }
279
298
 
280
299
  let candidate = original;
package/lib/update.ts CHANGED
@@ -19,7 +19,7 @@ type UpdateConfig = {
19
19
  project: string;
20
20
  org: string;
21
21
  language: string;
22
- platform?: { type?: string };
22
+ platform?: { type?: string; providers?: Record<string, unknown> };
23
23
  prFlow?: 'required' | 'disabled';
24
24
  sandbox?: Record<string, unknown>;
25
25
  task?: { shortIdLength: number };