@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
@@ -7,7 +7,8 @@ import type { ExecFileSyncOptions, StdioOptions } from 'node:child_process';
7
7
  import { parseArgs } from 'node:util';
8
8
  import * as p from '@clack/prompts';
9
9
  import pc from 'picocolors';
10
- import * as toml from 'smol-toml';
10
+ import { listAgentClientAdapters } from '../../agent-clients/registry.ts';
11
+ import type { SandboxAlias } from '../tool-types.ts';
11
12
  import { loadConfig } from '../config.ts';
12
13
  import {
13
14
  assertValidBranchName,
@@ -18,6 +19,7 @@ import {
18
19
  sandboxImageConfigLabel,
19
20
  sandboxImageRefreshLabel,
20
21
  sandboxLabel,
22
+ sandboxRuntimeCapabilityLabel,
21
23
  shareBranchDir,
22
24
  shareCommonDir,
23
25
  shellConfigDir,
@@ -43,6 +45,11 @@ import {
43
45
  runVerboseEngine
44
46
  } from '../shell.ts';
45
47
  import { resolveTaskBranch } from '../task-resolver.ts';
48
+ import {
49
+ createSandboxCapabilityPlan,
50
+ runSandboxHooks,
51
+ runBoundedSandboxHookCommand
52
+ } from '../agent-client-reconciler.ts';
46
53
  import {
47
54
  resolveTools,
48
55
  tmpfsSeedStagingPath,
@@ -61,6 +68,7 @@ import { clipboardHostDir, CONTAINER_CLIPBOARD_MOUNT } from '../clipboard/paths.
61
68
  import { validateSelinuxDisableEnv } from '../engines/selinux.ts';
62
69
  import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.ts';
63
70
  import { ensureSandboxDiscoveryReadmes } from '../readme-scaffold.ts';
71
+ import { removeDirRecursive } from '../../remove-dir.ts';
64
72
  import {
65
73
  prepareClaudeCredentials,
66
74
  redactCommandError,
@@ -76,29 +84,13 @@ import {
76
84
  parseRefreshTimestamp
77
85
  } from '../image-build.ts';
78
86
 
79
- const OPENCODE_YOLO_PERMISSION = '{"*":"allow","read":"allow","bash":"allow","edit":"allow","webfetch":"allow","external_directory":"allow","doom_loop":"allow"}';
87
+ export {
88
+ ensureCodexModelInheritance,
89
+ ensureCodexWorkspaceTrust
90
+ } from '../../agent-clients/adapters/codex-sandbox.ts';
91
+
80
92
  const SANDBOX_ALIAS_BLOCK_BEGIN = '# >>> agent-infra managed aliases >>>';
81
93
  const SANDBOX_ALIAS_BLOCK_END = '# <<< agent-infra managed aliases <<<';
82
- const SANDBOX_ALIAS_NAMES = [
83
- 'claude-yolo',
84
- 'opencode-yolo',
85
- 'codex-yolo',
86
- 'gemini-yolo',
87
- 'cy',
88
- 'oy',
89
- 'xy',
90
- 'gy'
91
- ];
92
- const DEFAULT_SANDBOX_ALIASES = `alias claude-yolo='claude --dangerously-skip-permissions; tput ed'
93
- alias opencode-yolo='OPENCODE_PERMISSION='\\''${OPENCODE_YOLO_PERMISSION}'\\'' opencode; tput ed'
94
- alias codex-yolo='codex --yolo; tput ed'
95
- alias gemini-yolo='gemini --yolo; tput ed'
96
-
97
- alias cy='claude --dangerously-skip-permissions; tput ed'
98
- alias oy='OPENCODE_PERMISSION='\\''${OPENCODE_YOLO_PERMISSION}'\\'' opencode; tput ed'
99
- alias xy='codex --yolo; tput ed'
100
- alias gy='gemini --yolo; tput ed'
101
- `;
102
94
  const CONTAINER_HOME = '/home/devuser';
103
95
  const CONTAINER_SHELL_CONFIG_MOUNT = `${CONTAINER_HOME}/.host-shell-config`;
104
96
  const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh] [--inherit-proxy|-P] [--inherit-build-proxy|-B]
@@ -410,7 +402,7 @@ export function prepareHostShellConfig({
410
402
  repoRoot: string;
411
403
  }): HostShellConfig {
412
404
  const hostDir = hostShellConfigDir(home, project, branch);
413
- fs.rmSync(hostDir, { recursive: true, force: true });
405
+ removeDirRecursive(hostDir);
414
406
  fs.mkdirSync(hostDir, { recursive: true });
415
407
 
416
408
  writeSanitizedGitconfig({
@@ -459,10 +451,19 @@ function normalizeWorktreePath(worktreePath: string): string {
459
451
  return '';
460
452
  }
461
453
 
454
+ const wslMount = process.platform === 'win32'
455
+ ? worktreePath.match(/^\/mnt\/([A-Za-z])(?:\/(.*))?$/)
456
+ : null;
457
+ const hostPath = wslMount
458
+ ? `${wslMount[1]!.toUpperCase()}:\\${(wslMount[2] ?? '').replace(/\//g, '\\')}`
459
+ : worktreePath;
460
+
462
461
  try {
463
- return fs.existsSync(worktreePath) ? fs.realpathSync(worktreePath) : path.resolve(worktreePath);
462
+ const normalized = fs.existsSync(hostPath) ? fs.realpathSync(hostPath) : path.resolve(hostPath);
463
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
464
464
  } catch {
465
- return path.resolve(worktreePath);
465
+ const normalized = path.resolve(hostPath);
466
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
466
467
  }
467
468
  }
468
469
 
@@ -714,7 +715,7 @@ export function buildContainerEnvFile(
714
715
  mkdtempFn = fs.mkdtempSync,
715
716
  writeFileFn = fs.writeFileSync,
716
717
  chmodFn = fs.chmodSync,
717
- rmFn = fs.rmSync,
718
+ rmFn = removeDirRecursive as typeof fs.rmSync,
718
719
  tmpDir = os.tmpdir(),
719
720
  runSafeFn = runSafe
720
721
  } = options;
@@ -971,154 +972,6 @@ export function ensureClaudeSettings(toolDir: string, hostHomeDir?: string): voi
971
972
  }
972
973
  }
973
974
 
974
- function resolveHostCatalogPath(value: unknown, hostHomeDir: string): string | null {
975
- if (typeof value !== 'string' || value === '') {
976
- return null;
977
- }
978
- let resolved: string;
979
- if (value === '~' || value.startsWith('~/') || value.startsWith('~\\')) {
980
- resolved = path.join(hostHomeDir, value.slice(1).replace(/^[/\\]+/, ''));
981
- } else if (path.isAbsolute(value)) {
982
- resolved = value;
983
- } else {
984
- resolved = path.join(hostHomeDir, '.codex', value);
985
- }
986
- try {
987
- if (!fs.statSync(resolved).isFile()) {
988
- return null;
989
- }
990
- fs.accessSync(resolved, fs.constants.R_OK);
991
- return resolved;
992
- } catch {
993
- return null;
994
- }
995
- }
996
-
997
- const CODEX_DISABLED_FEATURE_FLAGS = ['apps', 'enable_mcp_apps'] as const;
998
-
999
- function removeCodexMcpServers(sandboxParsed: JsonObject): boolean {
1000
- if (!Object.hasOwn(sandboxParsed, 'mcp_servers')) {
1001
- return false;
1002
- }
1003
- delete sandboxParsed.mcp_servers;
1004
- return true;
1005
- }
1006
-
1007
- function inheritDisabledCodexFeatureFlags(sandboxParsed: JsonObject, hostParsed: JsonObject): boolean {
1008
- if (!isJsonObjectRecord(hostParsed.features)) {
1009
- return false;
1010
- }
1011
- if (Object.hasOwn(sandboxParsed, 'features') && !isJsonObjectRecord(sandboxParsed.features)) {
1012
- return false;
1013
- }
1014
-
1015
- let sandboxFeatures = sandboxParsed.features as JsonObject | undefined;
1016
- let changed = false;
1017
- for (const key of CODEX_DISABLED_FEATURE_FLAGS) {
1018
- if (hostParsed.features[key] !== false) {
1019
- continue;
1020
- }
1021
- if (!sandboxFeatures) {
1022
- sandboxFeatures = {};
1023
- sandboxParsed.features = sandboxFeatures;
1024
- }
1025
- if (sandboxFeatures[key] !== false) {
1026
- sandboxFeatures[key] = false;
1027
- changed = true;
1028
- }
1029
- }
1030
- return changed;
1031
- }
1032
-
1033
- export function ensureCodexModelInheritance(
1034
- toolDir: string,
1035
- hostHomeDir?: string,
1036
- containerCodexDir: string = '/home/devuser/.codex'
1037
- ): void {
1038
- if (!hostHomeDir) {
1039
- return;
1040
- }
1041
-
1042
- const hostConfigPath = path.join(hostHomeDir, '.codex', 'config.toml');
1043
- if (!fs.existsSync(hostConfigPath)) {
1044
- return;
1045
- }
1046
-
1047
- let hostParsed: JsonObject;
1048
- try {
1049
- hostParsed = toml.parse(fs.readFileSync(hostConfigPath, 'utf8')) as JsonObject;
1050
- } catch {
1051
- return;
1052
- }
1053
-
1054
- const sandboxConfigPath = path.join(toolDir, 'config.toml');
1055
- // This rewrites sandbox-side TOML and drops comments; the host config stays untouched.
1056
- let sandboxParsed: JsonObject = {};
1057
- if (fs.existsSync(sandboxConfigPath)) {
1058
- try {
1059
- sandboxParsed = toml.parse(fs.readFileSync(sandboxConfigPath, 'utf8')) as JsonObject;
1060
- } catch {
1061
- return;
1062
- }
1063
- }
1064
-
1065
- let changed = removeCodexMcpServers(sandboxParsed);
1066
- changed = inheritDisabledCodexFeatureFlags(sandboxParsed, hostParsed) || changed;
1067
-
1068
- const inheritSpecs: Array<readonly [string, 'string' | 'number']> = [
1069
- ['model', 'string'],
1070
- ['model_reasoning_effort', 'string'],
1071
- ['model_auto_compact_token_limit', 'number']
1072
- ];
1073
-
1074
- for (const [key, type] of inheritSpecs) {
1075
- if (Object.hasOwn(sandboxParsed, key)) {
1076
- continue;
1077
- }
1078
- const value = hostParsed[key];
1079
- if (type === 'string' && (typeof value !== 'string' || value === '')) {
1080
- continue;
1081
- }
1082
- if (type === 'number' && (typeof value !== 'number' || !Number.isFinite(value) || value <= 0)) {
1083
- continue;
1084
- }
1085
- sandboxParsed[key] = value;
1086
- changed = true;
1087
- }
1088
-
1089
- if (!Object.hasOwn(sandboxParsed, 'model_catalog_json')) {
1090
- const hostCatalogPath = resolveHostCatalogPath(hostParsed['model_catalog_json'], hostHomeDir);
1091
- if (hostCatalogPath) {
1092
- try {
1093
- const basename = path.basename(hostCatalogPath);
1094
- const destDir = path.join(toolDir, 'model-catalogs');
1095
- fs.mkdirSync(destDir, { recursive: true });
1096
- fs.copyFileSync(hostCatalogPath, path.join(destDir, basename));
1097
- sandboxParsed['model_catalog_json'] = path.posix.join(containerCodexDir, 'model-catalogs', basename);
1098
- changed = true;
1099
- } catch {
1100
- // Copy failed (e.g. permissions): skip catalog, keep scalar inheritance intact.
1101
- }
1102
- }
1103
- }
1104
-
1105
- if (changed) {
1106
- fs.writeFileSync(sandboxConfigPath, `${toml.stringify(sandboxParsed)}\n`, 'utf8');
1107
- }
1108
- }
1109
-
1110
- export function ensureCodexWorkspaceTrust(toolDir: string): void {
1111
- const configPath = path.join(toolDir, 'config.toml');
1112
- let content = '';
1113
- if (fs.existsSync(configPath)) {
1114
- content = fs.readFileSync(configPath, 'utf8');
1115
- }
1116
- if (!content.includes('[projects."/workspace"]')) {
1117
- const entry = '\n[projects."/workspace"]\ntrust_level = "trusted"\n';
1118
- fs.writeFileSync(configPath, content + entry, 'utf8');
1119
- }
1120
- }
1121
-
1122
975
  export function ensureOpenCodeModelInheritance(toolDir: string, hostHomeDir?: string): void {
1123
976
  if (!hostHomeDir) {
1124
977
  return;
@@ -1157,22 +1010,6 @@ export function ensureOpenCodeModelInheritance(toolDir: string, hostHomeDir?: st
1157
1010
  }
1158
1011
  }
1159
1012
 
1160
- export function ensureGeminiWorkspaceTrust(toolDir: string): void {
1161
- const trustPath = path.join(toolDir, 'trustedFolders.json');
1162
- let data: Record<string, string> = {};
1163
- if (fs.existsSync(trustPath)) {
1164
- try {
1165
- data = JSON.parse(fs.readFileSync(trustPath, 'utf8')) as Record<string, string>;
1166
- } catch {
1167
- // malformed JSON, start fresh
1168
- }
1169
- }
1170
- if (data['/workspace'] !== 'TRUST_FOLDER') {
1171
- data['/workspace'] = 'TRUST_FOLDER';
1172
- fs.writeFileSync(trustPath, JSON.stringify(data, null, 2), 'utf8');
1173
- }
1174
- }
1175
-
1176
1013
  export function sandboxAliasesPath(home: string): string {
1177
1014
  return hostJoin(home, '.agent-infra', 'aliases', 'sandbox.sh');
1178
1015
  }
@@ -1189,7 +1026,10 @@ function stripManagedSandboxAliasBlocks(content: string): string {
1189
1026
  return content.replace(blockPattern, '').trimEnd();
1190
1027
  }
1191
1028
 
1192
- function isLegacyManagedSandboxAliasFile(content: string): boolean {
1029
+ function isLegacyManagedSandboxAliasFile(
1030
+ content: string,
1031
+ aliases: readonly SandboxAlias[]
1032
+ ): boolean {
1193
1033
  const lines = content
1194
1034
  .split(/\r?\n/)
1195
1035
  .map((line) => line.trim())
@@ -1199,13 +1039,29 @@ function isLegacyManagedSandboxAliasFile(content: string): boolean {
1199
1039
  return false;
1200
1040
  }
1201
1041
 
1202
- const aliasPattern = new RegExp(`^alias (${SANDBOX_ALIAS_NAMES.map(escapeRegExp).join('|')})=`);
1042
+ const aliasPattern = new RegExp(
1043
+ `^alias (${aliases.map((alias) => escapeRegExp(alias.name)).join('|')})=`
1044
+ );
1203
1045
  return lines.every((line) => aliasPattern.test(line));
1204
1046
  }
1205
1047
 
1206
- export function ensureSandboxAliasesFile(home: string): { created: boolean; path: string } {
1048
+ function registrySandboxAliases(): readonly SandboxAlias[] {
1049
+ return listAgentClientAdapters().flatMap((adapter) => adapter.sandbox.aliases);
1050
+ }
1051
+
1052
+ function renderSandboxAliases(aliases: readonly SandboxAlias[]): string {
1053
+ return `${aliases.map((alias) =>
1054
+ `alias ${alias.name}='${alias.command.replaceAll("'", "'\\''")}'`
1055
+ ).join('\n')}\n`;
1056
+ }
1057
+
1058
+ export function ensureSandboxAliasesFile(
1059
+ home: string,
1060
+ aliases: readonly SandboxAlias[] = registrySandboxAliases()
1061
+ ): { created: boolean; path: string } {
1207
1062
  const aliasesPath = sandboxAliasesPath(home);
1208
- const managedBlock = `${SANDBOX_ALIAS_BLOCK_BEGIN}\n${DEFAULT_SANDBOX_ALIASES}${SANDBOX_ALIAS_BLOCK_END}\n`;
1063
+ const managedBlock =
1064
+ `${SANDBOX_ALIAS_BLOCK_BEGIN}\n${renderSandboxAliases(aliases)}${SANDBOX_ALIAS_BLOCK_END}\n`;
1209
1065
  fs.mkdirSync(path.dirname(aliasesPath), { recursive: true });
1210
1066
  const created = !fs.existsSync(aliasesPath);
1211
1067
  let existing = '';
@@ -1214,7 +1070,7 @@ export function ensureSandboxAliasesFile(home: string): { created: boolean; path
1214
1070
  existing = fs.readFileSync(aliasesPath, 'utf8');
1215
1071
  }
1216
1072
 
1217
- const userContent = isLegacyManagedSandboxAliasFile(existing)
1073
+ const userContent = isLegacyManagedSandboxAliasFile(existing, aliases)
1218
1074
  ? ''
1219
1075
  : stripManagedSandboxAliasBlocks(existing);
1220
1076
  const nextContent = userContent
@@ -1355,19 +1211,18 @@ export async function create(args: string[]): Promise<void> {
1355
1211
  };
1356
1212
  const worktreeCandidates = worktreeDirCandidates(effectiveConfig, branch);
1357
1213
  assertBranchAvailable(config.repoRoot, branch, { allowedWorktrees: worktreeCandidates });
1358
- const tools = resolveTools(effectiveConfig);
1214
+ const capabilityPlan = createSandboxCapabilityPlan(effectiveConfig);
1215
+ const tools = [...capabilityPlan.tools];
1359
1216
  const resolvedTools = resolveToolDirs(effectiveConfig, tools, branch);
1360
1217
  // Fatal credential states still fail before filesystem/docker side effects.
1361
- // A genuinely missing Claude Code credential only removes Claude Code's
1362
- // sandbox config and credential mounts for this create run.
1218
+ // Missing credentials leave the selected Claude Code capability installed
1219
+ // and mounted; only the absent live credential file is omitted.
1363
1220
  const credentialOutcome = prepareClaudeCredentials(
1364
1221
  effectiveConfig.home,
1365
1222
  effectiveConfig.project,
1366
1223
  resolvedTools
1367
1224
  );
1368
- const effectiveResolvedTools = credentialOutcome.status === 'SKIPPED'
1369
- ? resolvedTools.filter(({ tool }) => tool.id !== 'claude-code')
1370
- : resolvedTools;
1225
+ const effectiveResolvedTools = resolvedTools;
1371
1226
  const container = containerName(effectiveConfig, branch);
1372
1227
  const worktree = worktreeCandidates.find((candidate) => fs.existsSync(candidate)) ?? worktreeCandidates[0] ?? '';
1373
1228
  const shareCommon = shareCommonDir(effectiveConfig);
@@ -1392,6 +1247,16 @@ export async function create(args: string[]): Promise<void> {
1392
1247
 
1393
1248
  try {
1394
1249
  p.log.step('Checking container engine...');
1250
+ const prepareHookResults = await runSandboxHooks({
1251
+ hooks: capabilityPlan.hooksByPhase.prepare,
1252
+ phase: 'prepare',
1253
+ context: { config: effectiveConfig, plan: capabilityPlan },
1254
+ runCommand: runBoundedSandboxHookCommand
1255
+ });
1256
+ const prepareFailure = prepareHookResults.find((result) => result.status === 'fatal');
1257
+ if (prepareFailure) {
1258
+ throw new Error(prepareFailure.message ?? `Sandbox hook '${prepareFailure.hookId}' failed.`);
1259
+ }
1395
1260
  await ensureDocker(effectiveConfig, (detail: string) => {
1396
1261
  p.log.info(` ${detail}`);
1397
1262
  });
@@ -1476,7 +1341,7 @@ export async function create(args: string[]): Promise<void> {
1476
1341
  if (fs.readdirSync(worktree).length > 0) {
1477
1342
  return `Worktree exists at ${worktree}`;
1478
1343
  }
1479
- fs.rmSync(worktree, { recursive: true, force: true });
1344
+ removeDirRecursive(worktree);
1480
1345
  }
1481
1346
 
1482
1347
  const branchExists = runOk('git', [
@@ -1573,7 +1438,10 @@ export async function create(args: string[]): Promise<void> {
1573
1438
  }
1574
1439
  }
1575
1440
 
1576
- const aliasesFile = ensureSandboxAliasesFile(effectiveConfig.home);
1441
+ const aliasesFile = ensureSandboxAliasesFile(
1442
+ effectiveConfig.home,
1443
+ capabilityPlan.aliases
1444
+ );
1577
1445
  if (aliasesFile.created) {
1578
1446
  message(`Created default sandbox aliases at ${aliasesFile.path}`);
1579
1447
  }
@@ -1609,6 +1477,28 @@ export async function create(args: string[]): Promise<void> {
1609
1477
  let hostShellConfig: HostShellConfig;
1610
1478
  let tmpfsSeedPlan: TmpfsSeedPlanEntry[] = [];
1611
1479
  try {
1480
+ const beforeCreateResults = await runSandboxHooks({
1481
+ hooks: capabilityPlan.hooksByPhase['before-container-create'],
1482
+ phase: 'before-container-create',
1483
+ context: {
1484
+ config: effectiveConfig,
1485
+ plan: capabilityPlan,
1486
+ create: {
1487
+ hostHome: effectiveConfig.home,
1488
+ resolvedTools: effectiveResolvedTools
1489
+ }
1490
+ },
1491
+ runCommand: runBoundedSandboxHookCommand
1492
+ });
1493
+ const beforeCreateFailure = beforeCreateResults.find(
1494
+ (result) => result.status === 'fatal'
1495
+ );
1496
+ if (beforeCreateFailure) {
1497
+ throw new Error(
1498
+ beforeCreateFailure.message
1499
+ ?? `Sandbox hook '${beforeCreateFailure.hookId}' failed.`
1500
+ );
1501
+ }
1612
1502
  const claudeCodeEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'claude-code');
1613
1503
  if (claudeCodeEntry) {
1614
1504
  ensureClaudeOnboarding(claudeCodeEntry.dir, effectiveConfig.home);
@@ -1617,15 +1507,6 @@ export async function create(args: string[]): Promise<void> {
1617
1507
  // provider/API settings are enough for Claude Code. If no usable
1618
1508
  // auth was present, the claude-code entry was removed above.
1619
1509
  }
1620
- const codexEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'codex');
1621
- if (codexEntry) {
1622
- ensureCodexModelInheritance(codexEntry.dir, effectiveConfig.home, codexEntry.tool.containerMount);
1623
- ensureCodexWorkspaceTrust(codexEntry.dir);
1624
- }
1625
- const geminiEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'gemini-cli');
1626
- if (geminiEntry) {
1627
- ensureGeminiWorkspaceTrust(geminiEntry.dir);
1628
- }
1629
1510
  const opencodeEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'opencode');
1630
1511
  if (opencodeEntry) {
1631
1512
  // The TUI reads <toolDir>/opencode.json via OPENCODE_CONFIG pinned in tools.js.
@@ -1709,6 +1590,8 @@ export async function create(args: string[]): Promise<void> {
1709
1590
  sandboxLabel(effectiveConfig),
1710
1591
  '--label',
1711
1592
  `${sandboxBranchLabel(effectiveConfig)}=${branch}`,
1593
+ '--label',
1594
+ `${sandboxRuntimeCapabilityLabel(effectiveConfig)}=${capabilityPlan.runtimeSignature}`,
1712
1595
  ...coreVolumes,
1713
1596
  ...buildClipboardVolumeArgs(engine, effectiveConfig.home),
1714
1597
  '-v',
@@ -1805,6 +1688,22 @@ export async function create(args: string[]): Promise<void> {
1805
1688
  }
1806
1689
  }
1807
1690
 
1691
+ const afterStartResults = await runSandboxHooks({
1692
+ hooks: capabilityPlan.hooksByPhase['after-container-start'],
1693
+ phase: 'after-container-start',
1694
+ context: { config: effectiveConfig, plan: capabilityPlan },
1695
+ runCommand: runBoundedSandboxHookCommand
1696
+ });
1697
+ const afterStartFailure = afterStartResults.find(
1698
+ (result) => result.status === 'fatal'
1699
+ );
1700
+ if (afterStartFailure) {
1701
+ throw new Error(
1702
+ afterStartFailure.message
1703
+ ?? `Sandbox hook '${afterStartFailure.hookId}' failed.`
1704
+ );
1705
+ }
1706
+
1808
1707
  return 'Container started';
1809
1708
  }
1810
1709
  }
@@ -7,6 +7,11 @@ import {
7
7
  } from '../constants.ts';
8
8
  import { detectEngine } from '../engine.ts';
9
9
  import { ensureSandboxReady } from '../recovery.ts';
10
+ import {
11
+ createSandboxCapabilityPlan,
12
+ runBoundedSandboxHookCommand,
13
+ runSandboxHooks
14
+ } from '../agent-client-reconciler.ts';
10
15
  import {
11
16
  formatCredentialWarnings,
12
17
  formatRemaining,
@@ -186,8 +191,25 @@ export async function enter(args: string[]): Promise<number> {
186
191
  });
187
192
  const container = ready.container;
188
193
  const cmd = parsed.command;
194
+ const capabilityPlan = createSandboxCapabilityPlan(config);
195
+ const enterHookResults = await runSandboxHooks({
196
+ hooks: capabilityPlan.hooksByPhase['before-enter'],
197
+ phase: 'before-enter',
198
+ context: { config, plan: capabilityPlan },
199
+ runCommand: runBoundedSandboxHookCommand
200
+ });
201
+ for (const result of enterHookResults) {
202
+ if (result.status === 'fatal') {
203
+ throw new Error(result.message ?? `Sandbox hook '${result.hookId}' failed.`);
204
+ }
205
+ if (result.status === 'warning') {
206
+ process.stderr.write(
207
+ `Warning: ${result.message ?? `Sandbox hook '${result.hookId}' did not complete.`}\n`
208
+ );
209
+ }
210
+ }
189
211
 
190
- if (config.tools.includes('claude-code')) {
212
+ if (capabilityPlan.selectedAgentClients.some((adapter) => adapter.id === 'claude-code')) {
191
213
  try {
192
214
  // Scan all projects so a refresh from a neighbouring sandbox can still flow back to the host.
193
215
  const providerAuthAvailable = hasClaudeProviderAuth(config.home);
@@ -11,7 +11,7 @@ import { hostJoin } from '../engines/wsl2-paths.ts';
11
11
  import { removeManagedDir, removeWorktreeDir } from '../managed-fs.ts';
12
12
  import { parseLabels } from './ls.ts';
13
13
  import { runEngine, runSafe } from '../shell.ts';
14
- import { resolveTools } from '../tools.ts';
14
+ import { createSandboxCapabilityPlan } from '../agent-client-reconciler.ts';
15
15
  import type { SandboxTool } from '../tools.ts';
16
16
 
17
17
  const USAGE = `Usage: ai sandbox prune [--dry-run]`;
@@ -158,7 +158,7 @@ export async function prune(args: string[]): Promise<void> {
158
158
  }
159
159
 
160
160
  const config = loadConfig();
161
- const tools = resolveTools(config);
161
+ const tools = [...createSandboxCapabilityPlan(config).cleanupInventory];
162
162
  const engine = detectEngine(config);
163
163
  const psArgs = [
164
164
  'ps',
@@ -19,7 +19,8 @@ import { pruneSandboxDanglingImages } from '../image-prune.ts';
19
19
  import { removeManagedDir, removeWorktreeDir } from '../managed-fs.ts';
20
20
  import { runOk, runSafe, runSafeEngine } from '../shell.ts';
21
21
  import { resolveTaskBranch } from '../task-resolver.ts';
22
- import { resolveTools, toolConfigDirCandidates, toolProjectDirCandidates } from '../tools.ts';
22
+ import { toolConfigDirCandidates, toolProjectDirCandidates } from '../tools.ts';
23
+ import { createSandboxCapabilityPlan } from '../agent-client-reconciler.ts';
23
24
  import type { SandboxTool } from '../tools.ts';
24
25
  import { fetchSandboxRows } from './list-running.ts';
25
26
  import { lookupShortIdByBranch } from '../../task/short-id.ts';
@@ -353,7 +354,7 @@ export async function rm(args: string[]): Promise<void> {
353
354
  }
354
355
 
355
356
  const config = loadConfig();
356
- const tools = resolveTools(config);
357
+ const tools = [...createSandboxCapabilityPlan(config).cleanupInventory];
357
358
 
358
359
  if (values.purge) {
359
360
  await rmPurge(config, tools);
@@ -10,7 +10,7 @@ import { resolveTools, toolConfigDirCandidates } from '../tools.ts';
10
10
  const USAGE = `Usage: ai sandbox show <branch | TASK-id | N>
11
11
 
12
12
  Shows one sandbox's worktree path and per-tool state paths (Claude Code,
13
- Codex, Gemini CLI, OpenCode). The argument follows the same contract as
13
+ Codex, Antigravity CLI, OpenCode). The argument follows the same contract as
14
14
  'ai sandbox exec' and 'ai sandbox start': N (bare) is the recommended form
15
15
  for task short ids (e.g. 'ai sandbox show 11'); a TASK-id or a plain
16
16
  branch name are also accepted. Use 'ai sandbox ls' for the container list.`;
@@ -3,6 +3,9 @@ import path from 'node:path';
3
3
  import { homedir, platform } from 'node:os';
4
4
  import { execFileSync } from 'node:child_process';
5
5
  import pc from 'picocolors';
6
+ import { normalizeAgentClients } from '../agent-clients/config.ts';
7
+ import { isAgentClientId } from '../agent-clients/types.ts';
8
+ import type { AgentClientState } from '../agent-clients/types.ts';
6
9
  import { validateSandboxEngine } from './engine.ts';
7
10
  import { hostJoin } from './engines/wsl2-paths.ts';
8
11
  import { findRuntimeEngineMismatches } from './runtime-engines.ts';
@@ -12,7 +15,7 @@ import type { SandboxTool } from './tools.ts';
12
15
  const DEFAULTS = Object.freeze({
13
16
  engine: null,
14
17
  runtimes: ['node22'],
15
- tools: ['agent-infra', 'claude-code', 'codex', 'gemini-cli', 'opencode'],
18
+ tools: ['agent-infra'],
16
19
  refreshIntervalDays: 7,
17
20
  dockerfile: null,
18
21
  vm: {
@@ -57,6 +60,8 @@ export type SandboxConfig = {
57
60
  runtimes: string[];
58
61
  tools: string[];
59
62
  customTools: SandboxTool[];
63
+ agentClientState: AgentClientState;
64
+ agentClientSource: 'canonical' | 'legacy';
60
65
  refreshIntervalDays: number;
61
66
  dockerfile: string | null;
62
67
  vm: SandboxVmConfig;
@@ -65,6 +70,8 @@ export type SandboxConfig = {
65
70
  type AircConfig = {
66
71
  project?: unknown;
67
72
  org?: unknown;
73
+ agentClients?: unknown;
74
+ tuis?: unknown;
68
75
  sandbox?: SandboxConfigInput;
69
76
  };
70
77
 
@@ -98,6 +105,23 @@ function cloneDefaults(): SandboxConfigInput & { vm: SandboxVmConfig; runtimes:
98
105
  };
99
106
  }
100
107
 
108
+ function resolveSandboxToolIds(
109
+ sandbox: SandboxConfigInput,
110
+ agentClients: ReturnType<typeof normalizeAgentClients>,
111
+ defaults: readonly string[]
112
+ ): string[] {
113
+ if (Array.isArray(sandbox.tools)) {
114
+ const tools = sandbox.tools.filter((tool): tool is string => typeof tool === 'string');
115
+ return agentClients.source === 'canonical'
116
+ ? tools.filter((tool) => !isAgentClientId(tool))
117
+ : tools;
118
+ }
119
+ if (agentClients.remainingSandboxTools !== undefined) {
120
+ return [...agentClients.remainingSandboxTools];
121
+ }
122
+ return [...defaults];
123
+ }
124
+
101
125
  export function loadConfig({
102
126
  platformFn = platform,
103
127
  writeStderr = (chunk) => process.stderr.write(chunk)
@@ -115,6 +139,8 @@ export function loadConfig({
115
139
  }
116
140
 
117
141
  const airc = JSON.parse(fs.readFileSync(configPath, 'utf8')) as AircConfig;
142
+ const sandboxInput = airc.sandbox;
143
+ const agentClients = normalizeAgentClients(airc);
118
144
  const defaults = cloneDefaults();
119
145
  const sandbox = airc.sandbox ?? {};
120
146
  const engine = validateSandboxEngine(sandbox.engine ?? defaults.engine, { platformFn });
@@ -149,6 +175,7 @@ export function loadConfig({
149
175
  }
150
176
 
151
177
  const customTools = parseCustomTools(sandbox.customTools, { home });
178
+ const tools = resolveSandboxToolIds(sandbox, agentClients, defaults.tools);
152
179
 
153
180
  return {
154
181
  repoRoot,
@@ -164,10 +191,10 @@ export function loadConfig({
164
191
  dotfilesDir: hostJoin(home, '.agent-infra', 'dotfiles'),
165
192
  engine,
166
193
  runtimes,
167
- tools: Array.isArray(sandbox.tools) && sandbox.tools.length > 0
168
- ? [...sandbox.tools]
169
- : defaults.tools,
194
+ tools,
170
195
  customTools,
196
+ agentClientState: agentClients.state,
197
+ agentClientSource: agentClients.source,
171
198
  refreshIntervalDays: asNonNegativeIntegerOrDefault(
172
199
  sandbox.refreshIntervalDays,
173
200
  defaults.refreshIntervalDays
@@ -111,6 +111,12 @@ export function sandboxImageRefreshLabel(config: Pick<SandboxPathConfig, 'projec
111
111
  return `${sandboxLabel(config)}.last-refresh`;
112
112
  }
113
113
 
114
+ export function sandboxRuntimeCapabilityLabel(
115
+ config: Pick<SandboxPathConfig, 'project'>
116
+ ): string {
117
+ return `agent-infra.sandbox.runtime-capability.${config.project}`;
118
+ }
119
+
114
120
  export function parsePositiveIntegerOption(value: unknown, optionName: string): number | undefined {
115
121
  if (value === undefined || value === null) {
116
122
  return undefined;
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { createHash } from 'node:crypto';
5
5
  import { fileURLToPath } from 'node:url';
6
+ import { removeDirRecursive } from '../remove-dir.ts';
6
7
 
7
8
  const RUNTIMES_DIR = path.join(
8
9
  path.dirname(fileURLToPath(import.meta.url)),
@@ -88,7 +89,7 @@ export function prepareDockerfile(config: DockerfileConfig): { path: string; sig
88
89
  path: tempPath,
89
90
  signature: dockerfileSignature(config),
90
91
  cleanup() {
91
- fs.rmSync(tempDir, { recursive: true, force: true });
92
+ removeDirRecursive(tempDir);
92
93
  }
93
94
  };
94
95
  }