@fitlab-ai/agent-infra 0.9.9 → 0.9.11

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 (309) hide show
  1. package/README.md +13 -3
  2. package/README.zh-CN.md +13 -3
  3. package/bin/cli.ts +17 -4
  4. package/dist/bin/cli.js +19 -4
  5. package/dist/bin/internal-cli.js +55 -4
  6. package/dist/lib/agent-client.js +0 -1
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +17 -10
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +11 -31
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +15 -33
  10. package/dist/lib/agent-clients/adapters/codex-sandbox.js +72 -11
  11. package/dist/lib/agent-clients/adapters/index.js +3 -1
  12. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +0 -4
  13. package/dist/lib/agent-clients/adapters/traecli.js +65 -0
  14. package/dist/lib/agent-clients/config.js +14 -99
  15. package/dist/lib/agent-clients/reconcile.js +1 -11
  16. package/dist/lib/agent-clients/schema.js +5 -4
  17. package/dist/lib/agent-clients/tokens.js +7 -17
  18. package/dist/lib/agent-clients/types.js +2 -1
  19. package/dist/lib/decide.js +14 -30
  20. package/dist/lib/defaults.json +9 -0
  21. package/dist/lib/init.js +2 -2
  22. package/dist/lib/internal/codex-lifecycle.js +2 -2
  23. package/dist/lib/internal/codex-sandbox-controller.js +4 -3
  24. package/dist/lib/internal/release-workflow.js +0 -1
  25. package/dist/lib/internal/sandbox-control.js +2 -2
  26. package/dist/lib/internal/task-finalization.js +19 -9
  27. package/dist/lib/internal/task-ledger.js +8 -2
  28. package/dist/lib/internal/task-lifecycle.js +17 -93
  29. package/dist/lib/internal/task-orchestration.js +30 -216
  30. package/dist/lib/{task/commands/validate.js → internal/task-validate.js} +77 -43
  31. package/dist/lib/merge.js +205 -103
  32. package/dist/lib/process-data/normalize.js +2 -9
  33. package/dist/lib/run/host.js +46 -16
  34. package/dist/lib/run/tui.js +5 -2
  35. package/dist/lib/sandbox/agent-client-reconciler.js +4 -12
  36. package/dist/lib/sandbox/commands/create.js +3 -3
  37. package/dist/lib/sandbox/commands/enter.js +18 -4
  38. package/dist/lib/sandbox/config.js +3 -12
  39. package/dist/lib/sandbox/control/controller-registration.js +4 -2
  40. package/dist/lib/sandbox/control/executor.js +135 -40
  41. package/dist/lib/sandbox/control/lifecycle.js +29 -20
  42. package/dist/lib/sandbox/control/server.js +18 -16
  43. package/dist/lib/sandbox/mounts.js +3 -2
  44. package/dist/lib/sandbox/recovery.js +123 -22
  45. package/dist/lib/sandbox/workspace-identity.js +14 -0
  46. package/dist/lib/sandbox/workspace-view.js +8 -9
  47. package/dist/lib/self-update.js +278 -0
  48. package/dist/lib/server/protocol.js +5 -5
  49. package/dist/lib/task/activity-log.js +4 -1
  50. package/dist/lib/task/artifact-lifecycle.js +4 -2
  51. package/dist/lib/task/codex-orchestration.js +32 -35
  52. package/dist/lib/task/command-options.js +1 -3
  53. package/dist/lib/task/commands/cat.js +0 -5
  54. package/dist/lib/task/commands/decisions.js +76 -92
  55. package/dist/lib/task/commands/files.js +6 -6
  56. package/dist/lib/task/commands/grep.js +25 -61
  57. package/dist/lib/task/commands/issue-body.js +6 -6
  58. package/dist/lib/task/commands/log.js +25 -10
  59. package/dist/lib/task/commands/show.js +5 -6
  60. package/dist/lib/task/commands/status.js +8 -8
  61. package/dist/lib/task/commit-operation.js +21 -25
  62. package/dist/lib/task/commit-policy.js +1 -1
  63. package/dist/lib/task/control-authority.js +431 -0
  64. package/dist/lib/task/create.js +6 -1
  65. package/dist/lib/task/current-contract.js +35 -0
  66. package/dist/lib/task/decision-details.js +263 -0
  67. package/dist/lib/task/decision-intents.js +5 -2
  68. package/dist/lib/task/delegation-receipts.js +8 -7
  69. package/dist/lib/task/events.js +11 -5
  70. package/dist/lib/task/finalization.js +72 -46
  71. package/dist/lib/task/index.js +19 -29
  72. package/dist/lib/task/ledger-intents.js +8 -9
  73. package/dist/lib/task/ledger.js +13 -6
  74. package/dist/lib/task/lifecycle.js +16 -0
  75. package/dist/lib/task/orchestration.js +51 -14
  76. package/dist/lib/task/review-artifacts.js +31 -12
  77. package/dist/lib/task/review-finalization.js +19 -6
  78. package/dist/lib/task/verification-engine.js +38 -18
  79. package/dist/lib/task/verification-review.js +1 -1
  80. package/dist/lib/task/workspace-snapshot.js +5 -11
  81. package/dist/lib/task/write.js +11 -1
  82. package/dist/lib/update.js +6 -37
  83. package/dist/lib/version.js +5 -1
  84. package/dist/lifecycle-build-manifest.json +3 -3
  85. package/lib/agent-client.ts +0 -1
  86. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +25 -10
  87. package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +16 -33
  88. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +16 -35
  89. package/lib/agent-clients/adapters/codex-sandbox.ts +89 -14
  90. package/lib/agent-clients/adapters/index.ts +3 -1
  91. package/lib/agent-clients/adapters/opencode-sandbox.ts +0 -5
  92. package/lib/agent-clients/adapters/traecli.ts +66 -0
  93. package/lib/agent-clients/config.ts +14 -144
  94. package/lib/agent-clients/reconcile.ts +1 -12
  95. package/lib/agent-clients/schema.ts +5 -4
  96. package/lib/agent-clients/tokens.ts +7 -20
  97. package/lib/agent-clients/types.ts +2 -1
  98. package/lib/decide.ts +12 -22
  99. package/lib/defaults.json +9 -0
  100. package/lib/init.ts +2 -2
  101. package/lib/internal/codex-lifecycle.ts +2 -2
  102. package/lib/internal/codex-sandbox-controller.ts +4 -3
  103. package/lib/internal/release-workflow.ts +0 -1
  104. package/lib/internal/sandbox-control.ts +2 -2
  105. package/lib/internal/task-finalization.ts +27 -13
  106. package/lib/internal/task-ledger.ts +8 -2
  107. package/lib/internal/task-lifecycle.ts +33 -76
  108. package/lib/internal/task-orchestration.ts +33 -190
  109. package/lib/{task/commands/validate.ts → internal/task-validate.ts} +77 -41
  110. package/lib/merge.ts +236 -120
  111. package/lib/process-data/normalize.ts +2 -8
  112. package/lib/run/host.ts +63 -14
  113. package/lib/run/tui.ts +5 -3
  114. package/lib/sandbox/agent-client-reconciler.ts +5 -15
  115. package/lib/sandbox/commands/create.ts +4 -4
  116. package/lib/sandbox/commands/enter.ts +24 -4
  117. package/lib/sandbox/config.ts +2 -14
  118. package/lib/sandbox/control/container-identity.ts +2 -2
  119. package/lib/sandbox/control/controller-registration.ts +8 -3
  120. package/lib/sandbox/control/executor.ts +156 -53
  121. package/lib/sandbox/control/lifecycle.ts +34 -28
  122. package/lib/sandbox/control/protocol.ts +1 -3
  123. package/lib/sandbox/control/server.ts +15 -12
  124. package/lib/sandbox/control/state.ts +7 -7
  125. package/lib/sandbox/mounts.ts +4 -3
  126. package/lib/sandbox/recovery.ts +162 -34
  127. package/lib/sandbox/tools.ts +1 -1
  128. package/lib/sandbox/workspace-identity.ts +28 -0
  129. package/lib/sandbox/workspace-view.ts +14 -10
  130. package/lib/self-update.ts +341 -0
  131. package/lib/server/protocol.ts +5 -5
  132. package/lib/task/activity-log.ts +6 -1
  133. package/lib/task/artifact-lifecycle.ts +5 -3
  134. package/lib/task/codex-orchestration.ts +40 -45
  135. package/lib/task/command-options.ts +1 -2
  136. package/lib/task/commands/cat.ts +0 -4
  137. package/lib/task/commands/decisions.ts +80 -75
  138. package/lib/task/commands/files.ts +6 -6
  139. package/lib/task/commands/grep.ts +23 -51
  140. package/lib/task/commands/issue-body.ts +6 -6
  141. package/lib/task/commands/log.ts +22 -10
  142. package/lib/task/commands/show.ts +5 -6
  143. package/lib/task/commands/status.ts +8 -8
  144. package/lib/task/commit-operation.ts +25 -30
  145. package/lib/task/commit-policy.ts +1 -2
  146. package/lib/task/control-authority.ts +563 -0
  147. package/lib/task/create.ts +6 -1
  148. package/lib/task/current-contract.ts +49 -0
  149. package/lib/task/decision-details.ts +340 -0
  150. package/lib/task/decision-intents.ts +7 -2
  151. package/lib/task/delegation-receipts.ts +8 -6
  152. package/lib/task/events.ts +10 -5
  153. package/lib/task/finalization.ts +84 -42
  154. package/lib/task/index.ts +19 -28
  155. package/lib/task/ledger-intents.ts +6 -8
  156. package/lib/task/ledger.ts +17 -7
  157. package/lib/task/lifecycle.ts +20 -0
  158. package/lib/task/orchestration.ts +42 -16
  159. package/lib/task/review-artifacts.ts +53 -15
  160. package/lib/task/review-finalization.ts +33 -7
  161. package/lib/task/verification-engine.ts +33 -21
  162. package/lib/task/verification-review.ts +1 -1
  163. package/lib/task/workspace-snapshot.ts +4 -13
  164. package/lib/task/write.ts +20 -1
  165. package/lib/update.ts +6 -40
  166. package/lib/version.ts +6 -1
  167. package/package.json +1 -1
  168. package/templates/.agents/QUICKSTART.en.md +2 -3
  169. package/templates/.agents/QUICKSTART.zh-CN.md +2 -3
  170. package/templates/.agents/README.en.md +5 -3
  171. package/templates/.agents/README.zh-CN.md +5 -3
  172. package/templates/.agents/rules/README.en.md +1 -0
  173. package/templates/.agents/rules/README.zh-CN.md +1 -0
  174. package/templates/.agents/rules/compatibility-policy.en.md +40 -0
  175. package/templates/.agents/rules/compatibility-policy.zh-CN.md +40 -0
  176. package/templates/.agents/rules/create-issue.github.en.md +1 -1
  177. package/templates/.agents/rules/create-issue.github.zh-CN.md +1 -1
  178. package/templates/.agents/rules/human-decision-context.en.md +9 -7
  179. package/templates/.agents/rules/human-decision-context.zh-CN.md +9 -7
  180. package/templates/.agents/rules/issue-fields.github.en.md +1 -1
  181. package/templates/.agents/rules/issue-fields.github.zh-CN.md +1 -1
  182. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  183. package/templates/.agents/rules/issue-pr-commands.github.en.md +1 -1
  184. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +1 -1
  185. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  186. package/templates/.agents/rules/issue-sync.github.en.md +1 -1
  187. package/templates/.agents/rules/issue-sync.github.zh-CN.md +2 -2
  188. package/templates/.agents/rules/lifecycle-orchestration.en.md +4 -4
  189. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +4 -4
  190. package/templates/.agents/rules/milestone-inference.github.en.md +1 -1
  191. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +1 -1
  192. package/templates/.agents/rules/next-step-output.en.md +3 -3
  193. package/templates/.agents/rules/next-step-output.zh-CN.md +3 -3
  194. package/templates/.agents/rules/no-mid-flow-questions.en.md +1 -1
  195. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +1 -1
  196. package/templates/.agents/rules/pr-sync.en.md +2 -2
  197. package/templates/.agents/rules/pr-sync.github.en.md +3 -2
  198. package/templates/.agents/rules/pr-sync.github.zh-CN.md +3 -1
  199. package/templates/.agents/rules/pr-sync.zh-CN.md +2 -1
  200. package/templates/.agents/rules/release-commands.github.en.md +6 -0
  201. package/templates/.agents/rules/release-commands.github.zh-CN.md +6 -0
  202. package/templates/.agents/rules/review-handshake.en.md +1 -1
  203. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  204. package/templates/.agents/rules/review-method.en.md +1 -0
  205. package/templates/.agents/rules/review-method.zh-CN.md +1 -0
  206. package/templates/.agents/rules/task-management.en.md +1 -2
  207. package/templates/.agents/rules/task-management.zh-CN.md +1 -2
  208. package/templates/.agents/skills/analyze-task/SKILL.en.md +4 -3
  209. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +4 -3
  210. package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
  211. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
  212. package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
  213. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
  214. package/templates/.agents/skills/check-task/SKILL.en.md +2 -2
  215. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +2 -2
  216. package/templates/.agents/skills/close-codescan/SKILL.en.md +1 -1
  217. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +1 -1
  218. package/templates/.agents/skills/close-dependabot/SKILL.en.md +1 -1
  219. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +1 -1
  220. package/templates/.agents/skills/code-task/SKILL.en.md +4 -3
  221. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +5 -3
  222. package/templates/.agents/skills/commit/SKILL.en.md +27 -7
  223. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -4
  224. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +5 -5
  225. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +5 -5
  226. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  227. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  228. package/templates/.agents/skills/create-pr/SKILL.en.md +15 -11
  229. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +15 -11
  230. package/templates/.agents/skills/create-pr/reference/change-report.en.md +46 -0
  231. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +46 -0
  232. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +203 -0
  233. package/templates/.agents/skills/create-release-note/SKILL.en.md +5 -6
  234. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +5 -6
  235. package/templates/.agents/skills/create-task/SKILL.en.md +1 -1
  236. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -1
  237. package/templates/.agents/skills/import-issue/SKILL.en.md +1 -1
  238. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
  239. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -4
  240. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -4
  241. package/templates/.agents/skills/restore-task/SKILL.en.md +1 -1
  242. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +1 -1
  243. package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -3
  244. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -3
  245. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -0
  246. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -0
  247. package/templates/.agents/skills/review-code/SKILL.en.md +5 -3
  248. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -3
  249. package/templates/.agents/skills/review-code/config/verify.en.json +1 -0
  250. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -0
  251. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +9 -6
  252. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +9 -6
  253. package/templates/.agents/skills/review-plan/SKILL.en.md +5 -3
  254. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -3
  255. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -0
  256. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -0
  257. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +7 -3
  258. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +7 -3
  259. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +1 -1
  260. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +1 -1
  261. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -2
  262. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -2
  263. package/templates/.agents/skills/run-task/SKILL.en.md +6 -2
  264. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -2
  265. package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
  266. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
  267. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
  268. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
  269. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +159 -104
  270. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  271. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  272. package/templates/.agents/templates/task.en.md +1 -1
  273. package/templates/.agents/templates/task.zh-CN.md +1 -1
  274. package/templates/.claude/commands/analyze-task.en.md +1 -1
  275. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  276. package/templates/.claude/commands/block-task.en.md +1 -1
  277. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  278. package/templates/.claude/commands/cancel-task.en.md +1 -1
  279. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  280. package/templates/.claude/commands/check-task.en.md +1 -1
  281. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  282. package/templates/.claude/commands/code-task.en.md +1 -1
  283. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  284. package/templates/.claude/commands/commit.en.md +1 -1
  285. package/templates/.claude/commands/commit.zh-CN.md +1 -1
  286. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  287. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  288. package/templates/.claude/commands/complete-task.en.md +1 -1
  289. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  290. package/templates/.claude/commands/create-pr.en.md +1 -1
  291. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  292. package/templates/.claude/commands/plan-task.en.md +1 -1
  293. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  294. package/templates/.claude/commands/review-analysis.en.md +1 -1
  295. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  296. package/templates/.claude/commands/review-code.en.md +1 -1
  297. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  298. package/templates/.claude/commands/review-plan.en.md +1 -1
  299. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  300. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  301. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  302. package/templates/.claude/commands/run-task.en.md +1 -1
  303. package/templates/.claude/commands/run-task.zh-CN.md +1 -1
  304. package/templates/.claude/commands/watch-pr.en.md +1 -1
  305. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  306. package/templates/.traecli/commands/update-agent-infra.en.md +7 -0
  307. package/templates/.traecli/commands/update-agent-infra.zh-CN.md +7 -0
  308. package/dist/lib/builtin-tuis.js +0 -40
  309. package/lib/builtin-tuis.ts +0 -56
package/README.md CHANGED
@@ -121,6 +121,15 @@ brew install fitlab-ai/tap/agent-infra
121
121
 
122
122
  ### Updating agent-infra
123
123
 
124
+ ```bash
125
+ ai update
126
+ ```
127
+
128
+ `ai update` updates the installed agent-infra CLI. In an initialized project,
129
+ use `ai sync` to refresh project seed files and the file registry.
130
+
131
+ The equivalent package-manager commands remain:
132
+
124
133
  ```bash
125
134
  npm update -g @fitlab-ai/agent-infra
126
135
  # or, if installed via Homebrew:
@@ -142,7 +151,7 @@ ai init
142
151
  # or: agent-infra init
143
152
  ```
144
153
 
145
- The CLI collects project metadata, lets you select the enabled Agent Clients, installs their `update-agent-infra` seed commands, and generates `.agents/.airc.json`.
154
+ The CLI collects project metadata, lets you select the enabled Agent Clients, installs any client-specific `update-agent-infra` seed commands, and generates `.agents/.airc.json`.
146
155
 
147
156
  > `ai` is a shorthand for `agent-infra`. Both commands are equivalent.
148
157
 
@@ -156,12 +165,13 @@ Open the project in any AI TUI and run `update-agent-infra`:
156
165
  | Codex | `$update-agent-infra` |
157
166
  | Antigravity CLI | `/update-agent-infra` |
158
167
  | OpenCode | `/update-agent-infra` |
168
+ | TraeCode CLI | `/update-agent-infra` |
159
169
 
160
170
  This detects the packaged template version and renders all managed files. The same command is used both for first-time setup and for future template upgrades.
161
171
 
162
172
  ## Core Commands
163
173
 
164
- Manage the four built-in Agent Clients independently from the project lifecycle:
174
+ Manage the five built-in Agent Clients independently from the project lifecycle:
165
175
 
166
176
  ```bash
167
177
  ai agent-client list
@@ -171,7 +181,7 @@ ai agent-client disable antigravity-cli
171
181
  ai agent-client configure
172
182
  ```
173
183
 
174
- The most-used lifecycle commands, in delivery order. The command prefix varies by TUI (`/skill` in Claude Code/Antigravity/OpenCode and `$skill` in Codex); the workflow semantics stay the same.
184
+ The most-used lifecycle commands, in delivery order. The command prefix varies by TUI (`/skill` in Claude Code/Antigravity/OpenCode/TraeCode and `$skill` in Codex); the workflow semantics stay the same.
175
185
 
176
186
  | Command | Purpose |
177
187
  |---------|---------|
package/README.zh-CN.md CHANGED
@@ -120,6 +120,15 @@ brew install fitlab-ai/tap/agent-infra
120
120
 
121
121
  ### 更新 agent-infra
122
122
 
123
+ ```bash
124
+ ai update
125
+ ```
126
+
127
+ `ai update` 用于更新已安装的 agent-infra CLI。在已初始化项目中,使用
128
+ `ai sync` 刷新项目 seed files 和文件注册表。
129
+
130
+ 对应的包管理器命令仍然是:
131
+
123
132
  ```bash
124
133
  npm update -g @fitlab-ai/agent-infra
125
134
  # 或者通过 Homebrew 安装时:
@@ -141,7 +150,7 @@ ai init
141
150
  # 或:agent-infra init
142
151
  ```
143
152
 
144
- CLI 会收集项目元数据,让你选择启用的 Agent Client,为其安装 `update-agent-infra` 种子命令,并生成 `.agents/.airc.json`。
153
+ CLI 会收集项目元数据,让你选择启用的 Agent Client,安装该客户端需要的 `update-agent-infra` 种子命令,并生成 `.agents/.airc.json`。
145
154
 
146
155
  > `ai` 是 `agent-infra` 的简写命令,两者等价。
147
156
 
@@ -155,12 +164,13 @@ CLI 会收集项目元数据,让你选择启用的 Agent Client,为其安装
155
164
  | Codex | `$update-agent-infra` |
156
165
  | Antigravity CLI | `/update-agent-infra` |
157
166
  | OpenCode | `/update-agent-infra` |
167
+ | TraeCode CLI | `/update-agent-infra` |
158
168
 
159
169
  该命令会检测当前打包模板版本并渲染所有受管理文件。首次安装和后续升级都使用同一条命令。
160
170
 
161
171
  ## 核心命令
162
172
 
163
- 以下命令用于独立管理四个内建 Agent Client:
173
+ 以下命令用于独立管理五个内建 Agent Client:
164
174
 
165
175
  ```bash
166
176
  ai agent-client list
@@ -170,7 +180,7 @@ ai agent-client disable antigravity-cli
170
180
  ai agent-client configure
171
181
  ```
172
182
 
173
- 最常用的生命周期命令,按交付顺序排列。命令前缀因 TUI 而异(Claude Code/Antigravity/OpenCode 用 `/skill`,Codex 用 `$skill`),工作流语义保持一致。
183
+ 最常用的生命周期命令,按交付顺序排列。命令前缀因 TUI 而异(Claude Code/Antigravity/OpenCode/TraeCode 用 `/skill`,Codex 用 `$skill`),工作流语义保持一致。
174
184
 
175
185
  | 命令 | 用途 |
176
186
  |------|------|
package/bin/cli.ts CHANGED
@@ -21,12 +21,13 @@ Commands:
21
21
  decide Record a ruling; code-stage decisions require explicit implementation intent
22
22
  help Show this help message
23
23
  init Initialize a new project with update-agent-infra seed command
24
- merge Merge tasks from another workspace directory (active/blocked/completed/archive)
24
+ merge Merge tasks from another current workspace directory (active/blocked/completed/archive)
25
25
  run Schedule a lifecycle skill in the task sandbox tmux session
26
26
  sandbox, s Manage Docker-based AI sandboxes
27
27
  server Run the local AI collaboration daemon (start/stop/status/logs)
28
28
  task, t Read-only views of .agents/workspace tasks
29
- update Update seed files and sync file registry for an existing project
29
+ sync Update seed files and sync file registry for an existing project
30
+ update Update the agent-infra CLI itself
30
31
  version Show version
31
32
 
32
33
  'ai' and 'agent-infra' are interchangeable; 'ai' is the shorter form.
@@ -171,10 +172,22 @@ switch (command) {
171
172
  break;
172
173
  }
173
174
  case 'update': {
174
- const imported = await importCommand('../lib/update.ts');
175
+ const imported = await importCommand('../lib/self-update.ts');
175
176
  if (!imported) break;
176
177
  const { cmdUpdate } = imported;
177
- await cmdUpdate().catch((e: unknown) => {
178
+ const code = await cmdUpdate().catch((e: unknown) => {
179
+ process.stderr.write(`Error: ${errorMessage(e)}\n`);
180
+ process.exitCode = 1;
181
+ return 1;
182
+ });
183
+ if (code !== 0) process.exitCode = code;
184
+ break;
185
+ }
186
+ case 'sync': {
187
+ const imported = await importCommand('../lib/update.ts');
188
+ if (!imported) break;
189
+ const { cmdSync } = imported;
190
+ await cmdSync().catch((e: unknown) => {
178
191
  process.stderr.write(`Error: ${errorMessage(e)}\n`);
179
192
  process.exitCode = 1;
180
193
  });
package/dist/bin/cli.js CHANGED
@@ -25,12 +25,13 @@ Commands:
25
25
  decide Record a ruling; code-stage decisions require explicit implementation intent
26
26
  help Show this help message
27
27
  init Initialize a new project with update-agent-infra seed command
28
- merge Merge tasks from another workspace directory (active/blocked/completed/archive)
28
+ merge Merge tasks from another current workspace directory (active/blocked/completed/archive)
29
29
  run Schedule a lifecycle skill in the task sandbox tmux session
30
30
  sandbox, s Manage Docker-based AI sandboxes
31
31
  server Run the local AI collaboration daemon (start/stop/status/logs)
32
32
  task, t Read-only views of .agents/workspace tasks
33
- update Update seed files and sync file registry for an existing project
33
+ sync Update seed files and sync file registry for an existing project
34
+ update Update the agent-infra CLI itself
34
35
  version Show version
35
36
 
36
37
  'ai' and 'agent-infra' are interchangeable; 'ai' is the shorter form.
@@ -182,11 +183,25 @@ switch (command) {
182
183
  break;
183
184
  }
184
185
  case 'update': {
185
- const imported = await importCommand('../lib/update.ts');
186
+ const imported = await importCommand('../lib/self-update.ts');
186
187
  if (!imported)
187
188
  break;
188
189
  const { cmdUpdate } = imported;
189
- await cmdUpdate().catch((e) => {
190
+ const code = await cmdUpdate().catch((e) => {
191
+ process.stderr.write(`Error: ${errorMessage(e)}\n`);
192
+ process.exitCode = 1;
193
+ return 1;
194
+ });
195
+ if (code !== 0)
196
+ process.exitCode = code;
197
+ break;
198
+ }
199
+ case 'sync': {
200
+ const imported = await importCommand('../lib/update.ts');
201
+ if (!imported)
202
+ break;
203
+ const { cmdSync } = imported;
204
+ await cmdSync().catch((e) => {
190
205
  process.stderr.write(`Error: ${errorMessage(e)}\n`);
191
206
  process.exitCode = 1;
192
207
  });
@@ -5,10 +5,56 @@ if (major < 22 || (major === 22 && minor < 9)) {
5
5
  process.exit(1);
6
6
  }
7
7
  const command = process.argv[2] || '';
8
- if (process.env.AGENT_INFRA_CONTROL_TOKEN
9
- && (command === 'task-lifecycle' || command === 'task-orchestration' || command === 'task-finalization')) {
10
- const { sandboxControl } = await import('../lib/internal/sandbox-control.js');
11
- await sandboxControl(['client', command, ...process.argv.slice(3)]);
8
+ const taskControlCommand = command === 'task-lifecycle' || command === 'task-orchestration' || command === 'task-finalization';
9
+ function taskControlTransportFailure(message) {
10
+ process.stdout.write(`${JSON.stringify({
11
+ status: 'failed', changed: false,
12
+ error: { code: 'TASK_CONTROL_TRANSPORT_INVALID', message }
13
+ })}\n`);
14
+ process.exit(1);
15
+ }
16
+ if (taskControlCommand) {
17
+ const env = process.env;
18
+ const executorMarked = Boolean(env.AGENT_INFRA_EXECUTOR_MANIFEST);
19
+ const controlKeys = [
20
+ 'AGENT_INFRA_CONTROL_TOKEN', 'AGENT_INFRA_CONTROL_GENERATION',
21
+ 'AGENT_INFRA_CONTROL_DIR', 'AGENT_INFRA_CONTROL_STATUS_DIR'
22
+ ];
23
+ const hasControlMarker = controlKeys.some((key) => Boolean(env[key]))
24
+ || Boolean(env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING);
25
+ const taskBindingMarker = hasControlMarker && Boolean(env.AGENT_INFRA_TASK_ID);
26
+ const hasCompleteClientConfig = controlKeys.every((key) => Boolean(env[key]))
27
+ && !env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING
28
+ && (!taskBindingMarker || Boolean(env.AGENT_INFRA_RUNTIME_DIR));
29
+ if (executorMarked) {
30
+ taskControlTransportFailure('executor context is only valid for sandbox-control execute');
31
+ }
32
+ if ((hasControlMarker || taskBindingMarker) && !hasCompleteClientConfig) {
33
+ taskControlTransportFailure('sandbox client control configuration is incomplete or conflicting');
34
+ }
35
+ if (hasCompleteClientConfig) {
36
+ const { sandboxControl } = await import('../lib/internal/sandbox-control.js');
37
+ await sandboxControl(['client', command, ...process.argv.slice(3)]);
38
+ }
39
+ else {
40
+ switch (command) {
41
+ case 'task-orchestration': {
42
+ const { taskOrchestration } = await import('../lib/internal/task-orchestration.js');
43
+ await taskOrchestration(process.argv.slice(3));
44
+ break;
45
+ }
46
+ case 'task-lifecycle': {
47
+ const { taskLifecycle } = await import('../lib/internal/task-lifecycle.js');
48
+ taskLifecycle(process.argv.slice(3));
49
+ break;
50
+ }
51
+ case 'task-finalization': {
52
+ const { taskFinalization } = await import('../lib/internal/task-finalization.js');
53
+ taskFinalization(process.argv.slice(3));
54
+ break;
55
+ }
56
+ }
57
+ }
12
58
  }
13
59
  else
14
60
  switch (command) {
@@ -157,6 +203,11 @@ else
157
203
  taskVerify(process.argv.slice(3));
158
204
  break;
159
205
  }
206
+ case 'task-validate': {
207
+ const { taskValidate } = await import('../lib/internal/task-validate.js');
208
+ taskValidate(process.argv.slice(3));
209
+ break;
210
+ }
160
211
  default:
161
212
  process.stdout.write(`${JSON.stringify({
162
213
  status: 'failed',
@@ -96,7 +96,6 @@ async function cmdAgentClient(args) {
96
96
  throw new AgentClientCommandError('AGENT_CLIENT_ARGUMENT_INVALID', 'status accepts no arguments');
97
97
  }
98
98
  const plan = workflowPlan(projectRoot, config, { type: 'none' });
99
- process.stdout.write(`source: ${plan.source}\n`);
100
99
  printState(plan.desired);
101
100
  for (const seed of plan.seedOperations) {
102
101
  process.stdout.write(` seed ${seed.target}: ${seed.kind}\n`);
@@ -145,25 +145,32 @@ function verifyLifecycleBuildIdentity(expected, actual) {
145
145
  return {
146
146
  ok: false,
147
147
  code: 'CODEX_LIFECYCLE_PROTOCOL_MISMATCH',
148
- message: 'Codex lifecycle protocol version does not match'
148
+ message: 'Codex lifecycle protocol version does not match',
149
+ warnings: []
149
150
  };
150
151
  }
152
+ const warnings = [];
151
153
  if (actual.packageVersion !== expected.packageVersion
152
154
  || actual.internalExecutableBuildHash !== expected.internalExecutableBuildHash) {
153
- return {
154
- ok: false,
155
+ warnings.push({
155
156
  code: 'CODEX_LIFECYCLE_BUILD_MISMATCH',
156
- message: 'Codex lifecycle executable build identity does not match'
157
- };
157
+ message: 'Codex lifecycle executable build identity differs; rebuild the sandbox if the runtime is stale',
158
+ action: 'rebuild-sandbox'
159
+ });
158
160
  }
159
161
  if (actual.lifecycleContractHash !== expected.lifecycleContractHash) {
160
- return {
161
- ok: false,
162
+ warnings.push({
162
163
  code: 'CODEX_LIFECYCLE_CONTRACT_MISMATCH',
163
- message: 'Codex lifecycle contract identity does not match'
164
- };
164
+ message: 'Codex lifecycle contract identity differs; rebuild the sandbox if the runtime is stale',
165
+ action: 'rebuild-sandbox'
166
+ });
165
167
  }
166
- return { ok: true, code: null, message: null };
168
+ return {
169
+ ok: true,
170
+ code: null,
171
+ message: null,
172
+ warnings: Object.freeze(warnings)
173
+ };
167
174
  }
168
175
  export { LIFECYCLE_PROTOCOL_VERSION, computeLifecycleBuildIdentity, isCanonicalLifecyclePackageVersion, isLifecycleProtocolVersion, readLifecycleManifestFiles, resolveLifecycleExecutableFiles, verifyLifecycleBuildIdentity };
169
176
  //# sourceMappingURL=build-identity.js.map
@@ -2,28 +2,11 @@ import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { getProcessIdentityState } from '../../../server/process-state.js';
5
- import { computeLifecycleBuildIdentity } from './build-identity.js';
5
+ import { computeLifecycleBuildIdentity, verifyLifecycleBuildIdentity } from './build-identity.js';
6
6
  const HEX_256 = /^[a-f0-9]{64}$/u;
7
7
  function exactKeys(value, keys) {
8
8
  return Object.keys(value).sort().join(',') === [...keys].sort().join(',');
9
9
  }
10
- function digestProfiles(repoRoot) {
11
- const files = [
12
- path.join(repoRoot, '.codex', 'agents', 'agent-infra-lifecycle-executor.toml'),
13
- path.join(repoRoot, '.codex', 'agents', 'agent-infra-lifecycle-reviewer.toml')
14
- ];
15
- const hash = crypto.createHash('sha256');
16
- for (const file of files.sort()) {
17
- const stat = fs.lstatSync(file);
18
- if (!stat.isFile() || stat.isSymbolicLink())
19
- throw new Error('CODEX_SANDBOX_CONTROLLER_BUNDLE_MISMATCH');
20
- hash.update(path.basename(file));
21
- hash.update('\0');
22
- hash.update(fs.readFileSync(file));
23
- hash.update('\0');
24
- }
25
- return hash.digest('hex');
26
- }
27
10
  function validProcess(value) {
28
11
  if (!value || typeof value !== 'object' || Array.isArray(value))
29
12
  return false;
@@ -53,7 +36,7 @@ function validateContext(value) {
53
36
  if (!exactKeys(context, [
54
37
  'buildIdentity', 'controlGeneration', 'controllerInstanceDigest', 'controllerLease',
55
38
  'controllerProcess', 'expiresAt', 'hookDefinitionHash', 'issuedAt',
56
- 'lifecycleProfilesHash', 'taskId', 'version'
39
+ 'taskId', 'version'
57
40
  ])
58
41
  || context.version !== 2
59
42
  || typeof context.taskId !== 'string' || context.taskId.length === 0
@@ -68,13 +51,12 @@ function validateContext(value) {
68
51
  || !Number.isSafeInteger(context.expiresAt)
69
52
  || context.expiresAt <= context.issuedAt
70
53
  || !validBuildIdentity(context.buildIdentity)
71
- || typeof context.hookDefinitionHash !== 'string' || !HEX_256.test(context.hookDefinitionHash)
72
- || typeof context.lifecycleProfilesHash !== 'string' || !HEX_256.test(context.lifecycleProfilesHash)) {
54
+ || typeof context.hookDefinitionHash !== 'string' || !HEX_256.test(context.hookDefinitionHash)) {
73
55
  throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
74
56
  }
75
57
  return context;
76
58
  }
77
- export function contextFromControllerLease(lease, hashes) {
59
+ export function contextFromControllerLease(lease, input) {
78
60
  return Object.freeze({
79
61
  version: 2,
80
62
  taskId: lease.taskId,
@@ -85,8 +67,7 @@ export function contextFromControllerLease(lease, hashes) {
85
67
  issuedAt: lease.issuedAt,
86
68
  expiresAt: lease.expiresAt,
87
69
  buildIdentity: lease.buildIdentity,
88
- hookDefinitionHash: hashes.hookDefinitionHash,
89
- lifecycleProfilesHash: hashes.lifecycleProfilesHash
70
+ hookDefinitionHash: input.hookDefinitionHash
90
71
  });
91
72
  }
92
73
  export function writeCodexSandboxControllerContext(contextPath, context) {
@@ -102,7 +83,7 @@ export function writeCodexSandboxControllerContext(contextPath, context) {
102
83
  fs.rmSync(temporary, { force: true });
103
84
  }
104
85
  }
105
- export function verifyCodexSandboxControllerContext(contextPath, options = {}) {
86
+ export function verifyCodexSandboxControllerContextWithWarnings(contextPath, options = {}) {
106
87
  let stat;
107
88
  try {
108
89
  stat = fs.lstatSync(contextPath);
@@ -129,12 +110,11 @@ export function verifyCodexSandboxControllerContext(contextPath, options = {}) {
129
110
  || state !== 'alive') {
130
111
  throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
131
112
  }
132
- if (JSON.stringify(computeLifecycleBuildIdentity(repoRoot)) !== JSON.stringify(context.buildIdentity)
133
- || crypto.createHash('sha256').update(fs.readFileSync(path.join(repoRoot, '.codex', 'hooks.json'))).digest('hex') !== context.hookDefinitionHash
134
- || digestProfiles(repoRoot) !== context.lifecycleProfilesHash) {
135
- throw new Error('CODEX_SANDBOX_CONTROLLER_BUNDLE_MISMATCH');
136
- }
137
- return Object.freeze(context);
113
+ const currentBuildIdentity = computeLifecycleBuildIdentity(repoRoot);
114
+ const identity = verifyLifecycleBuildIdentity(context.buildIdentity, currentBuildIdentity);
115
+ if (!identity.ok)
116
+ throw new Error(`${identity.code}: ${identity.message}`);
117
+ return Object.freeze({ context: Object.freeze(context), warnings: identity.warnings });
138
118
  }
139
119
  export function controllerProofFromContext(context) {
140
120
  return Object.freeze({
@@ -8,22 +8,8 @@ import * as toml from 'smol-toml';
8
8
  import { requestCodexControllerClose, requestCodexControllerOpen, requestCodexControllerVerify, requestSandboxControl } from '../../../sandbox/control/client.js';
9
9
  import { readSandboxControlStatus } from '../../../sandbox/control/state.js';
10
10
  import { getProcessStartTime } from '../../../server/process-state.js';
11
- import { computeLifecycleBuildIdentity } from './build-identity.js';
12
- import { contextFromControllerLease, controllerProofFromContext, verifyCodexSandboxControllerContext as verifyContextFile, writeCodexSandboxControllerContext } from './controller-context.js';
13
- function digestFiles(files) {
14
- const hash = crypto.createHash('sha256');
15
- for (const file of [...files].sort()) {
16
- const stat = fs.lstatSync(file);
17
- if (!stat.isFile() || stat.isSymbolicLink()) {
18
- throw new Error('CODEX_SANDBOX_CONTROLLER_BUNDLE_MISMATCH');
19
- }
20
- hash.update(path.basename(file));
21
- hash.update('\0');
22
- hash.update(fs.readFileSync(file));
23
- hash.update('\0');
24
- }
25
- return hash.digest('hex');
26
- }
11
+ import { LIFECYCLE_PROTOCOL_VERSION } from './build-identity.js';
12
+ import { contextFromControllerLease, controllerProofFromContext, verifyCodexSandboxControllerContextWithWarnings as verifyContextFileWithWarnings, writeCodexSandboxControllerContext } from './controller-context.js';
27
13
  function copyRegular(source, destination, mode) {
28
14
  const stat = fs.lstatSync(source);
29
15
  if (!stat.isFile() || stat.isSymbolicLink()) {
@@ -108,14 +94,15 @@ function verifyControl(taskId, control) {
108
94
  if (payload.taskId !== taskId)
109
95
  throw new Error('CODEX_SANDBOX_CONTROLLER_TASK_BINDING_INVALID');
110
96
  }
111
- function verifyCodexSandboxControllerContext(contextPath, options = {}) {
97
+ function verifyCodexSandboxControllerContextWithWarnings(contextPath, options = {}) {
112
98
  const control = options.control ?? controlFromEnvironment();
113
- const context = verifyContextFile(contextPath, {
99
+ const fileVerification = verifyContextFileWithWarnings(contextPath, {
114
100
  repoRoot: options.repoRoot,
115
101
  now: options.now,
116
102
  generation: control.generation,
117
103
  probeProcess: options.probeProcess
118
104
  });
105
+ const context = fileVerification.context;
119
106
  const verified = (options.requestControllerVerify ?? requestCodexControllerVerify)({
120
107
  controllerProof: controllerProofFromContext(context),
121
108
  ...control,
@@ -126,7 +113,10 @@ function verifyCodexSandboxControllerContext(contextPath, options = {}) {
126
113
  || verified.binding.controllerInstanceDigest !== context.controllerInstanceDigest) {
127
114
  throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
128
115
  }
129
- return context;
116
+ return Object.freeze({
117
+ context,
118
+ warnings: fileVerification.warnings
119
+ });
130
120
  }
131
121
  function detectedCodexVersion() {
132
122
  const result = spawnSync('codex', ['--version'], { encoding: 'utf8' });
@@ -261,29 +251,21 @@ function prepareCodexSandboxController(input, options = {}) {
261
251
  copyRegular(hooks, path.join(home, 'hooks.json'), 0o600);
262
252
  copyRegular(executor, path.join(home, 'agents', path.basename(executor)), 0o600);
263
253
  copyRegular(reviewer, path.join(home, 'agents', path.basename(reviewer)), 0o600);
264
- if (crypto.createHash('sha256').update(fs.readFileSync(path.join(home, 'hooks.json'))).digest('hex')
265
- !== crypto.createHash('sha256').update(fs.readFileSync(hooks)).digest('hex')
266
- || digestFiles([
267
- path.join(home, 'agents', path.basename(executor)),
268
- path.join(home, 'agents', path.basename(reviewer))
269
- ]) !== digestFiles([executor, reviewer])) {
270
- throw new Error('CODEX_SANDBOX_CONTROLLER_BUNDLE_MISMATCH');
271
- }
272
- const buildIdentity = computeLifecycleBuildIdentity(repoRoot);
273
254
  const opened = (options.openController ?? requestCodexControllerOpen)({
274
255
  controllerProcess: { pid: process.pid, startTime: parentStartTime },
275
256
  ...control,
276
257
  timeoutMs: 30_000
277
258
  });
278
259
  const taskId = opened.lease.taskId;
260
+ if (opened.lease.buildIdentity.protocolVersion !== LIFECYCLE_PROTOCOL_VERSION) {
261
+ throw new Error('CODEX_LIFECYCLE_PROTOCOL_MISMATCH: Codex lifecycle protocol version does not match');
262
+ }
279
263
  context = contextFromControllerLease(opened.lease, {
280
- hookDefinitionHash: crypto.createHash('sha256').update(fs.readFileSync(hooks)).digest('hex'),
281
- lifecycleProfilesHash: digestFiles([executor, reviewer])
264
+ hookDefinitionHash: crypto.createHash('sha256').update(fs.readFileSync(hooks)).digest('hex')
282
265
  });
283
266
  if (opened.lease.controlGeneration !== control.generation
284
267
  || opened.lease.controllerProcess.pid !== process.pid
285
- || opened.lease.controllerProcess.startTime !== parentStartTime
286
- || JSON.stringify(opened.lease.buildIdentity) !== JSON.stringify(buildIdentity)) {
268
+ || opened.lease.controllerProcess.startTime !== parentStartTime) {
287
269
  throw new Error('SANDBOX_CONTROL_RESULT_INVALID');
288
270
  }
289
271
  (options.verifyTaskBinding ?? verifyControl)(taskId, control);
@@ -383,5 +365,5 @@ async function runCodexSandboxController(input, options = {}) {
383
365
  prepared.cleanup();
384
366
  }
385
367
  }
386
- export { prepareCodexSandboxController, runCodexSandboxController, verifyCodexSandboxControllerContext, controllerProofFromContext };
368
+ export { prepareCodexSandboxController, runCodexSandboxController, verifyCodexSandboxControllerContextWithWarnings, controllerProofFromContext };
387
369
  //# sourceMappingURL=sandbox-controller.js.map
@@ -30,6 +30,8 @@ function resolveHostCatalogPath(value, hostHomeDir) {
30
30
  }
31
31
  }
32
32
  const CODEX_DISABLED_FEATURE_FLAGS = ['apps', 'enable_mcp_apps'];
33
+ const SANDBOX_CODEX_HOOKS_PATH = '/workspace/.codex/hooks.json';
34
+ const CODEX_HOOK_TRUST_HASH = /^sha256:[a-f0-9]{64}$/;
33
35
  function removeCodexMcpServers(sandboxParsed) {
34
36
  if (!Object.hasOwn(sandboxParsed, 'mcp_servers')) {
35
37
  return false;
@@ -61,19 +63,58 @@ function inheritDisabledCodexFeatureFlags(sandboxParsed, hostParsed) {
61
63
  }
62
64
  return changed;
63
65
  }
64
- function ensureCodexModelInheritance(toolDir, hostHomeDir, containerCodexDir = '/home/devuser/.codex') {
65
- if (!hostHomeDir) {
66
- return;
66
+ function inheritCodexHookTrustState(sandboxParsed, hostParsed, hostProjectDir) {
67
+ if (!hostProjectDir) {
68
+ return false;
67
69
  }
68
- const hostConfigPath = path.join(hostHomeDir, '.codex', 'config.toml');
69
- if (!fs.existsSync(hostConfigPath)) {
70
- return;
70
+ if (Object.hasOwn(sandboxParsed, 'hooks') && !isJsonObjectRecord(sandboxParsed.hooks)) {
71
+ return false;
71
72
  }
72
- let hostParsed;
73
- try {
74
- hostParsed = toml.parse(fs.readFileSync(hostConfigPath, 'utf8'));
73
+ const sandboxHooks = sandboxParsed.hooks ?? {};
74
+ if (Object.hasOwn(sandboxHooks, 'state') && !isJsonObjectRecord(sandboxHooks.state)) {
75
+ return false;
75
76
  }
76
- catch {
77
+ const sandboxState = sandboxHooks.state ?? {};
78
+ const sandboxPrefix = `${SANDBOX_CODEX_HOOKS_PATH}:`;
79
+ const nextState = Object.fromEntries(Object.entries(sandboxState).filter(([key]) => !key.startsWith(sandboxPrefix)));
80
+ const hostState = isJsonObjectRecord(hostParsed.hooks)
81
+ && isJsonObjectRecord(hostParsed.hooks.state)
82
+ ? hostParsed.hooks.state
83
+ : {};
84
+ const hostPrefix = `${path.join(hostProjectDir, '.codex', 'hooks.json')}:`;
85
+ for (const [key, value] of Object.entries(hostState)) {
86
+ if (!key.startsWith(hostPrefix) || !isJsonObjectRecord(value)) {
87
+ continue;
88
+ }
89
+ const trustedHash = value.trusted_hash;
90
+ if (typeof trustedHash !== 'string' || !CODEX_HOOK_TRUST_HASH.test(trustedHash)) {
91
+ continue;
92
+ }
93
+ nextState[`${sandboxPrefix}${key.slice(hostPrefix.length)}`] = {
94
+ trusted_hash: trustedHash,
95
+ ...(typeof value.enabled === 'boolean' ? { enabled: value.enabled } : {})
96
+ };
97
+ }
98
+ if (JSON.stringify(sandboxState) === JSON.stringify(nextState)) {
99
+ return false;
100
+ }
101
+ if (Object.keys(nextState).length > 0) {
102
+ sandboxHooks.state = nextState;
103
+ sandboxParsed.hooks = sandboxHooks;
104
+ }
105
+ else {
106
+ delete sandboxHooks.state;
107
+ if (Object.keys(sandboxHooks).length > 0) {
108
+ sandboxParsed.hooks = sandboxHooks;
109
+ }
110
+ else {
111
+ delete sandboxParsed.hooks;
112
+ }
113
+ }
114
+ return true;
115
+ }
116
+ function ensureCodexModelInheritance(toolDir, hostHomeDir, containerCodexDir = '/home/devuser/.codex', hostProjectDir) {
117
+ if (!hostHomeDir) {
77
118
  return;
78
119
  }
79
120
  const sandboxConfigPath = path.join(toolDir, 'config.toml');
@@ -87,8 +128,25 @@ function ensureCodexModelInheritance(toolDir, hostHomeDir, containerCodexDir = '
87
128
  return;
88
129
  }
89
130
  }
131
+ const hostConfigPath = path.join(hostHomeDir, '.codex', 'config.toml');
132
+ let hostParsed = null;
133
+ if (fs.existsSync(hostConfigPath)) {
134
+ try {
135
+ hostParsed = toml.parse(fs.readFileSync(hostConfigPath, 'utf8'));
136
+ }
137
+ catch {
138
+ // An unavailable host trust source must not leave previously projected trust active.
139
+ }
140
+ }
141
+ if (!hostParsed) {
142
+ if (inheritCodexHookTrustState(sandboxParsed, {}, hostProjectDir)) {
143
+ fs.writeFileSync(sandboxConfigPath, `${toml.stringify(sandboxParsed)}\n`, 'utf8');
144
+ }
145
+ return;
146
+ }
90
147
  let changed = removeCodexMcpServers(sandboxParsed);
91
148
  changed = inheritDisabledCodexFeatureFlags(sandboxParsed, hostParsed) || changed;
149
+ changed = inheritCodexHookTrustState(sandboxParsed, hostParsed, hostProjectDir) || changed;
92
150
  const inheritSpecs = [
93
151
  ['model', 'string'],
94
152
  ['model_reasoning_effort', 'string'],
@@ -151,7 +209,10 @@ const codexBeforeContainerCreateHook = {
151
209
  message: 'Codex sandbox hook requires its resolved tool state.'
152
210
  };
153
211
  }
154
- ensureCodexModelInheritance(entry.dir, create.hostHome, entry.tool.containerMount);
212
+ const hostProjectDir = typeof context.config?.repoRoot === 'string'
213
+ ? context.config.repoRoot
214
+ : undefined;
215
+ ensureCodexModelInheritance(entry.dir, create.hostHome, entry.tool.containerMount, hostProjectDir);
155
216
  ensureCodexWorkspaceTrust(entry.dir);
156
217
  return { status: 'ready' };
157
218
  }
@@ -3,11 +3,13 @@ import { claudeCodeAdapter } from './claude-code.js';
3
3
  import { codexAdapter } from './codex.js';
4
4
  import { antigravityCliAdapter } from './antigravity-cli.js';
5
5
  import { opencodeAdapter } from './opencode.js';
6
+ import { traecliAdapter } from './traecli.js';
6
7
  const adaptersById = new Map([
7
8
  claudeCodeAdapter,
8
9
  codexAdapter,
9
10
  antigravityCliAdapter,
10
- opencodeAdapter
11
+ opencodeAdapter,
12
+ traecliAdapter
11
13
  ].map((adapter) => [adapter.id, adapter]));
12
14
  const BUILTIN_AGENT_CLIENT_ADAPTERS = Object.freeze(AGENT_CLIENT_IDS.map((id) => {
13
15
  const adapter = adaptersById.get(id);
@@ -20,12 +20,8 @@ function ensureOpenCodeSandboxState(toolDir, hostHome, hostEnv = {}) {
20
20
  const canonicalConfigDir = path.join(toolDir, '.xdg', 'config', 'opencode');
21
21
  const canonicalStateDir = path.join(toolDir, '.xdg', 'state', 'opencode');
22
22
  const canonicalConfigPath = path.join(canonicalConfigDir, 'opencode.json');
23
- const legacyConfigPath = path.join(toolDir, 'opencode.json');
24
23
  fs.mkdirSync(canonicalConfigDir, { recursive: true });
25
24
  fs.mkdirSync(canonicalStateDir, { recursive: true });
26
- if (!fs.existsSync(canonicalConfigPath) && fs.existsSync(legacyConfigPath)) {
27
- fs.copyFileSync(legacyConfigPath, canonicalConfigPath, fs.constants.COPYFILE_EXCL);
28
- }
29
25
  const hostConfigRoot = resolveXdgRoot(hostEnv.XDG_CONFIG_HOME, path.join(hostHome, '.config'));
30
26
  const hostConfig = readJsonObject(path.join(hostConfigRoot, 'opencode', 'opencode.json'));
31
27
  if (!hostConfig) {