@fitlab-ai/agent-infra 0.8.4 → 0.9.0

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 (443) hide show
  1. package/bin/cli.ts +2 -2
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/bin/internal-cli.js +98 -0
  4. package/dist/lib/decide.js +81 -90
  5. package/dist/lib/defaults.json +9 -0
  6. package/dist/lib/git/review-snapshot.js +79 -0
  7. package/dist/lib/git/workflow.js +101 -0
  8. package/dist/lib/init.js +5 -0
  9. package/dist/lib/internal/git-workflow.js +42 -0
  10. package/dist/lib/internal/platform-checks.js +119 -0
  11. package/dist/lib/internal/platform-comment.js +129 -0
  12. package/dist/lib/internal/platform-context.js +46 -0
  13. package/dist/lib/internal/platform-issue.js +142 -0
  14. package/dist/lib/internal/platform-pr.js +146 -0
  15. package/dist/lib/internal/release-workflow.js +217 -0
  16. package/dist/lib/internal/task-artifact.js +67 -0
  17. package/dist/lib/internal/task-context.js +43 -0
  18. package/dist/lib/internal/task-event.js +70 -0
  19. package/dist/lib/internal/task-ledger.js +114 -0
  20. package/dist/lib/internal/task-lifecycle.js +58 -0
  21. package/dist/lib/internal/task-short-id.js +83 -0
  22. package/dist/lib/internal/task-snapshot.js +47 -0
  23. package/dist/lib/internal/task-verify.js +50 -0
  24. package/dist/lib/internal/task-warning.js +74 -0
  25. package/dist/lib/platform/adapters.js +14 -0
  26. package/dist/lib/platform/context.js +146 -0
  27. package/dist/lib/platform/github-client.js +124 -0
  28. package/dist/lib/platform/issue-comments.js +409 -0
  29. package/dist/lib/platform/issue-metadata.js +183 -0
  30. package/dist/lib/platform/issues.js +617 -0
  31. package/dist/lib/platform/metadata-labels.js +28 -0
  32. package/dist/lib/platform/pr-checks.js +216 -0
  33. package/dist/lib/platform/pr-summary.js +88 -0
  34. package/dist/lib/platform/pull-request-metadata.js +38 -0
  35. package/dist/lib/platform/pull-requests.js +338 -0
  36. package/dist/lib/platform/releases.js +82 -0
  37. package/dist/lib/platform/types.js +22 -0
  38. package/dist/lib/platform/verification-required.js +78 -0
  39. package/dist/lib/platform/verification-sync.js +1014 -0
  40. package/dist/lib/platform/verification.js +6 -0
  41. package/dist/lib/release/channels.js +31 -0
  42. package/dist/lib/release/workflow.js +32 -0
  43. package/dist/lib/render.js +3 -2
  44. package/dist/lib/run/index.js +24 -7
  45. package/dist/lib/sandbox/capture.js +25 -3
  46. package/dist/lib/sandbox/commands/create.js +66 -26
  47. package/dist/lib/sandbox/commands/enter.js +34 -11
  48. package/dist/lib/sandbox/commands/list-running.js +10 -8
  49. package/dist/lib/sandbox/commands/show.js +2 -2
  50. package/dist/lib/sandbox/commands/start.js +53 -15
  51. package/dist/lib/sandbox/engine.js +33 -3
  52. package/dist/lib/sandbox/engines/colima.js +2 -2
  53. package/dist/lib/sandbox/index.js +6 -6
  54. package/dist/lib/sandbox/mounts.js +36 -0
  55. package/dist/lib/sandbox/recovery.js +562 -0
  56. package/dist/lib/sandbox/runtimes/base.dockerfile +4 -0
  57. package/dist/lib/sandbox/task-resolver.js +5 -1
  58. package/dist/lib/sandbox/tools.js +19 -0
  59. package/dist/lib/server/daemon.js +9 -0
  60. package/dist/lib/server/process-control.js +66 -73
  61. package/dist/lib/server/process-state.js +168 -0
  62. package/dist/lib/server/protocol.js +5 -5
  63. package/dist/lib/task/activity-log.js +61 -0
  64. package/dist/lib/task/artifact-lifecycle.js +427 -0
  65. package/dist/lib/task/command-options.js +30 -0
  66. package/dist/lib/task/commands/cat.js +36 -6
  67. package/dist/lib/task/commands/decisions.js +80 -46
  68. package/dist/lib/task/commands/files.js +21 -7
  69. package/dist/lib/task/commands/grep.js +55 -7
  70. package/dist/lib/task/commands/issue-body.js +23 -14
  71. package/dist/lib/task/commands/log.js +27 -70
  72. package/dist/lib/task/commands/show.js +20 -7
  73. package/dist/lib/task/commands/status.js +18 -8
  74. package/dist/lib/task/decision-intents.js +154 -0
  75. package/dist/lib/task/decision-items.js +53 -0
  76. package/dist/lib/task/events.js +318 -0
  77. package/dist/lib/task/frontmatter.js +159 -1
  78. package/dist/lib/task/implementation-inputs.js +117 -0
  79. package/dist/lib/task/index.js +12 -9
  80. package/dist/lib/task/issue-form.js +19 -6
  81. package/dist/lib/task/ledger-intents.js +185 -0
  82. package/dist/lib/task/ledger.js +65 -35
  83. package/dist/lib/task/lifecycle.js +484 -0
  84. package/dist/lib/task/resolve-ref.js +152 -32
  85. package/dist/lib/task/review-artifacts.js +101 -0
  86. package/dist/lib/task/review-fingerprint.js +46 -0
  87. package/dist/lib/task/sections.js +358 -4
  88. package/dist/lib/task/short-id.js +292 -7
  89. package/dist/lib/task/snapshot.js +95 -0
  90. package/dist/lib/task/verification-checks.js +8 -0
  91. package/dist/lib/task/verification-config.js +14 -0
  92. package/dist/lib/task/verification-engine.js +906 -0
  93. package/dist/lib/task/verification-review.js +3 -0
  94. package/dist/lib/task/verification-types.js +2 -0
  95. package/dist/lib/task/verification.js +113 -0
  96. package/dist/lib/task/workflow-warning-intents.js +131 -0
  97. package/dist/lib/task/workflow-warnings.js +10 -78
  98. package/dist/lib/task/write.js +241 -0
  99. package/dist/lib/update.js +2 -0
  100. package/lib/decide.ts +57 -97
  101. package/lib/defaults.json +9 -0
  102. package/lib/git/review-snapshot.ts +73 -0
  103. package/lib/git/workflow.ts +101 -0
  104. package/lib/init.ts +9 -0
  105. package/lib/internal/git-workflow.ts +37 -0
  106. package/lib/internal/platform-checks.ts +101 -0
  107. package/lib/internal/platform-comment.ts +99 -0
  108. package/lib/internal/platform-context.ts +33 -0
  109. package/lib/internal/platform-issue.ts +116 -0
  110. package/lib/internal/platform-pr.ts +119 -0
  111. package/lib/internal/release-workflow.ts +186 -0
  112. package/lib/internal/task-artifact.ts +47 -0
  113. package/lib/internal/task-context.ts +35 -0
  114. package/lib/internal/task-event.ts +51 -0
  115. package/lib/internal/task-ledger.ts +86 -0
  116. package/lib/internal/task-lifecycle.ts +41 -0
  117. package/lib/internal/task-short-id.ts +55 -0
  118. package/lib/internal/task-snapshot.ts +32 -0
  119. package/lib/internal/task-verify.ts +33 -0
  120. package/lib/internal/task-warning.ts +50 -0
  121. package/lib/platform/adapters.ts +30 -0
  122. package/lib/platform/context.ts +164 -0
  123. package/lib/platform/github-client.ts +146 -0
  124. package/lib/platform/issue-comments.ts +479 -0
  125. package/lib/platform/issue-metadata.ts +250 -0
  126. package/lib/platform/issues.ts +691 -0
  127. package/lib/platform/metadata-labels.ts +33 -0
  128. package/lib/platform/pr-checks.ts +246 -0
  129. package/lib/platform/pr-summary.ts +90 -0
  130. package/lib/platform/pull-request-metadata.ts +69 -0
  131. package/lib/platform/pull-requests.ts +380 -0
  132. package/lib/platform/releases.ts +71 -0
  133. package/lib/platform/types.ts +74 -0
  134. package/lib/platform/verification-required.ts +83 -0
  135. package/{templates/.agents/scripts/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +221 -363
  136. package/lib/platform/verification.ts +11 -0
  137. package/lib/release/channels.ts +30 -0
  138. package/lib/release/workflow.ts +31 -0
  139. package/lib/render.ts +3 -2
  140. package/lib/run/index.ts +25 -7
  141. package/lib/sandbox/capture.ts +29 -3
  142. package/lib/sandbox/commands/create.ts +75 -28
  143. package/lib/sandbox/commands/enter.ts +38 -11
  144. package/lib/sandbox/commands/list-running.ts +10 -8
  145. package/lib/sandbox/commands/show.ts +2 -2
  146. package/lib/sandbox/commands/start.ts +50 -16
  147. package/lib/sandbox/engine.ts +37 -3
  148. package/lib/sandbox/engines/colima.ts +2 -2
  149. package/lib/sandbox/index.ts +6 -6
  150. package/lib/sandbox/mounts.ts +55 -0
  151. package/lib/sandbox/recovery.ts +828 -0
  152. package/lib/sandbox/runtimes/base.dockerfile +4 -0
  153. package/lib/sandbox/task-resolver.ts +5 -1
  154. package/lib/sandbox/tools.ts +31 -0
  155. package/lib/server/daemon.ts +9 -0
  156. package/lib/server/process-control.ts +70 -71
  157. package/lib/server/process-state.ts +183 -0
  158. package/lib/server/protocol.ts +5 -5
  159. package/lib/task/activity-log.ts +62 -0
  160. package/lib/task/artifact-lifecycle.ts +484 -0
  161. package/lib/task/command-options.ts +32 -0
  162. package/lib/task/commands/cat.ts +22 -9
  163. package/lib/task/commands/decisions.ts +49 -47
  164. package/lib/task/commands/files.ts +14 -6
  165. package/lib/task/commands/grep.ts +34 -7
  166. package/lib/task/commands/issue-body.ts +16 -16
  167. package/lib/task/commands/log.ts +17 -70
  168. package/lib/task/commands/show.ts +14 -6
  169. package/lib/task/commands/status.ts +17 -7
  170. package/lib/task/decision-intents.ts +163 -0
  171. package/lib/task/decision-items.ts +64 -0
  172. package/lib/task/events.ts +320 -0
  173. package/lib/task/frontmatter.ts +202 -2
  174. package/lib/task/implementation-inputs.ts +137 -0
  175. package/lib/task/index.ts +12 -9
  176. package/lib/task/issue-form.ts +20 -6
  177. package/lib/task/ledger-intents.ts +201 -0
  178. package/lib/task/ledger.ts +77 -31
  179. package/lib/task/lifecycle.ts +458 -0
  180. package/lib/task/resolve-ref.ts +197 -36
  181. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  182. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +20 -10
  183. package/lib/task/sections.ts +486 -4
  184. package/lib/task/short-id.ts +403 -9
  185. package/lib/task/snapshot.ts +143 -0
  186. package/lib/task/verification-checks.ts +9 -0
  187. package/lib/task/verification-config.ts +20 -0
  188. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +257 -451
  189. package/lib/task/verification-review.ts +9 -0
  190. package/lib/task/verification-types.ts +29 -0
  191. package/lib/task/verification.ts +156 -0
  192. package/lib/task/workflow-warning-intents.ts +142 -0
  193. package/lib/task/workflow-warnings.ts +10 -78
  194. package/lib/task/write.ts +468 -0
  195. package/lib/update.ts +6 -0
  196. package/package.json +5 -2
  197. package/templates/.agents/README.en.md +6 -3
  198. package/templates/.agents/README.zh-CN.md +6 -3
  199. package/templates/.agents/rules/README.en.md +6 -5
  200. package/templates/.agents/rules/README.zh-CN.md +6 -5
  201. package/templates/.agents/rules/create-issue.en.md +1 -1
  202. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  203. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  204. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  205. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  206. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  207. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  208. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  209. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  210. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  211. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  212. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  213. package/templates/.agents/rules/issue-sync.en.md +1 -1
  214. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  215. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  216. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  217. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  218. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  219. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  220. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  221. package/templates/.agents/rules/next-step-output.en.md +12 -11
  222. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  223. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  224. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  225. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  226. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  227. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  228. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  229. package/templates/.agents/rules/pr-sync.en.md +30 -3
  230. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  231. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  232. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  233. package/templates/.agents/rules/review-handshake.en.md +13 -9
  234. package/templates/.agents/rules/review-handshake.zh-CN.md +13 -9
  235. package/templates/.agents/rules/task-management.en.md +11 -2
  236. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  237. package/templates/.agents/rules/task-short-id.en.md +25 -29
  238. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  239. package/templates/.agents/scripts/lib/agent-infra-package.js +141 -0
  240. package/templates/.agents/scripts/task-short-id.js +71 -533
  241. package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
  242. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
  243. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  244. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  245. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  246. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  247. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  248. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  249. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  250. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  251. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  252. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  253. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  254. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  255. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  256. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  257. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  258. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  259. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  260. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  261. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  262. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  263. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  264. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  265. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  266. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  267. package/templates/.agents/skills/commit/SKILL.en.md +18 -14
  268. package/templates/.agents/skills/commit/SKILL.zh-CN.md +18 -14
  269. package/templates/.agents/skills/commit/config/verify.json +1 -2
  270. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  271. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  272. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  273. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  274. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  275. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  276. package/templates/.agents/skills/commit/reference/task-status-update.en.md +42 -2
  277. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +42 -2
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  279. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  280. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  281. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  282. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  283. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  284. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  285. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  286. package/templates/.agents/skills/complete-task/config/verify.en.json +11 -6
  287. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -6
  288. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  289. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  290. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  291. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  292. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  293. package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
  294. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
  295. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  296. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  297. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  298. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  299. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  300. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  301. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  302. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  303. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  304. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  305. package/templates/.agents/skills/init-milestones/SKILL.en.md +2 -2
  306. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +2 -2
  307. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +5 -4
  308. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  309. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  310. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  311. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  312. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  313. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  314. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  315. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  316. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  317. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  318. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  319. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  320. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  321. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  322. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  323. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  324. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  325. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  326. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  327. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  328. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  329. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  330. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  331. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  332. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  333. package/templates/.agents/skills/review-code/config/verify.en.json +5 -5
  334. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +5 -5
  335. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  336. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  337. package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -4
  338. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -4
  339. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  340. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  341. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  342. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  343. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  344. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  345. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  346. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  347. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  348. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  349. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  350. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  351. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +6 -3
  352. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +6 -3
  353. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +177 -151
  354. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  355. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  356. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  357. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  358. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  359. package/templates/.agents/templates/task.en.md +6 -1
  360. package/templates/.agents/templates/task.zh-CN.md +6 -1
  361. package/templates/.claude/commands/analyze-task.en.md +1 -1
  362. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  363. package/templates/.claude/commands/block-task.en.md +1 -1
  364. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  365. package/templates/.claude/commands/cancel-task.en.md +1 -1
  366. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  367. package/templates/.claude/commands/check-task.en.md +1 -1
  368. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  369. package/templates/.claude/commands/code-task.en.md +1 -1
  370. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  371. package/templates/.claude/commands/commit.en.md +1 -0
  372. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  373. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  374. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  375. package/templates/.claude/commands/complete-task.en.md +1 -1
  376. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  377. package/templates/.claude/commands/create-pr.en.md +1 -1
  378. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  379. package/templates/.claude/commands/plan-task.en.md +1 -1
  380. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  381. package/templates/.claude/commands/review-analysis.en.md +1 -1
  382. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  383. package/templates/.claude/commands/review-code.en.md +1 -1
  384. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  385. package/templates/.claude/commands/review-plan.en.md +1 -1
  386. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  387. package/templates/.claude/commands/watch-pr.en.md +1 -1
  388. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  389. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  390. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  391. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  392. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  393. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  394. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  395. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  396. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  397. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  398. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  399. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  400. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  401. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  402. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  403. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  404. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  405. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  406. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  407. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  408. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  409. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  410. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  411. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  412. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  413. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  414. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  415. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  416. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  417. package/templates/.git-hooks/check-large-files.cjs +92 -0
  418. package/templates/.git-hooks/check-version-format.sh +5 -1
  419. package/templates/.git-hooks/pre-commit +1 -0
  420. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  421. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  422. package/templates/.opencode/commands/check-task.en.md +1 -1
  423. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  424. package/templates/.opencode/commands/code-task.en.md +1 -1
  425. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  426. package/templates/.opencode/commands/commit.en.md +2 -0
  427. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  428. package/templates/.opencode/commands/complete-task.en.md +1 -1
  429. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  430. package/templates/.opencode/commands/plan-task.en.md +1 -1
  431. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  432. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  433. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  434. package/templates/.opencode/commands/review-code.en.md +1 -1
  435. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  436. package/templates/.opencode/commands/review-plan.en.md +1 -1
  437. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  438. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  439. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -99
  440. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  441. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  442. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  443. package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
@@ -1,3 +1,4 @@
1
+ // frontmatter, ledger, Git snapshot and platform domains are imported below.
1
2
  import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  import process from "node:process";
@@ -7,16 +8,17 @@ import { fileURLToPath } from "node:url";
7
8
  import {
8
9
  extractReviewBaseline,
9
10
  extractReviewDiffFingerprint,
11
+ extractReviewedSnapshotTree,
10
12
  findAuthoritativeReviewCodeArtifact,
11
13
  parseReviewVerdict,
12
14
  resolvePostReviewGlobs
13
- } from "./lib/post-review-commit.js";
14
-
15
- const EXIT_CODE = {
16
- pass: 0,
17
- fail: 1,
18
- blocked: 2
19
- };
15
+ } from "./verification-review.ts";
16
+ import { check as checkPlatformSync } from "../platform/verification-sync.ts";
17
+ import { check as checkRequiredChecks } from "../platform/verification-required.ts";
18
+ import { parseTypedTaskFrontmatter } from "./frontmatter.ts";
19
+ import { parseLedger } from "./ledger.ts";
20
+ import { loadVerificationConfig } from "./verification-config.ts";
21
+ import { snapshotReview } from "../git/review-snapshot.ts";
20
22
 
21
23
  const TASK_ENUMS = {
22
24
  type: ["feature", "bugfix", "refactor", "docs", "chore"],
@@ -36,7 +38,6 @@ const DEFAULT_REQUIRED_FIELDS = [
36
38
  "assigned_to"
37
39
  ];
38
40
 
39
- const DEFAULT_FRESHNESS_MINUTES = 30;
40
41
  const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
41
42
  const AGENT_INFRA_VERSION_PATTERN = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
42
43
  const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
@@ -69,25 +70,14 @@ const WORKFLOW_WARNING_SEVERITIES = new Set(["IMPORTANT", "ACTION_REQUIRED"]);
69
70
  const WORKFLOW_WARNING_ID_PATTERN = /^WW-\d+$/;
70
71
 
71
72
  const scriptPath = fileURLToPath(import.meta.url);
72
- const repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
73
+ let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
73
74
 
74
- const PLATFORM_ADAPTERS = {};
75
+ const PLATFORM_ADAPTERS: Record<string, (context: any, shared: any) => any> = {
76
+ "platform-sync": checkPlatformSync,
77
+ "platform-sync-preflight": (context: any, shared: any) => ({ ...checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
78
+ "required-checks": checkRequiredChecks
79
+ };
75
80
  const OPTIONAL_PLATFORM_CHECKS = new Set(["platform-sync"]);
76
- const adaptersDir = path.join(path.dirname(scriptPath), "platform-adapters");
77
-
78
- if (fs.existsSync(adaptersDir)) {
79
- for (const file of fs.readdirSync(adaptersDir)) {
80
- if (!file.endsWith(".js")) {
81
- continue;
82
- }
83
-
84
- const adapterName = path.basename(file, ".js");
85
- const mod = await import(new URL(`./platform-adapters/${file}`, import.meta.url));
86
- if (typeof mod.check === "function") {
87
- PLATFORM_ADAPTERS[adapterName] = mod.check;
88
- }
89
- }
90
- }
91
81
 
92
82
  const sharedUtils = {
93
83
  loadTask,
@@ -100,125 +90,17 @@ const sharedUtils = {
100
90
  blockedResult,
101
91
  safeStat,
102
92
  parseIssueNumber,
103
- parsePrNumber,
104
- repoRoot
93
+ parsePrNumber
105
94
  };
106
95
 
107
- // === CLI Entry ===
108
-
109
- function main(argv) {
110
- const [mode, ...rest] = argv;
111
-
112
- if (mode === "gate") {
113
- runGate(rest);
114
- return;
115
- }
116
-
117
- if (mode === "check") {
118
- runSingleCheck(rest);
119
- return;
120
- }
121
-
122
- printUsageAndExit();
123
- }
124
-
125
- function runGate(args) {
126
- const { value: formatValue, rest: positional } = extractOption(args, "--format");
127
- const format = normalizeFormat(formatValue);
128
- const [skillName, taskDirArg, artifactFile] = positional;
129
-
130
- if (!skillName || !taskDirArg) {
131
- printUsageAndExit();
132
- }
133
-
134
- const taskDir = path.resolve(taskDirArg);
135
- const verifyConfig = loadVerifyConfig(skillName);
136
- const checks = [];
137
-
138
- for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
139
- if (checkConfig === null) {
140
- continue;
141
- }
142
-
143
- const result = runCheck(type, {
144
- skillName,
145
- taskDir,
146
- artifactFile,
147
- config: checkConfig
148
- });
149
-
150
- checks.push(result);
151
-
152
- if (result.status === "blocked") {
153
- break;
154
- }
155
- }
156
-
157
- const gate = summarizeGate(checks);
158
- const output = {
159
- gate,
160
- skill: skillName,
161
- checks,
162
- summary: summarizeChecks(checks),
163
- action: buildAction(gate, checks)
164
- };
165
-
166
- writeOutput(output, format);
167
- process.exit(EXIT_CODE[gate]);
168
- }
169
-
170
- function runSingleCheck(args) {
171
- const { value: formatValue, rest: formatArgs } = extractOption(args, "--format");
172
- const format = normalizeFormat(formatValue);
173
- const { value: skillName, rest: positional } = extractOption(formatArgs, "--skill");
174
-
175
- if (!skillName) {
176
- printUsageAndExit();
177
- }
178
-
179
- const [type, taskDirArg, artifactFile] = positional;
180
-
181
- if (!type || !taskDirArg) {
182
- printUsageAndExit();
183
- }
184
-
185
- const verifyConfig = loadVerifyConfig(skillName);
186
- const config = (verifyConfig.checks || {})[type];
187
-
188
- if (config === undefined) {
189
- failUsage(`Unknown check type '${type}' for skill '${skillName}'.`);
190
- }
191
-
192
- if (config === null) {
193
- writeOutput({
194
- type,
195
- skill: skillName,
196
- status: "pass",
197
- message: `Check '${type}' is disabled for skill '${skillName}'.`
198
- }, format);
199
- process.exit(0);
200
- }
201
-
202
- const result = runCheck(type, {
203
- skillName,
204
- taskDir: path.resolve(taskDirArg),
205
- artifactFile,
206
- config
207
- });
208
-
209
- writeOutput({
210
- skill: skillName,
211
- ...result
212
- }, format);
213
- process.exit(EXIT_CODE[result.status] ?? 1);
214
- }
215
-
216
- function runCheck(type, context) {
96
+ function runCheck(type: any, context: any, shared: any): any {
217
97
  switch (type) {
218
98
  case "task-meta":
219
99
  return checkTaskMeta(context);
220
100
  case "artifact":
221
101
  return checkArtifact(context);
102
+ case "implementation-input":
103
+ return checkImplementationInput(context);
222
104
  case "activity-log":
223
105
  return checkActivityLog(context);
224
106
  case "completion-checklist":
@@ -239,14 +121,14 @@ function runCheck(type, context) {
239
121
  return failResult(type, `Unsupported check type '${type}'.`);
240
122
  }
241
123
 
242
- return adapter(context, sharedUtils);
124
+ return adapter(context, shared);
243
125
  }
244
126
  }
245
127
  }
246
128
 
247
129
  // === Check Functions ===
248
130
 
249
- function checkTaskMeta({ taskDir, config }) {
131
+ function checkTaskMeta({ taskDir, config }: any): any {
250
132
  const task = loadTask(taskDir);
251
133
  if (!task.ok) {
252
134
  return failResult("task-meta", task.message);
@@ -254,8 +136,8 @@ function checkTaskMeta({ taskDir, config }) {
254
136
 
255
137
  const metadata = task.metadata;
256
138
  const requiredFields = config.required_fields || DEFAULT_REQUIRED_FIELDS;
257
- const missingFields = requiredFields.filter((field) => isBlank(metadata[field]));
258
- const blockingMissingFields = missingFields.filter((field) => field !== "agent_infra_version");
139
+ const missingFields = requiredFields.filter((field: any) => isBlank(metadata[field]));
140
+ const blockingMissingFields = missingFields.filter((field: any) => field !== "agent_infra_version");
259
141
  const warnings = [];
260
142
  if (missingFields.includes("agent_infra_version")) {
261
143
  warnings.push("field 'agent_infra_version' missing — historical task or skipped version stamp");
@@ -348,11 +230,11 @@ function checkTaskMeta({ taskDir, config }) {
348
230
  return passResult(
349
231
  "task-meta",
350
232
  `Task metadata valid (${requiredFields.length} required fields checked${warningSuffix})`,
351
- warnings
233
+ warnings as string[]
352
234
  );
353
235
  }
354
236
 
355
- function validateTaskBranch(metadata) {
237
+ function validateTaskBranch(metadata: any): any {
356
238
  if (isBlank(metadata.branch)) {
357
239
  return null;
358
240
  }
@@ -372,7 +254,7 @@ function validateTaskBranch(metadata) {
372
254
  return null;
373
255
  }
374
256
 
375
- function loadProjectName() {
257
+ function loadProjectName(): any {
376
258
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
377
259
  if (!fs.existsSync(configPath)) {
378
260
  return "";
@@ -386,7 +268,7 @@ function loadProjectName() {
386
268
  }
387
269
  }
388
270
 
389
- function loadReviewConfig() {
271
+ function loadReviewConfig(): any {
390
272
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
391
273
  if (!fs.existsSync(configPath)) {
392
274
  return {};
@@ -400,7 +282,7 @@ function loadReviewConfig() {
400
282
  }
401
283
  }
402
284
 
403
- function checkArtifact({ taskDir, config, artifactFile }) {
285
+ function checkArtifact({ taskDir, config, artifactFile }: any): any {
404
286
  const resolvedArtifact = resolveArtifactPath(taskDir, config.file_pattern, artifactFile);
405
287
  if (!resolvedArtifact.ok) {
406
288
  return failResult("artifact", resolvedArtifact.message);
@@ -419,7 +301,7 @@ function checkArtifact({ taskDir, config, artifactFile }) {
419
301
  const content = fs.readFileSync(artifactPath, "utf8");
420
302
  const requiredSections = config.required_sections || [];
421
303
  const missingSections = requiredSections.filter(
422
- (section) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content)
304
+ (section: any) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content)
423
305
  );
424
306
 
425
307
  if (missingSections.length > 0) {
@@ -436,22 +318,80 @@ function checkArtifact({ taskDir, config, artifactFile }) {
436
318
  }
437
319
  }
438
320
 
439
- const freshnessMinutes = Number(config.freshness_minutes ?? DEFAULT_FRESHNESS_MINUTES);
440
- const ageMinutes = (Date.now() - stat.mtimeMs) / 60000;
441
- if (Number.isFinite(freshnessMinutes) && ageMinutes > freshnessMinutes) {
442
- return failResult(
443
- "artifact",
444
- `${path.basename(artifactPath)} is stale (${ageMinutes.toFixed(1)}m old, limit ${freshnessMinutes}m)`
445
- );
446
- }
447
-
448
321
  return passResult(
449
322
  "artifact",
450
- `${path.basename(artifactPath)} passed (${requiredSections.length} sections, ${Math.max(0, freshnessMinutes)}m freshness window)`
323
+ `${path.basename(artifactPath)} passed (${requiredSections.length} sections)`
451
324
  );
452
325
  }
453
326
 
454
- function checkActivityLog({ taskDir, config }) {
327
+ function checkImplementationInput({ taskDir, artifactFile }: any): any {
328
+ const task = loadTask(taskDir);
329
+ if (!task.ok) return failResult("implementation-input", task.message);
330
+ if (!artifactFile) return failResult("implementation-input", "Artifact file is required");
331
+ const artifactPath = path.join(taskDir, artifactFile);
332
+ if (!safeStat(artifactPath)?.isFile()) return failResult("implementation-input", `Artifact not found: ${artifactFile}`);
333
+
334
+ const inputSection = getSectionContent(task.content, ["实现输入", "Implementation Inputs"]);
335
+ const rows = [];
336
+ if (inputSection) {
337
+ const table = inputSection.split(/\r?\n/).filter((line: any) => line.trim().startsWith("|"));
338
+ const cells = (line: any) => line.split("|").slice(1, -1).map((cell: any) => cell.trim());
339
+ const expected = ["id", "ledger_id", "decision_evidence", "stage", "needs_implementation", "decided_at", "status", "consumed_by"];
340
+ if (table.length < 2 || JSON.stringify(cells(table[0])) !== JSON.stringify(expected)) {
341
+ return failResult("implementation-input", "Implementation Inputs table schema is invalid");
342
+ }
343
+ const seen = new Set();
344
+ for (const line of table.slice(2)) {
345
+ const row = cells(line);
346
+ if (row.length !== 8 || !/^II-[1-9]\d*$/.test(row[0]) || seen.has(row[0])) {
347
+ return failResult("implementation-input", "Implementation Inputs table contains an invalid or duplicate id");
348
+ }
349
+ seen.add(row[0]);
350
+ rows.push({ id: row[0], ledgerId: row[1], evidence: row[2], stage: row[3], needs: row[4], status: row[6], consumedBy: row[7] });
351
+ }
352
+ }
353
+
354
+ const logSection = getSectionContent(task.content, ["活动日志", "Activity Log"]);
355
+ const doneActions = logSection.split(/\r?\n/).flatMap((line: any) => {
356
+ const match = line.trim().match(ACTIVITY_LOG_PATTERN);
357
+ return match && !ACTIVITY_LOG_STARTED_RE.test(match[2]) ? [match[2]] : [];
358
+ });
359
+ const latestAction = doneActions.at(-1) || "";
360
+ const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
361
+ const report = fs.readFileSync(artifactPath, "utf8");
362
+ const reportSection = getSectionContent(report, ["实现输入", "Implementation Input"]);
363
+ if (!reportSection) return failResult("implementation-input", "Implementation Input report section not found");
364
+ const field = (zh: any, en: any) => {
365
+ const pattern = "^- \\*\\*(?:" + escapeRegExp(zh) + "|" + escapeRegExp(en) + ")\\*\\*[::]\\s*`?([^`\\n]+)`?\\s*$";
366
+ const match = new RegExp(pattern, "m").exec(reportSection);
367
+ return match?.[1]?.trim() || "";
368
+ };
369
+ const reportInput = field("裁决输入", "Decision Input");
370
+ const reportLedger = field("账本 ID", "Ledger ID");
371
+ const reportEvidence = field("裁决证据", "Decision Evidence");
372
+
373
+ if (!actionDecision) {
374
+ if (reportInput && reportInput !== "N/A") {
375
+ return failResult("implementation-input", "Non-decision code action must report Decision Input as N/A");
376
+ }
377
+ return passResult("implementation-input", "Non-decision implementation input identity is consistent");
378
+ }
379
+ if (reportInput !== actionDecision) {
380
+ return failResult("implementation-input", `Report decision input '${reportInput}' does not match Activity Log ${actionDecision}`);
381
+ }
382
+ const matches = rows.filter((row) => row.id === actionDecision);
383
+ if (matches.length !== 1) return failResult("implementation-input", `${actionDecision} is missing or duplicated in task table`);
384
+ const row = matches[0]!;
385
+ if (row.stage !== "code" || row.needs !== "true" || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.evidence) {
386
+ return failResult("implementation-input", `${actionDecision} is not a consumed input for ${artifactFile}`);
387
+ }
388
+ if (reportLedger !== row.ledgerId || reportEvidence !== row.evidence) {
389
+ return failResult("implementation-input", `${actionDecision} report identity does not match task table evidence`);
390
+ }
391
+ return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
392
+ }
393
+
394
+ function checkActivityLog({ taskDir, config }: any): any {
455
395
  const task = loadTask(taskDir);
456
396
  if (!task.ok) {
457
397
  return failResult("activity-log", task.message);
@@ -464,8 +404,8 @@ function checkActivityLog({ taskDir, config }) {
464
404
 
465
405
  const entries = logSection
466
406
  .split(/\r?\n/)
467
- .map((line) => line.trim())
468
- .filter((line) => line.startsWith("- "));
407
+ .map((line: any) => line.trim())
408
+ .filter((line: any) => line.startsWith("- "));
469
409
 
470
410
  if (entries.length === 0) {
471
411
  return failResult("activity-log", "Activity Log has no entries");
@@ -489,7 +429,7 @@ function checkActivityLog({ taskDir, config }) {
489
429
  previousTimestamp = timestamp;
490
430
  // Ascending order is checked over every entry, but a `[started]` marker is
491
431
  // not a terminal action: keep latestAction/latestTimestamp on the most
492
- // recent done entry so expected_action_pattern and freshness see it.
432
+ // recent done entry so expected_action_pattern sees it.
493
433
  if (!ACTIVITY_LOG_STARTED_RE.test(action)) {
494
434
  latestTimestamp = timestamp;
495
435
  latestAction = action;
@@ -503,21 +443,10 @@ function checkActivityLog({ taskDir, config }) {
503
443
  );
504
444
  }
505
445
 
506
- const freshnessMinutes = Number(config.freshness_minutes ?? DEFAULT_FRESHNESS_MINUTES);
507
- if (Number.isFinite(freshnessMinutes)) {
508
- const ageMinutes = minutesSinceTimestamp(latestTimestamp);
509
- if (ageMinutes > freshnessMinutes) {
510
- return failResult(
511
- "activity-log",
512
- `Latest Activity Log entry is stale (${ageMinutes.toFixed(1)}m old, limit ${freshnessMinutes}m)`
513
- );
514
- }
515
- }
516
-
517
446
  return passResult("activity-log", `Latest entry '${latestAction}' at ${latestTimestamp}`);
518
447
  }
519
448
 
520
- function checkCompletionChecklist({ taskDir, config }) {
449
+ function checkCompletionChecklist({ taskDir, config }: any): any {
521
450
  const task = loadTask(taskDir);
522
451
  if (!task.ok) {
523
452
  return failResult("completion-checklist", task.message);
@@ -530,8 +459,8 @@ function checkCompletionChecklist({ taskDir, config }) {
530
459
 
531
460
  const items = checklist
532
461
  .split(/\r?\n/)
533
- .map((line) => line.trim())
534
- .filter((line) => /^- \[(?: |x|X)\] .+$/.test(line));
462
+ .map((line: any) => line.trim())
463
+ .filter((line: any) => /^- \[(?: |x|X)\] .+$/.test(line));
535
464
 
536
465
  if (items.length === 0) {
537
466
  return failResult("completion-checklist", "Completion Checklist has no checkbox items");
@@ -539,9 +468,9 @@ function checkCompletionChecklist({ taskDir, config }) {
539
468
 
540
469
  if (config.require_all_checked) {
541
470
  const unchecked = items
542
- .map((line) => line.match(/^- \[ \] (.+)$/))
471
+ .map((line: any) => line.match(/^- \[ \] (.+)$/))
543
472
  .filter(Boolean)
544
- .map((match) => match[1].trim());
473
+ .map((match: any) => match[1].trim());
545
474
 
546
475
  if (unchecked.length > 0) {
547
476
  return failResult(
@@ -554,27 +483,7 @@ function checkCompletionChecklist({ taskDir, config }) {
554
483
  return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
555
484
  }
556
485
 
557
- function parseLedgerRows(section) {
558
- const rows = [];
559
- for (const rawLine of String(section || "").split(/\r?\n/)) {
560
- const line = rawLine.trim();
561
- if (!line.startsWith("|")) {
562
- continue;
563
- }
564
- if (/^\|[\s:|-]+\|?$/.test(line)) {
565
- continue; // separator row
566
- }
567
- const inner = line.replace(/^\|/, "").replace(/\|$/, "");
568
- const cells = inner.split("|").map((cell) => cell.trim());
569
- if ((cells[0] || "").toLowerCase() === "id") {
570
- continue; // header row
571
- }
572
- rows.push(cells);
573
- }
574
- return rows;
575
- }
576
-
577
- function splitMarkdownTableRow(line) {
486
+ function splitMarkdownTableRow(line: any): any {
578
487
  let value = String(line || "").trim();
579
488
  if (!value.startsWith("|")) {
580
489
  return [];
@@ -596,7 +505,7 @@ function splitMarkdownTableRow(line) {
596
505
  return cells;
597
506
  }
598
507
 
599
- function unescapeMarkdownTableCell(value) {
508
+ function unescapeMarkdownTableCell(value: any): any {
600
509
  let output = "";
601
510
  for (let index = 0; index < value.length; index += 1) {
602
511
  const char = value[index];
@@ -611,7 +520,7 @@ function unescapeMarkdownTableCell(value) {
611
520
  return output;
612
521
  }
613
522
 
614
- function isEscapedAt(value, index) {
523
+ function isEscapedAt(value: any, index: any): any {
615
524
  let backslashes = 0;
616
525
  for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
617
526
  backslashes += 1;
@@ -619,7 +528,7 @@ function isEscapedAt(value, index) {
619
528
  return backslashes % 2 === 1;
620
529
  }
621
530
 
622
- function parseWorkflowWarningRows(section) {
531
+ function parseWorkflowWarningRows(section: any): any {
623
532
  const rows = [];
624
533
  for (const rawLine of String(section || "").split(/\r?\n/)) {
625
534
  const cells = splitMarkdownTableRow(rawLine);
@@ -629,7 +538,7 @@ function parseWorkflowWarningRows(section) {
629
538
  if ((cells[0] || "").toLowerCase() === "id") {
630
539
  continue;
631
540
  }
632
- if (cells.every((cell) => /^:?-{3,}:?$/.test(cell))) {
541
+ if (cells.every((cell: any) => /^:?-{3,}:?$/.test(cell))) {
633
542
  continue;
634
543
  }
635
544
  rows.push(cells);
@@ -637,7 +546,7 @@ function parseWorkflowWarningRows(section) {
637
546
  return rows;
638
547
  }
639
548
 
640
- function validateWorkflowWarnings(content) {
549
+ function validateWorkflowWarnings(content: any): any {
641
550
  const section = getSectionContent(content, WORKFLOW_WARNING_SECTION_NAMES);
642
551
  if (!section.trim()) {
643
552
  return [];
@@ -685,7 +594,7 @@ function validateWorkflowWarnings(content) {
685
594
  return errors;
686
595
  }
687
596
 
688
- function resolveReviewSetting(config, key, fallback) {
597
+ function resolveReviewSetting(config: any, key: any, fallback: any): any {
689
598
  if (config && config[key] !== undefined && config[key] !== null) {
690
599
  return config[key];
691
600
  }
@@ -696,7 +605,7 @@ function resolveReviewSetting(config, key, fallback) {
696
605
  return fallback;
697
606
  }
698
607
 
699
- function checkReviewLedger({ taskDir, config }) {
608
+ function checkReviewLedger({ taskDir, config }: any): any {
700
609
  const task = loadTask(taskDir);
701
610
  if (!task.ok) {
702
611
  return failResult("review-ledger", task.message);
@@ -707,7 +616,14 @@ function checkReviewLedger({ taskDir, config }) {
707
616
  return passResult("review-ledger", "No disagreement ledger section; treated as no open disagreements");
708
617
  }
709
618
 
710
- const rows = parseLedgerRows(section);
619
+ let rows;
620
+ try {
621
+ rows = parseLedger(task.content).map((row) => [
622
+ row.id, row.stage, row.round, row.severity, row.status, row.evidence
623
+ ]);
624
+ } catch (error) {
625
+ return failResult("review-ledger", `Invalid disagreement ledger: ${error instanceof Error ? error.message : String(error)}`);
626
+ }
711
627
  if (rows.length === 0) {
712
628
  return passResult("review-ledger", "Disagreement ledger has no entries");
713
629
  }
@@ -735,23 +651,23 @@ function checkReviewLedger({ taskDir, config }) {
735
651
  }
736
652
  inScopeCount += 1;
737
653
 
738
- if (!LEDGER_STATUSES.has(status)) {
654
+ if (!LEDGER_STATUSES.has(status!)) {
739
655
  problems.push(`${id}: illegal status '${status}'`);
740
656
  continue;
741
657
  }
742
658
  if (status !== "open" && evidence === "") {
743
659
  problems.push(`${id}: status '${status}' requires evidence`);
744
660
  }
745
- const round = Number.parseInt(roundRaw, 10);
661
+ const round = Number.parseInt(roundRaw!, 10);
746
662
  if (
747
663
  Number.isFinite(round) &&
748
664
  round >= maxRounds &&
749
- !LEDGER_TERMINAL_OK.has(status) &&
665
+ !LEDGER_TERMINAL_OK.has(status!) &&
750
666
  status !== "needs-human-decision"
751
667
  ) {
752
668
  problems.push(`${id}: round ${round} reached limit ${maxRounds} without convergence; escalate to needs-human-decision`);
753
669
  }
754
- if (!LEDGER_TERMINAL_OK.has(status)) {
670
+ if (!LEDGER_TERMINAL_OK.has(status!)) {
755
671
  problems.push(`${id}: unresolved (status '${status}')`);
756
672
  }
757
673
  }
@@ -764,7 +680,7 @@ function checkReviewLedger({ taskDir, config }) {
764
680
  return passResult("review-ledger", `Disagreement ledger clean (${inScopeCount} in-scope entries terminal${scopeLabel})`);
765
681
  }
766
682
 
767
- function checkPostReviewCommit({ taskDir, config }) {
683
+ function checkPostReviewCommit({ taskDir, config }: any): any {
768
684
  const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
769
685
  if (!reviewArtifact.ok) {
770
686
  return passResult("post-review-commit", "No review-code artifact; check inactive");
@@ -778,13 +694,11 @@ function checkPostReviewCommit({ taskDir, config }) {
778
694
  }
779
695
 
780
696
  const task = loadTask(taskDir);
781
- const content = fs.readFileSync(reviewArtifact.path, "utf8");
782
- const reviewBaseline = extractReviewBaseline(content);
697
+ const content = fs.readFileSync(reviewArtifact.path!, "utf8");
783
698
  const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
784
699
  const baselineSource = resolvePostReviewBaseline({
785
700
  gitRoot,
786
701
  lastReviewedCommit,
787
- reviewBaseline,
788
702
  reviewArtifact: reviewArtifact.fileName
789
703
  });
790
704
  if (!baselineSource.ok) {
@@ -805,10 +719,14 @@ function checkPostReviewCommit({ taskDir, config }) {
805
719
  return passResult("post-review-commit", `No post-review commits to code/rule paths since ${sha.slice(0, 8)}`);
806
720
  }
807
721
 
808
- const ledgerSection = task.ok ? getSectionContent(task.content, LEDGER_SECTION_NAMES) : "";
809
- const exempt = parseLedgerRows(ledgerSection).some(
810
- (cells) => cells[1] === POST_REVIEW_COMMIT_STAGE && cells[4] === "human-decided"
811
- );
722
+ let exempt = false;
723
+ try {
724
+ exempt = task.ok && parseLedger(task.content).some(
725
+ (row) => row.stage === POST_REVIEW_COMMIT_STAGE && row.status === "human-decided"
726
+ );
727
+ } catch {
728
+ return failResult("post-review-commit", "Invalid disagreement ledger");
729
+ }
812
730
  if (exempt) {
813
731
  return passResult(
814
732
  "post-review-commit",
@@ -818,11 +736,11 @@ function checkPostReviewCommit({ taskDir, config }) {
818
736
 
819
737
  return failResult(
820
738
  "post-review-commit",
821
- `${commits.length} commit(s) to code/rule paths after review baseline ${sha.slice(0, 8)}; re-run review-code or record a human-decided exemption`
739
+ `${commits.length} commit(s) to code/rule paths after reviewed commit ${sha.slice(0, 8)}; re-run review-code or record a human-decided exemption`
822
740
  );
823
741
  }
824
742
 
825
- function checkReviewFact({ taskDir, artifactFile }) {
743
+ function checkReviewFact({ taskDir, artifactFile }: any): any {
826
744
  const resolvedArtifact = resolveArtifactPath(
827
745
  taskDir,
828
746
  "review-code.md|review-code-r{N}.md",
@@ -841,6 +759,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
841
759
  const verdict = parseReviewVerdict(content);
842
760
  const reviewBaseline = extractReviewBaseline(content);
843
761
  const reviewedFingerprint = extractReviewDiffFingerprint(content);
762
+ const reviewedTree = extractReviewedSnapshotTree(content);
844
763
 
845
764
  if (!["通过", "需要修改", "拒绝", "Approved", "Changes Requested", "Rejected"].includes(verdict)) {
846
765
  return failResult("review-fact", `Unsupported review verdict '${verdict}'`);
@@ -867,13 +786,9 @@ function checkReviewFact({ taskDir, artifactFile }) {
867
786
  );
868
787
  }
869
788
 
870
- let actualFingerprint;
789
+ let actualSnapshot;
871
790
  try {
872
- actualFingerprint = execFileSync(
873
- process.execPath,
874
- [path.join(repoRoot, ".agents", "scripts", "review-diff-fingerprint.js"), "worktree", baseline],
875
- { cwd: gitRoot, encoding: "utf8" }
876
- ).trim();
791
+ actualSnapshot = snapshotReview({ cwd: gitRoot, mode: "worktree", baseline, globs: resolvePostReviewGlobs({}, loadReviewConfig()) });
877
792
  } catch {
878
793
  return blockedResult(
879
794
  "review-fact",
@@ -881,26 +796,37 @@ function checkReviewFact({ taskDir, artifactFile }) {
881
796
  );
882
797
  }
883
798
 
884
- if (actualFingerprint !== reviewedFingerprint) {
799
+ if (actualSnapshot.fingerprint !== reviewedFingerprint) {
885
800
  return failResult(
886
801
  "review-fact",
887
802
  `Reviewed diff fingerprint does not match the current worktree for baseline ${baseline.slice(0, 8)}; re-run review-code`
888
803
  );
889
804
  }
890
805
 
806
+ if (!reviewedTree || actualSnapshot.tree !== reviewedTree) {
807
+ return failResult(
808
+ "review-fact",
809
+ `Reviewed snapshot tree does not match the current worktree for baseline ${baseline.slice(0, 8)}; re-run review-code`
810
+ );
811
+ }
812
+
891
813
  if (["通过", "Approved"].includes(verdict)) {
892
814
  const lastReviewedCommit = String(task.metadata.last_reviewed_commit || "").trim();
893
- let reviewedCommit = "";
894
- try {
895
- reviewedCommit = execFileSync("git", ["-C", gitRoot, "rev-parse", `${lastReviewedCommit}^{commit}`], { encoding: "utf8" }).trim();
896
- } catch {
897
- // The failure below names the missing or invalid task review fact.
815
+ const cleanSnapshot = actualSnapshot.tree === execFileSync(
816
+ "git",
817
+ ["-C", gitRoot, "rev-parse", `${baseline}^{tree}`],
818
+ { encoding: "utf8" }
819
+ ).trim();
820
+ if (cleanSnapshot && lastReviewedCommit !== baseline) {
821
+ return failResult(
822
+ "review-fact",
823
+ `Approved clean review must set task last_reviewed_commit to baseline ${baseline.slice(0, 8)}`
824
+ );
898
825
  }
899
-
900
- if (reviewedCommit !== baseline) {
826
+ if (!cleanSnapshot && lastReviewedCommit) {
901
827
  return failResult(
902
828
  "review-fact",
903
- `Approved review must set task last_reviewed_commit to baseline ${baseline.slice(0, 8)}`
829
+ "Approved review with uncommitted changes must remain unanchored until commit"
904
830
  );
905
831
  }
906
832
  }
@@ -911,38 +837,21 @@ function checkReviewFact({ taskDir, artifactFile }) {
911
837
  );
912
838
  }
913
839
 
914
- function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewBaseline, reviewArtifact }) {
915
- if (lastReviewedCommit) {
916
- if (SHA_PATTERN.test(lastReviewedCommit) && gitCommitExists(gitRoot, lastReviewedCommit)) {
917
- return { ok: true, sha: lastReviewedCommit };
918
- }
919
- }
920
-
921
- if (!reviewBaseline) {
922
- return {
923
- ok: false,
924
- result: passResult(
925
- "post-review-commit",
926
- `${reviewArtifact} predates baseline-commit anchoring; skipped (legacy artifact)`,
927
- [`${reviewArtifact} has no 审查基线提交 / Review Baseline Commit field`]
928
- )
929
- };
930
- }
931
-
932
- if (!SHA_PATTERN.test(reviewBaseline)) {
933
- return {
934
- ok: false,
935
- result: blockedResult(
936
- "post-review-commit",
937
- `${reviewArtifact} has an empty or malformed 审查基线提交 SHA ('${reviewBaseline}'); manual remediation required`
938
- )
939
- };
840
+ function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewArtifact }: any): any {
841
+ if (SHA_PATTERN.test(lastReviewedCommit) && gitCommitExists(gitRoot, lastReviewedCommit)) {
842
+ return { ok: true, sha: lastReviewedCommit };
940
843
  }
941
844
 
942
- return { ok: true, sha: reviewBaseline };
845
+ return {
846
+ ok: false,
847
+ result: blockedResult(
848
+ "post-review-commit",
849
+ `${reviewArtifact}: reviewed snapshot was not anchored to a valid commit; re-run commit or review-code`
850
+ )
851
+ };
943
852
  }
944
853
 
945
- function gitCommitExists(gitRoot, sha) {
854
+ function gitCommitExists(gitRoot: any, sha: any): any {
946
855
  try {
947
856
  execFileSync("git", ["-C", gitRoot, "cat-file", "-e", `${sha}^{commit}`], { encoding: "utf8" });
948
857
  return true;
@@ -953,31 +862,24 @@ function gitCommitExists(gitRoot, sha) {
953
862
 
954
863
  // === File & Config Loaders ===
955
864
 
956
- function loadVerifyConfig(skillName) {
957
- const verifyPath = path.join(repoRoot, ".agents", "skills", skillName, "config", "verify.json");
958
- if (!fs.existsSync(verifyPath)) {
959
- failUsage(`config/verify.json not found for skill '${skillName}'`);
960
- }
961
-
962
- return JSON.parse(fs.readFileSync(verifyPath, "utf8"));
963
- }
964
-
965
- function loadTask(taskDir) {
865
+ function loadTask(taskDir: any): any {
966
866
  const taskPath = path.join(taskDir, "task.md");
967
867
  if (!fs.existsSync(taskPath)) {
968
868
  return { ok: false, message: `Task file not found: ${taskPath}` };
969
869
  }
970
870
 
971
871
  const content = fs.readFileSync(taskPath, "utf8");
972
- const metadata = parseFrontmatter(content);
973
- if (!metadata) {
872
+ let metadata;
873
+ try {
874
+ metadata = Object.fromEntries(Object.entries(parseTypedTaskFrontmatter(content)).map(([key, value]) => [key, value === null ? "" : String(value)]));
875
+ } catch {
974
876
  return { ok: false, message: "task.md frontmatter not found or invalid" };
975
877
  }
976
878
 
977
879
  return { ok: true, content, metadata };
978
880
  }
979
881
 
980
- function resolveArtifactPath(taskDir, filePattern, artifactFile) {
882
+ function resolveArtifactPath(taskDir: any, filePattern: any, artifactFile: any): any {
981
883
  if (artifactFile) {
982
884
  return { ok: true, path: path.join(taskDir, artifactFile) };
983
885
  }
@@ -989,7 +891,7 @@ function resolveArtifactPath(taskDir, filePattern, artifactFile) {
989
891
  const entries = fs.existsSync(taskDir) ? fs.readdirSync(taskDir) : [];
990
892
  const matches = [];
991
893
 
992
- for (const pattern of filePattern.split("|").map((value) => value.trim()).filter(Boolean)) {
894
+ for (const pattern of filePattern.split("|").map((value: any) => value.trim()).filter(Boolean)) {
993
895
  const regex = new RegExp(`^${escapePattern(pattern)}$`);
994
896
  for (const entry of entries) {
995
897
  const match = entry.match(regex);
@@ -1009,54 +911,53 @@ function resolveArtifactPath(taskDir, filePattern, artifactFile) {
1009
911
  }
1010
912
 
1011
913
  matches.sort((left, right) => right.round - left.round || left.fileName.localeCompare(right.fileName));
1012
- return { ok: true, path: path.join(taskDir, matches[0].fileName) };
914
+ return { ok: true, path: path.join(taskDir, matches[0]!.fileName) };
1013
915
  }
1014
916
 
1015
- function parseFrontmatter(content) {
1016
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
1017
- if (!match) {
1018
- return null;
1019
- }
917
+ function getSectionContent(content: any, names: any): any {
918
+ const lines = content.split(/\r?\n/);
1020
919
 
1021
- const metadata = {};
1022
- for (const line of match[1].split(/\r?\n/)) {
1023
- const parsed = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
1024
- if (!parsed) {
1025
- continue;
920
+ function visibleHeadings(): any {
921
+ const headings = [];
922
+ let fence = null;
923
+ for (let index = 0; index < lines.length; index += 1) {
924
+ const line = lines[index];
925
+ if (fence) {
926
+ const closer = line.match(/^ {0,3}(`+|~+)\s*$/);
927
+ if (closer && closer[1][0] === fence.character && closer[1].length >= fence.length) {
928
+ fence = null;
929
+ }
930
+ continue;
931
+ }
932
+ const opener = line.match(/^ {0,3}(`{3,}|~{3,})(?:[^`~].*)?$/);
933
+ if (opener) {
934
+ fence = { character: opener[1][0], length: opener[1].length };
935
+ continue;
936
+ }
937
+ if (line.startsWith("## ")) {
938
+ headings.push({ index, text: line.trim() });
939
+ }
1026
940
  }
1027
-
1028
- const [, key, rawValue] = parsed;
1029
- metadata[key] = rawValue.trim().replace(/^['"]|['"]$/g, "");
941
+ return headings;
1030
942
  }
1031
943
 
1032
- return metadata;
1033
- }
1034
-
1035
- function getSectionContent(content, names) {
1036
- const lines = content.split(/\r?\n/);
944
+ const headings = visibleHeadings();
1037
945
 
1038
946
  for (const name of names) {
1039
947
  const heading = `## ${name}`;
1040
- const startIndex = lines.findIndex((line) => line.trim() === heading);
1041
- if (startIndex === -1) {
948
+ const position = headings.findIndex((item: any) => item.text === heading);
949
+ if (position === -1) {
1042
950
  continue;
1043
951
  }
1044
-
1045
- const sectionLines = [];
1046
- for (let index = startIndex + 1; index < lines.length; index += 1) {
1047
- if (lines[index].startsWith("## ")) {
1048
- break;
1049
- }
1050
- sectionLines.push(lines[index]);
1051
- }
1052
-
1053
- return sectionLines.join("\n").trim();
952
+ const startIndex = headings[position]!.index;
953
+ const endIndex = headings[position + 1]?.index ?? lines.length;
954
+ return lines.slice(startIndex + 1, endIndex).join("\n").trim();
1054
955
  }
1055
956
 
1056
957
  return "";
1057
958
  }
1058
959
 
1059
- function getCheckedRequirements(content) {
960
+ function getCheckedRequirements(content: any): any {
1060
961
  const section = getSectionContent(content, ["需求", "Requirements"]);
1061
962
  if (!section) {
1062
963
  return [];
@@ -1064,13 +965,13 @@ function getCheckedRequirements(content) {
1064
965
 
1065
966
  return section
1066
967
  .split(/\r?\n/)
1067
- .map((line) => line.trim())
1068
- .map((line) => line.match(/^- \[x\] (.+)$/i))
968
+ .map((line: any) => line.trim())
969
+ .map((line: any) => line.match(/^- \[x\] (.+)$/i))
1069
970
  .filter(Boolean)
1070
- .map((match) => match[1].trim());
971
+ .map((match: any) => match[1].trim());
1071
972
  }
1072
973
 
1073
- function parseIssueNumber(value) {
974
+ function parseIssueNumber(value: any): any {
1074
975
  if (isBlank(value) || value === "N/A") {
1075
976
  return null;
1076
977
  }
@@ -1079,53 +980,43 @@ function parseIssueNumber(value) {
1079
980
  return match ? Number(match[0]) : null;
1080
981
  }
1081
982
 
1082
- function parsePrNumber(value) {
983
+ function parsePrNumber(value: any): any {
1083
984
  return parseIssueNumber(value);
1084
985
  }
1085
986
 
1086
987
  // === Utilities ===
1087
988
 
1088
- function normalizeContent(text) {
989
+ function normalizeContent(text: any): any {
1089
990
  return String(text || "")
1090
991
  .replace(/\r\n/g, "\n")
1091
992
  .replace(/\n{3,}/g, "\n\n")
1092
993
  .trim();
1093
994
  }
1094
995
 
1095
- function minutesSinceTimestamp(timestamp) {
1096
- const normalized = timestamp.includes("T") ? timestamp : timestamp.replace(" ", "T");
1097
- const parsed = Date.parse(normalized);
1098
- if (Number.isNaN(parsed)) {
1099
- return Number.POSITIVE_INFINITY;
1100
- }
1101
-
1102
- return (Date.now() - parsed) / 60000;
1103
- }
1104
-
1105
- function interpolate(template, taskDir, artifactFile) {
996
+ function interpolate(template: any, taskDir: any, artifactFile: any): any {
1106
997
  const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
1107
998
  return template
1108
999
  .replace(/\{task-id\}/g, path.basename(taskDir))
1109
1000
  .replace(/\{artifact-stem\}/g, artifactStem);
1110
1001
  }
1111
1002
 
1112
- function summarizeGate(checks) {
1113
- if (checks.some((check) => check.status === "blocked")) {
1003
+ function summarizeGate(checks: any): any {
1004
+ if (checks.some((check: any) => check.status === "blocked")) {
1114
1005
  return "blocked";
1115
1006
  }
1116
1007
 
1117
- if (checks.some((check) => check.status === "fail")) {
1008
+ if (checks.some((check: any) => check.status === "fail")) {
1118
1009
  return "fail";
1119
1010
  }
1120
1011
 
1121
1012
  return "pass";
1122
1013
  }
1123
1014
 
1124
- function summarizeChecks(checks) {
1015
+ function summarizeChecks(checks: any): any {
1125
1016
  const counts = {
1126
- pass: checks.filter((check) => check.status === "pass").length,
1127
- fail: checks.filter((check) => check.status === "fail").length,
1128
- blocked: checks.filter((check) => check.status === "blocked").length
1017
+ pass: checks.filter((check: any) => check.status === "pass").length,
1018
+ fail: checks.filter((check: any) => check.status === "fail").length,
1019
+ blocked: checks.filter((check: any) => check.status === "blocked").length
1129
1020
  };
1130
1021
 
1131
1022
  if (counts.blocked > 0) {
@@ -1135,12 +1026,12 @@ function summarizeChecks(checks) {
1135
1026
  return `${counts.pass} passed, ${counts.fail} failed`;
1136
1027
  }
1137
1028
 
1138
- function buildAction(gate, checks) {
1029
+ function buildAction(gate: any, checks: any): any {
1139
1030
  if (gate === "pass") {
1140
1031
  return "All declared checks passed";
1141
1032
  }
1142
1033
 
1143
- const firstFailure = checks.find((check) => check.status !== "pass");
1034
+ const firstFailure = checks.find((check: any) => check.status !== "pass");
1144
1035
  if (!firstFailure) {
1145
1036
  return "Review validation output";
1146
1037
  }
@@ -1152,47 +1043,23 @@ function buildAction(gate, checks) {
1152
1043
  return `Fix ${firstFailure.type} issues and re-run gate`;
1153
1044
  }
1154
1045
 
1155
- function buildCheckAction(result) {
1156
- if (result.status === "pass") {
1157
- return "Requested check passed";
1158
- }
1159
-
1160
- if (result.status === "blocked") {
1161
- return `Resolve blocked ${result.type} check and re-run check`;
1162
- }
1163
-
1164
- return `Fix ${result.type} issues and re-run check`;
1165
- }
1166
-
1167
- function buildSingleCheckSummary(status) {
1168
- if (status === "pass") {
1169
- return "1 passed, 0 failed";
1170
- }
1171
-
1172
- if (status === "blocked") {
1173
- return "0 passed, 0 failed, 1 blocked";
1174
- }
1175
-
1176
- return "0 passed, 1 failed";
1177
- }
1178
-
1179
- function passResult(type, message, warnings = []) {
1180
- const result = { type, status: "pass", message };
1046
+ function passResult(type: any, message: any, warnings: string[] = []): any {
1047
+ const result: { type: any; status: string; message: any; warnings?: string[] } = { type, status: "pass", message };
1181
1048
  if (warnings.length > 0) {
1182
1049
  result.warnings = warnings;
1183
1050
  }
1184
1051
  return result;
1185
1052
  }
1186
1053
 
1187
- function failResult(type, message, failType = "check_failed") {
1054
+ function failResult(type: any, message: any, failType = "check_failed"): any {
1188
1055
  return { type, status: "fail", fail_type: failType, message };
1189
1056
  }
1190
1057
 
1191
- function blockedResult(type, message, failType = "network_error") {
1058
+ function blockedResult(type: any, message: any, failType = "network_error"): any {
1192
1059
  return { type, status: "blocked", fail_type: failType, message };
1193
1060
  }
1194
1061
 
1195
- function safeStat(filePath) {
1062
+ function safeStat(filePath: any): any {
1196
1063
  try {
1197
1064
  return fs.statSync(filePath);
1198
1065
  } catch {
@@ -1200,105 +1067,44 @@ function safeStat(filePath) {
1200
1067
  }
1201
1068
  }
1202
1069
 
1203
- function escapePattern(pattern) {
1070
+ function escapePattern(pattern: any): any {
1204
1071
  return escapeRegExp(pattern)
1205
1072
  .replace(/\\\{N\\\}/g, "(\\d+)");
1206
1073
  }
1207
1074
 
1208
- function escapeRegExp(value) {
1075
+ function escapeRegExp(value: any): any {
1209
1076
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1210
1077
  }
1211
1078
 
1212
- function isBlank(value) {
1079
+ function isBlank(value: any): any {
1213
1080
  return value === undefined || value === null || String(value).trim() === "";
1214
1081
  }
1215
1082
 
1216
- function extractOption(args, name) {
1217
- const rest = [];
1218
- let value;
1219
-
1220
- for (let index = 0; index < args.length; index += 1) {
1221
- const arg = args[index];
1222
- if (arg === name) {
1223
- value = args[index + 1];
1224
- index += 1;
1225
- continue;
1226
- }
1227
-
1228
- const inlinePrefix = `${name}=`;
1229
- if (arg.startsWith(inlinePrefix)) {
1230
- value = arg.slice(inlinePrefix.length);
1231
- continue;
1232
- }
1233
-
1234
- rest.push(arg);
1235
- }
1236
-
1237
- return { value, rest };
1238
- }
1239
-
1240
- function normalizeFormat(value) {
1241
- return value === "text" ? "text" : "json";
1242
- }
1243
-
1244
- function formatStatusLabel(status) {
1245
- if (status === "fail") {
1246
- return "FAIL";
1247
- }
1248
-
1249
- if (status === "blocked") {
1250
- return "BLOCKED";
1251
- }
1252
-
1253
- return "pass";
1254
- }
1255
-
1256
- function writeOutput(value, format) {
1257
- if (format === "text") {
1258
- writeText(value);
1259
- return;
1083
+ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): any {
1084
+ if (repositoryRoot) repoRoot = path.resolve(repositoryRoot);
1085
+ else {
1086
+ let cursor = path.resolve(taskDir);
1087
+ while (path.dirname(cursor) !== cursor && !fs.existsSync(path.join(cursor, ".agents"))) cursor = path.dirname(cursor);
1088
+ if (fs.existsSync(path.join(cursor, ".agents"))) repoRoot = cursor;
1260
1089
  }
1261
-
1262
- writeJson(value);
1263
- }
1264
-
1265
- function writeText(value) {
1266
- const lines = [];
1267
-
1268
- if (Array.isArray(value.checks)) {
1269
- lines.push(`Verification: ${value.gate} | Skill: ${value.skill}`);
1270
- lines.push("");
1271
- for (const check of value.checks) {
1272
- lines.push(` [${formatStatusLabel(check.status)}] ${check.type} - ${check.message}`);
1090
+ const verifyConfig = loadVerificationConfig(repoRoot, skillName);
1091
+ const shared = { ...sharedUtils, repoRoot };
1092
+ if (mode === "gate") {
1093
+ const checks = [];
1094
+ for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
1095
+ if (checkConfig === null) continue;
1096
+ const result = runCheck(type, { skillName, taskDir: path.resolve(taskDir), artifactFile, config: checkConfig }, shared);
1097
+ checks.push(result);
1098
+ if (result.status === "blocked") break;
1273
1099
  }
1274
- lines.push("");
1275
- lines.push(`Result: ${value.summary} - ${value.action}`);
1276
- } else {
1277
- lines.push(`Check: ${value.status} | Skill: ${value.skill} | Type: ${value.type}`);
1278
- lines.push("");
1279
- lines.push(` [${formatStatusLabel(value.status)}] ${value.type} - ${value.message}`);
1280
- lines.push("");
1281
- lines.push(`Result: ${buildSingleCheckSummary(value.status)} - ${buildCheckAction(value)}`);
1100
+ const gate = summarizeGate(checks);
1101
+ return { gate, skill: skillName, checks, summary: summarizeChecks(checks), action: buildAction(gate, checks) };
1282
1102
  }
1283
-
1284
- process.stdout.write(`${lines.join("\n")}\n`);
1285
- }
1286
-
1287
- function writeJson(value) {
1288
- process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
1289
- }
1290
-
1291
- function printUsageAndExit() {
1292
- failUsage(
1293
- "Usage:\n" +
1294
- " node .agents/scripts/validate-artifact.js gate <skill-name> <task-dir> [artifact-file] [--format json|text]\n" +
1295
- " node .agents/scripts/validate-artifact.js check <type> <task-dir> [artifact-file] --skill <skill-name> [--format json|text]"
1296
- );
1297
- }
1298
-
1299
- function failUsage(message) {
1300
- process.stderr.write(`${message}\n`);
1301
- process.exit(1);
1103
+ const type = requestedChecks[0];
1104
+ const config = (verifyConfig.checks || {})[type];
1105
+ if (config === undefined) return { skill: skillName, ...failResult(type, `Unknown check type '${type}' for skill '${skillName}'.`) };
1106
+ if (config === null) return { skill: skillName, ...passResult(type, `Check '${type}' is disabled for skill '${skillName}'.`) };
1107
+ return { skill: skillName, ...runCheck(type, { skillName, taskDir: path.resolve(taskDir), artifactFile, config }, shared) };
1302
1108
  }
1303
1109
 
1304
- main(process.argv.slice(2));
1110
+ export { verifyInProcess };