@ours.network/fleet 1.2.0-nightly.7 → 1.2.0-nightly.71

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 (423) hide show
  1. package/README.md +279 -68
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +26 -9
  5. package/dist/agent-ours/correspondence.d.ts +10 -0
  6. package/dist/agent-ours/correspondence.js +1 -0
  7. package/dist/agent-ours/file-rpc.d.ts +12 -0
  8. package/dist/agent-ours/file-rpc.js +18 -4
  9. package/dist/agent-ours/harness.js +9 -1
  10. package/dist/agent-ours/mcp-endpoint.d.ts +19 -0
  11. package/dist/agent-ours/mcp-endpoint.js +98 -25
  12. package/dist/agent-ours/runtime.d.ts +9 -1
  13. package/dist/agent-ours/runtime.js +50 -2
  14. package/dist/agent-ours/service.d.ts +24 -1
  15. package/dist/agent-ours/service.js +97 -13
  16. package/dist/application/codex-models.d.ts +15 -0
  17. package/dist/application/codex-models.js +56 -0
  18. package/dist/application/conversation-history.d.ts +34 -0
  19. package/dist/application/conversation-history.js +280 -0
  20. package/dist/application/conversation-role-observer.d.ts +62 -0
  21. package/dist/application/conversation-role-observer.js +206 -0
  22. package/dist/application/fleet-query-service.d.ts +1 -1
  23. package/dist/application/fleet-query-service.js +3 -3
  24. package/dist/application/log-service.js +8 -8
  25. package/dist/application/model-catalog.d.ts +1 -1
  26. package/dist/application/model-catalog.js +5 -2
  27. package/dist/application/preset-provenance.d.ts +19 -0
  28. package/dist/application/preset-provenance.js +59 -0
  29. package/dist/application/resource-observer.d.ts +40 -0
  30. package/dist/application/resource-observer.js +278 -0
  31. package/dist/application/role-creation-service.js +3 -2
  32. package/dist/application/role-removal-service.js +17 -3
  33. package/dist/application/role-repository.d.ts +1 -1
  34. package/dist/application/role-repository.js +30 -7
  35. package/dist/application/room-layout-definitions.d.ts +45 -0
  36. package/dist/application/room-layout-definitions.js +130 -0
  37. package/dist/application/session-control.d.ts +61 -17
  38. package/dist/application/session-control.js +207 -23
  39. package/dist/application/supervisor-ours-tools.js +5 -11
  40. package/dist/application/task-layouts.d.ts +91 -0
  41. package/dist/application/task-layouts.js +261 -0
  42. package/dist/application/task-room-service.d.ts +101 -3
  43. package/dist/application/task-room-service.js +286 -33
  44. package/dist/application/types.d.ts +2 -0
  45. package/dist/atomic-file.d.ts +34 -1
  46. package/dist/atomic-file.js +161 -18
  47. package/dist/briefing.d.ts +3 -1
  48. package/dist/briefing.js +97 -31
  49. package/dist/build-info.json +9 -4
  50. package/dist/capabilities.d.ts +9 -1
  51. package/dist/capabilities.js +13 -0
  52. package/dist/cli.js +400 -37
  53. package/dist/client-profile.d.ts +5 -17
  54. package/dist/client-profile.js +4 -127
  55. package/dist/config.d.ts +45 -0
  56. package/dist/config.js +57 -6
  57. package/dist/creation.d.ts +1 -1
  58. package/dist/creation.js +4 -4
  59. package/dist/daemon-recovery.d.ts +14 -9
  60. package/dist/daemon-recovery.js +124 -115
  61. package/dist/docs.d.ts +1 -1
  62. package/dist/docs.js +207 -19
  63. package/dist/doctor.d.ts +4 -1
  64. package/dist/doctor.js +75 -60
  65. package/dist/erased-resources.d.ts +9 -0
  66. package/dist/erased-resources.js +87 -0
  67. package/dist/file-delivery/reader.d.ts +15 -0
  68. package/dist/file-delivery/reader.js +63 -0
  69. package/dist/file-delivery/store.d.ts +15 -0
  70. package/dist/file-delivery/store.js +124 -0
  71. package/dist/file-delivery/types.d.ts +19 -0
  72. package/dist/file-delivery/types.js +1 -0
  73. package/dist/fleet-command-audit.d.ts +7 -0
  74. package/dist/fleet-command-audit.js +24 -8
  75. package/dist/harness/agent-session.d.ts +4 -0
  76. package/dist/harness/claude-code-session.js +1 -1
  77. package/dist/harness/claude-code.js +21 -11
  78. package/dist/harness/claude-runtime.d.ts +12 -0
  79. package/dist/harness/claude-runtime.js +43 -0
  80. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  81. package/dist/harness/codex-app-server-proxy.js +41 -5
  82. package/dist/harness/codex-reasoning.d.ts +5 -0
  83. package/dist/harness/codex-reasoning.js +12 -0
  84. package/dist/harness/codex-runtime.d.ts +11 -1
  85. package/dist/harness/codex-runtime.js +31 -4
  86. package/dist/harness/codex-session.js +2 -2
  87. package/dist/harness/codex.js +24 -12
  88. package/dist/init-wizard.d.ts +2 -0
  89. package/dist/init-wizard.js +38 -19
  90. package/dist/isolation/policy.js +6 -1
  91. package/dist/isolation/types.d.ts +5 -0
  92. package/dist/managed-cli.d.ts +253 -0
  93. package/dist/managed-cli.js +923 -0
  94. package/dist/managed-recovery.d.ts +13 -0
  95. package/dist/managed-recovery.js +31 -0
  96. package/dist/minimal-setup.d.ts +2 -0
  97. package/dist/minimal-setup.js +44 -0
  98. package/dist/monitor.d.ts +9 -34
  99. package/dist/monitor.js +90 -153
  100. package/dist/notifications/fleet-producer.d.ts +22 -0
  101. package/dist/notifications/fleet-producer.js +237 -0
  102. package/dist/notifications/outbox.d.ts +46 -0
  103. package/dist/notifications/outbox.js +158 -0
  104. package/dist/notifications/target-cleanup.d.ts +11 -0
  105. package/dist/notifications/target-cleanup.js +63 -0
  106. package/dist/notifications/task-producer.d.ts +20 -0
  107. package/dist/notifications/task-producer.js +100 -0
  108. package/dist/ops.d.ts +2 -0
  109. package/dist/ops.js +20 -3
  110. package/dist/owner-channel/channel.js +17 -6
  111. package/dist/owner-channel/commands.d.ts +4 -0
  112. package/dist/owner-channel/commands.js +8 -0
  113. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  114. package/dist/owner-channel/ours-client.js +2 -17
  115. package/dist/paths.d.ts +2 -0
  116. package/dist/paths.js +2 -0
  117. package/dist/preset-migration.js +43 -0
  118. package/dist/process-incarnation.d.ts +23 -0
  119. package/dist/process-incarnation.js +42 -0
  120. package/dist/reminders/manager.d.ts +75 -0
  121. package/dist/reminders/manager.js +278 -0
  122. package/dist/reminders/runtime.d.ts +27 -0
  123. package/dist/reminders/runtime.js +32 -0
  124. package/dist/reminders/schedule.d.ts +37 -0
  125. package/dist/reminders/schedule.js +104 -0
  126. package/dist/reminders/store.d.ts +341 -0
  127. package/dist/reminders/store.js +762 -0
  128. package/dist/reminders/tools.d.ts +20 -0
  129. package/dist/reminders/tools.js +114 -0
  130. package/dist/resolved-plan.js +1 -0
  131. package/dist/rooms-tasks/add-member.d.ts +48 -0
  132. package/dist/rooms-tasks/add-member.js +84 -0
  133. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  134. package/dist/rooms-tasks/archived-absence.js +48 -0
  135. package/dist/rooms-tasks/cli.js +65 -5
  136. package/dist/rooms-tasks/close.d.ts +6 -2
  137. package/dist/rooms-tasks/close.js +246 -37
  138. package/dist/rooms-tasks/config.d.ts +1 -1
  139. package/dist/rooms-tasks/config.js +11 -4
  140. package/dist/rooms-tasks/cowork-adapter.d.ts +12 -5
  141. package/dist/rooms-tasks/cowork-adapter.js +15 -121
  142. package/dist/rooms-tasks/cowork-http.js +56 -6
  143. package/dist/rooms-tasks/deletion.d.ts +1 -1
  144. package/dist/rooms-tasks/deletion.js +84 -5
  145. package/dist/rooms-tasks/erasure.d.ts +6 -0
  146. package/dist/rooms-tasks/erasure.js +173 -0
  147. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  148. package/dist/rooms-tasks/external-worker.js +3 -4
  149. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  150. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  151. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  152. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  153. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  154. package/dist/rooms-tasks/layout-cli.js +107 -0
  155. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  156. package/dist/rooms-tasks/layout-config.js +89 -0
  157. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  158. package/dist/rooms-tasks/layout-control.js +52 -0
  159. package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
  160. package/dist/rooms-tasks/layout-member-retirement.js +90 -0
  161. package/dist/rooms-tasks/layout-service.d.ts +43 -0
  162. package/dist/rooms-tasks/layout-service.js +203 -0
  163. package/dist/rooms-tasks/layout.d.ts +121 -0
  164. package/dist/rooms-tasks/layout.js +286 -0
  165. package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
  166. package/dist/rooms-tasks/legacy-task-member.js +116 -0
  167. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  168. package/dist/rooms-tasks/live-readiness.js +85 -0
  169. package/dist/rooms-tasks/member-ownership.d.ts +5 -0
  170. package/dist/rooms-tasks/member-ownership.js +40 -0
  171. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  172. package/dist/rooms-tasks/member-startup.js +2 -0
  173. package/dist/rooms-tasks/provision.d.ts +3 -0
  174. package/dist/rooms-tasks/provision.js +101 -49
  175. package/dist/rooms-tasks/recovery.d.ts +19 -0
  176. package/dist/rooms-tasks/recovery.js +110 -0
  177. package/dist/rooms-tasks/room-state.d.ts +4 -2
  178. package/dist/rooms-tasks/room-state.js +47 -8
  179. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  180. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  181. package/dist/rooms-tasks/task-state.d.ts +52 -8
  182. package/dist/rooms-tasks/task-state.js +251 -26
  183. package/dist/rooms-tasks/types.d.ts +40 -0
  184. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  185. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  186. package/dist/rooms-tasks/workspace.d.ts +35 -0
  187. package/dist/rooms-tasks/workspace.js +325 -0
  188. package/dist/runner.d.ts +33 -4
  189. package/dist/runner.js +410 -62
  190. package/dist/session/acp.d.ts +75 -2
  191. package/dist/session/acp.js +345 -82
  192. package/dist/session/arbiter.d.ts +98 -0
  193. package/dist/session/arbiter.js +272 -3
  194. package/dist/session/codex-app-server.d.ts +45 -1
  195. package/dist/session/codex-app-server.js +225 -32
  196. package/dist/session/control.d.ts +17 -3
  197. package/dist/session/control.js +213 -23
  198. package/dist/session/conversation-normalizer.d.ts +2 -1
  199. package/dist/session/conversation-normalizer.js +1 -1
  200. package/dist/session/conversation-observation.d.ts +25 -0
  201. package/dist/session/conversation-observation.js +100 -0
  202. package/dist/session/conversation-replay.d.ts +50 -0
  203. package/dist/session/conversation-replay.js +203 -0
  204. package/dist/session/conversation-store.d.ts +15 -1
  205. package/dist/session/conversation-store.js +206 -26
  206. package/dist/session/conversation-types.d.ts +57 -4
  207. package/dist/session/prompt-batch.d.ts +79 -0
  208. package/dist/session/prompt-batch.js +120 -0
  209. package/dist/session/task-notice.d.ts +14 -0
  210. package/dist/session/task-notice.js +13 -0
  211. package/dist/session/types.d.ts +42 -1
  212. package/dist/setup-tunnel-preflight.d.ts +34 -0
  213. package/dist/setup-tunnel-preflight.js +62 -0
  214. package/dist/socket-path.d.ts +2 -0
  215. package/dist/socket-path.js +22 -0
  216. package/dist/spawn.d.ts +5 -1
  217. package/dist/spawn.js +40 -4
  218. package/dist/startup-prompt.d.ts +15 -0
  219. package/dist/startup-prompt.js +71 -0
  220. package/dist/startup-readiness.d.ts +32 -0
  221. package/dist/startup-readiness.js +101 -0
  222. package/dist/startup-telemetry.d.ts +16 -0
  223. package/dist/startup-telemetry.js +46 -0
  224. package/dist/subscriptions/cli.d.ts +91 -0
  225. package/dist/subscriptions/cli.js +223 -0
  226. package/dist/subscriptions/launch.d.ts +37 -0
  227. package/dist/subscriptions/launch.js +93 -0
  228. package/dist/subscriptions/login.d.ts +77 -0
  229. package/dist/subscriptions/login.js +215 -0
  230. package/dist/subscriptions/observed.d.ts +7 -0
  231. package/dist/subscriptions/observed.js +44 -0
  232. package/dist/subscriptions/probe.d.ts +10 -0
  233. package/dist/subscriptions/probe.js +73 -0
  234. package/dist/subscriptions/service.d.ts +102 -0
  235. package/dist/subscriptions/service.js +364 -0
  236. package/dist/subscriptions/store.d.ts +71 -0
  237. package/dist/subscriptions/store.js +143 -0
  238. package/dist/supervisor/adoption.d.ts +8 -0
  239. package/dist/supervisor/adoption.js +78 -0
  240. package/dist/supervisor/catalog.d.ts +62 -0
  241. package/dist/supervisor/catalog.js +254 -0
  242. package/dist/supervisor/fleet.d.ts +8 -0
  243. package/dist/supervisor/fleet.js +89 -0
  244. package/dist/supervisor/index.js +3 -6
  245. package/dist/supervisor/launchd.d.ts +1 -1
  246. package/dist/supervisor/launchd.js +26 -13
  247. package/dist/supervisor/legacy.d.ts +35 -0
  248. package/dist/supervisor/legacy.js +524 -0
  249. package/dist/supervisor/manager.d.ts +15 -0
  250. package/dist/supervisor/manager.js +270 -0
  251. package/dist/supervisor/registration-refresh.d.ts +45 -0
  252. package/dist/supervisor/registration-refresh.js +266 -0
  253. package/dist/supervisor/scope.d.ts +4 -0
  254. package/dist/supervisor/scope.js +10 -0
  255. package/dist/supervisor/systemd.d.ts +2 -2
  256. package/dist/supervisor/systemd.js +19 -33
  257. package/dist/task-supervision.d.ts +9 -0
  258. package/dist/task-supervision.js +145 -0
  259. package/dist/temp-idle.d.ts +17 -0
  260. package/dist/temp-idle.js +42 -0
  261. package/dist/temp-lifecycle.d.ts +23 -8
  262. package/dist/temp-lifecycle.js +123 -66
  263. package/dist/temp-supervisor-recovery.d.ts +1 -1
  264. package/dist/temp-supervisor-recovery.js +2 -2
  265. package/dist/tunnel-setup-completion.d.ts +7 -0
  266. package/dist/tunnel-setup-completion.js +13 -0
  267. package/dist/tunnel-setup-input.d.ts +19 -0
  268. package/dist/tunnel-setup-input.js +124 -0
  269. package/dist/watchdog/query.d.ts +3 -1
  270. package/dist/watchdog/query.js +2 -1
  271. package/dist/web/agent-attachments.d.ts +29 -0
  272. package/dist/web/agent-attachments.js +162 -0
  273. package/dist/web/auth.d.ts +65 -2
  274. package/dist/web/auth.js +201 -11
  275. package/dist/web/available-port.d.ts +2 -0
  276. package/dist/web/available-port.js +23 -0
  277. package/dist/web/control.d.ts +3 -3
  278. package/dist/web/control.js +10 -8
  279. package/dist/web/conversation-stream-codec.d.ts +23 -0
  280. package/dist/web/conversation-stream-codec.js +110 -0
  281. package/dist/web/conversation-stream.d.ts +25 -0
  282. package/dist/web/conversation-stream.js +231 -0
  283. package/dist/web/events.d.ts +2 -0
  284. package/dist/web/events.js +9 -0
  285. package/dist/web/fleet-config-service.d.ts +4 -1
  286. package/dist/web/fleet-config-service.js +46 -15
  287. package/dist/web/prefix-gateway.d.ts +32 -0
  288. package/dist/web/prefix-gateway.js +248 -0
  289. package/dist/web/resource-views.d.ts +124 -0
  290. package/dist/web/resource-views.js +424 -0
  291. package/dist/web/runtime.d.ts +3 -1
  292. package/dist/web/runtime.js +132 -34
  293. package/dist/web/server.d.ts +19 -0
  294. package/dist/web/server.js +802 -67
  295. package/dist/web/service.d.ts +11 -2
  296. package/dist/web/service.js +30 -4
  297. package/dist/web/workspace-devices.d.ts +107 -0
  298. package/dist/web/workspace-devices.js +277 -0
  299. package/dist/web/workspace-tunnel.d.ts +1 -0
  300. package/dist/web/workspace-tunnel.js +34 -0
  301. package/dist/workspace-enrollment.d.ts +83 -0
  302. package/dist/workspace-enrollment.js +580 -0
  303. package/dist/workspace-replacement.d.ts +66 -0
  304. package/dist/workspace-replacement.js +220 -0
  305. package/docs/acp-files.md +146 -0
  306. package/docs/conversation-stream.md +196 -0
  307. package/docs/fleet-migration.md +54 -0
  308. package/docs/live-voice.md +13 -0
  309. package/docs/room-layouts.md +227 -0
  310. package/docs/self-reminders.md +374 -0
  311. package/docs/task-workspaces.md +225 -0
  312. package/docs/validation/managed-cli-permissions.md +421 -0
  313. package/examples/room-layouts/fresh.yaml +27 -0
  314. package/examples/room-layouts/scoped.yaml +21 -0
  315. package/examples/room-layouts/shared.yaml +19 -0
  316. package/package.json +24 -20
  317. package/presets/README.md +78 -0
  318. package/presets/brain-catalog.json +8 -2
  319. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  320. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  321. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  322. package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -2
  323. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  324. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  325. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  326. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  327. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  328. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  329. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  330. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  331. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  332. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  333. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  334. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  335. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  336. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  337. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  338. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  339. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  340. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  341. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  342. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  343. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  344. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  346. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  347. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  348. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  349. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  352. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  353. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  354. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  355. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  356. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  357. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  364. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  365. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  366. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  367. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  368. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  369. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  370. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  371. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  372. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  373. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  374. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  375. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  376. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  377. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  378. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  379. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  380. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  381. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  382. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  383. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  384. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  385. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  386. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  387. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  388. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  389. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  390. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  391. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  392. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  393. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  394. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  395. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  396. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  397. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  398. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  399. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  400. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  401. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  402. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  403. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  404. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  405. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  406. package/presets/fleet/roles/Coordinator.yaml +12 -11
  407. package/presets/fleet/roles/Critic.yaml +13 -0
  408. package/presets/fleet/roles/Developer.yaml +13 -0
  409. package/presets/fleet/roles/Engineer.yaml +53 -0
  410. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  411. package/presets/fleet/room_layouts/pair.yaml +24 -0
  412. package/presets/fleet/room_layouts/single.yaml +17 -0
  413. package/presets/fleet/room_layouts/team.yaml +30 -0
  414. package/presets/fleet/room_templates/engineering.yaml +19 -0
  415. package/presets/manifest.json +2 -2
  416. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  417. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  418. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  419. package/dist/web-app/icons/ours-fleet.svg +0 -4
  420. package/dist/web-app/index.html +0 -17
  421. package/dist/web-app/manifest.webmanifest +0 -15
  422. package/dist/web-app/offline.html +0 -18
  423. package/dist/web-app/sw.js +0 -51
@@ -0,0 +1,15 @@
1
+ import { type FileHandle } from 'node:fs/promises';
2
+ export declare const MAX_FILE_BYTES: number;
3
+ /** Pin every component; neither trusted root ancestors nor agent components follow symlinks. */
4
+ export declare function openDirectory(path: string): Promise<FileHandle>;
5
+ /** The agent's provided path, resolved from its working directory; no export subtree. */
6
+ export declare function chatFilePath(cwd: string, input: string): string;
7
+ /**
8
+ * Runs in the harness bridge, never in the supervisor's OS context. Ancestor
9
+ * symlinks resolve normally; the named file itself must be one regular,
10
+ * singly-linked file within the size limit. `path` is the opened file's real path.
11
+ */
12
+ export declare function openChatFile(cwd: string, input: string): Promise<{
13
+ file: FileHandle;
14
+ path: string;
15
+ }>;
@@ -0,0 +1,63 @@
1
+ import { constants } from 'node:fs';
2
+ import { open, readlink } from 'node:fs/promises';
3
+ import { isAbsolute, resolve } from 'node:path';
4
+ export const MAX_FILE_BYTES = 20 * 1024 * 1024;
5
+ const FLAGS = constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK;
6
+ /** Pin every component; neither trusted root ancestors nor agent components follow symlinks. */
7
+ export async function openDirectory(path) {
8
+ if (process.platform !== 'linux' || !isAbsolute(path) || path !== resolve(path))
9
+ throw Error('FILE_DELIVERY_REQUIRES_LINUX_ROOT');
10
+ let dir = await open('/', FLAGS | constants.O_DIRECTORY);
11
+ try {
12
+ for (const part of path.split('/').filter(Boolean)) {
13
+ const next = await open(`/proc/self/fd/${dir.fd}/${part}`, FLAGS | constants.O_DIRECTORY);
14
+ await dir.close();
15
+ dir = next;
16
+ }
17
+ return dir;
18
+ }
19
+ catch (error) {
20
+ await dir.close();
21
+ throw error;
22
+ }
23
+ }
24
+ /** The agent's provided path, resolved from its working directory; no export subtree. */
25
+ export function chatFilePath(cwd, input) {
26
+ if (typeof input !== 'string' || !input || input.length > 4096 || /[\x00-\x1f]/.test(input))
27
+ throw Error('INVALID_CHAT_FILE_PATH');
28
+ return resolve(cwd, input);
29
+ }
30
+ /**
31
+ * Runs in the harness bridge, never in the supervisor's OS context. Ancestor
32
+ * symlinks resolve normally; the named file itself must be one regular,
33
+ * singly-linked file within the size limit. `path` is the opened file's real path.
34
+ */
35
+ export async function openChatFile(cwd, input) {
36
+ if (process.platform !== 'linux')
37
+ throw Error('CHAT_FILE_REQUIRES_LINUX');
38
+ let file;
39
+ try {
40
+ file = await open(chatFilePath(cwd, input), FLAGS);
41
+ }
42
+ catch (error) {
43
+ const code = error.code;
44
+ if (error instanceof Error && error.message === 'INVALID_CHAT_FILE_PATH')
45
+ throw error;
46
+ throw Error(code === 'ELOOP' ? 'CHAT_FILE_IS_SYMLINK' : code === 'ENOENT' || code === 'ENOTDIR' ? 'CHAT_FILE_NOT_FOUND'
47
+ : code === 'EACCES' || code === 'EPERM' ? 'CHAT_FILE_NOT_READABLE' : 'CHAT_FILE_OPEN_FAILED');
48
+ }
49
+ try {
50
+ const stat = await file.stat();
51
+ if (!stat.isFile())
52
+ throw Error('CHAT_FILE_NOT_REGULAR');
53
+ if (stat.nlink !== 1)
54
+ throw Error('CHAT_FILE_HARDLINKED');
55
+ if (stat.size > MAX_FILE_BYTES)
56
+ throw Error('FILE_EXCEEDS_20_MIB');
57
+ return { file, path: await readlink(`/proc/self/fd/${file.fd}`) };
58
+ }
59
+ catch (error) {
60
+ await file.close();
61
+ throw error;
62
+ }
63
+ }
@@ -0,0 +1,15 @@
1
+ import type { DeliveredFile, FileDeliveryBinding } from './types.js';
2
+ export declare function artifactDirectory(stateDir: string): string;
3
+ export declare class ArtifactStore {
4
+ private readonly stateDir;
5
+ constructor(stateDir: string);
6
+ copy(source: {
7
+ size: number;
8
+ body: ReadableStream<Uint8Array>;
9
+ close(): Promise<void>;
10
+ }, name: string, mimeType: string, binding: FileDeliveryBinding, signal: AbortSignal): Promise<DeliveredFile>;
11
+ }
12
+ export declare function readDeliveredFile(stateDir: string, id: string): Promise<{
13
+ record: DeliveredFile;
14
+ bytes: Buffer;
15
+ }>;
@@ -0,0 +1,124 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { constants, mkdirSync, readFileSync, readdirSync, lstatSync, openSync, fstatSync, closeSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { open, unlink } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { stateRoot } from '../paths.js';
6
+ import { openDirectory, MAX_FILE_BYTES } from './reader.js';
7
+ export function artifactDirectory(stateDir) {
8
+ const incarnation = readFileSync(join(stateDir, '.session-id'), 'utf8').trim();
9
+ if (!/^[a-f0-9-]{36}$/.test(incarnation))
10
+ throw Error('INVALID_ROLE_INCARNATION');
11
+ const key = createHash('sha256').update(JSON.stringify([stateDir, incarnation])).digest('hex');
12
+ return join(stateRoot(), 'private-file-delivery', key);
13
+ }
14
+ function privateDirectory(path) {
15
+ mkdirSync(path, { recursive: true, mode: 0o700 });
16
+ const stat = lstatSync(path);
17
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || stat.mode & 0o077)
18
+ throw Error('INVALID_ARTIFACT_DIRECTORY');
19
+ }
20
+ export class ArtifactStore {
21
+ stateDir;
22
+ constructor(stateDir) {
23
+ this.stateDir = stateDir;
24
+ }
25
+ async copy(source, name, mimeType, binding, signal) {
26
+ if (!Number.isSafeInteger(source.size) || source.size < 0 || source.size > MAX_FILE_BYTES)
27
+ throw Error('FILE_EXCEEDS_20_MIB');
28
+ const path = artifactDirectory(this.stateDir);
29
+ privateDirectory(join(stateRoot(), 'private-file-delivery'));
30
+ privateDirectory(path);
31
+ const root = await openDirectory(path);
32
+ const id = randomUUID(), base = `/proc/self/fd/${root.fd}/`, partial = base + id + '.part';
33
+ let file;
34
+ const reader = source.body.getReader();
35
+ try {
36
+ // Orphans count toward the same bounded quota. They are never republished.
37
+ const entries = readdirSync(base).filter(p => /\.(data|part)$/.test(p));
38
+ const bytes = entries.reduce((sum, p) => sum + lstatSync(base + p).size, 0);
39
+ if (entries.length >= 100 || bytes + source.size > 200 * 1024 * 1024)
40
+ throw Error('ARTIFACT_QUOTA_EXCEEDED');
41
+ file = await open(partial, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
42
+ const hash = createHash('sha256');
43
+ let size = 0;
44
+ for (;;) {
45
+ signal.throwIfAborted();
46
+ const chunk = await reader.read();
47
+ if (chunk.done)
48
+ break;
49
+ size += chunk.value.length;
50
+ if (size > source.size || size > MAX_FILE_BYTES)
51
+ throw Error('SOURCE_SIZE_CHANGED');
52
+ hash.update(chunk.value);
53
+ let offset = 0;
54
+ while (offset < chunk.value.length) {
55
+ const { bytesWritten } = await file.write(chunk.value, offset, chunk.value.length - offset);
56
+ if (!bytesWritten)
57
+ throw Error('SHORT_ARTIFACT_WRITE');
58
+ offset += bytesWritten;
59
+ }
60
+ }
61
+ if (size !== source.size)
62
+ throw Error('SOURCE_SIZE_CHANGED');
63
+ signal.throwIfAborted();
64
+ await file.chmod(0o400);
65
+ await file.sync();
66
+ await file.close();
67
+ file = undefined;
68
+ const record = { id, name, mimeType, size, sha256: hash.digest('hex'), ...binding };
69
+ renameSync(partial, base + id + '.data');
70
+ writeFileSync(base + id + '.json', JSON.stringify(record), { flag: 'wx', mode: 0o400, flush: true });
71
+ // No pending-send record or recovery: a later failure leaves only unreferenced stored bytes.
72
+ await root.sync();
73
+ // The newly created incarnation directory and store root must also survive
74
+ // a crash before a durable conversation event can reference this file.
75
+ for (const parent of [join(stateRoot(), 'private-file-delivery'), stateRoot()]) {
76
+ const handle = await openDirectory(parent);
77
+ try {
78
+ await handle.sync();
79
+ }
80
+ finally {
81
+ await handle.close();
82
+ }
83
+ }
84
+ return record;
85
+ }
86
+ finally {
87
+ await file?.close();
88
+ await reader.cancel().catch(() => { });
89
+ await source.close();
90
+ await unlink(partial).catch(() => { });
91
+ await root.close();
92
+ }
93
+ }
94
+ }
95
+ export async function readDeliveredFile(stateDir, id) {
96
+ if (!/^[a-f0-9-]{36}$/.test(id))
97
+ throw Error('ARTIFACT_NOT_FOUND');
98
+ const root = await openDirectory(artifactDirectory(stateDir));
99
+ const read = (suffix, max) => {
100
+ const fd = openSync(`/proc/self/fd/${root.fd}/${id}.${suffix}`, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
101
+ try {
102
+ const stat = fstatSync(fd);
103
+ if (!stat.isFile() || stat.nlink !== 1 || stat.uid !== process.getuid?.() || stat.size > max)
104
+ throw Error('INVALID_STORED_ARTIFACT');
105
+ const bytes = readFileSync(fd);
106
+ if (bytes.length > max)
107
+ throw Error('ARTIFACT_TOO_LARGE');
108
+ return bytes;
109
+ }
110
+ finally {
111
+ closeSync(fd);
112
+ }
113
+ };
114
+ try {
115
+ const record = JSON.parse(read('json', 4096).toString());
116
+ const bytes = read('data', MAX_FILE_BYTES);
117
+ if (record.id !== id || record.size !== bytes.length || record.sha256 !== createHash('sha256').update(bytes).digest('hex') || typeof record.name !== 'string')
118
+ throw Error('ARTIFACT_INTEGRITY_FAILED');
119
+ return { record, bytes };
120
+ }
121
+ finally {
122
+ await root.close();
123
+ }
124
+ }
@@ -0,0 +1,19 @@
1
+ export interface FileDeliveryBinding {
2
+ sessionGeneration: string;
3
+ acpSessionId: string;
4
+ turnId: string;
5
+ }
6
+ export interface DeliveredFile extends FileDeliveryBinding {
7
+ id: string;
8
+ name: string;
9
+ mimeType: string;
10
+ size: number;
11
+ sha256: string;
12
+ }
13
+ export interface FileDeliveryInput {
14
+ path: string;
15
+ filename?: string;
16
+ mime?: string;
17
+ }
18
+ export type CopyChatFile = (binding: FileDeliveryBinding) => Promise<DeliveredFile>;
19
+ export type SendChatFile = (input: FileDeliveryInput, signal: AbortSignal, copy: CopyChatFile) => Promise<DeliveredFile>;
@@ -0,0 +1 @@
1
+ export {};
@@ -113,6 +113,7 @@ export interface FleetCommandClassification {
113
113
  decision: FleetCommandDecision;
114
114
  }
115
115
  export interface FleetAuditAttempt {
116
+ erased?: boolean;
116
117
  version: 1;
117
118
  correlationId: string;
118
119
  requestId: string;
@@ -144,6 +145,12 @@ export declare const fleetProxyTopLevelInventory: Readonly<{
144
145
  }>;
145
146
  /** Classify before Commander parsing. Unknown and internal paths fail closed. */
146
147
  export declare function classifyFleetArgv(argv: readonly string[]): FleetCommandClassification;
148
+ /**
149
+ * The pinned configuration of a managed entry (src/managed-cli.ts) is recorded
150
+ * as a fingerprint, not as its path: diagnostics must tell which configuration a
151
+ * row ran under without the ledger holding the path itself.
152
+ */
153
+ export declare const managedPinMarker: (configuration: string) => string;
147
154
  /** Faithful ordered argv with deterministic structural redaction. */
148
155
  export declare function redactFleetArgv(argv: readonly string[]): string[];
149
156
  /** Durable write-once attempt ledger; contains redacted argv only. */
@@ -1,7 +1,7 @@
1
+ import { erasedArg, redactErasedContent, writePrivacyFilteredLedger } from './erased-resources.js';
1
2
  import { existsSync, readFileSync } from 'node:fs';
2
- import { randomUUID } from 'node:crypto';
3
+ import { createHash, randomUUID } from 'node:crypto';
3
4
  import { Buffer } from 'node:buffer';
4
- import { replaceFileAtomically } from './atomic-file.js';
5
5
  import { isSensitiveConfigKey } from './sensitive-config.js';
6
6
  import { mandatoryConfigurationFits } from './lifecycle-summary.js';
7
7
  import { MARKDOWN_MAX_BYTES, MARKDOWN_MAX_CODE_POINTS, markdownCode, markdownProse, } from './rooms-tasks/markdown.js';
@@ -91,7 +91,7 @@ export function recordFleetAuditPresentation(value) {
91
91
  : value.kind === 'lifecycle_failure'
92
92
  ? { label: fleetPresentationLabel(value.label) }
93
93
  : {};
94
- const presentation = structuredClone({ ...value, ...labels, eventId: basis });
94
+ const presentation = redactErasedContent(structuredClone({ ...value, ...labels, eventId: basis }));
95
95
  const digest = lifecycleEventDigestBasis(presentation);
96
96
  if (!collection.presentations.some(existing => lifecycleEventDigestBasis(existing) === digest))
97
97
  collection.presentations.push(presentation);
@@ -135,7 +135,8 @@ export const fleetProxyTopLevelInventory = Object.freeze({
135
135
  ], denied: [...DENIED],
136
136
  hidden: ['_run', '_run-temp', '_run-temp-worker', '_run-watchdog', '_run-watchdogs'], aliases: ['man'],
137
137
  });
138
- const globalValueOptions = new Set(['-c', '--configuration']);
138
+ // `--managed-configuration <file>` is the pinned managed entry form (src/managed-cli.ts).
139
+ const globalValueOptions = new Set(['-c', '--configuration', '--managed-configuration']);
139
140
  /** Classify before Commander parsing. Unknown and internal paths fail closed. */
140
141
  export function classifyFleetArgv(argv) {
141
142
  let command = '';
@@ -186,10 +187,16 @@ export function classifyFleetArgv(argv) {
186
187
  return { command, route: 'supervisor-proxy/public', decision: 'allow' };
187
188
  }
188
189
  const marker = (value) => value === '' ? '[REDACTED:empty]' : '[REDACTED:value]';
190
+ /**
191
+ * The pinned configuration of a managed entry (src/managed-cli.ts) is recorded
192
+ * as a fingerprint, not as its path: diagnostics must tell which configuration a
193
+ * row ran under without the ledger holding the path itself.
194
+ */
195
+ export const managedPinMarker = (configuration) => `[PIN:${createHash('sha256').update(configuration).digest('hex').slice(0, 16)}]`;
189
196
  const sensitiveValueFlags = new Set([
190
197
  '--identity', '--invite', '--token', '--api-token', '--password', '--password-file',
191
198
  '--env', '--brief', '--brief-file', '--bio-file', '--persona-file', '--isolation-file', '--loops-file',
192
- '--configuration', '-c', '--public-invite', '--public-invite-file', '--invite-file',
199
+ '--configuration', '-c', '--managed-configuration', '--public-invite', '--public-invite-file', '--invite-file',
193
200
  '--args-file', '--summary-file', '--text', '--message', '--summary', '--reason', '--goal', '--cwd',
194
201
  '--identity-cid', '--owner-cid', '--contact-cid', '--codex-config', '--add-dir',
195
202
  ]);
@@ -249,6 +256,11 @@ export function redactFleetArgv(argv) {
249
256
  result[index] = `${equal[1]}=${marker(equal[2])}`;
250
257
  continue;
251
258
  }
259
+ if (index === 0 && arg === '--managed-configuration' && result.length > 1) {
260
+ result[1] = managedPinMarker(result[1]);
261
+ index++;
262
+ continue;
263
+ }
252
264
  if (sensitiveValueFlags.has(arg) && index + 1 < result.length) {
253
265
  result[index + 1] = marker(result[index + 1]);
254
266
  index++;
@@ -305,11 +317,12 @@ export class FleetCommandAuditStore {
305
317
  if (recovered)
306
318
  this.persist();
307
319
  }
308
- list() { return this.attempts.map(item => structuredClone(item)); }
320
+ list() { return redactErasedContent(this.attempts).map(item => structuredClone(item)); }
309
321
  begin(requestId, caller, argv) {
322
+ this.attempts = redactErasedContent(this.attempts);
310
323
  const existing = this.attempts.find(item => item.caller === caller && item.requestId === requestId);
311
324
  if (existing) {
312
- if (JSON.stringify(existing.argv) !== JSON.stringify(redactFleetArgv(argv)))
325
+ if (JSON.stringify(existing.argv) !== JSON.stringify(existing.erased ? redactFleetArgv(argv).map(erasedArg) : redactFleetArgv(argv)))
313
326
  throw new Error('fleet command request ID was reused with different argv');
314
327
  return structuredClone(existing);
315
328
  }
@@ -329,6 +342,8 @@ export class FleetCommandAuditStore {
329
342
  return structuredClone(attempt);
330
343
  }
331
344
  finish(correlationId, caller, outcome) {
345
+ this.attempts = redactErasedContent(this.attempts);
346
+ outcome = redactErasedContent({ outcome }).outcome;
332
347
  const attempt = this.owned(correlationId, caller);
333
348
  if (!attempt.outcome)
334
349
  attempt.outcome = { ...outcome, completedAt: this.deps.now().toISOString(), delivery: 'sending' };
@@ -360,7 +375,8 @@ export class FleetCommandAuditStore {
360
375
  return attempt;
361
376
  }
362
377
  persist() {
363
- replaceFileAtomically(this.path, `${JSON.stringify({ version: 1, attempts: this.attempts })}\n`, 0o600);
378
+ this.attempts = redactErasedContent(this.attempts);
379
+ writePrivacyFilteredLedger(this.path, { version: 1, attempts: this.attempts });
364
380
  }
365
381
  }
366
382
  const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
@@ -30,6 +30,10 @@ export interface AgentSessionStartOptions {
30
30
  cwd: string;
31
31
  stateDir: string;
32
32
  mode: 'fresh' | 'resume';
33
+ /** Durable task context must never silently fall back to a fresh session. */
34
+ requireResume?: boolean;
35
+ /** Hold recovered never-started prompts until AgentSession.activateRecoveredPrompts(). */
36
+ deferRecoveredPrompts?: boolean;
33
37
  permissions: CommonPermissions;
34
38
  permissionMode: {
35
39
  fleetMode: FleetPermissionMode;
@@ -24,7 +24,7 @@ export class ClaudeCodeAgentSessionAdapter {
24
24
  return this.transport({
25
25
  name: role.name, harness: role.harness,
26
26
  argv: launch.argv, cwd: options.cwd, env: launch.env,
27
- stateDir: options.stateDir, mode: options.mode, permissions: options.permissions,
27
+ stateDir: options.stateDir, mode: options.mode, requireResume: options.requireResume, deferRecoveredPrompts: options.deferRecoveredPrompts, permissions: options.permissions,
28
28
  modeId: this.strategy.permissionModeId(role),
29
29
  mcpServers: options.managedOurs ? [...(this.strategy.mcpServers(role) ?? []).filter(s => s.name !== 'ours'), options.managedOurs.server] : this.strategy.mcpServers(role),
30
30
  inheritEnvironment: options.managedOurs ? false : undefined,
@@ -6,7 +6,8 @@ import { realExec } from '../exec.js';
6
6
  import { registerAdapter } from './registry.js';
7
7
  import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
8
8
  import { harnessRuntimeDir } from '../isolation/policy.js';
9
- import { bundledAcpAgent } from './acp-agent.js';
9
+ import { bundledAcpAgent, resolveBundledAcpAgent } from './acp-agent.js';
10
+ import { hostClaude } from './claude-runtime.js';
10
11
  import { ClaudeCodeAgentSessionAdapter } from './claude-code-session.js';
11
12
  const OPTION_KEYS = [
12
13
  'plugins', 'mem_palace', 'mem_palace_midsession_autosave', 'permission_mode', 'effort',
@@ -283,6 +284,13 @@ export function makeClaudeCodeAdapter(exec = realExec, transport) {
283
284
  };
284
285
  if (!memPalace)
285
286
  env.MEMPALACE_DISABLED = 'true';
287
+ // The bundled adapter runs the Claude Code shipped with its SDK unless told otherwise. A host
288
+ // Claude Code at least as new as that copy is the one the person updates, so sessions run it.
289
+ if (!customAcpCommand(role)) {
290
+ const host = hostClaude(resolveBundledAcpAgent('@agentclientprotocol/claude-agent-acp', 'claude-agent-acp', 'claude-agent-acp').manifestPath, { ...process.env, ...role.env }, dirs.runCwd);
291
+ if (host)
292
+ env.CLAUDE_CODE_EXECUTABLE = host.path;
293
+ }
286
294
  // Per-role harness runtime home. Created before sandbox entry so the
287
295
  // bind has something to mount; harmless for un-isolated roles.
288
296
  // Only a role that declares `isolation:` gets a sandbox, and only a
@@ -377,16 +385,18 @@ export function makeClaudeCodeAdapter(exec = realExec, transport) {
377
385
  supervisedWakeNote: () => 'Your mail wake-ups are delivered by the fleet supervisor directly into this console as ' +
378
386
  '`[fleet-monitor]` lines — do NOT arm an in-session Monitor. When such a line appears, run ' +
379
387
  '**get_messages** to drain the mail.',
380
- launchNote: name => `You were launched with \`--remote-control ${name}\`. Confirm you are running.`,
381
- restartPrompt: (id, worklog, role) => `Session restarted. Re-bind your ours identity now (choose_identity name "${id}" force=true), ` +
382
- (role?.monitor?.mode === 'fleet'
383
- ? 'then continue from '
384
- : `then ${armMonitor(id)}, then continue from `) +
385
- `${worklog}. Do not re-run whatever crashed you.` +
386
- (role?.monitor?.mode === 'fleet'
387
- ? ' Your mail wakes arrive as `[fleet-monitor]` console lines from the supervisor — ' +
388
- 'do NOT arm an in-session Monitor.'
389
- : ''),
388
+ launchNote: name => `You were launched as Fleet role \`${name}\` under a Claude session. Announce console readiness before task details.`,
389
+ restartPrompt: (id, worklog, role) => role?.monitor?.mode === 'fleet'
390
+ ? `Session restarted. The supervisor has verified assigned identity "${id}"; ` +
391
+ 'accept that readiness and continue without rebinding or profile reconciliation. ' +
392
+ 'Your mail wakes arrive as `[fleet-monitor]` console lines from the supervisor — ' +
393
+ 'do NOT arm an in-session Monitor. ' +
394
+ 'Announce console readiness first without tools, then end that readiness turn. ' +
395
+ `For a separate continuation task, read ${worklog} once for continuity if it records previous work; ` +
396
+ 'do not read it again later in this session. ' +
397
+ 'Do not re-run whatever crashed you.'
398
+ : `Session restarted. Re-bind your ours identity now (choose_identity name "${id}" force=true), ` +
399
+ `then ${armMonitor(id)}, then continue from ${worklog}. Do not re-run whatever crashed you.`,
390
400
  },
391
401
  exitPolicy: { cleanExitIsFresh: true, fastFailSecs: 20 },
392
402
  };
@@ -0,0 +1,12 @@
1
+ /** The Claude Code version shipped inside the adapter's own SDK dependency. */
2
+ export declare function bundledClaudeVersion(adapterManifest: string): string | undefined;
3
+ /**
4
+ * The host's own Claude Code, when ACP sessions should run it instead of the copy bundled with the adapter.
5
+ * The person signs in to, updates and checks the host Claude Code, and a newer one knows models the bundled
6
+ * one does not. It is used only when it is at least as new as the bundled copy; an explicit
7
+ * CLAUDE_CODE_EXECUTABLE, in the role or the service environment, always decides instead.
8
+ */
9
+ export declare function hostClaude(adapterManifest: string | undefined, env: NodeJS.ProcessEnv, cwd?: string, version?: (path: string, env: NodeJS.ProcessEnv) => string | undefined): {
10
+ path: string;
11
+ version: string;
12
+ } | undefined;
@@ -0,0 +1,43 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join } from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { codexVersionAtLeast, executableOnPath } from './codex-runtime.js';
6
+ const versionOf = (text) => text.match(/\b(\d+\.\d+\.\d+)\b/)?.[1];
7
+ function installedClaudeVersion(path, env) {
8
+ const result = spawnSync(path, ['--version'], { env, encoding: 'utf8', timeout: 5_000, stdio: ['ignore', 'pipe', 'ignore'] });
9
+ return result.status === 0 ? versionOf(result.stdout ?? '') : undefined;
10
+ }
11
+ /** The Claude Code version shipped inside the adapter's own SDK dependency. */
12
+ export function bundledClaudeVersion(adapterManifest) {
13
+ try {
14
+ const sdk = dirname(createRequire(adapterManifest).resolve('@anthropic-ai/claude-agent-sdk'));
15
+ const version = JSON.parse(readFileSync(join(sdk, 'package.json'), 'utf8')).claudeCodeVersion;
16
+ return typeof version === 'string' ? version : undefined;
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ /**
23
+ * The host's own Claude Code, when ACP sessions should run it instead of the copy bundled with the adapter.
24
+ * The person signs in to, updates and checks the host Claude Code, and a newer one knows models the bundled
25
+ * one does not. It is used only when it is at least as new as the bundled copy; an explicit
26
+ * CLAUDE_CODE_EXECUTABLE, in the role or the service environment, always decides instead.
27
+ */
28
+ export function hostClaude(adapterManifest, env, cwd = process.cwd(), version = installedClaudeVersion) {
29
+ if (env.CLAUDE_CODE_EXECUTABLE !== undefined || !adapterManifest)
30
+ return undefined;
31
+ const bundled = bundledClaudeVersion(adapterManifest);
32
+ if (!bundled)
33
+ return undefined;
34
+ let path;
35
+ try {
36
+ path = executableOnPath('claude', env, cwd);
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ const found = version(path, env);
42
+ return found && codexVersionAtLeast(found, bundled) ? { path, version: found } : undefined;
43
+ }
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ type JsonObject = Record<string, unknown>;
2
3
  interface TerminalRecoveryOptions {
3
4
  sendToCodex(line: string): void;
4
5
  emitToClient(line: string): void;
@@ -39,6 +40,8 @@ export declare class CodexTerminalRecovery {
39
40
  private finishTurn;
40
41
  }
41
42
  /** Transform one app-server NDJSON request; malformed input passes through. */
42
- export declare function rewriteCodexAppServerRequest(line: string, approval: string, expectedSandbox: string, disableInheritedMcp?: boolean): string;
43
+ export declare function rewriteCodexAppServerRequest(line: string, approval: string, expectedSandbox: string, disableInheritedMcp?: boolean, managedOursTools?: JsonObject): string;
44
+ /** ACP only carries transport fields; read policy from Fleet's complete config. */
45
+ export declare function managedCodexToolPolicy(env: NodeJS.ProcessEnv): JsonObject | undefined;
43
46
  export declare function runCodexAppServerProxy(): void;
44
47
  export {};
@@ -300,9 +300,9 @@ function sandboxMode(policy) {
300
300
  * Fleet keeps the preset's sandbox policy, but restores the independently
301
301
  * configured approval policy on the request Codex actually executes.
302
302
  */
303
- function rewriteMessage(value, approval, expectedSandbox, disableInheritedMcp) {
303
+ function rewriteMessage(value, approval, expectedSandbox, disableInheritedMcp, managedOursTools) {
304
304
  if (Array.isArray(value))
305
- return value.map(candidate => rewriteMessage(candidate, approval, expectedSandbox, disableInheritedMcp));
305
+ return value.map(candidate => rewriteMessage(candidate, approval, expectedSandbox, disableInheritedMcp, managedOursTools));
306
306
  if (!isObject(value) || !isObject(value.params))
307
307
  return value;
308
308
  if (value.method === 'turn/start') {
@@ -318,17 +318,52 @@ function rewriteMessage(value, approval, expectedSandbox, disableInheritedMcp) {
318
318
  params: { ...value.params, config: { ...config, mcp_servers: {} } },
319
319
  };
320
320
  }
321
+ if (managedOursTools
322
+ && (value.method === 'thread/start' || value.method === 'thread/resume')) {
323
+ const config = isObject(value.params.config) ? value.params.config : {};
324
+ const servers = isObject(config.mcp_servers) ? config.mcp_servers : {};
325
+ const ours = servers.ours;
326
+ // Policy cannot create or re-enable a connector that ACP did not inject.
327
+ if (!isObject(ours) || ours.enabled === false)
328
+ return value;
329
+ const tools = isObject(ours.tools) ? { ...ours.tools } : {};
330
+ for (const [name, policy] of Object.entries(managedOursTools)) {
331
+ if (isObject(policy))
332
+ tools[name] = {
333
+ ...(isObject(tools[name]) ? tools[name] : {}), ...policy,
334
+ };
335
+ }
336
+ return { ...value, params: { ...value.params, config: { ...config,
337
+ mcp_servers: { ...servers, ours: { ...ours, tools } },
338
+ } } };
339
+ }
321
340
  return value;
322
341
  }
323
342
  /** Transform one app-server NDJSON request; malformed input passes through. */
324
- export function rewriteCodexAppServerRequest(line, approval, expectedSandbox, disableInheritedMcp = false) {
343
+ export function rewriteCodexAppServerRequest(line, approval, expectedSandbox, disableInheritedMcp = false, managedOursTools) {
325
344
  try {
326
- return JSON.stringify(rewriteMessage(JSON.parse(line), approval, expectedSandbox, disableInheritedMcp));
345
+ return JSON.stringify(rewriteMessage(JSON.parse(line), approval, expectedSandbox, disableInheritedMcp, managedOursTools));
327
346
  }
328
347
  catch {
329
348
  return line;
330
349
  }
331
350
  }
351
+ /** ACP only carries transport fields; read policy from Fleet's complete config. */
352
+ export function managedCodexToolPolicy(env) {
353
+ if (env.FLEET_OURS_MANAGED !== '1')
354
+ return undefined;
355
+ try {
356
+ const config = JSON.parse(env.CODEX_CONFIG ?? '{}');
357
+ const servers = isObject(config) ? config.mcp_servers : undefined;
358
+ const ours = isObject(servers) ? servers.ours : undefined;
359
+ return isObject(ours) && ours.enabled !== false && isObject(ours.tools)
360
+ ? ours.tools : undefined;
361
+ }
362
+ catch {
363
+ // Invalid config never grants tool approval. ACP owns config diagnostics.
364
+ return undefined;
365
+ }
366
+ }
332
367
  function requiredChoice(name, allowed) {
333
368
  const value = process.env[name];
334
369
  if (value && allowed.has(value))
@@ -355,6 +390,7 @@ export function runCodexAppServerProxy() {
355
390
  const approval = requiredChoice(APPROVAL_ENV, APPROVAL_POLICIES);
356
391
  const expectedSandbox = requiredChoice(SANDBOX_ENV, SANDBOX_MODES);
357
392
  const disableInheritedMcp = process.env[DISABLE_INHERITED_MCP_ENV] === '1';
393
+ const managedOursTools = managedCodexToolPolicy(process.env);
358
394
  const launch = realCodexLaunch();
359
395
  const env = { ...process.env };
360
396
  delete env.CODEX_PATH;
@@ -450,7 +486,7 @@ export function runCodexAppServerProxy() {
450
486
  input.on('line', line => {
451
487
  if (finished)
452
488
  return;
453
- const rewritten = rewriteCodexAppServerRequest(line, approval, expectedSandbox, disableInheritedMcp);
489
+ const rewritten = rewriteCodexAppServerRequest(line, approval, expectedSandbox, disableInheritedMcp, managedOursTools);
454
490
  recovery.observeClientLine(rewritten);
455
491
  writeToChild(rewritten);
456
492
  });
@@ -0,0 +1,5 @@
1
+ /** Efforts supported by Fleet's Codex Brain contract. Keep native eligibility in sync. */
2
+ export declare const CODEX_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max", "ultra"];
3
+ export declare function isCodexReasoningEffort(value: unknown): value is string;
4
+ /** Only inspected model tuning may bypass the managed CLI native-config guard. */
5
+ export declare function isManagedCliCodexConfig(config: unknown): boolean;
@@ -0,0 +1,12 @@
1
+ /** Efforts supported by Fleet's Codex Brain contract. Keep native eligibility in sync. */
2
+ export const CODEX_REASONING_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max', 'ultra'];
3
+ export function isCodexReasoningEffort(value) {
4
+ return typeof value === 'string' && CODEX_REASONING_EFFORTS.includes(value);
5
+ }
6
+ /** Only inspected model tuning may bypass the managed CLI native-config guard. */
7
+ export function isManagedCliCodexConfig(config) {
8
+ if (config == null)
9
+ return true;
10
+ return typeof config === 'object' && !Array.isArray(config)
11
+ && Object.entries(config).every(([key, value]) => key === 'model_reasoning_effort' && isCodexReasoningEffort(value));
12
+ }
@@ -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;