@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
@@ -0,0 +1,378 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { execFile } from 'node:child_process';
3
+ import { isAgentClientId } from '../agent-clients/types.ts';
4
+ import {
5
+ listAgentClientAdapters,
6
+ listInstalledAgentClientAdapters
7
+ } from '../agent-clients/registry.ts';
8
+ import { hostJoin } from './engines/wsl2-paths.ts';
9
+ import type { AgentClientAdapter } from '../agent-clients/adapter.ts';
10
+ import type { AgentClientState } from '../agent-clients/types.ts';
11
+ import type {
12
+ AgentClientSandboxRecoveryCheck,
13
+ AgentClientSandboxHook,
14
+ AgentClientSandboxHookContext,
15
+ AgentClientSandboxHookResult,
16
+ SandboxAlias,
17
+ SandboxHookCommand,
18
+ SandboxHookCommandResult,
19
+ SandboxHookPhase,
20
+ SandboxHookStatus,
21
+ SandboxTool
22
+ } from './tool-types.ts';
23
+
24
+ const DEFAULT_SANDBOX_HOOK_TIMEOUT_MS = 30_000;
25
+
26
+ type SandboxCapabilityConfig = Readonly<{
27
+ home: string;
28
+ project: string;
29
+ tools: readonly string[];
30
+ customTools?: readonly SandboxTool[];
31
+ agentClientState?: AgentClientState;
32
+ }>;
33
+
34
+ type SandboxRuntimeCapabilityProjection = Readonly<{
35
+ tools: readonly Readonly<Record<string, unknown>>[];
36
+ selectedAgentClients: readonly string[];
37
+ hooks: readonly Readonly<{
38
+ adapterId: string;
39
+ id: string;
40
+ phase: SandboxHookPhase;
41
+ timeoutMs: number;
42
+ }>[];
43
+ recoveryChecks: readonly Readonly<{
44
+ adapterId: string;
45
+ id: string;
46
+ when?: AgentClientSandboxRecoveryCheck['when'];
47
+ probe: AgentClientSandboxRecoveryCheck['probe'];
48
+ finding: Readonly<{
49
+ repairKind: AgentClientSandboxRecoveryCheck['finding']['repairKind'];
50
+ path?: string;
51
+ }>;
52
+ repair?: AgentClientSandboxRecoveryCheck['repair'];
53
+ }>[];
54
+ }>;
55
+
56
+ type PlannedAgentClientRecoveryCheck = Readonly<{
57
+ adapterId: string;
58
+ check: AgentClientSandboxRecoveryCheck;
59
+ }>;
60
+
61
+ type SandboxCapabilityPlan = Readonly<{
62
+ tools: readonly SandboxTool[];
63
+ selectedAgentClients: readonly AgentClientAdapter[];
64
+ hooksByPhase: Readonly<Record<SandboxHookPhase, readonly AgentClientSandboxHook[]>>;
65
+ recoveryChecks: readonly PlannedAgentClientRecoveryCheck[];
66
+ aliases: readonly SandboxAlias[];
67
+ imageSignature: string;
68
+ runtimeSignature: string;
69
+ runtimeProjection: SandboxRuntimeCapabilityProjection;
70
+ cleanupInventory: readonly SandboxTool[];
71
+ }>;
72
+
73
+ type HookExecutionResult = Readonly<{
74
+ hookId: string;
75
+ phase: SandboxHookPhase;
76
+ status: SandboxHookStatus;
77
+ message?: string;
78
+ }>;
79
+
80
+ type TimerHandle = ReturnType<typeof setTimeout> | unknown;
81
+
82
+ function agentInfraTool(home: string): SandboxTool {
83
+ return {
84
+ id: 'agent-infra',
85
+ name: 'agent-infra CLI',
86
+ install: { type: 'npm', cmd: '@fitlab-ai/agent-infra@latest' },
87
+ sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'agent-infra'),
88
+ containerMount: '/home/devuser/.agent-infra-cli',
89
+ versionCmd: 'ai version --raw',
90
+ setupHint: 'Provides the ai and agent-infra CLI commands inside the sandbox.'
91
+ };
92
+ }
93
+
94
+ function compatAgentClientState(tools: readonly string[]): AgentClientState {
95
+ return Object.fromEntries(
96
+ listAgentClientAdapters().map((adapter) => [
97
+ adapter.id,
98
+ {
99
+ enabled: true,
100
+ installInSandbox: tools.includes(adapter.id)
101
+ }
102
+ ])
103
+ ) as AgentClientState;
104
+ }
105
+
106
+ function stableValue(value: unknown): unknown {
107
+ if (Array.isArray(value)) {
108
+ return value.map(stableValue);
109
+ }
110
+ if (value && typeof value === 'object') {
111
+ return Object.fromEntries(
112
+ Object.entries(value as Record<string, unknown>)
113
+ .sort(([left], [right]) => left.localeCompare(right))
114
+ .map(([key, nested]) => [key, stableValue(nested)])
115
+ );
116
+ }
117
+ return value;
118
+ }
119
+
120
+ function runtimeToolProjection(tool: SandboxTool): Readonly<Record<string, unknown>> {
121
+ return stableValue({
122
+ id: tool.id,
123
+ install: tool.install,
124
+ containerMount: tool.containerMount,
125
+ versionCmd: tool.versionCmd,
126
+ envVars: tool.envVars ?? {},
127
+ hostPreSeedFiles: (tool.hostPreSeedFiles ?? []).map(({ sandboxName }) => ({ sandboxName })),
128
+ hostPreSeedDirs: (tool.hostPreSeedDirs ?? []).map(({ sandboxSubdir }) => ({ sandboxSubdir })),
129
+ pathRewriteFiles: tool.pathRewriteFiles ?? [],
130
+ hostLiveMounts: (tool.hostLiveMounts ?? []).map(({ containerSubpath }) => ({ containerSubpath })),
131
+ postSetupCmds: tool.postSetupCmds ?? [],
132
+ tmpfs: tool.tmpfs ?? null
133
+ }) as Readonly<Record<string, unknown>>;
134
+ }
135
+
136
+ function hash(value: unknown): string {
137
+ return createHash('sha256').update(JSON.stringify(stableValue(value))).digest('hex');
138
+ }
139
+
140
+ function assertUniqueTools(tools: readonly SandboxTool[]): void {
141
+ const seen = new Set<string>();
142
+ for (const tool of tools) {
143
+ if (seen.has(tool.id)) {
144
+ throw new Error(`Duplicate sandbox tool id "${tool.id}"`);
145
+ }
146
+ seen.add(tool.id);
147
+ }
148
+ }
149
+
150
+ function hooksByPhase(
151
+ adapters: readonly AgentClientAdapter[]
152
+ ): SandboxCapabilityPlan['hooksByPhase'] {
153
+ const phases: SandboxHookPhase[] = [
154
+ 'prepare',
155
+ 'before-container-create',
156
+ 'after-container-start',
157
+ 'before-enter'
158
+ ];
159
+ return Object.freeze(Object.fromEntries(
160
+ phases.map((phase) => [
161
+ phase,
162
+ Object.freeze(adapters.flatMap((adapter) =>
163
+ adapter.sandbox.hooks.filter((hook) => hook.phase === phase)
164
+ ))
165
+ ])
166
+ ) as Record<SandboxHookPhase, readonly AgentClientSandboxHook[]>);
167
+ }
168
+
169
+ function createSandboxCapabilityPlan(
170
+ config: SandboxCapabilityConfig
171
+ ): SandboxCapabilityPlan {
172
+ const state = config.agentClientState ?? compatAgentClientState(config.tools);
173
+ const selectedAgentClients = listInstalledAgentClientAdapters(state);
174
+ const context = { home: config.home, project: config.project };
175
+ const selectedTools = selectedAgentClients.map((adapter) =>
176
+ adapter.sandbox.createTool(context)
177
+ );
178
+ const allClientTools = listAgentClientAdapters().map((adapter) =>
179
+ adapter.sandbox.createTool(context)
180
+ );
181
+ const customById = new Map((config.customTools ?? []).map((tool) => [tool.id, tool]));
182
+ if (customById.size !== (config.customTools ?? []).length) {
183
+ throw new Error('Duplicate sandbox tool id in customTools');
184
+ }
185
+ for (const id of customById.keys()) {
186
+ if (id === 'agent-infra' || isAgentClientId(id)) {
187
+ throw new Error(`Custom sandbox tool id "${id}" collides with a built-in tool`);
188
+ }
189
+ }
190
+
191
+ const nonClientTools: SandboxTool[] = [];
192
+ const selectedCustomTools: SandboxTool[] = [];
193
+ for (const id of config.tools) {
194
+ if (isAgentClientId(id)) continue;
195
+ if (id === 'agent-infra') {
196
+ if (!nonClientTools.some((tool) => tool.id === id)) {
197
+ nonClientTools.push(agentInfraTool(config.home));
198
+ }
199
+ continue;
200
+ }
201
+ const custom = customById.get(id);
202
+ if (!custom) {
203
+ throw new Error(`Unknown sandbox tool: ${id}`);
204
+ }
205
+ selectedCustomTools.push(custom);
206
+ }
207
+
208
+ const tools = Object.freeze([...nonClientTools, ...selectedTools, ...selectedCustomTools]);
209
+ assertUniqueTools(tools);
210
+ const phaseHooks = hooksByPhase(selectedAgentClients);
211
+ const hookProjection = selectedAgentClients.flatMap((adapter) =>
212
+ adapter.sandbox.hooks.map((hook) => ({
213
+ adapterId: adapter.id,
214
+ id: hook.id,
215
+ phase: hook.phase,
216
+ timeoutMs: hook.timeoutMs ?? DEFAULT_SANDBOX_HOOK_TIMEOUT_MS
217
+ }))
218
+ );
219
+ const recoveryChecks = Object.freeze(selectedAgentClients.flatMap((adapter) =>
220
+ (adapter.sandbox.recoveryChecks ?? []).map((check) => Object.freeze({
221
+ adapterId: adapter.id,
222
+ check
223
+ }))
224
+ ));
225
+ const recoveryCheckProjection = Object.freeze(recoveryChecks.map(({ adapterId, check }) =>
226
+ Object.freeze({
227
+ adapterId,
228
+ id: check.id,
229
+ ...(check.when === undefined ? {} : { when: check.when }),
230
+ probe: check.probe,
231
+ finding: Object.freeze({
232
+ repairKind: check.finding.repairKind,
233
+ ...(check.finding.path === undefined ? {} : { path: check.finding.path })
234
+ }),
235
+ ...(check.repair === undefined ? {} : { repair: check.repair })
236
+ })
237
+ ));
238
+ const runtimeProjection = Object.freeze({
239
+ tools: Object.freeze(tools.map(runtimeToolProjection)),
240
+ selectedAgentClients: Object.freeze(selectedAgentClients.map((adapter) => adapter.id)),
241
+ hooks: Object.freeze(hookProjection),
242
+ recoveryChecks: recoveryCheckProjection
243
+ });
244
+ const cleanupInventory = Object.freeze([
245
+ agentInfraTool(config.home),
246
+ ...allClientTools,
247
+ ...customById.values()
248
+ ]);
249
+ assertUniqueTools(cleanupInventory);
250
+
251
+ return Object.freeze({
252
+ tools,
253
+ selectedAgentClients,
254
+ hooksByPhase: phaseHooks,
255
+ recoveryChecks,
256
+ aliases: Object.freeze(
257
+ listAgentClientAdapters().flatMap((adapter) => adapter.sandbox.aliases)
258
+ ),
259
+ imageSignature: hash(tools.map(({ id, install }) => ({ id, install }))),
260
+ runtimeSignature: hash(runtimeProjection),
261
+ runtimeProjection,
262
+ cleanupInventory
263
+ });
264
+ }
265
+
266
+ function timeoutStatus(phase: SandboxHookPhase): SandboxHookStatus {
267
+ if (phase === 'before-enter') return 'warning';
268
+ return 'fatal';
269
+ }
270
+
271
+ async function runSandboxHooks({
272
+ hooks,
273
+ phase,
274
+ context,
275
+ runCommand = async () => {
276
+ throw new Error('Sandbox hook command runner is unavailable');
277
+ },
278
+ scheduleTimeout = (callback, timeoutMs) => setTimeout(callback, timeoutMs),
279
+ clearScheduledTimeout = (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>)
280
+ }: {
281
+ hooks: readonly AgentClientSandboxHook[];
282
+ phase: SandboxHookPhase;
283
+ context: Omit<AgentClientSandboxHookContext, 'signal' | 'runCommand'>;
284
+ runCommand?: (
285
+ command: SandboxHookCommand,
286
+ options: { signal: AbortSignal; timeoutMs: number }
287
+ ) => Promise<SandboxHookCommandResult>;
288
+ scheduleTimeout?: (callback: () => void, timeoutMs: number) => TimerHandle;
289
+ clearScheduledTimeout?: (handle: TimerHandle) => void;
290
+ }): Promise<HookExecutionResult[]> {
291
+ const results: HookExecutionResult[] = [];
292
+ for (const hook of hooks) {
293
+ if (hook.phase !== phase) continue;
294
+ const timeoutMs = hook.timeoutMs ?? DEFAULT_SANDBOX_HOOK_TIMEOUT_MS;
295
+ const controller = new AbortController();
296
+ let timedOut = false;
297
+ let timer: TimerHandle;
298
+ const timeout = new Promise<AgentClientSandboxHookResult>((resolve) => {
299
+ timer = scheduleTimeout(() => {
300
+ timedOut = true;
301
+ controller.abort();
302
+ resolve({
303
+ status: timeoutStatus(phase),
304
+ message: `Sandbox hook '${hook.id}' timed out after ${timeoutMs}ms.`
305
+ });
306
+ }, timeoutMs);
307
+ });
308
+ let result: AgentClientSandboxHookResult;
309
+ try {
310
+ const execution = Promise.resolve().then(() => hook.run({
311
+ ...context,
312
+ signal: controller.signal,
313
+ runCommand: (command) => runCommand(command, {
314
+ signal: controller.signal,
315
+ timeoutMs
316
+ })
317
+ }));
318
+ result = await Promise.race([execution, timeout]);
319
+ } catch (error) {
320
+ result = {
321
+ status: timeoutStatus(phase),
322
+ message: error instanceof Error ? error.message : String(error)
323
+ };
324
+ } finally {
325
+ clearScheduledTimeout(timer!);
326
+ }
327
+ results.push({
328
+ hookId: hook.id,
329
+ phase,
330
+ status: result.status,
331
+ ...(result.message ? { message: result.message } : {})
332
+ });
333
+ if (timedOut || result.status === 'fatal' || result.status === 'hard-failure') {
334
+ break;
335
+ }
336
+ }
337
+ return results;
338
+ }
339
+
340
+ function runBoundedSandboxHookCommand(
341
+ command: SandboxHookCommand,
342
+ options: { signal: AbortSignal; timeoutMs: number }
343
+ ): Promise<SandboxHookCommandResult> {
344
+ return new Promise((resolve, reject) => {
345
+ execFile(
346
+ command.command,
347
+ [...(command.args ?? [])],
348
+ {
349
+ cwd: command.cwd,
350
+ env: command.env,
351
+ encoding: 'utf8',
352
+ signal: options.signal,
353
+ timeout: options.timeoutMs
354
+ },
355
+ (error, stdout) => {
356
+ if (error) {
357
+ reject(error);
358
+ return;
359
+ }
360
+ resolve({ stdout: stdout.trim() });
361
+ }
362
+ );
363
+ });
364
+ }
365
+
366
+ export {
367
+ DEFAULT_SANDBOX_HOOK_TIMEOUT_MS,
368
+ createSandboxCapabilityPlan,
369
+ runBoundedSandboxHookCommand,
370
+ runSandboxHooks
371
+ };
372
+ export type {
373
+ HookExecutionResult,
374
+ SandboxCapabilityConfig,
375
+ SandboxCapabilityPlan,
376
+ PlannedAgentClientRecoveryCheck,
377
+ SandboxRuntimeCapabilityProjection
378
+ };
@@ -0,0 +1,94 @@
1
+ import semver from 'semver';
2
+ import { engineDisplayName } from './engine.ts';
3
+ import { runSafeEngine } from './shell.ts';
4
+
5
+ export const BUILD_PROXY_ENV_KEYS = ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY'] as const;
6
+ export const MIN_BUILD_PROXY_DOCKER_VERSION = '20.10.0';
7
+ export const MIN_BUILD_PROXY_BUILDKIT_VERSION = '0.9.0';
8
+
9
+ export type BuildProxyPlan = {
10
+ args: string[];
11
+ env: NodeJS.ProcessEnv;
12
+ redactionValues: string[];
13
+ };
14
+
15
+ type EngineRunSafeFn = (engine: string, cmd: string, args: string[]) => string;
16
+
17
+ export function prepareBuildProxy(
18
+ enabled: boolean,
19
+ hostEnv: NodeJS.ProcessEnv,
20
+ engine: string
21
+ ): BuildProxyPlan {
22
+ const env = { ...hostEnv };
23
+ if (!enabled) {
24
+ return { args: [], env, redactionValues: [] };
25
+ }
26
+
27
+ const entries = BUILD_PROXY_ENV_KEYS.flatMap((key) => {
28
+ const value = hostEnv[key]?.trim();
29
+ return value ? [[key, value] as const] : [];
30
+ });
31
+ if (entries.length === 0) {
32
+ throw new Error(
33
+ `No non-empty build proxy variables are set. Configure one of: ${BUILD_PROXY_ENV_KEYS.join(', ')}.`
34
+ );
35
+ }
36
+
37
+ for (const [key, value] of entries) env[key] = value;
38
+ if (engine === 'wsl2') {
39
+ const existing = (env.WSLENV ?? '').split(':').filter(Boolean);
40
+ env.WSLENV = [...new Set([...existing, ...entries.map(([key]) => key)])].join(':');
41
+ }
42
+
43
+ return {
44
+ args: entries.flatMap(([key]) => ['--secret', `id=${key},env=${key}`]),
45
+ env,
46
+ redactionValues: entries.map(([, value]) => value)
47
+ };
48
+ }
49
+
50
+ function parsedVersion(raw: string): string | null {
51
+ return semver.coerce(raw.trim())?.version ?? null;
52
+ }
53
+
54
+ export function assertBuildProxyCompatibility(
55
+ engine: string,
56
+ runSafeEngineFn: EngineRunSafeFn = runSafeEngine
57
+ ): void {
58
+ const dockerRaw = runSafeEngineFn(engine, 'docker', ['version', '--format', '{{.Server.Version}}']);
59
+ const dockerVersion = parsedVersion(dockerRaw);
60
+ if (!dockerVersion || !semver.gte(dockerVersion, MIN_BUILD_PROXY_DOCKER_VERSION)) {
61
+ throw new Error(
62
+ `Build proxy requires Docker Engine ${MIN_BUILD_PROXY_DOCKER_VERSION} or newer; `
63
+ + `observed ${dockerVersion ?? 'an unparseable version'}.`
64
+ );
65
+ }
66
+
67
+ const buildxRaw = runSafeEngineFn(engine, 'docker', ['buildx', 'inspect', '--bootstrap']);
68
+ const versions = [...buildxRaw.matchAll(/BuildKit(?:\s+version)?:\s*v?(\d+\.\d+\.\d+(?:[-+][^\s]+)?)/gi)]
69
+ .map((match) => parsedVersion(match[1] ?? ''))
70
+ .filter((version): version is string => version !== null);
71
+ if (versions.length === 0) {
72
+ throw new Error(
73
+ `Build proxy requires BuildKit ${MIN_BUILD_PROXY_BUILDKIT_VERSION} or newer, `
74
+ + 'but the active builder version could not be determined.'
75
+ );
76
+ }
77
+ const oldVersion = versions.find((version) => !semver.gte(version, MIN_BUILD_PROXY_BUILDKIT_VERSION));
78
+ if (oldVersion) {
79
+ throw new Error(
80
+ `Build proxy observed BuildKit ${oldVersion}; version ${MIN_BUILD_PROXY_BUILDKIT_VERSION} or newer is required.`
81
+ );
82
+ }
83
+ }
84
+
85
+ export function redactBuildProxyValues(text: string, values: readonly string[]): string {
86
+ return [...new Set(values.filter(Boolean))]
87
+ .sort((left, right) => right.length - left.length)
88
+ .reduce((result, value) => result.replaceAll(value, '[REDACTED_BUILD_PROXY]'), text);
89
+ }
90
+
91
+ export function buildProxyFailureHint(engine: string): string {
92
+ return `Build-step proxy inheritance is enabled for ${engineDisplayName(engine)}. `
93
+ + 'Image pulls and Dockerfile FROM resolution use the Docker daemon or builder proxy configuration.';
94
+ }
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import type { ExecFileSyncOptions } from 'node:child_process';
6
+ import { removeDirRecursive } from '../../remove-dir.ts';
6
7
 
7
8
  const PROBE_TIMEOUT_MS = 2_000;
8
9
  const READ_IMAGE_TIMEOUT_MS = 5_000;
@@ -26,7 +27,7 @@ export function createLinuxClipboardAdapter({
26
27
  execToFileFn = execToFile,
27
28
  mkdtempFn = fs.mkdtempSync,
28
29
  readFileFn = fs.readFileSync,
29
- rmFn = fs.rmSync
30
+ rmFn = removeDirRecursive as typeof fs.rmSync
30
31
  }: {
31
32
  env?: NodeJS.ProcessEnv;
32
33
  execFn?: ExecFn;