@ours.network/fleet 1.2.0-nightly.6 → 1.2.0-nightly.61
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 +287 -65
- package/dist/account-origin.d.ts +2 -0
- package/dist/account-origin.js +6 -0
- package/dist/agent-ours/bridge.js +35 -9
- 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 +12 -0
- package/dist/agent-ours/file-rpc.js +18 -4
- package/dist/agent-ours/harness.js +9 -1
- package/dist/agent-ours/mcp-endpoint.d.ts +4 -0
- package/dist/agent-ours/mcp-endpoint.js +5 -0
- package/dist/agent-ours/runtime.d.ts +9 -1
- package/dist/agent-ours/runtime.js +50 -2
- package/dist/agent-ours/service.d.ts +21 -1
- package/dist/agent-ours/service.js +94 -14
- package/dist/application/codex-models.d.ts +15 -0
- package/dist/application/codex-models.js +56 -0
- package/dist/application/conversation-history.d.ts +27 -0
- package/dist/application/conversation-history.js +212 -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/log-service.js +8 -8
- 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/role-creation-service.js +3 -2
- package/dist/application/role-removal-service.js +9 -1
- package/dist/application/role-repository.js +19 -2
- 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 +30 -0
- package/dist/application/session-control.js +72 -3
- package/dist/application/supervisor-ours-tools.d.ts +159 -0
- package/dist/application/supervisor-ours-tools.js +115 -0
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +259 -0
- package/dist/application/task-room-service.d.ts +99 -3
- package/dist/application/task-room-service.js +285 -32
- package/dist/application/types.d.ts +2 -0
- package/dist/atomic-file.d.ts +5 -0
- package/dist/atomic-file.js +62 -1
- package/dist/briefing.d.ts +3 -1
- package/dist/briefing.js +70 -30
- package/dist/build-info.json +7 -4
- package/dist/capabilities.d.ts +6 -1
- package/dist/capabilities.js +8 -0
- package/dist/cli.js +407 -37
- package/dist/client-profile.d.ts +5 -17
- package/dist/client-profile.js +4 -127
- package/dist/config.d.ts +45 -0
- package/dist/config.js +57 -6
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +4 -4
- package/dist/daemon-recovery.d.ts +1 -8
- package/dist/daemon-recovery.js +8 -113
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +123 -19
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +55 -60
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/file-delivery/reader.d.ts +15 -0
- package/dist/file-delivery/reader.js +63 -0
- package/dist/file-delivery/store.d.ts +15 -0
- package/dist/file-delivery/store.js +124 -0
- package/dist/file-delivery/types.d.ts +19 -0
- package/dist/file-delivery/types.js +1 -0
- package/dist/fleet-command-audit.d.ts +7 -0
- package/dist/fleet-command-audit.js +26 -9
- package/dist/harness/agent-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +1 -1
- package/dist/harness/claude-code.js +20 -11
- package/dist/harness/claude-runtime.d.ts +12 -0
- package/dist/harness/claude-runtime.js +43 -0
- 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-reasoning.d.ts +5 -0
- package/dist/harness/codex-reasoning.js +12 -0
- package/dist/harness/codex-runtime.d.ts +11 -1
- package/dist/harness/codex-runtime.js +31 -4
- package/dist/harness/codex-session.js +2 -2
- package/dist/harness/codex.js +23 -12
- package/dist/init-wizard.d.ts +2 -0
- package/dist/init-wizard.js +38 -19
- package/dist/isolation/policy.js +6 -1
- package/dist/isolation/types.d.ts +5 -0
- package/dist/managed-cli.d.ts +253 -0
- package/dist/managed-cli.js +923 -0
- package/dist/managed-recovery.d.ts +13 -0
- package/dist/managed-recovery.js +31 -0
- package/dist/minimal-setup.d.ts +2 -0
- package/dist/minimal-setup.js +44 -0
- package/dist/monitor.d.ts +8 -34
- package/dist/monitor.js +89 -152
- package/dist/notifications/fleet-producer.d.ts +19 -0
- package/dist/notifications/fleet-producer.js +208 -0
- package/dist/notifications/outbox.d.ts +46 -0
- package/dist/notifications/outbox.js +158 -0
- package/dist/notifications/target-cleanup.d.ts +8 -0
- package/dist/notifications/target-cleanup.js +41 -0
- package/dist/notifications/task-producer.d.ts +18 -0
- package/dist/notifications/task-producer.js +67 -0
- package/dist/ops.d.ts +2 -0
- package/dist/ops.js +20 -3
- package/dist/owner-channel/channel.js +17 -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/paths.d.ts +2 -0
- package/dist/paths.js +2 -0
- package/dist/preset-migration.js +25 -0
- package/dist/resolved-plan.js +1 -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 +65 -5
- package/dist/rooms-tasks/close.d.ts +6 -2
- package/dist/rooms-tasks/close.js +246 -37
- package/dist/rooms-tasks/config.d.ts +1 -1
- package/dist/rooms-tasks/config.js +11 -4
- package/dist/rooms-tasks/cowork-adapter.d.ts +2 -4
- package/dist/rooms-tasks/cowork-adapter.js +7 -121
- package/dist/rooms-tasks/cowork-http.js +29 -1
- package/dist/rooms-tasks/deletion.d.ts +1 -1
- package/dist/rooms-tasks/deletion.js +84 -5
- package/dist/rooms-tasks/erasure.d.ts +6 -0
- package/dist/rooms-tasks/erasure.js +173 -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-member-retirement.d.ts +10 -0
- package/dist/rooms-tasks/layout-member-retirement.js +90 -0
- package/dist/rooms-tasks/layout-service.d.ts +43 -0
- package/dist/rooms-tasks/layout-service.js +203 -0
- package/dist/rooms-tasks/layout.d.ts +121 -0
- package/dist/rooms-tasks/layout.js +285 -0
- package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
- package/dist/rooms-tasks/legacy-task-member.js +116 -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-ownership.d.ts +5 -0
- package/dist/rooms-tasks/member-ownership.js +40 -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 +3 -0
- package/dist/rooms-tasks/provision.js +101 -49
- package/dist/rooms-tasks/recovery.d.ts +19 -0
- package/dist/rooms-tasks/recovery.js +110 -0
- package/dist/rooms-tasks/room-state.d.ts +4 -2
- package/dist/rooms-tasks/room-state.js +47 -8
- package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
- package/dist/rooms-tasks/task-service-retirement.js +21 -0
- package/dist/rooms-tasks/task-state.d.ts +51 -8
- package/dist/rooms-tasks/task-state.js +245 -25
- package/dist/rooms-tasks/types.d.ts +40 -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 +35 -0
- package/dist/rooms-tasks/workspace.js +325 -0
- package/dist/runner.d.ts +25 -3
- package/dist/runner.js +291 -49
- package/dist/session/acp.d.ts +53 -1
- package/dist/session/acp.js +216 -40
- package/dist/session/arbiter.d.ts +11 -0
- package/dist/session/arbiter.js +43 -2
- package/dist/session/codex-app-server.d.ts +32 -0
- package/dist/session/codex-app-server.js +137 -23
- package/dist/session/control.d.ts +12 -1
- package/dist/session/control.js +68 -3
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-store.d.ts +1 -1
- package/dist/session/conversation-store.js +7 -11
- package/dist/session/conversation-types.d.ts +28 -3
- package/dist/session/prompt-batch.d.ts +63 -0
- package/dist/session/prompt-batch.js +86 -0
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +14 -0
- package/dist/setup-tunnel-preflight.d.ts +34 -0
- package/dist/setup-tunnel-preflight.js +62 -0
- package/dist/socket-path.d.ts +2 -0
- package/dist/socket-path.js +22 -0
- package/dist/spawn.d.ts +5 -1
- package/dist/spawn.js +40 -4
- package/dist/startup-prompt.d.ts +4 -0
- package/dist/startup-prompt.js +36 -0
- package/dist/startup-readiness.d.ts +13 -0
- package/dist/startup-readiness.js +38 -0
- package/dist/startup-telemetry.d.ts +16 -0
- package/dist/startup-telemetry.js +46 -0
- package/dist/subscriptions/cli.d.ts +91 -0
- package/dist/subscriptions/cli.js +223 -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/adoption.d.ts +8 -0
- package/dist/supervisor/adoption.js +78 -0
- package/dist/supervisor/catalog.d.ts +62 -0
- package/dist/supervisor/catalog.js +254 -0
- package/dist/supervisor/fleet.d.ts +8 -0
- package/dist/supervisor/fleet.js +89 -0
- package/dist/supervisor/index.js +3 -6
- package/dist/supervisor/launchd.d.ts +1 -1
- package/dist/supervisor/launchd.js +26 -13
- package/dist/supervisor/legacy.d.ts +35 -0
- package/dist/supervisor/legacy.js +524 -0
- package/dist/supervisor/manager.d.ts +15 -0
- package/dist/supervisor/manager.js +270 -0
- package/dist/supervisor/scope.d.ts +4 -0
- package/dist/supervisor/scope.js +10 -0
- package/dist/supervisor/systemd.d.ts +2 -2
- package/dist/supervisor/systemd.js +19 -33
- package/dist/task-supervision.d.ts +9 -0
- package/dist/task-supervision.js +145 -0
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +23 -8
- package/dist/temp-lifecycle.js +113 -65
- package/dist/temp-supervisor-recovery.d.ts +1 -1
- package/dist/temp-supervisor-recovery.js +2 -2
- package/dist/tunnel-setup-completion.d.ts +7 -0
- package/dist/tunnel-setup-completion.js +13 -0
- package/dist/tunnel-setup-input.d.ts +19 -0
- package/dist/tunnel-setup-input.js +124 -0
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +63 -2
- package/dist/web/auth.js +191 -10
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/control.d.ts +3 -3
- package/dist/web/control.js +10 -8
- 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 +32 -0
- package/dist/web/prefix-gateway.js +238 -0
- package/dist/web/runtime.d.ts +3 -1
- package/dist/web/runtime.js +116 -31
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.js +654 -55
- package/dist/web/service.d.ts +11 -2
- package/dist/web/service.js +30 -4
- package/dist/web/workspace-devices.d.ts +107 -0
- package/dist/web/workspace-devices.js +277 -0
- package/dist/web/workspace-tunnel.d.ts +1 -0
- package/dist/web/workspace-tunnel.js +34 -0
- package/dist/workspace-enrollment.d.ts +82 -0
- package/dist/workspace-enrollment.js +566 -0
- package/dist/workspace-replacement.d.ts +66 -0
- package/dist/workspace-replacement.js +220 -0
- package/docs/acp-files.md +146 -0
- package/docs/fleet-migration.md +54 -0
- package/docs/live-voice.md +13 -0
- package/docs/room-layouts.md +227 -0
- package/docs/task-workspaces.md +225 -0
- package/docs/validation/managed-cli-permissions.md +421 -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 +20 -19
- package/presets/README.md +78 -0
- package/presets/brain-catalog.json +8 -2
- package/presets/fleet/agent_templates/Critic.yaml +1 -1
- package/presets/fleet/agent_templates/Developer.yaml +1 -1
- package/presets/fleet/agent_templates/Engineer.yaml +5 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
- package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
- 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 +34 -11
- 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/index.html +0 -17
- package/dist/web-app/manifest.webmanifest +0 -15
- package/dist/web-app/offline.html +0 -18
- package/dist/web-app/sw.js +0 -51
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { beginWorkspaceReplacement, abandonWorkspaceReplacement, discardRetiredWorkspaceReplacement, clearWorkspaceReplacement, confirmWorkspaceReplacement, finishWorkspaceReplacement, readWorkspaceBinding, readWorkspaceReplacement, requiresWorkspaceReplacement, refreshWorkspaceReplacement } from './workspace-replacement.js';
|
|
3
|
+
import { completeTunnelSetup } from './tunnel-setup-completion.js';
|
|
4
|
+
import { readTunnelSetupFile, readTunnelSetupStdin, readTunnelSetupArgument, redeemTunnelSetup, inspectTunnelSetup, verifyTunnelSetupTarget } from './tunnel-setup-input.js';
|
|
5
|
+
import { ensureMinimalSetup } from './minimal-setup.js';
|
|
6
|
+
import { confirmWorkspaceTarget, checkWorkspaceConnector } from './workspace-enrollment.js';
|
|
7
|
+
import { clearPendingTunnelSetup, readPendingTunnelSetup, requiredPortAfterExpiry, savePendingTunnelSetup, setupTunnelPreflight } from './setup-tunnel-preflight.js';
|
|
8
|
+
import { availableWebPort } from './web/available-port.js';
|
|
9
|
+
import QRCode from 'qrcode';
|
|
10
|
+
import { readWorkspacePayload, enrollWorkspace, checkWorkspaceConfiguration } from './workspace-enrollment.js';
|
|
11
|
+
import { waitForRoleDaemon } from './startup-readiness.js';
|
|
12
|
+
import { SupervisorOursTools } from './application/supervisor-ours-tools.js';
|
|
2
13
|
import { runTempSupervisor, TEMP_RECYCLE_EXIT } from './temp-supervisor-recovery.js';
|
|
3
14
|
import { spawn as spawnChild } from 'node:child_process';
|
|
4
15
|
import { randomUUID } from 'node:crypto';
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, statSync } from 'node:fs';
|
|
16
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync, rmSync } from 'node:fs';
|
|
6
17
|
import { realpathSync } from 'node:fs';
|
|
7
18
|
import { join as joinPath, resolve as resolvePath } from 'node:path';
|
|
8
19
|
import { createInterface } from 'node:readline';
|
|
@@ -12,7 +23,7 @@ import { INIT_COMPLETION_GUIDANCE } from './init-guidance.js';
|
|
|
12
23
|
import { migrateLegacyStarterPresets, migratePackagedRoleDefaults } from './preset-migration.js';
|
|
13
24
|
import { executeInitAnswers, executeInitWizard, isInteractiveTerminal, publishSetup, readInitSettings, TerminalPrompter, } from './init-wizard.js';
|
|
14
25
|
import { analyzeInstalls, buildInfo, buildLabel, discoverInstalls, runningLabel, } from './provenance.js';
|
|
15
|
-
import { agentDir, agentsRoot, tmpRoot, logsRoot, deriveXdgRuntimeDir, defaultConfigPath } from './paths.js';
|
|
26
|
+
import { agentDir, agentsRoot, tmpRoot, logsRoot, deriveXdgRuntimeDir, defaultConfigPath, stateRoot } from './paths.js';
|
|
16
27
|
import { findRole, loadConfig, ROLE_NAME_RE } from './config.js';
|
|
17
28
|
import { formatDuration } from './duration.js';
|
|
18
29
|
import { redactSensitive, resolvedPlan, resolvedRolePlan } from './resolved-plan.js';
|
|
@@ -37,7 +48,7 @@ import { controlRequest, controlSocketPath, followControl, livenessNote, } from
|
|
|
37
48
|
import { SessionControlError } from './session/types.js';
|
|
38
49
|
import { readScheduledLoops, storedLoopHealth } from './loops/state.js';
|
|
39
50
|
import { startWebConsole } from './web/runtime.js';
|
|
40
|
-
import { requestWebControl } from './web/control.js';
|
|
51
|
+
import { requestWebControl, webControlPath } from './web/control.js';
|
|
41
52
|
import { WebServiceManager } from './web/service.js';
|
|
42
53
|
import { WebAccessStore, passwordAccess, validatePublicOrigin } from './web/access.js';
|
|
43
54
|
import { FLEET_PROXY_CALLER_ENV, FLEET_PROXY_STATE_DIR_ENV, } from './fleet-proxy.js';
|
|
@@ -45,6 +56,9 @@ import { beginFleetAuditCollection, consumeFleetAuditCollection, FleetCliExit, s
|
|
|
45
56
|
import './harness/claude-code.js'; // registers the claude-code adapter
|
|
46
57
|
import './harness/codex.js'; // registers the codex adapter
|
|
47
58
|
import './harness/hermes.js';
|
|
59
|
+
import { registerLayoutCommands } from './rooms-tasks/layout-cli.js';
|
|
60
|
+
import { MANAGED_CONFIGURATION_FLAG, assertPinnedConfiguration, enableManagedCli, managedCliReport, parseManagedEntry, } from './managed-cli.js';
|
|
61
|
+
import { MANAGED_CLI_WORKFLOW_IDS } from './config.js';
|
|
48
62
|
import { registerTemplateCommands, registerTaskCommands, registerRoomCommands } from './rooms-tasks/cli.js';
|
|
49
63
|
import { RoleCreationService } from './application/role-creation-service.js';
|
|
50
64
|
import { RoleRemovalService } from './application/role-removal-service.js';
|
|
@@ -88,6 +102,22 @@ const program = new Command()
|
|
|
88
102
|
.exitOverride()
|
|
89
103
|
.version(VERSION);
|
|
90
104
|
const cOpt = (cmd) => cmd.option('-c, --configuration <file>', 'manifest (default: ~/fleet.yaml; documents under ~/fleet/)');
|
|
105
|
+
/**
|
|
106
|
+
* Set only for the pinned managed entry form (see src/managed-cli.ts). Checked
|
|
107
|
+
* against the PARSED option, so every spelling of a later `-c` is covered.
|
|
108
|
+
*/
|
|
109
|
+
let pinnedConfiguration;
|
|
110
|
+
program.hook('preAction', (_program, action) => {
|
|
111
|
+
if (pinnedConfiguration === undefined)
|
|
112
|
+
return;
|
|
113
|
+
try {
|
|
114
|
+
assertPinnedConfiguration(pinnedConfiguration, action.opts().configuration);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
console.error(`error: ${error.message}`);
|
|
118
|
+
throw new FleetCliExit(1, 'validation', 'not_started');
|
|
119
|
+
}
|
|
120
|
+
});
|
|
91
121
|
const collect = (value, previous) => [...previous, value];
|
|
92
122
|
program.command('docs')
|
|
93
123
|
.alias('man')
|
|
@@ -496,6 +526,40 @@ program.command('peek <name> [lines]').description('pane snapshot without attach
|
|
|
496
526
|
die(controlFailure(name, 'peek', e));
|
|
497
527
|
}
|
|
498
528
|
});
|
|
529
|
+
const oursToolsCommand = program.command('ours').description('invoke tools through a named agent supervisor and its fixed identity');
|
|
530
|
+
oursToolsCommand.command('tools <agent>').description('list the same tools and schemas exposed to the agent MCP')
|
|
531
|
+
.action(async (agent) => {
|
|
532
|
+
try {
|
|
533
|
+
console.log(JSON.stringify(await new SupervisorOursTools().list(agent), null, 2));
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
die(error);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
oursToolsCommand.command('call <agent> <tool>').description('call a supervisor MCP tool without prompting the agent')
|
|
540
|
+
.option('--args-file <path>', 'JSON object arguments from a private file; omitted means {}')
|
|
541
|
+
.action(async (agent, tool, options) => {
|
|
542
|
+
try {
|
|
543
|
+
let args = {};
|
|
544
|
+
if (options.argsFile) {
|
|
545
|
+
try {
|
|
546
|
+
args = JSON.parse(readFileSync(options.argsFile, 'utf8'));
|
|
547
|
+
}
|
|
548
|
+
catch {
|
|
549
|
+
throw new Error('cannot read tool arguments: expected a readable JSON object file');
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
const response = await new SupervisorOursTools().call(agent, { tool, arguments: args });
|
|
553
|
+
console.log(JSON.stringify(response, null, 2));
|
|
554
|
+
if ('isError' in response.result && response.result.isError)
|
|
555
|
+
throw new FleetCliExit(1, 'runtime', 'unknown');
|
|
556
|
+
}
|
|
557
|
+
catch (error) {
|
|
558
|
+
if (error instanceof FleetCliExit)
|
|
559
|
+
throw error;
|
|
560
|
+
die(error);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
499
563
|
program.command('send <name> [text...]').description("type into the agent's console")
|
|
500
564
|
.action(async (name, text, opts) => {
|
|
501
565
|
const stateDir = acpStateDir(name);
|
|
@@ -553,7 +617,7 @@ cOpt(program.command('status <name>').description('declared persistent Agent uni
|
|
|
553
617
|
+ `${ledger.lastTermination.runStartedAt ?? 'unknown'}) died without an orderly exit; `
|
|
554
618
|
+ `observed ${ledger.lastTermination.observedAt}`
|
|
555
619
|
+ `\n abrupt terminations recorded: ${ledger.abruptTerminations ?? 1}`
|
|
556
|
-
+ `\n
|
|
620
|
+
+ `\n inspect member output: ours-fleet logs ${name}`);
|
|
557
621
|
const modelStatus = joinPath(agentDir(name), '.model-status');
|
|
558
622
|
if (existsSync(modelStatus)) {
|
|
559
623
|
try {
|
|
@@ -1254,6 +1318,78 @@ cOpt(program.command('spawn [name]').description('spawn a new agent (permanent b
|
|
|
1254
1318
|
die(e);
|
|
1255
1319
|
}
|
|
1256
1320
|
});
|
|
1321
|
+
function renderManagedCliReport(report) {
|
|
1322
|
+
const lines = [
|
|
1323
|
+
`Managed CLI setup for ${report.configuration}`,
|
|
1324
|
+
` node ${report.node}`, ` cli ${report.cli}`,
|
|
1325
|
+
` platform ${report.platform.os}${report.platform.declared ? '' : ' (not a declared platform)'}`,
|
|
1326
|
+
];
|
|
1327
|
+
for (const role of report.roles) {
|
|
1328
|
+
if (role.setup.state === 'not-declared')
|
|
1329
|
+
continue;
|
|
1330
|
+
lines.push('', `${role.role} (${role.harness}/${role.session}) — ${role.workflows.join(', ')}`);
|
|
1331
|
+
lines.push(` setup (static): ${role.setup.state}${role.setup.action ? ` [${role.setup.action}]` : ''} — ${role.setup.detail}`);
|
|
1332
|
+
if (role.setup.artifact)
|
|
1333
|
+
lines.push(` ${role.setup.artifact}`);
|
|
1334
|
+
lines.push(` running session: ${role.session_policy}`);
|
|
1335
|
+
lines.push(` observed (audit ledger): ${role.observed.summary}`);
|
|
1336
|
+
if (role.commandPrefix)
|
|
1337
|
+
lines.push(` invoke as: ${role.commandPrefix} <command>`);
|
|
1338
|
+
for (const line of role.scope)
|
|
1339
|
+
lines.push(` scope: ${line}`);
|
|
1340
|
+
for (const line of role.warnings)
|
|
1341
|
+
lines.push(` note: ${line}`);
|
|
1342
|
+
}
|
|
1343
|
+
if (!report.roles.some(role => role.setup.state !== 'not-declared'))
|
|
1344
|
+
lines.push('', 'No agent declares managed_cli. Nothing was generated and no permission changed.', 'Enable it for one agent with: ours-fleet managed-cli setup --enable <Agent>');
|
|
1345
|
+
for (const item of report.removed)
|
|
1346
|
+
lines.push('', `${item.action}: ${item.path} — ${item.detail ?? ''}`);
|
|
1347
|
+
lines.push('', ...report.disclosure.map(line => `* ${line}`));
|
|
1348
|
+
return lines.join('\n');
|
|
1349
|
+
}
|
|
1350
|
+
const managedCliCommand = program.command('managed-cli')
|
|
1351
|
+
.description('prepare and inspect native harness policy for Fleet commands run from a command sandbox');
|
|
1352
|
+
for (const [name, write, description] of [
|
|
1353
|
+
['setup', true, 'generate the policy for agents declaring managed_cli; starts no session and no model'],
|
|
1354
|
+
['status', false, 'compare generated policy and observed supervisor access without changing anything'],
|
|
1355
|
+
]) {
|
|
1356
|
+
const command = cOpt(managedCliCommand.command(name).description(description)).option('--json', 'JSON output');
|
|
1357
|
+
if (write)
|
|
1358
|
+
command.option('--enable <agent>', 'first add managed_cli: [task-workflow] to this Agent file (repeatable); its permissions are not changed', (value, all) => [...all, value], [])
|
|
1359
|
+
.option('--workflow <id>', `workflow --enable adds (${MANAGED_CLI_WORKFLOW_IDS.join(', ')})`, 'task-workflow');
|
|
1360
|
+
command.action((opts) => {
|
|
1361
|
+
try {
|
|
1362
|
+
const enabled = [];
|
|
1363
|
+
if (opts.enable?.length) {
|
|
1364
|
+
if (!MANAGED_CLI_WORKFLOW_IDS.includes(opts.workflow ?? ''))
|
|
1365
|
+
throw new Error(`unknown workflow '${opts.workflow}'; supported: ${MANAGED_CLI_WORKFLOW_IDS.join(', ')}`);
|
|
1366
|
+
// Validate every name before the first file is touched.
|
|
1367
|
+
const cfg = loadConfig(opts.configuration);
|
|
1368
|
+
for (const agent of opts.enable)
|
|
1369
|
+
findRole(cfg, agent);
|
|
1370
|
+
for (const agent of opts.enable)
|
|
1371
|
+
enabled.push({ agent, ...enableManagedCli(opts.configuration, agent, opts.workflow) });
|
|
1372
|
+
}
|
|
1373
|
+
const report = managedCliReport(loadConfig(opts.configuration), opts.configuration, { write });
|
|
1374
|
+
if (opts.json) {
|
|
1375
|
+
console.log(JSON.stringify({ ...report, enabled }, null, 2));
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
for (const item of enabled)
|
|
1379
|
+
console.log(`${item.changed ? 'Enabled' : 'Already enabled'} ${opts.workflow} for ${item.agent} in ${item.file}`);
|
|
1380
|
+
console.log(renderManagedCliReport(report));
|
|
1381
|
+
}
|
|
1382
|
+
const failing = report.roles.filter(role => ['unsupported', 'conflict', 'stale', 'missing'].includes(role.setup.state));
|
|
1383
|
+
if (failing.length)
|
|
1384
|
+
throw new FleetCliExit(1);
|
|
1385
|
+
}
|
|
1386
|
+
catch (error) {
|
|
1387
|
+
if (error instanceof FleetCliExit)
|
|
1388
|
+
throw error;
|
|
1389
|
+
die(error);
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1257
1393
|
cOpt(program.command('doctor').description('prerequisite report'))
|
|
1258
1394
|
.option('--harness <id>', 'check one harness explicitly')
|
|
1259
1395
|
.option('--yaml-mode <mode>', 'non-plain YAML policy: compat|strict', 'compat')
|
|
@@ -1351,7 +1487,7 @@ cOpt(program.command('migrate-role-defaults')
|
|
|
1351
1487
|
die(error);
|
|
1352
1488
|
}
|
|
1353
1489
|
});
|
|
1354
|
-
const webCommand = cOpt(program.command('web').description('start
|
|
1490
|
+
const webCommand = cOpt(program.command('web').description('start the Fleet HTTP service used by the App'))
|
|
1355
1491
|
.enablePositionalOptions()
|
|
1356
1492
|
.option('--port <port>', 'loopback service port (default: 49271)', value => {
|
|
1357
1493
|
const port = Number(value);
|
|
@@ -1359,7 +1495,7 @@ const webCommand = cOpt(program.command('web').description('start or open the se
|
|
|
1359
1495
|
throw new Error('invalid port');
|
|
1360
1496
|
return port;
|
|
1361
1497
|
})
|
|
1362
|
-
.option('--no-open', '
|
|
1498
|
+
.option('--no-open', 'accepted for existing service units; Fleet opens no browser')
|
|
1363
1499
|
.option('--bind <address>', 'explicit listen address (default: 127.0.0.1)')
|
|
1364
1500
|
.option('--public-origin <url>', 'browser origin served by an explicit reverse proxy')
|
|
1365
1501
|
.option('--password-file <path>', 'configure password protection from an owner-readable file')
|
|
@@ -1376,12 +1512,7 @@ const webCommand = cOpt(program.command('web').description('start or open the se
|
|
|
1376
1512
|
if (accessNotice)
|
|
1377
1513
|
process.stdout.write(accessNotice + '\n');
|
|
1378
1514
|
await manager.start();
|
|
1379
|
-
|
|
1380
|
-
await requestWebControlWhenReady('open');
|
|
1381
|
-
process.stdout.write('Control-panel authentication opened in the browser.\n');
|
|
1382
|
-
}
|
|
1383
|
-
else
|
|
1384
|
-
process.stdout.write('Web service started; run `ours-fleet web open` to pair a browser.\n');
|
|
1515
|
+
process.stdout.write('Fleet service started.\n');
|
|
1385
1516
|
}
|
|
1386
1517
|
catch (e) {
|
|
1387
1518
|
die(e);
|
|
@@ -1394,7 +1525,7 @@ const webPort = (command) => cOpt(command)
|
|
|
1394
1525
|
throw new Error('invalid port');
|
|
1395
1526
|
return port;
|
|
1396
1527
|
});
|
|
1397
|
-
const webServe = cOpt(webCommand.command('serve').description('run the
|
|
1528
|
+
const webServe = cOpt(webCommand.command('serve').description('run the Fleet HTTP service in the foreground'))
|
|
1398
1529
|
.option('--port <port>', 'loopback port (default: 49271; 0 chooses a free port)', value => {
|
|
1399
1530
|
const port = Number(value);
|
|
1400
1531
|
if (!Number.isInteger(port) || port < 0 || port > 65_535)
|
|
@@ -1402,7 +1533,7 @@ const webServe = cOpt(webCommand.command('serve').description('run the web conso
|
|
|
1402
1533
|
return port;
|
|
1403
1534
|
});
|
|
1404
1535
|
webServe
|
|
1405
|
-
.option('--no-open', '
|
|
1536
|
+
.option('--no-open', 'accepted for existing service units; Fleet opens no browser')
|
|
1406
1537
|
.option('--bind <address>', 'explicit listen address (default: 127.0.0.1)')
|
|
1407
1538
|
.option('--public-origin <url>', 'browser origin served by an explicit reverse proxy')
|
|
1408
1539
|
.option('--password-file <path>', 'configure password protection from an owner-readable file')
|
|
@@ -1413,15 +1544,12 @@ webServe
|
|
|
1413
1544
|
const accessNotice = configureWebAccess(opts);
|
|
1414
1545
|
const consoleServer = await startWebConsole({
|
|
1415
1546
|
configPath: opts.configuration, port: opts.port,
|
|
1416
|
-
|
|
1547
|
+
binPath, bind: opts.bind, publicOrigin: opts.publicOrigin,
|
|
1417
1548
|
log: line => process.stderr.write(line + '\n'),
|
|
1418
1549
|
});
|
|
1419
1550
|
if (accessNotice)
|
|
1420
1551
|
process.stdout.write(accessNotice + '\n');
|
|
1421
1552
|
process.stdout.write(`ours-fleet web listening on ${consoleServer.address}\n`);
|
|
1422
|
-
process.stdout.write(opts.open !== false
|
|
1423
|
-
? 'Control-panel authentication opened in the browser.\n'
|
|
1424
|
-
: 'Run `ours-fleet web open` to authenticate a browser.\n');
|
|
1425
1553
|
const shutdown = async () => { await consoleServer.close(); process.exit(0); };
|
|
1426
1554
|
process.once('SIGINT', () => { void shutdown(); });
|
|
1427
1555
|
process.once('SIGTERM', () => { void shutdown(); });
|
|
@@ -1480,11 +1608,209 @@ webCommand.command('uninstall').description('stop and uninstall the owner web se
|
|
|
1480
1608
|
die(e);
|
|
1481
1609
|
}
|
|
1482
1610
|
});
|
|
1483
|
-
|
|
1611
|
+
async function workspaceEnrollmentCommand(opts, setupTunnel = false, argument) {
|
|
1612
|
+
try {
|
|
1613
|
+
if (opts.discardRetiredReplacement) {
|
|
1614
|
+
if (!setupTunnel || argument !== undefined || opts.file || opts.stdin || opts.check || opts.resume || opts.migrateAppOrigin || opts.replaceRegistration || opts.configuration || opts.abandonReplacement)
|
|
1615
|
+
throw Error('--discard-retired-replacement takes no payload or other setup options');
|
|
1616
|
+
discardRetiredWorkspaceReplacement();
|
|
1617
|
+
process.stdout.write('Retired replacement recovery discarded. This host has no working registration: the old service was stopped and linked devices revoked. After removing the failed successor in the App, use a fresh command to complete a new registration. Installation data and the old local binding are preserved.\n');
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
if (opts.abandonReplacement) {
|
|
1621
|
+
if (!setupTunnel || argument !== undefined || opts.file || opts.stdin || opts.check || opts.resume || opts.migrateAppOrigin || opts.replaceRegistration || opts.configuration)
|
|
1622
|
+
throw Error('--abandon-replacement takes no payload or other setup options');
|
|
1623
|
+
await abandonWorkspaceReplacement();
|
|
1624
|
+
process.stdout.write('Unsent or rejected replacement abandoned; existing local setup preserved. Obtain a fresh App command for another setup.\n');
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
if (setupTunnel && opts.check && opts.resume)
|
|
1628
|
+
throw Error('Use either --check or --resume');
|
|
1629
|
+
if (setupTunnel && (opts.check || opts.resume) && (argument !== undefined || opts.file || opts.stdin || opts.migrateAppOrigin || opts.replaceRegistration))
|
|
1630
|
+
throw Error('--check and --resume take no payload or migration flag');
|
|
1631
|
+
if (setupTunnel && opts.check) {
|
|
1632
|
+
await setupTunnelPreflight();
|
|
1633
|
+
await checkWorkspaceConfiguration(opts.configuration ?? defaultConfigPath());
|
|
1634
|
+
process.stdout.write('Tunnel setup prerequisites are available.\n');
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
let pending;
|
|
1638
|
+
if (setupTunnel && opts.resume) {
|
|
1639
|
+
const replacement = readWorkspaceReplacement();
|
|
1640
|
+
if (replacement) {
|
|
1641
|
+
if (opts.configuration && resolvePath(opts.configuration) !== replacement.configuration)
|
|
1642
|
+
throw Error('Resume replacement with its original configuration');
|
|
1643
|
+
await setupTunnelPreflight();
|
|
1644
|
+
const result = await finishWorkspaceReplacement(replacement);
|
|
1645
|
+
pending = { appOrigin: replacement.payload.appOrigin, origin: result.origin, hostWorkspaceId: result.hostWorkspaceId, rootCid: result.rootCid, challenge: replacement.payload.challenge, configuration: replacement.configuration };
|
|
1646
|
+
savePendingTunnelSetup(pending);
|
|
1647
|
+
clearWorkspaceReplacement();
|
|
1648
|
+
}
|
|
1649
|
+
else {
|
|
1650
|
+
pending = readPendingTunnelSetup();
|
|
1651
|
+
if (opts.configuration && resolvePath(opts.configuration) !== pending.configuration)
|
|
1652
|
+
throw Error(`This setup started with configuration ${pending.configuration}; resume it without --configuration`);
|
|
1653
|
+
await setupTunnelPreflight();
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
else {
|
|
1657
|
+
if (argument === undefined && !opts.file && !opts.stdin)
|
|
1658
|
+
throw Error('setup-tunnel requires an App grant argument, --file <path>, or --stdin (or --resume to finish an interrupted setup)');
|
|
1659
|
+
if (Number(argument !== undefined) + Number(!!opts.file) + Number(!!opts.stdin) > 1)
|
|
1660
|
+
throw Error('Use one payload argument, --file, or --stdin');
|
|
1661
|
+
if (opts.stdin && process.stdin.isTTY)
|
|
1662
|
+
throw Error('--stdin requires a pipe; use an owned private --file instead');
|
|
1663
|
+
const input = setupTunnel ? (argument !== undefined ? readTunnelSetupArgument(argument) : opts.stdin ? await readTunnelSetupStdin() : readTunnelSetupFile(opts.file)) : undefined;
|
|
1664
|
+
const previous = setupTunnel ? readWorkspaceBinding() : undefined;
|
|
1665
|
+
const replacement = setupTunnel ? readWorkspaceReplacement() : undefined;
|
|
1666
|
+
if (replacement && !opts.replaceRegistration)
|
|
1667
|
+
throw Error('An unfinished replacement exists. Run setup-tunnel --resume, use a fresh command for the same target with --replace-registration, or --abandon-replacement when retirement was never sent or definitively rejected. If retirement and cleanup completed but the successor cannot be recovered, remove the successor in the App and use --discard-retired-replacement');
|
|
1668
|
+
if (replacement && resolvePath(opts.configuration ?? defaultConfigPath()) !== replacement.configuration)
|
|
1669
|
+
throw Error('Replacement requires its original configuration');
|
|
1670
|
+
const target = previous && !replacement ? await inspectTunnelSetup(input) : undefined;
|
|
1671
|
+
const different = previous && !replacement && (!target || requiresWorkspaceReplacement(previous, target, opts.migrateAppOrigin));
|
|
1672
|
+
if (different && !(await confirmWorkspaceReplacement(previous, opts.replaceRegistration))) {
|
|
1673
|
+
if (!process.stdin.isTTY)
|
|
1674
|
+
throw Error('Replacement confirmation required; existing setup and grant preserved');
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
if (setupTunnel) {
|
|
1678
|
+
await setupTunnelPreflight();
|
|
1679
|
+
await checkWorkspaceConfiguration(opts.configuration ?? defaultConfigPath());
|
|
1680
|
+
}
|
|
1681
|
+
let payload = setupTunnel ? await redeemTunnelSetup(input) : readWorkspacePayload(opts.file);
|
|
1682
|
+
verifyTunnelSetupTarget(target, payload);
|
|
1683
|
+
const replace = previous && !replacement && requiresWorkspaceReplacement(previous, { workspaceId: payload.challenge.workspaceId, serverCid: payload.serverCid, appOrigin: payload.appOrigin }, opts.migrateAppOrigin);
|
|
1684
|
+
if (replacement) {
|
|
1685
|
+
refreshWorkspaceReplacement(replacement, payload, opts.configuration ?? defaultConfigPath());
|
|
1686
|
+
payload = replacement.payload;
|
|
1687
|
+
}
|
|
1688
|
+
checkWorkspaceConnector(payload);
|
|
1689
|
+
if (setupTunnel)
|
|
1690
|
+
await ensureMinimalSetup(opts.configuration ?? defaultConfigPath());
|
|
1691
|
+
let result;
|
|
1692
|
+
if (replacement) {
|
|
1693
|
+
result = await finishWorkspaceReplacement(replacement);
|
|
1694
|
+
}
|
|
1695
|
+
else if (replace) {
|
|
1696
|
+
const record = await beginWorkspaceReplacement(previous, payload, opts.configuration ?? defaultConfigPath());
|
|
1697
|
+
result = await finishWorkspaceReplacement(record);
|
|
1698
|
+
}
|
|
1699
|
+
else
|
|
1700
|
+
result = await enrollWorkspace(payload, opts.configuration, { migrateAppOrigin: opts.migrateAppOrigin, preserveProfile: setupTunnel || opts.preserveProfile });
|
|
1701
|
+
pending = { appOrigin: payload.appOrigin, origin: result.origin, hostWorkspaceId: result.hostWorkspaceId, rootCid: result.rootCid, challenge: payload.challenge, configuration: resolvePath(opts.configuration ?? defaultConfigPath()) };
|
|
1702
|
+
// Keep both the replacement capability and the proof until the next recovery record is durable.
|
|
1703
|
+
if (setupTunnel) {
|
|
1704
|
+
savePendingTunnelSetup(pending);
|
|
1705
|
+
clearWorkspaceReplacement();
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
try {
|
|
1709
|
+
await finishWorkspaceService(pending, opts.resume ? pending.configuration : opts.configuration, setupTunnel);
|
|
1710
|
+
}
|
|
1711
|
+
catch (error) {
|
|
1712
|
+
if (!setupTunnel)
|
|
1713
|
+
throw error;
|
|
1714
|
+
throw Error(`${error instanceof Error ? error.message : String(error)}\nThis host is already bound to the workspace; do not request a new command. Fix the problem above, then run: ours-fleet setup-tunnel --resume`);
|
|
1715
|
+
}
|
|
1716
|
+
if (setupTunnel) {
|
|
1717
|
+
await completeTunnelSetup({ link: () => requestWebControl('link-device'), qr: code => QRCode.toString(code, { type: 'terminal', small: true }), write: text => new Promise((resolve, reject) => {
|
|
1718
|
+
const onError = (error) => reject(error);
|
|
1719
|
+
process.stdout.once('error', onError);
|
|
1720
|
+
process.stdout.write(text, error => { if (error)
|
|
1721
|
+
reject(error);
|
|
1722
|
+
else {
|
|
1723
|
+
process.stdout.removeListener('error', onError);
|
|
1724
|
+
resolve();
|
|
1725
|
+
} });
|
|
1726
|
+
}), clear: clearPendingTunnelSetup });
|
|
1727
|
+
}
|
|
1728
|
+
else {
|
|
1729
|
+
const link = await requestWebControl('link-device');
|
|
1730
|
+
const code = Buffer.from(JSON.stringify(link)).toString('base64url');
|
|
1731
|
+
process.stdout.write('Root proof submitted; account setup is ready only after tunnel health and binding verification.\nPrivate single-use device code:\n');
|
|
1732
|
+
process.stdout.write(await QRCode.toString(code, { type: 'terminal', small: true }));
|
|
1733
|
+
process.stdout.write('\n' + code + '\n');
|
|
1734
|
+
clearPendingTunnelSetup();
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
catch (error) {
|
|
1738
|
+
die(error);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
/** Everything after the root proof: supervised web service, its bound port, and the tunnel target. Safe to repeat. */
|
|
1742
|
+
async function finishWorkspaceService(pending, configuration, record) {
|
|
1743
|
+
if (!existsSync(new WebAccessStore().path))
|
|
1744
|
+
configureWebAccess({ pairing: true });
|
|
1745
|
+
// Once the challenge has expired the account can no longer retarget the tunnel. Decide before touching a running service.
|
|
1746
|
+
const expired = pending.challenge.expiresAt <= Date.now();
|
|
1747
|
+
const requiredPort = expired ? requiredPortAfterExpiry(pending) : undefined;
|
|
1748
|
+
const manager = new WebServiceManager(), previous = manager.readMetadata();
|
|
1749
|
+
if (previous)
|
|
1750
|
+
await manager.stop();
|
|
1751
|
+
const selectedPort = await availableWebPort(requiredPort ?? previous?.port ?? 49271);
|
|
1752
|
+
mkdirSync(joinPath(stateRoot(), 'web'), { recursive: true, mode: 0o700 });
|
|
1753
|
+
writeFileSync(joinPath(stateRoot(), 'web', 'port-selection.json'), JSON.stringify({ expiresAt: Date.now() + 60000 }) + '\n', { mode: 0o600 });
|
|
1754
|
+
const notes = await manager.install(binPath, selectedPort, configuration, { bind: '127.0.0.1', publicOrigin: pending.origin });
|
|
1755
|
+
await manager.restart();
|
|
1756
|
+
// Without linger the user service, and with it the tunnel, stops at logout and does not start at boot.
|
|
1757
|
+
for (const note of notes)
|
|
1758
|
+
if (note.startsWith('warning:'))
|
|
1759
|
+
process.stderr.write(`${note}\nUntil then the tunnel stops when you log out of this host.\n`);
|
|
1760
|
+
const waitForControl = async () => {
|
|
1761
|
+
const controlDeadline = Date.now() + 20000;
|
|
1762
|
+
while (!existsSync(webControlPath())) {
|
|
1763
|
+
if (Date.now() >= controlDeadline)
|
|
1764
|
+
throw Error('Fleet backend did not become ready within 20 seconds. Run ours-fleet web status; on Linux inspect journalctl --user -u ours-fleet-web.service -n 25 --no-pager. Resolve the startup error before running ours-fleet link-device');
|
|
1765
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
1766
|
+
}
|
|
1767
|
+
};
|
|
1768
|
+
await waitForControl();
|
|
1769
|
+
const bound = JSON.parse(readFileSync(joinPath(stateRoot(), 'web', 'workspace-port.json'), 'utf8'));
|
|
1770
|
+
if (!Number.isInteger(bound.port) || bound.port < 1 || bound.port > 65535)
|
|
1771
|
+
throw Error('Invalid workspace listener port');
|
|
1772
|
+
if (bound.port !== selectedPort) {
|
|
1773
|
+
await manager.retainBoundPort(binPath, bound.port, configuration, { bind: '127.0.0.1', publicOrigin: pending.origin });
|
|
1774
|
+
await waitForControl();
|
|
1775
|
+
}
|
|
1776
|
+
if (requiredPort === undefined) {
|
|
1777
|
+
// Record the request first: if its answer is lost, a later resume must not assume the default target.
|
|
1778
|
+
if (record) {
|
|
1779
|
+
pending = { ...pending, confirmedPort: undefined, requestedPorts: [...(pending.requestedPorts ?? []), bound.port] };
|
|
1780
|
+
savePendingTunnelSetup(pending);
|
|
1781
|
+
}
|
|
1782
|
+
await confirmWorkspaceTarget(pending, pending.hostWorkspaceId, pending.rootCid, bound.port, error => { process.stderr.write(`The enrollment contact could not be removed from Messenger (${error instanceof Error ? error.message : String(error)}); it can be removed there by hand.\n`); });
|
|
1783
|
+
if (record)
|
|
1784
|
+
savePendingTunnelSetup({ ...pending, confirmedPort: bound.port });
|
|
1785
|
+
}
|
|
1786
|
+
else if (bound.port !== requiredPort)
|
|
1787
|
+
throw Error(`The setup window has expired and the tunnel points at port ${requiredPort}, but this host could only bind port ${bound.port}. Free port ${requiredPort} on this host`);
|
|
1788
|
+
rmSync(joinPath(stateRoot(), 'web', 'port-selection.json'), { force: true });
|
|
1789
|
+
}
|
|
1790
|
+
cOpt(program.command('workspace-enroll').description('enroll this host using a private account setup file'))
|
|
1791
|
+
.requiredOption('--file <path>', 'owned private payload file')
|
|
1792
|
+
.option('--preserve-profile', 'retain the existing human profile without creating or rewriting it')
|
|
1793
|
+
.option('--migrate-app-origin', 'explicitly migrate the same workspace to its new account origin after verified signed proof')
|
|
1794
|
+
.action(async (opts) => workspaceEnrollmentCommand(opts));
|
|
1795
|
+
cOpt(program.command('setup-tunnel').argument('[payload]', 'minimal one-use v2 App grant (appears in shell history and process listings)')
|
|
1796
|
+
.configureOutput({ outputError: (_message, write) => write('Invalid setup-tunnel command; run ours-fleet setup-tunnel --help.\n') }).description('connect an installed host using scoped expiring App credentials; preserves identities and agent configuration'))
|
|
1797
|
+
.option('--file <path>', 'owned private App grant or legacy payload file (chmod 600)')
|
|
1798
|
+
.option('--stdin', 'read the private App grant or legacy payload from a pipe')
|
|
1799
|
+
.option('--check', 'only verify host prerequisites; changes nothing and needs no payload')
|
|
1800
|
+
.option('--resume', 'finish an interrupted replacement or setup; needs no new payload')
|
|
1801
|
+
.option('--discard-retired-replacement', 'forget a failed successor after retirement and local cleanup; remove it in the App first')
|
|
1802
|
+
.option('--abandon-replacement', 'discard an unsent or definitively rejected replacement after checking its private receipt')
|
|
1803
|
+
.option('--replace-registration', 'confirm retirement of the existing account registration when the new one differs')
|
|
1804
|
+
.option('--migrate-app-origin', 'explicitly migrate the same workspace to its new account origin after verified signed proof')
|
|
1805
|
+
.action(async (payload, opts) => workspaceEnrollmentCommand(opts, true, payload));
|
|
1806
|
+
program.command('link-device').description('create a single-use workspace device connection code (expires in five minutes)')
|
|
1484
1807
|
.action(async () => {
|
|
1485
1808
|
try {
|
|
1486
|
-
await requestWebControl('
|
|
1487
|
-
process.stdout.write('
|
|
1809
|
+
const link = await requestWebControl('link-device');
|
|
1810
|
+
process.stdout.write('Private connection code; share only with the intended device.\n');
|
|
1811
|
+
const code = Buffer.from(JSON.stringify(link)).toString('base64url');
|
|
1812
|
+
process.stdout.write(await QRCode.toString(code, { type: 'terminal', small: true }));
|
|
1813
|
+
process.stdout.write('\n' + code + '\n');
|
|
1488
1814
|
}
|
|
1489
1815
|
catch (e) {
|
|
1490
1816
|
die(e);
|
|
@@ -1500,20 +1826,6 @@ webCommand.command('revoke-all').description('revoke all trusted browsers and ac
|
|
|
1500
1826
|
die(e);
|
|
1501
1827
|
}
|
|
1502
1828
|
});
|
|
1503
|
-
async function requestWebControlWhenReady(command) {
|
|
1504
|
-
let last;
|
|
1505
|
-
for (let attempt = 0; attempt < 40; attempt++) {
|
|
1506
|
-
try {
|
|
1507
|
-
await requestWebControl(command, undefined, 500);
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1510
|
-
catch (error) {
|
|
1511
|
-
last = error;
|
|
1512
|
-
await new Promise(resolve => setTimeout(resolve, 125));
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
throw last;
|
|
1516
|
-
}
|
|
1517
1829
|
function configureWebAccess(opts) {
|
|
1518
1830
|
if (opts.publicOrigin)
|
|
1519
1831
|
validatePublicOrigin(opts.publicOrigin);
|
|
@@ -1541,9 +1853,47 @@ function configureWebAccess(opts) {
|
|
|
1541
1853
|
return undefined;
|
|
1542
1854
|
}
|
|
1543
1855
|
// ── rooms & tasks ──────────────────────────────────────────────────────────
|
|
1856
|
+
registerLayoutCommands(program, cOpt);
|
|
1544
1857
|
registerTemplateCommands(program, cOpt);
|
|
1545
1858
|
registerTaskCommands(program, cOpt);
|
|
1546
1859
|
registerRoomCommands(program, cOpt);
|
|
1860
|
+
program.command('_wait-daemon <name>', { hidden: true }).description('internal: service startup readiness')
|
|
1861
|
+
.option('-c, --configuration <file>')
|
|
1862
|
+
.action(async (name, opts) => {
|
|
1863
|
+
try {
|
|
1864
|
+
await waitForRoleDaemon(name, opts.configuration);
|
|
1865
|
+
}
|
|
1866
|
+
catch (e) {
|
|
1867
|
+
die(e);
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
program.command('_wait-temp-daemon <name>', { hidden: true })
|
|
1871
|
+
.action(async (name) => {
|
|
1872
|
+
try {
|
|
1873
|
+
await waitForRoleDaemon(name, undefined, {}, true);
|
|
1874
|
+
}
|
|
1875
|
+
catch (error) {
|
|
1876
|
+
die(error);
|
|
1877
|
+
}
|
|
1878
|
+
});
|
|
1879
|
+
program.command('_run-fleet', { hidden: true }).action(async () => {
|
|
1880
|
+
try {
|
|
1881
|
+
const { runFleetManager } = await import('./supervisor/manager.js');
|
|
1882
|
+
await runFleetManager(process.argv[1]);
|
|
1883
|
+
}
|
|
1884
|
+
catch (error) {
|
|
1885
|
+
die(error);
|
|
1886
|
+
}
|
|
1887
|
+
});
|
|
1888
|
+
program.command('_run-managed <key> <generation>', { hidden: true }).action(async (key, generation) => {
|
|
1889
|
+
try {
|
|
1890
|
+
const { runManagedMember } = await import('./supervisor/manager.js');
|
|
1891
|
+
await runManagedMember(key, generation);
|
|
1892
|
+
}
|
|
1893
|
+
catch (error) {
|
|
1894
|
+
die(error);
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1547
1897
|
program.command('_run <name>', { hidden: true }).description('internal: supervisor entrypoint')
|
|
1548
1898
|
.option('-c, --configuration <file>')
|
|
1549
1899
|
.action(async (name, opts) => {
|
|
@@ -1566,9 +1916,10 @@ program.command('_run-temp <name>', { hidden: true }).description('internal: tem
|
|
|
1566
1916
|
}
|
|
1567
1917
|
});
|
|
1568
1918
|
program.command('_run-temp-worker <name>', { hidden: true })
|
|
1569
|
-
.
|
|
1919
|
+
.option('--suspend-on-stop')
|
|
1920
|
+
.action(async (name, options) => {
|
|
1570
1921
|
try {
|
|
1571
|
-
await runTemp(name);
|
|
1922
|
+
await runTemp(name, { suspendOnStop: options.suspendOnStop === true });
|
|
1572
1923
|
}
|
|
1573
1924
|
catch (error) {
|
|
1574
1925
|
if (error instanceof SupervisorRecycleRequiredError)
|
|
@@ -1612,6 +1963,8 @@ async function parseFleetCli() {
|
|
|
1612
1963
|
await program.parseAsync(process.argv);
|
|
1613
1964
|
}
|
|
1614
1965
|
catch (error) {
|
|
1966
|
+
if (error instanceof FleetCliExit)
|
|
1967
|
+
throw error;
|
|
1615
1968
|
const commander = error;
|
|
1616
1969
|
if (commander.exitCode === 0)
|
|
1617
1970
|
return;
|
|
@@ -1623,7 +1976,15 @@ async function parseFleetCli() {
|
|
|
1623
1976
|
async function runFleetCli() {
|
|
1624
1977
|
const stateDir = process.env[FLEET_PROXY_STATE_DIR_ENV];
|
|
1625
1978
|
const caller = process.env[FLEET_PROXY_CALLER_ENV];
|
|
1979
|
+
const entry = parseManagedEntry(process.argv.slice(2));
|
|
1626
1980
|
if (!stateDir || !caller) {
|
|
1981
|
+
// The pinned form exists for managed sessions; outside one there is no
|
|
1982
|
+
// supervisor to audit the call, so it is refused rather than run unaudited.
|
|
1983
|
+
if (entry.kind !== 'none') {
|
|
1984
|
+
console.error(`error: ${entry.kind === 'error' ? entry.message
|
|
1985
|
+
: `${MANAGED_CONFIGURATION_FLAG} is only valid inside a Fleet-managed agent session, where the supervisor audits the call`}`);
|
|
1986
|
+
throw new FleetCliExit(1, 'validation', 'not_started');
|
|
1987
|
+
}
|
|
1627
1988
|
await parseFleetCli();
|
|
1628
1989
|
return;
|
|
1629
1990
|
}
|
|
@@ -1658,6 +2019,15 @@ async function runFleetCli() {
|
|
|
1658
2019
|
const originalExit = process.exit;
|
|
1659
2020
|
process.exit = ((code) => { throw new FleetCliExit(code ?? 0); });
|
|
1660
2021
|
try {
|
|
2022
|
+
if (entry.kind === 'error') {
|
|
2023
|
+
console.error(`error: ${entry.message}`);
|
|
2024
|
+
throw new FleetCliExit(1, 'validation', 'not_started');
|
|
2025
|
+
}
|
|
2026
|
+
if (entry.kind === 'pinned') {
|
|
2027
|
+
// The supervisor audited the argv as typed; Commander parses the ordinary form.
|
|
2028
|
+
pinnedConfiguration = entry.configuration;
|
|
2029
|
+
process.argv = [process.argv[0], process.argv[1], ...entry.argv];
|
|
2030
|
+
}
|
|
1661
2031
|
await parseFleetCli();
|
|
1662
2032
|
}
|
|
1663
2033
|
catch (error) {
|
package/dist/client-profile.d.ts
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
readonly serverUrl?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare class ClientProfileError extends Error {
|
|
9
|
-
constructor(message: string);
|
|
10
|
-
}
|
|
11
|
-
export declare function clientConfigPath(env: NodeJS.ProcessEnv): string;
|
|
12
|
-
/**
|
|
13
|
-
* Read Fleet's selected host-client profile without opening its credential.
|
|
14
|
-
* A legacy daemon config remains legacy only when none of the profile fields is
|
|
15
|
-
* present. Explicit and managed selections fail closed on invalid input.
|
|
16
|
-
*/
|
|
17
|
-
export declare function readClientProfile(env: NodeJS.ProcessEnv): ExplicitClientProfile | undefined;
|
|
1
|
+
import { clientProfilePath, readGatewayClientProfile } from '@ours.network/sdk/client';
|
|
2
|
+
export { ClientProfileError } from '@ours.network/sdk/client';
|
|
3
|
+
export type ExplicitClientProfile = ReturnType<typeof readGatewayClientProfile>;
|
|
4
|
+
export declare const clientConfigPath: typeof clientProfilePath;
|
|
5
|
+
export declare const readClientProfile: typeof readGatewayClientProfile;
|
|
18
6
|
export declare function clientProfileKey(profile: ExplicitClientProfile): string;
|