@fitlab-ai/agent-infra 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/README.md +12 -9
  2. package/README.zh-CN.md +12 -9
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +134 -108
  6. package/dist/lib/agent-clients/adapter.js +137 -4
  7. package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
  8. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  9. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  10. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  11. package/dist/lib/agent-clients/adapters/claude-code.js +27 -4
  12. package/dist/lib/agent-clients/adapters/codex.js +9 -0
  13. package/dist/lib/agent-clients/adapters/index.js +2 -2
  14. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  15. package/dist/lib/agent-clients/adapters/opencode.js +24 -3
  16. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  17. package/dist/lib/agent-clients/config.js +42 -4
  18. package/dist/lib/agent-clients/next-steps.js +11 -2
  19. package/dist/lib/agent-clients/reconcile.js +2 -1
  20. package/dist/lib/agent-clients/registry.js +16 -2
  21. package/dist/lib/agent-clients/schema.js +18 -0
  22. package/dist/lib/agent-clients/tokens.js +49 -0
  23. package/dist/lib/agent-clients/types.js +1 -1
  24. package/dist/lib/defaults.json +1 -1
  25. package/dist/lib/git/workflow.js +54 -1
  26. package/dist/lib/internal/agent-client.js +61 -4
  27. package/dist/lib/internal/git-workflow.js +6 -1
  28. package/dist/lib/internal/platform-checks.js +3 -3
  29. package/dist/lib/internal/platform-comment.js +29 -2
  30. package/dist/lib/internal/platform-issue.js +7 -0
  31. package/dist/lib/internal/platform-pr-review.js +132 -0
  32. package/dist/lib/internal/platform-pr.js +20 -2
  33. package/dist/lib/internal/platform-release-notes.js +52 -16
  34. package/dist/lib/internal/pr-review-grade.js +140 -0
  35. package/dist/lib/internal/release-workflow.js +13 -6
  36. package/dist/lib/internal/sandbox-control.js +24 -0
  37. package/dist/lib/internal/task-activity.js +105 -0
  38. package/dist/lib/internal/task-event.js +17 -1
  39. package/dist/lib/internal/task-ledger.js +12 -3
  40. package/dist/lib/internal/task-lifecycle.js +26 -1
  41. package/dist/lib/internal/task-orchestration.js +167 -18
  42. package/dist/lib/internal/task-review.js +8 -3
  43. package/dist/lib/platform/adapters.js +8 -1
  44. package/dist/lib/platform/completion-backfill.js +122 -0
  45. package/dist/lib/platform/github-client.js +19 -2
  46. package/dist/lib/platform/issue-comments.js +3 -2
  47. package/dist/lib/platform/merged-pr-equivalence.js +115 -5
  48. package/dist/lib/platform/pr-checks.js +65 -42
  49. package/dist/lib/platform/pr-review.js +166 -0
  50. package/dist/lib/platform/pull-requests.js +371 -4
  51. package/dist/lib/platform/release-notes.js +85 -3
  52. package/dist/lib/platform/releases.js +13 -5
  53. package/dist/lib/pr-review/evidence-grading.js +229 -0
  54. package/dist/lib/process-data/index.js +239 -0
  55. package/dist/lib/process-data/normalize.js +198 -0
  56. package/dist/lib/process-data/privacy.js +33 -0
  57. package/dist/lib/process-data/reconcile.js +95 -0
  58. package/dist/lib/process-data/repair.js +58 -0
  59. package/dist/lib/process-data/sources.js +345 -0
  60. package/dist/lib/process-data/store.js +282 -0
  61. package/dist/lib/process-data/types.js +2 -0
  62. package/dist/lib/run/index.js +4 -3
  63. package/dist/lib/run/tui.js +10 -13
  64. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  65. package/dist/lib/sandbox/capture.js +7 -2
  66. package/dist/lib/sandbox/commands/create.js +109 -248
  67. package/dist/lib/sandbox/commands/enter.js +15 -47
  68. package/dist/lib/sandbox/commands/list-running.js +16 -6
  69. package/dist/lib/sandbox/commands/ls.js +10 -6
  70. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  71. package/dist/lib/sandbox/commands/refresh.js +4 -84
  72. package/dist/lib/sandbox/commands/rm.js +24 -3
  73. package/dist/lib/sandbox/commands/show.js +13 -4
  74. package/dist/lib/sandbox/commands/start.js +7 -4
  75. package/dist/lib/sandbox/config.js +2 -0
  76. package/dist/lib/sandbox/constants.js +6 -0
  77. package/dist/lib/sandbox/control/client.js +44 -0
  78. package/dist/lib/sandbox/control/protocol.js +35 -0
  79. package/dist/lib/sandbox/control/server.js +109 -0
  80. package/dist/lib/sandbox/dockerfile.js +36 -13
  81. package/dist/lib/sandbox/mounts.js +17 -4
  82. package/dist/lib/sandbox/recovery.js +128 -5
  83. package/dist/lib/sandbox/redaction.js +12 -0
  84. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  85. package/dist/lib/sandbox/workspace-identity.js +95 -0
  86. package/dist/lib/sandbox/workspace-view.js +103 -0
  87. package/dist/lib/task/activity-intent.js +307 -0
  88. package/dist/lib/task/artifact-lifecycle.js +2 -1
  89. package/dist/lib/task/commands/log.js +15 -14
  90. package/dist/lib/task/commit-finalization.js +267 -0
  91. package/dist/lib/task/commit-intent.js +165 -0
  92. package/dist/lib/task/decision-intents.js +31 -17
  93. package/dist/lib/task/delegation-receipts.js +25 -4
  94. package/dist/lib/task/events.js +67 -28
  95. package/dist/lib/task/finalization-artifacts.js +35 -0
  96. package/dist/lib/task/implementation-inputs.js +54 -7
  97. package/dist/lib/task/ledger-intents.js +35 -1
  98. package/dist/lib/task/lifecycle-execution.js +46 -0
  99. package/dist/lib/task/orchestration.js +753 -54
  100. package/dist/lib/task/resolve-ref.js +41 -1
  101. package/dist/lib/task/review-finalization.js +29 -9
  102. package/dist/lib/task/task-execution-lock.js +231 -0
  103. package/dist/lib/task/verification-checks.js +1 -1
  104. package/dist/lib/task/verification-engine.js +218 -2
  105. package/dist/lib/task/verification.js +4 -3
  106. package/dist/lib/task/workspace-snapshot.js +17 -5
  107. package/lib/agent-clients/adapter.ts +201 -4
  108. package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
  109. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  110. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  111. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  112. package/lib/agent-clients/adapters/claude-code.ts +31 -4
  113. package/lib/agent-clients/adapters/codex.ts +9 -0
  114. package/lib/agent-clients/adapters/index.ts +2 -2
  115. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  116. package/lib/agent-clients/adapters/opencode.ts +27 -3
  117. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  118. package/lib/agent-clients/config.ts +49 -4
  119. package/lib/agent-clients/next-steps.ts +15 -2
  120. package/lib/agent-clients/reconcile.ts +2 -1
  121. package/lib/agent-clients/registry.ts +19 -1
  122. package/lib/agent-clients/schema.ts +18 -0
  123. package/lib/agent-clients/tokens.ts +53 -0
  124. package/lib/agent-clients/types.ts +15 -1
  125. package/lib/defaults.json +1 -1
  126. package/lib/git/workflow.ts +66 -2
  127. package/lib/internal/agent-client.ts +59 -4
  128. package/lib/internal/git-workflow.ts +5 -1
  129. package/lib/internal/platform-checks.ts +4 -4
  130. package/lib/internal/platform-comment.ts +17 -2
  131. package/lib/internal/platform-issue.ts +4 -0
  132. package/lib/internal/platform-pr-review.ts +104 -0
  133. package/lib/internal/platform-pr.ts +14 -1
  134. package/lib/internal/platform-release-notes.ts +59 -16
  135. package/lib/internal/pr-review-grade.ts +130 -0
  136. package/lib/internal/release-workflow.ts +13 -6
  137. package/lib/internal/sandbox-control.ts +24 -0
  138. package/lib/internal/task-activity.ts +91 -0
  139. package/lib/internal/task-event.ts +9 -1
  140. package/lib/internal/task-ledger.ts +12 -3
  141. package/lib/internal/task-lifecycle.ts +26 -1
  142. package/lib/internal/task-orchestration.ts +123 -14
  143. package/lib/internal/task-review.ts +8 -3
  144. package/lib/platform/adapters.ts +29 -2
  145. package/lib/platform/completion-backfill.ts +134 -0
  146. package/lib/platform/github-client.ts +20 -2
  147. package/lib/platform/issue-comments.ts +3 -2
  148. package/lib/platform/merged-pr-equivalence.ts +127 -5
  149. package/lib/platform/pr-checks.ts +73 -46
  150. package/lib/platform/pr-review.ts +201 -0
  151. package/lib/platform/pull-requests.ts +444 -3
  152. package/lib/platform/release-notes.ts +100 -4
  153. package/lib/platform/releases.ts +16 -4
  154. package/lib/pr-review/evidence-grading.ts +318 -0
  155. package/lib/process-data/index.ts +224 -0
  156. package/lib/process-data/normalize.ts +202 -0
  157. package/lib/process-data/privacy.ts +41 -0
  158. package/lib/process-data/reconcile.ts +110 -0
  159. package/lib/process-data/repair.ts +64 -0
  160. package/lib/process-data/sources.ts +354 -0
  161. package/lib/process-data/store.ts +315 -0
  162. package/lib/process-data/types.ts +135 -0
  163. package/lib/run/index.ts +5 -3
  164. package/lib/run/tui.ts +14 -12
  165. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  166. package/lib/sandbox/capture.ts +9 -2
  167. package/lib/sandbox/commands/create.ts +126 -280
  168. package/lib/sandbox/commands/enter.ts +13 -59
  169. package/lib/sandbox/commands/list-running.ts +23 -6
  170. package/lib/sandbox/commands/ls.ts +22 -6
  171. package/lib/sandbox/commands/rebuild.ts +4 -3
  172. package/lib/sandbox/commands/refresh.ts +4 -126
  173. package/lib/sandbox/commands/rm.ts +24 -3
  174. package/lib/sandbox/commands/show.ts +30 -4
  175. package/lib/sandbox/commands/start.ts +6 -4
  176. package/lib/sandbox/config.ts +4 -0
  177. package/lib/sandbox/constants.ts +8 -0
  178. package/lib/sandbox/control/client.ts +55 -0
  179. package/lib/sandbox/control/protocol.ts +75 -0
  180. package/lib/sandbox/control/server.ts +117 -0
  181. package/lib/sandbox/dockerfile.ts +66 -13
  182. package/lib/sandbox/mounts.ts +24 -4
  183. package/lib/sandbox/recovery.ts +163 -6
  184. package/lib/sandbox/redaction.ts +14 -0
  185. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  186. package/lib/sandbox/tool-types.ts +16 -0
  187. package/lib/sandbox/workspace-identity.ts +123 -0
  188. package/lib/sandbox/workspace-view.ts +143 -0
  189. package/lib/server/server.schema.json +2 -2
  190. package/lib/task/activity-intent.ts +417 -0
  191. package/lib/task/artifact-lifecycle.ts +2 -1
  192. package/lib/task/commands/log.ts +15 -14
  193. package/lib/task/commit-finalization.ts +356 -0
  194. package/lib/task/commit-intent.ts +230 -0
  195. package/lib/task/decision-intents.ts +32 -12
  196. package/lib/task/delegation-receipts.ts +34 -5
  197. package/lib/task/events.ts +75 -30
  198. package/lib/task/finalization-artifacts.ts +58 -0
  199. package/lib/task/implementation-inputs.ts +62 -8
  200. package/lib/task/ledger-intents.ts +43 -3
  201. package/lib/task/lifecycle-execution.ts +106 -0
  202. package/lib/task/orchestration.ts +1019 -72
  203. package/lib/task/resolve-ref.ts +46 -1
  204. package/lib/task/review-finalization.ts +40 -9
  205. package/lib/task/task-execution-lock.ts +296 -0
  206. package/lib/task/verification-checks.ts +1 -1
  207. package/lib/task/verification-engine.ts +249 -2
  208. package/lib/task/verification.ts +5 -3
  209. package/lib/task/workspace-snapshot.ts +26 -5
  210. package/package.json +3 -3
  211. package/templates/.agents/QUICKSTART.en.md +25 -8
  212. package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
  213. package/templates/.agents/README.en.md +10 -7
  214. package/templates/.agents/README.zh-CN.md +10 -7
  215. package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
  216. package/templates/.agents/rules/README.en.md +1 -1
  217. package/templates/.agents/rules/README.zh-CN.md +1 -1
  218. package/templates/.agents/rules/create-issue.github.en.md +4 -2
  219. package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
  220. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  221. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  222. package/templates/.agents/rules/issue-fields.github.en.md +3 -1
  223. package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
  224. package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
  225. package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
  226. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
  227. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
  228. package/templates/.agents/rules/issue-sync.github.en.md +7 -3
  229. package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
  230. package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
  231. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
  232. package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
  233. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
  234. package/templates/.agents/rules/next-step-output.en.md +3 -1
  235. package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
  236. package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
  237. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
  238. package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
  239. package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
  240. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +3 -3
  241. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
  242. package/templates/.agents/rules/pr-sync.en.md +3 -1
  243. package/templates/.agents/rules/pr-sync.github.en.md +11 -1
  244. package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
  245. package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
  246. package/templates/.agents/rules/release-commands.en.md +1 -1
  247. package/templates/.agents/rules/release-commands.github.en.md +12 -2
  248. package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
  249. package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
  250. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  251. package/templates/.agents/rules/task-management.en.md +13 -0
  252. package/templates/.agents/rules/task-management.zh-CN.md +13 -0
  253. package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
  254. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
  255. package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
  256. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
  257. package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
  258. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
  259. package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
  260. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
  261. package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
  262. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
  263. package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
  264. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +12 -9
  265. package/templates/.agents/skills/commit/SKILL.en.md +23 -11
  266. package/templates/.agents/skills/commit/SKILL.zh-CN.md +29 -11
  267. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  268. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  269. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
  270. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
  271. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  272. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  273. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  274. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  275. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  276. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  277. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
  279. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  280. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  281. package/templates/.agents/skills/complete-task/SKILL.en.md +22 -7
  282. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +22 -7
  283. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  284. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  285. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
  286. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
  287. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -5
  288. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -5
  289. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  290. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  291. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
  292. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
  293. package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
  294. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
  295. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  296. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  297. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
  298. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
  299. package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
  300. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
  301. package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
  302. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
  303. package/templates/.agents/skills/release/SKILL.en.md +16 -10
  304. package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
  305. package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
  306. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
  307. package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
  308. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
  309. package/templates/.agents/skills/review-code/SKILL.en.md +11 -8
  310. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -8
  311. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  312. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  313. package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
  314. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
  315. package/templates/.agents/skills/review-pr/SKILL.en.md +186 -0
  316. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +186 -0
  317. package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
  318. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
  319. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
  320. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
  321. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
  322. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
  323. package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
  324. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
  325. package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
  326. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
  327. package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
  328. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
  329. package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
  330. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
  331. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +98 -107
  332. package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
  333. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
  334. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
  335. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
  336. package/templates/.agents/templates/task.en.md +2 -2
  337. package/templates/.agents/templates/task.zh-CN.md +2 -2
  338. package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
  339. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
  340. package/templates/.agents/workflows/code-review.en.yaml +1 -1
  341. package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
  342. package/templates/.agents/workflows/feature-development.en.yaml +4 -4
  343. package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
  344. package/templates/.agents/workflows/refactoring.en.yaml +3 -3
  345. package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
  346. package/templates/.claude/commands/post-release.en.md +1 -0
  347. package/templates/.claude/commands/post-release.zh-CN.md +1 -0
  348. package/templates/.claude/commands/review-pr.en.md +8 -0
  349. package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
  350. package/templates/.claude/commands/watch-pr.en.md +1 -1
  351. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  352. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  353. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  354. package/templates/.opencode/commands/post-release.en.md +2 -0
  355. package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
  356. package/templates/.opencode/commands/review-pr.en.md +11 -0
  357. package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
  358. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  359. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  360. package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
  361. package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
  362. package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
  363. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
  364. package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
  365. package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
  366. package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
  367. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
  368. package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
  369. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
  370. package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
  371. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
  372. package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
  373. package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
  374. package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
  375. package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
  376. package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
  377. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
  378. package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
  379. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
  380. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
  381. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
  382. package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
  383. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
  384. package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
  385. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
  386. package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
  387. package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
  388. package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
  389. package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
  390. package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
  391. package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
  392. package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
  393. package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
  394. package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
  395. package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
  396. package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
  397. package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
  398. package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
  399. package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
  400. package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
  401. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
  402. package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
  403. package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
  404. package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
  405. package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
  406. package/templates/.gemini/commands/_project_/release.en.toml +0 -8
  407. package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
  408. package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
  409. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
  410. package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
  411. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
  412. package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
  413. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
  414. package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
  415. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
  416. package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
  417. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
  418. package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
  419. package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
  420. package/templates/.gemini/commands/_project_/test.en.toml +0 -6
  421. package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
  422. package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
  423. package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
  424. package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
  425. package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
  426. package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
  427. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
  428. package/templates/.gemini/settings.json +0 -3
@@ -6,7 +6,8 @@ import type {
6
6
  AgentClientConfig,
7
7
  AgentClientId,
8
8
  AgentClientsConfig,
9
- AgentClientState
9
+ AgentClientState,
10
+ OrchestrationModelPolicy
10
11
  } from './types.ts';
11
12
 
12
13
  type AgentClientConfigInput = Readonly<{
@@ -65,12 +66,49 @@ function fail(code: AgentClientDiagnosticCode, path: string): never {
65
66
  throw new AgentClientConfigError({ code, path });
66
67
  }
67
68
 
69
+ function parseExactText(value: unknown, path: string): string {
70
+ if (typeof value !== 'string' || value.length === 0 || value.trim() !== value) {
71
+ fail('INVALID_AGENT_CLIENTS', path);
72
+ }
73
+ return value;
74
+ }
75
+
76
+ function parseOrchestrationPolicy(value: unknown, path: string): OrchestrationModelPolicy {
77
+ if (!isRecord(value)) fail('INVALID_AGENT_CLIENTS', path);
78
+ const keys = Object.keys(value);
79
+ if (
80
+ keys.length !== 2
81
+ || !hasOwn(value, 'executor')
82
+ || !hasOwn(value, 'reviewer')
83
+ ) {
84
+ fail('INVALID_AGENT_CLIENTS', path);
85
+ }
86
+ const parseRole = (candidate: unknown, rolePath: string) => {
87
+ if (
88
+ !isRecord(candidate)
89
+ || Object.keys(candidate).length !== 2
90
+ || !hasOwn(candidate, 'model')
91
+ || !hasOwn(candidate, 'reasoningEffort')
92
+ ) {
93
+ fail('INVALID_AGENT_CLIENTS', rolePath);
94
+ }
95
+ return Object.freeze({
96
+ model: parseExactText(candidate.model, `${rolePath}.model`),
97
+ reasoningEffort: parseExactText(candidate.reasoningEffort, `${rolePath}.reasoningEffort`)
98
+ });
99
+ };
100
+ const executor = parseRole(value.executor, `${path}.executor`);
101
+ const reviewer = parseRole(value.reviewer, `${path}.reviewer`);
102
+ return Object.freeze({ executor, reviewer });
103
+ }
104
+
68
105
  function parseCanonical(value: unknown): AgentClientState {
69
106
  if (!Array.isArray(value)) fail('INVALID_AGENT_CLIENTS', 'agentClients');
70
107
 
71
108
  const entries = new Map<AgentClientId, Readonly<{
72
109
  enabled: boolean;
73
110
  installInSandbox: boolean;
111
+ orchestration?: OrchestrationModelPolicy;
74
112
  }>>();
75
113
 
76
114
  for (const [index, candidate] of value.entries()) {
@@ -79,10 +117,11 @@ function parseCanonical(value: unknown): AgentClientState {
79
117
 
80
118
  const keys = Object.keys(candidate);
81
119
  if (
82
- keys.length !== 3
120
+ (keys.length !== 3 && keys.length !== 4)
83
121
  || !hasOwn(candidate, 'id')
84
122
  || !hasOwn(candidate, 'enabled')
85
123
  || !hasOwn(candidate, 'installInSandbox')
124
+ || (keys.length === 4 && !hasOwn(candidate, 'orchestration'))
86
125
  ) {
87
126
  fail('INVALID_AGENT_CLIENTS', path);
88
127
  }
@@ -100,7 +139,10 @@ function parseCanonical(value: unknown): AgentClientState {
100
139
  }
101
140
  entries.set(candidate.id, {
102
141
  enabled: candidate.enabled,
103
- installInSandbox: candidate.installInSandbox
142
+ installInSandbox: candidate.installInSandbox,
143
+ ...(hasOwn(candidate, 'orchestration')
144
+ ? { orchestration: parseOrchestrationPolicy(candidate.orchestration, `${path}.orchestration`) }
145
+ : {})
104
146
  });
105
147
  }
106
148
 
@@ -117,7 +159,10 @@ function serializeAgentClients(state: AgentClientState): AgentClientsConfig {
117
159
  return AGENT_CLIENT_IDS.map((id): AgentClientConfig => ({
118
160
  id,
119
161
  enabled: state[id].enabled,
120
- installInSandbox: state[id].installInSandbox
162
+ installInSandbox: state[id].installInSandbox,
163
+ ...(state[id].orchestration
164
+ ? { orchestration: structuredClone(state[id].orchestration) }
165
+ : {})
121
166
  }));
122
167
  }
123
168
 
@@ -1,5 +1,6 @@
1
1
  import { listEnabledAgentClientAdapters } from './registry.ts';
2
2
  import { renderAgentClientInvocation } from './invocation.ts';
3
+ import semver from 'semver';
3
4
  import type { CustomTUI } from './custom-tuis.ts';
4
5
  import type { AgentClientId, AgentClientState } from './types.ts';
5
6
 
@@ -16,6 +17,7 @@ type RenderNextStepsInput = Readonly<{
16
17
  customTUIs: readonly CustomTUI[];
17
18
  skillName: string;
18
19
  taskRef?: string;
20
+ version?: string;
19
21
  }>;
20
22
 
21
23
  const SAFE_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
@@ -35,6 +37,17 @@ function renderNextStepCommands(
35
37
  if (input.taskRef !== undefined && !SAFE_TASK_REF.test(input.taskRef)) {
36
38
  throw new Error('Invalid task ref');
37
39
  }
40
+ if (
41
+ input.version !== undefined
42
+ && (!/^[0-9]/.test(input.version) || semver.valid(input.version) !== input.version)
43
+ ) {
44
+ throw new Error('Invalid version');
45
+ }
46
+
47
+ const args = [
48
+ ...(input.taskRef === undefined ? [] : [input.taskRef]),
49
+ ...(input.version === undefined ? [] : [input.version])
50
+ ];
38
51
 
39
52
  const builtins = listEnabledAgentClientAdapters(input.state).map(
40
53
  (adapter): NextStepCommand => Object.freeze({
@@ -46,7 +59,7 @@ function renderNextStepCommands(
46
59
  {
47
60
  projectName: input.projectName,
48
61
  skillName: input.skillName,
49
- args: input.taskRef === undefined ? [] : [input.taskRef]
62
+ args
50
63
  }
51
64
  )
52
65
  })
@@ -60,7 +73,7 @@ function renderNextStepCommands(
60
73
  {
61
74
  projectName: input.projectName,
62
75
  skillName: input.skillName,
63
- args: input.taskRef === undefined ? [] : [input.taskRef]
76
+ args
64
77
  }
65
78
  )
66
79
  })
@@ -236,7 +236,8 @@ function planAgentClientReconciliation(input: Readonly<{
236
236
  const actionableSeed = seedOperations.some((operation) =>
237
237
  operation.kind === 'write' || operation.kind === 'remove'
238
238
  );
239
- const changed = JSON.stringify(nextConfig) !== JSON.stringify(input.config) || actionableSeed;
239
+ const changed = JSON.stringify(nextConfig) !== JSON.stringify(input.config)
240
+ || actionableSeed;
240
241
 
241
242
  return Object.freeze({
242
243
  source: normalized.source,
@@ -104,6 +104,14 @@ function getAgentClientCapability(
104
104
  return getAgentClientAdapter(id).capabilities[capability];
105
105
  }
106
106
 
107
+ function getAgentClientModelSelection(id: unknown) {
108
+ return getAgentClientAdapter(id).modelSelection;
109
+ }
110
+
111
+ function getAgentClientDelegationEvidence(id: unknown) {
112
+ return getAgentClientAdapter(id).delegationEvidence;
113
+ }
114
+
107
115
  function listEnabledAgentClientAdaptersByCapability(
108
116
  state: AgentClientState,
109
117
  capability: AgentClientCapabilityId,
@@ -127,7 +135,15 @@ function createAgentClientManifest(): readonly AgentClientManifestEntry[] {
127
135
  ownedPathPrefixes: Object.freeze([...adapter.project.ownedPathPrefixes]),
128
136
  managed: Object.freeze([...adapter.project.managed]),
129
137
  merged: Object.freeze([...adapter.project.merged]),
130
- ejected: Object.freeze([...adapter.project.ejected])
138
+ ejected: Object.freeze([...adapter.project.ejected]),
139
+ ...(adapter.project.customCommand === undefined
140
+ ? {}
141
+ : {
142
+ customCommand: Object.freeze({
143
+ ...adapter.project.customCommand,
144
+ frontmatter: Object.freeze({ ...adapter.project.customCommand.frontmatter })
145
+ })
146
+ })
131
147
  }))
132
148
  );
133
149
  }
@@ -137,6 +153,8 @@ export {
137
153
  createAgentClientManifest,
138
154
  getAgentClientAdapter,
139
155
  getAgentClientCapability,
156
+ getAgentClientDelegationEvidence,
157
+ getAgentClientModelSelection,
140
158
  listAgentClientAdapters,
141
159
  listEnabledAgentClientAdapters,
142
160
  listEnabledAgentClientAdaptersByCapability,
@@ -29,6 +29,15 @@ const AGENT_CLIENTS_SCHEMA = {
29
29
  },
30
30
  installInSandbox: {
31
31
  type: 'boolean'
32
+ },
33
+ orchestration: {
34
+ type: 'object',
35
+ additionalProperties: false,
36
+ required: ['executor', 'reviewer'],
37
+ properties: {
38
+ executor: { $ref: '#/definitions/orchestrationRolePolicy' },
39
+ reviewer: { $ref: '#/definitions/orchestrationRolePolicy' }
40
+ }
32
41
  }
33
42
  }
34
43
  }
@@ -48,6 +57,15 @@ const AGENT_CLIENTS_SCHEMA = {
48
57
  }
49
58
  },
50
59
  definitions: {
60
+ orchestrationRolePolicy: {
61
+ type: 'object',
62
+ additionalProperties: false,
63
+ required: ['model', 'reasoningEffort'],
64
+ properties: {
65
+ model: { type: 'string', minLength: 1 },
66
+ reasoningEffort: { type: 'string', minLength: 1 }
67
+ }
68
+ },
51
69
  agentClientCapabilityId: {
52
70
  type: 'string',
53
71
  enum: [...AGENT_CLIENT_CAPABILITY_IDS]
@@ -0,0 +1,53 @@
1
+ // Active AI collaborator short tokens — the write-side whitelist for the
2
+ // activity log. Migrated from lib/task/commands/log.ts so that the write-side
3
+ // internal commands and the rendering side share one definition. Historical
4
+ // Gemini tokens remain read-only and are handled by classifyAgent below.
5
+ export const KNOWN_AI_AGENTS: ReadonlySet<string> =
6
+ new Set(['claude', 'codex', 'antigravity', 'opencode', 'cursor']);
7
+
8
+ // Long name -> short name mapping (HD-4, decision A): `claude-code` reuses the
9
+ // existing orchestration precedent, and `antigravity-cli` is the active
10
+ // client. `gemini-cli` is intentionally not writable.
11
+ export const AGENT_LONG_NAMES: Readonly<Record<string, string>> = {
12
+ 'claude-code': 'claude',
13
+ 'antigravity-cli': 'antigravity'
14
+ };
15
+
16
+ export const AGENT_USAGE_HINT =
17
+ "agent must be a short token (claude/codex/antigravity/opencode/cursor), " +
18
+ "a long name (claude-code -> claude, antigravity-cli -> antigravity), or 'human'";
19
+
20
+ // Read-side historical compatibility for activity-log rendering: `gemini` and
21
+ // `gemini-cli` stay recognizable when displaying old logs, but are never
22
+ // accepted by normalizeAgentToken (write side).
23
+ const READ_KNOWN_AI_AGENTS: ReadonlySet<string> =
24
+ new Set([...KNOWN_AI_AGENTS, 'gemini']);
25
+
26
+ const READ_AGENT_LONG_NAMES: Readonly<Record<string, string>> = {
27
+ ...AGENT_LONG_NAMES,
28
+ 'gemini-cli': 'gemini'
29
+ };
30
+
31
+ // Strict write-side validation: the value must be exactly a short token, a
32
+ // long name, or 'human'; returns the normalized short token, or null when
33
+ // the value is not a recognized agent.
34
+ export function normalizeAgentToken(value: string): string | null {
35
+ const trimmed = value.trim();
36
+ if (trimmed === 'human') return 'human';
37
+ if (KNOWN_AI_AGENTS.has(trimmed)) return trimmed;
38
+ const short = AGENT_LONG_NAMES[trimmed];
39
+ return short ?? null;
40
+ }
41
+
42
+ // Loose rendering-side classification: tolerates historical parenthetical
43
+ // annotations; unknown tokens keep the `human` grouping but get a visible
44
+ // signal. The "known AI token" test is `classifyAgent(value).status === 'ai'`.
45
+ export function classifyAgent(raw: string):
46
+ { status: 'ai' | 'human' | 'unknown'; display: string } {
47
+ const token = raw.trim().split(/\s+/)[0]?.replace(/\(.*$/, '') ?? '';
48
+ if (token === '') return { status: 'unknown', display: 'human' };
49
+ if (token === 'human') return { status: 'human', display: 'human' };
50
+ if (READ_KNOWN_AI_AGENTS.has(token)) return { status: 'ai', display: token };
51
+ const short = READ_AGENT_LONG_NAMES[token];
52
+ return short ? { status: 'ai', display: short } : { status: 'unknown', display: 'human' };
53
+ }
@@ -1,16 +1,27 @@
1
1
  const AGENT_CLIENT_IDS = [
2
2
  'claude-code',
3
3
  'codex',
4
- 'gemini-cli',
4
+ 'antigravity-cli',
5
5
  'opencode'
6
6
  ] as const;
7
7
 
8
8
  type AgentClientId = (typeof AGENT_CLIENT_IDS)[number];
9
9
 
10
+ type OrchestrationRolePolicy = Readonly<{
11
+ model: string;
12
+ reasoningEffort: string;
13
+ }>;
14
+
15
+ type OrchestrationModelPolicy = Readonly<{
16
+ executor: OrchestrationRolePolicy;
17
+ reviewer: OrchestrationRolePolicy;
18
+ }>;
19
+
10
20
  type AgentClientConfig = Readonly<{
11
21
  id: AgentClientId;
12
22
  enabled: boolean;
13
23
  installInSandbox: boolean;
24
+ orchestration?: OrchestrationModelPolicy;
14
25
  }>;
15
26
 
16
27
  type AgentClientsConfig = readonly AgentClientConfig[];
@@ -21,6 +32,7 @@ type AgentClientState = Readonly<
21
32
  Readonly<{
22
33
  enabled: boolean;
23
34
  installInSandbox: boolean;
35
+ orchestration?: OrchestrationModelPolicy;
24
36
  }>
25
37
  >
26
38
  >;
@@ -68,6 +80,8 @@ export {
68
80
  };
69
81
  export type {
70
82
  AgentClientId,
83
+ OrchestrationRolePolicy,
84
+ OrchestrationModelPolicy,
71
85
  AgentClientConfig,
72
86
  AgentClientsConfig,
73
87
  AgentClientState,
package/lib/defaults.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "installInSandbox": true
15
15
  },
16
16
  {
17
- "id": "gemini-cli",
17
+ "id": "antigravity-cli",
18
18
  "enabled": true,
19
19
  "installInSandbox": true
20
20
  },
@@ -1,4 +1,6 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
2
4
 
3
5
  type CommandResult = { status: number | null; stdout: string; stderr: string };
4
6
  type GitRunner = (args: readonly string[], cwd: string) => CommandResult;
@@ -18,6 +20,10 @@ function value(runner: GitRunner, cwd: string, args: readonly string[], trim = t
18
20
  return result.status === 0 ? (trim ? result.stdout.trim() : result.stdout.replace(/\n$/, '')) : null;
19
21
  }
20
22
 
23
+ function cleanMessage(message: string): string {
24
+ return message.replace(/(https?:\/\/)[^\s/@:]+(?::[^\s/@]*)?@/gi, '$1***@').trim();
25
+ }
26
+
21
27
  function inspectGitWorkflow(cwd: string, runner: GitRunner = defaultRunner, remoteInput?: { remote: string; refs: readonly string[] }) {
22
28
  const head = value(runner, cwd, ['rev-parse', 'HEAD']);
23
29
  const branch = value(runner, cwd, ['branch', '--show-current']);
@@ -97,5 +103,63 @@ function pushGitRefs(input: { cwd: string; remote: string; refs: readonly string
97
103
  return { status: failures === 0 ? 'applied' as const : failures === operations.length ? 'failed' as const : 'degraded' as const, changed: failures < operations.length, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations, error: failures ? { code: 'GIT_PUSH_PARTIAL', message: `${failures} ref push operation(s) failed` } : null };
98
104
  }
99
105
 
100
- export { commitExplicitPaths, inspectGitWorkflow, pushGitRefs };
101
- export type { CommandResult, GitRunner };
106
+ type PushRebasedInput = {
107
+ cwd: string;
108
+ remote: string;
109
+ branch: string;
110
+ expectedOldHead: string;
111
+ newHead: string;
112
+ baseBranch: string;
113
+ expectedBaseHead: string;
114
+ };
115
+
116
+ function pushRebasedBranch(input: PushRebasedInput, runner: GitRunner = defaultRunner) {
117
+ const sha = /^[0-9a-f]{40}$/i;
118
+ const refName = /^(?!-)(?!.*\.\.)(?!.*(?:^|\/)\.)(?!.*[~^:?*\[\\\s])(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+$/;
119
+ if (!input.remote || !refName.test(input.remote) || !refName.test(input.branch) || !refName.test(input.baseBranch) ||
120
+ !sha.test(input.expectedOldHead) || !sha.test(input.newHead) || !sha.test(input.expectedBaseHead)) {
121
+ return { status: 'failed' as const, changed: false, snapshot: null, operations: [], error: { code: 'GIT_REBASED_INPUT_INVALID', message: 'Remote, branches, and full 40-character SHAs are required' } };
122
+ }
123
+ const snapshot = inspectGitWorkflow(input.cwd, runner).snapshot;
124
+ if (!snapshot) return { status: 'failed' as const, changed: false, snapshot: null, operations: [], error: { code: 'GIT_INSPECT_FAILED', message: 'Unable to inspect Git repository' } };
125
+ if (snapshot.branch !== input.branch || snapshot.head !== input.newHead) {
126
+ return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_LOCAL_IDENTITY_MISMATCH', message: 'Current branch or HEAD does not match the rebased intent' } };
127
+ }
128
+ const rebasePaths = ['rebase-merge', 'rebase-apply']
129
+ .map((name) => value(runner, input.cwd, ['rev-parse', '--git-path', name]))
130
+ .filter((candidate): candidate is string => Boolean(candidate));
131
+ if (snapshot.worktree.length > 0 || snapshot.staged.length > 0 ||
132
+ run(runner, input.cwd, ['rev-parse', '-q', '--verify', 'REBASE_HEAD']).status === 0 ||
133
+ rebasePaths.some((candidate) => fs.existsSync(path.isAbsolute(candidate) ? candidate : path.join(input.cwd, candidate)))) {
134
+ return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_LOCAL_STATE_UNSAFE', message: 'Working tree must be clean with no rebase in progress' } };
135
+ }
136
+ const remoteRef = `refs/heads/${input.branch}`;
137
+ const baseRef = `refs/heads/${input.baseBranch}`;
138
+ const remoteHead = value(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, remoteRef])?.split(/\s+/)[0] ?? null;
139
+ if (remoteHead !== input.expectedOldHead) {
140
+ return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_REMOTE_HEAD_MISMATCH', message: `Expected remote head ${input.expectedOldHead}, received ${remoteHead ?? 'unavailable'}` } };
141
+ }
142
+ const baseHead = value(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, baseRef])?.split(/\s+/)[0] ?? null;
143
+ if (baseHead !== input.expectedBaseHead) {
144
+ return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_REMOTE_BASE_MISMATCH', message: `Expected base head ${input.expectedBaseHead}, received ${baseHead ?? 'unavailable'}` } };
145
+ }
146
+ if (run(runner, input.cwd, ['merge-base', '--is-ancestor', input.expectedBaseHead, input.newHead]).status !== 0) {
147
+ return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_REBASED_ANCESTOR_MISMATCH', message: 'Rebased head does not contain the expected base head' } };
148
+ }
149
+ const pushed = run(runner, input.cwd, [
150
+ 'push', `--force-with-lease=${remoteRef}:${input.expectedOldHead}`,
151
+ input.remote, `${input.newHead}:${remoteRef}`
152
+ ]);
153
+ if (pushed.status !== 0) {
154
+ const message = cleanMessage(pushed.stderr) || 'Rebased branch push was rejected';
155
+ return { status: 'failed' as const, changed: false, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'failed' as const, ref: input.branch, message }], error: { code: 'GIT_REBASED_PUSH_REJECTED', message } };
156
+ }
157
+ const verified = value(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, remoteRef])?.split(/\s+/)[0] ?? null;
158
+ if (verified !== input.newHead) {
159
+ return { status: 'failed' as const, changed: true, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'failed' as const, ref: input.branch, message: 'Remote ref verification failed' }], error: { code: 'GIT_REBASED_VERIFY_FAILED', message: `Expected pushed head ${input.newHead}, received ${verified ?? 'unavailable'}` } };
160
+ }
161
+ return { status: 'applied' as const, changed: true, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'applied' as const, ref: input.branch }], error: null };
162
+ }
163
+
164
+ export { commitExplicitPaths, inspectGitWorkflow, pushGitRefs, pushRebasedBranch };
165
+ export type { CommandResult, GitRunner, PushRebasedInput };
@@ -7,12 +7,15 @@ import {
7
7
  } from '../agent-clients/config.ts';
8
8
  import { normalizeCustomTUIs } from '../agent-clients/custom-tuis.ts';
9
9
  import { renderNextStepCommands } from '../agent-clients/next-steps.ts';
10
+ import { getAgentClientModelSelection } from '../agent-clients/registry.ts';
11
+ import { isAgentClientId } from '../agent-clients/types.ts';
10
12
 
11
- const USAGE = 'Usage: agent-infra-internal agent-client next-steps --skill <skill-name> [--task-ref <NN|TASK-id>] [--format text|json]\n';
13
+ const USAGE = 'Usage: agent-infra-internal agent-client <next-steps|model-selection> [options]\n';
12
14
 
13
15
  type ParsedArgs = Readonly<{
14
16
  skillName: string;
15
17
  taskRef?: string;
18
+ version?: string;
16
19
  format: 'text' | 'json';
17
20
  }>;
18
21
 
@@ -38,11 +41,12 @@ function parseArgs(args: string[]): ParsedArgs | null {
38
41
  }
39
42
  let skillName: string | undefined;
40
43
  let taskRef: string | undefined;
44
+ let version: string | undefined;
41
45
  let format: 'text' | 'json' = 'text';
42
46
  const seen = new Set<string>();
43
47
  for (let index = 1; index < args.length; index += 1) {
44
48
  const flag = args[index]!;
45
- if (!['--skill', '--task-ref', '--format'].includes(flag)) {
49
+ if (!['--skill', '--task-ref', '--version', '--format'].includes(flag)) {
46
50
  failure('AGENT_CLIENT_PAYLOAD_INVALID', `unknown option '${flag}'`);
47
51
  return null;
48
52
  }
@@ -58,6 +62,7 @@ function parseArgs(args: string[]): ParsedArgs | null {
58
62
  seen.add(flag);
59
63
  if (flag === '--skill') skillName = value;
60
64
  if (flag === '--task-ref') taskRef = value;
65
+ if (flag === '--version') version = value;
61
66
  if (flag === '--format') {
62
67
  if (value !== 'text' && value !== 'json') {
63
68
  failure('AGENT_CLIENT_PAYLOAD_INVALID', "format must be 'text' or 'json'");
@@ -70,10 +75,59 @@ function parseArgs(args: string[]): ParsedArgs | null {
70
75
  failure('AGENT_CLIENT_PAYLOAD_INVALID', "option '--skill' is required");
71
76
  return null;
72
77
  }
73
- return { skillName, ...(taskRef ? { taskRef } : {}), format };
78
+ return {
79
+ skillName,
80
+ ...(taskRef ? { taskRef } : {}),
81
+ ...(version ? { version } : {}),
82
+ format
83
+ };
74
84
  }
75
85
 
76
86
  function agentClient(args: string[] = []): void {
87
+ if (args[0] === 'model-selection') {
88
+ const values: Record<string, string> = {};
89
+ const seen = new Set<string>();
90
+ for (let index = 1; index < args.length; index += 1) {
91
+ const flag = args[index]!;
92
+ if (!['--client', '--format'].includes(flag) || seen.has(flag)) {
93
+ failure('AGENT_CLIENT_PAYLOAD_INVALID', `invalid or duplicate option '${flag}'`);
94
+ return;
95
+ }
96
+ const value = args[++index];
97
+ if (!value || value.startsWith('--')) {
98
+ failure('AGENT_CLIENT_PAYLOAD_INVALID', `option '${flag}' requires a value`);
99
+ return;
100
+ }
101
+ seen.add(flag);
102
+ values[flag] = value;
103
+ }
104
+ const client = values['--client'];
105
+ const format = values['--format'] ?? 'text';
106
+ if (!isAgentClientId(client) || !['text', 'json'].includes(format)) {
107
+ failure('AGENT_CLIENT_PAYLOAD_INVALID', 'model-selection requires a known --client and text|json format');
108
+ return;
109
+ }
110
+ const context = getAgentClientModelSelection(client);
111
+ if (format === 'json') {
112
+ process.stdout.write(`${JSON.stringify({
113
+ status: 'resolved', changed: false, client, context, error: null
114
+ })}\n`);
115
+ return;
116
+ }
117
+ if (context.kind === 'interactive-only') {
118
+ process.stdout.write(`Model selection: interactive-only\nCommand: ${context.command}\n${context.guidance}\n`);
119
+ } else {
120
+ process.stdout.write(`Model selection: ${context.completeness} catalog\nSource: ${context.source}\n`);
121
+ for (const model of context.models) {
122
+ const efforts = model.reasoningEfforts?.length
123
+ ? ` (${model.reasoningEfforts.join(', ')})`
124
+ : '';
125
+ process.stdout.write(`- ${model.id}${efforts}\n`);
126
+ }
127
+ if (context.guidance) process.stdout.write(`${context.guidance}\n`);
128
+ }
129
+ return;
130
+ }
77
131
  const parsed = parseArgs(args);
78
132
  if (!parsed || process.exitCode) return;
79
133
 
@@ -98,7 +152,8 @@ function agentClient(args: string[] = []): void {
98
152
  state: clients.state,
99
153
  customTUIs: custom.items,
100
154
  skillName: parsed.skillName,
101
- ...(parsed.taskRef ? { taskRef: parsed.taskRef } : {})
155
+ ...(parsed.taskRef ? { taskRef: parsed.taskRef } : {}),
156
+ ...(parsed.version ? { version: parsed.version } : {})
102
157
  });
103
158
  if (parsed.format === 'json') {
104
159
  process.stdout.write(`${JSON.stringify({
@@ -1,5 +1,5 @@
1
1
  import fs from 'node:fs';
2
- import { commitExplicitPaths, inspectGitWorkflow, pushGitRefs } from '../git/workflow.ts';
2
+ import { commitExplicitPaths, inspectGitWorkflow, pushGitRefs, pushRebasedBranch } from '../git/workflow.ts';
3
3
  import { compareReviewTrees, snapshotReview } from '../git/review-snapshot.ts';
4
4
  import { resolvePostReviewGlobs } from '../task/review-fingerprint.ts';
5
5
 
@@ -23,6 +23,10 @@ function gitWorkflow(args: string[] = []): void {
23
23
  const inputIndex = rest.indexOf('--input');
24
24
  const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1]!, 'utf8')) : null;
25
25
  result = input ? pushGitRefs({ cwd: cwd ?? process.cwd(), ...input }) : { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
26
+ } else if (action === 'push-rebased') {
27
+ const inputIndex = rest.indexOf('--input');
28
+ const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1]!, 'utf8')) : null;
29
+ result = input ? pushRebasedBranch({ cwd: cwd ?? process.cwd(), ...input }) : { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
26
30
  } else if (action === 'snapshot' || action === 'compare-trees') {
27
31
  const inputIndex = rest.indexOf('--input');
28
32
  const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1]!, 'utf8')) : null;
@@ -2,9 +2,9 @@ import path from 'node:path';
2
2
 
3
3
  import {
4
4
  fetchPlatformCheckLogs,
5
- inspectRequiredChecks,
5
+ inspectPullRequestReadiness,
6
6
  resolvePlatformCheckRun,
7
- watchPlatformChecks
7
+ watchPullRequestReadiness
8
8
  } from '../platform/pr-checks.ts';
9
9
  import type { ChecksResult } from '../platform/pr-checks.ts';
10
10
 
@@ -70,7 +70,7 @@ async function platformChecks(args: string[] = []): Promise<void> {
70
70
  };
71
71
  const unexpected = Object.keys(values).find((name) => !allowed[operation]!.includes(name));
72
72
  if (unexpected) { fail(`${operation} does not accept --${unexpected}`); return; }
73
- if (operation === 'inspect') { finish(inspectRequiredChecks(taskRef, { cwd })); return; }
73
+ if (operation === 'inspect') { finish(inspectPullRequestReadiness(taskRef, { cwd })); return; }
74
74
  if (operation === 'resolve-run') {
75
75
  if (!values.checkName) { fail('resolve-run requires --check-name'); return; }
76
76
  finish(resolvePlatformCheckRun(taskRef, { cwd, checkName: values.checkName, detailsUrl: values.detailsUrl }));
@@ -91,7 +91,7 @@ async function platformChecks(args: string[] = []): Promise<void> {
91
91
  process.once('SIGINT', abort);
92
92
  process.once('SIGTERM', abort);
93
93
  try {
94
- finish(await watchPlatformChecks(taskRef, { cwd, intervalSeconds, deadlineSeconds, signal: controller.signal }));
94
+ finish(await watchPullRequestReadiness(taskRef, { cwd, intervalSeconds, deadlineSeconds, signal: controller.signal }));
95
95
  } finally {
96
96
  process.removeListener('SIGINT', abort);
97
97
  process.removeListener('SIGTERM', abort);
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.ts';
4
5
  import {
5
6
  checkPlatformCommentOwner,
6
7
  listPlatformComments,
@@ -8,9 +9,11 @@ import {
8
9
  } from '../platform/issue-comments.ts';
9
10
  import type { CommentKind } from '../platform/issue-comments.ts';
10
11
  import type { PlatformResult } from '../platform/types.ts';
12
+ import { backfillCompletionComments } from '../platform/completion-backfill.ts';
11
13
 
12
14
  const USAGE = `Usage: agent-infra-internal platform-comment list --issue <N> [--cwd <path>]
13
15
  agent-infra-internal platform-comment owner <task-ref> [--cwd <path>]
16
+ agent-infra-internal platform-comment backfill <task-ref> --agent <agent> [--cwd <path>]
14
17
  agent-infra-internal platform-comment sync <task-ref> --kind <kind> --agent <agent> [--artifact <file>] [--body-file <path|->] [--status-label <label>] [--backfill] [--cwd <path>]
15
18
  `;
16
19
 
@@ -52,7 +55,7 @@ function readBodyFile(value: string, cwd: string): string {
52
55
  function platformComment(args: string[] = []): void {
53
56
  if (args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; }
54
57
  const operation = args[0];
55
- if (!operation || !['list', 'owner', 'sync'].includes(operation)) { fail('a valid operation is required'); return; }
58
+ if (!operation || !['list', 'owner', 'backfill', 'sync'].includes(operation)) { fail('a valid operation is required'); return; }
56
59
  const hasTaskRef = operation !== 'list';
57
60
  const taskRef = hasTaskRef ? args[1] : undefined;
58
61
  if (hasTaskRef && (!taskRef || taskRef.startsWith('--'))) { fail(`${operation} requires a task ref`); return; }
@@ -73,10 +76,22 @@ function platformComment(args: string[] = []): void {
73
76
  finish(checkPlatformCommentOwner(taskRef!, { cwd }));
74
77
  return;
75
78
  }
79
+ if (operation === 'backfill') {
80
+ const unexpected = Object.keys(parsed.values).find((key) => !['cwd', 'agent'].includes(key));
81
+ if (unexpected) { fail(`backfill does not accept '--${unexpected}'`); return; }
82
+ const agent = parsed.values.agent;
83
+ if (typeof agent !== 'string' || !agent) { fail('backfill requires --agent'); return; }
84
+ const normalizedAgent = normalizeAgentToken(agent);
85
+ if (!normalizedAgent) { fail(`invalid --agent '${agent}': ${AGENT_USAGE_HINT}`); return; }
86
+ finish(backfillCompletionComments(taskRef!, { cwd, agent: normalizedAgent }));
87
+ return;
88
+ }
76
89
  const kind = parsed.values.kind;
77
90
  const agent = parsed.values.agent;
78
91
  if (!['task', 'artifact', 'summary', 'cancel'].includes(String(kind))) { fail('sync requires a valid --kind'); return; }
79
92
  if (typeof agent !== 'string' || !agent) { fail('sync requires --agent'); return; }
93
+ const normalizedAgent = normalizeAgentToken(agent);
94
+ if (!normalizedAgent) { fail(`invalid --agent '${agent}': ${AGENT_USAGE_HINT}`); return; }
80
95
  if (kind === 'artifact' && typeof parsed.values.artifact !== 'string') { fail('artifact sync requires --artifact'); return; }
81
96
  if ((kind === 'summary' || kind === 'cancel') && typeof parsed.values.bodyFile !== 'string') { fail(`${kind} sync requires --body-file`); return; }
82
97
  let body: string | undefined;
@@ -88,7 +103,7 @@ function platformComment(args: string[] = []): void {
88
103
  }
89
104
  finish(syncPlatformComment(taskRef!, {
90
105
  kind: kind as CommentKind,
91
- agent,
106
+ agent: normalizedAgent,
92
107
  artifact: typeof parsed.values.artifact === 'string' ? parsed.values.artifact : undefined,
93
108
  body,
94
109
  backfill: parsed.values.backfill === true,
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
 
3
+ import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.ts';
3
4
  import {
4
5
  bindPlatformIssue,
5
6
  createPlatformIssue,
@@ -76,6 +77,9 @@ function platformIssue(args: string[] = []): void {
76
77
  if (unexpected) { fail(`${operation} does not accept --${unexpected}`); return; }
77
78
  if (operation === 'inspect') { finish(inspectPlatformIssue(taskRef, { cwd })); return; }
78
79
  if (typeof values.agent !== 'string' || !values.agent) { fail(`${operation} requires --agent`); return; }
80
+ const agent = normalizeAgentToken(values.agent);
81
+ if (!agent) { fail(`invalid --agent '${values.agent}': ${AGENT_USAGE_HINT}`); return; }
82
+ values.agent = agent;
79
83
  if (operation === 'create') {
80
84
  finish(createPlatformIssue(taskRef, { cwd, agent: values.agent, dryRun: values.dryRun === true })); return;
81
85
  }