@fitlab-ai/agent-infra 0.9.13 → 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/cli.ts +26 -9
  4. package/bin/internal-cli.sh +45 -0
  5. package/dist/bin/cli.js +173 -157
  6. package/dist/bin/internal-cli.js +126 -42
  7. package/dist/lib/agent-client.js +5 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  10. package/dist/lib/defaults.json +103 -103
  11. package/dist/lib/fs/durable-write.js +37 -0
  12. package/dist/lib/fs/file-lock.js +111 -0
  13. package/dist/lib/host-control/audit.js +19 -0
  14. package/dist/lib/host-control/client.js +142 -0
  15. package/dist/lib/host-control/command.js +49 -0
  16. package/dist/lib/host-control/path.js +160 -0
  17. package/dist/lib/host-control/secure-fs.js +140 -0
  18. package/dist/lib/host-control/server.js +159 -0
  19. package/dist/lib/host-control/service.js +112 -0
  20. package/dist/lib/init.js +11 -2
  21. package/dist/lib/internal/agent-client.js +5 -2
  22. package/dist/lib/internal/cli-route-inventory.js +154 -0
  23. package/dist/lib/internal/codex-lifecycle.js +15 -12
  24. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  25. package/dist/lib/internal/demo-promotion.js +322 -0
  26. package/dist/lib/internal/demo-transcript.js +454 -0
  27. package/dist/lib/internal/git-workflow.js +10 -6
  28. package/dist/lib/internal/host-control.js +28 -0
  29. package/dist/lib/internal/manual-validation.js +322 -0
  30. package/dist/lib/internal/platform-checks.js +16 -4
  31. package/dist/lib/internal/platform-comment.js +16 -4
  32. package/dist/lib/internal/platform-context.js +4 -1
  33. package/dist/lib/internal/platform-issue.js +12 -4
  34. package/dist/lib/internal/platform-metadata.js +88 -0
  35. package/dist/lib/internal/platform-pr-review.js +16 -3
  36. package/dist/lib/internal/platform-pr.js +42 -14
  37. package/dist/lib/internal/platform-release-notes.js +6 -3
  38. package/dist/lib/internal/platform-security.js +93 -0
  39. package/dist/lib/internal/pr-review-grade.js +14 -3
  40. package/dist/lib/internal/release-workflow.js +82 -89
  41. package/dist/lib/internal/sandbox-control.js +171 -7
  42. package/dist/lib/internal/task-activity.js +13 -4
  43. package/dist/lib/internal/task-artifact.js +19 -107
  44. package/dist/lib/internal/task-context.js +4 -1
  45. package/dist/lib/internal/task-create.js +48 -14
  46. package/dist/lib/internal/task-delivery.js +4 -1
  47. package/dist/lib/internal/task-event.js +38 -35
  48. package/dist/lib/internal/task-finalization.js +4 -1
  49. package/dist/lib/internal/task-invalidation.js +4 -1
  50. package/dist/lib/internal/task-ledger.js +12 -1
  51. package/dist/lib/internal/task-lifecycle.js +4 -1
  52. package/dist/lib/internal/task-operation-registry.js +519 -0
  53. package/dist/lib/internal/task-orchestration.js +12 -0
  54. package/dist/lib/internal/task-override.js +10 -3
  55. package/dist/lib/internal/task-qualification.js +90 -0
  56. package/dist/lib/internal/task-review.js +10 -52
  57. package/dist/lib/internal/task-short-id.js +11 -1
  58. package/dist/lib/internal/task-snapshot.js +4 -1
  59. package/dist/lib/internal/task-validate.js +37 -12
  60. package/dist/lib/internal/task-verify.js +5 -1
  61. package/dist/lib/internal/task-warning.js +8 -1
  62. package/dist/lib/owned-path.js +33 -0
  63. package/dist/lib/platform/check-status.js +11 -0
  64. package/dist/lib/platform/comment-safety.js +229 -0
  65. package/dist/lib/platform/completion-backfill.js +1 -1
  66. package/dist/lib/platform/github-data.js +241 -0
  67. package/dist/lib/platform/github-provider.js +248 -26
  68. package/dist/lib/platform/issue-comments.js +146 -34
  69. package/dist/lib/platform/issues.js +1 -179
  70. package/dist/lib/platform/pr-change-report.js +6 -12
  71. package/dist/lib/platform/pr-checks.js +12 -65
  72. package/dist/lib/platform/pr-summary.js +83 -10
  73. package/dist/lib/platform/provider-contract.d.ts +67 -1
  74. package/dist/lib/platform/provider-contract.js +6 -2
  75. package/dist/lib/platform/provider-validation.js +76 -3
  76. package/dist/lib/platform/pull-requests.js +117 -275
  77. package/dist/lib/platform/repository-metadata.js +377 -0
  78. package/dist/lib/platform/security-alerts.js +155 -0
  79. package/dist/lib/platform/snapshots.js +2 -0
  80. package/dist/lib/platform/verification-sync.js +154 -162
  81. package/dist/lib/process-data/index.js +7 -0
  82. package/dist/lib/release/workflow.js +1 -1
  83. package/dist/lib/run/index.js +5 -0
  84. package/dist/lib/sandbox/commands/control-status.js +22 -0
  85. package/dist/lib/sandbox/commands/create.js +39 -8
  86. package/dist/lib/sandbox/commands/ls.js +5 -0
  87. package/dist/lib/sandbox/commands/rm.js +3 -807
  88. package/dist/lib/sandbox/commands/show.js +16 -0
  89. package/dist/lib/sandbox/control/audit.js +203 -0
  90. package/dist/lib/sandbox/control/client.js +125 -12
  91. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  92. package/dist/lib/sandbox/control/container-identity.js +28 -31
  93. package/dist/lib/sandbox/control/executor.js +233 -34
  94. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  95. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  96. package/dist/lib/sandbox/control/lifecycle.js +656 -128
  97. package/dist/lib/sandbox/control/native-file-lock.js +85 -0
  98. package/dist/lib/sandbox/control/protocol.js +55 -4
  99. package/dist/lib/sandbox/control/server.js +720 -79
  100. package/dist/lib/sandbox/control/state.js +63 -3
  101. package/dist/lib/sandbox/control/task-view.js +183 -0
  102. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  103. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  104. package/dist/lib/sandbox/engines/authority.js +289 -0
  105. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  106. package/dist/lib/sandbox/index.js +7 -2
  107. package/dist/lib/sandbox/recovery.js +49 -5
  108. package/dist/lib/sandbox/removal.js +1717 -0
  109. package/dist/lib/sandbox/task-cleanup.js +217 -0
  110. package/dist/lib/sandbox/workspace-view.js +15 -15
  111. package/dist/lib/sandbox/worktree-safety.js +4 -1
  112. package/dist/lib/server/index.js +8 -0
  113. package/dist/lib/task/activity-intent.js +2 -1
  114. package/dist/lib/task/activity-log.js +30 -24
  115. package/dist/lib/task/artifact-command.js +101 -0
  116. package/dist/lib/task/artifact-lifecycle.js +71 -40
  117. package/dist/lib/task/artifact-name.js +36 -0
  118. package/dist/lib/task/artifact-operations.js +474 -0
  119. package/dist/lib/task/artifact-receipts.js +3 -15
  120. package/dist/lib/task/artifact-repair-intent.js +130 -0
  121. package/dist/lib/task/artifact-schema.js +127 -0
  122. package/dist/lib/task/capabilities.js +83 -19
  123. package/dist/lib/task/codex-orchestration.js +71 -25
  124. package/dist/lib/task/commit-identity.js +28 -0
  125. package/dist/lib/task/commit-operation.js +2 -16
  126. package/dist/lib/task/control-authority.js +375 -5
  127. package/dist/lib/task/control-recovery.js +128 -0
  128. package/dist/lib/task/create-service.js +103 -4
  129. package/dist/lib/task/create.js +80 -2
  130. package/dist/lib/task/decision-details.js +2 -46
  131. package/dist/lib/task/events.js +306 -76
  132. package/dist/lib/task/finalization-state.js +9 -0
  133. package/dist/lib/task/human-override.js +3 -6
  134. package/dist/lib/task/implementation-inputs.js +3 -3
  135. package/dist/lib/task/index.js +11 -3
  136. package/dist/lib/task/intermediate-cleanup.js +383 -0
  137. package/dist/lib/task/invalidation.js +18 -65
  138. package/dist/lib/task/ledger-intents.js +7 -22
  139. package/dist/lib/task/ledger.js +1 -3
  140. package/dist/lib/task/lifecycle.js +19 -1
  141. package/dist/lib/task/local-artifact-finalization.js +190 -290
  142. package/dist/lib/task/manual-validation-completion.js +26 -0
  143. package/dist/lib/task/manual-validation-evidence.js +130 -0
  144. package/dist/lib/task/manual-validation-receipt.js +101 -0
  145. package/dist/lib/task/manual-validation-shared.js +40 -0
  146. package/dist/lib/task/manual-validation-transaction.js +243 -0
  147. package/dist/lib/task/markdown.js +47 -0
  148. package/dist/lib/task/orchestration.js +206 -69
  149. package/dist/lib/task/qualification-audit.js +476 -0
  150. package/dist/lib/task/qualification-confirmation.js +109 -0
  151. package/dist/lib/task/qualification-intents.js +148 -0
  152. package/dist/lib/task/review-artifacts.js +23 -40
  153. package/dist/lib/task/review-command.js +25 -0
  154. package/dist/lib/task/review-finalization.js +146 -97
  155. package/dist/lib/task/review-fingerprint.js +2 -2
  156. package/dist/lib/task/sections.js +34 -54
  157. package/dist/lib/task/verification-config.js +11 -0
  158. package/dist/lib/task/verification-engine.js +170 -327
  159. package/dist/lib/task/verification.js +1 -1
  160. package/dist/lib/task/workflow-command.js +17 -0
  161. package/dist/lib/task/workflow-warning-intents.js +0 -16
  162. package/dist/lib/task/workflow-warnings.js +28 -2
  163. package/dist/lib/update.js +2 -0
  164. package/dist/lifecycle-build-manifest.json +3 -3
  165. package/lib/agent-client.ts +9 -0
  166. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  167. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  168. package/lib/fs/durable-write.ts +29 -0
  169. package/lib/fs/file-lock.ts +113 -0
  170. package/lib/host-control/audit.ts +22 -0
  171. package/lib/host-control/client.ts +172 -0
  172. package/lib/host-control/command.ts +60 -0
  173. package/lib/host-control/path.ts +167 -0
  174. package/lib/host-control/secure-fs.ts +135 -0
  175. package/lib/host-control/server.ts +180 -0
  176. package/lib/host-control/service.ts +133 -0
  177. package/lib/init.ts +15 -2
  178. package/lib/internal/agent-client.ts +4 -2
  179. package/lib/internal/cli-route-inventory.ts +142 -0
  180. package/lib/internal/codex-lifecycle.ts +14 -12
  181. package/lib/internal/codex-sandbox-controller.ts +7 -2
  182. package/lib/internal/demo-promotion.ts +354 -0
  183. package/lib/internal/demo-transcript.ts +419 -0
  184. package/lib/internal/git-workflow.ts +9 -6
  185. package/lib/internal/host-control.ts +28 -0
  186. package/lib/internal/manual-validation.ts +306 -0
  187. package/lib/internal/platform-checks.ts +12 -4
  188. package/lib/internal/platform-comment.ts +12 -4
  189. package/lib/internal/platform-context.ts +3 -1
  190. package/lib/internal/platform-issue.ts +11 -4
  191. package/lib/internal/platform-metadata.ts +70 -0
  192. package/lib/internal/platform-pr-review.ts +14 -3
  193. package/lib/internal/platform-pr.ts +38 -14
  194. package/lib/internal/platform-release-notes.ts +5 -3
  195. package/lib/internal/platform-security.ts +83 -0
  196. package/lib/internal/pr-review-grade.ts +10 -3
  197. package/lib/internal/release-workflow.ts +91 -87
  198. package/lib/internal/sandbox-control.ts +181 -6
  199. package/lib/internal/task-activity.ts +12 -4
  200. package/lib/internal/task-artifact.ts +15 -79
  201. package/lib/internal/task-context.ts +3 -1
  202. package/lib/internal/task-create.ts +76 -15
  203. package/lib/internal/task-delivery.ts +3 -1
  204. package/lib/internal/task-event.ts +21 -10
  205. package/lib/internal/task-finalization.ts +3 -1
  206. package/lib/internal/task-invalidation.ts +3 -1
  207. package/lib/internal/task-ledger.ts +11 -1
  208. package/lib/internal/task-lifecycle.ts +3 -1
  209. package/lib/internal/task-operation-registry.ts +590 -0
  210. package/lib/internal/task-orchestration.ts +12 -0
  211. package/lib/internal/task-override.ts +9 -3
  212. package/lib/internal/task-qualification.ts +61 -0
  213. package/lib/internal/task-review.ts +7 -50
  214. package/lib/internal/task-short-id.ts +10 -1
  215. package/lib/internal/task-snapshot.ts +3 -1
  216. package/lib/internal/task-validate.ts +32 -12
  217. package/lib/internal/task-verify.ts +4 -1
  218. package/lib/internal/task-warning.ts +7 -1
  219. package/lib/owned-path.ts +26 -0
  220. package/lib/platform/check-status.ts +9 -0
  221. package/lib/platform/comment-safety.ts +255 -0
  222. package/lib/platform/completion-backfill.ts +1 -1
  223. package/lib/platform/github-data.ts +322 -0
  224. package/lib/platform/github-provider.ts +244 -27
  225. package/lib/platform/issue-comments.ts +159 -35
  226. package/lib/platform/issues.ts +4 -245
  227. package/lib/platform/pr-change-report.ts +6 -12
  228. package/lib/platform/pr-checks.ts +13 -77
  229. package/lib/platform/pr-summary.ts +88 -11
  230. package/lib/platform/provider-contract.ts +78 -3
  231. package/lib/platform/provider-validation.ts +85 -3
  232. package/lib/platform/pull-requests.ts +129 -348
  233. package/lib/platform/repository-metadata.ts +453 -0
  234. package/lib/platform/security-alerts.ts +191 -0
  235. package/lib/platform/snapshots.ts +53 -0
  236. package/lib/platform/verification-sync.ts +171 -177
  237. package/lib/process-data/index.ts +7 -0
  238. package/lib/release/workflow.ts +3 -3
  239. package/lib/run/index.ts +5 -0
  240. package/lib/sandbox/commands/control-status.ts +26 -0
  241. package/lib/sandbox/commands/create.ts +53 -12
  242. package/lib/sandbox/commands/ls.ts +7 -0
  243. package/lib/sandbox/commands/rm.ts +3 -996
  244. package/lib/sandbox/commands/show.ts +16 -0
  245. package/lib/sandbox/control/audit.ts +253 -0
  246. package/lib/sandbox/control/client.ts +150 -13
  247. package/lib/sandbox/control/completed-reentry.ts +98 -0
  248. package/lib/sandbox/control/container-identity.ts +27 -43
  249. package/lib/sandbox/control/executor.ts +262 -37
  250. package/lib/sandbox/control/finalization-response.ts +29 -0
  251. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  252. package/lib/sandbox/control/lifecycle.ts +672 -18
  253. package/lib/sandbox/control/native-file-lock.ts +108 -0
  254. package/lib/sandbox/control/protocol.ts +80 -8
  255. package/lib/sandbox/control/server.ts +779 -82
  256. package/lib/sandbox/control/state.ts +84 -3
  257. package/lib/sandbox/control/task-view.ts +240 -0
  258. package/lib/sandbox/control/task-workflow.ts +95 -0
  259. package/lib/sandbox/control/workflow-executor.ts +102 -0
  260. package/lib/sandbox/engines/authority.ts +365 -0
  261. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  262. package/lib/sandbox/index.ts +9 -2
  263. package/lib/sandbox/recovery.ts +49 -6
  264. package/lib/sandbox/removal.ts +2144 -0
  265. package/lib/sandbox/task-cleanup.ts +209 -0
  266. package/lib/sandbox/workspace-view.ts +26 -18
  267. package/lib/sandbox/worktree-safety.ts +4 -1
  268. package/lib/server/index.ts +10 -0
  269. package/lib/task/activity-intent.ts +2 -2
  270. package/lib/task/activity-log.ts +27 -19
  271. package/lib/task/artifact-command.ts +104 -0
  272. package/lib/task/artifact-lifecycle.ts +66 -39
  273. package/lib/task/artifact-name.ts +55 -0
  274. package/lib/task/artifact-operations.ts +580 -0
  275. package/lib/task/artifact-receipts.ts +3 -14
  276. package/lib/task/artifact-repair-intent.ts +152 -0
  277. package/lib/task/artifact-schema.ts +163 -0
  278. package/lib/task/capabilities.ts +82 -22
  279. package/lib/task/codex-orchestration.ts +85 -24
  280. package/lib/task/commit-identity.ts +31 -0
  281. package/lib/task/commit-operation.ts +2 -16
  282. package/lib/task/control-authority.ts +513 -6
  283. package/lib/task/control-recovery.ts +174 -0
  284. package/lib/task/create-service.ts +131 -6
  285. package/lib/task/create.ts +83 -1
  286. package/lib/task/decision-details.ts +3 -71
  287. package/lib/task/events.ts +292 -75
  288. package/lib/task/finalization-state.ts +11 -0
  289. package/lib/task/human-override.ts +3 -8
  290. package/lib/task/implementation-inputs.ts +3 -3
  291. package/lib/task/index.ts +16 -3
  292. package/lib/task/intermediate-cleanup.ts +455 -0
  293. package/lib/task/invalidation.ts +18 -62
  294. package/lib/task/ledger-intents.ts +7 -24
  295. package/lib/task/ledger.ts +1 -3
  296. package/lib/task/lifecycle.ts +17 -1
  297. package/lib/task/local-artifact-finalization.ts +223 -388
  298. package/lib/task/manual-validation-completion.ts +40 -0
  299. package/lib/task/manual-validation-evidence.ts +209 -0
  300. package/lib/task/manual-validation-receipt.ts +152 -0
  301. package/lib/task/manual-validation-shared.ts +50 -0
  302. package/lib/task/manual-validation-transaction.ts +304 -0
  303. package/lib/task/markdown.ts +70 -0
  304. package/lib/task/orchestration.ts +191 -68
  305. package/lib/task/qualification-audit.ts +588 -0
  306. package/lib/task/qualification-confirmation.ts +117 -0
  307. package/lib/task/qualification-intents.ts +150 -0
  308. package/lib/task/review-artifacts.ts +21 -41
  309. package/lib/task/review-command.ts +23 -0
  310. package/lib/task/review-finalization.ts +154 -153
  311. package/lib/task/review-fingerprint.ts +2 -2
  312. package/lib/task/sections.ts +33 -52
  313. package/lib/task/verification-config.ts +12 -0
  314. package/lib/task/verification-engine.ts +165 -370
  315. package/lib/task/verification-types.ts +17 -0
  316. package/lib/task/verification.ts +1 -1
  317. package/lib/task/workflow-command.ts +18 -0
  318. package/lib/task/workflow-warning-intents.ts +0 -13
  319. package/lib/task/workflow-warnings.ts +21 -2
  320. package/lib/update.ts +6 -0
  321. package/package.json +7 -2
  322. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  323. package/templates/.agents/rules/README.en.md +2 -0
  324. package/templates/.agents/rules/README.zh-CN.md +2 -0
  325. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  326. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  327. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  328. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  329. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  330. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  331. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  332. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  333. package/templates/.agents/rules/security-alerts.en.md +8 -8
  334. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  335. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  336. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  337. package/templates/.agents/scripts/package.json +3 -0
  338. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  339. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  340. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  341. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  342. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  343. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  344. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  345. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  346. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  347. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  348. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  349. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  350. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  351. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  352. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  353. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  354. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  355. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  356. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  357. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  358. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
  359. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
  360. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  361. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  362. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
  363. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
  364. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  365. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  366. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
  367. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
  368. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  369. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  370. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  371. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  372. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  373. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  374. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  375. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  376. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  377. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  378. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  379. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  380. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  381. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  382. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  383. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  384. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  385. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  386. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  387. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  388. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  389. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  390. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  391. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  392. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  393. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  394. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  395. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  396. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  397. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  398. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  399. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  400. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  401. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  402. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  403. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  404. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  405. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  406. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
  407. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
  408. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  409. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  410. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
  411. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
  412. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  413. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  414. package/templates/.agents/skills/test/SKILL.en.md +29 -7
  415. package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
  416. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  417. package/templates/.agents/templates/task.en.md +6 -0
  418. package/templates/.agents/templates/task.zh-CN.md +6 -0
  419. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  420. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  421. package/dist/lib/platform/adapters.js +0 -56
  422. package/lib/platform/adapters.ts +0 -197
  423. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  424. package/templates/.agents/scripts/security-alerts.sh +0 -31
  425. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  426. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  427. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  428. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,152 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+
5
+ import type { ArtifactSchemaFamily } from './artifact-schema.ts';
6
+
7
+ export type ArtifactRepairPhase =
8
+ | 'orchestration.prepare'
9
+ | 'artifact.finalize-local'
10
+ | 'task-event.completed';
11
+ export type ArtifactRepairState = 'awaiting-repair' | 'finalize-ready' | 'commit-started' | 'passed' | 'consumed';
12
+
13
+ export type ArtifactRepairIntent = Readonly<{
14
+ version: 2;
15
+ taskId: string;
16
+ family: ArtifactSchemaFamily;
17
+ artifact: string;
18
+ state: ArtifactRepairState;
19
+ baselineSemanticDigest: string | null;
20
+ artifactSha256: string;
21
+ semanticDigest: string;
22
+ recoveryOperationId: string | null;
23
+ phase: ArtifactRepairPhase | null;
24
+ authorityDigest: string | null;
25
+ requestId: string;
26
+ createdAt: number;
27
+ updatedAt: number;
28
+ }>;
29
+
30
+ function intentRoot(repoRoot: string): string {
31
+ return path.join(repoRoot, '.agents', 'workspace', '.local-artifact-finalization-intents');
32
+ }
33
+
34
+ function intentPath(repoRoot: string, taskId: string, family: ArtifactSchemaFamily, artifact: string): string {
35
+ return path.join(intentRoot(repoRoot), `${taskId}-${family}-${artifact}.json`);
36
+ }
37
+
38
+ function validDigest(value: unknown): value is string {
39
+ return typeof value === 'string' && /^[a-f0-9]{64}$/u.test(value);
40
+ }
41
+
42
+ function validTaskId(value: unknown): value is string {
43
+ return typeof value === 'string' && /^TASK-\d{8}-\d{6}$/u.test(value);
44
+ }
45
+
46
+ function exactKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {
47
+ return Object.keys(value).sort().join(',') === [...keys].sort().join(',');
48
+ }
49
+
50
+ export function isArtifactRepairIntent(value: unknown): value is ArtifactRepairIntent {
51
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
52
+ const intent = value as Record<string, unknown>;
53
+ return exactKeys(intent, [
54
+ 'artifact', 'artifactSha256', 'authorityDigest', 'baselineSemanticDigest', 'createdAt',
55
+ 'family', 'phase', 'recoveryOperationId', 'requestId', 'semanticDigest', 'state',
56
+ 'taskId', 'updatedAt', 'version'
57
+ ])
58
+ && intent.version === 2
59
+ && validTaskId(intent.taskId)
60
+ && typeof intent.family === 'string'
61
+ && ['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code'].includes(intent.family)
62
+ && typeof intent.artifact === 'string' && intent.artifact.length > 0
63
+ && ['awaiting-repair', 'finalize-ready', 'commit-started', 'passed', 'consumed'].includes(String(intent.state))
64
+ && (intent.baselineSemanticDigest === null || validDigest(intent.baselineSemanticDigest))
65
+ && validDigest(intent.artifactSha256)
66
+ && validDigest(intent.semanticDigest)
67
+ && (intent.recoveryOperationId === null || (typeof intent.recoveryOperationId === 'string' && /^[a-f0-9-]{16,64}$/u.test(intent.recoveryOperationId)))
68
+ && (intent.phase === null || ['orchestration.prepare', 'artifact.finalize-local', 'task-event.completed'].includes(String(intent.phase)))
69
+ && (intent.authorityDigest === null || validDigest(intent.authorityDigest))
70
+ && typeof intent.requestId === 'string' && intent.requestId.length > 0 && !/[\r\n]/u.test(intent.requestId)
71
+ && Number.isSafeInteger(intent.createdAt) && Number.isSafeInteger(intent.updatedAt)
72
+ && (intent.state === 'awaiting-repair' ? intent.baselineSemanticDigest === intent.semanticDigest : true);
73
+ }
74
+
75
+ function readArtifactRepairIntent(
76
+ repoRoot: string,
77
+ taskId: string,
78
+ family: ArtifactSchemaFamily,
79
+ artifact: string
80
+ ): ArtifactRepairIntent | null {
81
+ const target = intentPath(repoRoot, taskId, family, artifact);
82
+ if (!fs.existsSync(target)) return null;
83
+ let value: unknown;
84
+ try { value = JSON.parse(fs.readFileSync(target, 'utf8')) as unknown; }
85
+ catch (error) { throw new Error(`ARTIFACT_REPAIR_INTENT_INVALID: ${String(error)}`); }
86
+ if (!isArtifactRepairIntent(value) || value.taskId !== taskId || value.family !== family || value.artifact !== artifact) {
87
+ throw new Error('ARTIFACT_REPAIR_INTENT_INVALID: repair provenance schema is invalid');
88
+ }
89
+ return value;
90
+ }
91
+
92
+ export function writeArtifactRepairIntent(
93
+ repoRoot: string,
94
+ value: ArtifactRepairIntent,
95
+ options: Readonly<{ expected?: ArtifactRepairIntent | null }> = {}
96
+ ): void {
97
+ if (!isArtifactRepairIntent(value)) throw new Error('ARTIFACT_REPAIR_INTENT_INVALID: repair provenance schema is invalid');
98
+ const directory = intentRoot(repoRoot);
99
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
100
+ const target = intentPath(repoRoot, value.taskId, value.family, value.artifact);
101
+ const lock = `${target}.lock`;
102
+ let descriptor: number;
103
+ try { descriptor = fs.openSync(lock, 'wx', 0o600); }
104
+ catch (error) {
105
+ if ((error as NodeJS.ErrnoException).code === 'EEXIST') {
106
+ throw new Error('ARTIFACT_REPAIR_INTENT_CONFLICT: another provenance writer owns the intent');
107
+ }
108
+ throw error;
109
+ }
110
+ try {
111
+ const current = fs.existsSync(target)
112
+ ? readArtifactRepairIntent(repoRoot, value.taskId, value.family, value.artifact)
113
+ : null;
114
+ if (!isDeepStrictEqual(current, options.expected ?? null)) {
115
+ throw new Error('ARTIFACT_REPAIR_INTENT_CONFLICT: repair provenance changed during finalization');
116
+ }
117
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
118
+ fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
119
+ try { fs.renameSync(temporary, target); }
120
+ catch (error) {
121
+ try { fs.unlinkSync(temporary); } catch { /* preserve primary error */ }
122
+ throw error;
123
+ }
124
+ } finally {
125
+ fs.closeSync(descriptor);
126
+ try { fs.unlinkSync(lock); } catch { /* preserve the primary result */ }
127
+ }
128
+ }
129
+
130
+ export function findArtifactRepairIntentsByOperation(
131
+ repoRoot: string,
132
+ operationId: string
133
+ ): readonly ArtifactRepairIntent[] {
134
+ if (!operationId || /[\r\n]/u.test(operationId)) {
135
+ throw new Error('ARTIFACT_REPAIR_OPERATION_INVALID: recovery operation id is invalid');
136
+ }
137
+ const directory = intentRoot(repoRoot);
138
+ if (!fs.existsSync(directory)) return Object.freeze([]);
139
+ return Object.freeze(fs.readdirSync(directory)
140
+ .filter((name) => name.endsWith('.json'))
141
+ .map((name) => {
142
+ const target = path.join(directory, name);
143
+ let value: unknown;
144
+ try { value = JSON.parse(fs.readFileSync(target, 'utf8')) as unknown; }
145
+ catch (error) { throw new Error(`ARTIFACT_REPAIR_INTENT_INVALID: ${String(error)}`); }
146
+ if (!isArtifactRepairIntent(value)) throw new Error('ARTIFACT_REPAIR_INTENT_INVALID: repair provenance schema is invalid');
147
+ return value;
148
+ })
149
+ .filter((value) => value.recoveryOperationId === operationId));
150
+ }
151
+
152
+ export { readArtifactRepairIntent };
@@ -0,0 +1,163 @@
1
+ import { parseArtifactName } from './artifact-name.ts';
2
+ import type { ArtifactFamily } from './artifact-name.ts';
3
+
4
+ type ArtifactSchemaFamily = Exclude<ArtifactFamily, 'manual-validation' | 'validation-run' | 'pr-review'>;
5
+ type ArtifactLocale = 'zh-CN' | 'en';
6
+ type ArtifactSection = Readonly<{
7
+ id: string;
8
+ order: number;
9
+ headings: Readonly<{ zh: string; en: string }>;
10
+ marker: string;
11
+ }>;
12
+ type ArtifactSchema = Readonly<{
13
+ family: ArtifactSchemaFamily;
14
+ title: Readonly<{ zh: string; en: string }>;
15
+ sections: readonly ArtifactSection[];
16
+ requiredPatterns: readonly string[];
17
+ }>;
18
+ type ArtifactSkeletonInput = Readonly<{
19
+ taskId: string;
20
+ family: ArtifactSchemaFamily;
21
+ artifact: string;
22
+ locale?: ArtifactLocale;
23
+ }>;
24
+
25
+ const LOCAL_SECTIONS = {
26
+ analysis: [
27
+ ['source', '需求来源', 'Requirements Source'],
28
+ ['understanding', '需求理解', 'Requirements Understanding'],
29
+ ['files', '相关文件', 'Related Files'],
30
+ ['impact', '影响评估', 'Impact Assessment'],
31
+ ['risks', '技术风险', 'Technical Risks'],
32
+ ['effort', '工作量和复杂度评估', 'Effort and Complexity Assessment'],
33
+ ['state-check', '状态核对', 'State Check']
34
+ ],
35
+ plan: [
36
+ ['understanding', '问题理解', 'Problem Understanding'],
37
+ ['constraints', '约束条件', 'Constraints'],
38
+ ['options', '方案对比', 'Options Comparison'],
39
+ ['approach', '技术方法', 'Technical Approach'],
40
+ ['steps', '实施步骤', 'Implementation Steps'],
41
+ ['files', '文件清单', 'File List'],
42
+ ['verification', '验证策略', 'Verification Strategy'],
43
+ ['state-check', '状态核对', 'State Check']
44
+ ],
45
+ code: [
46
+ ['input', '实现输入', 'Implementation Input'],
47
+ ['files', '变更文件', 'Changed Files'],
48
+ ['key-code', '关键代码说明', 'Key Code Notes'],
49
+ ['tests', '测试结果', 'Test Results'],
50
+ ['deviations', '与方案的差异', 'Differences from Plan'],
51
+ ['review-focus', '供审查关注的内容', 'Review Focus'],
52
+ ['state-check', '状态核对', 'State Check'],
53
+ ['evidence', '证据原文', 'Raw Evidence']
54
+ ],
55
+ 'review-analysis': [
56
+ ['summary', '审查摘要', 'Review Summary'],
57
+ ['coverage', '检视覆盖声明', 'Inspection Coverage'],
58
+ ['specialized-coverage', '需求分析专项覆盖', 'Requirements Analysis Coverage'],
59
+ ['traceability', '追踪矩阵', 'Traceability Matrix'],
60
+ ['issues', '问题清单', 'Findings'],
61
+ ['non-blocking', '非阻塞建议', 'Non-blocking Suggestions'],
62
+ ['manual-validation', '人工校验项', 'Manual Validation Items'],
63
+ ['conclusion', '结论与建议', 'Conclusion and Recommendation'],
64
+ ['state-check', '状态核对', 'State Check'],
65
+ ['evidence', '证据原文', 'Raw Evidence'],
66
+ ['self-critique', '自我质疑', 'Self-critique'],
67
+ ['ledger-writeback', '审查分歧账本回写', 'Review Disagreement Ledger Write-back']
68
+ ],
69
+ 'review-plan': [
70
+ ['summary', '审查摘要', 'Review Summary'],
71
+ ['coverage', '检视覆盖声明', 'Inspection Coverage'],
72
+ ['specialized-coverage', '技术方案架构覆盖', 'Technical Plan Architecture Coverage'],
73
+ ['traceability', '追踪矩阵', 'Traceability Matrix'],
74
+ ['issues', '问题清单', 'Findings'],
75
+ ['non-blocking', '非阻塞建议', 'Non-blocking Suggestions'],
76
+ ['manual-validation', '人工校验项', 'Manual Validation Items'],
77
+ ['conclusion', '结论与建议', 'Conclusion and Recommendation'],
78
+ ['state-check', '状态核对', 'State Check'],
79
+ ['evidence', '证据原文', 'Raw Evidence'],
80
+ ['self-critique', '自我质疑', 'Self-critique'],
81
+ ['ledger-writeback', '审查分歧账本回写', 'Review Disagreement Ledger Write-back']
82
+ ],
83
+ 'review-code': [
84
+ ['summary', '审查摘要', 'Review Summary'],
85
+ ['coverage', '检视覆盖声明', 'Inspection Coverage'],
86
+ ['specialized-coverage', '代码实现专项覆盖', 'Code Implementation Coverage'],
87
+ ['traceability', '追踪矩阵', 'Traceability Matrix'],
88
+ ['issues', '问题清单', 'Findings'],
89
+ ['non-blocking', '非阻塞建议', 'Non-blocking Suggestions'],
90
+ ['manual-validation', '人工校验项', 'Manual Validation Items'],
91
+ ['conclusion', '结论与建议', 'Conclusion and Recommendation'],
92
+ ['state-check', '状态核对', 'State Check'],
93
+ ['evidence', '证据原文', 'Raw Evidence'],
94
+ ['self-critique', '自我质疑', 'Self-critique'],
95
+ ['ledger-writeback', '审查分歧账本回写', 'Review Disagreement Ledger Write-back']
96
+ ]
97
+ } as const;
98
+
99
+ function buildSections(family: ArtifactSchemaFamily): readonly ArtifactSection[] {
100
+ return LOCAL_SECTIONS[family].map(([id, zh, en], index) => ({
101
+ id,
102
+ order: index + 1,
103
+ headings: { zh, en },
104
+ marker: `artifact-section:${family}:${id}`
105
+ }));
106
+ }
107
+
108
+ const ARTIFACT_SCHEMAS: readonly ArtifactSchema[] = [
109
+ { family: 'analysis', title: { zh: '需求分析报告', en: 'Requirements Analysis' }, sections: buildSections('analysis'), requiredPatterns: ['^\\$ '] },
110
+ { family: 'review-analysis', title: { zh: '需求分析审查报告', en: 'Analysis Review Report' }, sections: buildSections('review-analysis'), requiredPatterns: ['^### (?:审查决定|Approval Decision)$', '^\\$ '] },
111
+ { family: 'plan', title: { zh: '技术方案', en: 'Technical Plan' }, sections: buildSections('plan'), requiredPatterns: ['^\\$ '] },
112
+ { family: 'review-plan', title: { zh: '技术方案审查报告', en: 'Plan Review Report' }, sections: buildSections('review-plan'), requiredPatterns: ['^### (?:审查决定|Approval Decision)$', '^\\$ '] },
113
+ { family: 'code', title: { zh: '实现报告', en: 'Implementation Report' }, sections: buildSections('code'), requiredPatterns: ['^\\$ '] },
114
+ { family: 'review-code', title: { zh: '代码审查报告', en: 'Code Review Report' }, sections: buildSections('review-code'), requiredPatterns: [
115
+ '^### (?:审查决定|Approval Decision)$',
116
+ '^\\$ ',
117
+ '^- \\*\\*(?:总体结论|Overall Verdict)\\*\\*[::]\\s*(?:通过|需要修改|拒绝|Approved|Changes Requested|Rejected)\\s*$',
118
+ '^- \\*\\*(?:审查基线提交|Review Baseline Commit)\\*\\*[::]\\s*\\S',
119
+ '^- \\*\\*(?:审查差异基线|Reviewed Diff Base)\\*\\*[::]\\s*[0-9a-f]{40,64}\\s*$',
120
+ '^- \\*\\*(?:审查差异指纹|Reviewed Diff Fingerprint)\\*\\*[::]\\s*sha256:[0-9a-f]{64}\\s*$',
121
+ '^- \\*\\*(?:审查快照树|Reviewed Snapshot Tree)\\*\\*[::]\\s*[0-9a-f]{40,64}\\s*$'
122
+ ] }
123
+ ];
124
+
125
+ function getArtifactSchema(family: string): ArtifactSchema | null {
126
+ return ARTIFACT_SCHEMAS.find((schema) => schema.family === family) ?? null;
127
+ }
128
+
129
+ function renderArtifactSkeleton(input: ArtifactSkeletonInput): string {
130
+ const schema = getArtifactSchema(input.family);
131
+ if (!schema) throw new Error(`unknown artifact schema family '${input.family}'`);
132
+ const locale = input.locale ?? 'zh-CN';
133
+ const identity = parseArtifactName(input.artifact);
134
+ if (identity?.family !== input.family) throw new Error(`invalid artifact identity '${input.artifact}' for '${input.family}'`);
135
+ const round = identity.round;
136
+ const title = schema.title[locale === 'en' ? 'en' : 'zh'];
137
+ const headings = locale === 'en' ? 'en' : 'zh';
138
+ const lines = [
139
+ `<!-- artifact-context:${input.taskId}:${input.family}:${round} -->`,
140
+ `# ${title}`,
141
+ ''
142
+ ];
143
+ for (const section of schema.sections) {
144
+ lines.push(`## ${section.headings[headings]}`);
145
+ lines.push(`<!-- ${section.marker} -->`);
146
+ lines.push('<!-- artifact-slot:empty -->');
147
+ lines.push('');
148
+ }
149
+ return `${lines.join('\n').trimEnd()}\n`;
150
+ }
151
+
152
+ export {
153
+ ARTIFACT_SCHEMAS,
154
+ getArtifactSchema,
155
+ renderArtifactSkeleton
156
+ };
157
+ export type {
158
+ ArtifactLocale,
159
+ ArtifactSchema,
160
+ ArtifactSchemaFamily,
161
+ ArtifactSection,
162
+ ArtifactSkeletonInput
163
+ };
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ import { parseArtifactName } from './artifact-name.ts';
4
5
  import type { InvalidationDocument } from './invalidation.ts';
5
6
  import { invalidationBlocks, isArtifactInvalidated, parseInvalidationDocument } from './invalidation.ts';
6
7
  import { receiptForOutput } from './artifact-receipts.ts';
@@ -11,6 +12,10 @@ import { parseReworkIntentDocument } from './rework-intent.ts';
11
12
  import type { ReworkIntent } from './rework-intent.ts';
12
13
  import { sha256File } from './artifact-receipts.ts';
13
14
  import { hasOpenLifecycleExecution } from './activity-log.ts';
15
+ import { parseQualificationAudit, parseTaskQualification } from './qualification-audit.ts';
16
+ import type { QualificationAudit, TaskQualification } from './qualification-audit.ts';
17
+
18
+ const ARTIFACT_AUDIT_FAMILIES = new Set(['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code']);
14
19
 
15
20
  type LifecycleAction =
16
21
  | 'analysis' | 'review-analysis' | 'plan' | 'review-plan'
@@ -42,6 +47,8 @@ type LifecycleFacts = {
42
47
  unresolvedLedger: Record<'analysis' | 'plan' | 'code', number>;
43
48
  executionBusy: boolean;
44
49
  recommendedAction?: LifecycleAction | null;
50
+ qualificationStale?: boolean;
51
+ qualificationStaleArtifacts?: readonly string[];
45
52
  };
46
53
  type CapabilityResult = {
47
54
  allowed: boolean;
@@ -86,6 +93,9 @@ function canStart(action: LifecycleAction, facts: LifecycleFacts, trigger: Expli
86
93
  }
87
94
  if (facts.taskState !== 'active') return deny('TASK_NOT_ACTIVE', `state=${facts.taskState}`);
88
95
  if (invalidationBlocks(facts.invalidation)) return deny('INVALIDATION_INCOMPLETE');
96
+ if (facts.qualificationStale && facts.recommendedAction !== action) {
97
+ return deny('QUALIFICATION_STALE', ...(facts.qualificationStaleArtifacts ?? ['qualification audit is stale']));
98
+ }
89
99
  if (facts.executionBusy) return deny('EXECUTION_BUSY');
90
100
 
91
101
  const implicit = trigger.explicitRequest === false;
@@ -132,13 +142,9 @@ function canStart(action: LifecycleAction, facts: LifecycleFacts, trigger: Expli
132
142
  return deny('CAPABILITY_ACTION_UNKNOWN');
133
143
  }
134
144
 
135
- function artifactRound(name: string): number {
136
- const match = /-r(\d+)\.md$/.exec(name);
137
- return match ? Number(match[1]) : 1;
138
- }
139
-
140
145
  function latestArtifact(names: readonly string[]): string | null {
141
- return [...names].sort((left, right) => artifactRound(right) - artifactRound(left) || left.localeCompare(right))[0] ?? null;
146
+ return names.map(parseArtifactName).filter((identity) => identity !== null)
147
+ .sort((left, right) => right.round - left.round || left.name.localeCompare(right.name))[0]?.name ?? null;
142
148
  }
143
149
 
144
150
  function reviewedInputName(content: string, expectedFamily: 'analysis' | 'plan' | 'code'): string | null {
@@ -154,8 +160,42 @@ function reviewMatchesLatest(facts: LifecycleFacts, source: 'analysis' | 'plan'
154
160
  return Boolean(latestSource && facts.reviewedInputs?.[review] === latestSource);
155
161
  }
156
162
 
163
+ function qualificationCandidateSnapshotMatches(
164
+ audit: QualificationAudit,
165
+ qualification: TaskQualification
166
+ ): boolean {
167
+ const current = new Map(qualification.candidates.map((candidate) => [candidate.candidateId, candidate]));
168
+ return audit.candidateQualifications.length === current.size && audit.candidateQualifications.every((row) => {
169
+ const candidate = current.get(row.candidateId);
170
+ return Boolean(candidate && candidate.status === row.status && candidate.impact === row.impact
171
+ && candidate.evidence === row.evidence && candidate.constraintIds.join(',') === row.constraintIds.join(','));
172
+ });
173
+ }
174
+
175
+ const QUALIFICATION_RECOVERY_ORDER: ReadonlyArray<{ action: LifecycleAction; pattern: RegExp }> = [
176
+ { action: 'analysis', pattern: /^analysis(?:-r\d+)?\.md$/ },
177
+ { action: 'review-analysis', pattern: /^review-analysis(?:-r\d+)?\.md$/ },
178
+ { action: 'plan', pattern: /^plan(?:-r\d+)?\.md$/ },
179
+ { action: 'review-plan', pattern: /^review-plan(?:-r\d+)?\.md$/ },
180
+ { action: 'code', pattern: /^code(?:-r\d+)?\.md$/ },
181
+ { action: 'review-code', pattern: /^review-code(?:-r\d+)?\.md$/ }
182
+ ];
183
+
184
+ function qualificationRecoveryAction(facts: LifecycleFacts): LifecycleAction | null {
185
+ const stale = facts.qualificationStaleArtifacts ?? [];
186
+ return QUALIFICATION_RECOVERY_ORDER.find(({ pattern }) => stale.some((name) => pattern.test(name)))?.action ?? null;
187
+ }
188
+
157
189
  function recommendNext(facts: LifecycleFacts): LifecycleRecommendation {
158
190
  if (invalidationBlocks(facts.invalidation)) return { action: null, reasonCode: 'INVALIDATION_INCOMPLETE', evidence: ['reconcile task invalidation before routing'] };
191
+ if (facts.qualificationStale) {
192
+ const action = qualificationRecoveryAction(facts);
193
+ return {
194
+ action,
195
+ reasonCode: 'QUALIFICATION_RECOVERY_REQUIRED',
196
+ evidence: facts.qualificationStaleArtifacts ?? ['qualification audit is stale']
197
+ };
198
+ }
159
199
  const pendingIntent = (facts.reworkIntents ?? []).find((intent) => intent.status === 'pending');
160
200
  if (pendingIntent) return { action: pendingIntent.target, reasonCode: 'REWORK_INTENT_PENDING', evidence: [pendingIntent.intentId, pendingIntent.findingId] };
161
201
  if (!hasArtifact(facts, 'analysis')) return { action: 'analysis', reasonCode: 'ANALYSIS_ARTIFACT_MISSING', evidence: ['analysis artifact is absent'] };
@@ -199,17 +239,11 @@ function buildLifecycleFacts(taskDir: string, content: string, taskState = 'acti
199
239
  const stat = fs.lstatSync(path.join(taskDir, name));
200
240
  return stat.isFile() && !stat.isSymbolicLink();
201
241
  });
202
- const artifactFamilies = {
203
- analysis: /^analysis(?:-r\d+)?\.md$/,
204
- 'review-analysis': /^review-analysis(?:-r\d+)?\.md$/,
205
- plan: /^plan(?:-r\d+)?\.md$/,
206
- 'review-plan': /^review-plan(?:-r\d+)?\.md$/,
207
- code: /^code(?:-r\d+)?\.md$/,
208
- 'review-code': /^review-code(?:-r\d+)?\.md$/
209
- } as const;
210
- const familyFor = (name: string): keyof typeof artifactFamilies | null =>
211
- (Object.keys(artifactFamilies) as Array<keyof typeof artifactFamilies>)
212
- .find((family) => artifactFamilies[family].test(name)) ?? null;
242
+ const artifactFamilies = ['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code'] as const;
243
+ const familyFor = (name: string) => {
244
+ const family = parseArtifactName(name)?.family;
245
+ return artifactFamilies.find((candidate) => candidate === family) ?? null;
246
+ };
213
247
  const activeFiles = files.filter((name) => {
214
248
  const family = familyFor(name);
215
249
  return !family || !isArtifactInvalidated(invalidation.document, family, name);
@@ -217,15 +251,37 @@ function buildLifecycleFacts(taskDir: string, content: string, taskState = 'acti
217
251
  const artifactHashes: Record<string, string> = {};
218
252
  for (const name of activeFiles) artifactHashes[name] = sha256File(path.join(taskDir, name));
219
253
  const artifacts: Partial<Record<LifecycleAction, readonly string[]>> = Object.fromEntries(
220
- (Object.keys(artifactFamilies) as Array<keyof typeof artifactFamilies>).map((family) => [
221
- family, activeFiles.filter((name) => artifactFamilies[family].test(name))
254
+ artifactFamilies.map((family) => [
255
+ family, activeFiles.filter((name) => familyFor(name) === family)
222
256
  ])
223
257
  ) as Partial<Record<LifecycleAction, readonly string[]>>;
224
258
  const staleArtifacts: Partial<Record<LifecycleAction, readonly string[]>> = Object.fromEntries(
225
- (Object.keys(artifactFamilies) as Array<keyof typeof artifactFamilies>).map((family) => [
226
- family, files.filter((name) => artifactFamilies[family].test(name) && isArtifactInvalidated(invalidation.document, family, name))
259
+ artifactFamilies.map((family) => [
260
+ family, files.filter((name) => familyFor(name) === family && isArtifactInvalidated(invalidation.document, family, name))
227
261
  ])
228
262
  ) as Partial<Record<LifecycleAction, readonly string[]>>;
263
+ const qualification = parseTaskQualification(content);
264
+ if (!qualification.ok) return { ok: false, code: 'TASK_CAPABILITY_FACTS_INVALID', message: qualification.message };
265
+ const qualificationStaleArtifacts: string[] = [];
266
+ if (qualification.qualification.present) {
267
+ const constraints = new Map(qualification.qualification.constraints.map((row) => [row.constraintId, row.digest]));
268
+ for (const family of artifactFamilies) {
269
+ if (!ARTIFACT_AUDIT_FAMILIES.has(family)) continue;
270
+ const name = latestArtifact(artifacts[family] ?? []);
271
+ if (!name) continue;
272
+ let auditContent: string;
273
+ try { auditContent = fs.readFileSync(path.join(taskDir, name), 'utf8'); }
274
+ catch { qualificationStaleArtifacts.push(name); continue; }
275
+ const audit = parseQualificationAudit(auditContent);
276
+ if (!audit.ok || !audit.audit.present || !audit.audit.snapshot) { qualificationStaleArtifacts.push(name); continue; }
277
+ const constraintsChanged = audit.audit.constraintDependencies.some((dependency) => constraints.get(dependency.constraintId) !== dependency.constraintDigest);
278
+ const taskInputChanged = audit.audit.snapshot.taskInputDigest !== qualification.qualification.taskInputDigest;
279
+ if (audit.audit.snapshot.nonConstraintInputDigest !== qualification.qualification.nonConstraintInputDigest
280
+ || constraintsChanged
281
+ || (taskInputChanged && !constraintsChanged)
282
+ || (taskInputChanged && !qualificationCandidateSnapshotMatches(audit.audit, qualification.qualification))) qualificationStaleArtifacts.push(name);
283
+ }
284
+ }
229
285
  const reviews: LifecycleFacts['reviews'] = {};
230
286
  const reviewedInputs: NonNullable<LifecycleFacts['reviewedInputs']> = {};
231
287
  for (const family of ['review-analysis', 'review-plan', 'review-code'] as const) {
@@ -249,7 +305,11 @@ function buildLifecycleFacts(taskDir: string, content: string, taskState = 'acti
249
305
  taskState, currentStep: String(metadata.current_step ?? ''), artifacts, reviews,
250
306
  staleArtifacts, reviewedInputs, artifactHashes,
251
307
  invalidation: invalidation.document, reworkIntents: rework.intents,
252
- unresolvedLedger, executionBusy: executionBusy || hasOpenLifecycleExecution(content), recommendedAction: null
308
+ unresolvedLedger,
309
+ executionBusy: executionBusy || hasOpenLifecycleExecution(content),
310
+ recommendedAction: null,
311
+ qualificationStale: qualificationStaleArtifacts.length > 0,
312
+ qualificationStaleArtifacts
253
313
  };
254
314
  facts.recommendedAction = recommendNext(facts).action;
255
315
  return { ok: true, facts };