@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.
- package/README.md +158 -28
- package/dist/account-origin.d.ts +2 -0
- package/dist/account-origin.js +6 -0
- package/dist/agent-ours/bridge.d.ts +3 -0
- package/dist/agent-ours/bridge.js +178 -0
- package/dist/agent-ours/controller.d.ts +14 -0
- package/dist/agent-ours/controller.js +60 -0
- package/dist/agent-ours/correspondence.d.ts +10 -0
- package/dist/agent-ours/correspondence.js +1 -0
- package/dist/agent-ours/file-rpc.d.ts +23 -0
- package/dist/agent-ours/file-rpc.js +123 -0
- package/dist/agent-ours/harness.d.ts +14 -0
- package/dist/agent-ours/harness.js +72 -0
- package/dist/agent-ours/mcp-endpoint.d.ts +15 -0
- package/dist/agent-ours/mcp-endpoint.js +111 -0
- package/dist/agent-ours/runtime.d.ts +59 -0
- package/dist/agent-ours/runtime.js +283 -0
- package/dist/agent-ours/service.d.ts +23 -0
- package/dist/agent-ours/service.js +372 -0
- package/dist/agent-ours/state.d.ts +45 -0
- package/dist/agent-ours/state.js +95 -0
- package/dist/agent-ours/wire.d.ts +14 -0
- package/dist/agent-ours/wire.js +55 -0
- package/dist/application/conversation-history.d.ts +25 -0
- package/dist/application/conversation-history.js +189 -0
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +2 -2
- package/dist/application/legacy-supervisor-identity.d.ts +7 -0
- package/dist/application/legacy-supervisor-identity.js +43 -0
- package/dist/application/model-catalog.d.ts +1 -1
- package/dist/application/model-catalog.js +5 -2
- package/dist/application/preset-provenance.d.ts +19 -0
- package/dist/application/preset-provenance.js +59 -0
- package/dist/application/room-layout-definitions.d.ts +45 -0
- package/dist/application/room-layout-definitions.js +130 -0
- package/dist/application/session-control.d.ts +18 -0
- package/dist/application/session-control.js +54 -3
- package/dist/application/supervisor-ours-tools.d.ts +159 -0
- package/dist/application/supervisor-ours-tools.js +113 -0
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +249 -0
- package/dist/application/task-room-service.d.ts +99 -3
- package/dist/application/task-room-service.js +296 -31
- package/dist/atomic-file.d.ts +5 -0
- package/dist/atomic-file.js +62 -1
- package/dist/briefing.js +10 -59
- package/dist/build-info.json +6 -4
- package/dist/capabilities.d.ts +3 -1
- package/dist/capabilities.js +4 -0
- package/dist/cli.js +131 -5
- package/dist/client-profile.d.ts +5 -16
- package/dist/client-profile.js +4 -112
- package/dist/config.d.ts +4 -0
- package/dist/config.js +7 -0
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +5 -16
- package/dist/daemon-recovery.d.ts +1 -8
- package/dist/daemon-recovery.js +8 -113
- package/dist/docs.d.ts +3 -3
- package/dist/docs.js +43 -23
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +46 -59
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/fleet-command-audit.d.ts +1 -0
- package/dist/fleet-command-audit.js +12 -7
- package/dist/harness/agent-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +4 -2
- package/dist/harness/codex-app-server-proxy.d.ts +4 -1
- package/dist/harness/codex-app-server-proxy.js +41 -5
- package/dist/harness/codex-session.js +9 -2
- package/dist/harness/codex.d.ts +3 -2
- package/dist/harness/codex.js +4 -3
- package/dist/harness/hermes-session.js +7 -1
- package/dist/init-wizard.js +20 -9
- package/dist/isolation/policy.js +2 -0
- package/dist/isolation/types.d.ts +5 -0
- package/dist/monitor.d.ts +1 -34
- package/dist/monitor.js +24 -151
- package/dist/notifications/fleet-producer.d.ts +18 -0
- package/dist/notifications/fleet-producer.js +129 -0
- package/dist/notifications/outbox.d.ts +31 -0
- package/dist/notifications/outbox.js +104 -0
- package/dist/owner-channel/channel.d.ts +3 -0
- package/dist/owner-channel/channel.js +34 -6
- package/dist/owner-channel/commands.d.ts +4 -0
- package/dist/owner-channel/commands.js +8 -0
- package/dist/owner-channel/lifecycle-outbox.js +4 -3
- package/dist/owner-channel/ours-client.js +2 -17
- package/dist/preset-migration.js +15 -0
- package/dist/rooms-tasks/add-member.d.ts +48 -0
- package/dist/rooms-tasks/add-member.js +83 -0
- package/dist/rooms-tasks/archived-absence.d.ts +8 -0
- package/dist/rooms-tasks/archived-absence.js +48 -0
- package/dist/rooms-tasks/cli.js +34 -5
- package/dist/rooms-tasks/close.d.ts +5 -2
- package/dist/rooms-tasks/close.js +208 -28
- package/dist/rooms-tasks/config.js +3 -1
- package/dist/rooms-tasks/cowork-adapter.d.ts +6 -4
- package/dist/rooms-tasks/cowork-adapter.js +11 -117
- package/dist/rooms-tasks/cowork-http.d.ts +3 -0
- package/dist/rooms-tasks/cowork-http.js +70 -0
- package/dist/rooms-tasks/deletion.d.ts +1 -1
- package/dist/rooms-tasks/deletion.js +74 -5
- package/dist/rooms-tasks/erasure.d.ts +6 -0
- package/dist/rooms-tasks/erasure.js +169 -0
- package/dist/rooms-tasks/external-worker.d.ts +1 -1
- package/dist/rooms-tasks/external-worker.js +3 -4
- package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
- package/dist/rooms-tasks/layout-binding-client.js +56 -0
- package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
- package/dist/rooms-tasks/layout-binding-grants.js +128 -0
- package/dist/rooms-tasks/layout-cli.d.ts +4 -0
- package/dist/rooms-tasks/layout-cli.js +107 -0
- package/dist/rooms-tasks/layout-config.d.ts +11 -0
- package/dist/rooms-tasks/layout-config.js +89 -0
- package/dist/rooms-tasks/layout-control.d.ts +21 -0
- package/dist/rooms-tasks/layout-control.js +52 -0
- package/dist/rooms-tasks/layout-service.d.ts +42 -0
- package/dist/rooms-tasks/layout-service.js +185 -0
- package/dist/rooms-tasks/layout.d.ts +114 -0
- package/dist/rooms-tasks/layout.js +250 -0
- package/dist/rooms-tasks/live-readiness.d.ts +18 -0
- package/dist/rooms-tasks/live-readiness.js +85 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +2 -0
- package/dist/rooms-tasks/provision.d.ts +14 -0
- package/dist/rooms-tasks/provision.js +182 -48
- package/dist/rooms-tasks/room-state.d.ts +4 -2
- package/dist/rooms-tasks/room-state.js +53 -8
- package/dist/rooms-tasks/task-state.d.ts +42 -7
- package/dist/rooms-tasks/task-state.js +153 -23
- package/dist/rooms-tasks/types.d.ts +28 -0
- package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
- package/dist/rooms-tasks/workspace-artifacts.js +93 -0
- package/dist/rooms-tasks/workspace.d.ts +26 -0
- package/dist/rooms-tasks/workspace.js +195 -0
- package/dist/runner.d.ts +23 -3
- package/dist/runner.js +581 -494
- package/dist/session/acp.d.ts +3 -0
- package/dist/session/acp.js +14 -0
- package/dist/session/arbiter.d.ts +3 -0
- package/dist/session/arbiter.js +20 -2
- package/dist/session/codex-app-server-transport.js +1 -1
- package/dist/session/codex-app-server.d.ts +3 -0
- package/dist/session/codex-app-server.js +25 -1
- package/dist/session/control.d.ts +10 -1
- package/dist/session/control.js +37 -2
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-types.d.ts +5 -3
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +3 -0
- package/dist/socket-path.d.ts +2 -0
- package/dist/socket-path.js +22 -0
- package/dist/spawn.js +19 -16
- package/dist/startup-readiness.d.ts +13 -0
- package/dist/startup-readiness.js +38 -0
- package/dist/subscriptions/cli.d.ts +78 -0
- package/dist/subscriptions/cli.js +186 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +75 -0
- package/dist/subscriptions/login.js +182 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +140 -0
- package/dist/supervisor/launchd.js +2 -1
- package/dist/supervisor/systemd.js +9 -23
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +6 -1
- package/dist/temp-lifecycle.js +29 -13
- package/dist/temp-supervisor-recovery.d.ts +3 -0
- package/dist/temp-supervisor-recovery.js +46 -0
- package/dist/watchdog/briefing.js +3 -16
- package/dist/watchdog/run.js +19 -5
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +28 -2
- package/dist/web/auth.js +81 -8
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/control.d.ts +3 -2
- package/dist/web/control.js +11 -7
- package/dist/web/fleet-config-service.d.ts +4 -1
- package/dist/web/fleet-config-service.js +46 -15
- package/dist/web/prefix-gateway.d.ts +23 -0
- package/dist/web/prefix-gateway.js +156 -0
- package/dist/web/runtime.d.ts +4 -0
- package/dist/web/runtime.js +106 -20
- package/dist/web/server.d.ts +11 -0
- package/dist/web/server.js +445 -31
- package/dist/web/service.d.ts +11 -2
- package/dist/web/service.js +30 -4
- package/dist/web/workspace-devices.d.ts +29 -0
- package/dist/web/workspace-devices.js +84 -0
- package/dist/web/workspace-tunnel.d.ts +1 -0
- package/dist/web/workspace-tunnel.js +32 -0
- package/dist/web-app/assets/FleetApp-D58F4xje.css +1 -0
- package/dist/web-app/assets/FleetApp-DP5cBY0o.js +302 -0
- package/dist/web-app/assets/FleetApp-DP5cBY0o.js.map +1 -0
- package/dist/web-app/assets/abnfDiagram-VCTEODGH-BvJIz7wN.js +2 -0
- package/dist/web-app/assets/abnfDiagram-VCTEODGH-BvJIz7wN.js.map +1 -0
- package/dist/web-app/assets/arc-AT_BEfpe.js +2 -0
- package/dist/web-app/assets/arc-AT_BEfpe.js.map +1 -0
- package/dist/web-app/assets/architectureDiagram-5GKGNRK7-vSgJa9Xb.js +37 -0
- package/dist/web-app/assets/architectureDiagram-5GKGNRK7-vSgJa9Xb.js.map +1 -0
- package/dist/web-app/assets/blockDiagram-I7D4REHJ-DCFk_4Kv.js +130 -0
- package/dist/web-app/assets/blockDiagram-I7D4REHJ-DCFk_4Kv.js.map +1 -0
- package/dist/web-app/assets/browser-CMIwJ_8L.js +9 -0
- package/dist/web-app/assets/browser-CMIwJ_8L.js.map +1 -0
- package/dist/web-app/assets/c4Diagram-7LVT6UL2-8J_dVUtF.js +39 -0
- package/dist/web-app/assets/c4Diagram-7LVT6UL2-8J_dVUtF.js.map +1 -0
- package/dist/web-app/assets/channel-BHCBlfND.js +2 -0
- package/dist/web-app/assets/channel-BHCBlfND.js.map +1 -0
- package/dist/web-app/assets/chunk-2Q5K7J3B-31RX-jnL.js +2 -0
- package/dist/web-app/assets/chunk-2Q5K7J3B-31RX-jnL.js.map +1 -0
- package/dist/web-app/assets/chunk-5VM5RSS4-CFF8_ZJH.js +16 -0
- package/dist/web-app/assets/chunk-5VM5RSS4-CFF8_ZJH.js.map +1 -0
- package/dist/web-app/assets/chunk-F27PBJKO-Dx1l5wLI.js +2 -0
- package/dist/web-app/assets/chunk-F27PBJKO-Dx1l5wLI.js.map +1 -0
- package/dist/web-app/assets/chunk-IMKFNOWR-Ba2_9bl_.js +232 -0
- package/dist/web-app/assets/chunk-IMKFNOWR-Ba2_9bl_.js.map +1 -0
- package/dist/web-app/assets/chunk-JWPE2WC7-_mnRB2OH.js +2 -0
- package/dist/web-app/assets/chunk-JWPE2WC7-_mnRB2OH.js.map +1 -0
- package/dist/web-app/assets/chunk-POPQ4Y6H-B8jQTxQO.js +2 -0
- package/dist/web-app/assets/chunk-POPQ4Y6H-B8jQTxQO.js.map +1 -0
- package/dist/web-app/assets/chunk-SVP7TREG-BO_Jnb_c.js +89 -0
- package/dist/web-app/assets/chunk-SVP7TREG-BO_Jnb_c.js.map +1 -0
- package/dist/web-app/assets/chunk-TICWLB2K-ZYZ9hFu5.js +207 -0
- package/dist/web-app/assets/chunk-TICWLB2K-ZYZ9hFu5.js.map +1 -0
- package/dist/web-app/assets/chunk-XXDRQBXY-ByUAYXI3.js +2 -0
- package/dist/web-app/assets/chunk-XXDRQBXY-ByUAYXI3.js.map +1 -0
- package/dist/web-app/assets/classDiagram-ZZMXUADV-Ddx7RAuT.js +2 -0
- package/dist/web-app/assets/classDiagram-ZZMXUADV-Ddx7RAuT.js.map +1 -0
- package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-Ddx7RAuT.js +2 -0
- package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-Ddx7RAuT.js.map +1 -0
- package/dist/web-app/assets/cose-bilkent-JH36ORCC-BuOGJgHG.js +2 -0
- package/dist/web-app/assets/cose-bilkent-JH36ORCC-BuOGJgHG.js.map +1 -0
- package/dist/web-app/assets/cynefin-OW5HDTMX-DLksGPh8.js +179 -0
- package/dist/web-app/assets/cynefin-OW5HDTMX-DLksGPh8.js.map +1 -0
- package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-nJQb5qZR.js +63 -0
- package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-nJQb5qZR.js.map +1 -0
- package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js +332 -0
- package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js.map +1 -0
- package/dist/web-app/assets/dagre-GXQ25YYZ-CCF5O_UD.js +5 -0
- package/dist/web-app/assets/dagre-GXQ25YYZ-CCF5O_UD.js.map +1 -0
- package/dist/web-app/assets/defaultLocale-DX6XiGOO.js +2 -0
- package/dist/web-app/assets/defaultLocale-DX6XiGOO.js.map +1 -0
- package/dist/web-app/assets/diagram-S7CK7UJ4-C88au4NC.js +31 -0
- package/dist/web-app/assets/diagram-S7CK7UJ4-C88au4NC.js.map +1 -0
- package/dist/web-app/assets/diagram-UQ7AKVKN-B4QnPs7U.js +42 -0
- package/dist/web-app/assets/diagram-UQ7AKVKN-B4QnPs7U.js.map +1 -0
- package/dist/web-app/assets/diagram-VSXAHHWV-DeANdVWA.js +4 -0
- package/dist/web-app/assets/diagram-VSXAHHWV-DeANdVWA.js.map +1 -0
- package/dist/web-app/assets/diagram-VX7I27RA-YzlB_2AY.js +25 -0
- package/dist/web-app/assets/diagram-VX7I27RA-YzlB_2AY.js.map +1 -0
- package/dist/web-app/assets/diagram-Z3DM3KII-YY9NFaz_.js +25 -0
- package/dist/web-app/assets/diagram-Z3DM3KII-YY9NFaz_.js.map +1 -0
- package/dist/web-app/assets/ebnfDiagram-PWID7BFC-Cqu9kHUC.js +2 -0
- package/dist/web-app/assets/ebnfDiagram-PWID7BFC-Cqu9kHUC.js.map +1 -0
- package/dist/web-app/assets/erDiagram-RLTQ6QDP-IHi93MdG.js +100 -0
- package/dist/web-app/assets/erDiagram-RLTQ6QDP-IHi93MdG.js.map +1 -0
- package/dist/web-app/assets/flowDiagram-HODETNUW-19bm7W5P.js +169 -0
- package/dist/web-app/assets/flowDiagram-HODETNUW-19bm7W5P.js.map +1 -0
- package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-BvCqvyiB.js +293 -0
- package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-BvCqvyiB.js.map +1 -0
- package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-G4Ubl8Fs.js +107 -0
- package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-G4Ubl8Fs.js.map +1 -0
- package/dist/web-app/assets/index-C4BdeFB9.css +1 -0
- package/dist/web-app/assets/index-Dtn3ZY6J.js +430 -0
- package/dist/web-app/assets/index-Dtn3ZY6J.js.map +1 -0
- package/dist/web-app/assets/infoDiagram-27XIBGKW-B6rtfbuC.js +3 -0
- package/dist/web-app/assets/infoDiagram-27XIBGKW-B6rtfbuC.js.map +1 -0
- package/dist/web-app/assets/init-Gi6I4Gst.js +2 -0
- package/dist/web-app/assets/init-Gi6I4Gst.js.map +1 -0
- package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-Lp8q1D21.js +71 -0
- package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-Lp8q1D21.js.map +1 -0
- package/dist/web-app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/web-app/assets/journeyDiagram-3NMN7TZE-Av03B9l3.js +140 -0
- package/dist/web-app/assets/journeyDiagram-3NMN7TZE-Av03B9l3.js.map +1 -0
- package/dist/web-app/assets/kanban-definition-UXKFOSKX-Ddd3_ejb.js +90 -0
- package/dist/web-app/assets/kanban-definition-UXKFOSKX-Ddd3_ejb.js.map +1 -0
- package/dist/web-app/assets/katex-HP8lGamR.js +258 -0
- package/dist/web-app/assets/katex-HP8lGamR.js.map +1 -0
- package/dist/web-app/assets/layout-CNjBeOlp.js +2 -0
- package/dist/web-app/assets/layout-CNjBeOlp.js.map +1 -0
- package/dist/web-app/assets/linear-DDONU9Ir.js +2 -0
- package/dist/web-app/assets/linear-DDONU9Ir.js.map +1 -0
- package/dist/web-app/assets/mermaid.core-B9X3C61k.js +313 -0
- package/dist/web-app/assets/mermaid.core-B9X3C61k.js.map +1 -0
- package/dist/web-app/assets/mindmap-definition-YA3MSWOX-I2UME2Ce.js +97 -0
- package/dist/web-app/assets/mindmap-definition-YA3MSWOX-I2UME2Ce.js.map +1 -0
- package/dist/web-app/assets/ordinal-Cboi1Yqb.js +2 -0
- package/dist/web-app/assets/ordinal-Cboi1Yqb.js.map +1 -0
- package/dist/web-app/assets/pegDiagram-XKGWAZYB-BER8lNbi.js +2 -0
- package/dist/web-app/assets/pegDiagram-XKGWAZYB-BER8lNbi.js.map +1 -0
- package/dist/web-app/assets/pieDiagram-E7YTZNPT-FVWVg8rH.js +40 -0
- package/dist/web-app/assets/pieDiagram-E7YTZNPT-FVWVg8rH.js.map +1 -0
- package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-YlvT1u77.js +8 -0
- package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-YlvT1u77.js.map +1 -0
- package/dist/web-app/assets/railroadDiagram-O6MQD6OU-CvxT6dMW.js +2 -0
- package/dist/web-app/assets/railroadDiagram-O6MQD6OU-CvxT6dMW.js.map +1 -0
- package/dist/web-app/assets/requirementDiagram-BXWQKSXE-Caav4EkP.js +85 -0
- package/dist/web-app/assets/requirementDiagram-BXWQKSXE-Caav4EkP.js.map +1 -0
- package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-B5Uw70Gn.js +41 -0
- package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-B5Uw70Gn.js.map +1 -0
- package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-D2SLKVJl.js +163 -0
- package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-D2SLKVJl.js.map +1 -0
- package/dist/web-app/assets/sizeCapture-INFHLROL-BVaBfbwa.js +2 -0
- package/dist/web-app/assets/sizeCapture-INFHLROL-BVaBfbwa.js.map +1 -0
- package/dist/web-app/assets/stateDiagram-D77RDMKH-BlV9y2tf.js +2 -0
- package/dist/web-app/assets/stateDiagram-D77RDMKH-BlV9y2tf.js.map +1 -0
- package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-BU4Tu2pp.js +2 -0
- package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-BU4Tu2pp.js.map +1 -0
- package/dist/web-app/assets/swimlanes-42K2YHIH-Pv3Wv8c7.js +2 -0
- package/dist/web-app/assets/swimlanes-42K2YHIH-Pv3Wv8c7.js.map +1 -0
- package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-BNKjOvPH.js +9 -0
- package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-BNKjOvPH.js.map +1 -0
- package/dist/web-app/assets/timeline-definition-24CTP7MA-C9TOilaR.js +121 -0
- package/dist/web-app/assets/timeline-definition-24CTP7MA-C9TOilaR.js.map +1 -0
- package/dist/web-app/assets/vennDiagram-4TSXK5OY-DeSDprN4.js +35 -0
- package/dist/web-app/assets/vennDiagram-4TSXK5OY-DeSDprN4.js.map +1 -0
- package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-SulZn-nm.js +79 -0
- package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-SulZn-nm.js.map +1 -0
- package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-CC6MrQ0h.js +8 -0
- package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-CC6MrQ0h.js.map +1 -0
- package/dist/web-app/fleet-index.html +19 -0
- package/dist/web-app/fleet.webmanifest +37 -0
- package/dist/web-app/icons/apple-touch-icon.png +0 -0
- package/dist/web-app/icons/favicon-16.png +0 -0
- package/dist/web-app/icons/favicon-32.png +0 -0
- package/dist/web-app/icons/icon-192-maskable.png +0 -0
- package/dist/web-app/icons/icon-192.png +0 -0
- package/dist/web-app/icons/icon-512-maskable.png +0 -0
- package/dist/web-app/icons/icon-512.png +0 -0
- package/dist/web-app/index.html +9 -7
- package/dist/web-app/manifest.webmanifest +10 -8
- package/dist/web-app/sw.js +210 -40
- package/dist/web-app/version.json +1 -0
- package/dist/web-app/workspace-install.sh +148 -0
- package/dist/workspace-enrollment.d.ts +28 -0
- package/dist/workspace-enrollment.js +129 -0
- package/docs/room-layouts.md +227 -0
- package/docs/task-workspaces.md +130 -0
- package/examples/room-layouts/fresh.yaml +27 -0
- package/examples/room-layouts/scoped.yaml +21 -0
- package/examples/room-layouts/shared.yaml +19 -0
- package/package.json +14 -17
- package/presets/README.md +78 -0
- package/presets/brain-catalog.json +8 -2
- package/presets/fleet/agent_templates/Engineer.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
- package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +22 -0
- package/presets/fleet/roles/Engineer.yaml +40 -0
- package/presets/fleet/room_layouts/engineering.yaml +25 -0
- package/presets/fleet/room_layouts/pair.yaml +24 -0
- package/presets/fleet/room_layouts/single.yaml +17 -0
- package/presets/fleet/room_layouts/team.yaml +30 -0
- package/presets/fleet/room_templates/engineering.yaml +19 -0
- package/presets/manifest.json +2 -2
- package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
- package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
- package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
- package/dist/web-app/icons/ours-fleet.svg +0 -4
- package/dist/web-app/offline.html +0 -18
|
@@ -2,6 +2,8 @@ import { withFileLock } from '../atomic-file.js';
|
|
|
2
2
|
import { type TempLifecycleDeps } from '../temp-lifecycle.js';
|
|
3
3
|
import { type CoworkAdapter } from './cowork-adapter.js';
|
|
4
4
|
import type { RoomMemberSeat, RoomOrchestrationRecord } from './types.js';
|
|
5
|
+
export declare const CLOSE_LOCK_STALE_MS: number;
|
|
6
|
+
export declare function roomCloseLockPath(roomId: string): string;
|
|
5
7
|
export interface RoomCloseDeps {
|
|
6
8
|
inspectMember?(seat: RoomMemberSeat): Promise<{
|
|
7
9
|
launchId: string;
|
|
@@ -19,12 +21,13 @@ export declare function waitForLivenessAbsent(role: string, launchId: string, li
|
|
|
19
21
|
/** Report whether any daemon identity — under any name — carries this exact CID. */
|
|
20
22
|
export declare function identityCidPresent(cid: string): Promise<boolean>;
|
|
21
23
|
export declare function removeExactMemberIdentity(seat: RoomMemberSeat): Promise<void>;
|
|
24
|
+
export declare function assertMemberIdentityAbsent(seat: RoomMemberSeat): Promise<void>;
|
|
22
25
|
/** One forward-only room close saga shared by every Fleet entry point. */
|
|
23
26
|
export declare function acceptManagedRoomClose(roomId: string): Promise<RoomOrchestrationRecord>;
|
|
24
27
|
export declare function recordManagedRoomCloseError(roomId: string, error: string, recoveryHint: string): Promise<RoomOrchestrationRecord>;
|
|
25
28
|
export declare function closeManagedRoom(input: {
|
|
26
29
|
roomId: string;
|
|
27
|
-
cowork: Pick<CoworkAdapter, 'closeRoom'
|
|
30
|
+
cowork: Pick<CoworkAdapter, 'closeRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
28
31
|
deps?: RoomCloseDeps;
|
|
29
32
|
}): Promise<RoomOrchestrationRecord>;
|
|
30
33
|
export interface ManagedRoomDeleteResult {
|
|
@@ -38,6 +41,6 @@ export declare function deleteLegacyClosedRooms(input: {
|
|
|
38
41
|
/** Retire live resources through the existing cursor, then delete retained state. */
|
|
39
42
|
export declare function deleteManagedRoom(input: {
|
|
40
43
|
roomId: string;
|
|
41
|
-
cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'
|
|
44
|
+
cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
42
45
|
deps?: RoomCloseDeps;
|
|
43
46
|
}): Promise<ManagedRoomDeleteResult>;
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
import { detachDeletedRoom } from './task-state.js';
|
|
2
|
+
import { binderKey } from '../agent-ours/state.js';
|
|
3
|
+
import { eraseMemberArtifacts } from './erasure.js';
|
|
4
|
+
import { deleteWorkspace, assertWorkspaceDeletable } from './workspace.js';
|
|
5
|
+
import { collectWorkspaceArchives } from './workspace-artifacts.js';
|
|
1
6
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
7
|
import { join } from 'node:path';
|
|
3
8
|
import { randomUUID } from 'node:crypto';
|
|
4
9
|
import { attachOursClient } from '@ours.network/sdk/client';
|
|
5
10
|
import { withFileLock } from '../atomic-file.js';
|
|
6
11
|
import { agentDir, stateRoot } from '../paths.js';
|
|
7
|
-
import {
|
|
12
|
+
import { readClientProfile } from '../client-profile.js';
|
|
13
|
+
import { readTempSupervisor, secureStoppedTempArchive, stopTempSupervisor, tempSupervisorLiveness, tempArchiveForLaunch, tempArchiveForCreationAction, } from '../temp-lifecycle.js';
|
|
8
14
|
import { CoworkProtocolError } from './cowork-adapter.js';
|
|
9
|
-
import { advanceMemberRetirement, advanceRoomClose, beginRoomClose, closeRoom, deleteRoomRecord, getRoomRecord, listRoomRecords, setRoomCloseError, } from './room-state.js';
|
|
10
|
-
const CLOSE_LOCK_STALE_MS = 5 * 60_000;
|
|
15
|
+
import { advanceMemberRetirement, advanceRoomClose, beginRoomClose, closeRoom, deleteRoomRecord, getRoomRecord, listRoomRecords, setRoomCloseError, recordRetirementMemberCids, } from './room-state.js';
|
|
16
|
+
export const CLOSE_LOCK_STALE_MS = 5 * 60_000;
|
|
11
17
|
const STOP_POLLS = 50;
|
|
12
18
|
const STOP_POLL_MS = 100;
|
|
13
|
-
function roomCloseLockPath(roomId) {
|
|
19
|
+
export function roomCloseLockPath(roomId) {
|
|
14
20
|
return join(stateRoot(), 'locks', 'room-close', encodeURIComponent(roomId));
|
|
15
21
|
}
|
|
16
22
|
function errorText(error) {
|
|
@@ -19,6 +25,20 @@ function errorText(error) {
|
|
|
19
25
|
function exactMemberIdentity(seat) {
|
|
20
26
|
const dir = agentDir(seat.role_name, true);
|
|
21
27
|
const identityPath = join(dir, '.identity');
|
|
28
|
+
if (existsSync(dir) && !existsSync(identityPath) && seat.launch?.action_id && seat.launch.launch_id) {
|
|
29
|
+
const supervisor = readTempSupervisor(dir);
|
|
30
|
+
let creation;
|
|
31
|
+
try {
|
|
32
|
+
creation = JSON.parse(readFileSync(join(dir, 'creation.json'), 'utf8'));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error.code !== 'ENOENT')
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
if (supervisor?.role === seat.role_name && supervisor.launchId === seat.launch.launch_id
|
|
39
|
+
&& creation?.role === seat.role_name && creation.creationActionId === seat.launch.action_id)
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
22
42
|
if (!existsSync(dir) || !existsSync(identityPath)) {
|
|
23
43
|
throw new Error(`room member '${seat.role_name}' has no live Fleet temp-state identity proof; refusing retirement`);
|
|
24
44
|
}
|
|
@@ -30,7 +50,8 @@ function exactMemberIdentity(seat) {
|
|
|
30
50
|
export async function inspectMember(seat) {
|
|
31
51
|
exactMemberIdentity(seat);
|
|
32
52
|
const supervisor = readTempSupervisor(agentDir(seat.role_name, true));
|
|
33
|
-
if (!supervisor || supervisor.role !== seat.role_name
|
|
53
|
+
if (!supervisor || supervisor.role !== seat.role_name
|
|
54
|
+
|| (seat.launch?.launch_id && supervisor.launchId !== seat.launch.launch_id)) {
|
|
34
55
|
throw new Error(`room member '${seat.role_name}' has no exact Fleet supervisor ownership proof`);
|
|
35
56
|
}
|
|
36
57
|
return { launchId: supervisor.launchId };
|
|
@@ -54,16 +75,24 @@ export async function waitForLivenessAbsent(role, launchId, lifecycleDeps = {})
|
|
|
54
75
|
throw new Error(`temporary role '${role}' did not reach proven stopped liveness`);
|
|
55
76
|
}
|
|
56
77
|
async function withIdentityClient(work) {
|
|
78
|
+
const profile = readClientProfile(process.env);
|
|
79
|
+
const leaseToken = `ours-fleet-room-close-${process.pid}-${randomUUID()}`;
|
|
57
80
|
const client = await attachOursClient({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
endpoint: profile.endpoint,
|
|
82
|
+
expectedInstanceId: profile.expectedInstanceId,
|
|
83
|
+
credentialPath: profile.credentialPath,
|
|
84
|
+
sessionMode: 'external', env: {}, leaseToken,
|
|
61
85
|
});
|
|
62
86
|
try {
|
|
63
87
|
return await work(client);
|
|
64
88
|
}
|
|
65
89
|
finally {
|
|
66
|
-
|
|
90
|
+
try {
|
|
91
|
+
await client.releaseLease().catch(() => { });
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await client.close();
|
|
95
|
+
}
|
|
67
96
|
}
|
|
68
97
|
}
|
|
69
98
|
function listedIdentity(rows, name) {
|
|
@@ -78,14 +107,19 @@ export async function identityCidPresent(cid) {
|
|
|
78
107
|
}
|
|
79
108
|
export async function removeExactMemberIdentity(seat) {
|
|
80
109
|
await withIdentityClient(async (client) => {
|
|
81
|
-
const
|
|
82
|
-
|
|
110
|
+
const rows = await client.listIdentities();
|
|
111
|
+
const before = listedIdentity(rows, seat.role_name);
|
|
112
|
+
if (!before) {
|
|
113
|
+
if (rows.some(row => row.name === seat.role_name || (seat.identity_cid && 'cid' in row
|
|
114
|
+
&& row.cid.toLowerCase() === seat.identity_cid.toLowerCase())))
|
|
115
|
+
throw new Error(`room member '${seat.role_name}' identity absence is not proven`);
|
|
83
116
|
return;
|
|
117
|
+
}
|
|
84
118
|
if (!seat.identity_cid) {
|
|
85
|
-
throw new Error(`room member '${seat.role_name}' exists without a recorded authenticated CID; refusing removal`);
|
|
119
|
+
throw new Error(`room member '${seat.role_name}' exists without a recorded authenticated CID; identity absence is not proven; refusing removal`);
|
|
86
120
|
}
|
|
87
121
|
if (before.cid?.toLowerCase() !== seat.identity_cid.toLowerCase()) {
|
|
88
|
-
throw new Error(`room member '${seat.role_name}' identity CID mismatch: recorded ${seat.identity_cid}, found ${before.cid ?? 'none'}`);
|
|
122
|
+
throw new Error(`room member '${seat.role_name}' identity absence is not proven: CID mismatch: recorded ${seat.identity_cid}, found ${before.cid ?? 'none'}`);
|
|
89
123
|
}
|
|
90
124
|
try {
|
|
91
125
|
await client.removeIdentity({ name: seat.role_name });
|
|
@@ -100,17 +134,59 @@ export async function removeExactMemberIdentity(seat) {
|
|
|
100
134
|
if (after)
|
|
101
135
|
throw error;
|
|
102
136
|
}
|
|
103
|
-
const after =
|
|
104
|
-
if (after
|
|
137
|
+
const after = await client.listIdentities();
|
|
138
|
+
if (after.some(row => row.name === seat.role_name || (seat.identity_cid && 'cid' in row
|
|
139
|
+
&& row.cid.toLowerCase() === seat.identity_cid.toLowerCase()))) {
|
|
105
140
|
throw new Error(`room member '${seat.role_name}' identity still exists after remove_identity`);
|
|
106
141
|
}
|
|
107
142
|
});
|
|
108
143
|
}
|
|
144
|
+
export async function assertMemberIdentityAbsent(seat) {
|
|
145
|
+
await withIdentityClient(async (client) => {
|
|
146
|
+
const rows = await client.listIdentities();
|
|
147
|
+
if (rows.some(row => row.name === seat.role_name ||
|
|
148
|
+
(seat.identity_cid && 'cid' in row && row.cid.toLowerCase() === seat.identity_cid.toLowerCase()))) {
|
|
149
|
+
throw new Error(`room member '${seat.role_name}' identity absence is not proven; refusing retirement`);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
109
153
|
async function retireMember(roomId, seat, deps) {
|
|
110
154
|
let room = getRoomRecord(roomId);
|
|
111
155
|
let current = room.member_seats.find(candidate => candidate.role_name === seat.role_name);
|
|
112
156
|
let retirement = current.retirement;
|
|
157
|
+
if (retirement?.phase === 'identity_absent') {
|
|
158
|
+
if (!deps.inspectMember) {
|
|
159
|
+
if (existsSync(agentDir(current.role_name, true)))
|
|
160
|
+
throw new Error('Retired member has replacement launch live state');
|
|
161
|
+
await assertMemberIdentityAbsent(current);
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
113
165
|
if (!retirement) {
|
|
166
|
+
if (!existsSync(agentDir(current.role_name, true)) && current.launch?.launch_id && current.launch.action_id) {
|
|
167
|
+
const archived = tempArchiveForLaunch(current.role_name, current.launch.launch_id);
|
|
168
|
+
const created = tempArchiveForCreationAction(current.role_name, current.launch.action_id);
|
|
169
|
+
if (archived && (!created || created.path !== archived || created.launchId !== current.launch.launch_id))
|
|
170
|
+
throw new Error('Archived member creation ownership mismatch');
|
|
171
|
+
if (archived && created?.path === archived && created.launchId === current.launch.launch_id) {
|
|
172
|
+
if (readFileSync(join(archived, '.identity'), 'utf8').trim() !== current.role_name)
|
|
173
|
+
throw new Error(`room member '${current.role_name}' archive identity mismatch`);
|
|
174
|
+
if (await tempSupervisorLiveness(archived) !== 'stopped')
|
|
175
|
+
throw new Error(`room member '${current.role_name}' archived supervisor is not proven stopped`);
|
|
176
|
+
// A terminated launch can archive itself before room retirement begins.
|
|
177
|
+
// Accept its exact durable provenance only when no identity needs removal.
|
|
178
|
+
await (deps.removeIdentity ?? removeExactMemberIdentity)(current);
|
|
179
|
+
await assertMemberIdentityAbsent(current);
|
|
180
|
+
const latest = getRoomRecord(roomId)?.member_seats.find(seat => seat.role_name === current.role_name);
|
|
181
|
+
if (existsSync(agentDir(current.role_name, true))
|
|
182
|
+
|| latest?.launch?.launch_id !== current.launch.launch_id
|
|
183
|
+
|| latest?.launch?.action_id !== current.launch.action_id
|
|
184
|
+
|| latest?.identity_cid !== current.identity_cid)
|
|
185
|
+
throw new Error(`room member '${current.role_name}' changed during archived retirement proof`);
|
|
186
|
+
advanceMemberRetirement(roomId, current.role_name, 'identity_absent', current.launch.launch_id, archived);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
114
190
|
if (current.launch?.state === 'pending' && current.launch.attempt === 0) {
|
|
115
191
|
if (existsSync(agentDir(current.role_name, true))) {
|
|
116
192
|
throw new Error(`never-launched room member '${current.role_name}' unexpectedly has Fleet temp state`);
|
|
@@ -119,12 +195,31 @@ async function retireMember(roomId, seat, deps) {
|
|
|
119
195
|
advanceMemberRetirement(roomId, current.role_name, 'identity_absent', 'never-launched');
|
|
120
196
|
return;
|
|
121
197
|
}
|
|
198
|
+
if (!deps.inspectMember && !existsSync(agentDir(current.role_name, true))) {
|
|
199
|
+
await (deps.removeIdentity ?? removeExactMemberIdentity)(current);
|
|
200
|
+
if (existsSync(agentDir(current.role_name, true)))
|
|
201
|
+
throw new Error(`room member '${current.role_name}' acquired replacement state during retirement`);
|
|
202
|
+
advanceMemberRetirement(roomId, current.role_name, 'identity_absent', 'absent-verified');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
122
205
|
const ownership = await (deps.inspectMember ?? inspectMember)(current);
|
|
123
206
|
room = advanceMemberRetirement(roomId, current.role_name, 'stop_requested', ownership.launchId);
|
|
124
207
|
current = room.member_seats.find(candidate => candidate.role_name === seat.role_name);
|
|
125
208
|
retirement = current.retirement;
|
|
126
209
|
}
|
|
210
|
+
if (['stop_requested', 'liveness_absent', 'archive_secured'].includes(retirement.phase) && !deps.requestStop
|
|
211
|
+
&& !existsSync(agentDir(current.role_name, true))) {
|
|
212
|
+
const archive = tempArchiveForLaunch(current.role_name, retirement.launch_id);
|
|
213
|
+
if (archive && await tempSupervisorLiveness(archive) !== 'stopped')
|
|
214
|
+
throw new Error('Archived supervisor is not proven stopped');
|
|
215
|
+
await (deps.removeIdentity ?? removeExactMemberIdentity)(current);
|
|
216
|
+
await assertMemberIdentityAbsent(current);
|
|
217
|
+
advanceMemberRetirement(roomId, current.role_name, 'identity_absent', retirement.launch_id, archive, !archive);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
127
220
|
if (retirement.phase === 'stop_requested') {
|
|
221
|
+
if (!deps.inspectMember && (await inspectMember(current)).launchId !== retirement.launch_id)
|
|
222
|
+
throw new Error('Member launch changed before stop');
|
|
128
223
|
await (deps.requestStop ?? (async (role) => { await stopTempSupervisor(role); }))(current.role_name);
|
|
129
224
|
await (deps.waitForLivenessAbsent ?? waitForLivenessAbsent)(current.role_name, retirement.launch_id);
|
|
130
225
|
room = advanceMemberRetirement(roomId, current.role_name, 'liveness_absent', retirement.launch_id);
|
|
@@ -154,19 +249,31 @@ export async function closeManagedRoom(input) {
|
|
|
154
249
|
const lock = deps.lock ?? withFileLock;
|
|
155
250
|
return lock(roomCloseLockPath(input.roomId), async () => {
|
|
156
251
|
let room = beginRoomClose(input.roomId);
|
|
157
|
-
if (room.state === 'closed')
|
|
252
|
+
if (room.state === 'closed') {
|
|
253
|
+
if (!deps.inspectMember)
|
|
254
|
+
for (const seat of room.member_seats) {
|
|
255
|
+
if (existsSync(agentDir(seat.role_name, true)))
|
|
256
|
+
throw new Error('Closed room has replacement live state');
|
|
257
|
+
await assertMemberIdentityAbsent(seat);
|
|
258
|
+
}
|
|
158
259
|
return room;
|
|
260
|
+
}
|
|
159
261
|
try {
|
|
160
262
|
if (room.close?.phase === 'retire_members') {
|
|
263
|
+
room = await recoverMemberCids(room, input.cowork);
|
|
161
264
|
for (const seat of room.member_seats) {
|
|
162
|
-
if (seat.retirement?.phase === 'identity_absent')
|
|
163
|
-
continue;
|
|
164
265
|
await retireMember(input.roomId, seat, deps);
|
|
165
266
|
}
|
|
166
267
|
room = advanceRoomClose(input.roomId, 'close_cowork');
|
|
167
268
|
}
|
|
168
269
|
if (room.close?.phase === 'close_cowork') {
|
|
169
|
-
|
|
270
|
+
try {
|
|
271
|
+
await input.cowork.closeRoom(input.roomId);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
if (!(error instanceof CoworkProtocolError && error.code === 'not_found'))
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
170
277
|
}
|
|
171
278
|
return closeRoom(input.roomId);
|
|
172
279
|
}
|
|
@@ -180,6 +287,9 @@ export async function closeManagedRoom(input) {
|
|
|
180
287
|
export async function deleteLegacyClosedRooms(input) {
|
|
181
288
|
const deleted = [];
|
|
182
289
|
for (const room of listRoomRecords({ state: 'closed' })) {
|
|
290
|
+
// This compatibility sweep is retirement, never explicit workspace deletion.
|
|
291
|
+
if (room.workspace)
|
|
292
|
+
continue;
|
|
183
293
|
try {
|
|
184
294
|
await input.cowork.deleteRoom(room.room_id);
|
|
185
295
|
}
|
|
@@ -196,14 +306,84 @@ export async function deleteLegacyClosedRooms(input) {
|
|
|
196
306
|
}
|
|
197
307
|
/** Retire live resources through the existing cursor, then delete retained state. */
|
|
198
308
|
export async function deleteManagedRoom(input) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
309
|
+
if (getRoomRecord(input.roomId))
|
|
310
|
+
await closeManagedRoom(input);
|
|
311
|
+
return withFileLock(roomCloseLockPath(input.roomId), async () => {
|
|
312
|
+
try {
|
|
313
|
+
try {
|
|
314
|
+
await input.cowork.deleteRoom(input.roomId);
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
// An earlier explicit delete may have removed the remote room before
|
|
318
|
+
// local filesystem cleanup failed. Never restore it or repeat creation.
|
|
319
|
+
if (!(error instanceof CoworkProtocolError && error.code === 'not_found'))
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
const retained = getRoomRecord(input.roomId);
|
|
323
|
+
if (retained?.workspace && !retained.task_id) {
|
|
324
|
+
assertWorkspaceDeletable(retained.workspace, 'room', input.roomId);
|
|
325
|
+
collectWorkspaceArchives(retained.workspace);
|
|
326
|
+
deleteWorkspace(retained.workspace, 'room', input.roomId);
|
|
327
|
+
}
|
|
328
|
+
if (retained)
|
|
329
|
+
await eraseMemberArtifacts('room', input.roomId, retained.member_seats, [input.roomId]);
|
|
330
|
+
if (retained?.task_id)
|
|
331
|
+
detachDeletedRoom(retained.task_id, input.roomId);
|
|
332
|
+
deleteRoomRecord(input.roomId);
|
|
333
|
+
return { room_id: input.roomId, deleted: true };
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
if (getRoomRecord(input.roomId))
|
|
337
|
+
setRoomCloseError(input.roomId, errorText(error), `Fix the cleanup error and explicitly retry room delete ${input.roomId} ${input.roomId}.`);
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
}, {}, CLOSE_LOCK_STALE_MS);
|
|
341
|
+
}
|
|
342
|
+
/** Recover only an authenticated seat tied to this exact room and issued invite.
|
|
343
|
+
* Display names and the current daemon name inventory are never binding proof.
|
|
344
|
+
*/
|
|
345
|
+
async function recoverMemberCids(room, cowork) {
|
|
346
|
+
if (!room.member_seats.some(seat => !seat.identity_cid))
|
|
347
|
+
return room;
|
|
348
|
+
const profile = room.member_seats.some(seat => seat.launch?.action_id) ? readClientProfile(process.env) : undefined;
|
|
349
|
+
let remote;
|
|
350
|
+
if (cowork.getRoom && room.room_identity_cid) {
|
|
351
|
+
try {
|
|
352
|
+
remote = await cowork.getRoom(room.room_id);
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
if (!(error instanceof CoworkProtocolError && error.code === 'not_found'))
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
if (remote && (remote.room_id !== room.room_id || remote.identity_cid.toLowerCase() !== room.room_identity_cid.toLowerCase()))
|
|
359
|
+
throw new Error('Room identity mismatch during deletion recovery');
|
|
206
360
|
}
|
|
207
|
-
|
|
208
|
-
|
|
361
|
+
const seats = room.member_seats.map(seat => {
|
|
362
|
+
let runtimeCid;
|
|
363
|
+
if (profile && seat.launch?.action_id) {
|
|
364
|
+
const dir = join(stateRoot(), 'private-ours', binderKey(profile.expectedInstanceId, seat.role_name));
|
|
365
|
+
try {
|
|
366
|
+
const state = JSON.parse(readFileSync(join(dir, 'state.json'), 'utf8'));
|
|
367
|
+
const instance = JSON.parse(readFileSync(join(dir, 'instance.json'), 'utf8'));
|
|
368
|
+
if (state.name === seat.role_name && state.daemon === profile.expectedInstanceId
|
|
369
|
+
&& state.lifetime === 'temporary' && state.action === seat.launch.action_id
|
|
370
|
+
&& instance.role === seat.role_name && instance.temporary === true && instance.instance === state.instance)
|
|
371
|
+
runtimeCid = state.cid;
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
if (error.code !== 'ENOENT')
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const matches = seat.invite_id ? remote?.seats.filter(value => value.invite_id === seat.invite_id && value.role === seat.cowork_role) ?? [] : [];
|
|
379
|
+
if (matches.length > 1)
|
|
380
|
+
throw new Error('Ambiguous authenticated member identity during deletion recovery');
|
|
381
|
+
const candidates = [seat.identity_cid, runtimeCid, matches[0]?.identity_cid].filter((v) => !!v);
|
|
382
|
+
if (candidates.some(cid => !/^[a-f0-9]{64}$/i.test(cid)))
|
|
383
|
+
throw new Error('Invalid authenticated member CID');
|
|
384
|
+
if (new Set(candidates.map(cid => cid.toLowerCase())).size > 1)
|
|
385
|
+
throw new Error('Contradictory authenticated member CID evidence');
|
|
386
|
+
return candidates.length ? { ...seat, identity_cid: candidates[0] } : seat;
|
|
387
|
+
});
|
|
388
|
+
return recordRetirementMemberCids(room.room_id, seats);
|
|
209
389
|
}
|
|
@@ -54,7 +54,9 @@ export function validateRoomsConfig(raw, vars, path) {
|
|
|
54
54
|
if (!isPlainObject(raw.cowork))
|
|
55
55
|
throw new RoomsTasksConfigError(path, 'rooms.cowork: must be a mapping');
|
|
56
56
|
rejectUnknown(raw.cowork, RCK, path, 'rooms.cowork');
|
|
57
|
-
|
|
57
|
+
if (raw.cowork.config !== undefined)
|
|
58
|
+
throw new RoomsTasksConfigError(path, 'rooms.cowork.config is no longer supported; remove it and configure ~/.ours-client/profile.json for all services');
|
|
59
|
+
cowork = {};
|
|
58
60
|
}
|
|
59
61
|
if (!isPlainObject(raw.owner))
|
|
60
62
|
throw new RoomsTasksConfigError(path, 'rooms.owner: required and must be a mapping');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Typed client for the ours-cowork v1
|
|
2
|
+
* Typed client for the ours-cowork v1 gateway management protocol.
|
|
3
3
|
*
|
|
4
4
|
* Cowork owns room state. Fleet only invokes the versioned JSON RPC exposed
|
|
5
|
-
*
|
|
5
|
+
* through the shared HTTP gateway and projects the response into orchestration data.
|
|
6
6
|
*/
|
|
7
7
|
import type { Socket } from 'node:net';
|
|
8
8
|
import type { RoomHistoryEvidence } from './types.js';
|
|
@@ -58,6 +58,10 @@ export interface CoworkAdapter {
|
|
|
58
58
|
briefing: string;
|
|
59
59
|
quiet_membership?: boolean;
|
|
60
60
|
anonymous?: boolean;
|
|
61
|
+
activation_requirements?: Array<{
|
|
62
|
+
role: string;
|
|
63
|
+
count: number;
|
|
64
|
+
}>;
|
|
61
65
|
}): Promise<CoworkRoomCreateResult>;
|
|
62
66
|
acceptInvite(roomId: string, invite: string, opts: {
|
|
63
67
|
role: string;
|
|
@@ -104,6 +108,4 @@ export interface CoworkAdapterOptions {
|
|
|
104
108
|
home?: string;
|
|
105
109
|
connect?: (path: string) => Socket;
|
|
106
110
|
}
|
|
107
|
-
/** Resolve the same config/state inputs as ours-cowork and return its Unix socket. */
|
|
108
|
-
export declare function resolveCoworkSocketPath(options?: CoworkAdapterOptions): string;
|
|
109
111
|
export declare function createCoworkAdapter(options?: CoworkAdapterOptions): CoworkAdapter;
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Typed client for the ours-cowork v1
|
|
2
|
+
* Typed client for the ours-cowork v1 gateway management protocol.
|
|
3
3
|
*
|
|
4
4
|
* Cowork owns room state. Fleet only invokes the versioned JSON RPC exposed
|
|
5
|
-
*
|
|
5
|
+
* through the shared HTTP gateway and projects the response into orchestration data.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { join, resolve } from 'node:path';
|
|
10
|
-
import { createConnection } from 'node:net';
|
|
11
|
-
const RPC_VERSION = 1;
|
|
7
|
+
import { readClientProfile } from '../client-profile.js';
|
|
8
|
+
import { coworkHttpCall } from './cowork-http.js';
|
|
12
9
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
13
|
-
const MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
14
10
|
export class CoworkUnavailableError extends Error {
|
|
15
|
-
constructor(message = 'Cowork management
|
|
11
|
+
constructor(message = 'Cowork gateway management is not reachable', options) {
|
|
16
12
|
super(message, options);
|
|
17
13
|
this.name = 'CoworkUnavailableError';
|
|
18
14
|
}
|
|
@@ -169,116 +165,13 @@ function projectHistoryRecord(value) {
|
|
|
169
165
|
}
|
|
170
166
|
return undefined;
|
|
171
167
|
}
|
|
172
|
-
/** Resolve the same config/state inputs as ours-cowork and return its Unix socket. */
|
|
173
|
-
export function resolveCoworkSocketPath(options = {}) {
|
|
174
|
-
if (options.socketPath)
|
|
175
|
-
return resolve(options.socketPath);
|
|
176
|
-
const env = options.env ?? process.env;
|
|
177
|
-
const home = options.home ?? homedir();
|
|
178
|
-
const configuredPath = options.configPath ?? env.OURS_COWORK_CONFIG;
|
|
179
|
-
const configPath = resolve(configuredPath ?? join(home, '.ours-cowork', 'config.json'));
|
|
180
|
-
let stateDir = resolve(home, '.ours-cowork');
|
|
181
|
-
if (existsSync(configPath)) {
|
|
182
|
-
let parsed;
|
|
183
|
-
try {
|
|
184
|
-
parsed = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
throw new CoworkProtocolError('config', `malformed config at ${configPath}`, 'invalid_config', { cause: error });
|
|
188
|
-
}
|
|
189
|
-
const config = object(parsed, 'config', 'config');
|
|
190
|
-
if (config.version !== 1 || typeof config.stateDir !== 'string' || !config.stateDir)
|
|
191
|
-
throw new CoworkProtocolError('config', `invalid Cowork v1 config at ${configPath}`, 'invalid_config');
|
|
192
|
-
stateDir = resolve(config.stateDir);
|
|
193
|
-
}
|
|
194
|
-
else if (configuredPath !== undefined) {
|
|
195
|
-
throw new CoworkProtocolError('config', `configured Cowork config does not exist: ${configPath}`, 'invalid_config');
|
|
196
|
-
}
|
|
197
|
-
if (env.OURS_COWORK_STATE_DIR)
|
|
198
|
-
stateDir = resolve(env.OURS_COWORK_STATE_DIR);
|
|
199
|
-
return join(stateDir, 'management.sock');
|
|
200
|
-
}
|
|
201
|
-
function rpcCall(socketPath, method, params, timeoutMs, connect) {
|
|
202
|
-
const id = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
203
|
-
const request = `${JSON.stringify({ version: RPC_VERSION, id, method, params })}\n`;
|
|
204
|
-
return new Promise((resolveCall, rejectCall) => {
|
|
205
|
-
const socket = connect(socketPath);
|
|
206
|
-
let bytes = '';
|
|
207
|
-
let size = 0;
|
|
208
|
-
let settled = false;
|
|
209
|
-
let connected = false;
|
|
210
|
-
const finishError = (error) => {
|
|
211
|
-
if (settled)
|
|
212
|
-
return;
|
|
213
|
-
settled = true;
|
|
214
|
-
clearTimeout(timer);
|
|
215
|
-
socket.destroy();
|
|
216
|
-
rejectCall(error);
|
|
217
|
-
};
|
|
218
|
-
const timer = setTimeout(() => finishError(new CoworkUnavailableError(connected ? 'Cowork did not answer the management socket' : 'Cowork management socket is not reachable')), timeoutMs);
|
|
219
|
-
socket.setEncoding('utf8');
|
|
220
|
-
socket.once('connect', () => {
|
|
221
|
-
connected = true;
|
|
222
|
-
socket.write(request);
|
|
223
|
-
});
|
|
224
|
-
socket.on('data', (chunk) => {
|
|
225
|
-
if (settled)
|
|
226
|
-
return;
|
|
227
|
-
const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
|
228
|
-
size += Buffer.byteLength(text);
|
|
229
|
-
if (size > MAX_RESPONSE_BYTES) {
|
|
230
|
-
finishError(new CoworkProtocolError(method, 'response exceeded 4 MiB'));
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
bytes += text;
|
|
234
|
-
const newline = bytes.indexOf('\n');
|
|
235
|
-
if (newline < 0)
|
|
236
|
-
return;
|
|
237
|
-
if (bytes.slice(newline + 1).trim() !== '') {
|
|
238
|
-
finishError(new CoworkProtocolError(method, 'daemon returned more than one response'));
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
let response;
|
|
242
|
-
try {
|
|
243
|
-
response = object(JSON.parse(bytes.slice(0, newline)), method, 'RPC response');
|
|
244
|
-
}
|
|
245
|
-
catch (error) {
|
|
246
|
-
finishError(error instanceof CoworkProtocolError
|
|
247
|
-
? error : new CoworkProtocolError(method, 'daemon returned malformed JSON', 'protocol_error', { cause: error }));
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
if (response.version !== RPC_VERSION || response.id !== id
|
|
251
|
-
|| (Object.hasOwn(response, 'error') === Object.hasOwn(response, 'result'))) {
|
|
252
|
-
finishError(new CoworkProtocolError(method, 'daemon returned an invalid RPC response'));
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
settled = true;
|
|
256
|
-
clearTimeout(timer);
|
|
257
|
-
socket.destroy();
|
|
258
|
-
if (Object.hasOwn(response, 'error')) {
|
|
259
|
-
const error = object(response.error, method, 'RPC error');
|
|
260
|
-
rejectCall(new CoworkProtocolError(method, typeof error.message === 'string' ? error.message : 'unknown RPC error', typeof error.code === 'string' ? error.code : 'rpc_error'));
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
resolveCall(response.result);
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
socket.once('end', () => {
|
|
267
|
-
if (!settled)
|
|
268
|
-
finishError(new CoworkProtocolError(method, 'daemon closed without a complete response'));
|
|
269
|
-
});
|
|
270
|
-
socket.once('error', (error) => {
|
|
271
|
-
if (!settled)
|
|
272
|
-
finishError(new CoworkUnavailableError(error.code === 'EACCES' || error.code === 'EPERM'
|
|
273
|
-
? 'Cowork management socket access denied' : 'Cowork management socket is not reachable', { cause: error }));
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
168
|
export function createCoworkAdapter(options = {}) {
|
|
278
|
-
const
|
|
169
|
+
const env = options.env ?? process.env;
|
|
170
|
+
if (options.socketPath !== undefined || options.configPath !== undefined)
|
|
171
|
+
throw new CoworkProtocolError('config', 'Local Cowork selectors are unsupported; configure the shared gateway client profile', 'invalid_config');
|
|
172
|
+
const profile = readClientProfile({ ...env, HOME: options.home ?? env.HOME });
|
|
279
173
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
280
|
-
const
|
|
281
|
-
const call = (method, params) => rpcCall(socketPath, method, params, timeoutMs, connect);
|
|
174
|
+
const call = (method, params) => coworkHttpCall(profile, method, params, timeoutMs);
|
|
282
175
|
return {
|
|
283
176
|
async available() {
|
|
284
177
|
try {
|
|
@@ -296,6 +189,7 @@ export function createCoworkAdapter(options = {}) {
|
|
|
296
189
|
briefing: opts.briefing,
|
|
297
190
|
...(opts.quiet_membership === undefined ? {} : { quiet_membership: opts.quiet_membership }),
|
|
298
191
|
...(opts.anonymous === undefined ? {} : { anonymous: opts.anonymous }),
|
|
192
|
+
...(opts.activation_requirements === undefined ? {} : { activation_requirements: opts.activation_requirements }),
|
|
299
193
|
}), 'room.create');
|
|
300
194
|
if (!result.identity_cid)
|
|
301
195
|
throw new CoworkProtocolError('room.create', 'created room did not establish an identity CID');
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ExplicitClientProfile } from '../client-profile.js';
|
|
2
|
+
/** Same RPC protocol as the local socket; never replay a possibly delivered mutation. */
|
|
3
|
+
export declare function coworkHttpCall(profile: ExplicitClientProfile, method: string, params: Record<string, unknown>, timeoutMs: number): Promise<unknown>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { attachOursClient } from '@ours.network/sdk/client';
|
|
3
|
+
import { readPrivateFile } from '@ours.network/sdk/connector';
|
|
4
|
+
import { CoworkProtocolError, CoworkUnavailableError } from './cowork-adapter.js';
|
|
5
|
+
/** Same RPC protocol as the local socket; never replay a possibly delivered mutation. */
|
|
6
|
+
export async function coworkHttpCall(profile, method, params, timeoutMs) {
|
|
7
|
+
const id = randomUUID();
|
|
8
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
9
|
+
const body = JSON.stringify({ version: 1, id, method, params });
|
|
10
|
+
if (Buffer.byteLength(body) > 1024 * 1024)
|
|
11
|
+
throw new CoworkProtocolError(method, 'request exceeded 1 MiB');
|
|
12
|
+
try {
|
|
13
|
+
const client = await attachOursClient({ endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
|
|
14
|
+
credentialPath: profile.credentialPath, sessionMode: 'external', leaseToken: `fleet-cowork-check-${id}`, env: {}, requestSignal: signal });
|
|
15
|
+
await client.close();
|
|
16
|
+
const token = readPrivateFile(profile.credentialPath, 4096).toString('utf8').trim();
|
|
17
|
+
const response = await fetch(profile.serverUrl + '/cowork/management/rpc', {
|
|
18
|
+
method: 'POST', redirect: 'error', signal,
|
|
19
|
+
headers: { 'content-type': 'application/json', 'x-ours-api-token': token },
|
|
20
|
+
body,
|
|
21
|
+
});
|
|
22
|
+
if (response.status === 401 || response.status === 403) {
|
|
23
|
+
await response.body?.cancel();
|
|
24
|
+
throw new CoworkProtocolError(method, 'server credential was rejected', 'unauthorized');
|
|
25
|
+
}
|
|
26
|
+
const reader = response.body?.getReader();
|
|
27
|
+
if (!reader)
|
|
28
|
+
throw new CoworkProtocolError(method, 'empty HTTP response');
|
|
29
|
+
const chunks = [];
|
|
30
|
+
let size = 0;
|
|
31
|
+
try {
|
|
32
|
+
for (;;) {
|
|
33
|
+
const { done, value } = await reader.read();
|
|
34
|
+
if (done)
|
|
35
|
+
break;
|
|
36
|
+
size += value.length;
|
|
37
|
+
if (size > 4 * 1024 * 1024)
|
|
38
|
+
throw new CoworkProtocolError(method, 'response exceeded 4 MiB');
|
|
39
|
+
chunks.push(value);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await reader.cancel();
|
|
44
|
+
}
|
|
45
|
+
let rpc;
|
|
46
|
+
try {
|
|
47
|
+
rpc = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new CoworkProtocolError(method, 'server returned malformed JSON');
|
|
51
|
+
}
|
|
52
|
+
if (!rpc || Array.isArray(rpc) || rpc.version !== 1 || rpc.id !== id
|
|
53
|
+
|| Object.hasOwn(rpc, 'result') === Object.hasOwn(rpc, 'error'))
|
|
54
|
+
throw new CoworkProtocolError(method, 'server returned an invalid RPC response');
|
|
55
|
+
if (Object.hasOwn(rpc, 'error')) {
|
|
56
|
+
const error = rpc.error;
|
|
57
|
+
if (!error || typeof error.code !== 'string' || typeof error.message !== 'string')
|
|
58
|
+
throw new CoworkProtocolError(method, 'server returned an invalid RPC error');
|
|
59
|
+
throw new CoworkProtocolError(method, error.message, error.code);
|
|
60
|
+
}
|
|
61
|
+
if (!response.ok)
|
|
62
|
+
throw new CoworkProtocolError(method, `management answered HTTP ${response.status}`);
|
|
63
|
+
return rpc.result;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof CoworkProtocolError)
|
|
67
|
+
throw error;
|
|
68
|
+
throw new CoworkUnavailableError('Cowork HTTP management failed; check the selected server and credential', { cause: error });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -3,7 +3,7 @@ import { type CoworkAdapter } from './cowork-adapter.js';
|
|
|
3
3
|
import { type TaskDeletionAcceptance } from './task-state.js';
|
|
4
4
|
import type { TaskDeletionActor, TaskRecord } from './types.js';
|
|
5
5
|
export { DELETION_MEMBER_ABSENT_VERIFIED } from './task-state.js';
|
|
6
|
-
type DeletionCowork = Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'
|
|
6
|
+
type DeletionCowork = Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
7
7
|
export interface TaskDeletionSettleDeps {
|
|
8
8
|
roomClose?: RoomCloseDeps;
|
|
9
9
|
/** Test seam for the temp-state existence proof. */
|