@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,6 @@
1
+ import { inspectRequiredChecks } from './pr-checks.js';
2
+ function verificationCheck(type, status, message, failType) {
3
+ return { type, status, message, ...(failType ? { fail_type: failType } : {}) };
4
+ }
5
+ export { inspectRequiredChecks, verificationCheck };
6
+ //# sourceMappingURL=verification.js.map
@@ -0,0 +1,31 @@
1
+ async function inspectNpmChannel(name, version, fetcher = fetch) {
2
+ try {
3
+ const response = await fetcher(`https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(version)}`);
4
+ if (response.status === 404)
5
+ return { status: 'no-op', published: false, version, error: null };
6
+ if (!response.ok)
7
+ return { status: 'blocked', published: null, version, error: { code: 'NPM_REGISTRY_UNAVAILABLE', message: `npm registry returned ${response.status}` } };
8
+ const body = await response.json();
9
+ return { status: 'no-op', published: body.version === version, version, error: null };
10
+ }
11
+ catch (error) {
12
+ return { status: 'blocked', published: null, version, error: { code: 'NPM_REGISTRY_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
13
+ }
14
+ }
15
+ async function inspectHomebrewChannel(url, version, fetcher = fetch) {
16
+ try {
17
+ const response = await fetcher(url);
18
+ if (response.status === 404)
19
+ return { status: 'no-op', published: false, version, error: null };
20
+ if (!response.ok)
21
+ return { status: 'blocked', published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: `formula endpoint returned ${response.status}` } };
22
+ const formula = await response.text();
23
+ const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
24
+ return { status: 'no-op', published: new RegExp(`(?:version\\s+["']${escaped}["']|/v?${escaped}\\.)`).test(formula), version, error: null };
25
+ }
26
+ catch (error) {
27
+ return { status: 'blocked', published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
28
+ }
29
+ }
30
+ export { inspectHomebrewChannel, inspectNpmChannel };
31
+ //# sourceMappingURL=channels.js.map
@@ -0,0 +1,32 @@
1
+ function deriveReleasePhase(facts) {
2
+ if (!facts.localTag)
3
+ return 'unprepared';
4
+ if (!facts.remoteBranch && !facts.remoteTag)
5
+ return 'prepared';
6
+ if (!facts.remoteBranch || !facts.remoteTag)
7
+ return 'partially-published';
8
+ if (facts.githubRelease !== true || facts.npm !== true || facts.homebrew !== true)
9
+ return 'published';
10
+ if (facts.smoke !== 'success' || !facts.postCommit)
11
+ return 'post-pending';
12
+ return 'complete';
13
+ }
14
+ function releaseSnapshot(version, facts) {
15
+ return { version, tag: `v${version.replace(/^v/, '')}`, phase: deriveReleasePhase(facts), facts };
16
+ }
17
+ async function runReleaseAction(input) {
18
+ const before = releaseSnapshot(input.version, await input.inspect());
19
+ if (input.action === 'inspect')
20
+ return { status: 'no-op', changed: false, before, snapshot: before, error: null };
21
+ const allowed = input.action === 'prepare' ? before.phase === 'unprepared'
22
+ : input.action === 'publish' ? ['prepared', 'partially-published'].includes(before.phase)
23
+ : ['published', 'post-pending'].includes(before.phase);
24
+ if (!allowed)
25
+ return { status: before.phase === 'complete' ? 'no-op' : 'failed', changed: false, before, snapshot: before, error: before.phase === 'complete' ? null : { code: 'RELEASE_PHASE_INVALID', message: `Cannot ${input.action} from ${before.phase}` } };
26
+ await input[input.action]?.();
27
+ const snapshot = releaseSnapshot(input.version, await input.inspect());
28
+ const progressed = snapshot.phase !== before.phase;
29
+ return { status: progressed ? 'applied' : 'blocked', changed: progressed, before, snapshot, error: progressed ? null : { code: 'RELEASE_PROGRESS_PENDING', message: `${input.action} has not reached the next observable phase` } };
30
+ }
31
+ export { deriveReleasePhase, releaseSnapshot, runReleaseAction };
32
+ //# sourceMappingURL=workflow.js.map
@@ -1,7 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- // Add a new identifier here only after shipping matching .{platform}. template variants.
4
- const KNOWN_PLATFORMS = new Set(['github']);
3
+ // Built-in platform strategies. "none" deliberately selects generic templates
4
+ // and the no-op runtime adapter instead of requiring .none.* variants.
5
+ const KNOWN_PLATFORMS = new Set(['github', 'none']);
5
6
  const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
6
7
  function renderFile(src, dst, replacements) {
7
8
  if (!fs.existsSync(src)) {
@@ -7,14 +7,15 @@ import { loadShortIdByTaskId, normalizeShortIdInput } from '../task/short-id.js'
7
7
  import { buildTuiCommand, renderPrompt, selectTui } from './tui.js';
8
8
  import { getSkillRunSpec } from './skills.js';
9
9
  import { runHostCommand } from './host.js';
10
- const USAGE = `Usage: ai run <skill> [task-ref] [args...] [--tui <name>]
10
+ const USAGE = `Usage: ai run <skill> [task-ref] [args...] [--tui <name>] [--recreate]
11
11
 
12
12
  Task skills are scheduled inside the sandbox tmux session; ai run returns once
13
- the tmux window is created.
13
+ the tmux window is created. --recreate authorizes container-only replacement
14
+ when in-place sandbox recovery fails; it is not included in the TUI prompt.
14
15
 
15
16
  Examples:
16
17
  ai run create-task "describe the task" --tui codex
17
- ai run code-task #7 --tui codex`;
18
+ ai run code-task #7 --tui codex --recreate`;
18
19
  function extractTui(args) {
19
20
  const rest = [];
20
21
  let tui = null;
@@ -36,12 +37,16 @@ export function parseRunArgs(args) {
36
37
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
37
38
  throw new Error(USAGE);
38
39
  }
39
- const { rest, tui } = extractTui(args);
40
+ const { rest: withRecoveryFlags, tui } = extractTui(args);
41
+ const recreate = withRecoveryFlags.includes('--recreate');
42
+ const rest = withRecoveryFlags.filter((arg) => arg !== '--recreate');
40
43
  const [skill = '', maybeTaskRef, ...remaining] = rest;
41
44
  const spec = getSkillRunSpec(skill);
42
45
  if (!spec)
43
46
  throw new Error(`Unknown skill '${skill}'`);
44
47
  if (spec.kind === 'create') {
48
+ if (recreate)
49
+ throw new Error('--recreate is only valid for sandbox task runs');
45
50
  const createArgs = rest.slice(1);
46
51
  if (createArgs.length === 0)
47
52
  throw new Error('create-task requires a description');
@@ -49,7 +54,13 @@ export function parseRunArgs(args) {
49
54
  }
50
55
  if (!maybeTaskRef)
51
56
  throw new Error(`${skill} requires a task-ref`);
52
- return { skill, taskRef: maybeTaskRef, args: remaining, tui };
57
+ return {
58
+ skill,
59
+ taskRef: maybeTaskRef,
60
+ args: remaining,
61
+ tui,
62
+ ...(recreate ? { recreate: true } : {})
63
+ };
53
64
  }
54
65
  function assertAllowedByConfig(skill, commandConfig) {
55
66
  const allowed = commandConfig.allowedSkills;
@@ -97,7 +108,7 @@ function resolveActiveTaskIdentity(taskRef, repoRoot) {
97
108
  if (normalized.kind !== 'shortId')
98
109
  return null;
99
110
  resolvedTaskRef = normalized.value;
100
- taskId = readActiveShortIdRegistry(repoRoot)[normalized.value.slice(1)] ?? null;
111
+ taskId = readActiveShortIdRegistry(repoRoot)[normalized.value] ?? null;
101
112
  }
102
113
  if (!taskId)
103
114
  return null;
@@ -161,7 +172,13 @@ export async function runSkill(args, options = {}) {
161
172
  const writeStderr = options.writeStderr ?? ((chunk) => process.stderr.write(chunk));
162
173
  const runSandbox = options.runSandbox ??
163
174
  ((request) => runInSandbox(request));
164
- const result = await runSandbox({ taskRef: parsed.taskRef, branch, command, runId });
175
+ const result = await runSandbox({
176
+ taskRef: parsed.taskRef,
177
+ branch,
178
+ command,
179
+ runId,
180
+ recreate: parsed.recreate
181
+ });
165
182
  if (result.stdout) {
166
183
  writeStdout(result.stdout);
167
184
  }
@@ -3,6 +3,7 @@ import { loadConfig } from './config.js';
3
3
  import { containerNameCandidates, sandboxBranchLabel, sandboxLabel } from './constants.js';
4
4
  import { detectEngine } from './engine.js';
5
5
  import { commandForEngine } from './shell.js';
6
+ import { ensureSandboxReady } from './recovery.js';
6
7
  import { hostTimezoneEnvFlags, terminalEnvFlags } from './commands/enter.js';
7
8
  import { fetchSandboxRows, selectSandboxContainer, startSandboxContainer } from './commands/list-running.js';
8
9
  async function spawnCapture(file, args) {
@@ -131,7 +132,28 @@ export async function runInSandbox(request, options = {}) {
131
132
  if (!found) {
132
133
  throw new Error(`Sandbox for ${request.branch} not found. Create it first with ai sandbox create ${request.taskRef}.`);
133
134
  }
134
- if (!found.running) {
135
+ let container = found.name;
136
+ if (options.ensureReady) {
137
+ container = (await options.ensureReady({
138
+ branch: request.branch,
139
+ row: found,
140
+ allowRecreate: request.recreate ?? false
141
+ })).container;
142
+ }
143
+ else if (config) {
144
+ container = (await ensureSandboxReady({
145
+ config,
146
+ engine,
147
+ branch: request.branch,
148
+ row: found,
149
+ allowRecreate: request.recreate,
150
+ recreate: async (targetBranch) => {
151
+ const { create } = await import('./commands/create.js');
152
+ await create([targetBranch, '--no-refresh']);
153
+ }
154
+ })).container;
155
+ }
156
+ else if (!found.running) {
135
157
  (options.startContainer ?? ((name) => startSandboxContainer(engine, name)))(found.name);
136
158
  }
137
159
  const runId = options.runId ?? createRunId();
@@ -140,7 +162,7 @@ export async function runInSandbox(request, options = {}) {
140
162
  'exec',
141
163
  ...terminalEnvFlags(),
142
164
  ...hostTimezoneEnvFlags(),
143
- found.name,
165
+ container,
144
166
  'bash',
145
167
  '-lc',
146
168
  buildTmuxLauncher({ request, runId })
@@ -152,7 +174,7 @@ export async function runInSandbox(request, options = {}) {
152
174
  run: {
153
175
  runId,
154
176
  engine,
155
- container: found.name,
177
+ container,
156
178
  runDir
157
179
  }
158
180
  };
@@ -13,8 +13,10 @@ import { prepareDockerfile } from '../dockerfile.js';
13
13
  import { detectEngine, ensureDocker } from '../engine.js';
14
14
  import { commandForEngine, execEngine, run, runEngine, runOk, runOkEngine, runSafe, runSafeEngine, runVerboseEngine } from '../shell.js';
15
15
  import { resolveTaskBranch } from '../task-resolver.js';
16
- import { resolveTools, toolConfigDirCandidates } from '../tools.js';
16
+ import { resolveTools, tmpfsSeedStagingPath, tmpfsSeedTargetPath, toolConfigDirCandidates } from '../tools.js';
17
+ import { assertFreshSandboxReady, hydrateTmpfsSeedEntries, prepareTmpfsMounts } from '../recovery.js';
17
18
  import { hostJoin, toEnginePath, volumeArg } from '../engines/wsl2-paths.js';
19
+ import { sandboxCoreBindMounts } from '../mounts.js';
18
20
  import { clipboardHostDir, CONTAINER_CLIPBOARD_MOUNT } from '../clipboard/paths.js';
19
21
  import { validateSelinuxDisableEnv } from '../engines/selinux.js';
20
22
  import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.js';
@@ -47,13 +49,27 @@ alias gy='gemini --yolo; tput ed'
47
49
  `;
48
50
  const CONTAINER_HOME = '/home/devuser';
49
51
  const CONTAINER_SHELL_CONFIG_MOUNT = `${CONTAINER_HOME}/.host-shell-config`;
50
- const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh]
52
+ const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh] [--inherit-proxy|-P]
51
53
 
52
54
  Host aliases:
53
55
  ${'~'}/.agent-infra/aliases/sandbox.sh is auto-created on first run and exposed
54
56
  as ${CONTAINER_HOME}/.bash_aliases inside the sandbox container (the host
55
57
  shell-config directory is bind-mounted at ${CONTAINER_SHELL_CONFIG_MOUNT} and
56
- symlinked into $HOME).`;
58
+ symlinked into $HOME).
59
+
60
+ Proxy:
61
+ --inherit-proxy, -P Copy non-empty standard host proxy variables into the
62
+ container environment through the private env file.`;
63
+ const HOST_PROXY_ENV_KEYS = [
64
+ 'http_proxy',
65
+ 'HTTP_PROXY',
66
+ 'https_proxy',
67
+ 'HTTPS_PROXY',
68
+ 'all_proxy',
69
+ 'ALL_PROXY',
70
+ 'no_proxy',
71
+ 'NO_PROXY'
72
+ ];
57
73
  function resolveToolDirs(config, tools, branch) {
58
74
  return tools.map((tool) => {
59
75
  const candidates = toolConfigDirCandidates(tool, config.project, branch);
@@ -425,9 +441,17 @@ function formatEnvFileEntry(key, value) {
425
441
  }
426
442
  return `${key}=${value}`;
427
443
  }
444
+ export function collectHostProxyEntries(env) {
445
+ const entriesByExactKey = new Map(Object.entries(env));
446
+ return HOST_PROXY_ENV_KEYS.flatMap((key) => {
447
+ const value = entriesByExactKey.get(key);
448
+ return typeof value === 'string' && value !== '' ? [[key, value]] : [];
449
+ });
450
+ }
428
451
  export function buildContainerEnvFile(resolvedTools, engine, runSafeEngineFn = runSafeEngine, options = {}) {
429
- const { mkdtempFn = fs.mkdtempSync, writeFileFn = fs.writeFileSync, chmodFn = fs.chmodSync, rmFn = fs.rmSync, tmpDir = os.tmpdir(), runSafeFn = runSafe } = options;
452
+ const { additionalEntries = [], mkdtempFn = fs.mkdtempSync, writeFileFn = fs.writeFileSync, chmodFn = fs.chmodSync, rmFn = fs.rmSync, tmpDir = os.tmpdir(), runSafeFn = runSafe } = options;
430
453
  const entries = resolvedTools.flatMap(({ tool }) => Object.entries(tool.envVars ?? {}));
454
+ entries.push(...additionalEntries);
431
455
  let ghToken = runSafeEngineFn(engine, 'gh', ['auth', 'token']);
432
456
  if (!ghToken && engine === 'wsl2') {
433
457
  ghToken = runSafeFn('gh', ['auth', 'token']);
@@ -933,6 +957,7 @@ export async function create(args) {
933
957
  cpu: { type: 'string' },
934
958
  memory: { type: 'string' },
935
959
  'no-refresh': { type: 'boolean' },
960
+ 'inherit-proxy': { type: 'boolean', short: 'P' },
936
961
  help: { type: 'boolean', short: 'h' }
937
962
  }
938
963
  });
@@ -976,6 +1001,7 @@ export async function create(args) {
976
1001
  const baseBranch = base ?? runSafe('git', ['-C', effectiveConfig.repoRoot, 'branch', '--show-current']);
977
1002
  const expectedImageSignature = buildImageSignature(preparedDockerfile, tools);
978
1003
  const engine = detectEngine(effectiveConfig);
1004
+ let createdTmpfsSeedPlan = [];
979
1005
  p.intro(pc.cyan('AI Sandbox'));
980
1006
  p.log.info(`Project: ${pc.bold(effectiveConfig.project)} | Branch: ${pc.bold(branch)} | Base: ${pc.bold(baseBranch || 'HEAD')}`);
981
1007
  if (credentialOutcome.status === 'SKIPPED') {
@@ -1148,7 +1174,10 @@ export async function create(args) {
1148
1174
  const cachedGpg = needsGpg
1149
1175
  ? readGpgCache(effectiveConfig.home, effectiveConfig.project, undefined, signingKey)
1150
1176
  : null;
1151
- const envFile = buildContainerEnvFile(effectiveResolvedTools, engine);
1177
+ const proxyEntries = values['inherit-proxy'] ? collectHostProxyEntries(process.env) : [];
1178
+ const envFile = buildContainerEnvFile(effectiveResolvedTools, engine, undefined, {
1179
+ additionalEntries: proxyEntries
1180
+ });
1152
1181
  let hostShellConfig;
1153
1182
  let tmpfsSeedPlan = [];
1154
1183
  try {
@@ -1183,9 +1212,12 @@ export async function create(args) {
1183
1212
  branch,
1184
1213
  repoRoot: effectiveConfig.repoRoot
1185
1214
  });
1186
- const shellConfigVolumes = hostShellConfig.mounts.flatMap(({ hostPath, containerPath }) => [
1215
+ const coreVolumes = sandboxCoreBindMounts(effectiveConfig, branch, {
1216
+ worktree,
1217
+ shellConfigHostDir: hostShellConfig.hostDir
1218
+ }).flatMap(({ hostPaths, containerPath, readOnly }) => [
1187
1219
  '-v',
1188
- volumeArg(engine, hostPath, containerPath, ':ro')
1220
+ volumeArg(engine, hostPaths[0], containerPath, readOnly ? ':ro' : '')
1189
1221
  ]);
1190
1222
  // Mount each declared seed read-only at an isolated staging path.
1191
1223
  // After docker run mounts the empty tmpfs, the container's default
@@ -1194,14 +1226,17 @@ export async function create(args) {
1194
1226
  // stale runtime files (logs_2.sqlite, sessions, etc.) on the host from
1195
1227
  // being exposed or written through.
1196
1228
  tmpfsSeedPlan = effectiveResolvedTools.flatMap(({ tool, dir }) => (tool.tmpfs?.seed ?? []).flatMap((entry, index) => {
1229
+ const targetPath = tmpfsSeedTargetPath(tool.containerMount, entry);
1197
1230
  const hostPath = path.join(dir, entry);
1198
1231
  if (!fs.existsSync(hostPath)) {
1199
1232
  return [];
1200
1233
  }
1201
- const stagingPath = path.posix.join('/run/agent-infra/tmpfs-seeds', tool.id, String(index));
1234
+ const stagingPath = tmpfsSeedStagingPath(tool.id, index);
1202
1235
  return [{
1236
+ toolId: tool.id,
1237
+ containerMount: tool.containerMount,
1203
1238
  stagingPath,
1204
- targetPath: path.posix.join(tool.containerMount, entry),
1239
+ targetPath,
1205
1240
  volumeArgs: ['-v', volumeArg(engine, hostPath, stagingPath, ':ro')]
1206
1241
  }];
1207
1242
  }));
@@ -1232,14 +1267,7 @@ export async function create(args) {
1232
1267
  sandboxLabel(effectiveConfig),
1233
1268
  '--label',
1234
1269
  `${sandboxBranchLabel(effectiveConfig)}=${branch}`,
1235
- '-v',
1236
- volumeArg(engine, worktree, '/workspace'),
1237
- '-v',
1238
- volumeArg(engine, workspaceDir, '/workspace/.agents/workspace'),
1239
- '-v',
1240
- volumeArg(engine, shareCommon, '/share/common'),
1241
- '-v',
1242
- volumeArg(engine, shareBranch, '/share/branch'),
1270
+ ...coreVolumes,
1243
1271
  ...buildClipboardVolumeArgs(engine, effectiveConfig.home),
1244
1272
  '-v',
1245
1273
  volumeArg(engine, path.join(effectiveConfig.repoRoot, '.git'), `${toEnginePath(engine, effectiveConfig.repoRoot)}/.git`),
@@ -1248,25 +1276,30 @@ export async function create(args) {
1248
1276
  ...tmpfsArgs,
1249
1277
  ...tmpfsSeedPlan.flatMap(({ volumeArgs }) => volumeArgs),
1250
1278
  ...liveMountVolumes,
1251
- ...shellConfigVolumes,
1252
1279
  ...envFile.dockerArgs,
1253
1280
  ...tzFlags,
1254
1281
  '-w',
1255
1282
  '/workspace',
1256
1283
  effectiveConfig.imageName
1257
1284
  ]);
1285
+ createdTmpfsSeedPlan = tmpfsSeedPlan;
1258
1286
  }
1259
1287
  finally {
1260
1288
  envFile.cleanup();
1261
1289
  }
1262
- for (const { stagingPath, targetPath } of tmpfsSeedPlan) {
1263
- runEngineTaskCommand(engine, 'docker', [
1264
- 'exec', container, 'mkdir', '-p', path.posix.dirname(targetPath)
1265
- ]);
1266
- runEngineTaskCommand(engine, 'docker', [
1267
- 'exec', container, 'cp', '-R', '--', stagingPath, targetPath
1268
- ]);
1269
- }
1290
+ prepareTmpfsMounts({
1291
+ engine,
1292
+ container,
1293
+ mountPaths: effectiveResolvedTools
1294
+ .filter(({ tool }) => tool.tmpfs)
1295
+ .map(({ tool }) => tool.containerMount)
1296
+ });
1297
+ hydrateTmpfsSeedEntries({
1298
+ engine,
1299
+ container,
1300
+ entries: tmpfsSeedPlan,
1301
+ replace: true
1302
+ });
1270
1303
  // Belt-and-suspenders: re-create the four shell-config symlinks at
1271
1304
  // runtime so users with a custom `sandbox.dockerfile` (which won't
1272
1305
  // include the ai-tools.dockerfile symlink fragment) still get
@@ -1320,6 +1353,13 @@ export async function create(args) {
1320
1353
  preparedDockerfile.cleanup();
1321
1354
  }
1322
1355
  p.log.step('Verifying setup...');
1356
+ assertFreshSandboxReady({
1357
+ config: effectiveConfig,
1358
+ engine,
1359
+ branch,
1360
+ container,
1361
+ copiedEntries: createdTmpfsSeedPlan
1362
+ });
1323
1363
  const runningContainers = runSafeEngine(engine, 'docker', ['ps', '--format', '{{.Names}}']).split('\n');
1324
1364
  const checks = [
1325
1365
  { name: 'Container running', ok: runningContainers.includes(container) },
@@ -1,18 +1,20 @@
1
1
  import { loadConfig } from '../config.js';
2
2
  import { assertValidBranchName, containerNameCandidates, sandboxBranchLabel, sandboxLabel } from '../constants.js';
3
3
  import { detectEngine } from '../engine.js';
4
+ import { ensureSandboxReady } from '../recovery.js';
4
5
  import { formatCredentialWarnings, formatRemaining, hasClaudeProviderAuth, reconcileClaudeCredentials, redactCommandError, validateClaudeCredentialsEnvOverride } from '../credentials.js';
5
6
  import { runInteractiveEngine } from '../shell.js';
6
7
  import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.js';
7
8
  import { runInteractiveWithClipboardBridge } from '../clipboard/bridge.js';
8
9
  import { detectHostTimezone } from '../host-timezone.js';
9
- import { fetchSandboxRows, resolveBranchArg, selectSandboxContainer, startSandboxContainer } from './list-running.js';
10
- const USAGE = `Usage: ai sandbox exec <branch | TASK-id | N | '#N'> [cmd...]
10
+ import { fetchSandboxRows, resolveBranchArg, selectSandboxContainer, } from './list-running.js';
11
+ const USAGE = `Usage: ai sandbox exec [--recreate] <branch | TASK-id | N> [cmd...]
11
12
 
12
- N (bare) and '#N' both reference the same active task short id from
13
+ N references an active task short id from
13
14
  .agents/workspace/active/.short-ids.json. They resolve only via that
14
15
  registry — they do not reference a container's row position in
15
- 'ai sandbox ls' output.`;
16
+ 'ai sandbox ls' output. --recreate is a host recovery flag only before the
17
+ target; the same token after the target is passed to the container command.`;
16
18
  const TMUX_ENTRY_PATH = '/usr/local/bin/sandbox-tmux-entry';
17
19
  // Terminal-detection variables that interactive TUIs (e.g. claude-code)
18
20
  // inspect to enable progressive enhancements such as the kitty keyboard
@@ -76,6 +78,19 @@ export function formatCredentialSyncStatus(result, isTTY = process.stderr.isTTY,
76
78
  }
77
79
  return null;
78
80
  }
81
+ export function parseEnterArgs(args) {
82
+ let recreate = false;
83
+ let index = 0;
84
+ while (args[index] === '--recreate') {
85
+ recreate = true;
86
+ index += 1;
87
+ }
88
+ const target = args[index] ?? '';
89
+ if (!target) {
90
+ throw new Error(USAGE);
91
+ }
92
+ return { target, command: args.slice(index + 1), recreate };
93
+ }
79
94
  export async function enter(args) {
80
95
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
81
96
  process.stdout.write(`${USAGE}\n`);
@@ -87,19 +102,27 @@ export async function enter(args) {
87
102
  const config = loadConfig();
88
103
  validateClaudeCredentialsEnvOverride();
89
104
  const engine = detectEngine(config);
90
- const [firstArg = '', ...cmd] = args;
91
- const branch = resolveBranchArg(firstArg, { repoRoot: config.repoRoot });
105
+ const parsed = parseEnterArgs(args);
106
+ const branch = resolveBranchArg(parsed.target, { repoRoot: config.repoRoot });
92
107
  assertValidBranchName(branch);
93
108
  const { running, nonRunning } = fetchSandboxRows(engine, sandboxLabel(config), sandboxBranchLabel(config));
94
109
  const found = selectSandboxContainer([...running, ...nonRunning], containerNameCandidates(config, branch));
95
110
  if (!found) {
96
111
  throw new Error(`No sandbox found for branch '${branch}'. Run 'ai sandbox create ${branch}' to create one.`);
97
112
  }
98
- if (!found.running) {
99
- process.stderr.write(`Sandbox '${found.name}' is stopped; starting it...\n`);
100
- startSandboxContainer(engine, found.name);
101
- }
102
- const container = found.name;
113
+ const ready = await ensureSandboxReady({
114
+ config,
115
+ engine,
116
+ branch,
117
+ row: found,
118
+ allowRecreate: parsed.recreate,
119
+ recreate: async (targetBranch) => {
120
+ const { create } = await import('./create.js');
121
+ await create([targetBranch, '--no-refresh']);
122
+ }
123
+ });
124
+ const container = ready.container;
125
+ const cmd = parsed.command;
103
126
  if (config.tools.includes('claude-code')) {
104
127
  try {
105
128
  // Scan all projects so a refresh from a neighbouring sandbox can still flow back to the host.
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { runSafeEngine, runVerboseEngine } from '../shell.js';
5
5
  import { resolveTaskBranch } from '../task-resolver.js';
6
+ import { isRemovedHashShortIdInput } from '../../task/short-id.js';
6
7
  export function containerListFormat() {
7
8
  return '{{.Names}}\t{{.Status}}\t{{.Labels}}';
8
9
  }
@@ -70,13 +71,13 @@ export function fetchSandboxRows(engine, label, branchKey) {
70
71
  }
71
72
  /**
72
73
  * Returns true iff `arg` is a syntactically valid task short reference.
73
- * Accepts both bare numeric ('11') and '#'-prefixed ('#11') forms.
74
+ * Accepts bare numeric ('11') task short ids.
74
75
  * Zero IO. Callers MUST use this as the gate before constructing any context
75
76
  * for resolveTaskShortRef — that way non-matching arguments (e.g. '#abc',
76
77
  * '#1.5', '#') never trigger sandbox list IO.
77
78
  */
78
79
  export function isTaskShortRef(arg) {
79
- return /^#?\d+$/.test(arg);
80
+ return /^\d+$/.test(arg);
80
81
  }
81
82
  /**
82
83
  * Try to resolve a short ref against the global task-short-id registry.
@@ -91,9 +92,7 @@ function tryResolveFromRegistry(arg, repoRoot) {
91
92
  const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
92
93
  if (!fs.existsSync(scriptPath))
93
94
  return { status: 'miss' };
94
- // Strip leading '#' when forwarding bare-numeric input through the script's CLI.
95
- // (Script accepts both forms, but this avoids shell quoting confusion in error
96
- // messages echoed back to the user.)
95
+ // Forward the bare-numeric short ref to the registry script for ID resolution.
97
96
  const result = spawnSync('node', [scriptPath, 'resolve', arg], { encoding: 'utf8', cwd: repoRoot });
98
97
  if (result.status !== 0)
99
98
  return { status: 'miss' };
@@ -120,7 +119,7 @@ function tryResolveFromRegistry(arg, repoRoot) {
120
119
  }
121
120
  /**
122
121
  /**
123
- * Resolve a task short reference (bare 'N' or '#N') to a branch name for the
122
+ * Resolve a bare task short reference to a branch name for the
124
123
  * sandbox entrypoint.
125
124
  *
126
125
  * Resolution: registry-only. Look up the short id in the global task-short-id
@@ -137,11 +136,11 @@ export function resolveTaskShortRef(arg, ctx) {
137
136
  if (lookup.status === 'hit')
138
137
  return lookup.branch;
139
138
  throw new Error(`short ref '${arg}' is not in the active task registry. ` +
140
- `'#N' and bare N resolve only via the registry (not by row position in 'ai sandbox ls'); ` +
139
+ `bare N resolves only via the registry (not by row position in 'ai sandbox ls'); ` +
141
140
  `use a task short id (e.g. 'ai sandbox exec 11'), a TASK-id, or a branch name.`);
142
141
  }
143
142
  /**
144
- * Resolve a sandbox command argument (`<branch | TASK-id | N | '#N'>`) to a
143
+ * Resolve a sandbox command argument (`<branch | TASK-id | N>`) to a
145
144
  * branch name, mirroring `ai sandbox exec` so that `start` and `exec` share one
146
145
  * input contract. Short refs go through the registry-only resolver (which throws
147
146
  * an actionable error on a miss); everything else flows through resolveTaskBranch
@@ -149,6 +148,9 @@ export function resolveTaskShortRef(arg, ctx) {
149
148
  * Callers still run assertValidBranchName on the result.
150
149
  */
151
150
  export function resolveBranchArg(arg, ctx) {
151
+ if (isRemovedHashShortIdInput(arg)) {
152
+ throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
153
+ }
152
154
  return isTaskShortRef(arg)
153
155
  ? resolveTaskShortRef(arg, ctx)
154
156
  : resolveTaskBranch(arg, ctx.repoRoot);
@@ -5,12 +5,12 @@ import { loadConfig } from '../config.js';
5
5
  import { assertValidBranchName, worktreeDirCandidates } from '../constants.js';
6
6
  import { resolveBranchArg } from './list-running.js';
7
7
  import { resolveTools, toolConfigDirCandidates } from '../tools.js';
8
- const USAGE = `Usage: ai sandbox show <branch | TASK-id | N | '#N'>
8
+ const USAGE = `Usage: ai sandbox show <branch | TASK-id | N>
9
9
 
10
10
  Shows one sandbox's worktree path and per-tool state paths (Claude Code,
11
11
  Codex, Gemini CLI, OpenCode). The argument follows the same contract as
12
12
  'ai sandbox exec' and 'ai sandbox start': N (bare) is the recommended form
13
- for task short ids (e.g. 'ai sandbox show 11'); '#N', a TASK-id, or a plain
13
+ for task short ids (e.g. 'ai sandbox show 11'); a TASK-id or a plain
14
14
  branch name are also accepted. Use 'ai sandbox ls' for the container list.`;
15
15
  function existingDirs(candidates) {
16
16
  const seen = new Set();