@ours.network/fleet 1.2.0-nightly.6 → 1.2.0-nightly.60

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 (389) hide show
  1. package/README.md +287 -65
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +35 -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 +4 -0
  11. package/dist/agent-ours/mcp-endpoint.js +5 -0
  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 +21 -1
  15. package/dist/agent-ours/service.js +94 -14
  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 +27 -0
  19. package/dist/application/conversation-history.js +212 -0
  20. package/dist/application/fleet-query-service.d.ts +1 -1
  21. package/dist/application/fleet-query-service.js +2 -2
  22. package/dist/application/legacy-supervisor-identity.d.ts +7 -0
  23. package/dist/application/legacy-supervisor-identity.js +43 -0
  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/role-creation-service.js +3 -2
  30. package/dist/application/role-removal-service.js +9 -1
  31. package/dist/application/role-repository.js +19 -2
  32. package/dist/application/room-layout-definitions.d.ts +45 -0
  33. package/dist/application/room-layout-definitions.js +130 -0
  34. package/dist/application/session-control.d.ts +30 -0
  35. package/dist/application/session-control.js +72 -3
  36. package/dist/application/supervisor-ours-tools.d.ts +159 -0
  37. package/dist/application/supervisor-ours-tools.js +115 -0
  38. package/dist/application/task-layouts.d.ts +91 -0
  39. package/dist/application/task-layouts.js +259 -0
  40. package/dist/application/task-room-service.d.ts +99 -3
  41. package/dist/application/task-room-service.js +285 -32
  42. package/dist/application/types.d.ts +2 -0
  43. package/dist/atomic-file.d.ts +5 -0
  44. package/dist/atomic-file.js +62 -1
  45. package/dist/briefing.d.ts +3 -1
  46. package/dist/briefing.js +70 -30
  47. package/dist/build-info.json +7 -4
  48. package/dist/capabilities.d.ts +6 -1
  49. package/dist/capabilities.js +8 -0
  50. package/dist/cli.js +407 -37
  51. package/dist/client-profile.d.ts +5 -17
  52. package/dist/client-profile.js +4 -127
  53. package/dist/config.d.ts +45 -0
  54. package/dist/config.js +57 -6
  55. package/dist/creation.d.ts +1 -1
  56. package/dist/creation.js +4 -4
  57. package/dist/daemon-recovery.d.ts +1 -8
  58. package/dist/daemon-recovery.js +8 -113
  59. package/dist/docs.d.ts +1 -1
  60. package/dist/docs.js +123 -19
  61. package/dist/doctor.d.ts +1 -1
  62. package/dist/doctor.js +55 -60
  63. package/dist/erased-resources.d.ts +9 -0
  64. package/dist/erased-resources.js +87 -0
  65. package/dist/file-delivery/reader.d.ts +15 -0
  66. package/dist/file-delivery/reader.js +63 -0
  67. package/dist/file-delivery/store.d.ts +15 -0
  68. package/dist/file-delivery/store.js +124 -0
  69. package/dist/file-delivery/types.d.ts +19 -0
  70. package/dist/file-delivery/types.js +1 -0
  71. package/dist/fleet-command-audit.d.ts +7 -0
  72. package/dist/fleet-command-audit.js +26 -9
  73. package/dist/harness/agent-session.d.ts +2 -0
  74. package/dist/harness/claude-code-session.js +1 -1
  75. package/dist/harness/claude-code.js +20 -11
  76. package/dist/harness/claude-runtime.d.ts +12 -0
  77. package/dist/harness/claude-runtime.js +43 -0
  78. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  79. package/dist/harness/codex-app-server-proxy.js +41 -5
  80. package/dist/harness/codex-reasoning.d.ts +5 -0
  81. package/dist/harness/codex-reasoning.js +12 -0
  82. package/dist/harness/codex-runtime.d.ts +11 -1
  83. package/dist/harness/codex-runtime.js +31 -4
  84. package/dist/harness/codex-session.js +2 -2
  85. package/dist/harness/codex.js +23 -12
  86. package/dist/init-wizard.d.ts +2 -0
  87. package/dist/init-wizard.js +38 -19
  88. package/dist/isolation/policy.js +6 -1
  89. package/dist/isolation/types.d.ts +5 -0
  90. package/dist/managed-cli.d.ts +253 -0
  91. package/dist/managed-cli.js +923 -0
  92. package/dist/managed-recovery.d.ts +13 -0
  93. package/dist/managed-recovery.js +31 -0
  94. package/dist/minimal-setup.d.ts +2 -0
  95. package/dist/minimal-setup.js +44 -0
  96. package/dist/monitor.d.ts +8 -34
  97. package/dist/monitor.js +89 -152
  98. package/dist/notifications/fleet-producer.d.ts +19 -0
  99. package/dist/notifications/fleet-producer.js +208 -0
  100. package/dist/notifications/outbox.d.ts +46 -0
  101. package/dist/notifications/outbox.js +158 -0
  102. package/dist/notifications/target-cleanup.d.ts +8 -0
  103. package/dist/notifications/target-cleanup.js +41 -0
  104. package/dist/notifications/task-producer.d.ts +18 -0
  105. package/dist/notifications/task-producer.js +67 -0
  106. package/dist/ops.d.ts +2 -0
  107. package/dist/ops.js +20 -3
  108. package/dist/owner-channel/channel.js +17 -6
  109. package/dist/owner-channel/commands.d.ts +4 -0
  110. package/dist/owner-channel/commands.js +8 -0
  111. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  112. package/dist/owner-channel/ours-client.js +2 -17
  113. package/dist/paths.d.ts +2 -0
  114. package/dist/paths.js +2 -0
  115. package/dist/preset-migration.js +25 -0
  116. package/dist/resolved-plan.js +1 -0
  117. package/dist/rooms-tasks/add-member.d.ts +48 -0
  118. package/dist/rooms-tasks/add-member.js +83 -0
  119. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  120. package/dist/rooms-tasks/archived-absence.js +48 -0
  121. package/dist/rooms-tasks/cli.js +65 -5
  122. package/dist/rooms-tasks/close.d.ts +6 -2
  123. package/dist/rooms-tasks/close.js +246 -37
  124. package/dist/rooms-tasks/config.d.ts +1 -1
  125. package/dist/rooms-tasks/config.js +11 -4
  126. package/dist/rooms-tasks/cowork-adapter.d.ts +2 -4
  127. package/dist/rooms-tasks/cowork-adapter.js +7 -121
  128. package/dist/rooms-tasks/cowork-http.js +29 -1
  129. package/dist/rooms-tasks/deletion.d.ts +1 -1
  130. package/dist/rooms-tasks/deletion.js +84 -5
  131. package/dist/rooms-tasks/erasure.d.ts +6 -0
  132. package/dist/rooms-tasks/erasure.js +173 -0
  133. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  134. package/dist/rooms-tasks/external-worker.js +3 -4
  135. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  136. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  137. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  138. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  139. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  140. package/dist/rooms-tasks/layout-cli.js +107 -0
  141. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  142. package/dist/rooms-tasks/layout-config.js +89 -0
  143. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  144. package/dist/rooms-tasks/layout-control.js +52 -0
  145. package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
  146. package/dist/rooms-tasks/layout-member-retirement.js +90 -0
  147. package/dist/rooms-tasks/layout-service.d.ts +43 -0
  148. package/dist/rooms-tasks/layout-service.js +203 -0
  149. package/dist/rooms-tasks/layout.d.ts +121 -0
  150. package/dist/rooms-tasks/layout.js +285 -0
  151. package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
  152. package/dist/rooms-tasks/legacy-task-member.js +116 -0
  153. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  154. package/dist/rooms-tasks/live-readiness.js +85 -0
  155. package/dist/rooms-tasks/member-ownership.d.ts +5 -0
  156. package/dist/rooms-tasks/member-ownership.js +40 -0
  157. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  158. package/dist/rooms-tasks/member-startup.js +2 -0
  159. package/dist/rooms-tasks/provision.d.ts +3 -0
  160. package/dist/rooms-tasks/provision.js +101 -49
  161. package/dist/rooms-tasks/recovery.d.ts +19 -0
  162. package/dist/rooms-tasks/recovery.js +110 -0
  163. package/dist/rooms-tasks/room-state.d.ts +4 -2
  164. package/dist/rooms-tasks/room-state.js +47 -8
  165. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  166. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  167. package/dist/rooms-tasks/task-state.d.ts +51 -8
  168. package/dist/rooms-tasks/task-state.js +245 -25
  169. package/dist/rooms-tasks/types.d.ts +40 -0
  170. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  171. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  172. package/dist/rooms-tasks/workspace.d.ts +35 -0
  173. package/dist/rooms-tasks/workspace.js +325 -0
  174. package/dist/runner.d.ts +25 -3
  175. package/dist/runner.js +291 -49
  176. package/dist/session/acp.d.ts +53 -1
  177. package/dist/session/acp.js +216 -40
  178. package/dist/session/arbiter.d.ts +11 -0
  179. package/dist/session/arbiter.js +43 -2
  180. package/dist/session/codex-app-server.d.ts +32 -0
  181. package/dist/session/codex-app-server.js +137 -23
  182. package/dist/session/control.d.ts +12 -1
  183. package/dist/session/control.js +68 -3
  184. package/dist/session/conversation-normalizer.d.ts +2 -1
  185. package/dist/session/conversation-normalizer.js +1 -1
  186. package/dist/session/conversation-store.d.ts +1 -1
  187. package/dist/session/conversation-store.js +7 -11
  188. package/dist/session/conversation-types.d.ts +28 -3
  189. package/dist/session/prompt-batch.d.ts +63 -0
  190. package/dist/session/prompt-batch.js +86 -0
  191. package/dist/session/task-notice.d.ts +14 -0
  192. package/dist/session/task-notice.js +13 -0
  193. package/dist/session/types.d.ts +14 -0
  194. package/dist/setup-tunnel-preflight.d.ts +34 -0
  195. package/dist/setup-tunnel-preflight.js +62 -0
  196. package/dist/socket-path.d.ts +2 -0
  197. package/dist/socket-path.js +22 -0
  198. package/dist/spawn.d.ts +5 -1
  199. package/dist/spawn.js +40 -4
  200. package/dist/startup-prompt.d.ts +4 -0
  201. package/dist/startup-prompt.js +36 -0
  202. package/dist/startup-readiness.d.ts +13 -0
  203. package/dist/startup-readiness.js +38 -0
  204. package/dist/startup-telemetry.d.ts +16 -0
  205. package/dist/startup-telemetry.js +46 -0
  206. package/dist/subscriptions/cli.d.ts +91 -0
  207. package/dist/subscriptions/cli.js +223 -0
  208. package/dist/subscriptions/launch.d.ts +37 -0
  209. package/dist/subscriptions/launch.js +93 -0
  210. package/dist/subscriptions/login.d.ts +75 -0
  211. package/dist/subscriptions/login.js +182 -0
  212. package/dist/subscriptions/observed.d.ts +7 -0
  213. package/dist/subscriptions/observed.js +44 -0
  214. package/dist/subscriptions/probe.d.ts +10 -0
  215. package/dist/subscriptions/probe.js +73 -0
  216. package/dist/subscriptions/service.d.ts +102 -0
  217. package/dist/subscriptions/service.js +364 -0
  218. package/dist/subscriptions/store.d.ts +71 -0
  219. package/dist/subscriptions/store.js +140 -0
  220. package/dist/supervisor/adoption.d.ts +8 -0
  221. package/dist/supervisor/adoption.js +78 -0
  222. package/dist/supervisor/catalog.d.ts +62 -0
  223. package/dist/supervisor/catalog.js +254 -0
  224. package/dist/supervisor/fleet.d.ts +8 -0
  225. package/dist/supervisor/fleet.js +89 -0
  226. package/dist/supervisor/index.js +3 -6
  227. package/dist/supervisor/launchd.d.ts +1 -1
  228. package/dist/supervisor/launchd.js +26 -13
  229. package/dist/supervisor/legacy.d.ts +35 -0
  230. package/dist/supervisor/legacy.js +524 -0
  231. package/dist/supervisor/manager.d.ts +15 -0
  232. package/dist/supervisor/manager.js +270 -0
  233. package/dist/supervisor/scope.d.ts +4 -0
  234. package/dist/supervisor/scope.js +10 -0
  235. package/dist/supervisor/systemd.d.ts +2 -2
  236. package/dist/supervisor/systemd.js +19 -33
  237. package/dist/task-supervision.d.ts +9 -0
  238. package/dist/task-supervision.js +145 -0
  239. package/dist/temp-idle.d.ts +17 -0
  240. package/dist/temp-idle.js +42 -0
  241. package/dist/temp-lifecycle.d.ts +23 -8
  242. package/dist/temp-lifecycle.js +113 -65
  243. package/dist/temp-supervisor-recovery.d.ts +1 -1
  244. package/dist/temp-supervisor-recovery.js +2 -2
  245. package/dist/tunnel-setup-completion.d.ts +7 -0
  246. package/dist/tunnel-setup-completion.js +13 -0
  247. package/dist/tunnel-setup-input.d.ts +19 -0
  248. package/dist/tunnel-setup-input.js +124 -0
  249. package/dist/web/agent-attachments.d.ts +29 -0
  250. package/dist/web/agent-attachments.js +162 -0
  251. package/dist/web/auth.d.ts +63 -2
  252. package/dist/web/auth.js +191 -10
  253. package/dist/web/available-port.d.ts +2 -0
  254. package/dist/web/available-port.js +23 -0
  255. package/dist/web/control.d.ts +3 -3
  256. package/dist/web/control.js +10 -8
  257. package/dist/web/fleet-config-service.d.ts +4 -1
  258. package/dist/web/fleet-config-service.js +46 -15
  259. package/dist/web/prefix-gateway.d.ts +32 -0
  260. package/dist/web/prefix-gateway.js +238 -0
  261. package/dist/web/runtime.d.ts +3 -1
  262. package/dist/web/runtime.js +116 -31
  263. package/dist/web/server.d.ts +16 -0
  264. package/dist/web/server.js +654 -55
  265. package/dist/web/service.d.ts +11 -2
  266. package/dist/web/service.js +30 -4
  267. package/dist/web/workspace-devices.d.ts +107 -0
  268. package/dist/web/workspace-devices.js +277 -0
  269. package/dist/web/workspace-tunnel.d.ts +1 -0
  270. package/dist/web/workspace-tunnel.js +34 -0
  271. package/dist/workspace-enrollment.d.ts +82 -0
  272. package/dist/workspace-enrollment.js +566 -0
  273. package/dist/workspace-replacement.d.ts +66 -0
  274. package/dist/workspace-replacement.js +220 -0
  275. package/docs/acp-files.md +146 -0
  276. package/docs/fleet-migration.md +54 -0
  277. package/docs/live-voice.md +13 -0
  278. package/docs/room-layouts.md +227 -0
  279. package/docs/task-workspaces.md +225 -0
  280. package/docs/validation/managed-cli-permissions.md +421 -0
  281. package/examples/room-layouts/fresh.yaml +27 -0
  282. package/examples/room-layouts/scoped.yaml +21 -0
  283. package/examples/room-layouts/shared.yaml +19 -0
  284. package/package.json +20 -19
  285. package/presets/README.md +78 -0
  286. package/presets/brain-catalog.json +8 -2
  287. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  288. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  289. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  290. package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
  291. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  292. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  293. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  294. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  295. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  296. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  297. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  298. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  299. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  300. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  301. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  302. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  303. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  304. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  305. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  306. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  307. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  308. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  309. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  310. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  311. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  312. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  313. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  314. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  315. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  316. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  317. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  318. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  319. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  320. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  321. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  322. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  323. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  324. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  325. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  326. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  327. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  328. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  329. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  330. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  331. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  332. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  333. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  334. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  335. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  336. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  337. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  338. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  339. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  340. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  341. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  342. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  343. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  344. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  346. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  347. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  348. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  349. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  352. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  353. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  354. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  355. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  356. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  357. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  364. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  365. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  366. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  367. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  368. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  369. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  370. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  371. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  372. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  373. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  374. package/presets/fleet/roles/Coordinator.yaml +34 -11
  375. package/presets/fleet/roles/Engineer.yaml +40 -0
  376. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  377. package/presets/fleet/room_layouts/pair.yaml +24 -0
  378. package/presets/fleet/room_layouts/single.yaml +17 -0
  379. package/presets/fleet/room_layouts/team.yaml +30 -0
  380. package/presets/fleet/room_templates/engineering.yaml +19 -0
  381. package/presets/manifest.json +2 -2
  382. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  383. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  384. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  385. package/dist/web-app/icons/ours-fleet.svg +0 -4
  386. package/dist/web-app/index.html +0 -17
  387. package/dist/web-app/manifest.webmanifest +0 -15
  388. package/dist/web-app/offline.html +0 -18
  389. package/dist/web-app/sw.js +0 -51
@@ -0,0 +1,130 @@
1
+ /** Web authoring of `fleet/room_layouts/<name>.yaml`.
2
+ * Writes are revision-guarded (sha256 of the file bytes) and validated with the
3
+ * same parser the CLI uses. Retained layout runs keep their own snapshots, so
4
+ * editing or deleting a definition never changes an existing run.
5
+ */
6
+ import { createHash } from 'node:crypto';
7
+ import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync } from 'node:fs';
8
+ import { basename, extname, join } from 'node:path';
9
+ import { stringify } from 'yaml';
10
+ import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
11
+ import { parseFleetDocument } from '../config-yaml.js';
12
+ import { defaultConfigPath } from '../paths.js';
13
+ import { loadConfig, splitRootFor } from '../config.js';
14
+ import { assertLayoutFile, validLayoutKey, validateRoomLayout } from '../rooms-tasks/layout-config.js';
15
+ import { FleetError } from './errors.js';
16
+ import { layoutDefinitionHash } from './task-layouts.js';
17
+ export const ABSENT_REVISION = 'absent';
18
+ const revisionOf = (bytes) => createHash('sha256').update(bytes).digest('hex');
19
+ export class RoomLayoutDefinitions {
20
+ configPath;
21
+ deps;
22
+ constructor(configPath, deps = {}) {
23
+ this.configPath = configPath;
24
+ this.deps = deps;
25
+ }
26
+ root() { return join(splitRootFor(this.configPath ?? defaultConfigPath()), 'room_layouts'); }
27
+ pathFor(name) {
28
+ if (!validLayoutKey(name))
29
+ throw new FleetError('invalid_request', 'layout name must start with a letter and use letters, digits, - or _');
30
+ return join(this.root(), `${name}.yaml`);
31
+ }
32
+ currentRevision(path) {
33
+ if (!existsSync(path))
34
+ return ABSENT_REVISION;
35
+ assertLayoutFile(path);
36
+ return revisionOf(readFileSync(path));
37
+ }
38
+ /** Agent-template references that do not resolve in the current Fleet configuration. */
39
+ templateIssues(definition) {
40
+ let templates = {};
41
+ try {
42
+ templates = (this.deps.loadConfiguration ?? loadConfig)(this.configPath).agentTemplates ?? {};
43
+ }
44
+ catch (error) {
45
+ return [`fleet configuration unavailable: ${error.message}`];
46
+ }
47
+ return Object.entries(definition.participants).flatMap(([key, participant]) => participant.agent_template && !Object.hasOwn(templates, participant.agent_template)
48
+ ? [`participant ${key}: agent template not found: ${participant.agent_template}`] : []);
49
+ }
50
+ /** The configured default (`rooms.defaults.template`, else `tasks.default_room_template`) when it names a usable layout. */
51
+ defaultLayout(entries = this.list()) {
52
+ let name;
53
+ try {
54
+ const config = (this.deps.loadConfiguration ?? loadConfig)(this.configPath);
55
+ name = config.rooms?.defaults?.template ?? config.tasks?.default_room_template;
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ const entry = entries.find(e => e.name === name);
61
+ return entry && !('error' in entry) && !entry.issues.length ? entry.name : undefined;
62
+ }
63
+ list() {
64
+ const root = this.root();
65
+ if (!existsSync(root))
66
+ return [];
67
+ assertLayoutFile(root, true);
68
+ return readdirSync(root).filter(file => /\.ya?ml$/.test(file)).sort().map(file => {
69
+ const name = basename(file, extname(file)), path = join(root, file);
70
+ try {
71
+ if (!validLayoutKey(name))
72
+ throw Error(`invalid room layout id: ${name}`);
73
+ assertLayoutFile(path);
74
+ const bytes = readFileSync(path);
75
+ const definition = validateRoomLayout(parseFleetDocument(path, bytes.toString('utf8'), 'strict').value, file);
76
+ return { name, file, revision: revisionOf(bytes), definition, issues: this.templateIssues(definition), definition_hash: layoutDefinitionHash(definition) };
77
+ }
78
+ catch (error) {
79
+ // Only a trusted regular file may be read to offer an overwrite revision.
80
+ let revision = ABSENT_REVISION;
81
+ try {
82
+ assertLayoutFile(path);
83
+ revision = revisionOf(readFileSync(path));
84
+ }
85
+ catch { /* not trusted: never read */ }
86
+ return { name, file, revision, error: error.message };
87
+ }
88
+ });
89
+ }
90
+ validate(raw) {
91
+ let definition;
92
+ try {
93
+ definition = validateRoomLayout(raw, 'room layout');
94
+ }
95
+ catch (error) {
96
+ return { issues: [error.message] };
97
+ }
98
+ return { definition, issues: this.templateIssues(definition) };
99
+ }
100
+ async save(name, expectedRevision, raw) {
101
+ const path = this.pathFor(name);
102
+ const { definition, issues } = this.validate(raw);
103
+ if (!definition || issues.length)
104
+ throw new FleetError('invalid_request', issues.join('; '));
105
+ const root = this.root();
106
+ mkdirSync(root, { recursive: true, mode: 0o700 });
107
+ assertLayoutFile(root, true);
108
+ return withFileLock(`${path}.lock`, async () => {
109
+ const current = this.currentRevision(path);
110
+ if (current !== expectedRevision)
111
+ throw new FleetError('stale_state', 'room layout changed since it was loaded; reload before saving');
112
+ const { description, participants, rooms } = definition;
113
+ const text = stringify({ version: 1, ...(description ? { description } : {}), participants, rooms });
114
+ replaceFileAtomically(path, text, 0o600);
115
+ return { name, revision: revisionOf(text), definition };
116
+ });
117
+ }
118
+ async remove(name, expectedRevision) {
119
+ const path = this.pathFor(name);
120
+ return withFileLock(`${path}.lock`, async () => {
121
+ const current = this.currentRevision(path);
122
+ if (current === ABSENT_REVISION)
123
+ return { name, deleted: false };
124
+ if (current !== expectedRevision)
125
+ throw new FleetError('stale_state', 'room layout changed since it was loaded; reload before deleting');
126
+ unlinkSync(path);
127
+ return { name, deleted: true };
128
+ });
129
+ }
130
+ }
@@ -1,3 +1,5 @@
1
+ import { type ConversationTailPage } from './conversation-history.js';
2
+ import type { AgentHistoryQuery } from '../agent-ours/correspondence.js';
1
3
  import { controlRequest } from '../session/control.js';
2
4
  import type { ConversationEventV1, ConversationSnapshot, PromptReceipt } from '../session/conversation-types.js';
3
5
  import type { SessionSnapshot } from '../session/types.js';
@@ -23,6 +25,8 @@ export interface InterruptReceipt {
23
25
  reasonCode?: string;
24
26
  }
25
27
  export interface RoleSessionControl {
28
+ agentContacts?(): Promise<unknown>;
29
+ agentHistory?(request: AgentHistoryQuery): Promise<unknown>;
26
30
  describe(): Promise<SessionDescriptor>;
27
31
  snapshot(): Promise<SessionSnapshot>;
28
32
  recentOutput(request?: {
@@ -41,12 +45,24 @@ export interface RoleSessionControl {
41
45
  after?: string;
42
46
  limit?: number;
43
47
  }): Promise<ConversationPageView>;
48
+ /** The newest visible events (or those before `before`), read backwards from the ledger. */
49
+ conversationTail?(request: {
50
+ before?: string;
51
+ limit?: number;
52
+ }): Promise<ConversationTailPage>;
44
53
  submitPromptV2?(request: {
45
54
  commandId: string;
46
55
  text: string;
47
56
  actorBrowserSession: string;
57
+ expectedSessionGeneration?: string;
58
+ requireIdle?: boolean;
48
59
  source: 'owner_admin_console';
49
60
  }): Promise<PromptReceipt>;
61
+ interruptPromptV2?(request: {
62
+ commandId: string;
63
+ expectedSessionGeneration: string;
64
+ promptId: string;
65
+ }): Promise<InterruptReceipt>;
50
66
  interruptV2?(commandId: string): Promise<InterruptReceipt & {
51
67
  commandId: string;
52
68
  }>;
@@ -75,6 +91,9 @@ export declare class RoleSessionControlAdapter implements RoleSessionControl {
75
91
  private readonly stateDir;
76
92
  private readonly request;
77
93
  constructor(stateDir: string, request?: typeof controlRequest);
94
+ agentContacts(): Promise<unknown>;
95
+ agentHistory(request: AgentHistoryQuery): Promise<unknown>;
96
+ private requireCorrespondence;
78
97
  describe(): Promise<SessionDescriptor>;
79
98
  snapshot(): Promise<SessionSnapshot>;
80
99
  recentOutput(request?: {
@@ -87,12 +106,23 @@ export declare class RoleSessionControlAdapter implements RoleSessionControl {
87
106
  after?: string;
88
107
  limit?: number;
89
108
  }): Promise<ConversationPageView>;
109
+ conversationTail(request?: {
110
+ before?: string;
111
+ limit?: number;
112
+ }): Promise<ConversationTailPage>;
90
113
  submitPromptV2(request: {
91
114
  commandId: string;
92
115
  text: string;
93
116
  actorBrowserSession: string;
117
+ expectedSessionGeneration?: string;
118
+ requireIdle?: boolean;
94
119
  source: 'owner_admin_console';
95
120
  }): Promise<PromptReceipt>;
121
+ interruptPromptV2(request: {
122
+ commandId: string;
123
+ expectedSessionGeneration: string;
124
+ promptId: string;
125
+ }): Promise<InterruptReceipt>;
96
126
  interruptV2(commandId: string): Promise<InterruptReceipt & {
97
127
  commandId: string;
98
128
  }>;
@@ -1,3 +1,6 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { conversationTailPage, resumedConversationPage } from './conversation-history.js';
1
4
  import { controlRequest, followConversation } from '../session/control.js';
2
5
  import { FleetError, normalizeError } from './errors.js';
3
6
  const visibleEvents = (events) => events.filter(event => event.kind !== 'thought');
@@ -8,6 +11,10 @@ export class RoleSessionControlAdapter {
8
11
  this.stateDir = stateDir;
9
12
  this.request = request;
10
13
  }
14
+ async agentContacts() { await this.requireCorrespondence(); return this.call('agent_contacts'); }
15
+ async agentHistory(request) { await this.requireCorrespondence(); return this.call('agent_history', { agentHistory: request }); }
16
+ async requireCorrespondence() { if (!(await this.describe()).features.includes('agent_correspondence'))
17
+ throw new FleetError('capability_unavailable', 'This session needs an updated supervisor to show contacts and history.'); }
11
18
  async describe() {
12
19
  const response = await this.call('snapshot');
13
20
  const result = response;
@@ -58,28 +65,90 @@ export class RoleSessionControlAdapter {
58
65
  };
59
66
  }
60
67
  async conversationPage(request = {}) {
61
- return await this.call('conversation_page', {
68
+ const live = await this.call('conversation_page', {
62
69
  after: request.after, limit: request.limit,
63
70
  });
71
+ const snapshot = await this.snapshot();
72
+ if (snapshot.backend !== 'acp' || !snapshot.sessionId)
73
+ return live;
74
+ try {
75
+ const history = await resumedConversationPage(this.stateDir, request, live, snapshot.sessionId);
76
+ const check = await this.call('conversation_page', { limit: 1 });
77
+ return check.snapshot.sessionGeneration === live.snapshot.sessionGeneration ? history : await this.call('conversation_page', request);
78
+ }
79
+ catch {
80
+ return live;
81
+ }
82
+ }
83
+ async conversationTail(request = {}) {
84
+ const live = await this.call('conversation_page', { limit: 1 });
85
+ const snapshot = await this.snapshot();
86
+ let resumed;
87
+ if (snapshot.backend === 'acp' && snapshot.sessionId) {
88
+ try {
89
+ if ((await readFile(join(this.stateDir, '.acp-session-id'), 'utf8')).trim() === snapshot.sessionId)
90
+ resumed = snapshot.sessionId;
91
+ }
92
+ catch { /* no resumed history: live generation only */ }
93
+ }
94
+ try {
95
+ return await conversationTailPage(this.stateDir, request, live.snapshot, resumed);
96
+ }
97
+ catch (error) {
98
+ throw new FleetError('invalid_request', error.message);
99
+ }
64
100
  }
65
101
  async submitPromptV2(request) {
66
102
  if (!request.text.trim())
67
103
  throw new FleetError('invalid_request', 'text is required');
68
104
  if (Buffer.byteLength(request.text) > 32 * 1024)
69
105
  throw new FleetError('invalid_request', 'text exceeds 32 KiB');
106
+ // A prompt bound to a session generation (voice or attachments) is checked atomically by supervisors that
107
+ // support it. Older supervisors do not know that command and never answer, so check the generation here
108
+ // and submit an ordinary prompt; its command id keeps retries idempotent either way.
109
+ const features = request.requireIdle ? (await this.describe()).features : undefined;
110
+ if (request.requireIdle && (!request.expectedSessionGeneration || !features?.includes('idle_bound_prompts')))
111
+ throw new FleetError('capability_unavailable', 'Live voice requires an updated supervisor.');
112
+ let command = 'submit_prompt_v2';
113
+ if (request.expectedSessionGeneration) {
114
+ if ((await this.describe()).features.includes('generation_bound_prompts'))
115
+ command = 'submit_voice_prompt';
116
+ else {
117
+ const live = await this.call('conversation_page', { limit: 1 });
118
+ if (live.snapshot?.sessionGeneration !== request.expectedSessionGeneration)
119
+ throw new FleetError('stale_state', 'Agent session changed. Record a new voice message.');
120
+ }
121
+ }
70
122
  try {
71
- return await this.call('submit_prompt_v2', {
123
+ return await this.call(command, {
72
124
  commandId: request.commandId, text: request.text, actor: request.actorBrowserSession,
73
- source: request.source,
125
+ source: request.source, expectedSessionGeneration: request.expectedSessionGeneration, requireIdle: request.requireIdle,
74
126
  });
75
127
  }
76
128
  catch (error) {
77
129
  const fleetError = normalizeError(error);
130
+ if (fleetError.message.includes('session_changed:'))
131
+ throw new FleetError('stale_state', 'Agent session changed. Record a new voice message.');
132
+ if (fleetError.message.includes('voice_busy:'))
133
+ throw new FleetError('conflict', 'Agent is already working. Wait for the current turn.');
78
134
  if (fleetError.message.includes('idempotency_conflict'))
79
135
  throw new FleetError('idempotency_conflict', 'this command id was already used with a different prompt body');
80
136
  throw fleetError;
81
137
  }
82
138
  }
139
+ async interruptPromptV2(request) {
140
+ if (!(await this.describe()).features.includes('targeted_voice_interrupt'))
141
+ throw new FleetError('capability_unavailable', 'Live voice requires an updated supervisor.');
142
+ try {
143
+ return await this.call('interrupt_voice_v2', request);
144
+ }
145
+ catch (error) {
146
+ const failure = normalizeError(error);
147
+ if (failure.message.includes('session_changed:'))
148
+ throw new FleetError('stale_state', 'Agent session changed.');
149
+ throw failure;
150
+ }
151
+ }
83
152
  async interruptV2(commandId) {
84
153
  const receipt = await this.call('interrupt_v2', { commandId });
85
154
  return {
@@ -0,0 +1,159 @@
1
+ export interface SupervisorToolRequest {
2
+ tool: string;
3
+ arguments?: Record<string, unknown>;
4
+ }
5
+ /** CLI and REST use the same fixed-identity MCP server as the agent harness. */
6
+ export declare class SupervisorOursTools {
7
+ private withClient;
8
+ list(role: string): Promise<{
9
+ tools: {
10
+ inputSchema: {
11
+ [x: string]: unknown;
12
+ type: "object";
13
+ properties?: Record<string, object> | undefined;
14
+ required?: string[] | undefined;
15
+ };
16
+ name: string;
17
+ description?: string | undefined;
18
+ outputSchema?: {
19
+ [x: string]: unknown;
20
+ type: "object";
21
+ properties?: Record<string, object> | undefined;
22
+ required?: string[] | undefined;
23
+ } | undefined;
24
+ annotations?: {
25
+ title?: string | undefined;
26
+ readOnlyHint?: boolean | undefined;
27
+ destructiveHint?: boolean | undefined;
28
+ idempotentHint?: boolean | undefined;
29
+ openWorldHint?: boolean | undefined;
30
+ } | undefined;
31
+ execution?: {
32
+ taskSupport?: "optional" | "required" | "forbidden" | undefined;
33
+ } | undefined;
34
+ _meta?: Record<string, unknown> | undefined;
35
+ icons?: {
36
+ src: string;
37
+ mimeType?: string | undefined;
38
+ sizes?: string[] | undefined;
39
+ theme?: "light" | "dark" | undefined;
40
+ }[] | undefined;
41
+ title?: string | undefined;
42
+ }[];
43
+ _meta?: {
44
+ [x: string]: unknown;
45
+ progressToken?: string | number | undefined;
46
+ "io.modelcontextprotocol/related-task"?: {
47
+ taskId: string;
48
+ } | undefined;
49
+ } | undefined;
50
+ nextCursor?: string | undefined;
51
+ agent: string;
52
+ identity: {
53
+ name: string;
54
+ cid: string;
55
+ generation: number;
56
+ };
57
+ }>;
58
+ call(role: string, request: SupervisorToolRequest): Promise<{
59
+ agent: string;
60
+ identity: {
61
+ name: string;
62
+ cid: string;
63
+ generation: number;
64
+ };
65
+ result: {
66
+ [x: string]: unknown;
67
+ content: ({
68
+ type: "text";
69
+ text: string;
70
+ annotations?: {
71
+ audience?: ("user" | "assistant")[] | undefined;
72
+ priority?: number | undefined;
73
+ lastModified?: string | undefined;
74
+ } | undefined;
75
+ _meta?: Record<string, unknown> | undefined;
76
+ } | {
77
+ type: "image";
78
+ data: string;
79
+ mimeType: string;
80
+ annotations?: {
81
+ audience?: ("user" | "assistant")[] | undefined;
82
+ priority?: number | undefined;
83
+ lastModified?: string | undefined;
84
+ } | undefined;
85
+ _meta?: Record<string, unknown> | undefined;
86
+ } | {
87
+ type: "audio";
88
+ data: string;
89
+ mimeType: string;
90
+ annotations?: {
91
+ audience?: ("user" | "assistant")[] | undefined;
92
+ priority?: number | undefined;
93
+ lastModified?: string | undefined;
94
+ } | undefined;
95
+ _meta?: Record<string, unknown> | undefined;
96
+ } | {
97
+ type: "resource";
98
+ resource: {
99
+ uri: string;
100
+ text: string;
101
+ mimeType?: string | undefined;
102
+ _meta?: Record<string, unknown> | undefined;
103
+ } | {
104
+ uri: string;
105
+ blob: string;
106
+ mimeType?: string | undefined;
107
+ _meta?: Record<string, unknown> | undefined;
108
+ };
109
+ annotations?: {
110
+ audience?: ("user" | "assistant")[] | undefined;
111
+ priority?: number | undefined;
112
+ lastModified?: string | undefined;
113
+ } | undefined;
114
+ _meta?: Record<string, unknown> | undefined;
115
+ } | {
116
+ uri: string;
117
+ name: string;
118
+ type: "resource_link";
119
+ description?: string | undefined;
120
+ mimeType?: string | undefined;
121
+ size?: number | undefined;
122
+ annotations?: {
123
+ audience?: ("user" | "assistant")[] | undefined;
124
+ priority?: number | undefined;
125
+ lastModified?: string | undefined;
126
+ } | undefined;
127
+ _meta?: {
128
+ [x: string]: unknown;
129
+ } | undefined;
130
+ icons?: {
131
+ src: string;
132
+ mimeType?: string | undefined;
133
+ sizes?: string[] | undefined;
134
+ theme?: "light" | "dark" | undefined;
135
+ }[] | undefined;
136
+ title?: string | undefined;
137
+ })[];
138
+ _meta?: {
139
+ [x: string]: unknown;
140
+ progressToken?: string | number | undefined;
141
+ "io.modelcontextprotocol/related-task"?: {
142
+ taskId: string;
143
+ } | undefined;
144
+ } | undefined;
145
+ structuredContent?: Record<string, unknown> | undefined;
146
+ isError?: boolean | undefined;
147
+ } | {
148
+ [x: string]: unknown;
149
+ toolResult: unknown;
150
+ _meta?: {
151
+ [x: string]: unknown;
152
+ progressToken?: string | number | undefined;
153
+ "io.modelcontextprotocol/related-task"?: {
154
+ taskId: string;
155
+ } | undefined;
156
+ } | undefined;
157
+ };
158
+ }>;
159
+ }
@@ -0,0 +1,115 @@
1
+ import { socketPath } from '../socket-path.js';
2
+ import { createHash } from 'node:crypto';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
7
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
8
+ import { agentDir } from '../paths.js';
9
+ import { ROLE_NAME_RE } from '../config.js';
10
+ import { legacySupervisorIdentity } from './legacy-supervisor-identity.js';
11
+ import { FleetError } from './errors.js';
12
+ /** CLI and REST use the same fixed-identity MCP server as the agent harness. */
13
+ export class SupervisorOursTools {
14
+ async withClient(role, work) {
15
+ if (!ROLE_NAME_RE.test(role))
16
+ throw new FleetError('invalid_request', 'invalid agent name');
17
+ const findCandidates = () => [false, true].map(temporary => ({ temporary, dir: agentDir(role, temporary) }))
18
+ .map(row => ({ ...row, path: join(row.dir, '.ours-bridge', 'descriptor.json') }))
19
+ .filter(row => existsSync(row.path));
20
+ const candidates = findCandidates();
21
+ if (candidates.length !== 1)
22
+ throw new FleetError('capability_unavailable', 'agent supervisor endpoint is missing or ambiguous');
23
+ const selected = candidates[0];
24
+ let descriptor;
25
+ let identityName;
26
+ try {
27
+ descriptor = JSON.parse(readFileSync(selected.path, 'utf8'));
28
+ identityName = readFileSync(join(selected.dir, '.identity'), 'utf8').trim();
29
+ if (!descriptor || typeof descriptor !== 'object')
30
+ throw new Error();
31
+ }
32
+ catch {
33
+ throw new FleetError('capability_unavailable', 'supervisor identity metadata cannot be read');
34
+ }
35
+ const legacy = ['role', 'identity', 'cid'].every(key => descriptor[key] === undefined);
36
+ const identity = legacy
37
+ ? legacySupervisorIdentity(role, identityName, selected.temporary, descriptor.generation)
38
+ : { name: identityName, cid: descriptor.cid, generation: descriptor.generation };
39
+ const legacySocket = join(selected.dir, '.ours-bridge', `g${descriptor.generation}.sock`);
40
+ if (legacy && descriptor.socket !== legacySocket && descriptor.socket !== socketPath(legacySocket))
41
+ throw new FleetError('capability_unavailable', 'legacy supervisor socket does not match the selected agent');
42
+ if ((!legacy && (descriptor.role !== role || descriptor.identity !== identityName))
43
+ || !/^[a-f0-9]{64}$/i.test(identity.cid ?? '') || !Number.isSafeInteger(descriptor.generation) || descriptor.generation < 1)
44
+ throw new FleetError('capability_unavailable', 'supervisor identity metadata is unavailable or mismatched');
45
+ const verifySelection = () => {
46
+ try {
47
+ const current = findCandidates();
48
+ const freshDescriptor = JSON.parse(readFileSync(selected.path, 'utf8'));
49
+ if (current.length !== 1 || current[0].path !== selected.path
50
+ || readFileSync(join(selected.dir, '.identity'), 'utf8').trim() !== identityName
51
+ || ['role', 'identity', 'cid', 'socket', 'capability', 'generation']
52
+ .some(key => freshDescriptor[key] !== descriptor[key]))
53
+ throw new Error();
54
+ }
55
+ catch {
56
+ throw new FleetError('capability_unavailable', 'selected supervisor assignment changed');
57
+ }
58
+ };
59
+ const client = new Client({ name: 'ours-fleet-supervisor-tools', version: '1' });
60
+ const transport = new StdioClientTransport({
61
+ command: process.execPath,
62
+ args: [fileURLToPath(new URL('../agent-ours/bridge.js', import.meta.url))],
63
+ env: { ...Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined)),
64
+ FLEET_OURS_BRIDGE_DESCRIPTOR: selected.path,
65
+ FLEET_OURS_BRIDGE_EXPECTED: JSON.stringify({ role: descriptor.role, identity: descriptor.identity, cid: descriptor.cid, generation: descriptor.generation,
66
+ transportDigest: createHash('sha256').update(JSON.stringify([descriptor.socket, descriptor.capability, descriptor.generation])).digest('hex') }) },
67
+ stderr: 'pipe',
68
+ });
69
+ try {
70
+ await client.connect(transport);
71
+ const verify = async () => {
72
+ if (!legacy) {
73
+ verifySelection();
74
+ return;
75
+ }
76
+ // The supervisor owns the binding. The authenticated bridge and pinned local
77
+ // assignment are authoritative; current_identity is display text, not a protocol.
78
+ const fresh = legacySupervisorIdentity(role, identityName, selected.temporary, descriptor.generation);
79
+ if (!('proof' in identity) || fresh.proof !== identity.proof)
80
+ throw new FleetError('capability_unavailable', 'legacy supervisor identity changed');
81
+ verifySelection();
82
+ };
83
+ await verify();
84
+ return await work(client, { name: identity.name, cid: identity.cid, generation: identity.generation }, verify);
85
+ }
86
+ catch (error) {
87
+ if (error instanceof FleetError)
88
+ throw error;
89
+ // Do not leak arguments, invites, capabilities, or raw transport errors.
90
+ throw new FleetError('control_unavailable', 'supervisor tool request failed; its outcome may be unknown, do not retry a mutation automatically', { retryable: false });
91
+ }
92
+ finally {
93
+ await client.close().catch(() => { });
94
+ await transport.close().catch(() => { });
95
+ }
96
+ }
97
+ list(role) {
98
+ return this.withClient(role, async (client, identity) => ({
99
+ agent: role, identity, ...(await client.listTools()),
100
+ }));
101
+ }
102
+ call(role, request) {
103
+ if (!request || typeof request.tool !== 'string'
104
+ || (request.arguments !== undefined && (!request.arguments || typeof request.arguments !== 'object' || Array.isArray(request.arguments))))
105
+ throw new FleetError('invalid_request', 'tool and object arguments are required');
106
+ return this.withClient(role, async (client, identity, verify) => {
107
+ const { tools } = await client.listTools();
108
+ if (!tools.some(tool => tool.name === request.tool))
109
+ throw new FleetError('forbidden', 'tool is not exposed by the fixed-identity supervisor');
110
+ await verify();
111
+ const result = await client.callTool({ name: request.tool, arguments: request.arguments ?? {} });
112
+ return { agent: role, identity, result };
113
+ });
114
+ }
115
+ }