@fitlab-ai/agent-infra 0.9.1 → 0.9.3

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 (476) hide show
  1. package/README.md +24 -11
  2. package/README.zh-CN.md +24 -11
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +30 -0
  6. package/dist/lib/agent-client.js +163 -0
  7. package/dist/lib/agent-clients/adapter.js +337 -0
  8. package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
  9. package/dist/lib/agent-clients/adapters/claude-code.js +71 -0
  10. package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
  11. package/dist/lib/agent-clients/adapters/codex.js +63 -0
  12. package/dist/lib/agent-clients/adapters/index.js +20 -0
  13. package/dist/lib/agent-clients/adapters/opencode.js +73 -0
  14. package/dist/lib/agent-clients/config.js +215 -0
  15. package/dist/lib/agent-clients/custom-tuis.js +99 -0
  16. package/dist/lib/agent-clients/invocation.js +9 -0
  17. package/dist/lib/agent-clients/next-steps.js +47 -0
  18. package/dist/lib/agent-clients/project-assets.js +45 -0
  19. package/dist/lib/agent-clients/reconcile.js +236 -0
  20. package/dist/lib/agent-clients/registry.js +78 -0
  21. package/dist/lib/agent-clients/schema.js +75 -0
  22. package/dist/lib/agent-clients/tokens.js +49 -0
  23. package/dist/lib/agent-clients/types.js +29 -0
  24. package/dist/lib/builtin-tuis.js +9 -14
  25. package/dist/lib/defaults.json +85 -73
  26. package/dist/lib/git/review-snapshot.js +25 -10
  27. package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
  28. package/dist/lib/git/workflow.js +54 -1
  29. package/dist/lib/init.js +47 -91
  30. package/dist/lib/internal/agent-client.js +174 -0
  31. package/dist/lib/internal/git-workflow.js +7 -2
  32. package/dist/lib/internal/platform-checks.js +3 -3
  33. package/dist/lib/internal/platform-comment.js +29 -2
  34. package/dist/lib/internal/platform-issue.js +7 -0
  35. package/dist/lib/internal/platform-pr-review.js +132 -0
  36. package/dist/lib/internal/platform-pr.js +20 -2
  37. package/dist/lib/internal/platform-release-notes.js +52 -16
  38. package/dist/lib/internal/pr-review-grade.js +140 -0
  39. package/dist/lib/internal/release-workflow.js +82 -20
  40. package/dist/lib/internal/task-activity.js +73 -0
  41. package/dist/lib/internal/task-event.js +17 -1
  42. package/dist/lib/internal/task-lifecycle.js +7 -0
  43. package/dist/lib/internal/task-orchestration.js +196 -0
  44. package/dist/lib/internal/task-review.js +70 -0
  45. package/dist/lib/merge.js +2 -1
  46. package/dist/lib/platform/adapters.js +45 -1
  47. package/dist/lib/platform/change-request-git-evidence.js +113 -0
  48. package/dist/lib/platform/completion-backfill.js +122 -0
  49. package/dist/lib/platform/issue-comments.js +3 -2
  50. package/dist/lib/platform/merged-pr-equivalence.js +156 -16
  51. package/dist/lib/platform/pr-checks.js +101 -50
  52. package/dist/lib/platform/pr-review.js +166 -0
  53. package/dist/lib/platform/pull-requests.js +432 -7
  54. package/dist/lib/platform/release-notes.js +85 -3
  55. package/dist/lib/platform/releases.js +1 -1
  56. package/dist/lib/platform/verification-required.js +8 -10
  57. package/dist/lib/pr-review/evidence-grading.js +229 -0
  58. package/dist/lib/prompt.js +15 -3
  59. package/dist/lib/release/channels.js +4 -1
  60. package/dist/lib/release/workflow.js +4 -2
  61. package/dist/lib/remove-dir.js +25 -0
  62. package/dist/lib/run/tui.js +11 -7
  63. package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
  64. package/dist/lib/sandbox/clipboard/linux.js +2 -1
  65. package/dist/lib/sandbox/commands/create.js +76 -200
  66. package/dist/lib/sandbox/commands/enter.js +17 -1
  67. package/dist/lib/sandbox/commands/prune.js +2 -2
  68. package/dist/lib/sandbox/commands/rm.js +3 -2
  69. package/dist/lib/sandbox/commands/show.js +1 -1
  70. package/dist/lib/sandbox/config.js +21 -4
  71. package/dist/lib/sandbox/constants.js +3 -0
  72. package/dist/lib/sandbox/dockerfile.js +2 -1
  73. package/dist/lib/sandbox/managed-fs.js +10 -5
  74. package/dist/lib/sandbox/recovery.js +52 -36
  75. package/dist/lib/sandbox/shell.js +1 -1
  76. package/dist/lib/sandbox/tool-types.js +8 -0
  77. package/dist/lib/sandbox/tools.js +2 -126
  78. package/dist/lib/task/activity-intent.js +101 -0
  79. package/dist/lib/task/artifact-lifecycle.js +3 -50
  80. package/dist/lib/task/commands/decisions.js +50 -20
  81. package/dist/lib/task/commands/log.js +15 -14
  82. package/dist/lib/task/delegation-receipts.js +128 -0
  83. package/dist/lib/task/events.js +146 -8
  84. package/dist/lib/task/finalization-artifacts.js +35 -0
  85. package/dist/lib/task/lifecycle-execution.js +46 -0
  86. package/dist/lib/task/orchestration.js +784 -0
  87. package/dist/lib/task/review-artifacts.js +143 -59
  88. package/dist/lib/task/review-finalization.js +186 -0
  89. package/dist/lib/task/review-fingerprint.js +4 -0
  90. package/dist/lib/task/task-execution-lock.js +231 -0
  91. package/dist/lib/task/verification-checks.js +2 -1
  92. package/dist/lib/task/verification-engine.js +372 -28
  93. package/dist/lib/task/verification-review.js +1 -1
  94. package/dist/lib/task/verification.js +5 -2
  95. package/dist/lib/task/workspace-snapshot.js +46 -0
  96. package/dist/lib/update.js +42 -161
  97. package/lib/agent-client.ts +214 -0
  98. package/lib/agent-clients/adapter.ts +534 -0
  99. package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
  100. package/lib/agent-clients/adapters/claude-code.ts +79 -0
  101. package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
  102. package/lib/agent-clients/adapters/codex.ts +67 -0
  103. package/lib/agent-clients/adapters/index.ts +27 -0
  104. package/lib/agent-clients/adapters/opencode.ts +75 -0
  105. package/lib/agent-clients/config.ts +323 -0
  106. package/lib/agent-clients/custom-tuis.ts +149 -0
  107. package/lib/agent-clients/invocation.ts +19 -0
  108. package/lib/agent-clients/next-steps.ts +85 -0
  109. package/lib/agent-clients/project-assets.ts +96 -0
  110. package/lib/agent-clients/reconcile.ts +325 -0
  111. package/lib/agent-clients/registry.ts +154 -0
  112. package/lib/agent-clients/schema.ts +80 -0
  113. package/lib/agent-clients/tokens.ts +53 -0
  114. package/lib/agent-clients/types.ts +92 -0
  115. package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
  116. package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
  117. package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
  118. package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
  119. package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
  120. package/lib/builtin-tuis.ts +16 -15
  121. package/lib/defaults.json +24 -12
  122. package/lib/git/review-snapshot.ts +39 -9
  123. package/lib/git/reviewed-commit-equivalence.ts +135 -0
  124. package/lib/git/workflow.ts +66 -2
  125. package/lib/init.ts +53 -121
  126. package/lib/internal/agent-client.ts +186 -0
  127. package/lib/internal/git-workflow.ts +6 -2
  128. package/lib/internal/platform-checks.ts +4 -4
  129. package/lib/internal/platform-comment.ts +17 -2
  130. package/lib/internal/platform-issue.ts +4 -0
  131. package/lib/internal/platform-pr-review.ts +104 -0
  132. package/lib/internal/platform-pr.ts +14 -1
  133. package/lib/internal/platform-release-notes.ts +59 -16
  134. package/lib/internal/pr-review-grade.ts +130 -0
  135. package/lib/internal/release-workflow.ts +79 -20
  136. package/lib/internal/task-activity.ts +55 -0
  137. package/lib/internal/task-event.ts +9 -1
  138. package/lib/internal/task-lifecycle.ts +4 -0
  139. package/lib/internal/task-orchestration.ts +171 -0
  140. package/lib/internal/task-review.ts +70 -0
  141. package/lib/merge.ts +2 -1
  142. package/lib/platform/adapters.ts +169 -3
  143. package/lib/platform/change-request-git-evidence.ts +159 -0
  144. package/lib/platform/completion-backfill.ts +134 -0
  145. package/lib/platform/issue-comments.ts +3 -2
  146. package/lib/platform/merged-pr-equivalence.ts +178 -19
  147. package/lib/platform/pr-checks.ts +121 -66
  148. package/lib/platform/pr-review.ts +201 -0
  149. package/lib/platform/pull-requests.ts +529 -27
  150. package/lib/platform/release-notes.ts +100 -4
  151. package/lib/platform/releases.ts +1 -1
  152. package/lib/platform/verification-required.ts +12 -10
  153. package/lib/pr-review/evidence-grading.ts +318 -0
  154. package/lib/prompt.ts +16 -3
  155. package/lib/release/channels.ts +4 -1
  156. package/lib/release/workflow.ts +4 -3
  157. package/lib/remove-dir.ts +28 -0
  158. package/lib/run/tui.ts +12 -5
  159. package/lib/sandbox/agent-client-reconciler.ts +378 -0
  160. package/lib/sandbox/clipboard/linux.ts +2 -1
  161. package/lib/sandbox/commands/create.ts +111 -212
  162. package/lib/sandbox/commands/enter.ts +23 -1
  163. package/lib/sandbox/commands/prune.ts +2 -2
  164. package/lib/sandbox/commands/rm.ts +3 -2
  165. package/lib/sandbox/commands/show.ts +1 -1
  166. package/lib/sandbox/config.ts +31 -4
  167. package/lib/sandbox/constants.ts +6 -0
  168. package/lib/sandbox/dockerfile.ts +2 -1
  169. package/lib/sandbox/managed-fs.ts +18 -5
  170. package/lib/sandbox/recovery.ts +98 -67
  171. package/lib/sandbox/shell.ts +1 -1
  172. package/lib/sandbox/tool-types.ts +143 -0
  173. package/lib/sandbox/tools.ts +5 -157
  174. package/lib/server/server.schema.json +2 -2
  175. package/lib/task/activity-intent.ts +128 -0
  176. package/lib/task/artifact-lifecycle.ts +3 -39
  177. package/lib/task/commands/decisions.ts +53 -20
  178. package/lib/task/commands/log.ts +15 -14
  179. package/lib/task/delegation-receipts.ts +199 -0
  180. package/lib/task/events.ts +164 -11
  181. package/lib/task/finalization-artifacts.ts +58 -0
  182. package/lib/task/lifecycle-execution.ts +106 -0
  183. package/lib/task/orchestration.ts +1022 -0
  184. package/lib/task/review-artifacts.ts +201 -69
  185. package/lib/task/review-finalization.ts +306 -0
  186. package/lib/task/review-fingerprint.ts +5 -0
  187. package/lib/task/task-execution-lock.ts +296 -0
  188. package/lib/task/verification-checks.ts +2 -1
  189. package/lib/task/verification-engine.ts +424 -28
  190. package/lib/task/verification-review.ts +1 -0
  191. package/lib/task/verification.ts +8 -3
  192. package/lib/task/workspace-snapshot.ts +57 -0
  193. package/lib/update.ts +48 -184
  194. package/package.json +4 -4
  195. package/templates/.agents/QUICKSTART.en.md +25 -8
  196. package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
  197. package/templates/.agents/README.en.md +29 -25
  198. package/templates/.agents/README.zh-CN.md +29 -25
  199. package/templates/.agents/hooks/lifecycle-delegation.js +75 -0
  200. package/templates/.agents/rules/README.en.md +2 -0
  201. package/templates/.agents/rules/README.zh-CN.md +2 -0
  202. package/templates/.agents/rules/commit-and-pr.en.md +1 -0
  203. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
  204. package/templates/.agents/rules/create-issue.github.en.md +4 -2
  205. package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
  206. package/templates/.agents/rules/human-decision-context.en.md +14 -12
  207. package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
  208. package/templates/.agents/rules/issue-fields.github.en.md +3 -1
  209. package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
  210. package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
  211. package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
  212. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
  213. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
  214. package/templates/.agents/rules/issue-sync.github.en.md +7 -3
  215. package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
  216. package/templates/.agents/rules/lifecycle-orchestration.en.md +24 -0
  217. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +24 -0
  218. package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
  219. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
  220. package/templates/.agents/rules/next-step-output.en.md +18 -0
  221. package/templates/.agents/rules/next-step-output.zh-CN.md +18 -0
  222. package/templates/.agents/rules/no-mid-flow-questions.en.md +19 -0
  223. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +19 -0
  224. package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
  225. package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
  226. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
  227. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
  228. package/templates/.agents/rules/pr-sync.en.md +3 -1
  229. package/templates/.agents/rules/pr-sync.github.en.md +11 -1
  230. package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
  231. package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
  232. package/templates/.agents/rules/release-commands.en.md +1 -1
  233. package/templates/.agents/rules/release-commands.github.en.md +21 -5
  234. package/templates/.agents/rules/release-commands.github.zh-CN.md +21 -5
  235. package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
  236. package/templates/.agents/rules/review-handshake.en.md +4 -4
  237. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
  238. package/templates/.agents/rules/review-method.en.md +113 -0
  239. package/templates/.agents/rules/review-method.zh-CN.md +98 -0
  240. package/templates/.agents/rules/task-management.en.md +11 -0
  241. package/templates/.agents/rules/task-management.zh-CN.md +11 -0
  242. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -12
  243. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +15 -12
  244. package/templates/.agents/skills/block-task/SKILL.en.md +11 -9
  245. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +11 -9
  246. package/templates/.agents/skills/cancel-task/SKILL.en.md +10 -8
  247. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +11 -9
  248. package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
  249. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
  250. package/templates/.agents/skills/close-codescan/SKILL.en.md +7 -5
  251. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +7 -5
  252. package/templates/.agents/skills/close-dependabot/SKILL.en.md +7 -5
  253. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +7 -5
  254. package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
  255. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +13 -10
  256. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
  257. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
  258. package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
  259. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
  260. package/templates/.agents/skills/commit/SKILL.en.md +13 -1
  261. package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -1
  262. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  263. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  264. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  265. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  266. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  267. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  268. package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
  269. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
  270. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
  271. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
  272. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  273. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  274. package/templates/.agents/skills/complete-task/SKILL.en.md +23 -8
  275. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +23 -8
  276. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  277. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  278. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
  279. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
  280. package/templates/.agents/skills/create-pr/SKILL.en.md +13 -11
  281. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +13 -11
  282. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  283. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  284. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
  285. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
  286. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
  287. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
  288. package/templates/.agents/skills/create-task/SKILL.en.md +16 -14
  289. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +16 -14
  290. package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
  291. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
  292. package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
  293. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
  294. package/templates/.agents/skills/import-issue/SKILL.en.md +10 -8
  295. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -8
  296. package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
  297. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
  298. package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
  299. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
  300. package/templates/.agents/skills/plan-task/SKILL.en.md +13 -10
  301. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
  302. package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
  303. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
  304. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  305. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  306. package/templates/.agents/skills/release/SKILL.en.md +16 -10
  307. package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
  308. package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
  309. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
  310. package/templates/.agents/skills/review-analysis/SKILL.en.md +18 -4
  311. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +19 -5
  312. package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
  313. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
  314. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
  315. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
  316. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
  317. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
  318. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
  319. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
  320. package/templates/.agents/skills/review-code/SKILL.en.md +35 -12
  321. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +35 -12
  322. package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
  323. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
  324. package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
  325. package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
  326. package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
  327. package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
  328. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
  329. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
  330. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
  331. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
  332. package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
  333. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
  334. package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
  335. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
  336. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
  337. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
  338. package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
  339. package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
  340. package/templates/.agents/skills/review-plan/SKILL.en.md +18 -4
  341. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +19 -5
  342. package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
  343. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
  344. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
  345. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
  346. package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
  347. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
  348. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
  349. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
  350. package/templates/.agents/skills/review-pr/SKILL.en.md +158 -0
  351. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +158 -0
  352. package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
  353. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
  354. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
  355. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
  356. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
  357. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
  358. package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
  359. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
  360. package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
  361. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
  362. package/templates/.agents/skills/run-task/config/verify.en.json +10 -0
  363. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +10 -0
  364. package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
  365. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
  366. package/templates/.agents/skills/test/SKILL.en.md +4 -4
  367. package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
  368. package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
  369. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
  370. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
  371. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
  372. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +664 -246
  373. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
  374. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
  375. package/templates/.agents/skills/watch-pr/SKILL.en.md +21 -21
  376. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +21 -21
  377. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
  378. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
  379. package/templates/.agents/templates/task.en.md +1 -1
  380. package/templates/.agents/templates/task.zh-CN.md +1 -1
  381. package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
  382. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
  383. package/templates/.agents/workflows/code-review.en.yaml +1 -1
  384. package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
  385. package/templates/.agents/workflows/feature-development.en.yaml +4 -4
  386. package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
  387. package/templates/.agents/workflows/refactoring.en.yaml +3 -3
  388. package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
  389. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
  390. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
  391. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
  392. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
  393. package/templates/.claude/commands/post-release.en.md +1 -0
  394. package/templates/.claude/commands/post-release.zh-CN.md +1 -0
  395. package/templates/.claude/commands/review-pr.en.md +8 -0
  396. package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
  397. package/templates/.claude/commands/run-task.en.md +8 -0
  398. package/templates/.claude/commands/run-task.zh-CN.md +8 -0
  399. package/templates/.claude/settings.json +24 -0
  400. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
  401. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
  402. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
  403. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
  404. package/templates/.gemini/commands/_project_/review-pr.en.toml +10 -0
  405. package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +10 -0
  406. package/templates/.opencode/commands/post-release.en.md +2 -0
  407. package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
  408. package/templates/.opencode/commands/review-pr.en.md +11 -0
  409. package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
  410. package/templates/.opencode/commands/run-task.en.md +11 -0
  411. package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
  412. package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
  413. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
  414. package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
  415. package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
  416. package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
  417. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
  418. package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
  419. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
  420. package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
  421. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
  422. package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
  423. package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
  424. package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
  425. package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
  426. package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
  427. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
  428. package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
  429. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
  430. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
  431. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
  432. package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
  433. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
  434. package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
  435. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
  436. package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
  437. package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
  438. package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
  439. package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
  440. package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
  441. package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
  442. package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
  443. package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
  444. package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
  445. package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
  446. package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
  447. package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
  448. package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
  449. package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
  450. package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
  451. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
  452. package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
  453. package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
  454. package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
  455. package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
  456. package/templates/.gemini/commands/_project_/release.en.toml +0 -8
  457. package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
  458. package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
  459. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
  460. package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
  461. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
  462. package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
  463. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
  464. package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
  465. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
  466. package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
  467. package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
  468. package/templates/.gemini/commands/_project_/test.en.toml +0 -6
  469. package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
  470. package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
  471. package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
  472. package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
  473. package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
  474. package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
  475. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
  476. package/templates/.gemini/settings.json +0 -3
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { execFileSync } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
4
5
 
5
6
  import { resolvePlatformContext } from './context.ts';
6
7
  import {
@@ -24,6 +25,86 @@ const unsupportedError = {
24
25
  retryable: false
25
26
  };
26
27
 
28
+ const SHA256_PATTERN = /^sha256:[0-9a-f]{64}$/;
29
+
30
+ function releaseNoteFailure(code: string, message: string) {
31
+ return {
32
+ status: 'failed' as const,
33
+ changed: false,
34
+ operation: null,
35
+ url: null,
36
+ error: { code, message, retryable: false }
37
+ };
38
+ }
39
+
40
+ function normalizeReleaseNoteBytes(input: Uint8Array): Buffer {
41
+ const text = new TextDecoder('utf-8', { fatal: true }).decode(input);
42
+ const normalized = text.replace(/\r\n?/g, '\n').replace(/\n*$/, '') + '\n';
43
+ return Buffer.from(normalized, 'utf8');
44
+ }
45
+
46
+ function releaseNoteSha256(bytes: Uint8Array): string {
47
+ return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
48
+ }
49
+
50
+ function isWithin(parent: string, candidate: string): boolean {
51
+ const relative = path.relative(parent, candidate);
52
+ return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
53
+ }
54
+
55
+ function stageReleaseNotes(
56
+ input: { notesFile: string },
57
+ options: Pick<ReleaseNoteOptions, 'cwd'> = {}
58
+ ) {
59
+ if (!input.notesFile || input.notesFile === '-') {
60
+ return { status: 'failed' as const, changed: false, notesFile: null, sha256: null, byteLength: null, error: { code: 'RELEASE_NOTES_INPUT_INVALID', message: 'notes-file must identify an existing external file', retryable: false } };
61
+ }
62
+ const requestedPath = path.resolve(input.notesFile);
63
+ let notesFile: string;
64
+ let sourceStat: fs.Stats;
65
+ try {
66
+ if (fs.lstatSync(requestedPath).isSymbolicLink()) throw new Error('symbolic links are not allowed');
67
+ notesFile = fs.realpathSync(requestedPath);
68
+ sourceStat = fs.statSync(notesFile);
69
+ const worktree = fs.realpathSync(path.resolve(options.cwd || process.cwd()));
70
+ if (!sourceStat.isFile() || isWithin(worktree, notesFile)) throw new Error('path is not an external regular file');
71
+ } catch {
72
+ return { status: 'failed' as const, changed: false, notesFile: null, sha256: null, byteLength: null, error: { code: 'RELEASE_NOTES_PATH_INVALID', message: 'notes-file must be a regular file outside the current worktree and must not be a symbolic link', retryable: false } };
73
+ }
74
+
75
+ let original: Buffer;
76
+ let normalized: Buffer;
77
+ try {
78
+ original = fs.readFileSync(notesFile);
79
+ normalized = normalizeReleaseNoteBytes(original);
80
+ } catch {
81
+ return { status: 'failed' as const, changed: false, notesFile, sha256: null, byteLength: null, error: { code: 'RELEASE_NOTES_CONTENT_INVALID', message: 'notes-file must contain valid UTF-8', retryable: false } };
82
+ }
83
+
84
+ const changed = !original.equals(normalized);
85
+ if (changed) {
86
+ const temporary = path.join(
87
+ path.dirname(notesFile),
88
+ `.${path.basename(notesFile)}.${process.pid}.${Date.now()}.tmp`
89
+ );
90
+ try {
91
+ fs.writeFileSync(temporary, normalized, { flag: 'wx', mode: sourceStat.mode });
92
+ fs.renameSync(temporary, notesFile);
93
+ } catch {
94
+ fs.rmSync(temporary, { force: true });
95
+ return { status: 'failed' as const, changed: false, notesFile, sha256: null, byteLength: null, error: { code: 'RELEASE_NOTES_STAGE_FAILED', message: 'notes-file could not be staged atomically', retryable: false } };
96
+ }
97
+ }
98
+ return {
99
+ status: changed ? 'applied' as const : 'no-op' as const,
100
+ changed,
101
+ notesFile,
102
+ sha256: releaseNoteSha256(normalized),
103
+ byteLength: normalized.byteLength,
104
+ error: null
105
+ };
106
+ }
107
+
27
108
  function baseResult(status: 'no-op' | 'failed' | 'blocked') {
28
109
  return {
29
110
  status,
@@ -148,11 +229,20 @@ function releaseNoteContext(
148
229
  }
149
230
 
150
231
  function publishReleaseNotes(
151
- input: { tag: string; title: string; notesFile: string; dryRun?: boolean },
232
+ input: { tag: string; title: string; notesFile: string; expectedSha256: string; dryRun?: boolean },
152
233
  options: ReleaseNoteOptions = {}
153
234
  ) {
154
- if (!input.tag || !input.title || !input.notesFile) {
155
- return { status: 'failed' as const, changed: false, operation: null, url: null, error: { code: 'RELEASE_NOTES_INPUT_INVALID', message: 'tag, title, and notes-file are required', retryable: false } };
235
+ if (!input.tag || !input.title || !input.notesFile || !SHA256_PATTERN.test(input.expectedSha256)) {
236
+ return releaseNoteFailure('RELEASE_NOTES_INPUT_INVALID', 'tag, title, notes-file, and expected-sha256 are required');
237
+ }
238
+ let actualSha256: string;
239
+ try {
240
+ actualSha256 = releaseNoteSha256(fs.readFileSync(input.notesFile));
241
+ } catch {
242
+ return releaseNoteFailure('RELEASE_NOTES_FILE_UNREADABLE', 'notes-file could not be read');
243
+ }
244
+ if (actualSha256 !== input.expectedSha256) {
245
+ return releaseNoteFailure('RELEASE_NOTES_DIGEST_MISMATCH', 'notes-file does not match the confirmed SHA-256 digest');
156
246
  }
157
247
  const cwd = path.resolve(options.cwd || process.cwd());
158
248
  const platformType = options.platformType ?? configuredPlatform(cwd);
@@ -164,4 +254,10 @@ function publishReleaseNotes(
164
254
  return publishGitHubReleaseNotes({ ...input, repository: context.platform.repository }, { cwd, client: options.client });
165
255
  }
166
256
 
167
- export { publishReleaseNotes, releaseNoteContext };
257
+ export {
258
+ normalizeReleaseNoteBytes,
259
+ publishReleaseNotes,
260
+ releaseNoteContext,
261
+ releaseNoteSha256,
262
+ stageReleaseNotes
263
+ };
@@ -21,7 +21,7 @@ function inspectPlatformRelease(tag: string, options: ReleaseOptions = {}) {
21
21
  return { ...platformResult(result.error.retryable ? 'blocked' : 'failed'), platform: context.platform, release: null, workflows: [], error: result.error };
22
22
  }
23
23
  const release: ReleaseSnapshot = { tag: String(result.value.tagName || tag), published: !Boolean(result.value.isDraft), draft: Boolean(result.value.isDraft), url: result.value.url ? String(result.value.url) : null };
24
- const runs = client.json<unknown[]>(['run', 'list', '--repo', context.platform.repository, '--limit', '100', '--json', 'name,headBranch,status,conclusion,url'], { cwd: options.cwd });
24
+ const runs = client.json<unknown[]>(['run', 'list', '--repo', context.platform.repository, '--limit', '100', '--json', 'name,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,databaseId,attempt,url'], { cwd: options.cwd });
25
25
  return { ...platformResult(runs.ok ? 'no-op' : runs.error.retryable ? 'blocked' : 'degraded'), platform: context.platform, release, workflows: runs.ok ? runs.value : [], error: runs.ok ? null : runs.error };
26
26
  }
27
27
 
@@ -2,10 +2,10 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { execFileSync } from "node:child_process";
4
4
 
5
+ import { hasPlatformCapability } from "./adapters.ts";
5
6
  import { inspectRequiredChecks } from "./pr-checks.ts";
6
7
  import { resolvePlatformContext } from "./context.ts";
7
8
  import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.ts";
8
- import { loadPostReviewConfig, resolvePostReviewGlobs } from "../task/review-fingerprint.ts";
9
9
 
10
10
  const CHECK_TYPE = "required-checks";
11
11
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
@@ -57,10 +57,9 @@ export function evaluateRequiredChecks(context: any, shared: any): any {
57
57
  context.gitRoot && inspection.pullRequest?.head
58
58
  ? resolveReviewedHeadRelation({
59
59
  gitRoot: context.gitRoot,
60
- localHead,
60
+ comparisonHead: localHead,
61
61
  lastReviewedCommit: reviewedHead,
62
- pullRequest: inspection.pullRequest,
63
- pathspecs: context.pathspecs || [":/"]
62
+ pullRequest: inspection.pullRequest
64
63
  })
65
64
  : localHead === reviewedHead && localHead === prHead
66
65
  ? { status: "strict" }
@@ -87,14 +86,18 @@ export function evaluateRequiredChecks(context: any, shared: any): any {
87
86
  export function check({ taskDir }: any, shared: any): any {
88
87
  const task = shared.loadTask(taskDir);
89
88
  if (!task.ok) return shared.failResult(CHECK_TYPE, task.message);
90
- const platform = resolvePlatformContext({ cwd: shared.repoRoot });
91
- if (platform.platform.type !== "github") {
92
- return shared.passResult(CHECK_TYPE, "Skipped: this code platform does not provide required checks");
93
- }
94
89
  const prFlow = readPrFlow(shared.repoRoot);
95
90
  if (prFlow === "disabled" || task.metadata.pr_status === "skipped" || !validPrNumber(task.metadata.pr_number)) {
96
91
  return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
97
92
  }
93
+ const platform = resolvePlatformContext({ cwd: shared.repoRoot });
94
+ if (!hasPlatformCapability(platform.platform.type, "required-checks")) {
95
+ return shared.blockedResult(
96
+ CHECK_TYPE,
97
+ `Platform '${platform.platform.type || "none"}' does not provide required-checks inspection`,
98
+ "dependency_error"
99
+ );
100
+ }
98
101
  const localHead = readHead(shared.repoRoot);
99
102
  if (!localHead) return evaluateRequiredChecks({ metadata: task.metadata, localHead, inspection: null, prFlow }, shared);
100
103
  const inspection = inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
@@ -103,7 +106,6 @@ export function check({ taskDir }: any, shared: any): any {
103
106
  localHead,
104
107
  inspection,
105
108
  prFlow,
106
- gitRoot: shared.repoRoot,
107
- pathspecs: resolvePostReviewGlobs({}, loadPostReviewConfig(shared.repoRoot))
109
+ gitRoot: shared.repoRoot
108
110
  }, shared);
109
111
  }
@@ -0,0 +1,318 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import { parseTaskFrontmatter } from '../task/frontmatter.ts';
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Host resolution (PL-4): PR -> unique / ambiguous / none.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ export type HostCandidate = {
11
+ taskId: string;
12
+ taskDir: string;
13
+ issueNumber: number | null;
14
+ prNumber: number | null;
15
+ };
16
+
17
+ export type HostResolution =
18
+ | { kind: 'unique'; taskId: string; taskDir: string; issueNumber: number; prNumber: number }
19
+ | { kind: 'ambiguous'; candidates: Array<{ taskId: string; issueNumber: number }> }
20
+ | { kind: 'none' };
21
+
22
+ export type HostResolutionErrorCode = 'HOST_AMBIGUOUS' | 'HOST_RESOLUTION_INVALID';
23
+
24
+ export class HostResolutionError extends Error {
25
+ code: HostResolutionErrorCode;
26
+
27
+ constructor(code: HostResolutionErrorCode, message: string) {
28
+ super(message);
29
+ this.name = 'HostResolutionError';
30
+ this.code = code;
31
+ }
32
+ }
33
+
34
+ function toPositiveNumber(value: unknown): number | null {
35
+ const n = Number(value);
36
+ return Number.isInteger(n) && n > 0 ? n : null;
37
+ }
38
+
39
+ /**
40
+ * Parse the PR body for closing-issue references. Handles the conventional
41
+ * `Closes #1` / `Fixes: #2, #3` shapes (case-insensitive, comma/space
42
+ * separated, optional keyword list on the same logical line).
43
+ */
44
+ export function extractClosingIssueNumbers(body: string): number[] {
45
+ const result: number[] = [];
46
+ const seen = new Set<number>();
47
+ const linePattern = /(?:^|\n)[^\n]*\b(?:close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\b[^\n]*/gi;
48
+ let lineMatch: RegExpExecArray | null;
49
+ while ((lineMatch = linePattern.exec(body)) !== null) {
50
+ const line = lineMatch[0]!;
51
+ for (const numMatch of line.matchAll(/#(\d+)/g)) {
52
+ const n = Number(numMatch[1]!);
53
+ if (Number.isInteger(n) && n > 0 && !seen.has(n)) {
54
+ seen.add(n);
55
+ result.push(n);
56
+ }
57
+ }
58
+ }
59
+ return result;
60
+ }
61
+
62
+ /**
63
+ * Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
64
+ * PR number or to one of the PR's closing issues. A task is emitted at most once;
65
+ * a direct `pr_number` hit takes priority over the issue-number reverse lookup.
66
+ */
67
+ export function collectHostCandidates(input: {
68
+ prNumber: number;
69
+ closingIssues: number[];
70
+ workspaceRoot: string;
71
+ }): HostCandidate[] {
72
+ const activeRoot = path.join(input.workspaceRoot, '.agents', 'workspace', 'active');
73
+ const candidates: HostCandidate[] = [];
74
+ let entries: fs.Dirent[];
75
+ try {
76
+ entries = fs.readdirSync(activeRoot, { withFileTypes: true });
77
+ } catch {
78
+ return [];
79
+ }
80
+ for (const entry of entries) {
81
+ if (!entry.isDirectory()) continue;
82
+ const taskDir = path.join(activeRoot, entry.name);
83
+ const taskMdPath = path.join(taskDir, 'task.md');
84
+ let content: string;
85
+ try {
86
+ content = fs.readFileSync(taskMdPath, 'utf8');
87
+ } catch {
88
+ continue;
89
+ }
90
+ const frontmatter = parseTaskFrontmatter(content);
91
+ const issueNumber = toPositiveNumber(frontmatter.issue_number);
92
+ const prNumber = toPositiveNumber(frontmatter.pr_number);
93
+ if (prNumber === input.prNumber) {
94
+ candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
95
+ } else if (issueNumber !== null && input.closingIssues.includes(issueNumber)) {
96
+ candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
97
+ }
98
+ }
99
+ return candidates;
100
+ }
101
+
102
+ /**
103
+ * Collapse a candidate list into a typed HostResolution. Zero candidates ->
104
+ * none; exactly one -> unique; more than one (no stable selection rule) ->
105
+ * ambiguous (fail closed, AN-6).
106
+ */
107
+ export function resolveHostFromCandidates(candidates: HostCandidate[]): HostResolution {
108
+ if (candidates.length === 0) return { kind: 'none' };
109
+ if (candidates.length === 1) {
110
+ const candidate = candidates[0]!;
111
+ return {
112
+ kind: 'unique',
113
+ taskId: candidate.taskId,
114
+ taskDir: candidate.taskDir,
115
+ issueNumber: candidate.issueNumber ?? 0,
116
+ prNumber: candidate.prNumber ?? 0
117
+ };
118
+ }
119
+ return {
120
+ kind: 'ambiguous',
121
+ candidates: candidates.map((candidate) => ({ taskId: candidate.taskId, issueNumber: candidate.issueNumber ?? 0 }))
122
+ };
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // Evidence presence, head state, scenarios, risk and mode (AN-5/6/7, PL-3/5/9).
127
+ // ---------------------------------------------------------------------------
128
+
129
+ export type ArtifactPresence = {
130
+ hasAnalysis: boolean;
131
+ hasPlan: boolean;
132
+ hasCode: boolean;
133
+ hasReviewAnalysis: boolean;
134
+ hasReviewPlan: boolean;
135
+ hasReviewCode: boolean;
136
+ hasPriorPrReview: boolean;
137
+ };
138
+
139
+ export type HeadState = {
140
+ currentHeadSha: string;
141
+ priorHeadSha: string | null;
142
+ issueNumberBound: boolean;
143
+ taskIssueMatches: boolean;
144
+ prNumberBound: boolean;
145
+ taskPrMatches: boolean;
146
+ };
147
+
148
+ export type EvidenceScenario = 'S1' | 'S2' | 'S3';
149
+ export type Freshness = 'fresh' | 'stale' | 'n/a';
150
+ export type Alignment = 'aligned' | 'misaligned' | 'n/a';
151
+ export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH';
152
+ export type ReviewMode = 'verify' | 'audit' | 'reconstruct';
153
+
154
+ export type RiskFactors = {
155
+ changeSize: 'LOW' | 'HIGH';
156
+ sensitivity: 'LOW' | 'HIGH';
157
+ structural: 'LOW' | 'HIGH';
158
+ testCoverage: 'LOW' | 'HIGH';
159
+ sourceCredibility: 'LOW' | 'HIGH';
160
+ recoveryImpact: 'LOW' | 'HIGH';
161
+ };
162
+
163
+ export type DecisionRecord = {
164
+ host: HostResolution;
165
+ scenario: EvidenceScenario;
166
+ freshness: Freshness;
167
+ alignment: Alignment;
168
+ risk: RiskLevel;
169
+ mode: ReviewMode;
170
+ firstReview: boolean;
171
+ reason: string;
172
+ };
173
+
174
+ function hasNoLifecycleArtifacts(presence: ArtifactPresence): boolean {
175
+ return !presence.hasAnalysis && !presence.hasPlan && !presence.hasCode &&
176
+ !presence.hasReviewAnalysis && !presence.hasReviewPlan && !presence.hasReviewCode &&
177
+ !presence.hasPriorPrReview;
178
+ }
179
+
180
+ function hasFullArtifacts(presence: ArtifactPresence): boolean {
181
+ return presence.hasAnalysis && presence.hasPlan && presence.hasCode &&
182
+ presence.hasReviewAnalysis && presence.hasReviewPlan && presence.hasReviewCode;
183
+ }
184
+
185
+ function isTrusted(head: HeadState): boolean {
186
+ return head.issueNumberBound && head.taskIssueMatches && (!head.prNumberBound || head.taskPrMatches);
187
+ }
188
+
189
+ /**
190
+ * Derive the S1(a) trust factor `taskIssueMatches` (PL-3) mechanically from
191
+ * resolved data: a unique host is trusted on the issue dimension only when the
192
+ * task's bound issue_number is among the PR's closing issues. Ambiguous/none
193
+ * hosts and tasks without a positive issue_number cannot be confirmed -> false
194
+ * (fail closed to S2/audit). `resolve-host` emits this value so the prompt layer
195
+ * does not derive the trust factor ad hoc (CD-2).
196
+ */
197
+ export function deriveTaskIssueMatches(host: HostResolution, closingIssues: number[]): boolean {
198
+ return host.kind === 'unique' && host.issueNumber > 0 && closingIssues.includes(host.issueNumber);
199
+ }
200
+
201
+ /**
202
+ * S1 -> S2 -> S3 classification (analysis §6.1). The ambiguous host is rejected
203
+ * before classification (AN-6 fail closed). S3(a) is host.kind === 'none';
204
+ * S3(b) is a unique task with no lifecycle artifacts and no prior pr-review
205
+ * (PL-5/PL-9 symmetric: any review-only task falls to S2).
206
+ */
207
+ export function classifyScenario(host: HostResolution, presence: ArtifactPresence, head: HeadState): EvidenceScenario {
208
+ if (host.kind === 'ambiguous') {
209
+ throw new HostResolutionError('HOST_AMBIGUOUS', 'multiple candidate hosts; resolve before evidence classification');
210
+ }
211
+ if (host.kind === 'none') return 'S3';
212
+ if (hasNoLifecycleArtifacts(presence)) return 'S3';
213
+ const priorHeadMatches = presence.hasPriorPrReview && head.priorHeadSha !== null && head.priorHeadSha === head.currentHeadSha;
214
+ if (hasFullArtifacts(presence) && priorHeadMatches && isTrusted(head)) return 'S1';
215
+ return 'S2';
216
+ }
217
+
218
+ /**
219
+ * Freshness is benchmarked against the prior `pr-review*` reviewed head SHA
220
+ * (analysis §6.2, AN-7). No prior review -> n/a/n/a (first-review special case).
221
+ */
222
+ export function evaluateHead(head: HeadState): { freshness: Freshness; alignment: Alignment } {
223
+ if (head.priorHeadSha === null) return { freshness: 'n/a', alignment: 'n/a' };
224
+ const freshness: Freshness = head.priorHeadSha === head.currentHeadSha ? 'fresh' : 'stale';
225
+ const aligned = freshness === 'fresh' && isTrusted(head);
226
+ return { freshness, alignment: aligned ? 'aligned' : 'misaligned' };
227
+ }
228
+
229
+ /**
230
+ * Pure-evidence risk aggregation (analysis §6.3, AN-5): any priority factor
231
+ * (sensitivity / sourceCredibility) HIGH -> HIGH; otherwise any HIGH -> MEDIUM;
232
+ * all LOW -> LOW. Identity factors are structurally absent from the input type.
233
+ */
234
+ export function gradeRisk(factors: RiskFactors): RiskLevel {
235
+ const priority = [factors.sensitivity, factors.sourceCredibility] as const;
236
+ if (priority.includes('HIGH')) return 'HIGH';
237
+ const values = Object.values(factors) as Array<'LOW' | 'HIGH'>;
238
+ if (values.includes('HIGH')) return 'MEDIUM';
239
+ return 'LOW';
240
+ }
241
+
242
+ /**
243
+ * verify / audit / reconstruct selection matrix (analysis §6.4). S3 ->
244
+ * reconstruct; S2 -> audit; S1 fresh+aligned -> verify (LOW/MEDIUM risk) or
245
+ * audit (HIGH risk); any other S1 combination falls back to audit.
246
+ */
247
+ export function selectMode(scenario: EvidenceScenario, freshness: Freshness, alignment: Alignment, risk: RiskLevel): ReviewMode {
248
+ if (scenario === 'S3') return 'reconstruct';
249
+ if (scenario === 'S2') return 'audit';
250
+ if (freshness === 'fresh' && alignment === 'aligned') {
251
+ return risk === 'HIGH' ? 'audit' : 'verify';
252
+ }
253
+ return 'audit';
254
+ }
255
+
256
+ function buildReason(input: {
257
+ scenario: EvidenceScenario;
258
+ freshness: Freshness;
259
+ alignment: Alignment;
260
+ risk: RiskLevel;
261
+ mode: ReviewMode;
262
+ firstReview: boolean;
263
+ hasPriorPrReview: boolean;
264
+ }): string {
265
+ const pieces: string[] = [];
266
+ if (input.firstReview) pieces.push('first review (no prior pr-review head)');
267
+ if (input.hasPriorPrReview) pieces.push(`prior head ${input.freshness}`);
268
+ if (input.freshness === 'fresh') pieces.push(`alignment ${input.alignment}`);
269
+ pieces.push(`evidence scenario ${input.scenario}`);
270
+ pieces.push(`risk ${input.risk}`);
271
+ pieces.push(`mode ${input.mode}`);
272
+ return pieces.join('; ');
273
+ }
274
+
275
+ /**
276
+ * Full decision pipeline: classify -> freshness/alignment -> risk -> mode,
277
+ * producing a traceable DecisionRecord (AC3). Ambiguous hosts are rejected
278
+ * before any classification runs (AN-6).
279
+ */
280
+ export function decide(input: {
281
+ host: HostResolution;
282
+ presence: ArtifactPresence;
283
+ head: HeadState;
284
+ riskFactors: RiskFactors;
285
+ }): DecisionRecord {
286
+ if (input.host.kind === 'ambiguous') {
287
+ throw new HostResolutionError('HOST_AMBIGUOUS', 'ambiguous host; resolve before evidence classification');
288
+ }
289
+ const scenario = classifyScenario(input.host, input.presence, input.head);
290
+ const { freshness, alignment } = evaluateHead(input.head);
291
+ const risk = gradeRisk(input.riskFactors);
292
+ const mode = selectMode(scenario, freshness, alignment, risk);
293
+ const firstReview = !input.presence.hasPriorPrReview;
294
+ return {
295
+ host: input.host,
296
+ scenario,
297
+ freshness,
298
+ alignment,
299
+ risk,
300
+ mode,
301
+ firstReview,
302
+ reason: buildReason({
303
+ scenario,
304
+ freshness,
305
+ alignment,
306
+ risk,
307
+ mode,
308
+ firstReview,
309
+ hasPriorPrReview: input.presence.hasPriorPrReview
310
+ })
311
+ };
312
+ }
313
+
314
+ export {
315
+ hasFullArtifacts,
316
+ hasNoLifecycleArtifacts,
317
+ isTrusted
318
+ };
package/lib/prompt.ts CHANGED
@@ -88,20 +88,33 @@ async function select(question: string, choices: string[], defaultValue?: string
88
88
 
89
89
  async function multiSelect(
90
90
  question: string,
91
- choices: { id: string; label: string }[]
91
+ choices: { id: string; label: string }[],
92
+ defaultIds: readonly string[] = choices.map((choice) => choice.id)
92
93
  ): Promise<string[]> {
94
+ const choiceIds = new Set(choices.map((choice) => choice.id));
95
+ if (defaultIds.some((id) => !choiceIds.has(id))) {
96
+ throw new Error('Default selection contains an unknown id');
97
+ }
98
+ const normalizedDefaults = choices
99
+ .map((choice) => choice.id)
100
+ .filter((id) => defaultIds.includes(id));
93
101
  process.stdout.write(` ${question}:\n`);
94
102
  const idWidth = Math.max(...choices.map((c) => c.id.length));
95
103
  choices.forEach((c, i) => {
96
104
  process.stdout.write(` ${i + 1}) ${c.id.padEnd(idWidth)} (${c.label})\n`);
97
105
  });
98
- ask('Enter comma-separated numbers or ids to keep, or "none" to select nothing [default: all]: ');
106
+ const defaultLabel = normalizedDefaults.length === choices.length
107
+ ? 'all'
108
+ : normalizedDefaults.length === 0
109
+ ? 'none'
110
+ : normalizedDefaults.join(',');
111
+ ask(`Enter comma-separated numbers or ids to keep, or "none" to select nothing [default: ${defaultLabel}]: `);
99
112
 
100
113
  setupInterface();
101
114
 
102
115
  const line = await nextLine();
103
116
  // Strictly distinguish bare Enter (null/empty string) from whitespace input.
104
- if (line === null || line === '') return choices.map((c) => c.id);
117
+ if (line === null || line === '') return normalizedDefaults;
105
118
  // Explicit empty selection: "none" means deliberately zero built-in choices.
106
119
  if (line.trim().toLowerCase() === 'none') return [];
107
120
 
@@ -20,7 +20,10 @@ async function inspectHomebrewChannel(url: string, version: string, fetcher: Fet
20
20
  if (!response.ok) return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: `formula endpoint returned ${response.status}` } };
21
21
  const formula = await response.text();
22
22
  const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
- return { status: 'no-op' as const, published: new RegExp(`(?:version\\s+["']${escaped}["']|/v?${escaped}\\.)`).test(formula), version, error: null };
23
+ const formulaUrl = /^\s*url\s+["']([^"']+)["']\s*$/m.exec(formula)?.[1] ?? '';
24
+ const npmTarball = new RegExp(`^https://registry\\.npmjs\\.org/.+/-/[^/]+-${escaped}\\.tgz$`).test(formulaUrl);
25
+ const bottle = /^\s*bottle do\s*$/m.test(formula);
26
+ return { status: 'no-op' as const, published: npmTarball && bottle, version, error: null };
24
27
  } catch (error) {
25
28
  return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
26
29
  }
@@ -1,8 +1,8 @@
1
1
  type ReleasePhase = 'unprepared' | 'prepared' | 'partially-published' | 'published' | 'post-pending' | 'complete';
2
- type ReleaseFacts = { localTag: boolean; localTagConflict?: boolean; remoteBranch: boolean; remoteTag: boolean; githubRelease: boolean | null; npm: boolean | null; homebrew: boolean | null; smoke: 'success' | 'pending' | 'failed' | null; postCommit: boolean };
2
+ type ReleaseFacts = { localTag: boolean; localTagAncestor?: boolean; localTagConflict?: boolean; remoteBranch: boolean; remoteTag: boolean; githubRelease: boolean | null; npm: boolean | null; homebrew: boolean | null; smoke: 'success' | 'pending' | 'failed' | null; postCommit: boolean };
3
3
 
4
4
  function deriveReleasePhase(facts: ReleaseFacts): ReleasePhase {
5
- if (!facts.localTag) return 'unprepared';
5
+ if (!facts.localTag && !facts.localTagAncestor) return 'unprepared';
6
6
  if (!facts.remoteBranch && !facts.remoteTag) return 'prepared';
7
7
  if (!facts.remoteBranch || !facts.remoteTag) return 'partially-published';
8
8
  if (facts.githubRelease !== true || facts.npm !== true || facts.homebrew !== true) return 'published';
@@ -17,8 +17,9 @@ function releaseSnapshot(version: string, facts: ReleaseFacts) {
17
17
  async function runReleaseAction(input: { version: string; action: 'inspect' | 'prepare' | 'publish' | 'post'; inspect: () => Promise<ReleaseFacts>; prepare?: () => Promise<void>; publish?: () => Promise<void>; post?: () => Promise<void> }) {
18
18
  const before = releaseSnapshot(input.version, await input.inspect());
19
19
  if (input.action === 'inspect') return { status: 'no-op' as const, changed: false, before, snapshot: before, error: null };
20
+ if (before.facts.localTagConflict) return { status: 'failed' as const, changed: false, before, snapshot: before, error: { code: 'GIT_TAG_CONFLICT', message: `Tag ${before.tag} is not reachable from HEAD` } };
20
21
  const allowed = input.action === 'prepare' ? before.phase === 'unprepared'
21
- : input.action === 'publish' ? ['prepared', 'partially-published'].includes(before.phase)
22
+ : input.action === 'publish' ? before.facts.localTag && ['prepared', 'partially-published'].includes(before.phase)
22
23
  : ['published', 'post-pending'].includes(before.phase);
23
24
  if (!allowed) return { status: before.phase === 'complete' ? 'no-op' as const : 'failed' as const, changed: false, before, snapshot: before, error: before.phase === 'complete' ? null : { code: 'RELEASE_PHASE_INVALID', message: `Cannot ${input.action} from ${before.phase}` } };
24
25
  await input[input.action]?.();
@@ -0,0 +1,28 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ export function removeDirRecursive(dir: string): void {
5
+ if (!fs.existsSync(dir)) {
6
+ return;
7
+ }
8
+
9
+ const pending = [dir];
10
+ const directories: string[] = [];
11
+ while (pending.length > 0) {
12
+ const current = pending.pop()!;
13
+ const stat = fs.lstatSync(current);
14
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
15
+ fs.unlinkSync(current);
16
+ continue;
17
+ }
18
+
19
+ directories.push(current);
20
+ for (const entry of fs.readdirSync(current)) {
21
+ pending.push(path.join(current, entry));
22
+ }
23
+ }
24
+
25
+ for (const directory of directories.reverse()) {
26
+ fs.rmdirSync(directory);
27
+ }
28
+ }
package/lib/run/tui.ts CHANGED
@@ -1,6 +1,9 @@
1
- export type TuiName = 'claude' | 'codex' | 'gemini' | 'opencode';
1
+ import { renderAgentClientInvocation } from '../agent-clients/invocation.ts';
2
+ import { getAgentClientAdapter } from '../agent-clients/registry.ts';
2
3
 
3
- const TUI_NAMES = new Set(['claude', 'codex', 'gemini', 'opencode']);
4
+ export type TuiName = 'claude' | 'codex' | 'antigravity' | 'opencode';
5
+
6
+ const TUI_NAMES = new Set(['claude', 'codex', 'antigravity', 'opencode']);
4
7
 
5
8
  export type CommandConfig = {
6
9
  defaultTui?: unknown;
@@ -27,14 +30,18 @@ export function selectTui(
27
30
 
28
31
  export function renderPrompt(params: { tui: TuiName; skill: string; args: string[] }): string {
29
32
  const suffix = [params.skill, ...params.args].join(' ').trim();
30
- if (params.tui === 'codex') return `$${suffix}`;
31
- if (params.tui === 'gemini') return `/agent-infra:${suffix}`;
33
+ if (params.tui === 'codex') {
34
+ return renderAgentClientInvocation(getAgentClientAdapter('codex').invocation, {
35
+ skillName: params.skill,
36
+ args: params.args
37
+ });
38
+ }
32
39
  return `/${suffix}`;
33
40
  }
34
41
 
35
42
  export function buildTuiCommand(tui: TuiName, prompt: string): [string, string[]] {
36
43
  if (tui === 'claude') return ['claude', ['--dangerously-skip-permissions', '--print', prompt]];
37
- if (tui === 'gemini') return ['gemini', ['--approval-mode', 'yolo', '--prompt', prompt]];
44
+ if (tui === 'antigravity') return ['agy', ['--dangerously-skip-permissions', '--print', prompt]];
38
45
  if (tui === 'opencode') return ['opencode', ['run', '--dangerously-skip-permissions', prompt]];
39
46
  return ['codex', ['exec', '--dangerously-bypass-approvals-and-sandbox', prompt]];
40
47
  }