@ours.network/fleet 1.2.0-nightly.5 → 1.2.0-nightly.51

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 (330) hide show
  1. package/README.md +263 -53
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +9 -0
  5. package/dist/agent-ours/correspondence.d.ts +10 -0
  6. package/dist/agent-ours/correspondence.js +1 -0
  7. package/dist/agent-ours/harness.js +8 -0
  8. package/dist/agent-ours/runtime.d.ts +6 -0
  9. package/dist/agent-ours/runtime.js +36 -0
  10. package/dist/agent-ours/service.js +33 -13
  11. package/dist/application/codex-models.d.ts +15 -0
  12. package/dist/application/codex-models.js +56 -0
  13. package/dist/application/conversation-history.d.ts +25 -0
  14. package/dist/application/conversation-history.js +189 -0
  15. package/dist/application/fleet-query-service.d.ts +1 -1
  16. package/dist/application/fleet-query-service.js +2 -2
  17. package/dist/application/legacy-supervisor-identity.d.ts +7 -0
  18. package/dist/application/legacy-supervisor-identity.js +43 -0
  19. package/dist/application/model-catalog.d.ts +1 -1
  20. package/dist/application/model-catalog.js +5 -2
  21. package/dist/application/preset-provenance.d.ts +19 -0
  22. package/dist/application/preset-provenance.js +59 -0
  23. package/dist/application/role-creation-service.js +1 -1
  24. package/dist/application/role-removal-service.js +2 -0
  25. package/dist/application/role-repository.js +2 -2
  26. package/dist/application/room-layout-definitions.d.ts +45 -0
  27. package/dist/application/room-layout-definitions.js +130 -0
  28. package/dist/application/session-control.d.ts +30 -0
  29. package/dist/application/session-control.js +72 -3
  30. package/dist/application/supervisor-ours-tools.d.ts +159 -0
  31. package/dist/application/supervisor-ours-tools.js +113 -0
  32. package/dist/application/task-layouts.d.ts +91 -0
  33. package/dist/application/task-layouts.js +249 -0
  34. package/dist/application/task-room-service.d.ts +99 -3
  35. package/dist/application/task-room-service.js +296 -31
  36. package/dist/atomic-file.d.ts +5 -0
  37. package/dist/atomic-file.js +62 -1
  38. package/dist/briefing.d.ts +2 -0
  39. package/dist/briefing.js +8 -1
  40. package/dist/build-info.json +7 -4
  41. package/dist/capabilities.d.ts +6 -1
  42. package/dist/capabilities.js +8 -0
  43. package/dist/cli.js +376 -34
  44. package/dist/client-profile.d.ts +5 -17
  45. package/dist/client-profile.js +4 -127
  46. package/dist/config.d.ts +28 -0
  47. package/dist/config.js +41 -6
  48. package/dist/creation.js +2 -2
  49. package/dist/daemon-recovery.d.ts +1 -8
  50. package/dist/daemon-recovery.js +8 -113
  51. package/dist/docs.d.ts +3 -3
  52. package/dist/docs.js +126 -22
  53. package/dist/doctor.d.ts +1 -1
  54. package/dist/doctor.js +55 -60
  55. package/dist/erased-resources.d.ts +9 -0
  56. package/dist/erased-resources.js +87 -0
  57. package/dist/fleet-command-audit.d.ts +7 -0
  58. package/dist/fleet-command-audit.js +26 -9
  59. package/dist/harness/claude-code.js +9 -1
  60. package/dist/harness/claude-runtime.d.ts +12 -0
  61. package/dist/harness/claude-runtime.js +43 -0
  62. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  63. package/dist/harness/codex-app-server-proxy.js +41 -5
  64. package/dist/harness/codex-reasoning.d.ts +5 -0
  65. package/dist/harness/codex-reasoning.js +12 -0
  66. package/dist/harness/codex-runtime.d.ts +11 -1
  67. package/dist/harness/codex-runtime.js +31 -4
  68. package/dist/harness/codex.d.ts +3 -2
  69. package/dist/harness/codex.js +20 -11
  70. package/dist/init-wizard.d.ts +2 -0
  71. package/dist/init-wizard.js +38 -19
  72. package/dist/isolation/policy.js +2 -0
  73. package/dist/isolation/types.d.ts +5 -0
  74. package/dist/managed-cli.d.ts +253 -0
  75. package/dist/managed-cli.js +923 -0
  76. package/dist/minimal-setup.d.ts +2 -0
  77. package/dist/minimal-setup.js +44 -0
  78. package/dist/monitor.d.ts +1 -34
  79. package/dist/monitor.js +24 -151
  80. package/dist/notifications/fleet-producer.d.ts +19 -0
  81. package/dist/notifications/fleet-producer.js +208 -0
  82. package/dist/notifications/outbox.d.ts +46 -0
  83. package/dist/notifications/outbox.js +158 -0
  84. package/dist/notifications/target-cleanup.d.ts +8 -0
  85. package/dist/notifications/target-cleanup.js +41 -0
  86. package/dist/ops.js +5 -1
  87. package/dist/owner-channel/channel.d.ts +3 -0
  88. package/dist/owner-channel/channel.js +34 -6
  89. package/dist/owner-channel/commands.d.ts +4 -0
  90. package/dist/owner-channel/commands.js +8 -0
  91. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  92. package/dist/owner-channel/ours-client.js +2 -17
  93. package/dist/paths.d.ts +2 -0
  94. package/dist/paths.js +2 -0
  95. package/dist/preset-migration.js +25 -0
  96. package/dist/resolved-plan.js +1 -0
  97. package/dist/rooms-tasks/add-member.d.ts +48 -0
  98. package/dist/rooms-tasks/add-member.js +83 -0
  99. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  100. package/dist/rooms-tasks/archived-absence.js +48 -0
  101. package/dist/rooms-tasks/cli.js +34 -5
  102. package/dist/rooms-tasks/close.d.ts +5 -2
  103. package/dist/rooms-tasks/close.js +208 -28
  104. package/dist/rooms-tasks/config.d.ts +1 -1
  105. package/dist/rooms-tasks/config.js +11 -4
  106. package/dist/rooms-tasks/cowork-adapter.d.ts +6 -4
  107. package/dist/rooms-tasks/cowork-adapter.js +8 -121
  108. package/dist/rooms-tasks/deletion.d.ts +1 -1
  109. package/dist/rooms-tasks/deletion.js +74 -5
  110. package/dist/rooms-tasks/erasure.d.ts +6 -0
  111. package/dist/rooms-tasks/erasure.js +169 -0
  112. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  113. package/dist/rooms-tasks/external-worker.js +3 -4
  114. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  115. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  116. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  117. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  118. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  119. package/dist/rooms-tasks/layout-cli.js +107 -0
  120. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  121. package/dist/rooms-tasks/layout-config.js +89 -0
  122. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  123. package/dist/rooms-tasks/layout-control.js +52 -0
  124. package/dist/rooms-tasks/layout-service.d.ts +42 -0
  125. package/dist/rooms-tasks/layout-service.js +185 -0
  126. package/dist/rooms-tasks/layout.d.ts +114 -0
  127. package/dist/rooms-tasks/layout.js +250 -0
  128. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  129. package/dist/rooms-tasks/live-readiness.js +85 -0
  130. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  131. package/dist/rooms-tasks/member-startup.js +2 -0
  132. package/dist/rooms-tasks/provision.d.ts +14 -0
  133. package/dist/rooms-tasks/provision.js +173 -46
  134. package/dist/rooms-tasks/room-state.d.ts +4 -2
  135. package/dist/rooms-tasks/room-state.js +53 -8
  136. package/dist/rooms-tasks/task-state.d.ts +42 -7
  137. package/dist/rooms-tasks/task-state.js +153 -23
  138. package/dist/rooms-tasks/types.d.ts +28 -0
  139. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  140. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  141. package/dist/rooms-tasks/workspace.d.ts +26 -0
  142. package/dist/rooms-tasks/workspace.js +195 -0
  143. package/dist/runner.d.ts +19 -3
  144. package/dist/runner.js +128 -45
  145. package/dist/session/acp.d.ts +9 -1
  146. package/dist/session/acp.js +31 -6
  147. package/dist/session/arbiter.d.ts +5 -0
  148. package/dist/session/arbiter.js +28 -2
  149. package/dist/session/codex-app-server.d.ts +5 -0
  150. package/dist/session/codex-app-server.js +36 -3
  151. package/dist/session/control.d.ts +12 -1
  152. package/dist/session/control.js +68 -3
  153. package/dist/session/conversation-normalizer.d.ts +2 -1
  154. package/dist/session/conversation-normalizer.js +1 -1
  155. package/dist/session/conversation-store.d.ts +1 -1
  156. package/dist/session/conversation-store.js +7 -11
  157. package/dist/session/conversation-types.d.ts +7 -3
  158. package/dist/session/task-notice.d.ts +14 -0
  159. package/dist/session/task-notice.js +13 -0
  160. package/dist/session/types.d.ts +6 -0
  161. package/dist/setup-tunnel-preflight.d.ts +34 -0
  162. package/dist/setup-tunnel-preflight.js +62 -0
  163. package/dist/socket-path.d.ts +2 -0
  164. package/dist/socket-path.js +22 -0
  165. package/dist/spawn.js +8 -1
  166. package/dist/startup-readiness.d.ts +13 -0
  167. package/dist/startup-readiness.js +38 -0
  168. package/dist/subscriptions/cli.d.ts +91 -0
  169. package/dist/subscriptions/cli.js +223 -0
  170. package/dist/subscriptions/launch.d.ts +37 -0
  171. package/dist/subscriptions/launch.js +93 -0
  172. package/dist/subscriptions/login.d.ts +75 -0
  173. package/dist/subscriptions/login.js +182 -0
  174. package/dist/subscriptions/observed.d.ts +7 -0
  175. package/dist/subscriptions/observed.js +44 -0
  176. package/dist/subscriptions/probe.d.ts +10 -0
  177. package/dist/subscriptions/probe.js +73 -0
  178. package/dist/subscriptions/service.d.ts +102 -0
  179. package/dist/subscriptions/service.js +364 -0
  180. package/dist/subscriptions/store.d.ts +71 -0
  181. package/dist/subscriptions/store.js +140 -0
  182. package/dist/supervisor/launchd.js +2 -1
  183. package/dist/supervisor/systemd.js +9 -23
  184. package/dist/temp-idle.d.ts +17 -0
  185. package/dist/temp-idle.js +42 -0
  186. package/dist/temp-lifecycle.d.ts +6 -1
  187. package/dist/temp-lifecycle.js +29 -13
  188. package/dist/tunnel-setup-completion.d.ts +7 -0
  189. package/dist/tunnel-setup-completion.js +13 -0
  190. package/dist/tunnel-setup-input.d.ts +19 -0
  191. package/dist/tunnel-setup-input.js +124 -0
  192. package/dist/web/agent-attachments.d.ts +29 -0
  193. package/dist/web/agent-attachments.js +162 -0
  194. package/dist/web/auth.d.ts +29 -1
  195. package/dist/web/auth.js +82 -7
  196. package/dist/web/available-port.d.ts +2 -0
  197. package/dist/web/available-port.js +23 -0
  198. package/dist/web/control.d.ts +3 -3
  199. package/dist/web/control.js +10 -8
  200. package/dist/web/fleet-config-service.d.ts +4 -1
  201. package/dist/web/fleet-config-service.js +46 -15
  202. package/dist/web/prefix-gateway.d.ts +32 -0
  203. package/dist/web/prefix-gateway.js +234 -0
  204. package/dist/web/runtime.d.ts +3 -1
  205. package/dist/web/runtime.js +116 -31
  206. package/dist/web/server.d.ts +16 -0
  207. package/dist/web/server.js +592 -53
  208. package/dist/web/service.d.ts +11 -2
  209. package/dist/web/service.js +30 -4
  210. package/dist/web/workspace-devices.d.ts +36 -0
  211. package/dist/web/workspace-devices.js +101 -0
  212. package/dist/web/workspace-tunnel.d.ts +1 -0
  213. package/dist/web/workspace-tunnel.js +34 -0
  214. package/dist/workspace-enrollment.d.ts +82 -0
  215. package/dist/workspace-enrollment.js +566 -0
  216. package/dist/workspace-replacement.d.ts +66 -0
  217. package/dist/workspace-replacement.js +220 -0
  218. package/docs/live-voice.md +13 -0
  219. package/docs/room-layouts.md +227 -0
  220. package/docs/task-workspaces.md +130 -0
  221. package/docs/validation/managed-cli-permissions.md +421 -0
  222. package/examples/room-layouts/fresh.yaml +27 -0
  223. package/examples/room-layouts/scoped.yaml +21 -0
  224. package/examples/room-layouts/shared.yaml +19 -0
  225. package/package.json +15 -18
  226. package/presets/README.md +78 -0
  227. package/presets/brain-catalog.json +8 -2
  228. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  229. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  230. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  231. package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
  232. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  233. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  234. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  235. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  236. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  237. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  238. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  239. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  240. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  241. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  242. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  243. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  244. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  245. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  246. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  247. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  248. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  249. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  250. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  251. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  252. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  253. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  254. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  255. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  256. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  257. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  258. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  259. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  260. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  261. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  262. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  263. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  264. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  265. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  266. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  267. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  268. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  269. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  270. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  271. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  272. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  273. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  274. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  275. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  276. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  277. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  278. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  279. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  280. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  281. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  282. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  283. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  284. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  285. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  286. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  287. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  288. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  289. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  290. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  291. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  292. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  293. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  294. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  295. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  296. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  297. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  298. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  299. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  300. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  301. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  302. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  303. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  304. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  305. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  306. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  307. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  308. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  309. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  310. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  311. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  312. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  313. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  314. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  315. package/presets/fleet/roles/Coordinator.yaml +34 -11
  316. package/presets/fleet/roles/Engineer.yaml +40 -0
  317. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  318. package/presets/fleet/room_layouts/pair.yaml +24 -0
  319. package/presets/fleet/room_layouts/single.yaml +17 -0
  320. package/presets/fleet/room_layouts/team.yaml +30 -0
  321. package/presets/fleet/room_templates/engineering.yaml +19 -0
  322. package/presets/manifest.json +2 -2
  323. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  324. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  325. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  326. package/dist/web-app/icons/ours-fleet.svg +0 -4
  327. package/dist/web-app/index.html +0 -17
  328. package/dist/web-app/manifest.webmanifest +0 -15
  329. package/dist/web-app/offline.html +0 -18
  330. package/dist/web-app/sw.js +0 -51
@@ -4,8 +4,18 @@ export declare const VERIFIED_CODEX_ACP_VERSIONS: Set<string>;
4
4
  export declare function executableOnPath(command: string, env: NodeJS.ProcessEnv, cwd?: string): string;
5
5
  /** Match the npm Codex wrapper's platform-package/vendor selection. */
6
6
  export declare function codexExecutable(entry: string): string;
7
+ /**
8
+ * The host's own Codex, when ACP sessions should run it instead of the copy bundled with the adapter.
9
+ * The person signs in to, updates and checks the host Codex, and a newer Codex knows models the bundled
10
+ * one does not. It is used only when it is at least as new as the bundled copy; an explicit CODEX_PATH
11
+ * (including an empty one, which selects the bundled copy) always decides instead.
12
+ */
13
+ export declare function hostCodex(adapterManifest: string | undefined, env: NodeJS.ProcessEnv, cwd?: string, version?: (path: string, env: NodeJS.ProcessEnv) => string | undefined): {
14
+ path: string;
15
+ version: string;
16
+ } | undefined;
7
17
  export interface CodexRuntime {
8
- source: 'CODEX_PATH' | 'bundled';
18
+ source: 'CODEX_PATH' | 'host' | 'bundled';
9
19
  entry: string;
10
20
  executable: string;
11
21
  version: string;
@@ -1,5 +1,6 @@
1
1
  import { createRequire } from 'node:module';
2
- import { accessSync, constants, existsSync, realpathSync } from 'node:fs';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { accessSync, constants, existsSync, readFileSync, realpathSync } from 'node:fs';
3
4
  import { dirname, join, isAbsolute, resolve, delimiter } from 'node:path';
4
5
  import { realExec } from '../exec.js';
5
6
  export const VERIFIED_CODEX_ACP_VERSIONS = new Set(['1.1.7', '1.10.0']);
@@ -46,18 +47,44 @@ export function codexExecutable(entry) {
46
47
  }
47
48
  throw new Error(`Codex platform binary missing under ${vendor}; reinstall Fleet with optional dependencies`);
48
49
  }
50
+ const versionOf = (text) => text.match(/\b(\d+\.\d+\.\d+)\b/)?.[1];
51
+ function installedCodexVersion(path, env) {
52
+ const result = spawnSync(path, ['--version'], { env, encoding: 'utf8', timeout: 5_000, stdio: ['ignore', 'pipe', 'ignore'] });
53
+ return result.status === 0 ? versionOf(result.stdout ?? '') : undefined;
54
+ }
55
+ /**
56
+ * The host's own Codex, when ACP sessions should run it instead of the copy bundled with the adapter.
57
+ * The person signs in to, updates and checks the host Codex, and a newer Codex knows models the bundled
58
+ * one does not. It is used only when it is at least as new as the bundled copy; an explicit CODEX_PATH
59
+ * (including an empty one, which selects the bundled copy) always decides instead.
60
+ */
61
+ export function hostCodex(adapterManifest, env, cwd = process.cwd(), version = installedCodexVersion) {
62
+ if (env.CODEX_PATH !== undefined || !adapterManifest)
63
+ return undefined;
64
+ let path, bundled;
65
+ try {
66
+ path = executableOnPath('codex', env, cwd);
67
+ bundled = JSON.parse(readFileSync(createRequire(adapterManifest).resolve('@openai/codex/package.json'), 'utf8')).version;
68
+ }
69
+ catch {
70
+ return undefined;
71
+ }
72
+ const found = version(path, env);
73
+ return found && typeof bundled === 'string' && codexVersionAtLeast(found, bundled) ? { path, version: found } : undefined;
74
+ }
49
75
  export async function probeCodexRuntime(adapter, env, exec = realExec, cwd = process.cwd()) {
50
- const configured = env.CODEX_PATH;
76
+ const host = hostCodex(adapter.manifestPath, env, cwd);
77
+ const configured = env.CODEX_PATH || host?.path;
51
78
  if (!configured && !adapter.manifestPath)
52
79
  throw new Error('ACP runtime is unknown for a PATH/custom adapter; set CODEX_PATH to an absolute executable or use the bundled adapter');
53
80
  const entry = configured ? executableOnPath(configured, env, cwd)
54
81
  : createRequire(adapter.manifestPath).resolve('@openai/codex/bin/codex.js');
55
82
  const executable = codexExecutable(entry);
56
83
  const result = await exec(!configured ? process.execPath : entry, !configured ? [entry, '--version'] : ['--version'], { env, timeout: 5_000 });
57
- const version = result.stdout.match(/\b(\d+\.\d+\.\d+)\b/)?.[1];
84
+ const version = versionOf(result.stdout);
58
85
  if (result.code !== 0 || !version)
59
86
  throw new Error(`Cannot read Codex version from ${entry}; check CODEX_PATH and executable permissions`);
60
- return { source: configured ? 'CODEX_PATH' : 'bundled', entry, executable, version };
87
+ return { source: host ? 'host' : configured ? 'CODEX_PATH' : 'bundled', entry, executable, version };
61
88
  }
62
89
  export function codexVersionAtLeast(version, minimum) {
63
90
  const actual = version.split('.').map(Number);
@@ -6,8 +6,9 @@ import type { AcpSessionTransport } from './acp-session-transport.js';
6
6
  import type { CodexAppServerSessionTransport } from './codex-session.js';
7
7
  /**
8
8
  * What an unattended role can actually do under Codex's native settings.
9
- * `on-request` and `untrusted` stop to ask, and with no console attached that
10
- * request is refused rather than answered — so the role can only read.
9
+ * `on-request` and `untrusted` can ask even for startup file reads (for example,
10
+ * shell reads or files outside the sandbox). Without a controller the request
11
+ * waits or is denied according to policy. Neither guarantees `read-state`.
11
12
  */
12
13
  export declare function codexCapabilities(approval: string, sandbox: string): UnattendedCapability[];
13
14
  /** Defense in depth for callers which launch a role after validation was bypassed. */
@@ -6,8 +6,9 @@ import { realExec } from '../exec.js';
6
6
  import { registerAdapter } from './registry.js';
7
7
  import { harnessRuntimeDir } from '../isolation/policy.js';
8
8
  import { resolveBundledAcpAgent, } from './acp-agent.js';
9
- import { VERIFIED_CODEX_ACP_VERSIONS, probeCodexRuntime, codexVersionAtLeast } from './codex-runtime.js';
9
+ import { VERIFIED_CODEX_ACP_VERSIONS, probeCodexRuntime, codexVersionAtLeast, hostCodex } from './codex-runtime.js';
10
10
  import { CodexAgentSessionAdapter } from './codex-session.js';
11
+ import { CODEX_REASONING_EFFORTS, isCodexReasoningEffort } from './codex-reasoning.js';
11
12
  const OPTION_KEYS = [
12
13
  'launcher', 'sandbox', 'approval', 'permission_mode', 'search', 'profile', 'config', 'add_dirs',
13
14
  'monitor',
@@ -25,12 +26,13 @@ const CODEX_PROXY_REAL_PATH_ENV = 'OURS_FLEET_REAL_CODEX_PATH';
25
26
  const CODEX_PROXY_MANIFEST_ENV = 'OURS_FLEET_CODEX_ACP_MANIFEST';
26
27
  /**
27
28
  * What an unattended role can actually do under Codex's native settings.
28
- * `on-request` and `untrusted` stop to ask, and with no console attached that
29
- * request is refused rather than answered — so the role can only read.
29
+ * `on-request` and `untrusted` can ask even for startup file reads (for example,
30
+ * shell reads or files outside the sandbox). Without a controller the request
31
+ * waits or is denied according to policy. Neither guarantees `read-state`.
30
32
  */
31
33
  export function codexCapabilities(approval, sandbox) {
32
34
  if (approval !== 'never')
33
- return ['read-state'];
35
+ return [];
34
36
  const caps = ['read-state', 'messaging', 'monitor', 'status-commands'];
35
37
  if (sandbox !== 'read-only')
36
38
  caps.push('write-state', 'workspace-edit');
@@ -140,6 +142,13 @@ function neutralSandboxMode(role) {
140
142
  function isNativeConfigKeyAllowed(key) {
141
143
  return NATIVE_CONFIG_ALLOWLIST.has(key);
142
144
  }
145
+ /** Brain wins; a validated native effort also needs delivery through ACP's selection API. */
146
+ function reasoningEffort(role) {
147
+ if (typeof role.effort === 'string')
148
+ return role.effort;
149
+ const value = role.harness_options?.config?.model_reasoning_effort;
150
+ return isCodexReasoningEffort(value) ? value : undefined;
151
+ }
143
152
  /** Defense in depth for callers which launch a role after validation was bypassed. */
144
153
  export function nativeCodexConfig(role) {
145
154
  const options = role.harness_options;
@@ -265,7 +274,9 @@ function codexAcpEnvironment(role, dirs) {
265
274
  [CODEX_PROXY_APPROVAL_ENV]: approvalPolicy(role) ?? 'on-request',
266
275
  [CODEX_PROXY_SANDBOX_ENV]: acpRuntimeSandbox(role),
267
276
  [CODEX_PROXY_MANIFEST_ENV]: resolution.manifestPath,
268
- [CODEX_PROXY_REAL_PATH_ENV]: role.env?.CODEX_PATH ?? process.env.CODEX_PATH ?? '',
277
+ // Same choice as probeCodexRuntime: an explicit CODEX_PATH, else a host Codex at least as new as the bundled one.
278
+ [CODEX_PROXY_REAL_PATH_ENV]: role.env?.CODEX_PATH ?? process.env.CODEX_PATH
279
+ ?? hostCodex(resolution.manifestPath, { ...process.env, ...role.env }, dirs.runCwd)?.path ?? '',
269
280
  };
270
281
  }
271
282
  function encodeTomlValue(value) {
@@ -315,10 +326,8 @@ export function makeCodexAdapter(exec = realExec, transport, nativeTransport) {
315
326
  id: 'codex',
316
327
  agentSession: new CodexAgentSessionAdapter({
317
328
  resolveBrain(brain) {
318
- const levels = ['low', 'medium', 'high', 'xhigh', 'max', 'ultra'];
319
- if (brain.effort != null
320
- && (typeof brain.effort !== 'string' || !levels.includes(brain.effort)))
321
- throw new Error(`Codex Brain effort must be one of: ${levels.join(', ')}`);
329
+ if (brain.effort != null && !isCodexReasoningEffort(brain.effort))
330
+ throw new Error(`Codex Brain effort must be one of: ${CODEX_REASONING_EFFORTS.join(', ')}`);
322
331
  const harnessOptions = { ...(brain.harnessOptions ?? {}) };
323
332
  if (brain.effort)
324
333
  harnessOptions.config = {
@@ -340,8 +349,8 @@ export function makeCodexAdapter(exec = realExec, transport, nativeTransport) {
340
349
  sessionConfigSelections: role => [
341
350
  ...(typeof role.model === 'string'
342
351
  ? [{ configId: 'model', value: role.model }] : []),
343
- ...(typeof role.effort === 'string'
344
- ? [{ configId: 'reasoning_effort', value: role.effort }] : []),
352
+ ...(reasoningEffort(role)
353
+ ? [{ configId: 'reasoning_effort', value: reasoningEffort(role) }] : []),
345
354
  ],
346
355
  permissionModeId: role => acpAgentMode(role),
347
356
  mcpServers: () => undefined,
@@ -53,6 +53,8 @@ export declare function validateCatalog(value: BrainCatalog, path?: string): Bra
53
53
  export declare function readInitSettings(path: string): InitAnswers;
54
54
  export declare function askInitQuestions(prompter: InitPrompter, configuration: string): Promise<InitAnswers | undefined>;
55
55
  export declare function formatSetupSummary(answers: InitAnswers, configuration: string): string;
56
+ /** The packaged Brain preset for a catalog model at one effort; the same naming the presets are generated with. */
57
+ export declare function brainPresetId(model: Pick<CatalogModel, 'harness' | 'model'>, effort: string): string;
56
58
  /** Build the exact, deterministic default experience without writing to disk. */
57
59
  export declare function generateSetup(answers: InitAnswers): GeneratedSetup;
58
60
  /** Run the mutation boundary only after the complete questionnaire is accepted. */
@@ -7,13 +7,19 @@ import { packagedPresetRoot } from './preset-bootstrap.js';
7
7
  import { listTemplates } from './rooms-tasks/templates.js';
8
8
  const WORK_KINDS = ['development', 'review', 'coordination'];
9
9
  const ROLE_WORK = {
10
- Developer: 'development', Critic: 'review',
10
+ Developer: 'development', Engineer: 'development', Critic: 'review',
11
11
  LocalCoordinator: 'coordination', Coordinator: 'coordination', FleetCoordinator: 'coordination',
12
12
  };
13
13
  const REASONING_EFFORT = {
14
14
  quick: 'low', balanced: 'medium', thorough: 'high',
15
15
  };
16
16
  const MODEL_LABELS = {
17
+ 'gpt-6.1-sol': 'GPT-6.1 Sol',
18
+ 'gpt-6-sol': 'GPT-6 Sol',
19
+ 'gpt-6-luna': 'GPT-6 Luna',
20
+ 'claude-fable-5-1': 'Claude Fable 5.1',
21
+ 'claude-opus-5-5': 'Claude Opus 5.5',
22
+ 'claude-haiku-4-5-20251001': 'Claude Haiku 4.5',
17
23
  'gpt-6-astra': 'GPT-6 Astra',
18
24
  'gpt-5.6-sol': 'GPT-5.6 Sol',
19
25
  'gpt-5.6-terra': 'GPT-5.6 Terra',
@@ -33,10 +39,10 @@ export function validateCatalog(value, path = 'supported model catalog') {
33
39
  for (const model of value.models) {
34
40
  if (!['codex', 'claude-code'].includes(model.harness) || model.session !== 'acp'
35
41
  || typeof model.model !== 'string' || !MODEL_LABELS[model.model]
36
- || !Array.isArray(model.efforts) || model.efforts.length === 0
42
+ || !Array.isArray(model.efforts)
37
43
  || new Set(model.efforts).size !== model.efforts.length
38
44
  || model.efforts.some(effort => !['low', 'medium', 'high', 'xhigh', 'max', 'ultra'].includes(effort))
39
- || !['low', 'medium', 'high'].every(effort => model.efforts.includes(effort)))
45
+ || (model.efforts.length > 0 && !['low', 'medium', 'high'].every(effort => model.efforts.includes(effort))))
40
46
  throw new Error(`unsupported model state in ${path}`);
41
47
  const tuple = `${model.harness}\0${model.session}\0${model.model}`;
42
48
  if (tuples.has(tuple))
@@ -90,7 +96,9 @@ export async function askInitQuestions(prompter, configuration) {
90
96
  return undefined;
91
97
  if (subscriptions.length === 0)
92
98
  throw new Error('Select at least one subscription.');
93
- const available = catalog().models.filter(model => subscriptions.includes(subscriptionFor(model)));
99
+ // The wizard assigns low/medium/high; no-effort models remain available as named presets.
100
+ const available = catalog().models.filter(model => subscriptions.includes(subscriptionFor(model))
101
+ && model.efforts.length > 0);
94
102
  if (!available.length)
95
103
  throw new Error('None of the selected subscriptions has a supported model.');
96
104
  prompter.note([
@@ -163,7 +171,9 @@ export function formatSetupSummary(answers, configuration) {
163
171
  ' One-agent work: one Developer',
164
172
  ' Reviewed pair: Developer + independent Critic',
165
173
  ' Team: LocalCoordinator + Developer + Critic',
174
+ ' Gated engineering: Engineer (gate pipeline) + independent Critic',
166
175
  ' FleetCoordinator: coordination model',
176
+ ' Brains: the packaged presets; each prepared agent references the preset of its chosen model',
167
177
  '',
168
178
  'After the final Yes, Fleet performs host service setup before publishing the complete configuration.',
169
179
  'A hard termination after that Yes can leave host integration or private stage/recovery evidence to inspect.',
@@ -172,6 +182,11 @@ export function formatSetupSummary(answers, configuration) {
172
182
  function preset(relative) {
173
183
  return readFileSync(join(packagedPresetRoot(), 'fleet', relative), 'utf8');
174
184
  }
185
+ /** The packaged Brain preset for a catalog model at one effort; the same naming the presets are generated with. */
186
+ export function brainPresetId(model, effort) {
187
+ return `${model.harness === 'claude-code' ? 'claude' : 'codex'}-${model.model
188
+ .replace(/^claude-/, '').replace(/\./g, '-').toLowerCase()}-${effort}`;
189
+ }
175
190
  /** Build the exact, deterministic default experience without writing to disk. */
176
191
  export function generateSetup(answers) {
177
192
  const effort = REASONING_EFFORT[answers.reasoning];
@@ -192,6 +207,7 @@ export function generateSetup(answers) {
192
207
  ' permissions: { approval: ask, filesystem: workspace, unattended: deny }',
193
208
  '',
194
209
  ].join('\n'));
210
+ const assigned = {};
195
211
  for (const work of WORK_KINDS) {
196
212
  const proposed = answers.models[work];
197
213
  if (!proposed || !answers.subscriptions.includes(subscriptionFor(proposed)))
@@ -205,14 +221,14 @@ export function generateSetup(answers) {
205
221
  throw new Error(`${work} contains tampered model capabilities`);
206
222
  if (!model.efforts.includes(effort))
207
223
  throw new Error(`${MODEL_LABELS[model.model]} does not support ${answers.reasoning} reasoning`);
208
- files.set(`brains/${work}.yaml`, [
209
- `harness: ${model.harness}`,
210
- `session: ${model.session}`,
211
- `model: ${model.model}`,
212
- `effort: ${effort}`,
213
- '',
214
- ].join('\n'));
224
+ // The chosen model is assigned by reference to its packaged Brain preset; setup defines no Brain of its own.
225
+ const id = brainPresetId(model, effort);
226
+ if (!existsSync(join(packagedPresetRoot(), 'fleet', 'brains', `${id}.yaml`)))
227
+ throw new Error(`no packaged Brain preset for ${MODEL_LABELS[model.model]} at ${effort} reasoning`);
228
+ assigned[work] = id;
215
229
  }
230
+ for (const name of readdirSync(join(packagedPresetRoot(), 'fleet', 'brains')).filter(name => name.endsWith('.yaml')).sort())
231
+ files.set(`brains/${name}`, preset(`brains/${name}`));
216
232
  if (answers.assignmentStrategy === 'one-model') {
217
233
  const tuples = new Set(WORK_KINDS.map(work => {
218
234
  const model = answers.models[work];
@@ -221,23 +237,26 @@ export function generateSetup(answers) {
221
237
  if (tuples.size !== 1)
222
238
  throw new Error('one-model assignment requires the same exact model for development, review, and coordination');
223
239
  }
224
- for (const role of ['Coordinator', 'LocalCoordinator', 'Developer', 'Critic']) {
240
+ for (const role of ['Coordinator', 'LocalCoordinator', 'Developer', 'Engineer', 'Critic']) {
225
241
  files.set(`roles/${role}.yaml`, preset(`roles/${role}.yaml`));
226
242
  if (role === 'Coordinator')
227
243
  continue;
228
244
  files.set(`agent_templates/${role}.yaml`, [
229
245
  `role: { ref: ${role} }`,
230
- `brain: { ref: ${ROLE_WORK[role]} }`,
246
+ `brain: { ref: ${assigned[ROLE_WORK[role]]} }`,
231
247
  'coordinator: FleetCoordinator',
232
- 'permissions: { approval: ask, filesystem: workspace, unattended: deny }',
248
+ // Temporary default while the product is being tested: prepared agents work without asking.
249
+ 'permissions: { approval: allow, filesystem: unrestricted, unattended: deny }',
233
250
  'monitor: { mode: fleet, interrupt: after_tool }',
234
251
  '',
235
252
  ].join('\n'));
236
253
  }
237
254
  files.set('agents/FleetCoordinator.yaml', preset('agents/FleetCoordinator.yaml')
238
- .replace('brain: { ref: claude-default }', 'brain: { ref: coordination }'));
239
- for (const name of ['single', 'pair', 'team'])
255
+ .replace('brain: { ref: claude-default }', `brain: { ref: ${assigned.coordination} }`));
256
+ for (const name of ['single', 'pair', 'team', 'engineering']) {
240
257
  files.set(`room_templates/${name}.yaml`, preset(`room_templates/${name}.yaml`));
258
+ files.set(`room_layouts/${name}.yaml`, preset(`room_layouts/${name}.yaml`));
259
+ }
241
260
  return { files, answers };
242
261
  }
243
262
  /** Run the mutation boundary only after the complete questionnaire is accepted. */
@@ -385,7 +404,7 @@ function writeStaged(stageManifest, setup) {
385
404
  replaceFileAtomically(target, contents, 0o600);
386
405
  fsyncPath(target);
387
406
  }
388
- for (const kind of ['agents', 'agent_templates', 'roles', 'brains', 'room_templates'])
407
+ for (const kind of ['agents', 'agent_templates', 'roles', 'brains', 'room_templates', 'room_layouts'])
389
408
  fsyncPath(join(stageRoot, kind));
390
409
  fsyncPath(stageRoot);
391
410
  fsyncPath(dirname(stageManifest));
@@ -394,8 +413,8 @@ function validateStaged(stageManifest) {
394
413
  const config = loadConfig(stageManifest, { yamlMode: 'strict' });
395
414
  const templates = listTemplates(config.roomTemplates ?? {});
396
415
  const names = new Set(templates.map(template => template.name));
397
- if (!['pair', 'single', 'team'].every(name => names.has(name)))
398
- throw new Error('generated setup did not resolve the default single, pair, and team experiences');
416
+ if (!['pair', 'single', 'team', 'engineering'].every(name => names.has(name)))
417
+ throw new Error('generated setup did not resolve the default single, pair, team, and engineering experiences');
399
418
  for (const template of templates)
400
419
  for (const member of template.members)
401
420
  if (!config.agentTemplates?.[member.agent_template])
@@ -168,6 +168,8 @@ export function resolveIsolation(cfg, ctx) {
168
168
  }
169
169
  for (const dir of ctx.additionalWriteDirs ?? [])
170
170
  addRw(dir);
171
+ if (ctx.subscriptionHome)
172
+ addRw(ctx.subscriptionHome);
171
173
  // The selected harness/session command may live outside the system allowlist
172
174
  // (for example Node and a bundled ACP adapter under ~/.local). The runner
173
175
  // resolves its exact executable/package closure; keep every such bind RO.
@@ -63,6 +63,11 @@ export interface WrapContext {
63
63
  * them for itself or for its peers.
64
64
  */
65
65
  harnessSharedPaths?: string[];
66
+ /**
67
+ * The pinned subscription profile home (CLAUDE_CONFIG_DIR / CODEX_HOME), mounted
68
+ * read-write so the CLI can refresh that profile's login. Absent for the default.
69
+ */
70
+ subscriptionHome?: string;
66
71
  /** Exact launcher/interpreter/module closure required by the selected command. */
67
72
  runtimeReadPaths?: string[];
68
73
  brokerEndpoint?: string;
@@ -0,0 +1,253 @@
1
+ import { type FleetConfig, type ManagedCliWorkflowId, type ResolvedRole } from './config.js';
2
+ import type { SessionPrep } from './harness/types.js';
3
+ /** Capability-gated by the installer; see src/capabilities.ts. */
4
+ export declare const MANAGED_CONFIGURATION_FLAG = "--managed-configuration";
5
+ /** What the last launch of a role actually prepared. Lives in the role's state dir. */
6
+ export declare const MANAGED_CLI_RECORD = ".managed-cli.json";
7
+ /** Quoted path tokens were refused by Codex 0.159.0 (#231) and granted by 0.160.0. */
8
+ export declare const CODEX_QUOTED_PATH_MINIMUM = "0.160.0";
9
+ export interface ManagedCliForm {
10
+ /** Argv tokens after the pin, matched exactly. */
11
+ tokens: readonly string[];
12
+ /** `lifecycle` forms create, change or retire tasks, rooms and agents. */
13
+ effect: 'help' | 'read' | 'lifecycle';
14
+ /** Whether the command itself takes -c/--configuration, where the pin is injected. */
15
+ configuration: boolean;
16
+ }
17
+ export interface ManagedCliWorkflow {
18
+ description: string;
19
+ forms: readonly ManagedCliForm[];
20
+ /** Named so nobody reads their absence as an oversight. */
21
+ excluded: readonly string[];
22
+ }
23
+ export declare const MANAGED_CLI_WORKFLOWS: Readonly<Record<ManagedCliWorkflowId, ManagedCliWorkflow>>;
24
+ export type ManagedEntry = {
25
+ kind: 'none';
26
+ } | {
27
+ kind: 'error';
28
+ message: string;
29
+ } | {
30
+ kind: 'pinned';
31
+ configuration: string;
32
+ form: ManagedCliForm;
33
+ argv: string[];
34
+ };
35
+ /**
36
+ * Recognise the pinned entry form in `argv` (process.argv.slice(2)) and return
37
+ * the ordinary argv Commander should parse.
38
+ *
39
+ * The pin must be the first argument: that is the only position a native prefix
40
+ * rule can fix. For a command that takes `--configuration`, the pinned file is
41
+ * injected directly after the command tokens; a later, different value is
42
+ * refused by `assertPinnedConfiguration` on the PARSED option, so `-c`,
43
+ * `-cFILE`, `--configuration=FILE` and repeats need no token heuristics here.
44
+ */
45
+ export declare function parseManagedEntry(argv: readonly string[]): ManagedEntry;
46
+ /** Refuse a parsed `--configuration` that is not the pinned file. Throws a plain Error. */
47
+ export declare function assertPinnedConfiguration(pinned: string, parsed: unknown): void;
48
+ export interface ManagedCliPaths {
49
+ node: string;
50
+ cli: string;
51
+ configuration: string;
52
+ }
53
+ /** The exact tokens a rule fixes: this process's node, this installation's CLI, this configuration. */
54
+ export declare function managedCliPaths(configPath?: string, overrides?: Partial<ManagedCliPaths>): ManagedCliPaths;
55
+ /** The canonical shell spelling of one path token, or undefined when none is qualified. */
56
+ export declare function shellSpelling(token: string): string | undefined;
57
+ export declare const needsQuoting: (paths: ManagedCliPaths) => boolean;
58
+ /** The argv prefix every prepared invocation starts with. */
59
+ export declare function managedCliPrefix(paths: ManagedCliPaths): string[];
60
+ /** The same prefix as the agent must type it. Undefined when a path cannot be spelled. */
61
+ export declare function managedCliCommandPrefix(paths: ManagedCliPaths): string | undefined;
62
+ /** Codex execution rules: one `prefix_rule` per form. JSON strings are valid Starlark strings. */
63
+ export declare function renderCodexRules(paths: ManagedCliPaths, workflows: readonly ManagedCliWorkflowId[]): string;
64
+ export interface ClaudeManagedCliSettings {
65
+ permissions: {
66
+ allow: string[];
67
+ };
68
+ sandbox: {
69
+ excludedCommands: string[];
70
+ };
71
+ }
72
+ /**
73
+ * Claude needs BOTH halves: `permissions.allow` authorizes the Bash call and
74
+ * `sandbox.excludedCommands` places it outside the OS sandbox when one is
75
+ * enabled. Each form is listed bare and with ` *` because the wildcard form
76
+ * alone is not relied on to match an invocation without arguments.
77
+ */
78
+ export declare function claudeManagedCliSettings(paths: ManagedCliPaths, workflows: readonly ManagedCliWorkflowId[]): ClaudeManagedCliSettings | undefined;
79
+ /**
80
+ * Merge the fragment into Fleet's own per-role settings overlay. Entries from a
81
+ * previous launch are dropped first, so a moved node, CLI or configuration
82
+ * leaves nothing stale behind. `sandbox.enabled` is never written: whether
83
+ * Claude's OS sandbox is on stays the operator's setting.
84
+ */
85
+ export declare function mergeClaudeOverlay(base: Record<string, unknown>, fragment: ClaudeManagedCliSettings | undefined): Record<string, unknown>;
86
+ export type ManagedCliMechanism = 'codex-workspace-rules' | 'claude-session-settings';
87
+ export interface ManagedCliAnalysis {
88
+ role: string;
89
+ harness: string;
90
+ session: string;
91
+ workflows: ManagedCliWorkflowId[];
92
+ state: 'not-declared' | 'not-required' | 'unsupported' | 'supported';
93
+ mechanism?: ManagedCliMechanism;
94
+ /** Why the state is not-required or unsupported. Actionable, one per line. */
95
+ reasons: string[];
96
+ /** What the prepared policy actually grants, for disclosure. */
97
+ scope: string[];
98
+ workspace: string;
99
+ paths: ManagedCliPaths;
100
+ /** The prefix the agent types; absent unless supported. */
101
+ commandPrefix?: string;
102
+ }
103
+ export interface ManagedCliDeps {
104
+ platform?: NodeJS.Platform;
105
+ paths?: Partial<ManagedCliPaths>;
106
+ /** Codex version for the quoted-path qualification; read from the role's Codex when omitted. */
107
+ codexVersion?: string;
108
+ }
109
+ export declare function roleWorkspace(role: ResolvedRole, temp?: boolean): string;
110
+ /** Decide, without touching the filesystem, what Fleet prepares for one role. */
111
+ export declare function analyzeManagedCli(role: ResolvedRole, configPath: string | undefined, options?: ManagedCliDeps & {
112
+ temp?: boolean;
113
+ workspace?: string;
114
+ }): ManagedCliAnalysis;
115
+ export declare function codexRulesPath(workspace: string, configuration: string): string;
116
+ export type RulesAction = 'created' | 'updated' | 'unchanged' | 'removed' | 'conflict';
117
+ export interface RulesResult {
118
+ path: string;
119
+ action: RulesAction;
120
+ detail?: string;
121
+ }
122
+ /** Write this workspace's rules file and record `holder` as needing it. */
123
+ export declare function acquireCodexRules(workspace: string, paths: ManagedCliPaths, workflows: readonly ManagedCliWorkflowId[], holder: string): RulesResult;
124
+ /**
125
+ * Drop `holder` from every rules file except `keep`. A file left without a
126
+ * holder is removed when Fleet still owns it; a file other agents hold is left
127
+ * exactly as it is. This is what a launch does when the role stopped declaring
128
+ * the workflow, lost support, or moved to another workspace or configuration.
129
+ */
130
+ export declare function releaseCodexRules(holder: string, keep?: string): RulesResult[];
131
+ /**
132
+ * Bring every registered rules file of `configuration` in line with `expected`
133
+ * (path → persistent holders). Temporary holders stay while their state dir
134
+ * exists. A file nobody holds is removed if — and only if — Fleet still owns
135
+ * it; a file whose configuration no longer exists is obsolete and goes too.
136
+ */
137
+ export declare function reconcileCodexRules(configuration: string, expected: ReadonlyMap<string, readonly string[]>, write: boolean): RulesResult[];
138
+ /** Static comparison of the rules file with what this installation would generate. */
139
+ export declare function inspectCodexRules(workspace: string, paths: ManagedCliPaths, workflows: readonly ManagedCliWorkflowId[]): {
140
+ path: string;
141
+ state: 'prepared' | 'missing' | 'stale' | 'conflict';
142
+ detail: string;
143
+ };
144
+ /** Whether Codex treats the workspace as trusted, which is what loads project rules. */
145
+ export declare function codexWorkspaceTrust(workspace: string, env?: NodeJS.ProcessEnv): {
146
+ state: 'trusted' | 'untrusted' | 'unknown';
147
+ source: string;
148
+ };
149
+ export interface ClaudeSettingsInspection {
150
+ /** `unknown` when no readable source states it; Claude's default is then off. */
151
+ sandbox: 'enabled' | 'disabled' | 'unknown';
152
+ sources: string[];
153
+ /** Bash deny rules, which take precedence over Fleet's allow entries. */
154
+ bashDeny: string[];
155
+ unreadable: string[];
156
+ }
157
+ export declare function inspectClaudeSettings(workspace: string, env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): ClaudeSettingsInspection;
158
+ export interface ManagedCliRecord {
159
+ version: 1;
160
+ state: ManagedCliAnalysis['state'] | 'conflict';
161
+ mechanism?: ManagedCliMechanism;
162
+ workflows: ManagedCliWorkflowId[];
163
+ paths: ManagedCliPaths;
164
+ workspace: string;
165
+ /** Hash of everything that decides the generated policy; equal digests mean the same policy. */
166
+ digest: string;
167
+ /** When a policy with this digest was first loaded into a launch. */
168
+ preparedAt: string;
169
+ artifact?: string;
170
+ reasons: string[];
171
+ }
172
+ export declare function managedCliDigest(analysis: ManagedCliAnalysis): string;
173
+ export declare function readManagedCliRecord(stateDir: string): ManagedCliRecord | undefined;
174
+ /**
175
+ * Prepare the native policy for one launch and return the session prep to use.
176
+ * Never throws: a role whose policy cannot be prepared still launches, exactly
177
+ * as sandboxed as it was, and the reason is logged and recorded.
178
+ */
179
+ export declare function prepareManagedCliLaunch(role: ResolvedRole, options: {
180
+ stateDir: string;
181
+ runCwd: string;
182
+ configPath?: string;
183
+ temp?: boolean;
184
+ prep: SessionPrep;
185
+ log(line: string): void;
186
+ deps?: ManagedCliDeps;
187
+ now?(): Date;
188
+ }): SessionPrep;
189
+ export interface ManagedCliObservation {
190
+ /** Per form, the best completed pinned invocation recorded after the current policy was loaded. */
191
+ current: {
192
+ form: string;
193
+ effect: ManagedCliForm['effect'];
194
+ at: string;
195
+ class: string;
196
+ }[];
197
+ /** Pinned invocations that predate the current policy: history, not verification. */
198
+ historical: number;
199
+ /** Rows pinned to a configuration other than the one this policy was prepared for. */
200
+ foreign: number;
201
+ summary: string;
202
+ }
203
+ /** Read the role's audit ledger without mutating or recovering it. */
204
+ export declare function observeManagedCli(stateDir: string, record: ManagedCliRecord | undefined): ManagedCliObservation;
205
+ export interface ManagedCliRoleReport {
206
+ role: string;
207
+ harness: string;
208
+ session: string;
209
+ workflows: ManagedCliWorkflowId[];
210
+ /** Generated configuration compared with this installation. Static. */
211
+ setup: {
212
+ state: 'not-declared' | 'not-required' | 'unsupported' | 'prepared' | 'missing' | 'stale' | 'conflict' | 'generated-at-launch';
213
+ mechanism?: ManagedCliMechanism;
214
+ artifact?: string;
215
+ action?: RulesAction;
216
+ detail: string;
217
+ };
218
+ /** Whether the session that is (or was last) running loaded the current policy. */
219
+ session_policy: 'not-applicable' | 'never-launched' | 'current' | 'restart-required';
220
+ /** From the audit ledger. Never inferred from `setup`. */
221
+ observed: ManagedCliObservation;
222
+ commandPrefix?: string;
223
+ scope: string[];
224
+ warnings: string[];
225
+ }
226
+ export interface ManagedCliReport {
227
+ version: 1;
228
+ configuration: string;
229
+ node: string;
230
+ cli: string;
231
+ platform: {
232
+ os: NodeJS.Platform;
233
+ declared: boolean;
234
+ };
235
+ wrote: boolean;
236
+ roles: ManagedCliRoleReport[];
237
+ removed: RulesResult[];
238
+ disclosure: string[];
239
+ }
240
+ export declare function managedCliReport(cfg: Pick<FleetConfig, 'roles'>, configPath: string | undefined, options: ManagedCliDeps & {
241
+ write: boolean;
242
+ env?: NodeJS.ProcessEnv;
243
+ }): ManagedCliReport;
244
+ /**
245
+ * Add a workflow to an existing Agent file, and nothing else. Comments, key
246
+ * order and every other setting — permissions included — are preserved.
247
+ */
248
+ export declare function enableManagedCli(configPath: string | undefined, agent: string, workflow: ManagedCliWorkflowId): {
249
+ file: string;
250
+ changed: boolean;
251
+ };
252
+ /** The briefing section for a role, or nothing when it declares no workflow. */
253
+ export declare function managedCliBriefing(role: ResolvedRole, configPath: string | undefined, temp?: boolean): string[];