@fitlab-ai/agent-infra 0.8.4 → 0.9.0

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 (443) hide show
  1. package/bin/cli.ts +2 -2
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/bin/internal-cli.js +98 -0
  4. package/dist/lib/decide.js +81 -90
  5. package/dist/lib/defaults.json +9 -0
  6. package/dist/lib/git/review-snapshot.js +79 -0
  7. package/dist/lib/git/workflow.js +101 -0
  8. package/dist/lib/init.js +5 -0
  9. package/dist/lib/internal/git-workflow.js +42 -0
  10. package/dist/lib/internal/platform-checks.js +119 -0
  11. package/dist/lib/internal/platform-comment.js +129 -0
  12. package/dist/lib/internal/platform-context.js +46 -0
  13. package/dist/lib/internal/platform-issue.js +142 -0
  14. package/dist/lib/internal/platform-pr.js +146 -0
  15. package/dist/lib/internal/release-workflow.js +217 -0
  16. package/dist/lib/internal/task-artifact.js +67 -0
  17. package/dist/lib/internal/task-context.js +43 -0
  18. package/dist/lib/internal/task-event.js +70 -0
  19. package/dist/lib/internal/task-ledger.js +114 -0
  20. package/dist/lib/internal/task-lifecycle.js +58 -0
  21. package/dist/lib/internal/task-short-id.js +83 -0
  22. package/dist/lib/internal/task-snapshot.js +47 -0
  23. package/dist/lib/internal/task-verify.js +50 -0
  24. package/dist/lib/internal/task-warning.js +74 -0
  25. package/dist/lib/platform/adapters.js +14 -0
  26. package/dist/lib/platform/context.js +146 -0
  27. package/dist/lib/platform/github-client.js +124 -0
  28. package/dist/lib/platform/issue-comments.js +409 -0
  29. package/dist/lib/platform/issue-metadata.js +183 -0
  30. package/dist/lib/platform/issues.js +617 -0
  31. package/dist/lib/platform/metadata-labels.js +28 -0
  32. package/dist/lib/platform/pr-checks.js +216 -0
  33. package/dist/lib/platform/pr-summary.js +88 -0
  34. package/dist/lib/platform/pull-request-metadata.js +38 -0
  35. package/dist/lib/platform/pull-requests.js +338 -0
  36. package/dist/lib/platform/releases.js +82 -0
  37. package/dist/lib/platform/types.js +22 -0
  38. package/dist/lib/platform/verification-required.js +78 -0
  39. package/dist/lib/platform/verification-sync.js +1014 -0
  40. package/dist/lib/platform/verification.js +6 -0
  41. package/dist/lib/release/channels.js +31 -0
  42. package/dist/lib/release/workflow.js +32 -0
  43. package/dist/lib/render.js +3 -2
  44. package/dist/lib/run/index.js +24 -7
  45. package/dist/lib/sandbox/capture.js +25 -3
  46. package/dist/lib/sandbox/commands/create.js +66 -26
  47. package/dist/lib/sandbox/commands/enter.js +34 -11
  48. package/dist/lib/sandbox/commands/list-running.js +10 -8
  49. package/dist/lib/sandbox/commands/show.js +2 -2
  50. package/dist/lib/sandbox/commands/start.js +53 -15
  51. package/dist/lib/sandbox/engine.js +33 -3
  52. package/dist/lib/sandbox/engines/colima.js +2 -2
  53. package/dist/lib/sandbox/index.js +6 -6
  54. package/dist/lib/sandbox/mounts.js +36 -0
  55. package/dist/lib/sandbox/recovery.js +562 -0
  56. package/dist/lib/sandbox/runtimes/base.dockerfile +4 -0
  57. package/dist/lib/sandbox/task-resolver.js +5 -1
  58. package/dist/lib/sandbox/tools.js +19 -0
  59. package/dist/lib/server/daemon.js +9 -0
  60. package/dist/lib/server/process-control.js +66 -73
  61. package/dist/lib/server/process-state.js +168 -0
  62. package/dist/lib/server/protocol.js +5 -5
  63. package/dist/lib/task/activity-log.js +61 -0
  64. package/dist/lib/task/artifact-lifecycle.js +427 -0
  65. package/dist/lib/task/command-options.js +30 -0
  66. package/dist/lib/task/commands/cat.js +36 -6
  67. package/dist/lib/task/commands/decisions.js +80 -46
  68. package/dist/lib/task/commands/files.js +21 -7
  69. package/dist/lib/task/commands/grep.js +55 -7
  70. package/dist/lib/task/commands/issue-body.js +23 -14
  71. package/dist/lib/task/commands/log.js +27 -70
  72. package/dist/lib/task/commands/show.js +20 -7
  73. package/dist/lib/task/commands/status.js +18 -8
  74. package/dist/lib/task/decision-intents.js +154 -0
  75. package/dist/lib/task/decision-items.js +53 -0
  76. package/dist/lib/task/events.js +318 -0
  77. package/dist/lib/task/frontmatter.js +159 -1
  78. package/dist/lib/task/implementation-inputs.js +117 -0
  79. package/dist/lib/task/index.js +12 -9
  80. package/dist/lib/task/issue-form.js +19 -6
  81. package/dist/lib/task/ledger-intents.js +185 -0
  82. package/dist/lib/task/ledger.js +65 -35
  83. package/dist/lib/task/lifecycle.js +484 -0
  84. package/dist/lib/task/resolve-ref.js +152 -32
  85. package/dist/lib/task/review-artifacts.js +101 -0
  86. package/dist/lib/task/review-fingerprint.js +46 -0
  87. package/dist/lib/task/sections.js +358 -4
  88. package/dist/lib/task/short-id.js +292 -7
  89. package/dist/lib/task/snapshot.js +95 -0
  90. package/dist/lib/task/verification-checks.js +8 -0
  91. package/dist/lib/task/verification-config.js +14 -0
  92. package/dist/lib/task/verification-engine.js +906 -0
  93. package/dist/lib/task/verification-review.js +3 -0
  94. package/dist/lib/task/verification-types.js +2 -0
  95. package/dist/lib/task/verification.js +113 -0
  96. package/dist/lib/task/workflow-warning-intents.js +131 -0
  97. package/dist/lib/task/workflow-warnings.js +10 -78
  98. package/dist/lib/task/write.js +241 -0
  99. package/dist/lib/update.js +2 -0
  100. package/lib/decide.ts +57 -97
  101. package/lib/defaults.json +9 -0
  102. package/lib/git/review-snapshot.ts +73 -0
  103. package/lib/git/workflow.ts +101 -0
  104. package/lib/init.ts +9 -0
  105. package/lib/internal/git-workflow.ts +37 -0
  106. package/lib/internal/platform-checks.ts +101 -0
  107. package/lib/internal/platform-comment.ts +99 -0
  108. package/lib/internal/platform-context.ts +33 -0
  109. package/lib/internal/platform-issue.ts +116 -0
  110. package/lib/internal/platform-pr.ts +119 -0
  111. package/lib/internal/release-workflow.ts +186 -0
  112. package/lib/internal/task-artifact.ts +47 -0
  113. package/lib/internal/task-context.ts +35 -0
  114. package/lib/internal/task-event.ts +51 -0
  115. package/lib/internal/task-ledger.ts +86 -0
  116. package/lib/internal/task-lifecycle.ts +41 -0
  117. package/lib/internal/task-short-id.ts +55 -0
  118. package/lib/internal/task-snapshot.ts +32 -0
  119. package/lib/internal/task-verify.ts +33 -0
  120. package/lib/internal/task-warning.ts +50 -0
  121. package/lib/platform/adapters.ts +30 -0
  122. package/lib/platform/context.ts +164 -0
  123. package/lib/platform/github-client.ts +146 -0
  124. package/lib/platform/issue-comments.ts +479 -0
  125. package/lib/platform/issue-metadata.ts +250 -0
  126. package/lib/platform/issues.ts +691 -0
  127. package/lib/platform/metadata-labels.ts +33 -0
  128. package/lib/platform/pr-checks.ts +246 -0
  129. package/lib/platform/pr-summary.ts +90 -0
  130. package/lib/platform/pull-request-metadata.ts +69 -0
  131. package/lib/platform/pull-requests.ts +380 -0
  132. package/lib/platform/releases.ts +71 -0
  133. package/lib/platform/types.ts +74 -0
  134. package/lib/platform/verification-required.ts +83 -0
  135. package/{templates/.agents/scripts/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +221 -363
  136. package/lib/platform/verification.ts +11 -0
  137. package/lib/release/channels.ts +30 -0
  138. package/lib/release/workflow.ts +31 -0
  139. package/lib/render.ts +3 -2
  140. package/lib/run/index.ts +25 -7
  141. package/lib/sandbox/capture.ts +29 -3
  142. package/lib/sandbox/commands/create.ts +75 -28
  143. package/lib/sandbox/commands/enter.ts +38 -11
  144. package/lib/sandbox/commands/list-running.ts +10 -8
  145. package/lib/sandbox/commands/show.ts +2 -2
  146. package/lib/sandbox/commands/start.ts +50 -16
  147. package/lib/sandbox/engine.ts +37 -3
  148. package/lib/sandbox/engines/colima.ts +2 -2
  149. package/lib/sandbox/index.ts +6 -6
  150. package/lib/sandbox/mounts.ts +55 -0
  151. package/lib/sandbox/recovery.ts +828 -0
  152. package/lib/sandbox/runtimes/base.dockerfile +4 -0
  153. package/lib/sandbox/task-resolver.ts +5 -1
  154. package/lib/sandbox/tools.ts +31 -0
  155. package/lib/server/daemon.ts +9 -0
  156. package/lib/server/process-control.ts +70 -71
  157. package/lib/server/process-state.ts +183 -0
  158. package/lib/server/protocol.ts +5 -5
  159. package/lib/task/activity-log.ts +62 -0
  160. package/lib/task/artifact-lifecycle.ts +484 -0
  161. package/lib/task/command-options.ts +32 -0
  162. package/lib/task/commands/cat.ts +22 -9
  163. package/lib/task/commands/decisions.ts +49 -47
  164. package/lib/task/commands/files.ts +14 -6
  165. package/lib/task/commands/grep.ts +34 -7
  166. package/lib/task/commands/issue-body.ts +16 -16
  167. package/lib/task/commands/log.ts +17 -70
  168. package/lib/task/commands/show.ts +14 -6
  169. package/lib/task/commands/status.ts +17 -7
  170. package/lib/task/decision-intents.ts +163 -0
  171. package/lib/task/decision-items.ts +64 -0
  172. package/lib/task/events.ts +320 -0
  173. package/lib/task/frontmatter.ts +202 -2
  174. package/lib/task/implementation-inputs.ts +137 -0
  175. package/lib/task/index.ts +12 -9
  176. package/lib/task/issue-form.ts +20 -6
  177. package/lib/task/ledger-intents.ts +201 -0
  178. package/lib/task/ledger.ts +77 -31
  179. package/lib/task/lifecycle.ts +458 -0
  180. package/lib/task/resolve-ref.ts +197 -36
  181. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  182. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +20 -10
  183. package/lib/task/sections.ts +486 -4
  184. package/lib/task/short-id.ts +403 -9
  185. package/lib/task/snapshot.ts +143 -0
  186. package/lib/task/verification-checks.ts +9 -0
  187. package/lib/task/verification-config.ts +20 -0
  188. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +257 -451
  189. package/lib/task/verification-review.ts +9 -0
  190. package/lib/task/verification-types.ts +29 -0
  191. package/lib/task/verification.ts +156 -0
  192. package/lib/task/workflow-warning-intents.ts +142 -0
  193. package/lib/task/workflow-warnings.ts +10 -78
  194. package/lib/task/write.ts +468 -0
  195. package/lib/update.ts +6 -0
  196. package/package.json +5 -2
  197. package/templates/.agents/README.en.md +6 -3
  198. package/templates/.agents/README.zh-CN.md +6 -3
  199. package/templates/.agents/rules/README.en.md +6 -5
  200. package/templates/.agents/rules/README.zh-CN.md +6 -5
  201. package/templates/.agents/rules/create-issue.en.md +1 -1
  202. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  203. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  204. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  205. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  206. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  207. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  208. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  209. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  210. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  211. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  212. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  213. package/templates/.agents/rules/issue-sync.en.md +1 -1
  214. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  215. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  216. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  217. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  218. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  219. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  220. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  221. package/templates/.agents/rules/next-step-output.en.md +12 -11
  222. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  223. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  224. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  225. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  226. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  227. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  228. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  229. package/templates/.agents/rules/pr-sync.en.md +30 -3
  230. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  231. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  232. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  233. package/templates/.agents/rules/review-handshake.en.md +13 -9
  234. package/templates/.agents/rules/review-handshake.zh-CN.md +13 -9
  235. package/templates/.agents/rules/task-management.en.md +11 -2
  236. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  237. package/templates/.agents/rules/task-short-id.en.md +25 -29
  238. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  239. package/templates/.agents/scripts/lib/agent-infra-package.js +141 -0
  240. package/templates/.agents/scripts/task-short-id.js +71 -533
  241. package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
  242. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
  243. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  244. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  245. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  246. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  247. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  248. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  249. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  250. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  251. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  252. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  253. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  254. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  255. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  256. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  257. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  258. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  259. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  260. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  261. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  262. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  263. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  264. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  265. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  266. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  267. package/templates/.agents/skills/commit/SKILL.en.md +18 -14
  268. package/templates/.agents/skills/commit/SKILL.zh-CN.md +18 -14
  269. package/templates/.agents/skills/commit/config/verify.json +1 -2
  270. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  271. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  272. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  273. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  274. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  275. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  276. package/templates/.agents/skills/commit/reference/task-status-update.en.md +42 -2
  277. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +42 -2
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  279. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  280. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  281. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  282. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  283. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  284. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  285. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  286. package/templates/.agents/skills/complete-task/config/verify.en.json +11 -6
  287. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -6
  288. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  289. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  290. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  291. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  292. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  293. package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
  294. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
  295. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  296. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  297. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  298. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  299. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  300. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  301. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  302. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  303. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  304. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  305. package/templates/.agents/skills/init-milestones/SKILL.en.md +2 -2
  306. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +2 -2
  307. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +5 -4
  308. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  309. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  310. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  311. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  312. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  313. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  314. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  315. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  316. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  317. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  318. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  319. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  320. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  321. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  322. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  323. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  324. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  325. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  326. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  327. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  328. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  329. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  330. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  331. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  332. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  333. package/templates/.agents/skills/review-code/config/verify.en.json +5 -5
  334. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +5 -5
  335. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  336. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  337. package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -4
  338. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -4
  339. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  340. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  341. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  342. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  343. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  344. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  345. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  346. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  347. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  348. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  349. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  350. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  351. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +6 -3
  352. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +6 -3
  353. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +177 -151
  354. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  355. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  356. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  357. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  358. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  359. package/templates/.agents/templates/task.en.md +6 -1
  360. package/templates/.agents/templates/task.zh-CN.md +6 -1
  361. package/templates/.claude/commands/analyze-task.en.md +1 -1
  362. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  363. package/templates/.claude/commands/block-task.en.md +1 -1
  364. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  365. package/templates/.claude/commands/cancel-task.en.md +1 -1
  366. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  367. package/templates/.claude/commands/check-task.en.md +1 -1
  368. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  369. package/templates/.claude/commands/code-task.en.md +1 -1
  370. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  371. package/templates/.claude/commands/commit.en.md +1 -0
  372. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  373. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  374. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  375. package/templates/.claude/commands/complete-task.en.md +1 -1
  376. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  377. package/templates/.claude/commands/create-pr.en.md +1 -1
  378. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  379. package/templates/.claude/commands/plan-task.en.md +1 -1
  380. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  381. package/templates/.claude/commands/review-analysis.en.md +1 -1
  382. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  383. package/templates/.claude/commands/review-code.en.md +1 -1
  384. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  385. package/templates/.claude/commands/review-plan.en.md +1 -1
  386. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  387. package/templates/.claude/commands/watch-pr.en.md +1 -1
  388. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  389. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  390. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  391. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  392. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  393. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  394. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  395. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  396. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  397. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  398. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  399. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  400. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  401. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  402. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  403. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  404. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  405. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  406. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  407. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  408. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  409. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  410. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  411. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  412. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  413. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  414. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  415. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  416. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  417. package/templates/.git-hooks/check-large-files.cjs +92 -0
  418. package/templates/.git-hooks/check-version-format.sh +5 -1
  419. package/templates/.git-hooks/pre-commit +1 -0
  420. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  421. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  422. package/templates/.opencode/commands/check-task.en.md +1 -1
  423. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  424. package/templates/.opencode/commands/code-task.en.md +1 -1
  425. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  426. package/templates/.opencode/commands/commit.en.md +2 -0
  427. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  428. package/templates/.opencode/commands/complete-task.en.md +1 -1
  429. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  430. package/templates/.opencode/commands/plan-task.en.md +1 -1
  431. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  432. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  433. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  434. package/templates/.opencode/commands/review-code.en.md +1 -1
  435. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  436. package/templates/.opencode/commands/review-plan.en.md +1 -1
  437. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  438. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  439. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -99
  440. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  441. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  442. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  443. package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
@@ -0,0 +1,11 @@
1
+ import { inspectRequiredChecks } from './pr-checks.ts';
2
+
3
+ type VerificationStatus = 'pass' | 'fail' | 'blocked';
4
+ type VerificationCheck = { type: string; status: VerificationStatus; message: string; fail_type?: string };
5
+
6
+ function verificationCheck(type: string, status: VerificationStatus, message: string, failType?: string): VerificationCheck {
7
+ return { type, status, message, ...(failType ? { fail_type: failType } : {}) };
8
+ }
9
+
10
+ export { inspectRequiredChecks, verificationCheck };
11
+ export type { VerificationCheck, VerificationStatus };
@@ -0,0 +1,30 @@
1
+ type FetchResponse = { ok: boolean; status: number; json(): Promise<unknown>; text(): Promise<string> };
2
+ type Fetcher = (url: string) => Promise<FetchResponse>;
3
+
4
+ async function inspectNpmChannel(name: string, version: string, fetcher: Fetcher = fetch as unknown as Fetcher) {
5
+ try {
6
+ const response = await fetcher(`https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(version)}`);
7
+ if (response.status === 404) return { status: 'no-op' as const, published: false, version, error: null };
8
+ if (!response.ok) return { status: 'blocked' as const, published: null, version, error: { code: 'NPM_REGISTRY_UNAVAILABLE', message: `npm registry returned ${response.status}` } };
9
+ const body = await response.json() as Record<string, unknown>;
10
+ return { status: 'no-op' as const, published: body.version === version, version, error: null };
11
+ } catch (error) {
12
+ return { status: 'blocked' as const, published: null, version, error: { code: 'NPM_REGISTRY_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
13
+ }
14
+ }
15
+
16
+ async function inspectHomebrewChannel(url: string, version: string, fetcher: Fetcher = fetch as unknown as Fetcher) {
17
+ try {
18
+ const response = await fetcher(url);
19
+ if (response.status === 404) return { status: 'no-op' as const, published: false, version, error: null };
20
+ if (!response.ok) return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: `formula endpoint returned ${response.status}` } };
21
+ const formula = await response.text();
22
+ const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
+ return { status: 'no-op' as const, published: new RegExp(`(?:version\\s+["']${escaped}["']|/v?${escaped}\\.)`).test(formula), version, error: null };
24
+ } catch (error) {
25
+ return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
26
+ }
27
+ }
28
+
29
+ export { inspectHomebrewChannel, inspectNpmChannel };
30
+ export type { Fetcher, FetchResponse };
@@ -0,0 +1,31 @@
1
+ type ReleasePhase = 'unprepared' | 'prepared' | 'partially-published' | 'published' | 'post-pending' | 'complete';
2
+ type ReleaseFacts = { localTag: boolean; localTagConflict?: boolean; remoteBranch: boolean; remoteTag: boolean; githubRelease: boolean | null; npm: boolean | null; homebrew: boolean | null; smoke: 'success' | 'pending' | 'failed' | null; postCommit: boolean };
3
+
4
+ function deriveReleasePhase(facts: ReleaseFacts): ReleasePhase {
5
+ if (!facts.localTag) return 'unprepared';
6
+ if (!facts.remoteBranch && !facts.remoteTag) return 'prepared';
7
+ if (!facts.remoteBranch || !facts.remoteTag) return 'partially-published';
8
+ if (facts.githubRelease !== true || facts.npm !== true || facts.homebrew !== true) return 'published';
9
+ if (facts.smoke !== 'success' || !facts.postCommit) return 'post-pending';
10
+ return 'complete';
11
+ }
12
+
13
+ function releaseSnapshot(version: string, facts: ReleaseFacts) {
14
+ return { version, tag: `v${version.replace(/^v/, '')}`, phase: deriveReleasePhase(facts), facts };
15
+ }
16
+
17
+ async function runReleaseAction(input: { version: string; action: 'inspect' | 'prepare' | 'publish' | 'post'; inspect: () => Promise<ReleaseFacts>; prepare?: () => Promise<void>; publish?: () => Promise<void>; post?: () => Promise<void> }) {
18
+ const before = releaseSnapshot(input.version, await input.inspect());
19
+ if (input.action === 'inspect') return { status: 'no-op' as const, changed: false, before, snapshot: before, error: null };
20
+ const allowed = input.action === 'prepare' ? before.phase === 'unprepared'
21
+ : input.action === 'publish' ? ['prepared', 'partially-published'].includes(before.phase)
22
+ : ['published', 'post-pending'].includes(before.phase);
23
+ if (!allowed) return { status: before.phase === 'complete' ? 'no-op' as const : 'failed' as const, changed: false, before, snapshot: before, error: before.phase === 'complete' ? null : { code: 'RELEASE_PHASE_INVALID', message: `Cannot ${input.action} from ${before.phase}` } };
24
+ await input[input.action]?.();
25
+ const snapshot = releaseSnapshot(input.version, await input.inspect());
26
+ const progressed = snapshot.phase !== before.phase;
27
+ return { status: progressed ? 'applied' as const : 'blocked' as const, changed: progressed, before, snapshot, error: progressed ? null : { code: 'RELEASE_PROGRESS_PENDING', message: `${input.action} has not reached the next observable phase` } };
28
+ }
29
+
30
+ export { deriveReleasePhase, releaseSnapshot, runReleaseAction };
31
+ export type { ReleaseFacts, ReleasePhase };
package/lib/render.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
- // Add a new identifier here only after shipping matching .{platform}. template variants.
5
- const KNOWN_PLATFORMS = new Set(['github']);
4
+ // Built-in platform strategies. "none" deliberately selects generic templates
5
+ // and the no-op runtime adapter instead of requiring .none.* variants.
6
+ const KNOWN_PLATFORMS = new Set(['github', 'none']);
6
7
  const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
7
8
 
8
9
  type Replacements = {
package/lib/run/index.ts CHANGED
@@ -13,6 +13,7 @@ export type ParsedRunArgs = {
13
13
  taskRef: string | null;
14
14
  args: string[];
15
15
  tui: string | null;
16
+ recreate?: true;
16
17
  };
17
18
 
18
19
  export type SandboxRunRequest = {
@@ -20,6 +21,7 @@ export type SandboxRunRequest = {
20
21
  branch: string;
21
22
  command: string[];
22
23
  runId?: string;
24
+ recreate?: boolean;
23
25
  };
24
26
 
25
27
  export type SandboxRunResult = RunProcessResult & {
@@ -35,14 +37,15 @@ export type RunSkillOptions = {
35
37
  writeStderr?: (chunk: string) => void;
36
38
  };
37
39
 
38
- const USAGE = `Usage: ai run <skill> [task-ref] [args...] [--tui <name>]
40
+ const USAGE = `Usage: ai run <skill> [task-ref] [args...] [--tui <name>] [--recreate]
39
41
 
40
42
  Task skills are scheduled inside the sandbox tmux session; ai run returns once
41
- the tmux window is created.
43
+ the tmux window is created. --recreate authorizes container-only replacement
44
+ when in-place sandbox recovery fails; it is not included in the TUI prompt.
42
45
 
43
46
  Examples:
44
47
  ai run create-task "describe the task" --tui codex
45
- ai run code-task #7 --tui codex`;
48
+ ai run code-task #7 --tui codex --recreate`;
46
49
 
47
50
  function extractTui(args: string[]): { rest: string[]; tui: string | null } {
48
51
  const rest: string[] = [];
@@ -65,17 +68,26 @@ export function parseRunArgs(args: string[]): ParsedRunArgs {
65
68
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
66
69
  throw new Error(USAGE);
67
70
  }
68
- const { rest, tui } = extractTui(args);
71
+ const { rest: withRecoveryFlags, tui } = extractTui(args);
72
+ const recreate = withRecoveryFlags.includes('--recreate');
73
+ const rest = withRecoveryFlags.filter((arg) => arg !== '--recreate');
69
74
  const [skill = '', maybeTaskRef, ...remaining] = rest;
70
75
  const spec = getSkillRunSpec(skill);
71
76
  if (!spec) throw new Error(`Unknown skill '${skill}'`);
72
77
  if (spec.kind === 'create') {
78
+ if (recreate) throw new Error('--recreate is only valid for sandbox task runs');
73
79
  const createArgs = rest.slice(1);
74
80
  if (createArgs.length === 0) throw new Error('create-task requires a description');
75
81
  return { skill, taskRef: null, args: createArgs, tui };
76
82
  }
77
83
  if (!maybeTaskRef) throw new Error(`${skill} requires a task-ref`);
78
- return { skill, taskRef: maybeTaskRef, args: remaining, tui };
84
+ return {
85
+ skill,
86
+ taskRef: maybeTaskRef,
87
+ args: remaining,
88
+ tui,
89
+ ...(recreate ? { recreate: true as const } : {})
90
+ };
79
91
  }
80
92
 
81
93
  function assertAllowedByConfig(skill: string, commandConfig: Record<string, unknown>): void {
@@ -129,7 +141,7 @@ function resolveActiveTaskIdentity(taskRef: string, repoRoot: string): ActiveTas
129
141
  const normalized = normalizeShortIdInput(taskRef, { shortIdLength: readShortIdLength(repoRoot) });
130
142
  if (normalized.kind !== 'shortId') return null;
131
143
  resolvedTaskRef = normalized.value;
132
- taskId = readActiveShortIdRegistry(repoRoot)[normalized.value.slice(1)] ?? null;
144
+ taskId = readActiveShortIdRegistry(repoRoot)[normalized.value] ?? null;
133
145
  }
134
146
 
135
147
  if (!taskId) return null;
@@ -207,7 +219,13 @@ export async function runSkill(args: string[], options: RunSkillOptions = {}): P
207
219
  const runSandbox =
208
220
  options.runSandbox ??
209
221
  ((request: SandboxRunRequest) => runInSandbox(request));
210
- const result = await runSandbox({ taskRef: parsed.taskRef, branch, command, runId });
222
+ const result = await runSandbox({
223
+ taskRef: parsed.taskRef,
224
+ branch,
225
+ command,
226
+ runId,
227
+ recreate: parsed.recreate
228
+ });
211
229
  if (result.stdout) {
212
230
  writeStdout(result.stdout);
213
231
  }
@@ -3,6 +3,7 @@ import { loadConfig } from './config.ts';
3
3
  import { containerNameCandidates, sandboxBranchLabel, sandboxLabel } from './constants.ts';
4
4
  import { detectEngine } from './engine.ts';
5
5
  import { commandForEngine } from './shell.ts';
6
+ import { ensureSandboxReady, type SandboxReadyResult } from './recovery.ts';
6
7
  import { hostTimezoneEnvFlags, terminalEnvFlags } from './commands/enter.ts';
7
8
  import {
8
9
  fetchSandboxRows,
@@ -16,6 +17,7 @@ export type SandboxCaptureRequest = {
16
17
  branch: string;
17
18
  command: string[];
18
19
  timeoutMs?: number;
20
+ recreate?: boolean;
19
21
  };
20
22
 
21
23
  export type SandboxCaptureResult = {
@@ -40,6 +42,11 @@ export type SandboxCaptureOptions = {
40
42
  containerCandidates?: string[];
41
43
  rows?: SandboxRow[];
42
44
  startContainer?: (name: string) => void;
45
+ ensureReady?: (params: {
46
+ branch: string;
47
+ row: SandboxRow;
48
+ allowRecreate: boolean;
49
+ }) => Promise<SandboxReadyResult>;
43
50
  spawn?: (file: string, args: string[]) => Promise<SandboxCaptureResult>;
44
51
  };
45
52
 
@@ -189,7 +196,26 @@ export async function runInSandbox(
189
196
  `Sandbox for ${request.branch} not found. Create it first with ai sandbox create ${request.taskRef}.`
190
197
  );
191
198
  }
192
- if (!found.running) {
199
+ let container = found.name;
200
+ if (options.ensureReady) {
201
+ container = (await options.ensureReady({
202
+ branch: request.branch,
203
+ row: found,
204
+ allowRecreate: request.recreate ?? false
205
+ })).container;
206
+ } else if (config) {
207
+ container = (await ensureSandboxReady({
208
+ config,
209
+ engine,
210
+ branch: request.branch,
211
+ row: found,
212
+ allowRecreate: request.recreate,
213
+ recreate: async (targetBranch) => {
214
+ const { create } = await import('./commands/create.ts');
215
+ await create([targetBranch, '--no-refresh']);
216
+ }
217
+ })).container;
218
+ } else if (!found.running) {
193
219
  (options.startContainer ?? ((name: string) => startSandboxContainer(engine, name)))(found.name);
194
220
  }
195
221
  const runId = options.runId ?? createRunId();
@@ -198,7 +224,7 @@ export async function runInSandbox(
198
224
  'exec',
199
225
  ...terminalEnvFlags(),
200
226
  ...hostTimezoneEnvFlags(),
201
- found.name,
227
+ container,
202
228
  'bash',
203
229
  '-lc',
204
230
  buildTmuxLauncher({ request, runId })
@@ -210,7 +236,7 @@ export async function runInSandbox(
210
236
  run: {
211
237
  runId,
212
238
  engine,
213
- container: found.name,
239
+ container,
214
240
  runDir
215
241
  }
216
242
  };
@@ -39,10 +39,18 @@ import {
39
39
  import { resolveTaskBranch } from '../task-resolver.ts';
40
40
  import {
41
41
  resolveTools,
42
+ tmpfsSeedStagingPath,
43
+ tmpfsSeedTargetPath,
42
44
  toolConfigDirCandidates
43
45
  } from '../tools.ts';
44
- import type { SandboxTool } from '../tools.ts';
46
+ import type { SandboxTool, TmpfsSeedEntry } from '../tools.ts';
47
+ import {
48
+ assertFreshSandboxReady,
49
+ hydrateTmpfsSeedEntries,
50
+ prepareTmpfsMounts
51
+ } from '../recovery.ts';
45
52
  import { hostJoin, toEnginePath, volumeArg } from '../engines/wsl2-paths.ts';
53
+ import { sandboxCoreBindMounts } from '../mounts.ts';
46
54
  import { clipboardHostDir, CONTAINER_CLIPBOARD_MOUNT } from '../clipboard/paths.ts';
47
55
  import { validateSelinuxDisableEnv } from '../engines/selinux.ts';
48
56
  import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.ts';
@@ -87,20 +95,32 @@ alias gy='gemini --yolo; tput ed'
87
95
  `;
88
96
  const CONTAINER_HOME = '/home/devuser';
89
97
  const CONTAINER_SHELL_CONFIG_MOUNT = `${CONTAINER_HOME}/.host-shell-config`;
90
- const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh]
98
+ const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh] [--inherit-proxy|-P]
91
99
 
92
100
  Host aliases:
93
101
  ${'~'}/.agent-infra/aliases/sandbox.sh is auto-created on first run and exposed
94
102
  as ${CONTAINER_HOME}/.bash_aliases inside the sandbox container (the host
95
103
  shell-config directory is bind-mounted at ${CONTAINER_SHELL_CONFIG_MOUNT} and
96
- symlinked into $HOME).`;
104
+ symlinked into $HOME).
105
+
106
+ Proxy:
107
+ --inherit-proxy, -P Copy non-empty standard host proxy variables into the
108
+ container environment through the private env file.`;
109
+ const HOST_PROXY_ENV_KEYS = [
110
+ 'http_proxy',
111
+ 'HTTP_PROXY',
112
+ 'https_proxy',
113
+ 'HTTPS_PROXY',
114
+ 'all_proxy',
115
+ 'ALL_PROXY',
116
+ 'no_proxy',
117
+ 'NO_PROXY'
118
+ ] as const;
97
119
 
98
120
  type SandboxCreateConfig = ReturnType<typeof loadConfig>;
99
121
  type PreparedDockerfile = ReturnType<typeof prepareDockerfile>;
100
122
  type ResolvedTool = { tool: SandboxTool; dir: string };
101
- type TmpfsSeedPlanEntry = {
102
- stagingPath: string;
103
- targetPath: string;
123
+ type TmpfsSeedPlanEntry = TmpfsSeedEntry & {
104
124
  volumeArgs: string[];
105
125
  };
106
126
  type RuntimeCheck = { name: string; cmd: string[] };
@@ -626,11 +646,20 @@ function formatEnvFileEntry(key: string, value: string): string {
626
646
  return `${key}=${value}`;
627
647
  }
628
648
 
649
+ export function collectHostProxyEntries(env: NodeJS.ProcessEnv): Array<[string, string]> {
650
+ const entriesByExactKey = new Map(Object.entries(env));
651
+ return HOST_PROXY_ENV_KEYS.flatMap((key) => {
652
+ const value = entriesByExactKey.get(key);
653
+ return typeof value === 'string' && value !== '' ? [[key, value]] : [];
654
+ });
655
+ }
656
+
629
657
  export function buildContainerEnvFile(
630
658
  resolvedTools: ResolvedTool[],
631
659
  engine: string,
632
660
  runSafeEngineFn: EngineRunSafeFn = runSafeEngine,
633
661
  options: {
662
+ additionalEntries?: Array<[string, string]>;
634
663
  mkdtempFn?: typeof fs.mkdtempSync;
635
664
  writeFileFn?: typeof fs.writeFileSync;
636
665
  chmodFn?: typeof fs.chmodSync;
@@ -640,6 +669,7 @@ export function buildContainerEnvFile(
640
669
  } = {}
641
670
  ): { dockerArgs: string[]; cleanup: () => void } {
642
671
  const {
672
+ additionalEntries = [],
643
673
  mkdtempFn = fs.mkdtempSync,
644
674
  writeFileFn = fs.writeFileSync,
645
675
  chmodFn = fs.chmodSync,
@@ -649,6 +679,7 @@ export function buildContainerEnvFile(
649
679
  } = options;
650
680
 
651
681
  const entries: Array<[string, string]> = resolvedTools.flatMap(({ tool }) => Object.entries(tool.envVars ?? {}));
682
+ entries.push(...additionalEntries);
652
683
  let ghToken = runSafeEngineFn(engine, 'gh', ['auth', 'token']);
653
684
  if (!ghToken && engine === 'wsl2') {
654
685
  ghToken = runSafeFn('gh', ['auth', 'token']);
@@ -1246,6 +1277,7 @@ export async function create(args: string[]): Promise<void> {
1246
1277
  cpu: { type: 'string' },
1247
1278
  memory: { type: 'string' },
1248
1279
  'no-refresh': { type: 'boolean' },
1280
+ 'inherit-proxy': { type: 'boolean', short: 'P' },
1249
1281
  help: { type: 'boolean', short: 'h' }
1250
1282
  }
1251
1283
  });
@@ -1297,6 +1329,7 @@ export async function create(args: string[]): Promise<void> {
1297
1329
  const baseBranch = base ?? runSafe('git', ['-C', effectiveConfig.repoRoot, 'branch', '--show-current']);
1298
1330
  const expectedImageSignature = buildImageSignature(preparedDockerfile, tools);
1299
1331
  const engine = detectEngine(effectiveConfig);
1332
+ let createdTmpfsSeedPlan: TmpfsSeedPlanEntry[] = [];
1300
1333
 
1301
1334
  p.intro(pc.cyan('AI Sandbox'));
1302
1335
  p.log.info(
@@ -1503,7 +1536,10 @@ export async function create(args: string[]): Promise<void> {
1503
1536
  signingKey
1504
1537
  )
1505
1538
  : null;
1506
- const envFile = buildContainerEnvFile(effectiveResolvedTools, engine);
1539
+ const proxyEntries = values['inherit-proxy'] ? collectHostProxyEntries(process.env) : [];
1540
+ const envFile = buildContainerEnvFile(effectiveResolvedTools, engine, undefined, {
1541
+ additionalEntries: proxyEntries
1542
+ });
1507
1543
  let hostShellConfig: HostShellConfig;
1508
1544
  let tmpfsSeedPlan: TmpfsSeedPlanEntry[] = [];
1509
1545
  try {
@@ -1542,9 +1578,12 @@ export async function create(args: string[]): Promise<void> {
1542
1578
  branch,
1543
1579
  repoRoot: effectiveConfig.repoRoot
1544
1580
  });
1545
- const shellConfigVolumes = hostShellConfig.mounts.flatMap(({ hostPath, containerPath }) => [
1581
+ const coreVolumes = sandboxCoreBindMounts(effectiveConfig, branch, {
1582
+ worktree,
1583
+ shellConfigHostDir: hostShellConfig.hostDir
1584
+ }).flatMap(({ hostPaths, containerPath, readOnly }) => [
1546
1585
  '-v',
1547
- volumeArg(engine, hostPath, containerPath, ':ro')
1586
+ volumeArg(engine, hostPaths[0]!, containerPath, readOnly ? ':ro' : '')
1548
1587
  ]);
1549
1588
  // Mount each declared seed read-only at an isolated staging path.
1550
1589
  // After docker run mounts the empty tmpfs, the container's default
@@ -1554,14 +1593,17 @@ export async function create(args: string[]): Promise<void> {
1554
1593
  // being exposed or written through.
1555
1594
  tmpfsSeedPlan = effectiveResolvedTools.flatMap(({ tool, dir }) =>
1556
1595
  (tool.tmpfs?.seed ?? []).flatMap((entry, index) => {
1596
+ const targetPath = tmpfsSeedTargetPath(tool.containerMount, entry);
1557
1597
  const hostPath = path.join(dir, entry);
1558
1598
  if (!fs.existsSync(hostPath)) {
1559
1599
  return [];
1560
1600
  }
1561
- const stagingPath = path.posix.join('/run/agent-infra/tmpfs-seeds', tool.id, String(index));
1601
+ const stagingPath = tmpfsSeedStagingPath(tool.id, index);
1562
1602
  return [{
1603
+ toolId: tool.id,
1604
+ containerMount: tool.containerMount,
1563
1605
  stagingPath,
1564
- targetPath: path.posix.join(tool.containerMount, entry),
1606
+ targetPath,
1565
1607
  volumeArgs: ['-v', volumeArg(engine, hostPath, stagingPath, ':ro')]
1566
1608
  }];
1567
1609
  })
@@ -1601,14 +1643,7 @@ export async function create(args: string[]): Promise<void> {
1601
1643
  sandboxLabel(effectiveConfig),
1602
1644
  '--label',
1603
1645
  `${sandboxBranchLabel(effectiveConfig)}=${branch}`,
1604
- '-v',
1605
- volumeArg(engine, worktree, '/workspace'),
1606
- '-v',
1607
- volumeArg(engine, workspaceDir, '/workspace/.agents/workspace'),
1608
- '-v',
1609
- volumeArg(engine, shareCommon, '/share/common'),
1610
- '-v',
1611
- volumeArg(engine, shareBranch, '/share/branch'),
1646
+ ...coreVolumes,
1612
1647
  ...buildClipboardVolumeArgs(engine, effectiveConfig.home),
1613
1648
  '-v',
1614
1649
  volumeArg(
@@ -1621,25 +1656,30 @@ export async function create(args: string[]): Promise<void> {
1621
1656
  ...tmpfsArgs,
1622
1657
  ...tmpfsSeedPlan.flatMap(({ volumeArgs }) => volumeArgs),
1623
1658
  ...liveMountVolumes,
1624
- ...shellConfigVolumes,
1625
1659
  ...envFile.dockerArgs,
1626
1660
  ...tzFlags,
1627
1661
  '-w',
1628
1662
  '/workspace',
1629
1663
  effectiveConfig.imageName
1630
1664
  ]);
1665
+ createdTmpfsSeedPlan = tmpfsSeedPlan;
1631
1666
  } finally {
1632
1667
  envFile.cleanup();
1633
1668
  }
1634
1669
 
1635
- for (const { stagingPath, targetPath } of tmpfsSeedPlan) {
1636
- runEngineTaskCommand(engine, 'docker', [
1637
- 'exec', container, 'mkdir', '-p', path.posix.dirname(targetPath)
1638
- ]);
1639
- runEngineTaskCommand(engine, 'docker', [
1640
- 'exec', container, 'cp', '-R', '--', stagingPath, targetPath
1641
- ]);
1642
- }
1670
+ prepareTmpfsMounts({
1671
+ engine,
1672
+ container,
1673
+ mountPaths: effectiveResolvedTools
1674
+ .filter(({ tool }) => tool.tmpfs)
1675
+ .map(({ tool }) => tool.containerMount)
1676
+ });
1677
+ hydrateTmpfsSeedEntries({
1678
+ engine,
1679
+ container,
1680
+ entries: tmpfsSeedPlan,
1681
+ replace: true
1682
+ });
1643
1683
 
1644
1684
  // Belt-and-suspenders: re-create the four shell-config symlinks at
1645
1685
  // runtime so users with a custom `sandbox.dockerfile` (which won't
@@ -1708,6 +1748,13 @@ export async function create(args: string[]): Promise<void> {
1708
1748
  }
1709
1749
 
1710
1750
  p.log.step('Verifying setup...');
1751
+ assertFreshSandboxReady({
1752
+ config: effectiveConfig,
1753
+ engine,
1754
+ branch,
1755
+ container,
1756
+ copiedEntries: createdTmpfsSeedPlan
1757
+ });
1711
1758
  const runningContainers = runSafeEngine(engine, 'docker', ['ps', '--format', '{{.Names}}']).split('\n');
1712
1759
  const checks = [
1713
1760
  { name: 'Container running', ok: runningContainers.includes(container) },
@@ -6,6 +6,7 @@ import {
6
6
  sandboxLabel
7
7
  } from '../constants.ts';
8
8
  import { detectEngine } from '../engine.ts';
9
+ import { ensureSandboxReady } from '../recovery.ts';
9
10
  import {
10
11
  formatCredentialWarnings,
11
12
  formatRemaining,
@@ -22,15 +23,15 @@ import {
22
23
  fetchSandboxRows,
23
24
  resolveBranchArg,
24
25
  selectSandboxContainer,
25
- startSandboxContainer
26
26
  } from './list-running.ts';
27
27
 
28
- const USAGE = `Usage: ai sandbox exec <branch | TASK-id | N | '#N'> [cmd...]
28
+ const USAGE = `Usage: ai sandbox exec [--recreate] <branch | TASK-id | N> [cmd...]
29
29
 
30
- N (bare) and '#N' both reference the same active task short id from
30
+ N references an active task short id from
31
31
  .agents/workspace/active/.short-ids.json. They resolve only via that
32
32
  registry — they do not reference a container's row position in
33
- 'ai sandbox ls' output.`;
33
+ 'ai sandbox ls' output. --recreate is a host recovery flag only before the
34
+ target; the same token after the target is passed to the container command.`;
34
35
  const TMUX_ENTRY_PATH = '/usr/local/bin/sandbox-tmux-entry';
35
36
 
36
37
  // Terminal-detection variables that interactive TUIs (e.g. claude-code)
@@ -123,6 +124,24 @@ export function formatCredentialSyncStatus(
123
124
  return null;
124
125
  }
125
126
 
127
+ export function parseEnterArgs(args: string[]): {
128
+ target: string;
129
+ command: string[];
130
+ recreate: boolean;
131
+ } {
132
+ let recreate = false;
133
+ let index = 0;
134
+ while (args[index] === '--recreate') {
135
+ recreate = true;
136
+ index += 1;
137
+ }
138
+ const target = args[index] ?? '';
139
+ if (!target) {
140
+ throw new Error(USAGE);
141
+ }
142
+ return { target, command: args.slice(index + 1), recreate };
143
+ }
144
+
126
145
  export async function enter(args: string[]): Promise<number> {
127
146
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
128
147
  process.stdout.write(`${USAGE}\n`);
@@ -135,8 +154,8 @@ export async function enter(args: string[]): Promise<number> {
135
154
  const config = loadConfig();
136
155
  validateClaudeCredentialsEnvOverride();
137
156
  const engine = detectEngine(config);
138
- const [firstArg = '', ...cmd] = args;
139
- const branch = resolveBranchArg(firstArg, { repoRoot: config.repoRoot });
157
+ const parsed = parseEnterArgs(args);
158
+ const branch = resolveBranchArg(parsed.target, { repoRoot: config.repoRoot });
140
159
  assertValidBranchName(branch);
141
160
 
142
161
  const { running, nonRunning } = fetchSandboxRows(
@@ -154,11 +173,19 @@ export async function enter(args: string[]): Promise<number> {
154
173
  `No sandbox found for branch '${branch}'. Run 'ai sandbox create ${branch}' to create one.`
155
174
  );
156
175
  }
157
- if (!found.running) {
158
- process.stderr.write(`Sandbox '${found.name}' is stopped; starting it...\n`);
159
- startSandboxContainer(engine, found.name);
160
- }
161
- const container = found.name;
176
+ const ready = await ensureSandboxReady({
177
+ config,
178
+ engine,
179
+ branch,
180
+ row: found,
181
+ allowRecreate: parsed.recreate,
182
+ recreate: async (targetBranch) => {
183
+ const { create } = await import('./create.ts');
184
+ await create([targetBranch, '--no-refresh']);
185
+ }
186
+ });
187
+ const container = ready.container;
188
+ const cmd = parsed.command;
162
189
 
163
190
  if (config.tools.includes('claude-code')) {
164
191
  try {
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { runSafeEngine, runVerboseEngine } from '../shell.ts';
5
5
  import { resolveTaskBranch } from '../task-resolver.ts';
6
+ import { isRemovedHashShortIdInput } from '../../task/short-id.ts';
6
7
 
7
8
  export type SandboxRow = {
8
9
  name: string;
@@ -90,13 +91,13 @@ export function fetchSandboxRows(
90
91
 
91
92
  /**
92
93
  * Returns true iff `arg` is a syntactically valid task short reference.
93
- * Accepts both bare numeric ('11') and '#'-prefixed ('#11') forms.
94
+ * Accepts bare numeric ('11') task short ids.
94
95
  * Zero IO. Callers MUST use this as the gate before constructing any context
95
96
  * for resolveTaskShortRef — that way non-matching arguments (e.g. '#abc',
96
97
  * '#1.5', '#') never trigger sandbox list IO.
97
98
  */
98
99
  export function isTaskShortRef(arg: string): boolean {
99
- return /^#?\d+$/.test(arg);
100
+ return /^\d+$/.test(arg);
100
101
  }
101
102
 
102
103
  type RegistryLookup =
@@ -115,9 +116,7 @@ type RegistryLookup =
115
116
  function tryResolveFromRegistry(arg: string, repoRoot: string): RegistryLookup {
116
117
  const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
117
118
  if (!fs.existsSync(scriptPath)) return { status: 'miss' };
118
- // Strip leading '#' when forwarding bare-numeric input through the script's CLI.
119
- // (Script accepts both forms, but this avoids shell quoting confusion in error
120
- // messages echoed back to the user.)
119
+ // Forward the bare-numeric short ref to the registry script for ID resolution.
121
120
  const result = spawnSync('node', [scriptPath, 'resolve', arg], { encoding: 'utf8', cwd: repoRoot });
122
121
  if (result.status !== 0) return { status: 'miss' };
123
122
  const taskId = (result.stdout || '').trim();
@@ -149,7 +148,7 @@ function tryResolveFromRegistry(arg: string, repoRoot: string): RegistryLookup {
149
148
 
150
149
  /**
151
150
  /**
152
- * Resolve a task short reference (bare 'N' or '#N') to a branch name for the
151
+ * Resolve a bare task short reference to a branch name for the
153
152
  * sandbox entrypoint.
154
153
  *
155
154
  * Resolution: registry-only. Look up the short id in the global task-short-id
@@ -169,13 +168,13 @@ export function resolveTaskShortRef(
169
168
  if (lookup.status === 'hit') return lookup.branch;
170
169
  throw new Error(
171
170
  `short ref '${arg}' is not in the active task registry. ` +
172
- `'#N' and bare N resolve only via the registry (not by row position in 'ai sandbox ls'); ` +
171
+ `bare N resolves only via the registry (not by row position in 'ai sandbox ls'); ` +
173
172
  `use a task short id (e.g. 'ai sandbox exec 11'), a TASK-id, or a branch name.`
174
173
  );
175
174
  }
176
175
 
177
176
  /**
178
- * Resolve a sandbox command argument (`<branch | TASK-id | N | '#N'>`) to a
177
+ * Resolve a sandbox command argument (`<branch | TASK-id | N>`) to a
179
178
  * branch name, mirroring `ai sandbox exec` so that `start` and `exec` share one
180
179
  * input contract. Short refs go through the registry-only resolver (which throws
181
180
  * an actionable error on a miss); everything else flows through resolveTaskBranch
@@ -183,6 +182,9 @@ export function resolveTaskShortRef(
183
182
  * Callers still run assertValidBranchName on the result.
184
183
  */
185
184
  export function resolveBranchArg(arg: string, ctx: { repoRoot: string }): string {
185
+ if (isRemovedHashShortIdInput(arg)) {
186
+ throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
187
+ }
186
188
  return isTaskShortRef(arg)
187
189
  ? resolveTaskShortRef(arg, ctx)
188
190
  : resolveTaskBranch(arg, ctx.repoRoot);
@@ -7,12 +7,12 @@ import { assertValidBranchName, worktreeDirCandidates } from '../constants.ts';
7
7
  import { resolveBranchArg } from './list-running.ts';
8
8
  import { resolveTools, toolConfigDirCandidates } from '../tools.ts';
9
9
 
10
- const USAGE = `Usage: ai sandbox show <branch | TASK-id | N | '#N'>
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
13
  Codex, Gemini 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
- for task short ids (e.g. 'ai sandbox show 11'); '#N', a TASK-id, or a plain
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.`;
17
17
 
18
18
  export type SandboxDetail = {