@fitlab-ai/agent-infra 0.8.5 → 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 (425) 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 +1 -0
  6. package/dist/lib/git/review-snapshot.js +79 -0
  7. package/dist/lib/git/workflow.js +101 -0
  8. package/dist/lib/internal/git-workflow.js +42 -0
  9. package/dist/lib/internal/platform-checks.js +119 -0
  10. package/dist/lib/internal/platform-comment.js +129 -0
  11. package/dist/lib/internal/platform-context.js +46 -0
  12. package/dist/lib/internal/platform-issue.js +142 -0
  13. package/dist/lib/internal/platform-pr.js +146 -0
  14. package/dist/lib/internal/release-workflow.js +217 -0
  15. package/dist/lib/internal/task-artifact.js +67 -0
  16. package/dist/lib/internal/task-context.js +43 -0
  17. package/dist/lib/internal/task-event.js +70 -0
  18. package/dist/lib/internal/task-ledger.js +114 -0
  19. package/dist/lib/internal/task-lifecycle.js +58 -0
  20. package/dist/lib/internal/task-short-id.js +83 -0
  21. package/dist/lib/internal/task-snapshot.js +47 -0
  22. package/dist/lib/internal/task-verify.js +50 -0
  23. package/dist/lib/internal/task-warning.js +74 -0
  24. package/dist/lib/platform/adapters.js +14 -0
  25. package/dist/lib/platform/context.js +146 -0
  26. package/dist/lib/platform/github-client.js +124 -0
  27. package/dist/lib/platform/issue-comments.js +409 -0
  28. package/dist/lib/platform/issue-metadata.js +183 -0
  29. package/dist/lib/platform/issues.js +617 -0
  30. package/dist/lib/platform/metadata-labels.js +28 -0
  31. package/dist/lib/platform/pr-checks.js +216 -0
  32. package/dist/lib/platform/pr-summary.js +88 -0
  33. package/dist/lib/platform/pull-request-metadata.js +38 -0
  34. package/dist/lib/platform/pull-requests.js +338 -0
  35. package/dist/lib/platform/releases.js +82 -0
  36. package/dist/lib/platform/types.js +22 -0
  37. package/dist/lib/platform/verification-required.js +78 -0
  38. package/dist/lib/platform/verification-sync.js +1014 -0
  39. package/dist/lib/platform/verification.js +6 -0
  40. package/dist/lib/release/channels.js +31 -0
  41. package/dist/lib/release/workflow.js +32 -0
  42. package/dist/lib/render.js +3 -2
  43. package/dist/lib/run/index.js +24 -7
  44. package/dist/lib/sandbox/capture.js +25 -3
  45. package/dist/lib/sandbox/commands/create.js +36 -22
  46. package/dist/lib/sandbox/commands/enter.js +34 -11
  47. package/dist/lib/sandbox/commands/list-running.js +10 -8
  48. package/dist/lib/sandbox/commands/show.js +2 -2
  49. package/dist/lib/sandbox/commands/start.js +53 -15
  50. package/dist/lib/sandbox/index.js +6 -6
  51. package/dist/lib/sandbox/mounts.js +36 -0
  52. package/dist/lib/sandbox/recovery.js +562 -0
  53. package/dist/lib/sandbox/task-resolver.js +5 -1
  54. package/dist/lib/sandbox/tools.js +19 -0
  55. package/dist/lib/server/protocol.js +5 -5
  56. package/dist/lib/task/activity-log.js +61 -0
  57. package/dist/lib/task/artifact-lifecycle.js +427 -0
  58. package/dist/lib/task/command-options.js +30 -0
  59. package/dist/lib/task/commands/cat.js +36 -6
  60. package/dist/lib/task/commands/decisions.js +80 -46
  61. package/dist/lib/task/commands/files.js +21 -7
  62. package/dist/lib/task/commands/grep.js +55 -7
  63. package/dist/lib/task/commands/issue-body.js +23 -14
  64. package/dist/lib/task/commands/log.js +27 -70
  65. package/dist/lib/task/commands/show.js +20 -7
  66. package/dist/lib/task/commands/status.js +18 -8
  67. package/dist/lib/task/decision-intents.js +154 -0
  68. package/dist/lib/task/decision-items.js +53 -0
  69. package/dist/lib/task/events.js +318 -0
  70. package/dist/lib/task/frontmatter.js +159 -1
  71. package/dist/lib/task/implementation-inputs.js +117 -0
  72. package/dist/lib/task/index.js +12 -9
  73. package/dist/lib/task/issue-form.js +19 -6
  74. package/dist/lib/task/ledger-intents.js +185 -0
  75. package/dist/lib/task/ledger.js +65 -35
  76. package/dist/lib/task/lifecycle.js +484 -0
  77. package/dist/lib/task/resolve-ref.js +152 -32
  78. package/dist/lib/task/review-artifacts.js +101 -0
  79. package/dist/lib/task/review-fingerprint.js +46 -0
  80. package/dist/lib/task/sections.js +358 -4
  81. package/dist/lib/task/short-id.js +292 -7
  82. package/dist/lib/task/snapshot.js +95 -0
  83. package/dist/lib/task/verification-checks.js +8 -0
  84. package/dist/lib/task/verification-config.js +14 -0
  85. package/dist/lib/task/verification-engine.js +906 -0
  86. package/dist/lib/task/verification-review.js +3 -0
  87. package/dist/lib/task/verification-types.js +2 -0
  88. package/dist/lib/task/verification.js +113 -0
  89. package/dist/lib/task/workflow-warning-intents.js +131 -0
  90. package/dist/lib/task/workflow-warnings.js +10 -78
  91. package/dist/lib/task/write.js +241 -0
  92. package/lib/decide.ts +57 -97
  93. package/lib/defaults.json +1 -0
  94. package/lib/git/review-snapshot.ts +73 -0
  95. package/lib/git/workflow.ts +101 -0
  96. package/lib/internal/git-workflow.ts +37 -0
  97. package/lib/internal/platform-checks.ts +101 -0
  98. package/lib/internal/platform-comment.ts +99 -0
  99. package/lib/internal/platform-context.ts +33 -0
  100. package/lib/internal/platform-issue.ts +116 -0
  101. package/lib/internal/platform-pr.ts +119 -0
  102. package/lib/internal/release-workflow.ts +186 -0
  103. package/lib/internal/task-artifact.ts +47 -0
  104. package/lib/internal/task-context.ts +35 -0
  105. package/lib/internal/task-event.ts +51 -0
  106. package/lib/internal/task-ledger.ts +86 -0
  107. package/lib/internal/task-lifecycle.ts +41 -0
  108. package/lib/internal/task-short-id.ts +55 -0
  109. package/lib/internal/task-snapshot.ts +32 -0
  110. package/lib/internal/task-verify.ts +33 -0
  111. package/lib/internal/task-warning.ts +50 -0
  112. package/lib/platform/adapters.ts +30 -0
  113. package/lib/platform/context.ts +164 -0
  114. package/lib/platform/github-client.ts +146 -0
  115. package/lib/platform/issue-comments.ts +479 -0
  116. package/lib/platform/issue-metadata.ts +250 -0
  117. package/lib/platform/issues.ts +691 -0
  118. package/lib/platform/metadata-labels.ts +33 -0
  119. package/lib/platform/pr-checks.ts +246 -0
  120. package/lib/platform/pr-summary.ts +90 -0
  121. package/lib/platform/pull-request-metadata.ts +69 -0
  122. package/lib/platform/pull-requests.ts +380 -0
  123. package/lib/platform/releases.ts +71 -0
  124. package/lib/platform/types.ts +74 -0
  125. package/lib/platform/verification-required.ts +83 -0
  126. package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
  127. package/lib/platform/verification.ts +11 -0
  128. package/lib/release/channels.ts +30 -0
  129. package/lib/release/workflow.ts +31 -0
  130. package/lib/render.ts +3 -2
  131. package/lib/run/index.ts +25 -7
  132. package/lib/sandbox/capture.ts +29 -3
  133. package/lib/sandbox/commands/create.ts +43 -25
  134. package/lib/sandbox/commands/enter.ts +38 -11
  135. package/lib/sandbox/commands/list-running.ts +10 -8
  136. package/lib/sandbox/commands/show.ts +2 -2
  137. package/lib/sandbox/commands/start.ts +50 -16
  138. package/lib/sandbox/index.ts +6 -6
  139. package/lib/sandbox/mounts.ts +55 -0
  140. package/lib/sandbox/recovery.ts +828 -0
  141. package/lib/sandbox/task-resolver.ts +5 -1
  142. package/lib/sandbox/tools.ts +31 -0
  143. package/lib/server/protocol.ts +5 -5
  144. package/lib/task/activity-log.ts +62 -0
  145. package/lib/task/artifact-lifecycle.ts +484 -0
  146. package/lib/task/command-options.ts +32 -0
  147. package/lib/task/commands/cat.ts +22 -9
  148. package/lib/task/commands/decisions.ts +49 -47
  149. package/lib/task/commands/files.ts +14 -6
  150. package/lib/task/commands/grep.ts +34 -7
  151. package/lib/task/commands/issue-body.ts +16 -16
  152. package/lib/task/commands/log.ts +17 -70
  153. package/lib/task/commands/show.ts +14 -6
  154. package/lib/task/commands/status.ts +17 -7
  155. package/lib/task/decision-intents.ts +163 -0
  156. package/lib/task/decision-items.ts +64 -0
  157. package/lib/task/events.ts +320 -0
  158. package/lib/task/frontmatter.ts +202 -2
  159. package/lib/task/implementation-inputs.ts +137 -0
  160. package/lib/task/index.ts +12 -9
  161. package/lib/task/issue-form.ts +20 -6
  162. package/lib/task/ledger-intents.ts +201 -0
  163. package/lib/task/ledger.ts +77 -31
  164. package/lib/task/lifecycle.ts +458 -0
  165. package/lib/task/resolve-ref.ts +197 -36
  166. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  167. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +17 -12
  168. package/lib/task/sections.ts +486 -4
  169. package/lib/task/short-id.ts +403 -9
  170. package/lib/task/snapshot.ts +143 -0
  171. package/lib/task/verification-checks.ts +9 -0
  172. package/lib/task/verification-config.ts +20 -0
  173. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +199 -406
  174. package/lib/task/verification-review.ts +9 -0
  175. package/lib/task/verification-types.ts +29 -0
  176. package/lib/task/verification.ts +156 -0
  177. package/lib/task/workflow-warning-intents.ts +142 -0
  178. package/lib/task/workflow-warnings.ts +10 -78
  179. package/lib/task/write.ts +468 -0
  180. package/package.json +4 -2
  181. package/templates/.agents/README.en.md +4 -3
  182. package/templates/.agents/README.zh-CN.md +4 -3
  183. package/templates/.agents/rules/README.en.md +6 -5
  184. package/templates/.agents/rules/README.zh-CN.md +6 -5
  185. package/templates/.agents/rules/create-issue.en.md +1 -1
  186. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  187. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  188. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  189. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  190. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  191. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  192. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  193. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  194. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  195. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  196. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  197. package/templates/.agents/rules/issue-sync.en.md +1 -1
  198. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  199. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  200. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  201. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  202. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  203. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  204. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  205. package/templates/.agents/rules/next-step-output.en.md +12 -11
  206. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  207. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  208. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  209. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  210. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  211. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  212. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  213. package/templates/.agents/rules/pr-sync.en.md +30 -3
  214. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  215. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  216. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  217. package/templates/.agents/rules/review-handshake.en.md +8 -5
  218. package/templates/.agents/rules/review-handshake.zh-CN.md +8 -5
  219. package/templates/.agents/rules/task-management.en.md +11 -2
  220. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  221. package/templates/.agents/rules/task-short-id.en.md +25 -29
  222. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  223. package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
  224. package/templates/.agents/scripts/task-short-id.js +71 -533
  225. package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
  226. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
  227. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  228. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  229. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  230. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  231. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  232. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  233. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  234. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  235. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  236. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  237. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  238. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  239. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  240. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  241. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  242. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  243. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  244. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  245. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  246. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  247. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  248. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  249. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  250. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  251. package/templates/.agents/skills/commit/SKILL.en.md +13 -11
  252. package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
  253. package/templates/.agents/skills/commit/config/verify.json +1 -2
  254. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  255. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  256. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  257. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  258. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  259. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  260. package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
  261. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
  262. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  263. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  264. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  265. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  266. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  267. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  268. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  269. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  270. package/templates/.agents/skills/complete-task/config/verify.en.json +11 -7
  271. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -7
  272. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  273. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  274. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  275. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  276. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  277. package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
  278. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
  279. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  280. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  281. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  282. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  283. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  284. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  285. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  286. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  287. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  288. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  289. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  290. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  291. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  292. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  293. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  294. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  295. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  296. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  297. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  298. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  299. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  300. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  301. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  302. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  303. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  304. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  305. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  306. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  307. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  308. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  309. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  310. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  311. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  312. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  313. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  314. package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
  315. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
  316. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  317. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  318. package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
  319. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
  320. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  321. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  322. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  323. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  324. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  325. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  326. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  327. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  328. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  329. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  330. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  331. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  332. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
  333. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
  334. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
  335. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  336. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  337. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  338. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  339. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  340. package/templates/.agents/templates/task.en.md +6 -1
  341. package/templates/.agents/templates/task.zh-CN.md +6 -1
  342. package/templates/.claude/commands/analyze-task.en.md +1 -1
  343. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  344. package/templates/.claude/commands/block-task.en.md +1 -1
  345. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  346. package/templates/.claude/commands/cancel-task.en.md +1 -1
  347. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  348. package/templates/.claude/commands/check-task.en.md +1 -1
  349. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  350. package/templates/.claude/commands/code-task.en.md +1 -1
  351. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  352. package/templates/.claude/commands/commit.en.md +1 -0
  353. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  354. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  355. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  356. package/templates/.claude/commands/complete-task.en.md +1 -1
  357. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  358. package/templates/.claude/commands/create-pr.en.md +1 -1
  359. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  360. package/templates/.claude/commands/plan-task.en.md +1 -1
  361. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  362. package/templates/.claude/commands/review-analysis.en.md +1 -1
  363. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  364. package/templates/.claude/commands/review-code.en.md +1 -1
  365. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  366. package/templates/.claude/commands/review-plan.en.md +1 -1
  367. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  368. package/templates/.claude/commands/watch-pr.en.md +1 -1
  369. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  370. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  371. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  372. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  373. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  374. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  375. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  376. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  377. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  378. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  379. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  380. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  381. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  382. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  383. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  384. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  385. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  386. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  387. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  388. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  389. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  390. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  391. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  392. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  393. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  394. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  395. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  396. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  397. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  398. package/templates/.git-hooks/check-large-files.cjs +92 -0
  399. package/templates/.git-hooks/check-version-format.sh +5 -1
  400. package/templates/.git-hooks/pre-commit +1 -0
  401. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  402. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  403. package/templates/.opencode/commands/check-task.en.md +1 -1
  404. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  405. package/templates/.opencode/commands/code-task.en.md +1 -1
  406. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  407. package/templates/.opencode/commands/commit.en.md +2 -0
  408. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  409. package/templates/.opencode/commands/complete-task.en.md +1 -1
  410. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  411. package/templates/.opencode/commands/plan-task.en.md +1 -1
  412. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  413. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  414. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  415. package/templates/.opencode/commands/review-code.en.md +1 -1
  416. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  417. package/templates/.opencode/commands/review-plan.en.md +1 -1
  418. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  419. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
  420. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  421. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
  422. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  423. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  424. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  425. 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';
@@ -999,6 +1001,7 @@ export async function create(args) {
999
1001
  const baseBranch = base ?? runSafe('git', ['-C', effectiveConfig.repoRoot, 'branch', '--show-current']);
1000
1002
  const expectedImageSignature = buildImageSignature(preparedDockerfile, tools);
1001
1003
  const engine = detectEngine(effectiveConfig);
1004
+ let createdTmpfsSeedPlan = [];
1002
1005
  p.intro(pc.cyan('AI Sandbox'));
1003
1006
  p.log.info(`Project: ${pc.bold(effectiveConfig.project)} | Branch: ${pc.bold(branch)} | Base: ${pc.bold(baseBranch || 'HEAD')}`);
1004
1007
  if (credentialOutcome.status === 'SKIPPED') {
@@ -1209,9 +1212,12 @@ export async function create(args) {
1209
1212
  branch,
1210
1213
  repoRoot: effectiveConfig.repoRoot
1211
1214
  });
1212
- const shellConfigVolumes = hostShellConfig.mounts.flatMap(({ hostPath, containerPath }) => [
1215
+ const coreVolumes = sandboxCoreBindMounts(effectiveConfig, branch, {
1216
+ worktree,
1217
+ shellConfigHostDir: hostShellConfig.hostDir
1218
+ }).flatMap(({ hostPaths, containerPath, readOnly }) => [
1213
1219
  '-v',
1214
- volumeArg(engine, hostPath, containerPath, ':ro')
1220
+ volumeArg(engine, hostPaths[0], containerPath, readOnly ? ':ro' : '')
1215
1221
  ]);
1216
1222
  // Mount each declared seed read-only at an isolated staging path.
1217
1223
  // After docker run mounts the empty tmpfs, the container's default
@@ -1220,14 +1226,17 @@ export async function create(args) {
1220
1226
  // stale runtime files (logs_2.sqlite, sessions, etc.) on the host from
1221
1227
  // being exposed or written through.
1222
1228
  tmpfsSeedPlan = effectiveResolvedTools.flatMap(({ tool, dir }) => (tool.tmpfs?.seed ?? []).flatMap((entry, index) => {
1229
+ const targetPath = tmpfsSeedTargetPath(tool.containerMount, entry);
1223
1230
  const hostPath = path.join(dir, entry);
1224
1231
  if (!fs.existsSync(hostPath)) {
1225
1232
  return [];
1226
1233
  }
1227
- const stagingPath = path.posix.join('/run/agent-infra/tmpfs-seeds', tool.id, String(index));
1234
+ const stagingPath = tmpfsSeedStagingPath(tool.id, index);
1228
1235
  return [{
1236
+ toolId: tool.id,
1237
+ containerMount: tool.containerMount,
1229
1238
  stagingPath,
1230
- targetPath: path.posix.join(tool.containerMount, entry),
1239
+ targetPath,
1231
1240
  volumeArgs: ['-v', volumeArg(engine, hostPath, stagingPath, ':ro')]
1232
1241
  }];
1233
1242
  }));
@@ -1258,14 +1267,7 @@ export async function create(args) {
1258
1267
  sandboxLabel(effectiveConfig),
1259
1268
  '--label',
1260
1269
  `${sandboxBranchLabel(effectiveConfig)}=${branch}`,
1261
- '-v',
1262
- volumeArg(engine, worktree, '/workspace'),
1263
- '-v',
1264
- volumeArg(engine, workspaceDir, '/workspace/.agents/workspace'),
1265
- '-v',
1266
- volumeArg(engine, shareCommon, '/share/common'),
1267
- '-v',
1268
- volumeArg(engine, shareBranch, '/share/branch'),
1270
+ ...coreVolumes,
1269
1271
  ...buildClipboardVolumeArgs(engine, effectiveConfig.home),
1270
1272
  '-v',
1271
1273
  volumeArg(engine, path.join(effectiveConfig.repoRoot, '.git'), `${toEnginePath(engine, effectiveConfig.repoRoot)}/.git`),
@@ -1274,25 +1276,30 @@ export async function create(args) {
1274
1276
  ...tmpfsArgs,
1275
1277
  ...tmpfsSeedPlan.flatMap(({ volumeArgs }) => volumeArgs),
1276
1278
  ...liveMountVolumes,
1277
- ...shellConfigVolumes,
1278
1279
  ...envFile.dockerArgs,
1279
1280
  ...tzFlags,
1280
1281
  '-w',
1281
1282
  '/workspace',
1282
1283
  effectiveConfig.imageName
1283
1284
  ]);
1285
+ createdTmpfsSeedPlan = tmpfsSeedPlan;
1284
1286
  }
1285
1287
  finally {
1286
1288
  envFile.cleanup();
1287
1289
  }
1288
- for (const { stagingPath, targetPath } of tmpfsSeedPlan) {
1289
- runEngineTaskCommand(engine, 'docker', [
1290
- 'exec', container, 'mkdir', '-p', path.posix.dirname(targetPath)
1291
- ]);
1292
- runEngineTaskCommand(engine, 'docker', [
1293
- 'exec', container, 'cp', '-R', '--', stagingPath, targetPath
1294
- ]);
1295
- }
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
+ });
1296
1303
  // Belt-and-suspenders: re-create the four shell-config symlinks at
1297
1304
  // runtime so users with a custom `sandbox.dockerfile` (which won't
1298
1305
  // include the ai-tools.dockerfile symlink fragment) still get
@@ -1346,6 +1353,13 @@ export async function create(args) {
1346
1353
  preparedDockerfile.cleanup();
1347
1354
  }
1348
1355
  p.log.step('Verifying setup...');
1356
+ assertFreshSandboxReady({
1357
+ config: effectiveConfig,
1358
+ engine,
1359
+ branch,
1360
+ container,
1361
+ copiedEntries: createdTmpfsSeedPlan
1362
+ });
1349
1363
  const runningContainers = runSafeEngine(engine, 'docker', ['ps', '--format', '{{.Names}}']).split('\n');
1350
1364
  const checks = [
1351
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();
@@ -1,36 +1,74 @@
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 { fetchSandboxRows, resolveBranchArg, selectSandboxContainer, startSandboxContainer } from './list-running.js';
5
- const USAGE = `Usage: ai sandbox start <branch | TASK-id | N | '#N'>
4
+ import { ensureSandboxReady } from '../recovery.js';
5
+ import { fetchSandboxRows, resolveBranchArg, selectSandboxContainer, } from './list-running.js';
6
+ const USAGE = `Usage: ai sandbox start [--recreate] <branch | TASK-id | N>
6
7
 
7
8
  Start an existing sandbox container that has stopped (for example after the
8
9
  Docker daemon was restarted or replaced). The container must already exist:
9
10
  if none is found, run 'ai sandbox create <branch>' first. A container that is
10
- already running is left untouched.`;
11
+ already running is checked without modifying healthy runtime state. --recreate
12
+ allows container-only replacement after in-place recovery fails.`;
13
+ export function parseStartArgs(args) {
14
+ let recreate = false;
15
+ let help = false;
16
+ const positionals = [];
17
+ for (const arg of args) {
18
+ if (arg === '--recreate') {
19
+ recreate = true;
20
+ }
21
+ else if (arg === '--help' || arg === '-h') {
22
+ help = true;
23
+ }
24
+ else if (arg.startsWith('-')) {
25
+ throw new Error(`Unknown option: ${arg}\n${USAGE}`);
26
+ }
27
+ else {
28
+ positionals.push(arg);
29
+ }
30
+ }
31
+ if (!help && positionals.length !== 1) {
32
+ throw new Error(USAGE);
33
+ }
34
+ return { target: positionals[0] ?? '', recreate, help };
35
+ }
11
36
  export async function start(args) {
12
- if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
37
+ if (args.length === 0) {
38
+ process.stdout.write(`${USAGE}\n`);
39
+ process.exitCode = 1;
40
+ return;
41
+ }
42
+ const parsed = parseStartArgs(args);
43
+ if (parsed.help) {
13
44
  process.stdout.write(`${USAGE}\n`);
14
- if (args.length === 0) {
15
- process.exitCode = 1;
16
- }
17
45
  return;
18
46
  }
19
- const [firstArg = ''] = args;
20
47
  const config = loadConfig();
21
48
  const engine = detectEngine(config);
22
- const branch = resolveBranchArg(firstArg, { repoRoot: config.repoRoot });
49
+ const branch = resolveBranchArg(parsed.target, { repoRoot: config.repoRoot });
23
50
  assertValidBranchName(branch);
24
51
  const { running, nonRunning } = fetchSandboxRows(engine, sandboxLabel(config), sandboxBranchLabel(config));
25
52
  const found = selectSandboxContainer([...running, ...nonRunning], containerNameCandidates(config, branch));
26
53
  if (!found) {
27
54
  throw new Error(`No sandbox container for branch '${branch}'. Run 'ai sandbox create ${branch}' to create one.`);
28
55
  }
29
- if (found.running) {
30
- process.stdout.write(`Sandbox '${found.name}' is already running.\n`);
31
- return;
32
- }
33
- startSandboxContainer(engine, found.name);
34
- process.stdout.write(`Started sandbox '${found.name}'.\n`);
56
+ const ready = await ensureSandboxReady({
57
+ config,
58
+ engine,
59
+ branch,
60
+ row: found,
61
+ allowRecreate: parsed.recreate,
62
+ recreate: async (targetBranch) => {
63
+ const { create } = await import('./create.js');
64
+ await create([targetBranch, '--no-refresh']);
65
+ }
66
+ });
67
+ const message = ready.path === 'healthy'
68
+ ? `Sandbox '${ready.container}' is already running and healthy.`
69
+ : ready.path === 'recreated'
70
+ ? `Recreated sandbox '${ready.container}' and verified readiness.`
71
+ : `Recovered sandbox '${ready.container}' and verified readiness.`;
72
+ process.stdout.write(`${message}\n`);
35
73
  }
36
74
  //# sourceMappingURL=start.js.map
@@ -2,14 +2,14 @@ const USAGE = `Usage: ai sandbox <command> [options]
2
2
 
3
3
  Commands:
4
4
  create <branch> [base] Create a sandbox (VM + image + worktree + container)
5
- exec <branch | TASK-id | N | '#N'> [cmd...]
5
+ exec [--recreate] <branch | TASK-id | N> [cmd...]
6
6
  Enter sandbox or run a command. N (bare) is the
7
7
  recommended form for task short ids (e.g.
8
- 'ai sandbox exec 11'); '#N' is also accepted.
8
+ 'ai sandbox exec 11').
9
9
  ls List sandboxes for the current project (the '#'
10
10
  column is a display-only row number; the 'SHORT'
11
11
  column shows the active task short id, '-' if none)
12
- show <branch | TASK-id | N | '#N'>
12
+ show <branch | TASK-id | N>
13
13
  Show one sandbox's worktree and per-tool state paths
14
14
  prune [--dry-run] Remove orphaned per-branch state dirs
15
15
  rebuild [--quiet] [--refresh]
@@ -18,9 +18,9 @@ Commands:
18
18
  rm <branch> | --all | --purge
19
19
  Remove one sandbox, all sandboxes not bound to an
20
20
  active task (--all), or tear down everything (--purge)
21
- start <branch | TASK-id | N | '#N'>
22
- Start an existing stopped sandbox container
23
- (e.g. after the Docker daemon restarted)
21
+ start [--recreate] <branch | TASK-id | N>
22
+ Verify or recover an existing sandbox container;
23
+ optionally replace only the container on failure
24
24
  vm status|start|stop Manage the sandbox VM (macOS) or check the backend (Windows)
25
25
 
26
26
  Run 'ai sandbox <command> --help' for details.`;