@fitlab-ai/agent-infra 0.9.0 → 0.9.2

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 (327) hide show
  1. package/README.md +22 -5
  2. package/README.zh-CN.md +21 -5
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +20 -0
  6. package/dist/lib/agent-client.js +163 -0
  7. package/dist/lib/agent-clients/adapter.js +294 -0
  8. package/dist/lib/agent-clients/adapters/claude-code.js +62 -0
  9. package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
  10. package/dist/lib/agent-clients/adapters/codex.js +54 -0
  11. package/dist/lib/agent-clients/adapters/gemini-cli.js +64 -0
  12. package/dist/lib/agent-clients/adapters/index.js +20 -0
  13. package/dist/lib/agent-clients/adapters/opencode.js +64 -0
  14. package/dist/lib/agent-clients/config.js +177 -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 +38 -0
  18. package/dist/lib/agent-clients/project-assets.js +45 -0
  19. package/dist/lib/agent-clients/reconcile.js +235 -0
  20. package/dist/lib/agent-clients/registry.js +72 -0
  21. package/dist/lib/agent-clients/schema.js +57 -0
  22. package/dist/lib/agent-clients/types.js +29 -0
  23. package/dist/lib/builtin-tuis.js +9 -14
  24. package/dist/lib/defaults.json +85 -73
  25. package/dist/lib/git/review-snapshot.js +25 -10
  26. package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
  27. package/dist/lib/init.js +47 -91
  28. package/dist/lib/internal/agent-client.js +117 -0
  29. package/dist/lib/internal/git-workflow.js +1 -1
  30. package/dist/lib/internal/platform-release-notes.js +53 -0
  31. package/dist/lib/internal/release-workflow.js +175 -17
  32. package/dist/lib/internal/task-orchestration.js +151 -0
  33. package/dist/lib/internal/task-review.js +65 -0
  34. package/dist/lib/merge.js +2 -1
  35. package/dist/lib/platform/adapters.js +38 -1
  36. package/dist/lib/platform/change-request-git-evidence.js +113 -0
  37. package/dist/lib/platform/github-release-notes.js +96 -0
  38. package/dist/lib/platform/issues.js +4 -2
  39. package/dist/lib/platform/merged-pr-equivalence.js +84 -0
  40. package/dist/lib/platform/pr-checks.js +43 -15
  41. package/dist/lib/platform/pull-requests.js +113 -7
  42. package/dist/lib/platform/release-notes.js +143 -0
  43. package/dist/lib/platform/releases.js +1 -1
  44. package/dist/lib/platform/verification-required.js +31 -9
  45. package/dist/lib/prompt.js +15 -3
  46. package/dist/lib/release/channels.js +4 -1
  47. package/dist/lib/release/workflow.js +4 -2
  48. package/dist/lib/remove-dir.js +25 -0
  49. package/dist/lib/run/tui.js +8 -2
  50. package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
  51. package/dist/lib/sandbox/build-proxy.js +63 -0
  52. package/dist/lib/sandbox/clipboard/linux.js +2 -1
  53. package/dist/lib/sandbox/commands/create.js +133 -189
  54. package/dist/lib/sandbox/commands/enter.js +17 -1
  55. package/dist/lib/sandbox/commands/prune.js +2 -2
  56. package/dist/lib/sandbox/commands/rebuild.js +24 -7
  57. package/dist/lib/sandbox/commands/rm.js +3 -2
  58. package/dist/lib/sandbox/config.js +21 -4
  59. package/dist/lib/sandbox/constants.js +3 -0
  60. package/dist/lib/sandbox/dockerfile.js +2 -1
  61. package/dist/lib/sandbox/image-build.js +2 -1
  62. package/dist/lib/sandbox/managed-fs.js +10 -5
  63. package/dist/lib/sandbox/recovery.js +52 -36
  64. package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  65. package/dist/lib/sandbox/runtimes/base.dockerfile +8 -1
  66. package/dist/lib/sandbox/runtimes/java17.dockerfile +8 -1
  67. package/dist/lib/sandbox/runtimes/java21.dockerfile +8 -1
  68. package/dist/lib/sandbox/runtimes/node20.dockerfile +8 -1
  69. package/dist/lib/sandbox/runtimes/node22.dockerfile +8 -1
  70. package/dist/lib/sandbox/runtimes/python3.dockerfile +8 -1
  71. package/dist/lib/sandbox/shell.js +3 -2
  72. package/dist/lib/sandbox/tool-types.js +8 -0
  73. package/dist/lib/sandbox/tools.js +2 -126
  74. package/dist/lib/task/artifact-lifecycle.js +1 -49
  75. package/dist/lib/task/commands/decisions.js +50 -20
  76. package/dist/lib/task/commands/issue-body.js +10 -5
  77. package/dist/lib/task/delegation-receipts.js +107 -0
  78. package/dist/lib/task/events.js +101 -2
  79. package/dist/lib/task/issue-form.js +2 -0
  80. package/dist/lib/task/orchestration.js +420 -0
  81. package/dist/lib/task/review-artifacts.js +143 -59
  82. package/dist/lib/task/review-finalization.js +166 -0
  83. package/dist/lib/task/review-fingerprint.js +13 -0
  84. package/dist/lib/task/verification-checks.js +2 -1
  85. package/dist/lib/task/verification-engine.js +168 -23
  86. package/dist/lib/task/verification-review.js +1 -1
  87. package/dist/lib/task/verification.js +4 -2
  88. package/dist/lib/task/workspace-snapshot.js +34 -0
  89. package/dist/lib/update.js +42 -161
  90. package/lib/agent-client.ts +214 -0
  91. package/lib/agent-clients/adapter.ts +461 -0
  92. package/lib/agent-clients/adapters/claude-code.ts +70 -0
  93. package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
  94. package/lib/agent-clients/adapters/codex.ts +58 -0
  95. package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
  96. package/lib/agent-clients/adapters/index.ts +27 -0
  97. package/lib/agent-clients/adapters/opencode.ts +66 -0
  98. package/lib/agent-clients/config.ts +278 -0
  99. package/lib/agent-clients/custom-tuis.ts +149 -0
  100. package/lib/agent-clients/invocation.ts +19 -0
  101. package/lib/agent-clients/next-steps.ts +72 -0
  102. package/lib/agent-clients/project-assets.ts +96 -0
  103. package/lib/agent-clients/reconcile.ts +324 -0
  104. package/lib/agent-clients/registry.ts +144 -0
  105. package/lib/agent-clients/schema.ts +62 -0
  106. package/lib/agent-clients/types.ts +78 -0
  107. package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
  108. package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
  109. package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
  110. package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
  111. package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
  112. package/lib/builtin-tuis.ts +16 -15
  113. package/lib/defaults.json +24 -12
  114. package/lib/git/review-snapshot.ts +39 -9
  115. package/lib/git/reviewed-commit-equivalence.ts +135 -0
  116. package/lib/init.ts +53 -121
  117. package/lib/internal/agent-client.ts +131 -0
  118. package/lib/internal/git-workflow.ts +1 -1
  119. package/lib/internal/platform-release-notes.ts +55 -0
  120. package/lib/internal/release-workflow.ts +172 -18
  121. package/lib/internal/task-orchestration.ts +132 -0
  122. package/lib/internal/task-review.ts +65 -0
  123. package/lib/merge.ts +2 -1
  124. package/lib/platform/adapters.ts +142 -3
  125. package/lib/platform/change-request-git-evidence.ts +159 -0
  126. package/lib/platform/github-release-notes.ts +132 -0
  127. package/lib/platform/issues.ts +6 -4
  128. package/lib/platform/merged-pr-equivalence.ts +107 -0
  129. package/lib/platform/pr-checks.ts +57 -28
  130. package/lib/platform/pull-requests.ts +140 -25
  131. package/lib/platform/release-notes.ts +167 -0
  132. package/lib/platform/releases.ts +1 -1
  133. package/lib/platform/verification-required.ts +37 -9
  134. package/lib/prompt.ts +16 -3
  135. package/lib/release/channels.ts +4 -1
  136. package/lib/release/workflow.ts +4 -3
  137. package/lib/remove-dir.ts +28 -0
  138. package/lib/run/tui.ts +9 -1
  139. package/lib/sandbox/agent-client-reconciler.ts +378 -0
  140. package/lib/sandbox/build-proxy.ts +94 -0
  141. package/lib/sandbox/clipboard/linux.ts +2 -1
  142. package/lib/sandbox/commands/create.ts +188 -203
  143. package/lib/sandbox/commands/enter.ts +23 -1
  144. package/lib/sandbox/commands/prune.ts +2 -2
  145. package/lib/sandbox/commands/rebuild.ts +29 -7
  146. package/lib/sandbox/commands/rm.ts +3 -2
  147. package/lib/sandbox/config.ts +31 -4
  148. package/lib/sandbox/constants.ts +6 -0
  149. package/lib/sandbox/dockerfile.ts +2 -1
  150. package/lib/sandbox/image-build.ts +4 -1
  151. package/lib/sandbox/managed-fs.ts +18 -5
  152. package/lib/sandbox/recovery.ts +98 -67
  153. package/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  154. package/lib/sandbox/runtimes/base.dockerfile +8 -1
  155. package/lib/sandbox/runtimes/java17.dockerfile +8 -1
  156. package/lib/sandbox/runtimes/java21.dockerfile +8 -1
  157. package/lib/sandbox/runtimes/node20.dockerfile +8 -1
  158. package/lib/sandbox/runtimes/node22.dockerfile +8 -1
  159. package/lib/sandbox/runtimes/python3.dockerfile +8 -1
  160. package/lib/sandbox/shell.ts +4 -2
  161. package/lib/sandbox/tool-types.ts +143 -0
  162. package/lib/sandbox/tools.ts +5 -157
  163. package/lib/task/artifact-lifecycle.ts +1 -38
  164. package/lib/task/commands/decisions.ts +53 -20
  165. package/lib/task/commands/issue-body.ts +10 -5
  166. package/lib/task/delegation-receipts.ts +170 -0
  167. package/lib/task/events.ts +111 -3
  168. package/lib/task/issue-form.ts +4 -0
  169. package/lib/task/orchestration.ts +543 -0
  170. package/lib/task/review-artifacts.ts +201 -69
  171. package/lib/task/review-finalization.ts +275 -0
  172. package/lib/task/review-fingerprint.ts +15 -1
  173. package/lib/task/verification-checks.ts +2 -1
  174. package/lib/task/verification-engine.ts +190 -25
  175. package/lib/task/verification-review.ts +2 -0
  176. package/lib/task/verification.ts +6 -3
  177. package/lib/task/workspace-snapshot.ts +36 -0
  178. package/lib/update.ts +48 -184
  179. package/package.json +2 -2
  180. package/templates/.agents/README.en.md +21 -20
  181. package/templates/.agents/README.zh-CN.md +21 -20
  182. package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
  183. package/templates/.agents/rules/README.en.md +2 -0
  184. package/templates/.agents/rules/README.zh-CN.md +2 -0
  185. package/templates/.agents/rules/commit-and-pr.en.md +1 -0
  186. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
  187. package/templates/.agents/rules/human-decision-context.en.md +14 -12
  188. package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
  189. package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
  190. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
  191. package/templates/.agents/rules/next-step-output.en.md +16 -0
  192. package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
  193. package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
  194. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
  195. package/templates/.agents/rules/release-commands.en.md +2 -2
  196. package/templates/.agents/rules/release-commands.github.en.md +15 -39
  197. package/templates/.agents/rules/release-commands.github.zh-CN.md +14 -38
  198. package/templates/.agents/rules/release-commands.zh-CN.md +2 -2
  199. package/templates/.agents/rules/review-handshake.en.md +4 -3
  200. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -3
  201. package/templates/.agents/rules/review-method.en.md +113 -0
  202. package/templates/.agents/rules/review-method.zh-CN.md +98 -0
  203. package/templates/.agents/rules/testing-discipline.en.md +20 -2
  204. package/templates/.agents/rules/testing-discipline.zh-CN.md +20 -2
  205. package/templates/.agents/skills/analyze-task/SKILL.en.md +9 -6
  206. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +9 -6
  207. package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
  208. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
  209. package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
  210. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
  211. package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
  212. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
  213. package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
  214. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
  215. package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
  216. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
  217. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  218. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  219. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
  220. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
  221. package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
  222. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
  223. package/templates/.agents/skills/commit/SKILL.en.md +11 -1
  224. package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
  225. package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
  226. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
  227. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  228. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  229. package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
  230. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
  231. package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
  232. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
  233. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
  234. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
  235. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -38
  236. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +16 -37
  237. package/templates/.agents/skills/create-task/SKILL.en.md +15 -11
  238. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +15 -11
  239. package/templates/.agents/skills/create-task/reference/context-capture.en.md +29 -0
  240. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +29 -0
  241. package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
  242. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
  243. package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
  244. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
  245. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
  246. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
  247. package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
  248. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
  249. package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
  250. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
  251. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
  252. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
  253. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  254. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  255. package/templates/.agents/skills/release/SKILL.en.md +1 -1
  256. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
  257. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
  258. package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
  259. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
  260. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
  261. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
  262. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
  263. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
  264. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
  265. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
  266. package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
  267. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
  268. package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
  269. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
  270. package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
  271. package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
  272. package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
  273. package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
  274. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
  275. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
  276. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
  277. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
  278. package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
  279. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
  280. package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
  281. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
  282. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
  283. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
  284. package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
  285. package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
  286. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
  287. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
  288. package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
  289. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
  290. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
  291. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
  292. package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
  293. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
  294. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
  295. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
  296. package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
  297. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
  298. package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
  299. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
  300. package/templates/.agents/skills/test/SKILL.en.md +4 -4
  301. package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
  302. package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
  303. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
  304. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
  305. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
  306. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
  307. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
  308. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
  309. package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
  310. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
  311. package/templates/.agents/templates/task.en.md +18 -0
  312. package/templates/.agents/templates/task.zh-CN.md +18 -0
  313. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
  314. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
  315. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
  316. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
  317. package/templates/.claude/commands/run-task.en.md +8 -0
  318. package/templates/.claude/commands/run-task.zh-CN.md +8 -0
  319. package/templates/.claude/settings.json +24 -0
  320. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
  321. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
  322. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
  323. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
  324. package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
  325. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
  326. package/templates/.opencode/commands/run-task.en.md +11 -0
  327. package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
@@ -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',
@@ -16,8 +16,14 @@ import {
16
16
  parseImageLabels,
17
17
  parseRefreshTimestamp
18
18
  } from '../image-build.ts';
19
+ import {
20
+ assertBuildProxyCompatibility,
21
+ buildProxyFailureHint,
22
+ prepareBuildProxy,
23
+ redactBuildProxyValues
24
+ } from '../build-proxy.ts';
19
25
 
20
- const USAGE = `Usage: ai sandbox rebuild [--quiet] [--refresh]`;
26
+ const USAGE = `Usage: ai sandbox rebuild [--quiet] [--refresh] [--inherit-build-proxy|-B]`;
21
27
 
22
28
  type EngineRunFn = (engine: string, cmd: string, args: string[], opts?: { cwd?: string }) => string;
23
29
  type EngineRunSafeFn = EngineRunFn;
@@ -33,7 +39,8 @@ export function buildArgs(
33
39
  runSafeFn = runSafeEngine,
34
40
  env = process.env,
35
41
  refresh = false,
36
- lastRefresh
42
+ lastRefresh,
43
+ buildProxyArgs = []
37
44
  }: {
38
45
  engine?: string;
39
46
  runFn?: EngineRunFn;
@@ -41,6 +48,7 @@ export function buildArgs(
41
48
  env?: NodeJS.ProcessEnv;
42
49
  refresh?: boolean;
43
50
  lastRefresh?: number;
51
+ buildProxyArgs?: string[];
44
52
  } = {}
45
53
  ): string[] {
46
54
  return buildSandboxImageArgs(config, tools, dockerfilePath, imageSignature, {
@@ -49,7 +57,8 @@ export function buildArgs(
49
57
  runSafeFn,
50
58
  env,
51
59
  refresh,
52
- lastRefresh
60
+ lastRefresh,
61
+ buildProxyArgs
53
62
  });
54
63
  }
55
64
 
@@ -77,6 +86,7 @@ export async function rebuild(args: string[]): Promise<void> {
77
86
  options: {
78
87
  refresh: { type: 'boolean' },
79
88
  quiet: { type: 'boolean', short: 'q' },
89
+ 'inherit-build-proxy': { type: 'boolean', short: 'B' },
80
90
  help: { type: 'boolean', short: 'h' }
81
91
  }
82
92
  });
@@ -95,6 +105,11 @@ export async function rebuild(args: string[]): Promise<void> {
95
105
  const engine = detectEngine(config);
96
106
 
97
107
  await ensureDocker(config, undefined);
108
+ if (values['inherit-build-proxy'] && config.dockerfile) {
109
+ throw new Error('Build proxy inheritance is unavailable with a custom sandbox Dockerfile.');
110
+ }
111
+ const buildProxy = prepareBuildProxy(values['inherit-build-proxy'] ?? false, process.env, engine);
112
+ if (values['inherit-build-proxy']) assertBuildProxyCompatibility(engine);
98
113
  const lastRefresh = refresh ? Date.now() : readExistingLastRefresh(config, engine);
99
114
  p.intro(pc.cyan('Rebuilding sandbox image'));
100
115
 
@@ -105,9 +120,11 @@ export async function rebuild(args: string[]): Promise<void> {
105
120
  runEngine(engine, 'docker', buildArgs(config, tools, preparedDockerfile.path, imageSignature, {
106
121
  engine,
107
122
  refresh,
108
- lastRefresh
123
+ lastRefresh,
124
+ buildProxyArgs: buildProxy.args
109
125
  }), {
110
- cwd: config.repoRoot
126
+ cwd: config.repoRoot,
127
+ env: buildProxy.env
111
128
  });
112
129
  spinner.stop(pc.green('Sandbox image rebuilt'));
113
130
  } else {
@@ -118,13 +135,18 @@ export async function rebuild(args: string[]): Promise<void> {
118
135
  buildArgs(config, tools, preparedDockerfile.path, imageSignature, {
119
136
  engine,
120
137
  refresh,
121
- lastRefresh
138
+ lastRefresh,
139
+ buildProxyArgs: buildProxy.args
122
140
  }),
123
- { cwd: config.repoRoot }
141
+ { cwd: config.repoRoot, env: buildProxy.env }
124
142
  );
125
143
  p.log.success(pc.green('Sandbox image rebuilt'));
126
144
  }
127
145
  pruneSandboxDanglingImages(config, engine);
146
+ } catch (error) {
147
+ const message = redactBuildProxyValues(error instanceof Error ? error.message : String(error), buildProxy.redactionValues);
148
+ const hint = values['inherit-build-proxy'] ? `\n${buildProxyFailureHint(engine)}` : '';
149
+ throw new Error(`${message}${hint}`);
128
150
  } finally {
129
151
  preparedDockerfile.cleanup();
130
152
  }
@@ -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);
@@ -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
  }
@@ -44,7 +44,8 @@ export function buildSandboxImageArgs(
44
44
  runSafeFn = runSafeEngine,
45
45
  env = process.env,
46
46
  refresh = false,
47
- lastRefresh
47
+ lastRefresh,
48
+ buildProxyArgs = []
48
49
  }: {
49
50
  engine?: string;
50
51
  runFn?: EngineRunFn;
@@ -52,6 +53,7 @@ export function buildSandboxImageArgs(
52
53
  env?: NodeJS.ProcessEnv;
53
54
  refresh?: boolean;
54
55
  lastRefresh?: number;
56
+ buildProxyArgs?: string[];
55
57
  } = {}
56
58
  ): string[] {
57
59
  const selectedEngine = engine ?? detectEngine({ engine: config.engine });
@@ -79,6 +81,7 @@ export function buildSandboxImageArgs(
79
81
  '--label',
80
82
  `${sandboxImageConfigLabel(config)}=${imageSignature}`
81
83
  ];
84
+ args.push(...buildProxyArgs);
82
85
 
83
86
  if (lastRefresh !== undefined) {
84
87
  args.push('--label', `${sandboxImageRefreshLabel(config)}=${lastRefresh}`);
@@ -1,6 +1,6 @@
1
- import fs from 'node:fs';
2
1
  import path from 'node:path';
3
- import { run } from './shell.ts';
2
+ import { run, runSafe } from './shell.ts';
3
+ import { removeDirRecursive } from '../remove-dir.ts';
4
4
 
5
5
  export function assertManagedPath(root: string, target: string): void {
6
6
  const resolvedRoot = path.resolve(root);
@@ -15,13 +15,26 @@ export function assertManagedPath(root: string, target: string): void {
15
15
 
16
16
  export function removeManagedDir(root: string, dir: string): void {
17
17
  assertManagedPath(root, dir);
18
- fs.rmSync(dir, { recursive: true, force: true });
18
+ removeDirRecursive(dir);
19
19
  }
20
20
 
21
- export function removeWorktreeDir(repoRoot: string, worktreeBase: string, dir: string): void {
21
+ export function removeWorktreeDir(
22
+ repoRoot: string,
23
+ worktreeBase: string,
24
+ dir: string,
25
+ { runFn = run, runSafeFn = runSafe }: {
26
+ runFn?: typeof run;
27
+ runSafeFn?: typeof runSafe;
28
+ } = {}
29
+ ): void {
22
30
  try {
23
- run('git', ['-C', repoRoot, 'worktree', 'remove', dir, '--force']);
31
+ runFn('git', ['-C', repoRoot, 'worktree', 'remove', dir, '--force']);
24
32
  } catch {
33
+ // On WSL2 the worktree is registered under its `/mnt/<drive>/...` path, so
34
+ // `git worktree remove <windows-path>` cannot match it. Delete the managed
35
+ // directory directly, then prune the now-dangling worktree metadata so the
36
+ // branch is no longer reported as checked out.
25
37
  removeManagedDir(worktreeBase, dir);
38
+ runSafeFn('git', ['-C', repoRoot, 'worktree', 'prune']);
26
39
  }
27
40
  }
@@ -1,6 +1,19 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { containerNameCandidates, sandboxBranchLabel, sandboxLabel } from './constants.ts';
3
+ import {
4
+ containerNameCandidates,
5
+ sandboxBranchLabel,
6
+ sandboxLabel,
7
+ sandboxRuntimeCapabilityLabel
8
+ } from './constants.ts';
9
+ import { isAgentClientId } from '../agent-clients/types.ts';
10
+ import {
11
+ createSandboxCapabilityPlan
12
+ } from './agent-client-reconciler.ts';
13
+ import type {
14
+ SandboxRecoveryFindingDescriptor,
15
+ SandboxRecoveryRepair
16
+ } from './tool-types.ts';
4
17
  import type { SandboxConfig } from './config.ts';
5
18
  import { toEnginePath } from './engines/wsl2-paths.ts';
6
19
  import { sandboxCoreBindMounts } from './mounts.ts';
@@ -9,6 +22,7 @@ import {
9
22
  declaredTmpfsSeedEntries,
10
23
  resolveTools,
11
24
  toolConfigDirCandidates,
25
+ type SandboxTool,
12
26
  type TmpfsSeedEntry
13
27
  } from './tools.ts';
14
28
  import {
@@ -23,10 +37,22 @@ export type SandboxRecoveryFinding = {
23
37
  message: string;
24
38
  path?: string;
25
39
  seed?: TmpfsSeedEntry;
40
+ repair?: SandboxRecoveryRepair;
41
+ };
42
+
43
+ type SandboxAgentClientCheckSnapshot = {
44
+ adapterId: string;
45
+ checkId: string;
46
+ applicable: boolean;
47
+ healthy: boolean;
48
+ finding: SandboxRecoveryFindingDescriptor;
49
+ repair?: SandboxRecoveryRepair;
26
50
  };
27
51
 
28
52
  export type SandboxRecoverySnapshot = {
29
53
  identityOk: boolean;
54
+ runtimeCapabilityOk?: boolean;
55
+ unexpectedCapabilityMounts?: string[];
30
56
  mounts: Array<{
31
57
  path: string;
32
58
  expectedType: string;
@@ -48,12 +74,7 @@ export type SandboxRecoverySnapshot = {
48
74
  targetState: 'ok' | 'missing' | 'wrong-type' | 'inaccessible';
49
75
  }>;
50
76
  aliasesReadable: boolean;
51
- codex?: {
52
- commandAvailable: boolean;
53
- stateWritable: boolean;
54
- promptsSourceExists: boolean;
55
- promptsValid: boolean;
56
- };
77
+ agentClientChecks: SandboxAgentClientCheckSnapshot[];
57
78
  };
58
79
 
59
80
  export type SandboxReadyResult = {
@@ -114,6 +135,19 @@ export function classifySandboxRecovery(snapshot: SandboxRecoverySnapshot): Sand
114
135
  message: 'Container identity does not match the requested sandbox branch.'
115
136
  });
116
137
  }
138
+ if (snapshot.runtimeCapabilityOk === false) {
139
+ findings.push({
140
+ repairKind: 'hard-failure',
141
+ message: 'Container runtime capability signature does not match the current sandbox plan.'
142
+ });
143
+ }
144
+ for (const mountPath of snapshot.unexpectedCapabilityMounts ?? []) {
145
+ findings.push({
146
+ repairKind: 'hard-failure',
147
+ message: `Disabled Agent Client capability remains mounted at ${mountPath}.`,
148
+ path: mountPath
149
+ });
150
+ }
117
151
 
118
152
  for (const mount of snapshot.mounts) {
119
153
  if (
@@ -177,25 +211,11 @@ export function classifySandboxRecovery(snapshot: SandboxRecoverySnapshot): Sand
177
211
  });
178
212
  }
179
213
 
180
- if (snapshot.codex) {
181
- if (!snapshot.codex.commandAvailable) {
214
+ for (const check of snapshot.agentClientChecks) {
215
+ if (check.applicable && !check.healthy) {
182
216
  findings.push({
183
- repairKind: 'hard-failure',
184
- message: 'Codex is not available on PATH inside the sandbox.'
185
- });
186
- }
187
- if (!snapshot.codex.stateWritable) {
188
- findings.push({
189
- repairKind: 'permissions',
190
- message: 'Codex state directory is not writable by devuser.',
191
- path: '/home/devuser/.codex'
192
- });
193
- }
194
- if (snapshot.codex.promptsSourceExists && !snapshot.codex.promptsValid) {
195
- findings.push({
196
- repairKind: 'builtin-link',
197
- message: 'Codex prompts link does not point to the workspace commands directory.',
198
- path: '/home/devuser/.codex/prompts'
217
+ ...check.finding,
218
+ ...(check.repair === undefined ? {} : { repair: check.repair })
199
219
  });
200
220
  }
201
221
  }
@@ -277,11 +297,10 @@ function hostSourceAccessible(hostPath: string, writable: boolean): boolean {
277
297
  function expectedMounts(params: {
278
298
  config: SandboxConfig;
279
299
  branch: string;
280
- engine: string;
300
+ tools: readonly SandboxTool[];
281
301
  actualMounts: Map<string, DockerMount>;
282
302
  }): ExpectedMount[] {
283
- const { config, branch, actualMounts } = params;
284
- const tools = resolveTools(config);
303
+ const { config, branch, tools, actualMounts } = params;
285
304
  const core = sandboxCoreBindMounts(config, branch).map((mount) => ({
286
305
  path: mount.containerPath,
287
306
  expectedType: 'bind' as const,
@@ -301,7 +320,13 @@ function expectedMounts(params: {
301
320
  })
302
321
  );
303
322
  const persistentTools = tools
304
- .filter((tool) => !tool.tmpfs && actualMounts.has(tool.containerMount))
323
+ .filter((tool) =>
324
+ !tool.tmpfs
325
+ && (
326
+ config.agentClientSource === 'canonical'
327
+ || actualMounts.has(tool.containerMount)
328
+ )
329
+ )
305
330
  .map((tool) => ({
306
331
  path: tool.containerMount,
307
332
  expectedType: 'bind' as const,
@@ -401,7 +426,8 @@ export function collectSandboxRecoverySnapshot(params: {
401
426
  });
402
427
  }
403
428
  }
404
- const tools = resolveTools(params.config);
429
+ const capabilityPlan = createSandboxCapabilityPlan(params.config);
430
+ const tools = [...capabilityPlan.tools];
405
431
  const seeds = declaredTmpfsSeedEntries(tools).map((seed) => {
406
432
  const mounted = mountsByDestination.get(seed.stagingPath)?.Type === 'bind';
407
433
  return {
@@ -434,11 +460,18 @@ export function collectSandboxRecoverySnapshot(params: {
434
460
  }));
435
461
  const labels = inspection.Config?.Labels ?? {};
436
462
  const branchLabel = labels[sandboxBranchLabel(params.config)];
437
- const hasCodex = tools.some((tool) => tool.id === 'codex');
463
+ const selectedToolIds = new Set(tools.map((tool) => tool.id));
464
+ const enforceCanonicalPlan = params.config.agentClientSource === 'canonical';
465
+ const unexpectedCapabilityMounts = enforceCanonicalPlan
466
+ ? capabilityPlan.cleanupInventory
467
+ .filter((tool) => isAgentClientId(tool.id) && !selectedToolIds.has(tool.id))
468
+ .map((tool) => tool.containerMount)
469
+ .filter((mountPath) => mountsByDestination.has(mountPath))
470
+ : [];
438
471
  const mountSnapshots = expectedMounts({
439
472
  config: params.config,
440
473
  branch: params.branch,
441
- engine: params.engine,
474
+ tools,
442
475
  actualMounts: mountsByDestination
443
476
  }).map((expected) => {
444
477
  const actual = mountsByDestination.get(expected.path);
@@ -478,6 +511,10 @@ export function collectSandboxRecoverySnapshot(params: {
478
511
  identityOk: typeof inspection.Id === 'string'
479
512
  && inspection.Id.length > 0
480
513
  && branchLabel === params.branch,
514
+ runtimeCapabilityOk: enforceCanonicalPlan
515
+ ? labels[sandboxRuntimeCapabilityLabel(params.config)] === capabilityPlan.runtimeSignature
516
+ : undefined,
517
+ unexpectedCapabilityMounts,
481
518
  mounts: mountSnapshots,
482
519
  tmpfs,
483
520
  seeds,
@@ -488,38 +525,31 @@ export function collectSandboxRecoverySnapshot(params: {
488
525
  ['/home/devuser/.bash_aliases'],
489
526
  runOkFn
490
527
  ),
491
- codex: hasCodex
492
- ? {
493
- commandAvailable: probe(
494
- params.engine,
495
- params.container,
496
- 'command -v codex',
497
- [],
498
- runOkFn
499
- ),
500
- stateWritable: probe(
501
- params.engine,
502
- params.container,
503
- 'probe="$1/.agent-infra-codex-state-$$"; trap \'rm -f -- "$probe"\' EXIT; : > "$probe"',
504
- ['/home/devuser/.codex'],
505
- runOkFn
506
- ),
507
- promptsSourceExists: probe(
508
- params.engine,
509
- params.container,
510
- 'test -d "$1"',
511
- ['/workspace/.codex/commands'],
512
- runOkFn
513
- ),
514
- promptsValid: probe(
515
- params.engine,
516
- params.container,
517
- 'test "$(readlink -- "$1")" = "$2"',
518
- ['/home/devuser/.codex/prompts', '/workspace/.codex/commands'],
519
- runOkFn
520
- )
521
- }
522
- : undefined
528
+ agentClientChecks: capabilityPlan.recoveryChecks.map(({ adapterId, check }) => {
529
+ const applicable = check.when === undefined || probe(
530
+ params.engine,
531
+ params.container,
532
+ check.when.script,
533
+ [...check.when.args],
534
+ runOkFn,
535
+ check.when.user
536
+ );
537
+ return {
538
+ adapterId,
539
+ checkId: check.id,
540
+ applicable,
541
+ healthy: !applicable || probe(
542
+ params.engine,
543
+ params.container,
544
+ check.probe.script,
545
+ [...check.probe.args],
546
+ runOkFn,
547
+ check.probe.user
548
+ ),
549
+ finding: check.finding,
550
+ ...(check.repair === undefined ? {} : { repair: check.repair })
551
+ };
552
+ })
523
553
  };
524
554
  }
525
555
 
@@ -626,10 +656,11 @@ function repairFindings(params: {
626
656
  deps: params.deps
627
657
  });
628
658
  const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
629
- if (params.findings.some((finding) => finding.repairKind === 'builtin-link')) {
659
+ for (const repair of params.findings.flatMap((finding) =>
660
+ finding.repair === undefined ? [] : [finding.repair]
661
+ )) {
630
662
  runVerboseFn(params.engine, 'docker', [
631
- 'exec', '--user', 'devuser', params.container, 'ln', '-sfn',
632
- '/workspace/.codex/commands', '/home/devuser/.codex/prompts'
663
+ 'exec', '--user', repair.user, params.container, repair.command, ...repair.args
633
664
  ]);
634
665
  }
635
666
  }
@@ -5,20 +5,41 @@ ENV NPM_CONFIG_PREFIX=/home/devuser/.npm-global
5
5
  ENV PATH="/home/devuser/.npm-global/bin:${PATH}"
6
6
 
7
7
  ARG AI_TOOL_PACKAGES=
8
- RUN set -e && \
8
+ RUN --mount=type=secret,id=HTTP_PROXY \
9
+ --mount=type=secret,id=HTTPS_PROXY \
10
+ --mount=type=secret,id=NO_PROXY \
11
+ export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
12
+ export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
13
+ export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
14
+ export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
15
+ set -e && \
9
16
  for pkg in ${AI_TOOL_PACKAGES}; do \
10
17
  npm install -g "$pkg"; \
11
18
  done
12
19
 
13
20
  ARG AI_TOOLS_SHELL_INSTALL_B64=
14
- RUN if [ -n "${AI_TOOLS_SHELL_INSTALL_B64}" ]; then \
21
+ RUN --mount=type=secret,id=HTTP_PROXY \
22
+ --mount=type=secret,id=HTTPS_PROXY \
23
+ --mount=type=secret,id=NO_PROXY \
24
+ export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
25
+ export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
26
+ export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
27
+ export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
28
+ if [ -n "${AI_TOOLS_SHELL_INSTALL_B64}" ]; then \
15
29
  set -e && \
16
30
  echo "${AI_TOOLS_SHELL_INSTALL_B64}" | base64 -d > /tmp/ai-tools-install.sh && \
17
31
  bash /tmp/ai-tools-install.sh && \
18
32
  rm /tmp/ai-tools-install.sh; \
19
33
  fi
20
34
 
21
- RUN npm install -g pyright
35
+ RUN --mount=type=secret,id=HTTP_PROXY \
36
+ --mount=type=secret,id=HTTPS_PROXY \
37
+ --mount=type=secret,id=NO_PROXY \
38
+ export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
39
+ export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
40
+ export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
41
+ export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
42
+ npm install -g pyright
22
43
 
23
44
  RUN mkdir -p /home/devuser/.local/share /home/devuser/.local/state
24
45
 
@@ -19,7 +19,14 @@ RUN if [ "${HOST_UID}" = "0" ]; then \
19
19
  useradd -u ${HOST_UID} -g ${HOST_GID} -m -s /bin/bash devuser; \
20
20
  fi
21
21
 
22
- RUN apt-get update && apt-get install -y \
22
+ RUN --mount=type=secret,id=HTTP_PROXY \
23
+ --mount=type=secret,id=HTTPS_PROXY \
24
+ --mount=type=secret,id=NO_PROXY \
25
+ export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
26
+ export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
27
+ export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
28
+ export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
29
+ apt-get update && apt-get install -y \
23
30
  curl wget git vim file jq \
24
31
  build-essential ca-certificates gnupg lsb-release \
25
32
  libevent-core-2.1-7 libncursesw6 libtinfo6 \
@@ -1,3 +1,10 @@
1
- RUN apt-get update && apt-get install -y \
1
+ RUN --mount=type=secret,id=HTTP_PROXY \
2
+ --mount=type=secret,id=HTTPS_PROXY \
3
+ --mount=type=secret,id=NO_PROXY \
4
+ export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
5
+ export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
6
+ export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
7
+ export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
8
+ apt-get update && apt-get install -y \
2
9
  openjdk-17-jdk maven \
3
10
  && rm -rf /var/lib/apt/lists/*
@@ -1,3 +1,10 @@
1
- RUN apt-get update && apt-get install -y \
1
+ RUN --mount=type=secret,id=HTTP_PROXY \
2
+ --mount=type=secret,id=HTTPS_PROXY \
3
+ --mount=type=secret,id=NO_PROXY \
4
+ export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
5
+ export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
6
+ export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
7
+ export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
8
+ apt-get update && apt-get install -y \
2
9
  openjdk-21-jdk maven \
3
10
  && rm -rf /var/lib/apt/lists/*