@fitlab-ai/agent-infra 0.9.12 → 0.9.14

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 (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,365 @@
1
+ import { createHash } from 'node:crypto';
2
+ import type { SpawnSyncReturns } from 'node:child_process';
3
+ import { runProbe } from '../shell.ts';
4
+ import { getAdapter } from './index.ts';
5
+
6
+ export type SandboxAuthorityEvidenceV1 = Readonly<{
7
+ version: 1;
8
+ provider: string;
9
+ lockDomain: string;
10
+ routeKind: 'default' | 'context' | 'endpoint' | 'wsl2';
11
+ routeSelector: Readonly<Record<string, string>>;
12
+ normalizedEndpoint: string;
13
+ endpointFingerprint: string;
14
+ daemonIdentity: Readonly<{
15
+ kind: 'docker-server-id';
16
+ fingerprint: string;
17
+ }>;
18
+ apiVersion: Readonly<{ major: number; minor: number }>;
19
+ authorityFingerprint: string;
20
+ }>;
21
+
22
+ export type AuthorityProbe = (cmd: string, args: string[], options?: { timeout?: number }) => SpawnSyncReturns<string | Buffer>;
23
+
24
+ export type AuthorityCaptureOptions = Readonly<{
25
+ probe?: AuthorityProbe;
26
+ timeoutMs?: number;
27
+ env?: NodeJS.ProcessEnv;
28
+ lockDomain?: string;
29
+ route?: SandboxAuthorityEvidenceV1;
30
+ }>;
31
+
32
+ export type AuthorityVerification = Readonly<{
33
+ state: 'verified' | 'unknown' | 'conflict';
34
+ reason?: string;
35
+ }>;
36
+
37
+ function digest(value: string): string {
38
+ return createHash('sha256').update(value).digest('hex');
39
+ }
40
+
41
+ function canonical(value: unknown): string {
42
+ if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;
43
+ if (!value || typeof value !== 'object') return JSON.stringify(value) ?? 'null';
44
+ return `{${Object.entries(value as Record<string, unknown>)
45
+ .sort(([left], [right]) => left.localeCompare(right))
46
+ .map(([key, entry]) => `${JSON.stringify(key)}:${canonical(entry)}`)
47
+ .join(',')}}`;
48
+ }
49
+
50
+ function text(value: string | Buffer | null | undefined): string {
51
+ return typeof value === 'string' ? value : value?.toString('utf8') ?? '';
52
+ }
53
+
54
+ function safeEndpoint(value: string): string {
55
+ if (!value) return 'docker-default';
56
+ try {
57
+ const parsed = new URL(value);
58
+ const hasUnreplayableParts = Boolean(parsed.username || parsed.password || parsed.search || parsed.hash);
59
+ parsed.username = '';
60
+ parsed.password = '';
61
+ parsed.search = '';
62
+ parsed.hash = '';
63
+ const normalized = parsed.toString().replace(/\/$/u, '');
64
+ return hasUnreplayableParts
65
+ ? `${normalized}#<redacted>`
66
+ : normalized;
67
+ } catch {
68
+ const normalized = value
69
+ .replace(/\/\/[^/@]+@/u, '//<redacted>@')
70
+ .replace(/[?&](?:token|password|secret|key)=[^&]*/giu, '');
71
+ return /[@?#]/u.test(value) ? `${normalized.replace(/[?#].*$/u, '')}#<redacted>` : normalized;
72
+ }
73
+ }
74
+
75
+ function lockDomainFor(engine: string, endpoint: string): string {
76
+ return digest(`${process.platform}\0${process.arch}\0${engine}\0${endpoint}`);
77
+ }
78
+
79
+ type SandboxAuthorityRoute = Readonly<{
80
+ kind: SandboxAuthorityEvidenceV1['routeKind'];
81
+ selector: Readonly<Record<string, string>>;
82
+ endpoint: string;
83
+ command: (args: string[]) => { cmd: string; args: string[] };
84
+ }>;
85
+
86
+ function contextRoute(context: string): SandboxAuthorityRoute {
87
+ return {
88
+ kind: 'context',
89
+ selector: { context },
90
+ endpoint: `docker-context://${context}`,
91
+ command: (args) => ({ cmd: 'docker', args: ['--context', context, ...args] })
92
+ };
93
+ }
94
+
95
+ function endpointRoute(endpoint: string, rawEndpoint: string, unreplayable?: string): SandboxAuthorityRoute {
96
+ return {
97
+ kind: 'endpoint',
98
+ selector: {
99
+ source: 'DOCKER_HOST',
100
+ endpoint,
101
+ ...(unreplayable ? { unreplayable } : {})
102
+ },
103
+ endpoint,
104
+ command: (args) => ({ cmd: 'docker', args: ['--host', rawEndpoint, ...args] })
105
+ };
106
+ }
107
+
108
+ function tlsEnvironmentReason(env: NodeJS.ProcessEnv): string | undefined {
109
+ return env.DOCKER_TLS_VERIFY || env.DOCKER_CERT_PATH || env.DOCKER_TLS
110
+ ? 'tls-environment'
111
+ : undefined;
112
+ }
113
+
114
+ function routeFor(engine: string, env: NodeJS.ProcessEnv): SandboxAuthorityRoute {
115
+ const context = getAdapter(engine).dockerContext;
116
+ if (context) {
117
+ return contextRoute(context);
118
+ }
119
+ if (env.DOCKER_CONTEXT) {
120
+ return contextRoute(env.DOCKER_CONTEXT);
121
+ }
122
+ if (env.DOCKER_HOST) {
123
+ return endpointRoute(safeEndpoint(env.DOCKER_HOST), env.DOCKER_HOST, tlsEnvironmentReason(env));
124
+ }
125
+ return contextRoute('default');
126
+ }
127
+
128
+ function validRouteName(value: string): boolean {
129
+ return /^[A-Za-z0-9][A-Za-z0-9_.@/-]*$/u.test(value);
130
+ }
131
+
132
+ function resolveWslDistro(probe: AuthorityProbe, timeoutMs?: number, explicit?: string): string {
133
+ if (explicit) {
134
+ if (!validRouteName(explicit)) throw new Error('SANDBOX_AUTHORITY_ROUTE_CAPTURE_FAILED');
135
+ return explicit;
136
+ }
137
+ const result = probe(
138
+ 'wsl.exe',
139
+ ['--list', '--verbose'],
140
+ timeoutMs === undefined ? {} : { timeout: timeoutMs }
141
+ );
142
+ if (result.status !== 0) throw new Error('SANDBOX_AUTHORITY_ROUTE_CAPTURE_FAILED');
143
+ const output = text(result.stdout).replace(/\0/gu, '').replace(/\r/gu, '');
144
+ const defaultLine = output.split('\n').find((line) => /^\s*\*\s+/u.test(line));
145
+ const distro = defaultLine?.replace(/^\s*\*\s+/u, '').replace(/\s+(?:Running|Stopped)\s+\d+\s*$/iu, '').trim();
146
+ if (!distro || !validRouteName(distro)) throw new Error('SANDBOX_AUTHORITY_ROUTE_CAPTURE_FAILED');
147
+ return distro;
148
+ }
149
+
150
+ function wslRoute(
151
+ distro: string,
152
+ context: string | undefined,
153
+ env: NodeJS.ProcessEnv
154
+ ): SandboxAuthorityRoute {
155
+ const endpoint = env.DOCKER_HOST
156
+ ? safeEndpoint(env.DOCKER_HOST)
157
+ : `wsl://${distro}/${context ?? 'default'}`;
158
+ const unreplayable = tlsEnvironmentReason(env)
159
+ ?? (endpoint.includes('<redacted>') ? 'ambient-endpoint-secret' : undefined);
160
+ return {
161
+ kind: 'wsl2',
162
+ selector: {
163
+ distro,
164
+ ...(context ? { context } : {}),
165
+ ...(unreplayable ? { unreplayable } : {}),
166
+ ...(env.DOCKER_HOST ? { endpoint } : {})
167
+ },
168
+ endpoint,
169
+ command: (args) => ({
170
+ cmd: 'wsl.exe',
171
+ args: [
172
+ '--distribution', distro,
173
+ '--exec', 'docker',
174
+ ...(context ? ['--context', context] : []),
175
+ ...(env.DOCKER_HOST ? ['--host', env.DOCKER_HOST] : []),
176
+ ...args
177
+ ]
178
+ })
179
+ };
180
+ }
181
+
182
+ function currentWslRoute(
183
+ env: NodeJS.ProcessEnv,
184
+ probe: AuthorityProbe,
185
+ timeoutMs?: number
186
+ ): SandboxAuthorityRoute {
187
+ const distro = resolveWslDistro(probe, timeoutMs, env.WSL_DISTRO_NAME);
188
+ let context = env.DOCKER_CONTEXT;
189
+ if (!context && !env.DOCKER_HOST) {
190
+ const result = probe(
191
+ 'wsl.exe',
192
+ ['--distribution', distro, '--exec', 'docker', 'context', 'show'],
193
+ timeoutMs === undefined ? {} : { timeout: timeoutMs }
194
+ );
195
+ context = text(result.stdout).trim();
196
+ if (result.status !== 0 || !validRouteName(context)) {
197
+ throw new Error('SANDBOX_AUTHORITY_ROUTE_CAPTURE_FAILED');
198
+ }
199
+ }
200
+ return wslRoute(distro, context, env);
201
+ }
202
+
203
+ function routeFromEvidence(evidence: SandboxAuthorityEvidenceV1): SandboxAuthorityRoute {
204
+ return {
205
+ kind: evidence.routeKind,
206
+ selector: evidence.routeSelector,
207
+ endpoint: evidence.normalizedEndpoint,
208
+ command: (args) => commandForSandboxAuthority(evidence, 'docker', args)
209
+ };
210
+ }
211
+
212
+ function currentContextRoute(
213
+ engine: string,
214
+ env: NodeJS.ProcessEnv,
215
+ probe: AuthorityProbe,
216
+ timeoutMs?: number
217
+ ): SandboxAuthorityRoute {
218
+ const configured = routeFor(engine, env);
219
+ if (configured.kind !== 'context' || configured.selector.context !== 'default') return configured;
220
+ if (env.DOCKER_CONTEXT || env.DOCKER_HOST || getAdapter(engine).dockerContext) return configured;
221
+ const result = probe('docker', ['context', 'show'], timeoutMs === undefined ? {} : { timeout: timeoutMs });
222
+ const context = text(result.stdout).trim();
223
+ if (result.status !== 0 || !/^[A-Za-z0-9][A-Za-z0-9_.@/-]*$/u.test(context)) {
224
+ throw new Error('SANDBOX_AUTHORITY_ROUTE_CAPTURE_FAILED');
225
+ }
226
+ return contextRoute(context);
227
+ }
228
+
229
+ /** Build a command using only the route persisted with the sandbox authority. */
230
+ export function commandForSandboxAuthority(
231
+ evidence: SandboxAuthorityEvidenceV1,
232
+ cmd: string,
233
+ args: string[] = []
234
+ ): { cmd: string; args: string[] } {
235
+ if (cmd !== 'docker') {
236
+ throw new Error('SANDBOX_AUTHORITY_ROUTE_UNSUPPORTED');
237
+ }
238
+ if (evidence.routeKind === 'context') {
239
+ const context = evidence.routeSelector.context;
240
+ if (!context) throw new Error('SANDBOX_AUTHORITY_ROUTE_INVALID');
241
+ return { cmd, args: ['--context', context, ...args] };
242
+ }
243
+ if (evidence.routeKind === 'endpoint') {
244
+ const endpoint = evidence.routeSelector.endpoint;
245
+ if (!endpoint || endpoint.includes('<redacted>') || evidence.routeSelector.unreplayable) {
246
+ throw new Error('SANDBOX_AUTHORITY_ROUTE_UNREPLAYABLE');
247
+ }
248
+ return { cmd, args: ['--host', endpoint, ...args] };
249
+ }
250
+ if (evidence.routeKind === 'wsl2') {
251
+ const distro = evidence.routeSelector.distro;
252
+ const context = evidence.routeSelector.context;
253
+ const endpoint = evidence.routeSelector.endpoint;
254
+ if (!distro || evidence.routeSelector.unreplayable || endpoint?.includes('<redacted>')) {
255
+ throw new Error('SANDBOX_AUTHORITY_ROUTE_UNREPLAYABLE');
256
+ }
257
+ return {
258
+ cmd: 'wsl.exe',
259
+ args: [
260
+ '--distribution', distro,
261
+ '--exec', cmd,
262
+ ...(context ? ['--context', context] : []),
263
+ ...(endpoint && !endpoint.startsWith('wsl://') ? ['--host', endpoint] : []),
264
+ ...args
265
+ ]
266
+ };
267
+ }
268
+ return { cmd, args: ['--context', 'default', ...args] };
269
+ }
270
+
271
+ export function authorityVersionArgs(): string[] {
272
+ return ['version', '--format', '{{json .Server}}'];
273
+ }
274
+
275
+ export function captureSandboxAuthority(
276
+ engine: string,
277
+ options: AuthorityCaptureOptions = {}
278
+ ): SandboxAuthorityEvidenceV1 {
279
+ const env = options.env ?? process.env;
280
+ const probe = options.probe ?? runProbe;
281
+ const route = options.route
282
+ ? routeFromEvidence(options.route)
283
+ : engine === 'wsl2'
284
+ ? currentWslRoute(env, probe, options.timeoutMs)
285
+ : currentContextRoute(engine, env, probe, options.timeoutMs);
286
+ function probeJson(args: string[]): unknown {
287
+ const command = options.route
288
+ ? commandForSandboxAuthority(options.route, 'docker', args)
289
+ : route.command(args);
290
+ try {
291
+ const response = probe(
292
+ command.cmd,
293
+ command.args,
294
+ options.timeoutMs === undefined ? {} : { timeout: options.timeoutMs }
295
+ );
296
+ if (response.status !== 0) throw new Error('SANDBOX_AUTHORITY_CAPTURE_FAILED');
297
+ return JSON.parse(text(response.stdout).trim());
298
+ } catch {
299
+ throw new Error('SANDBOX_AUTHORITY_CAPTURE_FAILED');
300
+ }
301
+ }
302
+ const server = probeJson(authorityVersionArgs());
303
+ if (!server || typeof server !== 'object' || Array.isArray(server)) {
304
+ throw new Error('SANDBOX_AUTHORITY_CAPTURE_FAILED');
305
+ }
306
+ const record = server as Record<string, unknown>;
307
+ const api = typeof record.ApiVersion === 'string' ? /^(\d+)\.(\d+)$/u.exec(record.ApiVersion) : null;
308
+ if (!api) throw new Error('SANDBOX_AUTHORITY_CAPTURE_FAILED');
309
+ // Docker version exposes API metadata; the daemon ID belongs to Docker info.
310
+ const serverId = probeJson(['info', '--format', '{{json .ID}}']);
311
+ if (typeof serverId !== 'string' || !serverId.trim()) throw new Error('SANDBOX_AUTHORITY_CAPTURE_FAILED');
312
+ const normalizedEndpoint = route.endpoint;
313
+ const evidenceWithoutFingerprint = {
314
+ version: 1 as const,
315
+ provider: engine,
316
+ lockDomain: options.lockDomain ?? options.route?.lockDomain ?? lockDomainFor(engine, normalizedEndpoint),
317
+ routeKind: route.kind,
318
+ routeSelector: route.selector,
319
+ normalizedEndpoint,
320
+ endpointFingerprint: digest(normalizedEndpoint),
321
+ daemonIdentity: { kind: 'docker-server-id' as const, fingerprint: digest(serverId) },
322
+ apiVersion: { major: Number(api[1]), minor: Number(api[2]) }
323
+ };
324
+ return {
325
+ ...evidenceWithoutFingerprint,
326
+ authorityFingerprint: digest(canonical(evidenceWithoutFingerprint))
327
+ };
328
+ }
329
+
330
+ export function verifySandboxAuthority(
331
+ expected: SandboxAuthorityEvidenceV1 | null | undefined,
332
+ actual: SandboxAuthorityEvidenceV1 | null
333
+ ): AuthorityVerification {
334
+ if (!expected) return { state: 'unknown', reason: 'SANDBOX_AUTHORITY_EVIDENCE_MISSING' };
335
+ if (!actual) return { state: 'unknown', reason: 'SANDBOX_AUTHORITY_UNAVAILABLE' };
336
+ if (expected.authorityFingerprint !== actual.authorityFingerprint
337
+ || expected.lockDomain !== actual.lockDomain
338
+ || expected.routeKind !== actual.routeKind
339
+ || expected.endpointFingerprint !== actual.endpointFingerprint
340
+ || expected.daemonIdentity.fingerprint !== actual.daemonIdentity.fingerprint) {
341
+ return { state: 'conflict', reason: 'SANDBOX_AUTHORITY_DRIFT' };
342
+ }
343
+ return { state: 'verified' };
344
+ }
345
+
346
+ export function isSandboxAuthorityEvidence(value: unknown): value is SandboxAuthorityEvidenceV1 {
347
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
348
+ const evidence = value as Record<string, unknown>;
349
+ const selector = evidence.routeSelector as Record<string, unknown> | null;
350
+ const daemon = evidence.daemonIdentity as Record<string, unknown> | null;
351
+ const api = evidence.apiVersion as Record<string, unknown> | null;
352
+ return evidence.version === 1
353
+ && typeof evidence.provider === 'string'
354
+ && /^[a-f0-9]{64}$/u.test(evidence.lockDomain as string)
355
+ && ['default', 'context', 'endpoint', 'wsl2'].includes(evidence.routeKind as string)
356
+ && !!selector && typeof selector === 'object' && !Array.isArray(selector)
357
+ && Object.values(selector).every((entry) => typeof entry === 'string')
358
+ && typeof evidence.normalizedEndpoint === 'string'
359
+ && /^[a-f0-9]{64}$/u.test(evidence.endpointFingerprint as string)
360
+ && !!daemon && daemon.kind === 'docker-server-id'
361
+ && /^[a-f0-9]{64}$/u.test(daemon.fingerprint as string)
362
+ && !!api && Number.isSafeInteger(api.major) && (api.major as number) >= 0
363
+ && Number.isSafeInteger(api.minor) && (api.minor as number) >= 0
364
+ && /^[a-f0-9]{64}$/u.test(evidence.authorityFingerprint as string);
365
+ }
@@ -0,0 +1,132 @@
1
+ import type { SpawnSyncReturns } from 'node:child_process';
2
+ import { commandForEngine, runProbe } from '../shell.ts';
3
+ import { commandForSandboxAuthority, type SandboxAuthorityEvidenceV1 } from './authority.ts';
4
+
5
+ type ProbeResult = SpawnSyncReturns<string | Buffer>;
6
+ type Probe = (cmd: string, args: string[], options?: { timeout?: number }) => ProbeResult;
7
+
8
+ export type ExactContainerDiscovery =
9
+ | Readonly<{ state: 'absent'; id: string; evidence: 'exact-empty' }>
10
+ | Readonly<{
11
+ state: 'found';
12
+ id: string;
13
+ running: boolean;
14
+ labels: Readonly<Record<string, string>>;
15
+ evidence: 'exact-present';
16
+ }>
17
+ | Readonly<{ state: 'conflict'; reason: string }>
18
+ | Readonly<{ state: 'unknown'; reason: string }>;
19
+
20
+ export type ExactContainerDiscoveryOptions = Readonly<{
21
+ probe?: Probe;
22
+ timeoutMs?: number;
23
+ authority?: SandboxAuthorityEvidenceV1;
24
+ }>;
25
+
26
+ const FULL_CONTAINER_ID = /^[a-f0-9]{64}$/u;
27
+
28
+ function outputText(value: string | Buffer | null | undefined): string {
29
+ return typeof value === 'string' ? value : value?.toString('utf8') ?? '';
30
+ }
31
+
32
+ function unknown(reason: string): ExactContainerDiscovery {
33
+ return { state: 'unknown', reason };
34
+ }
35
+
36
+ export function buildExactContainerListArgs(id: string): string[] {
37
+ if (!FULL_CONTAINER_ID.test(id)) throw new Error('SANDBOX_CONTAINER_ID_NOT_FULL');
38
+ return ['container', 'ls', '--all', '--no-trunc', '--filter', `id=${id}`, '--format', '{{.ID}}'];
39
+ }
40
+
41
+ function buildExactContainerInspectArgs(id: string): string[] {
42
+ return ['container', 'inspect', '--format', '{{json .}}', id];
43
+ }
44
+
45
+ function runDockerProbe(
46
+ engine: string,
47
+ args: string[],
48
+ options: ExactContainerDiscoveryOptions
49
+ ): ProbeResult {
50
+ const command = options.authority
51
+ ? commandForSandboxAuthority(options.authority, 'docker', args)
52
+ : commandForEngine(engine, 'docker', args);
53
+ return (options.probe ?? runProbe)(
54
+ command.cmd,
55
+ command.args,
56
+ options.timeoutMs === undefined ? {} : { timeout: options.timeoutMs }
57
+ );
58
+ }
59
+
60
+ function parseExactList(stdout: string, expectedId: string): 'empty' | 'present' | 'conflict' | string {
61
+ const rows = stdout.split(/\r?\n/u).map((row) => row.trim()).filter(Boolean);
62
+ if (rows.length === 0) return 'empty';
63
+ if (rows.length !== 1) return 'exact container query returned multiple rows';
64
+ if (!FULL_CONTAINER_ID.test(rows[0]!)) return 'exact container query returned a malformed ID';
65
+ if (rows[0] !== expectedId) return 'conflict';
66
+ return 'present';
67
+ }
68
+
69
+ function parseExactInspect(stdout: string, expectedId: string): ExactContainerDiscovery {
70
+ let value: unknown;
71
+ try {
72
+ value = JSON.parse(stdout);
73
+ } catch {
74
+ return unknown('exact container inspection returned malformed JSON');
75
+ }
76
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
77
+ return unknown('exact container inspection returned an incomplete object');
78
+ }
79
+ const inspected = value as {
80
+ Id?: unknown;
81
+ State?: { Running?: unknown };
82
+ Config?: { Labels?: unknown };
83
+ };
84
+ if (inspected.Id !== expectedId || typeof inspected.State?.Running !== 'boolean'
85
+ || !inspected.Config?.Labels || typeof inspected.Config.Labels !== 'object'
86
+ || Array.isArray(inspected.Config.Labels)) {
87
+ return unknown('exact container inspection identity is incomplete');
88
+ }
89
+ const rawLabels = inspected.Config.Labels as Record<string, unknown>;
90
+ if (Object.values(rawLabels).some((value) => typeof value !== 'string')) {
91
+ return unknown('exact container inspection labels are malformed');
92
+ }
93
+ return {
94
+ state: 'found',
95
+ id: expectedId,
96
+ running: inspected.State.Running,
97
+ labels: { ...rawLabels as Record<string, string> },
98
+ evidence: 'exact-present'
99
+ };
100
+ }
101
+
102
+ export function discoverExactContainer(
103
+ engine: string,
104
+ id: string,
105
+ options: ExactContainerDiscoveryOptions = {}
106
+ ): ExactContainerDiscovery {
107
+ if (!FULL_CONTAINER_ID.test(id)) return unknown('container identity is not a full 64-character ID');
108
+ let listed: ProbeResult;
109
+ try {
110
+ listed = runDockerProbe(engine, buildExactContainerListArgs(id), options);
111
+ } catch {
112
+ return unknown('exact container query failed before producing a result');
113
+ }
114
+ if (listed.status !== 0) {
115
+ return unknown(`exact container query exited with ${listed.status ?? 'unknown status'}`);
116
+ }
117
+ const listState = parseExactList(outputText(listed.stdout), id);
118
+ if (listState === 'empty') return { state: 'absent', id, evidence: 'exact-empty' };
119
+ if (listState === 'conflict') return { state: 'conflict', reason: 'exact container query returned a different ID' };
120
+ if (listState !== 'present') return unknown(listState);
121
+
122
+ let inspected: ProbeResult;
123
+ try {
124
+ inspected = runDockerProbe(engine, buildExactContainerInspectArgs(id), options);
125
+ } catch {
126
+ return unknown('exact container inspection failed before producing a result');
127
+ }
128
+ if (inspected.status !== 0) {
129
+ return unknown(`exact container inspection exited with ${inspected.status ?? 'unknown status'}`);
130
+ }
131
+ return parseExactInspect(outputText(inspected.stdout).trim(), id);
132
+ }
@@ -1,3 +1,5 @@
1
+ import { PUBLIC_CLI_ROUTE_SELECTORS } from '../internal/cli-route-inventory.ts';
2
+
1
3
  const USAGE = `Usage: ai sandbox <command> [options]
2
4
 
3
5
  Commands:
@@ -26,6 +28,7 @@ Commands:
26
28
  vm status|start|stop Manage the sandbox VM (macOS) or check the backend (Windows)
27
29
 
28
30
  Run 'ai sandbox <command> --help' for details.`;
31
+ const SANDBOX_OPERATIONS = PUBLIC_CLI_ROUTE_SELECTORS.sandbox;
29
32
 
30
33
  export async function runSandbox(args: string[]): Promise<void> {
31
34
  const [subcommand, ...rest] = args;
@@ -41,6 +44,10 @@ export async function runSandbox(args: string[]): Promise<void> {
41
44
  return;
42
45
  }
43
46
 
47
+ if (!SANDBOX_OPERATIONS.includes(subcommand as typeof SANDBOX_OPERATIONS[number])) {
48
+ throw new Error(`Unknown sandbox command: ${subcommand}`);
49
+ }
50
+
44
51
  switch (subcommand) {
45
52
  case 'create': {
46
53
  const { create } = await import('./commands/create.ts');
@@ -1,3 +1,4 @@
1
+ import { prepareCompletedReentry, publishCompletedReentry, waitForCompletedReentry } from './control/completed-reentry.ts';
1
2
  import fs from 'node:fs';
2
3
  import path from 'node:path';
3
4
  import { spawn } from 'node:child_process';
@@ -653,7 +654,7 @@ function recoveryTaskSources(repoRoot: string, taskId: string): {
653
654
  return { mountPaths, accessiblePaths: [completedSource] };
654
655
  }
655
656
 
656
- function startCompletedSandboxContainer(params: {
657
+ export function startCompletedSandboxContainer(params: {
657
658
  config: SandboxConfig;
658
659
  engine: string;
659
660
  container: string;
@@ -1250,7 +1251,17 @@ export async function ensureSandboxReady(params: EnsureSandboxReadyParams): Prom
1250
1251
  throw new Error('Explicit container recreation requested.');
1251
1252
  }
1252
1253
  if (!params.row.running) {
1254
+ let completedReentry: { manifest: SandboxControlManifest; evidence: Awaited<ReturnType<typeof prepareCompletedReentry>> } | null = null;
1253
1255
  if (params.reentry === 'completed' && params.workspace?.mode === 'task-bound') {
1256
+ const control = sandboxControlPaths({
1257
+ base: params.config.controlBase, project: params.config.project,
1258
+ container: params.row.name, identity: params.workspace
1259
+ });
1260
+ const manifest = readSandboxControlManifest(control.manifestPath);
1261
+ if (manifest.taskId !== params.workspace.taskId || manifest.branch !== params.branch) {
1262
+ throw new Error('SANDBOX_COMPLETED_REENTRY_EVIDENCE_INVALID');
1263
+ }
1264
+ completedReentry = { manifest, evidence: await prepareCompletedReentry(manifest) };
1254
1265
  startCompletedSandboxContainer({
1255
1266
  config: params.config,
1256
1267
  engine: params.engine,
@@ -1315,6 +1326,15 @@ export async function ensureSandboxReady(params: EnsureSandboxReadyParams): Prom
1315
1326
  if (final.findings.length > 0) {
1316
1327
  throw new Error(describeFindings(final.findings));
1317
1328
  }
1329
+ if (completedReentry) {
1330
+ const { manifest, evidence } = completedReentry;
1331
+ const current = await prepareCompletedReentry(manifest);
1332
+ if (JSON.stringify(current) !== JSON.stringify(evidence)) {
1333
+ throw new Error('SANDBOX_COMPLETED_REENTRY_EVIDENCE_INVALID');
1334
+ }
1335
+ publishCompletedReentry(manifest, evidence);
1336
+ await waitForCompletedReentry(manifest, evidence);
1337
+ }
1318
1338
  return { container: params.row.name, path: 'recovered', warnings };
1319
1339
  }
1320
1340
 
@@ -57,7 +57,7 @@ export type SandboxControlSetup = Readonly<{
57
57
  generation: string;
58
58
  }>;
59
59
 
60
- export type SandboxControlManifestDraft = Readonly<Omit<SandboxControlManifest, 'containerIdentity' | 'engine'> & {
60
+ export type SandboxControlManifestDraft = Readonly<Omit<SandboxControlManifest, 'containerIdentity' | 'engine' | 'authorityEvidence'> & {
61
61
  engine: string;
62
62
  }>;
63
63
 
@@ -256,13 +256,19 @@ export function materializeSandboxControl(params: Readonly<{
256
256
 
257
257
  export function finalizeSandboxControlManifest(
258
258
  setup: SandboxControlSetup,
259
- identity: Readonly<{ engine: string; id: string; labels: Readonly<Record<string, string>> }>
259
+ identity: Readonly<{
260
+ engine: string;
261
+ id: string;
262
+ labels: Readonly<Record<string, string>>;
263
+ authorityEvidence: SandboxControlManifest['authorityEvidence'];
264
+ }>
260
265
  ): SandboxControlManifest {
261
266
  if (!identity.engine || !identity.id) throw new Error('SANDBOX_CONTROL_CONTAINER_ID_INVALID');
262
267
  const manifest: SandboxControlManifest = {
263
268
  ...setup.manifestDraft,
264
269
  engine: identity.engine,
265
- containerIdentity: { id: identity.id, labels: { ...identity.labels } }
270
+ containerIdentity: { id: identity.id, labels: { ...identity.labels } },
271
+ authorityEvidence: identity.authorityEvidence
266
272
  };
267
273
  const temporary = `${setup.manifestPath}.${process.pid}.${randomBytes(8).toString('hex')}.tmp`;
268
274
  try {
@@ -436,7 +436,10 @@ function verifyWorktreePermit(
436
436
  ? inspectRecoveredWorktree(permit.snapshot.worktree, permit.snapshot.recovery, options)
437
437
  : inspectWorktree(permit.snapshot.worktree, options);
438
438
  if (current.status === 'failed') throw new Error(`Unable to verify worktree permit: ${current.message}`);
439
- if (current.snapshot.identity !== permit.snapshot.identity || (permit.mode === 'clean' && current.status !== 'clean')) {
439
+ const sameTarget = current.snapshot.worktree === permit.snapshot.worktree
440
+ && current.snapshot.branch === permit.snapshot.branch;
441
+ if (!sameTarget || (permit.mode === 'clean'
442
+ && (current.snapshot.identity !== permit.snapshot.identity || current.status !== 'clean'))) {
440
443
  throw new Error(`Worktree changed after authorization: ${permit.snapshot.worktree}`);
441
444
  }
442
445
  return current.snapshot;
@@ -1,5 +1,8 @@
1
1
  import { runDaemon } from './daemon.ts';
2
2
  import { start, stop, status, logs } from './process-control.ts';
3
+ import { PUBLIC_CLI_ROUTE_SELECTORS } from '../internal/cli-route-inventory.ts';
4
+
5
+ const SERVER_OPERATIONS = PUBLIC_CLI_ROUTE_SELECTORS.server;
3
6
 
4
7
  const USAGE = `Usage: ai server <command> [options]
5
8
 
@@ -25,6 +28,13 @@ export async function runServer(args: string[]): Promise<void> {
25
28
  return;
26
29
  }
27
30
 
31
+ if (!SERVER_OPERATIONS.includes(subcommand as typeof SERVER_OPERATIONS[number])) {
32
+ process.stderr.write(`Unknown server command: ${subcommand}\n`);
33
+ process.stdout.write(`${USAGE}\n`);
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+
28
38
  switch (subcommand) {
29
39
  case 'start':
30
40
  await start({ foreground: rest.includes('--foreground') });
@@ -20,6 +20,27 @@ function taskSubcommand(subcommand: string): string {
20
20
  return subcommand === 'list' ? 'ls' : subcommand;
21
21
  }
22
22
 
23
+ function splitRunArguments(args: readonly string[]): { hostArgs: string[]; skillArgs: string[] } {
24
+ const hostArgs: string[] = [];
25
+ const skillArgs: string[] = [];
26
+ for (let i = 0; i < args.length; i += 1) {
27
+ const arg = args[i] as string;
28
+ if (arg === '--tui') {
29
+ hostArgs.push(arg);
30
+ const value = args[i + 1];
31
+ if (value !== undefined) {
32
+ hostArgs.push(value);
33
+ i += 1;
34
+ }
35
+ } else if (arg === '--recreate') {
36
+ hostArgs.push(arg);
37
+ } else {
38
+ skillArgs.push(arg);
39
+ }
40
+ }
41
+ return { hostArgs, skillArgs };
42
+ }
43
+
23
44
  export function commandHelp(): string {
24
45
  return [
25
46
  `agent-infra ${VERSION}`,
@@ -88,7 +109,21 @@ export function parseCommand(text: string): CommandPlan {
88
109
  if (command === '/run') {
89
110
  const spec = getSkillRunSpec(subcommand);
90
111
  if (!spec) return { kind: 'error', message: `Unknown skill: ${subcommand}` };
91
- return { kind: 'ai', role: spec.role, argv: ['run', subcommand, ...rest] };
112
+ if (spec.kind === 'create') {
113
+ return { kind: 'ai', role: spec.role, argv: ['run', '--skill', subcommand, ...rest] };
114
+ }
115
+ const [taskRef, ...skillArgs] = rest;
116
+ if (!taskRef) return { kind: 'error', message: '/run task skills require a task-ref' };
117
+ const { hostArgs, skillArgs: forwardedSkillArgs } = splitRunArguments(skillArgs);
118
+ return {
119
+ kind: 'ai',
120
+ role: spec.role,
121
+ argv: [
122
+ 'run', '--skill', subcommand, '--task', taskRef,
123
+ ...hostArgs,
124
+ ...(forwardedSkillArgs.length > 0 ? ['--', ...forwardedSkillArgs] : [])
125
+ ]
126
+ };
92
127
  }
93
128
 
94
129
  return { kind: 'error', message: `Unknown command: ${command}` };