@fitlab-ai/agent-infra 0.8.5 → 0.9.1

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 (467) hide show
  1. package/README.md +6 -1
  2. package/README.zh-CN.md +5 -1
  3. package/bin/cli.ts +2 -2
  4. package/dist/bin/cli.js +2 -2
  5. package/dist/bin/internal-cli.js +103 -0
  6. package/dist/lib/decide.js +81 -90
  7. package/dist/lib/defaults.json +1 -0
  8. package/dist/lib/git/review-snapshot.js +79 -0
  9. package/dist/lib/git/workflow.js +101 -0
  10. package/dist/lib/internal/git-workflow.js +42 -0
  11. package/dist/lib/internal/platform-checks.js +119 -0
  12. package/dist/lib/internal/platform-comment.js +129 -0
  13. package/dist/lib/internal/platform-context.js +46 -0
  14. package/dist/lib/internal/platform-issue.js +142 -0
  15. package/dist/lib/internal/platform-pr.js +146 -0
  16. package/dist/lib/internal/platform-release-notes.js +53 -0
  17. package/dist/lib/internal/release-workflow.js +320 -0
  18. package/dist/lib/internal/task-artifact.js +67 -0
  19. package/dist/lib/internal/task-context.js +43 -0
  20. package/dist/lib/internal/task-event.js +70 -0
  21. package/dist/lib/internal/task-ledger.js +114 -0
  22. package/dist/lib/internal/task-lifecycle.js +58 -0
  23. package/dist/lib/internal/task-short-id.js +83 -0
  24. package/dist/lib/internal/task-snapshot.js +47 -0
  25. package/dist/lib/internal/task-verify.js +50 -0
  26. package/dist/lib/internal/task-warning.js +74 -0
  27. package/dist/lib/platform/adapters.js +14 -0
  28. package/dist/lib/platform/context.js +146 -0
  29. package/dist/lib/platform/github-client.js +124 -0
  30. package/dist/lib/platform/github-release-notes.js +96 -0
  31. package/dist/lib/platform/issue-comments.js +409 -0
  32. package/dist/lib/platform/issue-metadata.js +183 -0
  33. package/dist/lib/platform/issues.js +619 -0
  34. package/dist/lib/platform/merged-pr-equivalence.js +54 -0
  35. package/dist/lib/platform/metadata-labels.js +28 -0
  36. package/dist/lib/platform/pr-checks.js +216 -0
  37. package/dist/lib/platform/pr-summary.js +88 -0
  38. package/dist/lib/platform/pull-request-metadata.js +38 -0
  39. package/dist/lib/platform/pull-requests.js +340 -0
  40. package/dist/lib/platform/release-notes.js +143 -0
  41. package/dist/lib/platform/releases.js +82 -0
  42. package/dist/lib/platform/types.js +22 -0
  43. package/dist/lib/platform/verification-required.js +102 -0
  44. package/dist/lib/platform/verification-sync.js +1014 -0
  45. package/dist/lib/platform/verification.js +6 -0
  46. package/dist/lib/release/channels.js +31 -0
  47. package/dist/lib/release/workflow.js +32 -0
  48. package/dist/lib/render.js +3 -2
  49. package/dist/lib/run/index.js +24 -7
  50. package/dist/lib/sandbox/build-proxy.js +63 -0
  51. package/dist/lib/sandbox/capture.js +25 -3
  52. package/dist/lib/sandbox/commands/create.js +93 -31
  53. package/dist/lib/sandbox/commands/enter.js +34 -11
  54. package/dist/lib/sandbox/commands/list-running.js +10 -8
  55. package/dist/lib/sandbox/commands/rebuild.js +24 -7
  56. package/dist/lib/sandbox/commands/show.js +2 -2
  57. package/dist/lib/sandbox/commands/start.js +53 -15
  58. package/dist/lib/sandbox/image-build.js +2 -1
  59. package/dist/lib/sandbox/index.js +6 -6
  60. package/dist/lib/sandbox/mounts.js +36 -0
  61. package/dist/lib/sandbox/recovery.js +562 -0
  62. package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  63. package/dist/lib/sandbox/runtimes/base.dockerfile +8 -1
  64. package/dist/lib/sandbox/runtimes/java17.dockerfile +8 -1
  65. package/dist/lib/sandbox/runtimes/java21.dockerfile +8 -1
  66. package/dist/lib/sandbox/runtimes/node20.dockerfile +8 -1
  67. package/dist/lib/sandbox/runtimes/node22.dockerfile +8 -1
  68. package/dist/lib/sandbox/runtimes/python3.dockerfile +8 -1
  69. package/dist/lib/sandbox/shell.js +2 -1
  70. package/dist/lib/sandbox/task-resolver.js +5 -1
  71. package/dist/lib/sandbox/tools.js +19 -0
  72. package/dist/lib/server/protocol.js +5 -5
  73. package/dist/lib/task/activity-log.js +61 -0
  74. package/dist/lib/task/artifact-lifecycle.js +427 -0
  75. package/dist/lib/task/command-options.js +30 -0
  76. package/dist/lib/task/commands/cat.js +36 -6
  77. package/dist/lib/task/commands/decisions.js +80 -46
  78. package/dist/lib/task/commands/files.js +21 -7
  79. package/dist/lib/task/commands/grep.js +55 -7
  80. package/dist/lib/task/commands/issue-body.js +33 -19
  81. package/dist/lib/task/commands/log.js +27 -70
  82. package/dist/lib/task/commands/show.js +20 -7
  83. package/dist/lib/task/commands/status.js +18 -8
  84. package/dist/lib/task/decision-intents.js +154 -0
  85. package/dist/lib/task/decision-items.js +53 -0
  86. package/dist/lib/task/events.js +318 -0
  87. package/dist/lib/task/frontmatter.js +159 -1
  88. package/dist/lib/task/implementation-inputs.js +117 -0
  89. package/dist/lib/task/index.js +12 -9
  90. package/dist/lib/task/issue-form.js +21 -6
  91. package/dist/lib/task/ledger-intents.js +185 -0
  92. package/dist/lib/task/ledger.js +65 -35
  93. package/dist/lib/task/lifecycle.js +484 -0
  94. package/dist/lib/task/resolve-ref.js +152 -32
  95. package/dist/lib/task/review-artifacts.js +101 -0
  96. package/dist/lib/task/review-fingerprint.js +55 -0
  97. package/dist/lib/task/sections.js +358 -4
  98. package/dist/lib/task/short-id.js +292 -7
  99. package/dist/lib/task/snapshot.js +95 -0
  100. package/dist/lib/task/verification-checks.js +8 -0
  101. package/dist/lib/task/verification-config.js +14 -0
  102. package/dist/lib/task/verification-engine.js +923 -0
  103. package/dist/lib/task/verification-review.js +3 -0
  104. package/dist/lib/task/verification-types.js +2 -0
  105. package/dist/lib/task/verification.js +113 -0
  106. package/dist/lib/task/workflow-warning-intents.js +131 -0
  107. package/dist/lib/task/workflow-warnings.js +10 -78
  108. package/dist/lib/task/write.js +241 -0
  109. package/lib/decide.ts +57 -97
  110. package/lib/defaults.json +1 -0
  111. package/lib/git/review-snapshot.ts +73 -0
  112. package/lib/git/workflow.ts +101 -0
  113. package/lib/internal/git-workflow.ts +37 -0
  114. package/lib/internal/platform-checks.ts +101 -0
  115. package/lib/internal/platform-comment.ts +99 -0
  116. package/lib/internal/platform-context.ts +33 -0
  117. package/lib/internal/platform-issue.ts +116 -0
  118. package/lib/internal/platform-pr.ts +119 -0
  119. package/lib/internal/platform-release-notes.ts +55 -0
  120. package/lib/internal/release-workflow.ts +288 -0
  121. package/lib/internal/task-artifact.ts +47 -0
  122. package/lib/internal/task-context.ts +35 -0
  123. package/lib/internal/task-event.ts +51 -0
  124. package/lib/internal/task-ledger.ts +86 -0
  125. package/lib/internal/task-lifecycle.ts +41 -0
  126. package/lib/internal/task-short-id.ts +55 -0
  127. package/lib/internal/task-snapshot.ts +32 -0
  128. package/lib/internal/task-verify.ts +33 -0
  129. package/lib/internal/task-warning.ts +50 -0
  130. package/lib/platform/adapters.ts +30 -0
  131. package/lib/platform/context.ts +164 -0
  132. package/lib/platform/github-client.ts +146 -0
  133. package/lib/platform/github-release-notes.ts +132 -0
  134. package/lib/platform/issue-comments.ts +479 -0
  135. package/lib/platform/issue-metadata.ts +250 -0
  136. package/lib/platform/issues.ts +693 -0
  137. package/lib/platform/merged-pr-equivalence.ts +70 -0
  138. package/lib/platform/metadata-labels.ts +33 -0
  139. package/lib/platform/pr-checks.ts +247 -0
  140. package/lib/platform/pr-summary.ts +90 -0
  141. package/lib/platform/pull-request-metadata.ts +69 -0
  142. package/lib/platform/pull-requests.ts +386 -0
  143. package/lib/platform/release-notes.ts +167 -0
  144. package/lib/platform/releases.ts +71 -0
  145. package/lib/platform/types.ts +74 -0
  146. package/lib/platform/verification-required.ts +109 -0
  147. package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
  148. package/lib/platform/verification.ts +11 -0
  149. package/lib/release/channels.ts +30 -0
  150. package/lib/release/workflow.ts +31 -0
  151. package/lib/render.ts +3 -2
  152. package/lib/run/index.ts +25 -7
  153. package/lib/sandbox/build-proxy.ts +94 -0
  154. package/lib/sandbox/capture.ts +29 -3
  155. package/lib/sandbox/commands/create.ts +120 -36
  156. package/lib/sandbox/commands/enter.ts +38 -11
  157. package/lib/sandbox/commands/list-running.ts +10 -8
  158. package/lib/sandbox/commands/rebuild.ts +29 -7
  159. package/lib/sandbox/commands/show.ts +2 -2
  160. package/lib/sandbox/commands/start.ts +50 -16
  161. package/lib/sandbox/image-build.ts +4 -1
  162. package/lib/sandbox/index.ts +6 -6
  163. package/lib/sandbox/mounts.ts +55 -0
  164. package/lib/sandbox/recovery.ts +828 -0
  165. package/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  166. package/lib/sandbox/runtimes/base.dockerfile +8 -1
  167. package/lib/sandbox/runtimes/java17.dockerfile +8 -1
  168. package/lib/sandbox/runtimes/java21.dockerfile +8 -1
  169. package/lib/sandbox/runtimes/node20.dockerfile +8 -1
  170. package/lib/sandbox/runtimes/node22.dockerfile +8 -1
  171. package/lib/sandbox/runtimes/python3.dockerfile +8 -1
  172. package/lib/sandbox/shell.ts +3 -1
  173. package/lib/sandbox/task-resolver.ts +5 -1
  174. package/lib/sandbox/tools.ts +31 -0
  175. package/lib/server/protocol.ts +5 -5
  176. package/lib/task/activity-log.ts +62 -0
  177. package/lib/task/artifact-lifecycle.ts +484 -0
  178. package/lib/task/command-options.ts +32 -0
  179. package/lib/task/commands/cat.ts +22 -9
  180. package/lib/task/commands/decisions.ts +49 -47
  181. package/lib/task/commands/files.ts +14 -6
  182. package/lib/task/commands/grep.ts +34 -7
  183. package/lib/task/commands/issue-body.ts +26 -21
  184. package/lib/task/commands/log.ts +17 -70
  185. package/lib/task/commands/show.ts +14 -6
  186. package/lib/task/commands/status.ts +17 -7
  187. package/lib/task/decision-intents.ts +163 -0
  188. package/lib/task/decision-items.ts +64 -0
  189. package/lib/task/events.ts +320 -0
  190. package/lib/task/frontmatter.ts +202 -2
  191. package/lib/task/implementation-inputs.ts +137 -0
  192. package/lib/task/index.ts +12 -9
  193. package/lib/task/issue-form.ts +24 -6
  194. package/lib/task/ledger-intents.ts +201 -0
  195. package/lib/task/ledger.ts +77 -31
  196. package/lib/task/lifecycle.ts +458 -0
  197. package/lib/task/resolve-ref.ts +197 -36
  198. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  199. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +26 -12
  200. package/lib/task/sections.ts +486 -4
  201. package/lib/task/short-id.ts +403 -9
  202. package/lib/task/snapshot.ts +143 -0
  203. package/lib/task/verification-checks.ts +9 -0
  204. package/lib/task/verification-config.ts +20 -0
  205. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +230 -421
  206. package/lib/task/verification-review.ts +10 -0
  207. package/lib/task/verification-types.ts +29 -0
  208. package/lib/task/verification.ts +156 -0
  209. package/lib/task/workflow-warning-intents.ts +142 -0
  210. package/lib/task/workflow-warnings.ts +10 -78
  211. package/lib/task/write.ts +468 -0
  212. package/package.json +4 -2
  213. package/templates/.agents/README.en.md +4 -3
  214. package/templates/.agents/README.zh-CN.md +4 -3
  215. package/templates/.agents/rules/README.en.md +6 -5
  216. package/templates/.agents/rules/README.zh-CN.md +6 -5
  217. package/templates/.agents/rules/create-issue.en.md +1 -1
  218. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  219. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  220. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  221. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  222. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  223. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  224. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  225. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  226. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  227. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  228. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  229. package/templates/.agents/rules/issue-sync.en.md +1 -1
  230. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  231. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  232. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  233. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  234. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  235. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  236. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  237. package/templates/.agents/rules/next-step-output.en.md +12 -11
  238. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  239. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  240. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  241. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  242. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  243. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  244. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  245. package/templates/.agents/rules/pr-sync.en.md +30 -3
  246. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  247. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  248. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  249. package/templates/.agents/rules/release-commands.en.md +2 -2
  250. package/templates/.agents/rules/release-commands.github.en.md +10 -40
  251. package/templates/.agents/rules/release-commands.github.zh-CN.md +9 -39
  252. package/templates/.agents/rules/release-commands.zh-CN.md +2 -2
  253. package/templates/.agents/rules/review-handshake.en.md +10 -6
  254. package/templates/.agents/rules/review-handshake.zh-CN.md +10 -6
  255. package/templates/.agents/rules/task-management.en.md +11 -2
  256. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  257. package/templates/.agents/rules/task-short-id.en.md +25 -29
  258. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  259. package/templates/.agents/rules/testing-discipline.en.md +20 -2
  260. package/templates/.agents/rules/testing-discipline.zh-CN.md +20 -2
  261. package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
  262. package/templates/.agents/scripts/task-short-id.js +71 -533
  263. package/templates/.agents/skills/analyze-task/SKILL.en.md +26 -56
  264. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +30 -60
  265. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  266. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  267. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  268. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  269. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  270. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  271. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  272. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  273. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  274. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  275. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  276. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  277. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  278. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  279. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  280. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  281. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  282. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  283. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  284. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  285. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  286. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  287. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  288. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  289. package/templates/.agents/skills/commit/SKILL.en.md +13 -11
  290. package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
  291. package/templates/.agents/skills/commit/config/verify.json +1 -2
  292. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  293. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  294. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  295. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  296. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  297. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  298. package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
  299. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
  300. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  301. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  302. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  303. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  304. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  305. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  306. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  307. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  308. package/templates/.agents/skills/complete-task/config/verify.en.json +10 -7
  309. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +10 -7
  310. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  311. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  312. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  313. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  314. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  315. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -38
  316. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +16 -37
  317. package/templates/.agents/skills/create-task/SKILL.en.md +16 -13
  318. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +16 -13
  319. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  320. package/templates/.agents/skills/create-task/reference/context-capture.en.md +29 -0
  321. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +29 -0
  322. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  323. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  324. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  325. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  326. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  327. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  328. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  329. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  330. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  331. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  332. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  333. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  334. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  335. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  336. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  337. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  338. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  339. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  340. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  341. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  342. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  343. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  344. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  345. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  346. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  347. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  348. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  349. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  350. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  351. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  352. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  353. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  354. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  355. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  356. package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
  357. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
  358. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  359. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  360. package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
  361. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
  362. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  363. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  364. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  365. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  366. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  367. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  368. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  369. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  370. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  371. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  372. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  373. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  374. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
  375. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
  376. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
  377. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  378. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  379. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  380. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  381. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  382. package/templates/.agents/templates/task.en.md +24 -1
  383. package/templates/.agents/templates/task.zh-CN.md +24 -1
  384. package/templates/.claude/commands/analyze-task.en.md +1 -1
  385. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  386. package/templates/.claude/commands/block-task.en.md +1 -1
  387. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  388. package/templates/.claude/commands/cancel-task.en.md +1 -1
  389. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  390. package/templates/.claude/commands/check-task.en.md +1 -1
  391. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  392. package/templates/.claude/commands/code-task.en.md +1 -1
  393. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  394. package/templates/.claude/commands/commit.en.md +1 -0
  395. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  396. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  397. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  398. package/templates/.claude/commands/complete-task.en.md +1 -1
  399. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  400. package/templates/.claude/commands/create-pr.en.md +1 -1
  401. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  402. package/templates/.claude/commands/plan-task.en.md +1 -1
  403. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  404. package/templates/.claude/commands/review-analysis.en.md +1 -1
  405. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  406. package/templates/.claude/commands/review-code.en.md +1 -1
  407. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  408. package/templates/.claude/commands/review-plan.en.md +1 -1
  409. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  410. package/templates/.claude/commands/watch-pr.en.md +1 -1
  411. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  412. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  413. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  414. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  415. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  416. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  417. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  418. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  419. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  420. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  421. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  422. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  423. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  424. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  425. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  426. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  427. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  428. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  429. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  430. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  431. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  432. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  433. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  434. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  435. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  436. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  437. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  438. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  439. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  440. package/templates/.git-hooks/check-large-files.cjs +92 -0
  441. package/templates/.git-hooks/check-version-format.sh +5 -1
  442. package/templates/.git-hooks/pre-commit +1 -0
  443. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  444. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  445. package/templates/.opencode/commands/check-task.en.md +1 -1
  446. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  447. package/templates/.opencode/commands/code-task.en.md +1 -1
  448. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  449. package/templates/.opencode/commands/commit.en.md +2 -0
  450. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  451. package/templates/.opencode/commands/complete-task.en.md +1 -1
  452. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  453. package/templates/.opencode/commands/plan-task.en.md +1 -1
  454. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  455. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  456. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  457. package/templates/.opencode/commands/review-code.en.md +1 -1
  458. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  459. package/templates/.opencode/commands/review-plan.en.md +1 -1
  460. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  461. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
  462. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  463. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
  464. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  465. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  466. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  467. package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
@@ -0,0 +1,484 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import { resolveTaskRef } from './resolve-ref.ts';
5
+ import type { ResolveTaskRefErrorCode, TaskWorkspaceState } from './resolve-ref.ts';
6
+ import { locateActivityLog } from './activity-log.ts';
7
+ import { parseImplementationInputs, selectPendingImplementationInput } from './implementation-inputs.ts';
8
+ import { extractSection, findSectionHeading } from './sections.ts';
9
+
10
+ const artifactFamilyCatalog = [
11
+ { family: 'analysis', sectionAliases: ['分析', 'Analysis'], heading: '分析', labels: ['需求分析报告', 'Requirements Analysis'] },
12
+ { family: 'review-analysis', sectionAliases: ['审查反馈', 'Review Feedback'], heading: '审查反馈', labels: ['需求分析审查', 'Analysis Review'] },
13
+ { family: 'plan', sectionAliases: ['设计', 'Design'], heading: '设计', labels: ['技术方案', 'Technical Plan'] },
14
+ { family: 'review-plan', sectionAliases: ['审查反馈', 'Review Feedback'], heading: '审查反馈', labels: ['技术方案审查', 'Plan Review'] },
15
+ { family: 'code', sectionAliases: ['实现备注', 'Implementation Notes'], heading: '实现备注', labels: ['实现报告', 'Implementation Report'] },
16
+ { family: 'review-code', sectionAliases: ['审查反馈', 'Review Feedback'], heading: '审查反馈', labels: ['代码审查', 'Code Review'] },
17
+ { family: 'manual-validation', sectionAliases: ['实现备注', 'Implementation Notes'], heading: '实现备注', labels: ['人工验证', 'Manual Validation'] }
18
+ ] as const;
19
+
20
+ type ArtifactFamily = (typeof artifactFamilyCatalog)[number]['family'];
21
+ type ArtifactFamilySpec = (typeof artifactFamilyCatalog)[number];
22
+ type ArtifactIdentity = {
23
+ family: ArtifactFamily;
24
+ round: number;
25
+ name: string;
26
+ path: string;
27
+ size: number;
28
+ mtimeMs: number;
29
+ };
30
+ type ArtifactDiagnosticCode =
31
+ | 'NONCANONICAL_NAME' | 'ROUND_OUT_OF_RANGE' | 'MISSING_BASE' | 'ROUND_GAP'
32
+ | 'DUPLICATE_LOGICAL_ROUND' | 'NON_REGULAR_FILE' | 'SYMBOLIC_LINK'
33
+ | 'FILESYSTEM_RACE' | 'CATALOG_CONFLICT' | 'BROKEN_REFERENCE';
34
+ type ArtifactDiagnostic = {
35
+ code: ArtifactDiagnosticCode;
36
+ family: ArtifactFamily;
37
+ name: string | null;
38
+ message: string;
39
+ };
40
+ type ArtifactErrorCode =
41
+ | ResolveTaskRefErrorCode | 'ARTIFACT_FAMILY_UNKNOWN' | 'ARTIFACT_DIRECTORY_READ_FAILED'
42
+ | 'ARTIFACT_TOPOLOGY_CONFLICT' | 'ARTIFACT_INPUT_MISSING'
43
+ | 'ARTIFACT_REFERENCE_INVALID' | 'ARTIFACT_PATH_INVALID'
44
+ | 'ARTIFACT_IDENTITY_INVALID' | 'ARTIFACT_NOT_FOUND'
45
+ | 'ARTIFACT_NOT_REGULAR' | 'ARTIFACT_NOT_READABLE' | 'ARTIFACT_MODE_REFUSED';
46
+ type ArtifactError = { code: ArtifactErrorCode; message: string };
47
+ type ArtifactInventoryResult = {
48
+ status: 'ready' | 'failed';
49
+ changed: false;
50
+ requestRef: string;
51
+ taskId: string | null;
52
+ taskDir: string | null;
53
+ taskState: TaskWorkspaceState | null;
54
+ family: ArtifactFamily | string;
55
+ artifacts: readonly ArtifactIdentity[];
56
+ latest: ArtifactIdentity | null;
57
+ next: { round: number; name: string } | null;
58
+ reviewedInput: ArtifactIdentity | null;
59
+ diagnostics: readonly ArtifactDiagnostic[];
60
+ error: ArtifactError | null;
61
+ };
62
+ type ArtifactContextStatus = 'ready' | 'refused' | 'failed';
63
+ type CodeArtifactMode = 'init' | 'fix' | 'decision' | 'refused' | 'error';
64
+ type ArtifactContextResult = Omit<ArtifactInventoryResult, 'status'> & {
65
+ status: ArtifactContextStatus;
66
+ inputs: readonly ArtifactIdentity[];
67
+ codeMode: {
68
+ mode: CodeArtifactMode;
69
+ codeMax: number;
70
+ reviewMax: number;
71
+ verdict: string | null;
72
+ reviewArtifact: string | null;
73
+ implementationInput: string | null;
74
+ decisionId: string | null;
75
+ decisionEvidence: string | null;
76
+ message: string;
77
+ } | null;
78
+ };
79
+ type InspectOptions = { repoRoot?: string };
80
+
81
+ const FAMILY_SET = new Set<string>(artifactFamilyCatalog.map((item) => item.family));
82
+ const BLOCKING_DIAGNOSTICS = new Set<ArtifactDiagnosticCode>([
83
+ 'NONCANONICAL_NAME', 'ROUND_OUT_OF_RANGE', 'MISSING_BASE', 'ROUND_GAP',
84
+ 'DUPLICATE_LOGICAL_ROUND', 'NON_REGULAR_FILE', 'SYMBOLIC_LINK',
85
+ 'FILESYSTEM_RACE', 'CATALOG_CONFLICT'
86
+ ]);
87
+
88
+ function familySpec(family: string): ArtifactFamilySpec | null {
89
+ return artifactFamilyCatalog.find((item) => item.family === family) ?? null;
90
+ }
91
+
92
+ function artifactName(family: ArtifactFamily, round: number): string {
93
+ if (!FAMILY_SET.has(family)) throw new Error(`unknown artifact family '${family}'`);
94
+ if (!Number.isSafeInteger(round) || round < 1) throw new Error('artifact round must be a safe positive integer');
95
+ return round === 1 ? `${family}.md` : `${family}-r${round}.md`;
96
+ }
97
+
98
+ function parseArtifactName(name: string): { family: ArtifactFamily; round: number; name: string } | null {
99
+ if (path.basename(name) !== name) return null;
100
+ const matches: Array<{ family: ArtifactFamily; round: number; name: string }> = [];
101
+ for (const spec of artifactFamilyCatalog) {
102
+ if (name === `${spec.family}.md`) matches.push({ family: spec.family, round: 1, name });
103
+ const match = new RegExp(`^${escapeRegExp(spec.family)}-r([1-9]\\d*)\\.md$`).exec(name);
104
+ if (!match) continue;
105
+ const round = Number(match[1]);
106
+ if (Number.isSafeInteger(round) && round >= 2 && String(round) === match[1]) {
107
+ matches.push({ family: spec.family, round, name });
108
+ }
109
+ }
110
+ return matches.length === 1 ? matches[0]! : null;
111
+ }
112
+
113
+ function escapeRegExp(value: string): string {
114
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
115
+ }
116
+
117
+ function failure(requestRef: string, family: string, error: ArtifactError, extra: Partial<ArtifactInventoryResult> = {}): ArtifactInventoryResult {
118
+ return {
119
+ status: 'failed', changed: false, requestRef, taskId: null, taskDir: null,
120
+ taskState: null, family, artifacts: [], latest: null, next: null,
121
+ reviewedInput: null, diagnostics: [], error, ...extra
122
+ };
123
+ }
124
+
125
+ function diagnostic(code: ArtifactDiagnosticCode, family: ArtifactFamily, name: string | null, message: string): ArtifactDiagnostic {
126
+ return { code, family, name, message };
127
+ }
128
+
129
+ function inspectTaskArtifacts(taskRef: string, family: string, options: InspectOptions = {}): ArtifactInventoryResult {
130
+ const spec = familySpec(family);
131
+ if (!spec) return failure(taskRef, family, { code: 'ARTIFACT_FAMILY_UNKNOWN', message: `unknown artifact family '${family}'` });
132
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
133
+ if (!resolved.ok) return failure(taskRef, family, { code: resolved.code, message: resolved.message }, { taskId: resolved.taskId });
134
+ return inspectArtifactDirectory(resolved.taskDir, spec.family, {
135
+ requestRef: taskRef, taskId: resolved.taskId, taskState: resolved.state
136
+ });
137
+ }
138
+
139
+ function inspectArtifactDirectory(
140
+ taskDir: string,
141
+ family: ArtifactFamily,
142
+ identity: { requestRef?: string; taskId?: string; taskState?: TaskWorkspaceState } = {}
143
+ ): ArtifactInventoryResult {
144
+ const requestRef = identity.requestRef ?? taskDir;
145
+ let entries: fs.Dirent[];
146
+ try { entries = fs.readdirSync(taskDir, { withFileTypes: true }); }
147
+ catch (error) {
148
+ return failure(requestRef, family, { code: 'ARTIFACT_DIRECTORY_READ_FAILED', message: String(error) }, {
149
+ taskId: identity.taskId ?? null, taskDir, taskState: identity.taskState ?? null
150
+ });
151
+ }
152
+ const artifacts: ArtifactIdentity[] = [];
153
+ const diagnostics: ArtifactDiagnostic[] = [];
154
+ for (const entry of entries) {
155
+ const parsed = parseArtifactName(entry.name);
156
+ const reserved = entry.name.toLowerCase().startsWith(`${family.toLowerCase()}-r`) || entry.name.toLowerCase() === `${family.toLowerCase()}.md`;
157
+ if (!parsed || parsed.family !== family) {
158
+ if (reserved) {
159
+ const roundText = new RegExp(`^${escapeRegExp(family)}-r(.+)\\.md$`, 'i').exec(entry.name)?.[1];
160
+ const code = roundText && /^\d+$/.test(roundText) && !Number.isSafeInteger(Number(roundText))
161
+ ? 'ROUND_OUT_OF_RANGE' : 'NONCANONICAL_NAME';
162
+ diagnostics.push(diagnostic(code, family, entry.name, `noncanonical ${family} artifact candidate '${entry.name}' (verify whether this is an unrelated file with a reserved prefix)`));
163
+ }
164
+ continue;
165
+ }
166
+ const abs = path.join(taskDir, entry.name);
167
+ try {
168
+ const stat = fs.lstatSync(abs);
169
+ if (stat.isSymbolicLink()) {
170
+ diagnostics.push(diagnostic('SYMBOLIC_LINK', family, entry.name, `symbolic links are not workflow artifacts: ${entry.name}`));
171
+ continue;
172
+ }
173
+ if (!stat.isFile()) {
174
+ diagnostics.push(diagnostic('NON_REGULAR_FILE', family, entry.name, `artifact is not a regular file: ${entry.name}`));
175
+ continue;
176
+ }
177
+ try { fs.accessSync(abs, fs.constants.R_OK); }
178
+ catch {
179
+ diagnostics.push(diagnostic('FILESYSTEM_RACE', family, entry.name, `artifact is not readable: ${entry.name}`));
180
+ continue;
181
+ }
182
+ artifacts.push({ ...parsed, path: abs, size: stat.size, mtimeMs: stat.mtimeMs });
183
+ } catch (error) {
184
+ diagnostics.push(diagnostic('FILESYSTEM_RACE', family, entry.name, String(error)));
185
+ }
186
+ }
187
+ artifacts.sort((left, right) => left.round - right.round);
188
+ const rounds = new Set(artifacts.map((item) => item.round));
189
+ if (artifacts.length > 0 && !rounds.has(1)) diagnostics.push(diagnostic('MISSING_BASE', family, null, `${family}.md is missing`));
190
+ const max = artifacts.at(-1)?.round ?? 0;
191
+ for (let round = 1; round <= max; round += 1) {
192
+ if (!rounds.has(round)) diagnostics.push(diagnostic('ROUND_GAP', family, null, `${artifactName(family, round)} is missing`));
193
+ }
194
+ const latest = artifacts.at(-1) ?? null;
195
+ const reviewedInput = family.startsWith('review-') && latest
196
+ ? resolveReviewedInput(taskDir, latest, family === 'review-analysis' ? 'analysis' : family === 'review-plan' ? 'plan' : 'code', diagnostics)
197
+ : null;
198
+ return {
199
+ status: 'ready', changed: false, requestRef, taskId: identity.taskId ?? null,
200
+ taskDir, taskState: identity.taskState ?? null, family, artifacts, latest,
201
+ next: { round: max + 1, name: artifactName(family, max + 1) },
202
+ reviewedInput, diagnostics, error: null
203
+ };
204
+ }
205
+
206
+ function resolveReviewedInput(
207
+ taskDir: string,
208
+ review: ArtifactIdentity,
209
+ expectedFamily: ArtifactFamily,
210
+ diagnostics: ArtifactDiagnostic[]
211
+ ): ArtifactIdentity | null {
212
+ let content: string;
213
+ try { content = fs.readFileSync(review.path, 'utf8'); }
214
+ catch (error) {
215
+ diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, String(error)));
216
+ return null;
217
+ }
218
+ const lines = content.split(/\r?\n/);
219
+ const header = lines.findIndex((line) => /\*\*(?:审查输入|Review Input)\*\*[::]/.test(line));
220
+ const referenceBlock = header >= 0 ? lines.slice(header, header + 12).join('\n') : '';
221
+ const candidates = [...referenceBlock.matchAll(/`([^`]+\.md)`/g)].map((match) => match[1]!);
222
+ const parsed = candidates.map((name) => parseArtifactName(name)).find((item) => item?.family === expectedFamily);
223
+ if (!parsed) {
224
+ diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, `${review.name} does not reference a canonical ${expectedFamily} artifact`));
225
+ return null;
226
+ }
227
+ const abs = path.join(taskDir, parsed.name);
228
+ try {
229
+ const stat = fs.lstatSync(abs);
230
+ if (!stat.isFile() || stat.isSymbolicLink()) throw new Error('referenced input is not a regular file');
231
+ if (stat.mtimeMs > review.mtimeMs) {
232
+ diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, `${parsed.name} is newer than ${review.name}`));
233
+ return null;
234
+ }
235
+ return { ...parsed, path: abs, size: stat.size, mtimeMs: stat.mtimeMs };
236
+ } catch (error) {
237
+ diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, `${parsed.name}: ${String(error)}`));
238
+ return null;
239
+ }
240
+ }
241
+
242
+ function extractMarkdownSection(content: string, names: readonly string[]): string {
243
+ const lines = content.split(/\r?\n/);
244
+ const allowed = new Set(names);
245
+ const start = lines.findIndex((line) => {
246
+ const match = /^##\s+(.+?)\s*$/.exec(line.trim());
247
+ return Boolean(match?.[1] && allowed.has(match[1]));
248
+ });
249
+ if (start === -1) return '';
250
+ let end = lines.length;
251
+ for (let index = start + 1; index < lines.length; index += 1) {
252
+ if (/^##\s+/.test(lines[index]!)) { end = index; break; }
253
+ }
254
+ return lines.slice(start + 1, end).join('\n');
255
+ }
256
+
257
+ function assertWritableInventory(inventory: ArtifactInventoryResult): ArtifactError | null {
258
+ if (inventory.status === 'failed') return inventory.error;
259
+ const blockers = inventory.diagnostics.filter((item) => BLOCKING_DIAGNOSTICS.has(item.code));
260
+ return blockers.length === 0 ? null : {
261
+ code: 'ARTIFACT_TOPOLOGY_CONFLICT',
262
+ message: blockers.map((item) => `${item.code}: ${item.message}`).join('; ')
263
+ };
264
+ }
265
+
266
+ const REQUIRED_INPUT: Partial<Record<ArtifactFamily, ArtifactFamily>> = {
267
+ 'review-analysis': 'analysis', plan: 'analysis', 'review-plan': 'plan', 'review-code': 'code'
268
+ };
269
+ const OPTIONAL_CONTEXT: Partial<Record<ArtifactFamily, { family: ArtifactFamily; requireReference?: boolean }>> = {
270
+ analysis: { family: 'review-analysis', requireReference: true },
271
+ plan: { family: 'review-plan', requireReference: true },
272
+ 'review-code': { family: 'review-plan' },
273
+ 'manual-validation': { family: 'review-code' }
274
+ };
275
+
276
+ function resolveArtifactContext(taskRef: string, family: string, options: InspectOptions = {}): ArtifactContextResult {
277
+ const inventory = inspectTaskArtifacts(taskRef, family, options);
278
+ if (inventory.status === 'failed') return { ...inventory, inputs: [], codeMode: null };
279
+ const writableError = assertWritableInventory(inventory);
280
+ if (writableError) return { ...inventory, status: 'failed', inputs: [], codeMode: null, error: writableError };
281
+ if (inventory.family === 'code') return resolveCodeContext(inventory, options);
282
+ const required = REQUIRED_INPUT[inventory.family as ArtifactFamily];
283
+ const inputs: ArtifactIdentity[] = [];
284
+ if (required) {
285
+ const input = inspectTaskArtifacts(taskRef, required, options);
286
+ if (input.status === 'failed' || !input.latest) {
287
+ return { ...inventory, status: 'failed', inputs, codeMode: null, error: { code: 'ARTIFACT_INPUT_MISSING', message: `latest ${required} artifact is required` } };
288
+ }
289
+ inputs.push(input.latest);
290
+ }
291
+ const optional = OPTIONAL_CONTEXT[inventory.family as ArtifactFamily];
292
+ if (optional) {
293
+ const context = inspectTaskArtifacts(taskRef, optional.family, options);
294
+ if (context.status === 'ready' && context.latest) {
295
+ if (optional.requireReference && !context.reviewedInput) {
296
+ return { ...inventory, status: 'failed', inputs, codeMode: null, error: { code: 'ARTIFACT_REFERENCE_INVALID', message: `${context.latest.name} has no valid reviewed input` } };
297
+ }
298
+ inputs.push(context.latest);
299
+ }
300
+ }
301
+ return { ...inventory, inputs, codeMode: null };
302
+ }
303
+
304
+ function resolveCodeContext(inventory: ArtifactInventoryResult, options: InspectOptions): ArtifactContextResult {
305
+ const taskRef = inventory.requestRef;
306
+ const plan = inspectTaskArtifacts(taskRef, 'plan', options);
307
+ if (plan.status === 'failed' || !plan.latest) return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', 'latest plan artifact is required');
308
+ const reviewPlan = inspectTaskArtifacts(taskRef, 'review-plan', options);
309
+ const reviewCode = inspectTaskArtifacts(taskRef, 'review-code', options);
310
+ const latestCode = inventory.latest;
311
+ const codeMax = latestCode?.round ?? 0;
312
+ const reviewMax = reviewCode.latest?.round ?? 0;
313
+ const inputs = [plan.latest];
314
+ if (!latestCode) {
315
+ if (!reviewPlan.latest || reviewPlan.reviewedInput?.name !== plan.latest.name) {
316
+ return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', `latest plan '${plan.latest.name}' requires a matching approved review-plan`);
317
+ }
318
+ const verdict = parseVerdict(reviewPlan.latest.path);
319
+ if (!verdict.ok) return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', verdict.message, reviewPlan.latest.name);
320
+ if (verdict.verdict !== 'Approved') {
321
+ return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', `latest ${reviewPlan.latest.name} is not approved`, reviewPlan.latest.name);
322
+ }
323
+ return withCodeMode(inventory, inputs, 'ready', 'init', codeMax, reviewMax, null, null,
324
+ 'No prior code artifact. Starting initial implementation (round 1 -> code.md).');
325
+ }
326
+ if (reviewPlan.latest && reviewPlan.reviewedInput?.name === plan.latest.name) {
327
+ const verdict = parseVerdict(reviewPlan.latest.path);
328
+ if (verdict.ok && verdict.verdict === 'Approved' && reviewPlan.latest.mtimeMs > latestCode.mtimeMs) {
329
+ return withCodeMode(inventory, inputs, 'ready', 'init', codeMax, reviewMax, verdict.verdict, reviewPlan.latest.name,
330
+ `Latest ${reviewPlan.latest.name} is approved and newer than the latest code artifact. Entering replan-driven init.`);
331
+ }
332
+ }
333
+ if (reviewMax < codeMax) {
334
+ const expected = artifactName('review-code', codeMax);
335
+ return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', `${expected} is required before another code round`, expected);
336
+ }
337
+ const review = reviewCode.latest;
338
+ if (!review) return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', 'latest review-code artifact is required');
339
+ const verdict = parseVerdict(review.path);
340
+ if (!verdict.ok) return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', verdict.message);
341
+ if (verdict.verdict === 'Approved') {
342
+ const decision = resolveDecisionImplementationInput(inventory, review);
343
+ if ('error' in decision) return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', decision.error, review.name);
344
+ if (decision.input) {
345
+ return withCodeMode(
346
+ inventory, [...inputs, review], 'ready', 'decision', codeMax, reviewMax,
347
+ verdict.verdict, review.name, `Implementation input ${decision.input.id} requires a new code round.`,
348
+ decision.input.id, decision.input.ledgerId, decision.input.decisionEvidence
349
+ );
350
+ }
351
+ }
352
+ if (verdict.verdict === 'Approved' || verdict.verdict === 'Rejected') {
353
+ return withCodeMode(inventory, [...inputs, review], 'refused', 'refused', codeMax, reviewMax, verdict.verdict, review.name,
354
+ verdict.verdict === 'Approved'
355
+ ? `Latest ${review.name} verdict is Approved with no findings. Nothing to fix. Run /commit to proceed.`
356
+ : `Latest ${review.name} verdict is Rejected. Re-plan before re-running code-task.`);
357
+ }
358
+ return withCodeMode(inventory, [...inputs, review], 'ready', 'fix', codeMax, reviewMax, verdict.verdict, review.name,
359
+ `Latest ${review.name} requires or permits fixes. Entering fix mode.`);
360
+ }
361
+
362
+ function contextFailure(inventory: ArtifactInventoryResult, code: ArtifactErrorCode, message: string, reviewArtifact: string | null = null): ArtifactContextResult {
363
+ return { ...inventory, status: 'failed', inputs: [], codeMode: { mode: 'error', codeMax: inventory.latest?.round ?? 0, reviewMax: 0, verdict: null, reviewArtifact, implementationInput: null, decisionId: null, decisionEvidence: null, message }, error: { code, message } };
364
+ }
365
+
366
+ function withCodeMode(
367
+ inventory: ArtifactInventoryResult, inputs: ArtifactIdentity[], status: ArtifactContextStatus,
368
+ mode: CodeArtifactMode, codeMax: number, reviewMax: number, verdict: string | null,
369
+ reviewArtifact: string | null, message: string,
370
+ implementationInput: string | null = null,
371
+ decisionId: string | null = null,
372
+ decisionEvidence: string | null = null
373
+ ): ArtifactContextResult {
374
+ return { ...inventory, status, inputs, codeMode: { mode, codeMax, reviewMax, verdict, reviewArtifact, implementationInput, decisionId, decisionEvidence, message }, error: status === 'refused' ? { code: 'ARTIFACT_MODE_REFUSED', message } : null };
375
+ }
376
+
377
+ function resolveDecisionImplementationInput(
378
+ inventory: ArtifactInventoryResult,
379
+ review: ArtifactIdentity
380
+ ): { input: ReturnType<typeof selectPendingImplementationInput> } | { error: string } {
381
+ if (!inventory.taskDir) return { error: 'task directory is unavailable' };
382
+ let content: string;
383
+ try { content = fs.readFileSync(path.join(inventory.taskDir, 'task.md'), 'utf8'); }
384
+ catch (error) { return { error: String(error) }; }
385
+ let rows;
386
+ try { rows = parseImplementationInputs(content).rows; }
387
+ catch (error) { return { error: error instanceof Error ? error.message : String(error) }; }
388
+ const pending = rows.filter((row) => row.needsImplementation && row.status === 'pending');
389
+ if (pending.length === 0) return { input: null };
390
+ const activity = locateActivityLog(content);
391
+ if (!activity) return { error: 'task has no unique Activity Log section' };
392
+ const reviewEntries = activity.entries.filter((entry) =>
393
+ /^Review Code \(Round \d+\)$/.test(entry.step) && entry.note.includes(`→ ${review.name}`)
394
+ );
395
+ const completed = reviewEntries.at(-1);
396
+ if (!completed) return { error: `cannot find completed Activity Log identity for ${review.name}` };
397
+ try { return { input: selectPendingImplementationInput(rows, completed.time) }; }
398
+ catch (error) { return { error: error instanceof Error ? error.message : String(error) }; }
399
+ }
400
+
401
+ function normalizeVerdict(value: string): 'Approved' | 'Changes Requested' | 'Rejected' | null {
402
+ const normalized = value.trim().toLowerCase();
403
+ if (normalized === '通过' || normalized === 'approved') return 'Approved';
404
+ if (normalized === '需要修改' || normalized === 'changes requested') return 'Changes Requested';
405
+ if (normalized === '拒绝' || normalized === 'rejected') return 'Rejected';
406
+ return null;
407
+ }
408
+
409
+ function parseVerdict(file: string): { ok: true; verdict: string } | { ok: false; message: string } {
410
+ let content: string;
411
+ try { content = fs.readFileSync(file, 'utf8'); }
412
+ catch (error) { return { ok: false, message: String(error) }; }
413
+ const summary = extractMarkdownSection(content, ['审查摘要', 'Review Summary']);
414
+ const verdictMatch = /^[-*]?\s*\*\*(?:总体结论|Overall Verdict)\*\*[::]\s*(.+?)\s*$/im.exec(summary);
415
+ const verdict = verdictMatch?.[1] ? normalizeVerdict(verdictMatch[1]) : null;
416
+ if (!verdict) return { ok: false, message: `cannot parse verdict in ${path.basename(file)}` };
417
+ if (verdict !== 'Approved') return { ok: true, verdict };
418
+ const findings = /^[-*]?\s*\*\*(?:发现(AI 可处理)|Findings \(AI-actionable\))\*\*[::]\s*(.+?)\s*$/im.exec(summary)?.[1];
419
+ const counts = findings?.match(/(\d+)\s*(?:阻塞项|blockers?).*?(\d+)\s*(?:主要|majors?).*?(\d+)\s*(?:次要|minors?)/i);
420
+ if (!counts) return { ok: false, message: `cannot parse findings count in ${path.basename(file)}` };
421
+ return { ok: true, verdict: counts.slice(1).some((value) => Number(value) > 0) ? 'Approved-with-issues' : 'Approved' };
422
+ }
423
+
424
+ function validateCompletedArtifact(taskDir: string, family: ArtifactFamily, name: string, round?: number): { ok: true; artifact: ArtifactIdentity } | { ok: false; error: ArtifactError } {
425
+ if (path.basename(name) !== name) return { ok: false, error: { code: 'ARTIFACT_PATH_INVALID', message: 'artifact must be a top-level basename' } };
426
+ const parsed = parseArtifactName(name);
427
+ if (!parsed || parsed.family !== family || (round !== undefined && parsed.round !== round)) {
428
+ return { ok: false, error: { code: 'ARTIFACT_IDENTITY_INVALID', message: `artifact '${name}' does not match ${family}${round ? ` round ${round}` : ''}` } };
429
+ }
430
+ const abs = path.join(taskDir, name);
431
+ let stat: fs.Stats;
432
+ try { stat = fs.lstatSync(abs); }
433
+ catch { return { ok: false, error: { code: 'ARTIFACT_NOT_FOUND', message: `artifact '${name}' is not landed` } }; }
434
+ if (stat.isSymbolicLink() || !stat.isFile()) return { ok: false, error: { code: 'ARTIFACT_NOT_REGULAR', message: `artifact '${name}' is not a regular file` } };
435
+ try { fs.accessSync(abs, fs.constants.R_OK); }
436
+ catch { return { ok: false, error: { code: 'ARTIFACT_NOT_READABLE', message: `artifact '${name}' is not readable` } }; }
437
+ const inventory = inspectArtifactDirectory(taskDir, family);
438
+ const topology = assertWritableInventory(inventory);
439
+ if (topology) return { ok: false, error: topology };
440
+ const artifact = inventory.artifacts.find((item) => item.name === name);
441
+ return artifact ? { ok: true, artifact } : { ok: false, error: { code: 'ARTIFACT_NOT_FOUND', message: `artifact '${name}' is not in inventory` } };
442
+ }
443
+
444
+ function buildArtifactLinkSection(content: string, artifact: ArtifactIdentity): {
445
+ aliases: readonly string[];
446
+ heading: string;
447
+ body: string;
448
+ } {
449
+ const spec = familySpec(artifact.family)!;
450
+ const aliases = [...spec.sectionAliases];
451
+ const heading = findSectionHeading(content, aliases);
452
+ const english = heading === spec.sectionAliases[1];
453
+ const label = english
454
+ ? `${spec.labels[1]} (Round ${artifact.round})`
455
+ : `${spec.labels[0]}(Round ${artifact.round})`;
456
+ const link = `[${label}](${artifact.name})`;
457
+ let body = extractSection(content, aliases);
458
+ if (body.includes(`](${artifact.name})`)) return { aliases, heading, body };
459
+ const placeholders = new Set([
460
+ '[分析阶段的发现。哪些文件受影响?范围是什么?]',
461
+ '[Findings from the analysis phase. Which files are affected? What is the scope?]',
462
+ '[技术方案。接口、数据流、架构决策。]',
463
+ '[Technical approach. Interfaces, data flow, architecture decisions.]',
464
+ '[实现阶段的备注。做出的决策、权衡、与设计的偏差。]',
465
+ '[Notes from the code phase. Decisions made, trade-offs, deviations from design.]'
466
+ ]);
467
+ const lines = body.split(/\r?\n/);
468
+ const placeholder = lines.findIndex((line) => placeholders.has(line.trim()));
469
+ if (placeholder >= 0) lines[placeholder] = link;
470
+ else lines.push(...(body ? ['', link] : [link]));
471
+ body = lines.join('\n').replace(/^\n+|\n+$/g, '');
472
+ return { aliases, heading, body };
473
+ }
474
+
475
+ export {
476
+ artifactFamilyCatalog, artifactName, parseArtifactName, familySpec,
477
+ inspectTaskArtifacts, inspectArtifactDirectory, resolveArtifactContext,
478
+ assertWritableInventory, validateCompletedArtifact, buildArtifactLinkSection
479
+ };
480
+ export type {
481
+ ArtifactFamily, ArtifactFamilySpec, ArtifactIdentity, ArtifactDiagnostic,
482
+ ArtifactDiagnosticCode, ArtifactError, ArtifactErrorCode,
483
+ ArtifactInventoryResult, ArtifactContextResult, CodeArtifactMode, InspectOptions
484
+ };
@@ -0,0 +1,32 @@
1
+ type TaskScope = {
2
+ taskRef?: string;
3
+ positionals: string[];
4
+ explicit: boolean;
5
+ };
6
+
7
+ function parseTaskScope(args: string[]): TaskScope {
8
+ const positionals: string[] = [];
9
+ let taskRef: string | undefined;
10
+ let explicit = false;
11
+ for (let index = 0; index < args.length; index += 1) {
12
+ const arg = args[index]!;
13
+ let value: string | undefined;
14
+ if (arg === '--task' || arg === '-t') {
15
+ value = args[++index];
16
+ if (value === undefined || value === '' || value.startsWith('-')) throw new Error(`${arg} requires a value`);
17
+ } else if (arg.startsWith('--task=')) {
18
+ value = arg.slice('--task='.length);
19
+ if (value === '') throw new Error('--task requires a value');
20
+ } else {
21
+ positionals.push(arg);
22
+ continue;
23
+ }
24
+ if (explicit) throw new Error("duplicate option '--task'");
25
+ taskRef = value;
26
+ explicit = true;
27
+ }
28
+ return { taskRef, positionals, explicit };
29
+ }
30
+
31
+ export { parseTaskScope };
32
+ export type { TaskScope };
@@ -1,11 +1,15 @@
1
1
  import fs from 'node:fs';
2
- import { resolveTaskRef } from '../resolve-ref.ts';
2
+ import { parseTaskScope } from '../command-options.ts';
3
+ import { resolveTaskContext } from '../resolve-ref.ts';
3
4
  import { resolveArtifact } from '../artifacts.ts';
4
5
 
5
- const USAGE = `Usage: ai task cat <N | #N | TASK-id> <artifact | N>
6
+ const USAGE = `Usage: ai task cat <artifact | N>
7
+ ai task cat (--task <ref> | -t <ref>) <artifact | N>
8
+ ai task cat <ref> <artifact | N>
6
9
 
7
10
  Prints a task artifact's raw content to stdout.
8
- <ref> Bare numeric / '#N' short id, or a full TASK-YYYYMMDD-HHMMSS id.
11
+ One positional Uses current task context and treats the operand as the artifact.
12
+ <ref> Bare numeric short id, or a full TASK-YYYYMMDD-HHMMSS id.
9
13
  <artifact | N> Artifact filename (with or without '.md'), or the number from 'ai task files'.
10
14
  `;
11
15
 
@@ -14,12 +18,21 @@ function cat(args: string[] = []): void {
14
18
  process.stdout.write(USAGE);
15
19
  return;
16
20
  }
17
- if (args.length < 2) {
18
- process.stdout.write(USAGE);
19
- process.exitCode = 1;
20
- return;
21
+ let scope;
22
+ try { scope = parseTaskScope(args); } catch (error) {
23
+ process.stderr.write(`ai task cat: ${error instanceof Error ? error.message : String(error)}\n`); process.exitCode = 1; return;
21
24
  }
22
- const resolved = resolveTaskRef(args[0]!);
25
+ let taskRef: string | undefined;
26
+ let artifact: string | undefined;
27
+ if (scope.explicit) {
28
+ if (scope.positionals.length !== 1) { process.stdout.write(USAGE); process.exitCode = 1; return; }
29
+ taskRef = scope.taskRef; artifact = scope.positionals[0];
30
+ } else if (scope.positionals.length === 1) {
31
+ artifact = scope.positionals[0];
32
+ } else if (scope.positionals.length === 2) {
33
+ [taskRef, artifact] = scope.positionals;
34
+ } else { process.stdout.write(USAGE); process.exitCode = 1; return; }
35
+ const resolved = resolveTaskContext(taskRef);
23
36
  if (!resolved.ok) {
24
37
  process.stderr.write(`ai task cat: ${resolved.message}\n`);
25
38
  process.exitCode = 1;
@@ -27,7 +40,7 @@ function cat(args: string[] = []): void {
27
40
  }
28
41
  let artifactPath: string;
29
42
  try {
30
- artifactPath = resolveArtifact(resolved.taskDir, args[1]!);
43
+ artifactPath = resolveArtifact(resolved.taskDir, artifact!);
31
44
  } catch (e) {
32
45
  process.stderr.write(`ai task cat: ${(e as Error).message}\n`);
33
46
  process.exitCode = 1;