@ours.network/fleet 1.2.0-nightly.3 → 1.2.0-nightly.31

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 (458) hide show
  1. package/README.md +158 -28
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.d.ts +3 -0
  5. package/dist/agent-ours/bridge.js +178 -0
  6. package/dist/agent-ours/controller.d.ts +14 -0
  7. package/dist/agent-ours/controller.js +60 -0
  8. package/dist/agent-ours/correspondence.d.ts +10 -0
  9. package/dist/agent-ours/correspondence.js +1 -0
  10. package/dist/agent-ours/file-rpc.d.ts +23 -0
  11. package/dist/agent-ours/file-rpc.js +123 -0
  12. package/dist/agent-ours/harness.d.ts +14 -0
  13. package/dist/agent-ours/harness.js +72 -0
  14. package/dist/agent-ours/mcp-endpoint.d.ts +15 -0
  15. package/dist/agent-ours/mcp-endpoint.js +111 -0
  16. package/dist/agent-ours/runtime.d.ts +59 -0
  17. package/dist/agent-ours/runtime.js +283 -0
  18. package/dist/agent-ours/service.d.ts +23 -0
  19. package/dist/agent-ours/service.js +372 -0
  20. package/dist/agent-ours/state.d.ts +45 -0
  21. package/dist/agent-ours/state.js +95 -0
  22. package/dist/agent-ours/wire.d.ts +14 -0
  23. package/dist/agent-ours/wire.js +55 -0
  24. package/dist/application/conversation-history.d.ts +25 -0
  25. package/dist/application/conversation-history.js +189 -0
  26. package/dist/application/fleet-query-service.d.ts +1 -1
  27. package/dist/application/fleet-query-service.js +2 -2
  28. package/dist/application/legacy-supervisor-identity.d.ts +7 -0
  29. package/dist/application/legacy-supervisor-identity.js +43 -0
  30. package/dist/application/model-catalog.d.ts +1 -1
  31. package/dist/application/model-catalog.js +5 -2
  32. package/dist/application/preset-provenance.d.ts +19 -0
  33. package/dist/application/preset-provenance.js +59 -0
  34. package/dist/application/room-layout-definitions.d.ts +45 -0
  35. package/dist/application/room-layout-definitions.js +130 -0
  36. package/dist/application/session-control.d.ts +18 -0
  37. package/dist/application/session-control.js +54 -3
  38. package/dist/application/supervisor-ours-tools.d.ts +159 -0
  39. package/dist/application/supervisor-ours-tools.js +113 -0
  40. package/dist/application/task-layouts.d.ts +91 -0
  41. package/dist/application/task-layouts.js +249 -0
  42. package/dist/application/task-room-service.d.ts +99 -3
  43. package/dist/application/task-room-service.js +296 -31
  44. package/dist/atomic-file.d.ts +5 -0
  45. package/dist/atomic-file.js +62 -1
  46. package/dist/briefing.js +10 -59
  47. package/dist/build-info.json +6 -4
  48. package/dist/capabilities.d.ts +3 -1
  49. package/dist/capabilities.js +4 -0
  50. package/dist/cli.js +131 -5
  51. package/dist/client-profile.d.ts +5 -16
  52. package/dist/client-profile.js +4 -112
  53. package/dist/config.d.ts +4 -0
  54. package/dist/config.js +7 -0
  55. package/dist/creation.d.ts +1 -1
  56. package/dist/creation.js +5 -16
  57. package/dist/daemon-recovery.d.ts +1 -8
  58. package/dist/daemon-recovery.js +8 -113
  59. package/dist/docs.d.ts +3 -3
  60. package/dist/docs.js +43 -23
  61. package/dist/doctor.d.ts +1 -1
  62. package/dist/doctor.js +46 -59
  63. package/dist/erased-resources.d.ts +9 -0
  64. package/dist/erased-resources.js +87 -0
  65. package/dist/fleet-command-audit.d.ts +1 -0
  66. package/dist/fleet-command-audit.js +12 -7
  67. package/dist/harness/agent-session.d.ts +2 -0
  68. package/dist/harness/claude-code-session.js +4 -2
  69. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  70. package/dist/harness/codex-app-server-proxy.js +41 -5
  71. package/dist/harness/codex-session.js +9 -2
  72. package/dist/harness/codex.d.ts +3 -2
  73. package/dist/harness/codex.js +4 -3
  74. package/dist/harness/hermes-session.js +7 -1
  75. package/dist/init-wizard.js +20 -9
  76. package/dist/isolation/policy.js +2 -0
  77. package/dist/isolation/types.d.ts +5 -0
  78. package/dist/monitor.d.ts +1 -34
  79. package/dist/monitor.js +24 -151
  80. package/dist/notifications/fleet-producer.d.ts +18 -0
  81. package/dist/notifications/fleet-producer.js +129 -0
  82. package/dist/notifications/outbox.d.ts +31 -0
  83. package/dist/notifications/outbox.js +104 -0
  84. package/dist/owner-channel/channel.d.ts +3 -0
  85. package/dist/owner-channel/channel.js +34 -6
  86. package/dist/owner-channel/commands.d.ts +4 -0
  87. package/dist/owner-channel/commands.js +8 -0
  88. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  89. package/dist/owner-channel/ours-client.js +2 -17
  90. package/dist/preset-migration.js +15 -0
  91. package/dist/rooms-tasks/add-member.d.ts +48 -0
  92. package/dist/rooms-tasks/add-member.js +83 -0
  93. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  94. package/dist/rooms-tasks/archived-absence.js +48 -0
  95. package/dist/rooms-tasks/cli.js +34 -5
  96. package/dist/rooms-tasks/close.d.ts +5 -2
  97. package/dist/rooms-tasks/close.js +208 -28
  98. package/dist/rooms-tasks/config.js +3 -1
  99. package/dist/rooms-tasks/cowork-adapter.d.ts +6 -4
  100. package/dist/rooms-tasks/cowork-adapter.js +11 -117
  101. package/dist/rooms-tasks/cowork-http.d.ts +3 -0
  102. package/dist/rooms-tasks/cowork-http.js +70 -0
  103. package/dist/rooms-tasks/deletion.d.ts +1 -1
  104. package/dist/rooms-tasks/deletion.js +74 -5
  105. package/dist/rooms-tasks/erasure.d.ts +6 -0
  106. package/dist/rooms-tasks/erasure.js +169 -0
  107. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  108. package/dist/rooms-tasks/external-worker.js +3 -4
  109. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  110. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  111. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  112. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  113. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  114. package/dist/rooms-tasks/layout-cli.js +107 -0
  115. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  116. package/dist/rooms-tasks/layout-config.js +89 -0
  117. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  118. package/dist/rooms-tasks/layout-control.js +52 -0
  119. package/dist/rooms-tasks/layout-service.d.ts +42 -0
  120. package/dist/rooms-tasks/layout-service.js +185 -0
  121. package/dist/rooms-tasks/layout.d.ts +114 -0
  122. package/dist/rooms-tasks/layout.js +250 -0
  123. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  124. package/dist/rooms-tasks/live-readiness.js +85 -0
  125. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  126. package/dist/rooms-tasks/member-startup.js +2 -0
  127. package/dist/rooms-tasks/provision.d.ts +14 -0
  128. package/dist/rooms-tasks/provision.js +182 -48
  129. package/dist/rooms-tasks/room-state.d.ts +4 -2
  130. package/dist/rooms-tasks/room-state.js +53 -8
  131. package/dist/rooms-tasks/task-state.d.ts +42 -7
  132. package/dist/rooms-tasks/task-state.js +153 -23
  133. package/dist/rooms-tasks/types.d.ts +28 -0
  134. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  135. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  136. package/dist/rooms-tasks/workspace.d.ts +26 -0
  137. package/dist/rooms-tasks/workspace.js +195 -0
  138. package/dist/runner.d.ts +23 -3
  139. package/dist/runner.js +581 -494
  140. package/dist/session/acp.d.ts +3 -0
  141. package/dist/session/acp.js +14 -0
  142. package/dist/session/arbiter.d.ts +3 -0
  143. package/dist/session/arbiter.js +20 -2
  144. package/dist/session/codex-app-server-transport.js +1 -1
  145. package/dist/session/codex-app-server.d.ts +3 -0
  146. package/dist/session/codex-app-server.js +25 -1
  147. package/dist/session/control.d.ts +10 -1
  148. package/dist/session/control.js +37 -2
  149. package/dist/session/conversation-normalizer.d.ts +2 -1
  150. package/dist/session/conversation-normalizer.js +1 -1
  151. package/dist/session/conversation-types.d.ts +5 -3
  152. package/dist/session/task-notice.d.ts +14 -0
  153. package/dist/session/task-notice.js +13 -0
  154. package/dist/session/types.d.ts +3 -0
  155. package/dist/socket-path.d.ts +2 -0
  156. package/dist/socket-path.js +22 -0
  157. package/dist/spawn.js +19 -16
  158. package/dist/startup-readiness.d.ts +13 -0
  159. package/dist/startup-readiness.js +38 -0
  160. package/dist/subscriptions/cli.d.ts +78 -0
  161. package/dist/subscriptions/cli.js +186 -0
  162. package/dist/subscriptions/launch.d.ts +37 -0
  163. package/dist/subscriptions/launch.js +93 -0
  164. package/dist/subscriptions/login.d.ts +75 -0
  165. package/dist/subscriptions/login.js +182 -0
  166. package/dist/subscriptions/observed.d.ts +7 -0
  167. package/dist/subscriptions/observed.js +44 -0
  168. package/dist/subscriptions/probe.d.ts +10 -0
  169. package/dist/subscriptions/probe.js +73 -0
  170. package/dist/subscriptions/service.d.ts +102 -0
  171. package/dist/subscriptions/service.js +364 -0
  172. package/dist/subscriptions/store.d.ts +71 -0
  173. package/dist/subscriptions/store.js +140 -0
  174. package/dist/supervisor/launchd.js +2 -1
  175. package/dist/supervisor/systemd.js +9 -23
  176. package/dist/temp-idle.d.ts +17 -0
  177. package/dist/temp-idle.js +42 -0
  178. package/dist/temp-lifecycle.d.ts +6 -1
  179. package/dist/temp-lifecycle.js +29 -13
  180. package/dist/temp-supervisor-recovery.d.ts +3 -0
  181. package/dist/temp-supervisor-recovery.js +46 -0
  182. package/dist/watchdog/briefing.js +3 -16
  183. package/dist/watchdog/run.js +19 -5
  184. package/dist/web/agent-attachments.d.ts +29 -0
  185. package/dist/web/agent-attachments.js +162 -0
  186. package/dist/web/auth.d.ts +28 -2
  187. package/dist/web/auth.js +81 -8
  188. package/dist/web/available-port.d.ts +2 -0
  189. package/dist/web/available-port.js +23 -0
  190. package/dist/web/control.d.ts +3 -2
  191. package/dist/web/control.js +11 -7
  192. package/dist/web/fleet-config-service.d.ts +4 -1
  193. package/dist/web/fleet-config-service.js +46 -15
  194. package/dist/web/prefix-gateway.d.ts +23 -0
  195. package/dist/web/prefix-gateway.js +156 -0
  196. package/dist/web/runtime.d.ts +4 -0
  197. package/dist/web/runtime.js +106 -20
  198. package/dist/web/server.d.ts +11 -0
  199. package/dist/web/server.js +445 -31
  200. package/dist/web/service.d.ts +11 -2
  201. package/dist/web/service.js +30 -4
  202. package/dist/web/workspace-devices.d.ts +29 -0
  203. package/dist/web/workspace-devices.js +84 -0
  204. package/dist/web/workspace-tunnel.d.ts +1 -0
  205. package/dist/web/workspace-tunnel.js +32 -0
  206. package/dist/web-app/assets/FleetApp-D58F4xje.css +1 -0
  207. package/dist/web-app/assets/FleetApp-DP5cBY0o.js +302 -0
  208. package/dist/web-app/assets/FleetApp-DP5cBY0o.js.map +1 -0
  209. package/dist/web-app/assets/abnfDiagram-VCTEODGH-BvJIz7wN.js +2 -0
  210. package/dist/web-app/assets/abnfDiagram-VCTEODGH-BvJIz7wN.js.map +1 -0
  211. package/dist/web-app/assets/arc-AT_BEfpe.js +2 -0
  212. package/dist/web-app/assets/arc-AT_BEfpe.js.map +1 -0
  213. package/dist/web-app/assets/architectureDiagram-5GKGNRK7-vSgJa9Xb.js +37 -0
  214. package/dist/web-app/assets/architectureDiagram-5GKGNRK7-vSgJa9Xb.js.map +1 -0
  215. package/dist/web-app/assets/blockDiagram-I7D4REHJ-DCFk_4Kv.js +130 -0
  216. package/dist/web-app/assets/blockDiagram-I7D4REHJ-DCFk_4Kv.js.map +1 -0
  217. package/dist/web-app/assets/browser-CMIwJ_8L.js +9 -0
  218. package/dist/web-app/assets/browser-CMIwJ_8L.js.map +1 -0
  219. package/dist/web-app/assets/c4Diagram-7LVT6UL2-8J_dVUtF.js +39 -0
  220. package/dist/web-app/assets/c4Diagram-7LVT6UL2-8J_dVUtF.js.map +1 -0
  221. package/dist/web-app/assets/channel-BHCBlfND.js +2 -0
  222. package/dist/web-app/assets/channel-BHCBlfND.js.map +1 -0
  223. package/dist/web-app/assets/chunk-2Q5K7J3B-31RX-jnL.js +2 -0
  224. package/dist/web-app/assets/chunk-2Q5K7J3B-31RX-jnL.js.map +1 -0
  225. package/dist/web-app/assets/chunk-5VM5RSS4-CFF8_ZJH.js +16 -0
  226. package/dist/web-app/assets/chunk-5VM5RSS4-CFF8_ZJH.js.map +1 -0
  227. package/dist/web-app/assets/chunk-F27PBJKO-Dx1l5wLI.js +2 -0
  228. package/dist/web-app/assets/chunk-F27PBJKO-Dx1l5wLI.js.map +1 -0
  229. package/dist/web-app/assets/chunk-IMKFNOWR-Ba2_9bl_.js +232 -0
  230. package/dist/web-app/assets/chunk-IMKFNOWR-Ba2_9bl_.js.map +1 -0
  231. package/dist/web-app/assets/chunk-JWPE2WC7-_mnRB2OH.js +2 -0
  232. package/dist/web-app/assets/chunk-JWPE2WC7-_mnRB2OH.js.map +1 -0
  233. package/dist/web-app/assets/chunk-POPQ4Y6H-B8jQTxQO.js +2 -0
  234. package/dist/web-app/assets/chunk-POPQ4Y6H-B8jQTxQO.js.map +1 -0
  235. package/dist/web-app/assets/chunk-SVP7TREG-BO_Jnb_c.js +89 -0
  236. package/dist/web-app/assets/chunk-SVP7TREG-BO_Jnb_c.js.map +1 -0
  237. package/dist/web-app/assets/chunk-TICWLB2K-ZYZ9hFu5.js +207 -0
  238. package/dist/web-app/assets/chunk-TICWLB2K-ZYZ9hFu5.js.map +1 -0
  239. package/dist/web-app/assets/chunk-XXDRQBXY-ByUAYXI3.js +2 -0
  240. package/dist/web-app/assets/chunk-XXDRQBXY-ByUAYXI3.js.map +1 -0
  241. package/dist/web-app/assets/classDiagram-ZZMXUADV-Ddx7RAuT.js +2 -0
  242. package/dist/web-app/assets/classDiagram-ZZMXUADV-Ddx7RAuT.js.map +1 -0
  243. package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-Ddx7RAuT.js +2 -0
  244. package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-Ddx7RAuT.js.map +1 -0
  245. package/dist/web-app/assets/cose-bilkent-JH36ORCC-BuOGJgHG.js +2 -0
  246. package/dist/web-app/assets/cose-bilkent-JH36ORCC-BuOGJgHG.js.map +1 -0
  247. package/dist/web-app/assets/cynefin-OW5HDTMX-DLksGPh8.js +179 -0
  248. package/dist/web-app/assets/cynefin-OW5HDTMX-DLksGPh8.js.map +1 -0
  249. package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-nJQb5qZR.js +63 -0
  250. package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-nJQb5qZR.js.map +1 -0
  251. package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js +332 -0
  252. package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js.map +1 -0
  253. package/dist/web-app/assets/dagre-GXQ25YYZ-CCF5O_UD.js +5 -0
  254. package/dist/web-app/assets/dagre-GXQ25YYZ-CCF5O_UD.js.map +1 -0
  255. package/dist/web-app/assets/defaultLocale-DX6XiGOO.js +2 -0
  256. package/dist/web-app/assets/defaultLocale-DX6XiGOO.js.map +1 -0
  257. package/dist/web-app/assets/diagram-S7CK7UJ4-C88au4NC.js +31 -0
  258. package/dist/web-app/assets/diagram-S7CK7UJ4-C88au4NC.js.map +1 -0
  259. package/dist/web-app/assets/diagram-UQ7AKVKN-B4QnPs7U.js +42 -0
  260. package/dist/web-app/assets/diagram-UQ7AKVKN-B4QnPs7U.js.map +1 -0
  261. package/dist/web-app/assets/diagram-VSXAHHWV-DeANdVWA.js +4 -0
  262. package/dist/web-app/assets/diagram-VSXAHHWV-DeANdVWA.js.map +1 -0
  263. package/dist/web-app/assets/diagram-VX7I27RA-YzlB_2AY.js +25 -0
  264. package/dist/web-app/assets/diagram-VX7I27RA-YzlB_2AY.js.map +1 -0
  265. package/dist/web-app/assets/diagram-Z3DM3KII-YY9NFaz_.js +25 -0
  266. package/dist/web-app/assets/diagram-Z3DM3KII-YY9NFaz_.js.map +1 -0
  267. package/dist/web-app/assets/ebnfDiagram-PWID7BFC-Cqu9kHUC.js +2 -0
  268. package/dist/web-app/assets/ebnfDiagram-PWID7BFC-Cqu9kHUC.js.map +1 -0
  269. package/dist/web-app/assets/erDiagram-RLTQ6QDP-IHi93MdG.js +100 -0
  270. package/dist/web-app/assets/erDiagram-RLTQ6QDP-IHi93MdG.js.map +1 -0
  271. package/dist/web-app/assets/flowDiagram-HODETNUW-19bm7W5P.js +169 -0
  272. package/dist/web-app/assets/flowDiagram-HODETNUW-19bm7W5P.js.map +1 -0
  273. package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-BvCqvyiB.js +293 -0
  274. package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-BvCqvyiB.js.map +1 -0
  275. package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-G4Ubl8Fs.js +107 -0
  276. package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-G4Ubl8Fs.js.map +1 -0
  277. package/dist/web-app/assets/index-C4BdeFB9.css +1 -0
  278. package/dist/web-app/assets/index-Dtn3ZY6J.js +430 -0
  279. package/dist/web-app/assets/index-Dtn3ZY6J.js.map +1 -0
  280. package/dist/web-app/assets/infoDiagram-27XIBGKW-B6rtfbuC.js +3 -0
  281. package/dist/web-app/assets/infoDiagram-27XIBGKW-B6rtfbuC.js.map +1 -0
  282. package/dist/web-app/assets/init-Gi6I4Gst.js +2 -0
  283. package/dist/web-app/assets/init-Gi6I4Gst.js.map +1 -0
  284. package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-Lp8q1D21.js +71 -0
  285. package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-Lp8q1D21.js.map +1 -0
  286. package/dist/web-app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  287. package/dist/web-app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  288. package/dist/web-app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  289. package/dist/web-app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  290. package/dist/web-app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  291. package/dist/web-app/assets/journeyDiagram-3NMN7TZE-Av03B9l3.js +140 -0
  292. package/dist/web-app/assets/journeyDiagram-3NMN7TZE-Av03B9l3.js.map +1 -0
  293. package/dist/web-app/assets/kanban-definition-UXKFOSKX-Ddd3_ejb.js +90 -0
  294. package/dist/web-app/assets/kanban-definition-UXKFOSKX-Ddd3_ejb.js.map +1 -0
  295. package/dist/web-app/assets/katex-HP8lGamR.js +258 -0
  296. package/dist/web-app/assets/katex-HP8lGamR.js.map +1 -0
  297. package/dist/web-app/assets/layout-CNjBeOlp.js +2 -0
  298. package/dist/web-app/assets/layout-CNjBeOlp.js.map +1 -0
  299. package/dist/web-app/assets/linear-DDONU9Ir.js +2 -0
  300. package/dist/web-app/assets/linear-DDONU9Ir.js.map +1 -0
  301. package/dist/web-app/assets/mermaid.core-B9X3C61k.js +313 -0
  302. package/dist/web-app/assets/mermaid.core-B9X3C61k.js.map +1 -0
  303. package/dist/web-app/assets/mindmap-definition-YA3MSWOX-I2UME2Ce.js +97 -0
  304. package/dist/web-app/assets/mindmap-definition-YA3MSWOX-I2UME2Ce.js.map +1 -0
  305. package/dist/web-app/assets/ordinal-Cboi1Yqb.js +2 -0
  306. package/dist/web-app/assets/ordinal-Cboi1Yqb.js.map +1 -0
  307. package/dist/web-app/assets/pegDiagram-XKGWAZYB-BER8lNbi.js +2 -0
  308. package/dist/web-app/assets/pegDiagram-XKGWAZYB-BER8lNbi.js.map +1 -0
  309. package/dist/web-app/assets/pieDiagram-E7YTZNPT-FVWVg8rH.js +40 -0
  310. package/dist/web-app/assets/pieDiagram-E7YTZNPT-FVWVg8rH.js.map +1 -0
  311. package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-YlvT1u77.js +8 -0
  312. package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-YlvT1u77.js.map +1 -0
  313. package/dist/web-app/assets/railroadDiagram-O6MQD6OU-CvxT6dMW.js +2 -0
  314. package/dist/web-app/assets/railroadDiagram-O6MQD6OU-CvxT6dMW.js.map +1 -0
  315. package/dist/web-app/assets/requirementDiagram-BXWQKSXE-Caav4EkP.js +85 -0
  316. package/dist/web-app/assets/requirementDiagram-BXWQKSXE-Caav4EkP.js.map +1 -0
  317. package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-B5Uw70Gn.js +41 -0
  318. package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-B5Uw70Gn.js.map +1 -0
  319. package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-D2SLKVJl.js +163 -0
  320. package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-D2SLKVJl.js.map +1 -0
  321. package/dist/web-app/assets/sizeCapture-INFHLROL-BVaBfbwa.js +2 -0
  322. package/dist/web-app/assets/sizeCapture-INFHLROL-BVaBfbwa.js.map +1 -0
  323. package/dist/web-app/assets/stateDiagram-D77RDMKH-BlV9y2tf.js +2 -0
  324. package/dist/web-app/assets/stateDiagram-D77RDMKH-BlV9y2tf.js.map +1 -0
  325. package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-BU4Tu2pp.js +2 -0
  326. package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-BU4Tu2pp.js.map +1 -0
  327. package/dist/web-app/assets/swimlanes-42K2YHIH-Pv3Wv8c7.js +2 -0
  328. package/dist/web-app/assets/swimlanes-42K2YHIH-Pv3Wv8c7.js.map +1 -0
  329. package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-BNKjOvPH.js +9 -0
  330. package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-BNKjOvPH.js.map +1 -0
  331. package/dist/web-app/assets/timeline-definition-24CTP7MA-C9TOilaR.js +121 -0
  332. package/dist/web-app/assets/timeline-definition-24CTP7MA-C9TOilaR.js.map +1 -0
  333. package/dist/web-app/assets/vennDiagram-4TSXK5OY-DeSDprN4.js +35 -0
  334. package/dist/web-app/assets/vennDiagram-4TSXK5OY-DeSDprN4.js.map +1 -0
  335. package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-SulZn-nm.js +79 -0
  336. package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-SulZn-nm.js.map +1 -0
  337. package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-CC6MrQ0h.js +8 -0
  338. package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-CC6MrQ0h.js.map +1 -0
  339. package/dist/web-app/fleet-index.html +19 -0
  340. package/dist/web-app/fleet.webmanifest +37 -0
  341. package/dist/web-app/icons/apple-touch-icon.png +0 -0
  342. package/dist/web-app/icons/favicon-16.png +0 -0
  343. package/dist/web-app/icons/favicon-32.png +0 -0
  344. package/dist/web-app/icons/icon-192-maskable.png +0 -0
  345. package/dist/web-app/icons/icon-192.png +0 -0
  346. package/dist/web-app/icons/icon-512-maskable.png +0 -0
  347. package/dist/web-app/icons/icon-512.png +0 -0
  348. package/dist/web-app/index.html +9 -7
  349. package/dist/web-app/manifest.webmanifest +10 -8
  350. package/dist/web-app/sw.js +210 -40
  351. package/dist/web-app/version.json +1 -0
  352. package/dist/web-app/workspace-install.sh +148 -0
  353. package/dist/workspace-enrollment.d.ts +28 -0
  354. package/dist/workspace-enrollment.js +129 -0
  355. package/docs/room-layouts.md +227 -0
  356. package/docs/task-workspaces.md +130 -0
  357. package/examples/room-layouts/fresh.yaml +27 -0
  358. package/examples/room-layouts/scoped.yaml +21 -0
  359. package/examples/room-layouts/shared.yaml +19 -0
  360. package/package.json +14 -17
  361. package/presets/README.md +78 -0
  362. package/presets/brain-catalog.json +8 -2
  363. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  364. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  365. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  366. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  367. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  368. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  369. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  370. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  371. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  372. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  373. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  374. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  375. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  376. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  377. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  378. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  379. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  380. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  381. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  382. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  383. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  384. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  385. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  386. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  387. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  388. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  389. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  390. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  391. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  392. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  393. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  394. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  395. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  396. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  397. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  398. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  399. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  400. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  401. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  402. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  403. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  404. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  405. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  406. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  407. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  408. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  409. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  410. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  411. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  412. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  413. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  414. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  415. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  416. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  417. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  418. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  419. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  420. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  421. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  422. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  423. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  424. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  425. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  426. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  427. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  428. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  429. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  430. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  431. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  432. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  433. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  434. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  435. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  436. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  437. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  438. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  439. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  440. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  441. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  442. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  443. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  444. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  445. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  446. package/presets/fleet/roles/Coordinator.yaml +22 -0
  447. package/presets/fleet/roles/Engineer.yaml +40 -0
  448. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  449. package/presets/fleet/room_layouts/pair.yaml +24 -0
  450. package/presets/fleet/room_layouts/single.yaml +17 -0
  451. package/presets/fleet/room_layouts/team.yaml +30 -0
  452. package/presets/fleet/room_templates/engineering.yaml +19 -0
  453. package/presets/manifest.json +2 -2
  454. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  455. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  456. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  457. package/dist/web-app/icons/ours-fleet.svg +0 -4
  458. package/dist/web-app/offline.html +0 -18
@@ -1,13 +1,17 @@
1
+ import { eraseMemberArtifacts } from './erasure.js';
2
+ import { proveArchivedAbsence, verifyArchivedAbsence, verifyArchivedMemberStillAbsent } from './archived-absence.js';
1
3
  import { existsSync } from 'node:fs';
2
4
  import { withFileLock } from '../atomic-file.js';
3
5
  import { agentDir } from '../paths.js';
6
+ import { deleteWorkspace, assertWorkspaceDeletable } from './workspace.js';
7
+ import { collectWorkspaceArchives } from './workspace-artifacts.js';
4
8
  import { secureStoppedTempArchive, stopTempSupervisor } from '../temp-lifecycle.js';
5
- import { closeManagedRoom, identityCidPresent, inspectMember, removeExactMemberIdentity, waitForLivenessAbsent, } from './close.js';
9
+ import { closeManagedRoom, identityCidPresent, inspectMember, assertMemberIdentityAbsent, removeExactMemberIdentity, waitForLivenessAbsent, } from './close.js';
6
10
  import { CoworkProtocolError } from './cowork-adapter.js';
7
11
  import { deleteRoomRecord, getRoomRecord, listRoomRecords } from './room-state.js';
8
12
  import { acquireLaunchSnapshotLock, releaseLaunchSnapshotForDeletingTask } from './launch-snapshot.js';
9
13
  import { TASK_OPERATION_LOCK_STALE_MS, taskOperationLockPath } from './terminal.js';
10
- import { advanceTaskDeletionMember, beginTaskDeletionIntent, completeTaskDeletionReceipt, ensureTaskDeletionReceipt, getDeletingTask, importTaskDeletionRetirementEvidence, setTaskDeletionError, TaskStateError, unlinkDeletedTask, upsertTaskDeletionMembersFromSeats, } from './task-state.js';
14
+ import { advanceTaskDeletionMember, settleAbsentTaskDeletionMember, beginTaskDeletionIntent, completeTaskDeletionReceipt, ensureTaskDeletionReceipt, getDeletingTask, importTaskDeletionRetirementEvidence, setTaskDeletionError, TaskStateError, beginTaskArchiveCleanup, unlinkDeletedTask, upsertTaskDeletionMembersFromSeats, } from './task-state.js';
11
15
  export { DELETION_MEMBER_ABSENT_VERIFIED } from './task-state.js';
12
16
  import { DELETION_MEMBER_ABSENT_VERIFIED } from './task-state.js';
13
17
  /**
@@ -40,6 +44,7 @@ function tolerantCowork(cowork) {
40
44
  }
41
45
  };
42
46
  return {
47
+ ...(cowork.getRoom ? { getRoom: cowork.getRoom.bind(cowork) } : {}),
43
48
  closeRoom: roomId => tolerate(() => cowork.closeRoom(roomId)),
44
49
  deleteRoom: roomId => tolerate(() => cowork.deleteRoom(roomId)),
45
50
  };
@@ -48,6 +53,7 @@ function cursorSeat(cursor) {
48
53
  return {
49
54
  role_name: cursor.name, identity_cid: cursor.identity_cid,
50
55
  slot: cursor.name, cowork_role: 'member', seat_state: 'active',
56
+ ...(cursor.launch_id ? { retirement: { phase: 'identity_absent', launch_id: cursor.launch_id, archive_path: cursor.archive_path, updated_at: cursor.updated_at } } : {}),
51
57
  };
52
58
  }
53
59
  /**
@@ -60,8 +66,15 @@ function cursorSeat(cursor) {
60
66
  async function retireCursorMember(taskId, cursor, deps) {
61
67
  let phase = cursor.phase;
62
68
  let launchId = cursor.launch_id;
63
- if (phase === 'identity_absent')
69
+ if (phase === 'identity_absent') {
70
+ if (!deps.roomClose?.inspectMember) {
71
+ if ((deps.hasTempState ?? (name => existsSync(agentDir(name, true))))(cursor.name))
72
+ throw new Error('Retired deletion member has replacement live state');
73
+ if (await (deps.identityCidPresent ?? identityCidPresent)(cursor.identity_cid))
74
+ throw new Error('Retired deletion member identity reappeared');
75
+ }
64
76
  return;
77
+ }
65
78
  const seat = cursorSeat(cursor);
66
79
  const roomClose = deps.roomClose ?? {};
67
80
  if (phase === 'pending') {
@@ -85,7 +98,16 @@ async function retireCursorMember(taskId, cursor, deps) {
85
98
  phase = 'stop_requested';
86
99
  launchId = ownership.launchId;
87
100
  }
101
+ if (!roomClose.inspectMember && !existsSync(agentDir(cursor.name, true))) {
102
+ await (roomClose.removeIdentity ?? removeExactMemberIdentity)(seat);
103
+ if (existsSync(agentDir(cursor.name, true)))
104
+ throw new Error('Deletion member acquired replacement state');
105
+ settleAbsentTaskDeletionMember(taskId, cursor.name);
106
+ return;
107
+ }
88
108
  if (phase === 'stop_requested') {
109
+ if (!roomClose.inspectMember && (await inspectMember(seat)).launchId !== launchId)
110
+ throw new Error('Deletion member launch changed before stop');
89
111
  await (roomClose.requestStop
90
112
  ?? (async (role) => { await stopTempSupervisor(role); }))(cursor.name);
91
113
  await (roomClose.waitForLivenessAbsent ?? waitForLivenessAbsent)(cursor.name, launchId);
@@ -145,10 +167,40 @@ export async function settleTaskDeletion(input) {
145
167
  upsertTaskDeletionMembersFromSeats(taskId, record.member_seats);
146
168
  await closeManagedRoom({ roomId: record.room_id, cowork: cowork, deps: deps.roomClose });
147
169
  const closed = getRoomRecord(record.room_id);
148
- importTaskDeletionRetirementEvidence(taskId, closed?.member_seats ?? record.member_seats);
170
+ const seats = closed?.member_seats ?? record.member_seats;
171
+ const proofs = [];
172
+ for (const seat of seats) {
173
+ if (!seat.identity_cid && !seat.retirement?.absence_verified && !['never-launched', 'absent-verified'].includes(seat.retirement?.launch_id ?? '')) {
174
+ const prior = task.deletion.archived_absences?.find(proof => proof.name === seat.role_name);
175
+ if (task.deletion.workspace_cleanup_started_at && prior && !existsSync(prior.archive_path)) {
176
+ await verifyArchivedMemberStillAbsent(prior);
177
+ proofs.push(prior);
178
+ }
179
+ else
180
+ proofs.push(await proveArchivedAbsence(seat));
181
+ }
182
+ }
183
+ // No await between the last live-state fence and durable checkpoint.
184
+ for (const proof of proofs) {
185
+ const latest = getRoomRecord(record.room_id)?.member_seats.find(seat => seat.role_name === proof.name);
186
+ if (existsSync(agentDir(proof.name, true)) || latest?.identity_cid
187
+ || latest?.launch?.launch_id !== proof.launch_id || latest.launch.action_id !== proof.action_id)
188
+ throw new Error('Archived absence seat changed before checkpoint');
189
+ }
190
+ importTaskDeletionRetirementEvidence(taskId, seats, proofs);
149
191
  await cowork.deleteRoom(record.room_id);
192
+ for (const proof of proofs)
193
+ await (task.deletion.workspace_cleanup_started_at && !existsSync(proof.archive_path) ? verifyArchivedMemberStillAbsent : verifyArchivedAbsence)(proof);
194
+ beginTaskArchiveCleanup(taskId);
195
+ await eraseMemberArtifacts('room', record.room_id, seats, [record.room_id]);
196
+ for (const proof of proofs)
197
+ if (existsSync(agentDir(proof.name, true)))
198
+ throw new Error('Archived member replacement before room unlink');
150
199
  deleteRoomRecord(record.room_id);
151
200
  }
201
+ const deletion = getDeletingTask(taskId).deletion;
202
+ for (const proof of deletion.archived_absences ?? [])
203
+ await (deletion.workspace_cleanup_started_at && !existsSync(proof.archive_path) ? verifyArchivedMemberStillAbsent : verifyArchivedAbsence)(proof);
152
204
  // Members whose room record is gone (crash after record deletion, or
153
205
  // legacy state): resume from the durable cursors.
154
206
  for (const cursor of getDeletingTask(taskId).deletion.members) {
@@ -176,7 +228,7 @@ export async function settleTaskDeletion(input) {
176
228
  completeTaskDeletionReceipt(taskId);
177
229
  return { task_id: taskId, deleted: false };
178
230
  }
179
- const finalize = () => withFileLock(taskOperationLockPath(taskId), () => {
231
+ const finalize = () => withFileLock(taskOperationLockPath(taskId), async () => {
180
232
  try {
181
233
  const task = getDeletingTask(taskId);
182
234
  if (task.deletion?.status !== 'pending')
@@ -185,8 +237,25 @@ export async function settleTaskDeletion(input) {
185
237
  throw new TaskStateError(`task ${taskId} room records reappeared during deletion finalization`);
186
238
  if (task.deletion.members.some(member => member.phase !== 'identity_absent'))
187
239
  throw new TaskStateError(`task ${taskId} has unretired members at deletion finalization`);
240
+ for (const proof of task.deletion.archived_absences ?? [])
241
+ await (task.deletion.workspace_cleanup_started_at && !existsSync(proof.archive_path) ? verifyArchivedMemberStillAbsent : verifyArchivedAbsence)(proof);
242
+ for (const proof of task.deletion.archived_absences ?? [])
243
+ if (existsSync(agentDir(proof.name, true)))
244
+ throw new Error('Archived member replacement before task unlink');
245
+ for (const name of task.deletion.absent_members ?? []) {
246
+ if (existsSync(agentDir(name, true)))
247
+ throw new Error('Absent member acquired replacement state');
248
+ await assertMemberIdentityAbsent({ role_name: name, slot: name, cowork_role: 'member', seat_state: 'removed' });
249
+ }
188
250
  if (cleanup.snapshotHash)
189
251
  releaseLaunchSnapshotForDeletingTask(cleanup.snapshotHash, taskId);
252
+ await eraseMemberArtifacts('task', taskId, task.deletion.members.map(cursorSeat), task.deletion.room_id ? [task.deletion.room_id] : []);
253
+ if (task.workspace) {
254
+ assertWorkspaceDeletable(task.workspace, 'task', taskId);
255
+ beginTaskArchiveCleanup(taskId);
256
+ collectWorkspaceArchives(task.workspace);
257
+ deleteWorkspace(task.workspace, 'task', taskId);
258
+ }
190
259
  unlinkDeletedTask(taskId);
191
260
  }
192
261
  catch (error) {
@@ -0,0 +1,6 @@
1
+ import type { RoomMemberSeat } from './types.js';
2
+ /** Erase only proven launch artifacts. Each atomic rename transfers ownership to
3
+ * a random, durable tombstone before recursive removal can destroy its proof.
4
+ * The caller holds the task/room lifecycle lock and has retired all writers.
5
+ */
6
+ export declare function eraseMemberArtifacts(owner: 'room' | 'task', id: string, seats: readonly RoomMemberSeat[], roomIds: readonly string[]): Promise<void>;
@@ -0,0 +1,169 @@
1
+ import { eraseResourcePresentations } from '../erased-resources.js';
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync } from 'node:fs';
3
+ import { createHash, randomUUID } from 'node:crypto';
4
+ import { dirname, join, relative } from 'node:path';
5
+ import { parse } from 'yaml';
6
+ import { replaceFileAtomically } from '../atomic-file.js';
7
+ import { agentDir, stateRoot } from '../paths.js';
8
+ import { readTempSupervisor, tempSupervisorLiveness, eraseTerminationEvents } from '../temp-lifecycle.js';
9
+ import { assertSafeAncestors, auditWorkspaceGit } from './workspace.js';
10
+ function entries(path) {
11
+ try {
12
+ return readdirSync(path);
13
+ }
14
+ catch (error) {
15
+ if (error.code === 'ENOENT')
16
+ return [];
17
+ throw error;
18
+ }
19
+ }
20
+ function json(path) {
21
+ try {
22
+ if (!lstatSync(path).isFile() || lstatSync(path).isSymbolicLink())
23
+ return undefined;
24
+ return JSON.parse(readFileSync(path, 'utf8'));
25
+ }
26
+ catch (error) {
27
+ if (error.code === 'ENOENT')
28
+ return undefined;
29
+ throw error;
30
+ }
31
+ }
32
+ function fingerprint(path) {
33
+ const stat = lstatSync(path);
34
+ const files = stat.isDirectory() ? ['creation.json', '.temp-supervisor.json', '.identity', 'role.yaml', 'state.json', 'instance.json'] : [''];
35
+ const hash = createHash('sha256');
36
+ for (const file of files) {
37
+ const target = file ? join(path, file) : path;
38
+ if (existsSync(target)) {
39
+ if (!lstatSync(target).isFile() || lstatSync(target).isSymbolicLink())
40
+ throw new Error('Unsafe erasure proof');
41
+ hash.update(file).update(readFileSync(target));
42
+ }
43
+ }
44
+ return hash.digest('hex');
45
+ }
46
+ /** Erase only proven launch artifacts. Each atomic rename transfers ownership to
47
+ * a random, durable tombstone before recursive removal can destroy its proof.
48
+ * The caller holds the task/room lifecycle lock and has retired all writers.
49
+ */
50
+ export async function eraseMemberArtifacts(owner, id, seats, roomIds) {
51
+ if (!/^[a-zA-Z0-9_-]{1,80}$/.test(id))
52
+ throw new Error('Invalid erasure owner');
53
+ const root = stateRoot();
54
+ const manifestPath = join(root, 'erasure', `${owner}-${id}.json`);
55
+ assertSafeAncestors(dirname(manifestPath));
56
+ let manifest = json(manifestPath);
57
+ const names = new Set(seats.map(s => s.role_name));
58
+ for (const name of names) {
59
+ if (!/^[a-zA-Z0-9_-]{1,120}$/.test(name))
60
+ throw new Error('Invalid erasure member');
61
+ if (existsSync(agentDir(name, true)))
62
+ throw new Error(`Member '${name}' still has live state during erasure`);
63
+ }
64
+ if (!manifest) {
65
+ const paths = [];
66
+ const launches = seats.flatMap(seat => {
67
+ const launchId = seat.launch?.launch_id ?? seat.retirement?.launch_id;
68
+ return launchId ? [{ role: seat.role_name, launchId }] : [];
69
+ });
70
+ const actions = new Map(seats.map(s => [s.role_name, new Set([s.launch?.action_id].filter((v) => !!v))]));
71
+ const recovery = join(root, 'recovery', 'temporary');
72
+ assertSafeAncestors(recovery);
73
+ for (const entry of entries(recovery)) {
74
+ const path = join(recovery, entry);
75
+ const stat = lstatSync(path);
76
+ if (!stat.isDirectory() || stat.isSymbolicLink())
77
+ continue;
78
+ const supervisor = readTempSupervisor(path);
79
+ if (!supervisor || !names.has(supervisor.role))
80
+ continue;
81
+ const seat = seats.find(s => s.role_name === supervisor.role);
82
+ const creation = json(join(path, 'creation.json'));
83
+ let room;
84
+ const roleFile = join(path, 'role.yaml');
85
+ if (existsSync(roleFile) && lstatSync(roleFile).isFile() && !lstatSync(roleFile).isSymbolicLink()) {
86
+ const role = parse(readFileSync(roleFile, 'utf8'));
87
+ if (role?.name === supervisor.role)
88
+ room = role.roomMemberStartup?.room_id;
89
+ }
90
+ const exactLaunch = seat.launch?.launch_id === supervisor.launchId || seat.retirement?.launch_id === supervisor.launchId;
91
+ const exactAction = creation?.role === supervisor.role && creation.creationActionId === seat.launch?.action_id;
92
+ // Older attempts belong only when the launch descriptor pins the room.
93
+ if (!(exactLaunch && (exactAction || !seat.launch?.action_id)) && !(room && roomIds.includes(room)))
94
+ continue;
95
+ if (existsSync(join(path, '.identity')) && readFileSync(join(path, '.identity'), 'utf8').trim() !== supervisor.role)
96
+ throw new Error('Archive identity mismatch during erasure');
97
+ if (await tempSupervisorLiveness(path) !== 'stopped')
98
+ throw new Error('Archive writer is not stopped');
99
+ if (creation?.role === supervisor.role && typeof creation.creationActionId === 'string')
100
+ actions.get(supervisor.role).add(creation.creationActionId);
101
+ auditWorkspaceGit(path);
102
+ launches.push({ role: supervisor.role, launchId: supervisor.launchId });
103
+ paths.push(path);
104
+ }
105
+ const privateRoot = join(root, 'private-ours');
106
+ assertSafeAncestors(privateRoot);
107
+ for (const entry of entries(privateRoot)) {
108
+ const path = join(privateRoot, entry);
109
+ if (!lstatSync(path).isDirectory() || lstatSync(path).isSymbolicLink())
110
+ continue;
111
+ if (entry === 'launches' || entry === 'room-inputs') {
112
+ for (const file of entries(path)) {
113
+ const child = join(path, file), value = json(child);
114
+ if (!value)
115
+ continue;
116
+ const launchOwned = entry === 'launches' && value.role === value.identity
117
+ && actions.get(value.role)?.has(value.action);
118
+ const roomOwned = entry === 'room-inputs' && roomIds.includes(value.room_id)
119
+ && names.has(value.identity_name);
120
+ const readyOwned = entry === 'room-inputs' && file.endsWith('.ready.json')
121
+ && roomIds.includes(value.room) && seats.some(seat => seat.invite_id === value.invite && (!seat.identity_cid || seat.identity_cid === value.cid));
122
+ if (launchOwned || roomOwned || readyOwned)
123
+ paths.push(child);
124
+ }
125
+ continue;
126
+ }
127
+ const state = json(join(path, 'state.json')), instance = json(join(path, 'instance.json'));
128
+ if (state?.lifetime === 'temporary' && actions.get(state.name)?.has(state.action)
129
+ && instance?.role === state.name && instance?.temporary === true && instance?.instance === state.instance) {
130
+ auditWorkspaceGit(path);
131
+ paths.push(path);
132
+ }
133
+ }
134
+ manifest = { launches, version: 1, token: randomUUID(), paths, phases: {}, stamps: Object.fromEntries(paths.map(path => {
135
+ const stat = lstatSync(path);
136
+ return [path, { dev: stat.dev, ino: stat.ino, proof: fingerprint(path) }];
137
+ })) };
138
+ mkdirSync(dirname(manifestPath), { recursive: true, mode: 0o700 });
139
+ replaceFileAtomically(manifestPath, JSON.stringify(manifest));
140
+ }
141
+ if (manifest.version !== 1 || !/^[a-f0-9-]{36}$/.test(manifest.token) || !Array.isArray(manifest.paths))
142
+ throw new Error('Invalid erasure manifest');
143
+ for (const path of manifest.paths) {
144
+ const rel = relative(root, path);
145
+ if (!rel.startsWith('recovery/temporary/') && !rel.startsWith('private-ours/'))
146
+ throw new Error('Invalid erasure artifact path');
147
+ if (rel.split('/').includes('..'))
148
+ throw new Error('Invalid erasure artifact traversal');
149
+ assertSafeAncestors(dirname(path));
150
+ const tombstone = `${path}.erasing-${manifest.token}`;
151
+ if (manifest.phases[path] === 'removed')
152
+ continue;
153
+ if (existsSync(path) && !existsSync(tombstone) && manifest.phases[path] !== 'renamed') {
154
+ const stat = lstatSync(path), stamp = manifest.stamps[path];
155
+ if (stat.isSymbolicLink() || !stamp || stamp.dev !== stat.dev || stamp.ino !== stat.ino || stamp.proof !== fingerprint(path))
156
+ throw new Error('Erasure source ownership changed');
157
+ renameSync(path, tombstone);
158
+ }
159
+ manifest.phases[path] = 'renamed';
160
+ replaceFileAtomically(manifestPath, JSON.stringify(manifest));
161
+ rmSync(tombstone, { recursive: true, force: true });
162
+ manifest.phases[path] = 'removed';
163
+ replaceFileAtomically(manifestPath, JSON.stringify(manifest));
164
+ }
165
+ eraseResourcePresentations([{ kind: owner, id }, ...roomIds.map(id => ({ kind: 'room', id })),
166
+ ...seats.map(seat => ({ kind: 'agent', id: seat.role_name }))]);
167
+ eraseTerminationEvents(manifest.launches);
168
+ rmSync(manifestPath, { force: true });
169
+ }
@@ -8,4 +8,4 @@ export declare function presentFleetWorkerLifecycle(presentations: FleetAuditPre
8
8
  sleep(ms: number): Promise<void>;
9
9
  }): Promise<void>;
10
10
  /** Launch a Fleet CLI operation outside the caller's supervisor/session lifecycle. */
11
- export declare function launchFleetWorker(args: string[], operation: string, configPath?: string): Promise<void>;
11
+ export declare function launchFleetWorker(args: string[], operation: string, configPath?: string, binPath?: string): Promise<void>;
@@ -9,8 +9,7 @@ const LIFECYCLE_ACCEPT_TIMEOUT_MS = 10 * 60_000;
9
9
  const LIFECYCLE_RETRY_MS = 250;
10
10
  export function fleetWorkerEnv(source = process.env) {
11
11
  const inheritedKeys = [
12
- 'HOME', 'PATH', 'XDG_RUNTIME_DIR', 'OURS_FLEET_HOME', 'OURS_CONFIG',
13
- 'OURS_PORT', 'OURS_STATE_DIR', 'OURS_API_TOKEN', 'OURS_COWORK_CONFIG',
12
+ 'HOME', 'PATH', 'XDG_RUNTIME_DIR', 'OURS_FLEET_HOME', 'OURS_FLEET_SOCKET_ROOT', 'OURS_CONFIG',
14
13
  ];
15
14
  const env = Object.fromEntries(inheritedKeys.flatMap(key => source[key] === undefined ? [] : [[key, source[key]]]));
16
15
  const lifecycleStateDir = source[FLEET_WORKER_LIFECYCLE_STATE_DIR_ENV]
@@ -52,8 +51,8 @@ export async function presentFleetWorkerLifecycle(presentations, deps = {
52
51
  }
53
52
  }
54
53
  /** Launch a Fleet CLI operation outside the caller's supervisor/session lifecycle. */
55
- export function launchFleetWorker(args, operation, configPath) {
56
- const cli = [process.argv[1], ...args, ...(configPath ? ['-c', configPath] : [])];
54
+ export function launchFleetWorker(args, operation, configPath, binPath = process.argv[1]) {
55
+ const cli = [binPath, ...args, ...(configPath ? ['-c', configPath] : [])];
57
56
  const env = fleetWorkerEnv();
58
57
  const inherited = Object.entries(env).map(([key, value]) => `${key}=${value}`);
59
58
  const suffix = randomUUID().slice(0, 8);
@@ -0,0 +1,11 @@
1
+ import type { LayoutInstance } from './layout.js';
2
+ import type { LayoutControlRequest } from './layout-control.js';
3
+ export type LayoutBindingRequest = Omit<LayoutControlRequest, 'instance'> & {
4
+ roomId?: string;
5
+ roomRole?: string;
6
+ };
7
+ export declare const LAYOUT_BINDING_ACTIONS: readonly ["verify", "join", "assign"];
8
+ export declare const localLayoutReference: ({ remote: _remote, ...instance }: LayoutInstance) => LayoutInstance;
9
+ /** Initial support is the same-host, separate-OS-user use case from #194. */
10
+ export declare function layoutBindingOrigin(raw: string): string;
11
+ export declare function callRemoteLayoutBinding(instance: LayoutInstance, request: LayoutBindingRequest, daemonInstanceId: string, fetchImpl?: typeof fetch): Promise<unknown>;
@@ -0,0 +1,56 @@
1
+ import { lstatSync, readFileSync } from 'node:fs';
2
+ import { isAbsolute } from 'node:path';
3
+ import { canonicalJson } from '../canonical-json.js';
4
+ export const LAYOUT_BINDING_ACTIONS = ['verify', 'join', 'assign'];
5
+ export const localLayoutReference = ({ remote: _remote, ...instance }) => instance;
6
+ /** Initial support is the same-host, separate-OS-user use case from #194. */
7
+ export function layoutBindingOrigin(raw) {
8
+ const url = new URL(raw);
9
+ if (url.protocol !== 'http:' || !['127.0.0.1'].includes(url.hostname)
10
+ || url.username || url.password || url.pathname !== '/' || url.search || url.hash)
11
+ throw Error('cross-Fleet bindings require an explicit loopback HTTP origin');
12
+ return url.origin;
13
+ }
14
+ export async function callRemoteLayoutBinding(instance, request, daemonInstanceId, fetchImpl = fetch) {
15
+ const remote = instance.remote;
16
+ if (!LAYOUT_BINDING_ACTIONS.includes(request.action))
17
+ throw Error('cross-Fleet bindings allow only verify, join and assign');
18
+ if (remote.daemon_instance_id !== daemonInstanceId)
19
+ throw Error('cross-Fleet binding requires the same daemon instance');
20
+ const origin = layoutBindingOrigin(remote.url);
21
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(remote.grant_id) || !isAbsolute(remote.credential_file))
22
+ throw Error('invalid cross-Fleet binding');
23
+ const stat = lstatSync(remote.credential_file);
24
+ if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 0o077)
25
+ || (process.getuid && stat.uid !== process.getuid()) || stat.size > 256)
26
+ throw Error('untrusted cross-Fleet credential file');
27
+ const token = readFileSync(remote.credential_file, 'utf8').trim();
28
+ if (!/^[A-Za-z0-9_-]{43}$/.test(token))
29
+ throw Error('invalid cross-Fleet credential');
30
+ let response;
31
+ try {
32
+ response = await fetchImpl(`${origin}/api/v1/layout-bindings/${remote.grant_id}/control`, {
33
+ method: 'POST', redirect: 'error', signal: AbortSignal.timeout(60_000),
34
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },
35
+ body: JSON.stringify({ ...request, instance: localLayoutReference(instance), daemonInstanceId }),
36
+ });
37
+ }
38
+ catch {
39
+ throw Error('cross-Fleet control unavailable; operation outcome may be unknown');
40
+ }
41
+ // Remote errors are not trusted presentation data and may contain private request bytes.
42
+ if (!response.ok)
43
+ throw Error(`cross-Fleet binding rejected (${response.status})`);
44
+ let result;
45
+ try {
46
+ result = await response.json();
47
+ }
48
+ catch {
49
+ throw Error('invalid cross-Fleet control response');
50
+ }
51
+ if (!result || typeof result !== 'object')
52
+ throw Error('invalid cross-Fleet control response');
53
+ if (canonicalJson(result.instance) !== canonicalJson(localLayoutReference(instance)))
54
+ throw Error('cross-Fleet instance proof changed');
55
+ return result.result;
56
+ }
@@ -0,0 +1,21 @@
1
+ import type { LayoutInstance, LayoutSupervisor } from './layout.js';
2
+ import { type CoworkAdapter } from './cowork-adapter.js';
3
+ /** Private authorization records in the existing Fleet state; no foreign lifecycle port. */
4
+ export declare class LayoutBindingGrants {
5
+ private supervisor;
6
+ private options;
7
+ constructor(supervisor: LayoutSupervisor, options?: {
8
+ root?: string;
9
+ daemonInstanceId?: () => string;
10
+ cowork?: () => CoworkAdapter;
11
+ });
12
+ private get root();
13
+ private daemonInstanceId;
14
+ private path;
15
+ share(instance: LayoutInstance, origin: string, output: string, participant: string): Promise<{
16
+ grant_id: string;
17
+ file: string;
18
+ }>;
19
+ revoke(id: string): Promise<void>;
20
+ control(id: string, authorization: string | undefined, raw: unknown): Promise<unknown>;
21
+ }
@@ -0,0 +1,128 @@
1
+ import { randomBytes, randomUUID, createHash, timingSafeEqual } from 'node:crypto';
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { dirname, basename, join } from 'node:path';
4
+ import { stringify } from 'yaml';
5
+ import { stateRoot } from '../paths.js';
6
+ import { withFileLock } from '../atomic-file.js';
7
+ import { readClientProfile } from '../client-profile.js';
8
+ import { FleetError } from '../application/errors.js';
9
+ import { assertLayoutFile, validLayoutKey } from './layout-config.js';
10
+ import { canonicalJson } from '../canonical-json.js';
11
+ import { LAYOUT_BINDING_ACTIONS, layoutBindingOrigin } from './layout-binding-client.js';
12
+ import { createCoworkAdapter } from './cowork-adapter.js';
13
+ const digest = (token) => createHash('sha256').update(token).digest('hex');
14
+ function privatePath(path, directory = false) {
15
+ assertLayoutFile(path, directory);
16
+ if (lstatSync(path).mode & 0o077)
17
+ throw new FleetError('forbidden', 'layout grants require owner-only permissions');
18
+ }
19
+ const allowedId = (id) => /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(id);
20
+ /** Private authorization records in the existing Fleet state; no foreign lifecycle port. */
21
+ export class LayoutBindingGrants {
22
+ supervisor;
23
+ options;
24
+ constructor(supervisor, options = {}) {
25
+ this.supervisor = supervisor;
26
+ this.options = options;
27
+ }
28
+ get root() { return this.options.root ?? join(stateRoot(), 'layout-bindings'); }
29
+ daemonInstanceId() { return this.options.daemonInstanceId?.() ?? readClientProfile().expectedInstanceId; }
30
+ path(id) {
31
+ if (!allowedId(id))
32
+ throw new FleetError('invalid_request', 'invalid layout binding grant');
33
+ return join(this.root, `${id}.json`);
34
+ }
35
+ async share(instance, origin, output, participant) {
36
+ layoutBindingOrigin(origin);
37
+ if (!validLayoutKey(participant) || instance.remote || instance.supervisor !== this.supervisor.id)
38
+ throw new FleetError('invalid_request', 'only an exact local standalone instance can be shared');
39
+ await this.supervisor.verify(instance);
40
+ const daemonInstanceId = this.daemonInstanceId();
41
+ const token = randomBytes(32).toString('base64url'), id = randomUUID();
42
+ const credential = `${output}.token`;
43
+ // Create-only publication: never replace another binding or credential.
44
+ if (existsSync(output) || existsSync(credential))
45
+ throw new FleetError('conflict', 'binding output already exists');
46
+ mkdirSync(this.root, { recursive: true, mode: 0o700 });
47
+ privatePath(this.root, true);
48
+ mkdirSync(dirname(output), { recursive: true, mode: 0o700 });
49
+ assertLayoutFile(dirname(output), true);
50
+ const grant = { version: 1, digest: digest(token), instance, daemonInstanceId };
51
+ writeFileSync(this.path(id), JSON.stringify(grant), { mode: 0o600, flag: 'wx' });
52
+ let tokenWritten = false;
53
+ try {
54
+ writeFileSync(credential, `${token}\n`, { mode: 0o600, flag: 'wx' });
55
+ tokenWritten = true;
56
+ writeFileSync(output, stringify({ [participant]: { ...instance, remote: {
57
+ url: layoutBindingOrigin(origin), grant_id: id, credential_file: basename(credential), daemon_instance_id: daemonInstanceId,
58
+ } } }), { mode: 0o600, flag: 'wx' });
59
+ }
60
+ catch (error) {
61
+ rmSync(this.path(id), { force: true });
62
+ if (tokenWritten)
63
+ rmSync(credential, { force: true });
64
+ throw error;
65
+ }
66
+ return { grant_id: id, file: output };
67
+ }
68
+ async revoke(id) {
69
+ const path = this.path(id);
70
+ if (!existsSync(this.root))
71
+ return;
72
+ privatePath(this.root, true);
73
+ await withFileLock(path + '.lock', () => { rmSync(path, { force: true }); });
74
+ }
75
+ async control(id, authorization, raw) {
76
+ const path = this.path(id);
77
+ if (!existsSync(path))
78
+ throw new FleetError('unauthorized', 'layout binding is unavailable');
79
+ privatePath(this.root, true);
80
+ return withFileLock(path + '.lock', async () => {
81
+ if (!existsSync(path))
82
+ throw new FleetError('unauthorized', 'layout binding is unavailable');
83
+ privatePath(path);
84
+ const grant = JSON.parse(readFileSync(path, 'utf8'));
85
+ const token = authorization?.match(/^Bearer ([A-Za-z0-9_-]{43})$/)?.[1];
86
+ if (!token || grant.version !== 1 || typeof grant.digest !== 'string' || !/^[a-f0-9]{64}$/.test(grant.digest)
87
+ || !timingSafeEqual(Buffer.from(digest(token)), Buffer.from(grant.digest)))
88
+ throw new FleetError('unauthorized', 'layout binding is unavailable');
89
+ const request = raw;
90
+ if (!request || !LAYOUT_BINDING_ACTIONS.includes(request.action)
91
+ || Object.keys(request).some(k => !['action', 'instance', 'roomId', 'roomRole', 'roomCid', 'assignment', 'daemonInstanceId'].includes(k)))
92
+ throw new FleetError('invalid_request', 'unsupported layout binding operation');
93
+ if (request.daemonInstanceId !== grant.daemonInstanceId || grant.daemonInstanceId !== this.daemonInstanceId()
94
+ || canonicalJson(request.instance) !== canonicalJson(grant.instance))
95
+ throw new FleetError('forbidden', 'layout binding does not match the granted instance');
96
+ try {
97
+ await this.supervisor.verify(grant.instance);
98
+ let result;
99
+ if (request.action === 'join') {
100
+ if (!request.roomId || !request.roomCid || !request.roomRole)
101
+ throw Error('room ID, CID and role required');
102
+ const cowork = this.options.cowork?.() ?? createCoworkAdapter();
103
+ const room = await cowork.getRoom(request.roomId);
104
+ if (!room || !['provisioning', 'active'].includes(room.state) || room.identity_cid !== request.roomCid)
105
+ throw Error('known mutable Cowork room required');
106
+ // Never redeem a caller-supplied contact invitation. Cowork owns this receipt.
107
+ const invitation = await cowork.issueInvite(request.roomId, { mode: 'one_time', role: request.roomRole, min_accepts: 1 });
108
+ await this.supervisor.join(grant.instance, invitation.invite, request.roomCid);
109
+ }
110
+ else if (request.action === 'assign') {
111
+ const a = request.assignment;
112
+ if (!a?.room_id || !a.room_cid || !a.room_role)
113
+ throw Error('assignment required');
114
+ const room = await (this.options.cowork?.() ?? createCoworkAdapter()).getRoom(a.room_id);
115
+ if (room?.state !== 'active' || room.identity_cid !== a.room_cid
116
+ || !room.seats.some(s => s.identity_cid === grant.instance.cid && s.role === a.room_role && s.seat_state === 'active'))
117
+ throw Error('active granted membership required');
118
+ result = await this.supervisor.assign(grant.instance, a);
119
+ }
120
+ await this.supervisor.verify(grant.instance);
121
+ return { instance: grant.instance, result };
122
+ }
123
+ catch {
124
+ throw new FleetError('rejected', 'layout binding operation rejected or unconfirmed; inspect before retry');
125
+ }
126
+ });
127
+ }
128
+ }
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ import type { LayoutInstance } from './layout.js';
3
+ export declare function readLayoutBindings(file: string): Record<string, LayoutInstance>;
4
+ export declare function registerLayoutCommands(parent: Command, cOpt: (cmd: Command) => Command): void;