@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,562 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { containerNameCandidates, sandboxBranchLabel, sandboxLabel } from './constants.js';
4
+ import { toEnginePath } from './engines/wsl2-paths.js';
5
+ import { sandboxCoreBindMounts } from './mounts.js';
6
+ import { runEngine, runOkEngine, runVerboseEngine } from './shell.js';
7
+ import { declaredTmpfsSeedEntries, resolveTools, toolConfigDirCandidates } from './tools.js';
8
+ import { fetchSandboxRows, selectSandboxContainer, startSandboxContainer } from './commands/list-running.js';
9
+ function findingKey(finding) {
10
+ return `${finding.repairKind}:${finding.path ?? finding.seed?.targetPath ?? finding.message}`;
11
+ }
12
+ export function classifySandboxRecovery(snapshot) {
13
+ const findings = [];
14
+ if (!snapshot.identityOk) {
15
+ findings.push({
16
+ repairKind: 'hard-failure',
17
+ message: 'Container identity does not match the requested sandbox branch.'
18
+ });
19
+ }
20
+ for (const mount of snapshot.mounts) {
21
+ if (mount.actualType !== mount.expectedType
22
+ || !mount.sourceMatches
23
+ || mount.actualRW !== mount.expectedRW
24
+ || !mount.sourceAccessible) {
25
+ findings.push({
26
+ repairKind: 'hard-failure',
27
+ message: `Expected ${mount.expectedType} mount at ${mount.path}`
28
+ + `${mount.expectedSource === null ? '' : ` from ${mount.expectedSource}`}`
29
+ + ` with RW=${mount.expectedRW}, found ${mount.actualType ?? 'none'}`
30
+ + `${mount.actualSource === null ? '' : ` from ${mount.actualSource}`}`
31
+ + ` with RW=${mount.actualRW ?? 'unknown'}.`,
32
+ path: mount.path
33
+ });
34
+ }
35
+ }
36
+ for (const mount of snapshot.tmpfs) {
37
+ if (!mount.permissionsOk || !mount.writable) {
38
+ findings.push({
39
+ repairKind: 'permissions',
40
+ message: `Tmpfs ${mount.path} is not owned and writable by devuser with mode 0700.`,
41
+ path: mount.path
42
+ });
43
+ }
44
+ }
45
+ for (const seed of snapshot.seeds) {
46
+ if (!seed.mounted) {
47
+ continue;
48
+ }
49
+ if (seed.targetState === 'missing' || seed.targetState === 'wrong-type') {
50
+ findings.push({
51
+ repairKind: 'missing-seed',
52
+ message: `Runtime seed target ${seed.targetPath} must be restored from staging.`,
53
+ path: seed.targetPath,
54
+ seed: {
55
+ toolId: seed.toolId,
56
+ containerMount: seed.containerMount ?? seed.targetPath.slice(0, seed.targetPath.lastIndexOf('/')),
57
+ stagingPath: seed.stagingPath,
58
+ targetPath: seed.targetPath
59
+ }
60
+ });
61
+ }
62
+ else if (seed.targetState === 'inaccessible') {
63
+ findings.push({
64
+ repairKind: 'hard-failure',
65
+ message: `Runtime seed target ${seed.targetPath} exists but is not accessible to devuser.`,
66
+ path: seed.targetPath
67
+ });
68
+ }
69
+ }
70
+ if (!snapshot.aliasesReadable) {
71
+ findings.push({
72
+ repairKind: 'hard-failure',
73
+ message: 'Sandbox shell aliases are not readable by devuser.',
74
+ path: '/home/devuser/.bash_aliases'
75
+ });
76
+ }
77
+ if (snapshot.codex) {
78
+ if (!snapshot.codex.commandAvailable) {
79
+ findings.push({
80
+ repairKind: 'hard-failure',
81
+ message: 'Codex is not available on PATH inside the sandbox.'
82
+ });
83
+ }
84
+ if (!snapshot.codex.stateWritable) {
85
+ findings.push({
86
+ repairKind: 'permissions',
87
+ message: 'Codex state directory is not writable by devuser.',
88
+ path: '/home/devuser/.codex'
89
+ });
90
+ }
91
+ if (snapshot.codex.promptsSourceExists && !snapshot.codex.promptsValid) {
92
+ findings.push({
93
+ repairKind: 'builtin-link',
94
+ message: 'Codex prompts link does not point to the workspace commands directory.',
95
+ path: '/home/devuser/.codex/prompts'
96
+ });
97
+ }
98
+ }
99
+ const seen = new Set();
100
+ return findings.filter((finding) => {
101
+ const key = findingKey(finding);
102
+ if (seen.has(key))
103
+ return false;
104
+ seen.add(key);
105
+ return true;
106
+ });
107
+ }
108
+ function inspectContainer(engine, container, runFn) {
109
+ const raw = runFn(engine, 'docker', ['inspect', container]);
110
+ const parsed = JSON.parse(raw);
111
+ if (!Array.isArray(parsed) || !parsed[0] || typeof parsed[0] !== 'object') {
112
+ throw new Error(`Unable to inspect sandbox container '${container}'.`);
113
+ }
114
+ return parsed[0];
115
+ }
116
+ function probe(engine, container, script, args, runOkFn, user = 'devuser') {
117
+ return runOkFn(engine, 'docker', [
118
+ 'exec', '--user', user, container, 'sh', '-c', script, 'agent-infra-recovery', ...args
119
+ ]);
120
+ }
121
+ function normalizeMountSource(engine, source) {
122
+ const normalized = toEnginePath(engine, source).replace(/\\/g, '/').replace(/\/+$/, '');
123
+ return /^[A-Za-z]:\//.test(normalized)
124
+ ? `${normalized[0].toLowerCase()}${normalized.slice(1)}`
125
+ : normalized;
126
+ }
127
+ function sourceCandidates(engine, hostPath) {
128
+ const candidates = [hostPath];
129
+ try {
130
+ candidates.push(fs.realpathSync(hostPath));
131
+ }
132
+ catch {
133
+ // The access check below reports a missing or inaccessible host source.
134
+ }
135
+ return [...new Set(candidates.map((candidate) => normalizeMountSource(engine, candidate)))];
136
+ }
137
+ function sameHostSource(left, right) {
138
+ try {
139
+ const leftStat = fs.statSync(left, { bigint: true });
140
+ const rightStat = fs.statSync(right, { bigint: true });
141
+ return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ }
147
+ function hostSourceAccessible(hostPath, writable) {
148
+ try {
149
+ fs.accessSync(hostPath, fs.constants.R_OK | (writable ? fs.constants.W_OK : 0));
150
+ return true;
151
+ }
152
+ catch {
153
+ return false;
154
+ }
155
+ }
156
+ function expectedMounts(params) {
157
+ const { config, branch, actualMounts } = params;
158
+ const tools = resolveTools(config);
159
+ const core = sandboxCoreBindMounts(config, branch).map((mount) => ({
160
+ path: mount.containerPath,
161
+ expectedType: 'bind',
162
+ hostPaths: mount.hostPaths,
163
+ expectedRW: !mount.readOnly
164
+ }));
165
+ const live = tools.flatMap((tool) => (tool.hostLiveMounts ?? []).flatMap(({ hostPath, containerSubpath }) => {
166
+ const destination = path.posix.join(tool.containerMount, containerSubpath);
167
+ if (!fs.existsSync(hostPath) && !actualMounts.has(destination))
168
+ return [];
169
+ return [{
170
+ path: destination,
171
+ expectedType: 'bind',
172
+ hostPaths: [hostPath],
173
+ expectedRW: true
174
+ }];
175
+ }));
176
+ const persistentTools = tools
177
+ .filter((tool) => !tool.tmpfs && actualMounts.has(tool.containerMount))
178
+ .map((tool) => ({
179
+ path: tool.containerMount,
180
+ expectedType: 'bind',
181
+ hostPaths: toolConfigDirCandidates(tool, config.project, branch),
182
+ expectedRW: true
183
+ }));
184
+ const staging = tools.flatMap((tool) => (tool.tmpfs?.seed ?? []).flatMap((seedEntry, index) => {
185
+ const stagingPath = `/run/agent-infra/tmpfs-seeds/${tool.id}/${index}`;
186
+ if (!actualMounts.has(stagingPath))
187
+ return [];
188
+ return [{
189
+ path: stagingPath,
190
+ expectedType: 'bind',
191
+ hostPaths: toolConfigDirCandidates(tool, config.project, branch)
192
+ .map((candidate) => path.join(candidate, seedEntry)),
193
+ expectedRW: false
194
+ }];
195
+ }));
196
+ return [
197
+ ...core,
198
+ ...persistentTools,
199
+ ...live,
200
+ ...staging,
201
+ ...tools
202
+ .filter((tool) => tool.tmpfs)
203
+ .map((tool) => ({
204
+ path: tool.containerMount,
205
+ expectedType: 'tmpfs',
206
+ hostPaths: [],
207
+ expectedRW: true
208
+ }))
209
+ ];
210
+ }
211
+ function targetState(engine, container, seed, runOkFn) {
212
+ const exists = probe(engine, container, 'test -e "$1" || test -L "$1"', [seed.targetPath], runOkFn);
213
+ if (!exists)
214
+ return 'missing';
215
+ const compatible = probe(engine, container, 'if test -d "$1"; then test -d "$2"; else test -f "$2"; fi', [seed.stagingPath, seed.targetPath], runOkFn);
216
+ if (!compatible)
217
+ return 'wrong-type';
218
+ const readable = runOkFn(engine, 'docker', [
219
+ 'exec', '--user', 'devuser', container, 'test', '-r', seed.targetPath
220
+ ]);
221
+ const writable = runOkFn(engine, 'docker', [
222
+ 'exec', '--user', 'devuser', container, 'test', '-w', seed.targetPath
223
+ ]);
224
+ return readable && writable ? 'ok' : 'inaccessible';
225
+ }
226
+ export function collectSandboxRecoverySnapshot(params) {
227
+ const runFn = params.deps?.run ?? runEngine;
228
+ const runOkFn = params.deps?.runOk ?? runOkEngine;
229
+ const inspection = inspectContainer(params.engine, params.container, runFn);
230
+ const mounts = Array.isArray(inspection.Mounts) ? inspection.Mounts : [];
231
+ const mountsByDestination = new Map(mounts.flatMap((mount) => typeof mount.Destination === 'string'
232
+ ? [[mount.Destination, mount]]
233
+ : []));
234
+ const declaredTmpfs = inspection.HostConfig?.Tmpfs;
235
+ if (declaredTmpfs && typeof declaredTmpfs === 'object' && !Array.isArray(declaredTmpfs)) {
236
+ for (const [destination, rawOptions] of Object.entries(declaredTmpfs)) {
237
+ if (mountsByDestination.has(destination) || typeof rawOptions !== 'string')
238
+ continue;
239
+ const options = rawOptions.split(',').map((option) => option.trim());
240
+ mountsByDestination.set(destination, {
241
+ Type: 'tmpfs',
242
+ Source: '',
243
+ Destination: destination,
244
+ RW: !options.includes('ro')
245
+ });
246
+ }
247
+ }
248
+ const tools = resolveTools(params.config);
249
+ const seeds = declaredTmpfsSeedEntries(tools).map((seed) => {
250
+ const mounted = mountsByDestination.get(seed.stagingPath)?.Type === 'bind';
251
+ return {
252
+ toolId: seed.toolId,
253
+ containerMount: seed.containerMount,
254
+ stagingPath: seed.stagingPath,
255
+ targetPath: seed.targetPath,
256
+ mounted,
257
+ targetState: mounted
258
+ ? targetState(params.engine, params.container, seed, runOkFn)
259
+ : 'missing'
260
+ };
261
+ });
262
+ const tmpfs = tools.filter((tool) => tool.tmpfs).map((tool) => ({
263
+ path: tool.containerMount,
264
+ permissionsOk: probe(params.engine, params.container, 'test "$(stat -c %u:%g:%a -- "$1")" = "$(id -u devuser):$(id -g devuser):700"', [tool.containerMount], runOkFn),
265
+ writable: probe(params.engine, params.container, 'probe="$1/.agent-infra-ready-$$"; trap \'rm -f -- "$probe"\' EXIT; : > "$probe"', [tool.containerMount], runOkFn)
266
+ }));
267
+ const labels = inspection.Config?.Labels ?? {};
268
+ const branchLabel = labels[sandboxBranchLabel(params.config)];
269
+ const hasCodex = tools.some((tool) => tool.id === 'codex');
270
+ const mountSnapshots = expectedMounts({
271
+ config: params.config,
272
+ branch: params.branch,
273
+ engine: params.engine,
274
+ actualMounts: mountsByDestination
275
+ }).map((expected) => {
276
+ const actual = mountsByDestination.get(expected.path);
277
+ const actualSource = typeof actual?.Source === 'string' ? actual.Source : null;
278
+ const actualSourceCandidates = actualSource === null
279
+ ? []
280
+ : sourceCandidates(params.engine, actualSource);
281
+ const matchedHostPath = expected.hostPaths.find((hostPath) => sourceCandidates(params.engine, hostPath).some((candidate) => actualSourceCandidates.includes(candidate))
282
+ || (actualSource !== null && sameHostSource(hostPath, actualSource)));
283
+ const sourceMatches = expected.expectedType === 'tmpfs'
284
+ ? actualSource === '' || actualSource === null
285
+ : matchedHostPath !== undefined;
286
+ return {
287
+ path: expected.path,
288
+ expectedType: expected.expectedType,
289
+ actualType: typeof actual?.Type === 'string' ? actual.Type : null,
290
+ expectedSource: expected.hostPaths[0]
291
+ ? normalizeMountSource(params.engine, expected.hostPaths[0])
292
+ : null,
293
+ actualSource,
294
+ sourceMatches,
295
+ expectedRW: expected.expectedRW,
296
+ actualRW: typeof actual?.RW === 'boolean' ? actual.RW : null,
297
+ sourceAccessible: expected.expectedType === 'tmpfs'
298
+ ? true
299
+ : matchedHostPath !== undefined
300
+ && hostSourceAccessible(matchedHostPath, expected.expectedRW)
301
+ };
302
+ });
303
+ return {
304
+ identityOk: typeof inspection.Id === 'string'
305
+ && inspection.Id.length > 0
306
+ && branchLabel === params.branch,
307
+ mounts: mountSnapshots,
308
+ tmpfs,
309
+ seeds,
310
+ aliasesReadable: probe(params.engine, params.container, 'test -r "$1"', ['/home/devuser/.bash_aliases'], runOkFn),
311
+ codex: hasCodex
312
+ ? {
313
+ commandAvailable: probe(params.engine, params.container, 'command -v codex', [], runOkFn),
314
+ stateWritable: probe(params.engine, params.container, 'probe="$1/.agent-infra-codex-state-$$"; trap \'rm -f -- "$probe"\' EXIT; : > "$probe"', ['/home/devuser/.codex'], runOkFn),
315
+ promptsSourceExists: probe(params.engine, params.container, 'test -d "$1"', ['/workspace/.codex/commands'], runOkFn),
316
+ promptsValid: probe(params.engine, params.container, 'test "$(readlink -- "$1")" = "$2"', ['/home/devuser/.codex/prompts', '/workspace/.codex/commands'], runOkFn)
317
+ }
318
+ : undefined
319
+ };
320
+ }
321
+ export function prepareTmpfsMounts(params) {
322
+ const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
323
+ for (const mountPath of params.mountPaths) {
324
+ runVerboseFn(params.engine, 'docker', [
325
+ 'exec', '--user', 'root', params.container, 'chown', 'devuser:', '--', mountPath
326
+ ]);
327
+ runVerboseFn(params.engine, 'docker', [
328
+ 'exec', '--user', 'root', params.container, 'chmod', '0700', '--', mountPath
329
+ ]);
330
+ }
331
+ }
332
+ export function hydrateTmpfsSeedEntries(params) {
333
+ const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
334
+ for (const entry of params.entries) {
335
+ if (params.replace) {
336
+ runVerboseFn(params.engine, 'docker', [
337
+ 'exec', '--user', 'devuser', params.container, 'rm', '-rf', '--', entry.targetPath
338
+ ]);
339
+ }
340
+ runVerboseFn(params.engine, 'docker', [
341
+ 'exec', '--user', 'devuser', params.container, 'mkdir', '-p',
342
+ entry.targetPath.slice(0, entry.targetPath.lastIndexOf('/'))
343
+ ]);
344
+ runVerboseFn(params.engine, 'docker', [
345
+ 'exec', '--user', 'devuser', params.container, 'cp', '-R', '--',
346
+ entry.stagingPath, entry.targetPath
347
+ ]);
348
+ }
349
+ validateTmpfsSeedEntries(params);
350
+ }
351
+ export function validateTmpfsSeedEntries(params) {
352
+ const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
353
+ const runOkFn = params.deps?.runOk ?? runOkEngine;
354
+ for (const entry of params.entries) {
355
+ runVerboseFn(params.engine, 'docker', [
356
+ 'exec', '--user', 'devuser', params.container, 'diff', '-qr', '--',
357
+ entry.stagingPath, entry.targetPath
358
+ ]);
359
+ const readable = runOkFn(params.engine, 'docker', [
360
+ 'exec', '--user', 'devuser', params.container, 'test', '-r', entry.targetPath
361
+ ]);
362
+ const writable = runOkFn(params.engine, 'docker', [
363
+ 'exec', '--user', 'devuser', params.container, 'test', '-w', entry.targetPath
364
+ ]);
365
+ if (!readable || !writable) {
366
+ throw new Error(`Hydrated seed target ${entry.targetPath} is not writable by devuser.`);
367
+ }
368
+ }
369
+ }
370
+ function mountedSeeds(snapshot) {
371
+ return snapshot.seeds.filter((seed) => seed.mounted).map((seed) => ({
372
+ toolId: seed.toolId,
373
+ containerMount: seed.containerMount ?? seed.targetPath.slice(0, seed.targetPath.lastIndexOf('/')),
374
+ stagingPath: seed.stagingPath,
375
+ targetPath: seed.targetPath
376
+ }));
377
+ }
378
+ function repairFindings(params) {
379
+ const permissionPaths = params.findings
380
+ .filter((finding) => finding.repairKind === 'permissions' && finding.path)
381
+ .map((finding) => finding.path);
382
+ prepareTmpfsMounts({
383
+ engine: params.engine,
384
+ container: params.container,
385
+ mountPaths: [...new Set(permissionPaths)],
386
+ deps: params.deps
387
+ });
388
+ const missingSeeds = params.findings.flatMap((finding) => finding.repairKind === 'missing-seed' && finding.seed ? [finding.seed] : []);
389
+ hydrateTmpfsSeedEntries({
390
+ engine: params.engine,
391
+ container: params.container,
392
+ entries: missingSeeds,
393
+ replace: true,
394
+ deps: params.deps
395
+ });
396
+ const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
397
+ if (params.findings.some((finding) => finding.repairKind === 'builtin-link')) {
398
+ runVerboseFn(params.engine, 'docker', [
399
+ 'exec', '--user', 'devuser', params.container, 'ln', '-sfn',
400
+ '/workspace/.codex/commands', '/home/devuser/.codex/prompts'
401
+ ]);
402
+ }
403
+ }
404
+ function describeFindings(findings) {
405
+ return findings.map((finding) => finding.message).join(' ');
406
+ }
407
+ function assess(params) {
408
+ const snapshot = collectSandboxRecoverySnapshot(params);
409
+ return { snapshot, findings: classifySandboxRecovery(snapshot) };
410
+ }
411
+ export function assertFreshSandboxReady(params) {
412
+ validateTmpfsSeedEntries({
413
+ engine: params.engine,
414
+ container: params.container,
415
+ entries: params.copiedEntries,
416
+ deps: params.deps
417
+ });
418
+ const { findings } = assess(params);
419
+ if (findings.length > 0) {
420
+ throw new Error(`Fresh sandbox readiness check failed: ${describeFindings(findings)}`);
421
+ }
422
+ }
423
+ export async function ensureSandboxReady(params) {
424
+ const deps = params.deps;
425
+ const startFn = deps?.start ?? startSandboxContainer;
426
+ const warnings = [];
427
+ let failure = null;
428
+ try {
429
+ if (!params.row.running) {
430
+ startFn(params.engine, params.row.name);
431
+ const initial = assess({
432
+ config: params.config,
433
+ engine: params.engine,
434
+ branch: params.branch,
435
+ container: params.row.name,
436
+ deps
437
+ });
438
+ if (initial.findings.some((finding) => finding.repairKind === 'hard-failure')) {
439
+ throw new Error(describeFindings(initial.findings.filter((finding) => finding.repairKind === 'hard-failure')));
440
+ }
441
+ const tools = resolveTools(params.config);
442
+ prepareTmpfsMounts({
443
+ engine: params.engine,
444
+ container: params.row.name,
445
+ mountPaths: tools.filter((tool) => tool.tmpfs).map((tool) => tool.containerMount),
446
+ deps
447
+ });
448
+ hydrateTmpfsSeedEntries({
449
+ engine: params.engine,
450
+ container: params.row.name,
451
+ entries: mountedSeeds(initial.snapshot),
452
+ replace: true,
453
+ deps
454
+ });
455
+ let final = assess({
456
+ config: params.config,
457
+ engine: params.engine,
458
+ branch: params.branch,
459
+ container: params.row.name,
460
+ deps
461
+ });
462
+ if (!final.findings.some((finding) => finding.repairKind === 'hard-failure')) {
463
+ repairFindings({
464
+ engine: params.engine,
465
+ container: params.row.name,
466
+ findings: final.findings,
467
+ deps
468
+ });
469
+ final = assess({
470
+ config: params.config,
471
+ engine: params.engine,
472
+ branch: params.branch,
473
+ container: params.row.name,
474
+ deps
475
+ });
476
+ }
477
+ if (final.findings.length > 0) {
478
+ throw new Error(describeFindings(final.findings));
479
+ }
480
+ return { container: params.row.name, path: 'recovered', warnings };
481
+ }
482
+ const initial = assess({
483
+ config: params.config,
484
+ engine: params.engine,
485
+ branch: params.branch,
486
+ container: params.row.name,
487
+ deps
488
+ });
489
+ if (initial.findings.length === 0) {
490
+ return { container: params.row.name, path: 'healthy', warnings };
491
+ }
492
+ if (initial.findings.some((finding) => finding.repairKind === 'hard-failure')) {
493
+ throw new Error(describeFindings(initial.findings));
494
+ }
495
+ let current = initial;
496
+ const permissionFindings = current.findings.filter((finding) => finding.repairKind === 'permissions');
497
+ if (permissionFindings.length > 0) {
498
+ repairFindings({
499
+ engine: params.engine,
500
+ container: params.row.name,
501
+ findings: permissionFindings,
502
+ deps
503
+ });
504
+ current = assess({
505
+ config: params.config,
506
+ engine: params.engine,
507
+ branch: params.branch,
508
+ container: params.row.name,
509
+ deps
510
+ });
511
+ if (current.findings.some((finding) => finding.repairKind === 'hard-failure'
512
+ || finding.repairKind === 'permissions')) {
513
+ throw new Error(describeFindings(current.findings));
514
+ }
515
+ }
516
+ repairFindings({
517
+ engine: params.engine,
518
+ container: params.row.name,
519
+ findings: current.findings,
520
+ deps
521
+ });
522
+ const final = assess({
523
+ config: params.config,
524
+ engine: params.engine,
525
+ branch: params.branch,
526
+ container: params.row.name,
527
+ deps
528
+ });
529
+ if (final.findings.length > 0) {
530
+ throw new Error(describeFindings(final.findings));
531
+ }
532
+ return { container: params.row.name, path: 'recovered', warnings };
533
+ }
534
+ catch (error) {
535
+ failure = error instanceof Error ? error : new Error(String(error));
536
+ }
537
+ const dataBoundary = 'The existing container writable layer, ordinary /tmp data, processes, tmux sessions, and RAM state may be lost by replacement; worktree and host-managed sandbox data are preserved.';
538
+ if (!params.allowRecreate || !params.recreate) {
539
+ throw new Error(`Sandbox recovery failed: ${failure.message} ${dataBoundary} Re-run with --recreate to authorize container-only replacement.`);
540
+ }
541
+ const warning = `Sandbox recovery failed in place. Replacing only the container. ${dataBoundary}`;
542
+ warnings.push(warning);
543
+ (params.writeWarning ?? ((message) => process.stderr.write(`${message}\n`)))(warning);
544
+ await params.recreate(params.branch);
545
+ const rows = (deps?.fetchRows ?? fetchSandboxRows)(params.engine, sandboxLabel(params.config), sandboxBranchLabel(params.config));
546
+ const replacement = selectSandboxContainer([...rows.running, ...rows.nonRunning], containerNameCandidates(params.config, params.branch));
547
+ if (!replacement?.running) {
548
+ throw new Error('Replacement sandbox container was not found in a running state.');
549
+ }
550
+ const final = assess({
551
+ config: params.config,
552
+ engine: params.engine,
553
+ branch: params.branch,
554
+ container: replacement.name,
555
+ deps
556
+ });
557
+ if (final.findings.length > 0) {
558
+ throw new Error(`Replacement sandbox readiness check failed: ${describeFindings(final.findings)}`);
559
+ }
560
+ return { container: replacement.name, path: 'recreated', warnings };
561
+ }
562
+ //# sourceMappingURL=recovery.js.map
@@ -191,6 +191,10 @@ fi
191
191
  exec tmux new-session -s "$SESSION"
192
192
  SCRIPT
193
193
 
194
+ RUN test -s /usr/local/bin/cc-token-status && test -x /usr/local/bin/cc-token-status && \
195
+ test -s /usr/local/bin/sandbox-dotfiles-link && test -x /usr/local/bin/sandbox-dotfiles-link && \
196
+ test -s /usr/local/bin/sandbox-tmux-entry && test -x /usr/local/bin/sandbox-tmux-entry
197
+
194
198
  ENV LANG=en_US.UTF-8
195
199
  ENV LC_ALL=en_US.UTF-8
196
200
  ENV TERM=xterm-256color
@@ -1,8 +1,9 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
+ import { isRemovedHashShortIdInput } from '../task/short-id.js';
4
5
  const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
5
- const SHORT_ID_RE = /^#?\d+$/;
6
+ const SHORT_ID_RE = /^\d+$/;
6
7
  const WORKSPACE_DIRS = ['active', 'completed', 'blocked', 'archive'];
7
8
  function resolveShortIdStrict(arg, repoRoot) {
8
9
  const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
@@ -39,6 +40,9 @@ function resolveBranchFromTaskContent(content, taskId) {
39
40
  throw new Error(`Task ${taskId} has no branch field in task.md`);
40
41
  }
41
42
  export function resolveTaskBranch(arg, repoRoot) {
43
+ if (isRemovedHashShortIdInput(arg)) {
44
+ throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
45
+ }
42
46
  if (SHORT_ID_RE.test(arg)) {
43
47
  const taskId = resolveShortIdStrict(arg, repoRoot);
44
48
  const content = readTaskContent(repoRoot, taskId);
@@ -1,5 +1,24 @@
1
+ import path from 'node:path';
1
2
  import { safeNameCandidates, sanitizeBranchName } from './constants.js';
2
3
  import { hostJoin } from './engines/wsl2-paths.js';
4
+ export function tmpfsSeedStagingPath(toolId, index) {
5
+ return `/run/agent-infra/tmpfs-seeds/${toolId}/${index}`;
6
+ }
7
+ export function tmpfsSeedTargetPath(containerMount, entry) {
8
+ const normalized = path.posix.normalize(entry);
9
+ if (path.posix.isAbsolute(entry) || normalized === '..' || normalized.startsWith('../')) {
10
+ throw new Error(`tmpfs seed entry must stay within ${containerMount}: ${entry}`);
11
+ }
12
+ return path.posix.join(containerMount, normalized);
13
+ }
14
+ export function declaredTmpfsSeedEntries(tools) {
15
+ return tools.flatMap((tool) => (tool.tmpfs?.seed ?? []).map((entry, index) => ({
16
+ toolId: tool.id,
17
+ containerMount: tool.containerMount,
18
+ stagingPath: tmpfsSeedStagingPath(tool.id, index),
19
+ targetPath: tmpfsSeedTargetPath(tool.containerMount, entry)
20
+ })));
21
+ }
3
22
  const TOOL_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
4
23
  function createBuiltinTools(home, project) {
5
24
  return {
@@ -8,6 +8,7 @@ import { runAi } from './runner.js';
8
8
  import { streamCommand } from './streamer.js';
9
9
  import { markdownMessage, replyOutbound, textMessage } from './display.js';
10
10
  import { buildStatusModel, statusModelToDisplay } from '../task/commands/status.js';
11
+ import { getProcessStartTime, removePidRecordIfMatches } from './process-state.js';
11
12
  function errorMessage(error) {
12
13
  return error instanceof Error ? error.message : String(error);
13
14
  }
@@ -85,6 +86,7 @@ export async function runDaemon() {
85
86
  }
86
87
  const logger = createLogger(config.log);
87
88
  logger.info(`daemon starting agent-infra ${VERSION} pid=${process.pid}`);
89
+ const ownStartTime = getProcessStartTime(process.pid);
88
90
  const abortController = new AbortController();
89
91
  let resolveShutdown = () => { };
90
92
  const shutdown = new Promise((resolve) => {
@@ -106,6 +108,13 @@ export async function runDaemon() {
106
108
  await unloadAdapters(adapters);
107
109
  clearInterval(heartbeat);
108
110
  logger.close();
111
+ if (ownStartTime !== null) {
112
+ removePidRecordIfMatches(config.pidFile, {
113
+ version: 1,
114
+ pid: process.pid,
115
+ startTime: ownStartTime
116
+ });
117
+ }
109
118
  resolveShutdown();
110
119
  })();
111
120
  };