@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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Body-free recovery cursor. Dispatching is uncertain after a crash, never
|
|
2
|
+
* permission to replay an initial task which may already have caused effects. */
|
|
3
|
+
export interface ManagedRecovery {
|
|
4
|
+
version: 1;
|
|
5
|
+
session: 'pending' | 'established';
|
|
6
|
+
readiness: boolean;
|
|
7
|
+
initial: 'pending' | 'dispatching' | 'completed';
|
|
8
|
+
active: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const managedRecoveryPath: (dir: string) => string;
|
|
11
|
+
export declare function readManagedRecovery(dir: string): ManagedRecovery | undefined;
|
|
12
|
+
export declare function writeManagedRecovery(dir: string, value: ManagedRecovery): void;
|
|
13
|
+
export declare function firstManagedSessionMayStart(dir: string): boolean;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { lstatSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { replaceFileAtomically } from './atomic-file.js';
|
|
4
|
+
export const managedRecoveryPath = (dir) => join(dir, '.managed-recovery.json');
|
|
5
|
+
export function readManagedRecovery(dir) {
|
|
6
|
+
const path = managedRecoveryPath(dir);
|
|
7
|
+
let stat;
|
|
8
|
+
try {
|
|
9
|
+
stat = lstatSync(path);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error.code === 'ENOENT')
|
|
13
|
+
return;
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 4096)
|
|
17
|
+
throw Error('MANAGED_RECOVERY_UNSAFE_PROOF');
|
|
18
|
+
const value = JSON.parse(readFileSync(path, 'utf8'));
|
|
19
|
+
if (value.version !== 1 || !['pending', 'established'].includes(value.session)
|
|
20
|
+
|| !['pending', 'dispatching', 'completed'].includes(value.initial)
|
|
21
|
+
|| typeof value.readiness !== 'boolean' || typeof value.active !== 'boolean')
|
|
22
|
+
throw Error('MANAGED_RECOVERY_INVALID_PROOF');
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
export function writeManagedRecovery(dir, value) {
|
|
26
|
+
replaceFileAtomically(managedRecoveryPath(dir), JSON.stringify(value) + '\n');
|
|
27
|
+
}
|
|
28
|
+
export function firstManagedSessionMayStart(dir) {
|
|
29
|
+
const proof = readManagedRecovery(dir);
|
|
30
|
+
return Boolean(proof?.session === 'pending' && proof.initial === 'pending' && !proof.readiness && !proof.active);
|
|
31
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync, linkSync, mkdirSync, mkdtempSync, renameSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { withFileLock } from './atomic-file.js';
|
|
4
|
+
import { loadConfig, splitRootFor } from './config.js';
|
|
5
|
+
import { preflightInitPaths } from './init-wizard.js';
|
|
6
|
+
import { workspaceOwnerInvite } from './paths.js';
|
|
7
|
+
/** Prepare only the web configuration; App onboarding chooses agents and brains later. */
|
|
8
|
+
export async function ensureMinimalSetup(configuration) {
|
|
9
|
+
const initial = preflightInitPaths(configuration);
|
|
10
|
+
await withFileLock(join(initial.parent, `.${basename(initial.splitRoot)}.init.lock`), async () => {
|
|
11
|
+
const selected = preflightInitPaths(configuration);
|
|
12
|
+
if (selected.manifestExisted) {
|
|
13
|
+
loadConfig(selected.configPath, { yamlMode: 'strict', deferredOwnerInviteFile: workspaceOwnerInvite() });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (selected.rootExisted)
|
|
17
|
+
throw new Error('Fleet split configuration exists without its manifest; retain it and recover the existing setup before setting up a tunnel');
|
|
18
|
+
const stage = mkdtempSync(join(selected.parent, '.fleet-web-setup-'));
|
|
19
|
+
const manifest = join(stage, 'fleet.yaml');
|
|
20
|
+
const root = splitRootFor(manifest);
|
|
21
|
+
let publishedRoot = false;
|
|
22
|
+
try {
|
|
23
|
+
mkdirSync(join(root, 'agents'), { recursive: true, mode: 0o700 });
|
|
24
|
+
writeFileSync(manifest, 'api_version: ours.network/fleet/v2\n', { mode: 0o600, flag: 'wx' });
|
|
25
|
+
loadConfig(manifest, { yamlMode: 'strict' });
|
|
26
|
+
if (existsSync(selected.splitRoot) || existsSync(selected.configPath))
|
|
27
|
+
throw new Error('Fleet setup targets changed; refusing replacement');
|
|
28
|
+
renameSync(root, selected.splitRoot);
|
|
29
|
+
publishedRoot = true;
|
|
30
|
+
// Same-filesystem link publishes without replacing an unexpected manifest.
|
|
31
|
+
linkSync(manifest, selected.configPath);
|
|
32
|
+
unlinkSync(manifest);
|
|
33
|
+
loadConfig(selected.configPath, { yamlMode: 'strict' });
|
|
34
|
+
}
|
|
35
|
+
catch (cause) {
|
|
36
|
+
if (publishedRoot)
|
|
37
|
+
throw new Error('Minimal Fleet setup stopped after publishing its empty split directory; existing files were retained for recovery', { cause });
|
|
38
|
+
throw cause;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
rmSync(stage, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
package/dist/monitor.d.ts
CHANGED
|
@@ -28,6 +28,10 @@ export type FetchLike = (url: string, init?: {
|
|
|
28
28
|
signal?: AbortSignal;
|
|
29
29
|
}) => Promise<FetchResponse>;
|
|
30
30
|
export interface MonitorPageClient {
|
|
31
|
+
/** Body-free snapshot; never consumes messages or changes read status. */
|
|
32
|
+
unread(): Promise<{
|
|
33
|
+
identities: Array<Record<string, unknown>>;
|
|
34
|
+
}>;
|
|
31
35
|
readNotificationPage(identity: string, options?: {
|
|
32
36
|
since?: number | 'tip';
|
|
33
37
|
signal?: AbortSignal;
|
|
@@ -88,33 +92,6 @@ export interface MonitorDeps {
|
|
|
88
92
|
* turns they trigger keep dying.
|
|
89
93
|
*/
|
|
90
94
|
export type StatusCause = 'connectivity' | 'delivery' | 'modal' | 'offline' | 'turns-failing' | 'safe-boundary' | 'auth';
|
|
91
|
-
/** Best-effort daemon config (issue #17): the fields the MCP client reads. */
|
|
92
|
-
interface DaemonConfig {
|
|
93
|
-
apiToken?: string;
|
|
94
|
-
port?: number;
|
|
95
|
-
stateDir?: string;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Read the daemon config the way the MCP client does — best-effort. Any missing,
|
|
99
|
-
* malformed, or unreadable config yields `{}` so token resolution falls through
|
|
100
|
-
* (issue #17). Only the well-typed fields we consume are surfaced.
|
|
101
|
-
*/
|
|
102
|
-
export declare function readDaemonConfig(env: NodeJS.ProcessEnv): DaemonConfig;
|
|
103
|
-
/**
|
|
104
|
-
* Resolve the daemon API token exactly like the MCP client (issue #17), a 3-step
|
|
105
|
-
* chain: `OURS_API_TOKEN` (trimmed) → config `apiToken` (trimmed) → the 0600 owner
|
|
106
|
-
* token at `<stateDir>/daemon-token`. Never generates a token; a failed read of
|
|
107
|
-
* any source (missing/unreadable) silently falls through to the next.
|
|
108
|
-
*/
|
|
109
|
-
export declare function resolveApiToken(env: NodeJS.ProcessEnv, file?: DaemonConfig): string | undefined;
|
|
110
|
-
export interface DaemonEndpoint {
|
|
111
|
-
origin: string;
|
|
112
|
-
port: number;
|
|
113
|
-
configPath: string;
|
|
114
|
-
stateDir: string;
|
|
115
|
-
url(name: string): string;
|
|
116
|
-
headers: Record<string, string>;
|
|
117
|
-
}
|
|
118
95
|
export type IdentityPresence = {
|
|
119
96
|
state: 'present';
|
|
120
97
|
temporary: boolean;
|
|
@@ -125,16 +102,12 @@ export type IdentityPresence = {
|
|
|
125
102
|
state: 'unknown';
|
|
126
103
|
detail: string;
|
|
127
104
|
};
|
|
128
|
-
/** Resolve the daemon endpoint + auth header from env → config → defaults. */
|
|
129
|
-
export declare function resolveEndpoint(env: NodeJS.ProcessEnv, includeToken?: boolean): DaemonEndpoint;
|
|
130
105
|
/**
|
|
131
106
|
* Ask the daemon's authoritative identity index. The notifications endpoint is
|
|
132
107
|
* intentionally unsuitable for lifecycle: it serves an empty 200 page for a
|
|
133
108
|
* valid but missing identity, which made a closed temp identity look healthy.
|
|
134
109
|
*/
|
|
135
110
|
export declare function probeIdentityPresence(name: string, fetch: FetchLike, env: NodeJS.ProcessEnv, deps?: IdentityProbeDeps): Promise<IdentityPresence>;
|
|
136
|
-
/** Actionable, secret-free description of every token source for this profile. */
|
|
137
|
-
export declare function authResolutionHint(ep: DaemonEndpoint): string;
|
|
138
111
|
/** Keep only the events whose type the role asked to wake on. */
|
|
139
112
|
export declare function filterEvents(events: NotifyEvent[], wakeSources: string[]): NotifyEvent[];
|
|
140
113
|
/**
|
|
@@ -196,8 +169,7 @@ export declare class Monitor {
|
|
|
196
169
|
private readonly identity;
|
|
197
170
|
private readonly cfg;
|
|
198
171
|
private readonly deps;
|
|
199
|
-
private readonly
|
|
200
|
-
private readonly profile?;
|
|
172
|
+
private readonly profile;
|
|
201
173
|
private readonly profileKey;
|
|
202
174
|
private readonly monitorLeaseToken;
|
|
203
175
|
private profileClientPromise?;
|
|
@@ -211,6 +183,7 @@ export declare class Monitor {
|
|
|
211
183
|
private stopped;
|
|
212
184
|
private bootDeadline;
|
|
213
185
|
private currentAbort;
|
|
186
|
+
private initialBacklogPending;
|
|
214
187
|
private apiErrorStreak;
|
|
215
188
|
private readonly turnFailThreshold;
|
|
216
189
|
/** Active degradations, keyed by cause. Empty means armed. */
|
|
@@ -230,6 +203,7 @@ export declare class Monitor {
|
|
|
230
203
|
/** Gather stragglers arriving within batch_ms so a burst lands as one line. */
|
|
231
204
|
private coalesce;
|
|
232
205
|
private deliver;
|
|
206
|
+
private deliverLine;
|
|
233
207
|
/** Update the consecutive-API-error streak and derive `.monitor-status` from it. */
|
|
234
208
|
private recordTurn;
|
|
235
209
|
/**
|
|
@@ -242,6 +216,7 @@ export declare class Monitor {
|
|
|
242
216
|
*/
|
|
243
217
|
private doFetch;
|
|
244
218
|
private profileClient;
|
|
219
|
+
private readInitialUnread;
|
|
245
220
|
private disposeProfileClient;
|
|
246
221
|
private advance;
|
|
247
222
|
private persistCursor;
|
|
@@ -263,4 +238,3 @@ export declare class Monitor {
|
|
|
263
238
|
private writeStatus;
|
|
264
239
|
}
|
|
265
240
|
export declare function createMonitor(o: MonitorOpts): Monitor;
|
|
266
|
-
export {};
|
package/dist/monitor.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import { attachOursClient } from '@ours.network/sdk/client';
|
|
6
5
|
import { clientProfileKey, readClientProfile, } from './client-profile.js';
|
|
@@ -42,124 +41,28 @@ const TURN_OBSERVE_INTERVAL_MS = 1_500;
|
|
|
42
41
|
const DEFAULT_TURN_FAIL_THRESHOLD = 3; // fallback when the resolved config omits it
|
|
43
42
|
class AuthError extends Error {
|
|
44
43
|
}
|
|
45
|
-
/** Path to the daemon config the MCP client uses: OURS_CONFIG ?? real ~/.ours/config.json. */
|
|
46
|
-
const daemonConfigPath = (env) => env.OURS_CONFIG ?? join(homedir(), '.ours', 'config.json');
|
|
47
|
-
/** Preserve the daemon's legacy env integer semantics: parseInt, invalid → absent. */
|
|
48
|
-
function envInt(env, name) {
|
|
49
|
-
const raw = env[name];
|
|
50
|
-
if (raw === undefined)
|
|
51
|
-
return undefined;
|
|
52
|
-
const n = parseInt(raw, 10);
|
|
53
|
-
return Number.isNaN(n) ? undefined : n;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Read the daemon config the way the MCP client does — best-effort. Any missing,
|
|
57
|
-
* malformed, or unreadable config yields `{}` so token resolution falls through
|
|
58
|
-
* (issue #17). Only the well-typed fields we consume are surfaced.
|
|
59
|
-
*/
|
|
60
|
-
export function readDaemonConfig(env) {
|
|
61
|
-
try {
|
|
62
|
-
const p = JSON.parse(readFileSync(daemonConfigPath(env), 'utf8'));
|
|
63
|
-
const o = {};
|
|
64
|
-
if (typeof p.apiToken === 'string' && p.apiToken.trim())
|
|
65
|
-
o.apiToken = p.apiToken.trim();
|
|
66
|
-
if (typeof p.port === 'number' && Number.isFinite(p.port))
|
|
67
|
-
o.port = p.port;
|
|
68
|
-
if (typeof p.stateDir === 'string')
|
|
69
|
-
o.stateDir = p.stateDir;
|
|
70
|
-
return o;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return {};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Resolve the daemon API token exactly like the MCP client (issue #17), a 3-step
|
|
78
|
-
* chain: `OURS_API_TOKEN` (trimmed) → config `apiToken` (trimmed) → the 0600 owner
|
|
79
|
-
* token at `<stateDir>/daemon-token`. Never generates a token; a failed read of
|
|
80
|
-
* any source (missing/unreadable) silently falls through to the next.
|
|
81
|
-
*/
|
|
82
|
-
export function resolveApiToken(env, file = readDaemonConfig(env)) {
|
|
83
|
-
const e = env.OURS_API_TOKEN?.trim();
|
|
84
|
-
if (e)
|
|
85
|
-
return e;
|
|
86
|
-
if (file.apiToken)
|
|
87
|
-
return file.apiToken;
|
|
88
|
-
const sd = env.OURS_STATE_DIR ?? file.stateDir ?? join(homedir(), '.ours');
|
|
89
|
-
try {
|
|
90
|
-
const t = readFileSync(join(sd, 'daemon-token'), 'utf8').trim();
|
|
91
|
-
if (t)
|
|
92
|
-
return t;
|
|
93
|
-
}
|
|
94
|
-
catch { /* missing/unreadable (e.g. cross-user 0600) → fall through */ }
|
|
95
|
-
return undefined;
|
|
96
|
-
}
|
|
97
|
-
/** Resolve the daemon endpoint + auth header from env → config → defaults. */
|
|
98
|
-
export function resolveEndpoint(env, includeToken = true) {
|
|
99
|
-
const file = readDaemonConfig(env);
|
|
100
|
-
const port = envInt(env, 'OURS_PORT') ?? file.port ?? DEFAULT_PORT;
|
|
101
|
-
const configPath = daemonConfigPath(env);
|
|
102
|
-
const stateDir = env.OURS_STATE_DIR ?? file.stateDir ?? join(homedir(), '.ours');
|
|
103
|
-
const token = includeToken ? resolveApiToken(env, file) : undefined;
|
|
104
|
-
const origin = `http://127.0.0.1:${port}`;
|
|
105
|
-
return {
|
|
106
|
-
origin,
|
|
107
|
-
port,
|
|
108
|
-
configPath,
|
|
109
|
-
stateDir,
|
|
110
|
-
url: (name) => `${origin}/identities/${encodeURIComponent(name)}/notifications`,
|
|
111
|
-
headers: token ? { 'x-ours-api-token': token } : {},
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
44
|
/**
|
|
115
45
|
* Ask the daemon's authoritative identity index. The notifications endpoint is
|
|
116
46
|
* intentionally unsuitable for lifecycle: it serves an empty 200 page for a
|
|
117
47
|
* valid but missing identity, which made a closed temp identity look healthy.
|
|
118
48
|
*/
|
|
119
49
|
export async function probeIdentityPresence(name, fetch, env, deps = {}) {
|
|
120
|
-
|
|
121
|
-
if (profile) {
|
|
122
|
-
let client;
|
|
123
|
-
try {
|
|
124
|
-
client = await (deps.attachClient?.({
|
|
125
|
-
endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
|
|
126
|
-
credentialPath: profile.credentialPath,
|
|
127
|
-
sessionMode: 'external', leaseToken: randomUUID(), env: {},
|
|
128
|
-
}) ?? attachOursClient({
|
|
129
|
-
endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
|
|
130
|
-
credentialPath: profile.credentialPath,
|
|
131
|
-
sessionMode: 'external', leaseToken: randomUUID(), env: {},
|
|
132
|
-
}));
|
|
133
|
-
return classifyIdentityPresence(name, await client.identities());
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
return { state: 'unknown', detail: 'selected identity index is unavailable' };
|
|
137
|
-
}
|
|
138
|
-
finally {
|
|
139
|
-
await client?.close().catch(() => undefined);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
const ep = resolveEndpoint(env);
|
|
143
|
-
let response;
|
|
50
|
+
let client;
|
|
144
51
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (!response.ok)
|
|
151
|
-
return {
|
|
152
|
-
state: 'unknown',
|
|
153
|
-
detail: response.status === 401
|
|
154
|
-
? `daemon rejected the API token (401) — ${authResolutionHint(ep)}`
|
|
155
|
-
: `identity index returned HTTP ${response.status}`,
|
|
52
|
+
const profile = readClientProfile(env);
|
|
53
|
+
const options = {
|
|
54
|
+
endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
|
|
55
|
+
credentialPath: profile.credentialPath,
|
|
56
|
+
sessionMode: 'external', leaseToken: randomUUID(), env: {},
|
|
156
57
|
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return classifyIdentityPresence(name, body.identities);
|
|
58
|
+
client = await (deps.attachClient?.(options) ?? attachOursClient(options));
|
|
59
|
+
return classifyIdentityPresence(name, await client.identities());
|
|
160
60
|
}
|
|
161
|
-
catch
|
|
162
|
-
return { state: 'unknown', detail:
|
|
61
|
+
catch {
|
|
62
|
+
return { state: 'unknown', detail: 'gateway identity index unavailable; check the shared client profile and issued credential' };
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await client?.close().catch(() => undefined);
|
|
163
66
|
}
|
|
164
67
|
}
|
|
165
68
|
function classifyIdentityPresence(name, identities) {
|
|
@@ -186,12 +89,6 @@ function classifyIdentityPresence(name, identities) {
|
|
|
186
89
|
stale: found.stale === true,
|
|
187
90
|
};
|
|
188
91
|
}
|
|
189
|
-
/** Actionable, secret-free description of every token source for this profile. */
|
|
190
|
-
export function authResolutionHint(ep) {
|
|
191
|
-
const tokenPath = join(ep.stateDir, 'daemon-token');
|
|
192
|
-
return `set OURS_API_TOKEN, set apiToken in ${JSON.stringify(ep.configPath)}, or ensure ` +
|
|
193
|
-
`${JSON.stringify(tokenPath)} is readable by the fleet supervisor`;
|
|
194
|
-
}
|
|
195
92
|
/** Keep only the events whose type the role asked to wake on. */
|
|
196
93
|
export function filterEvents(events, wakeSources) {
|
|
197
94
|
const set = new Set(wakeSources);
|
|
@@ -414,7 +311,6 @@ export class Monitor {
|
|
|
414
311
|
identity;
|
|
415
312
|
cfg;
|
|
416
313
|
deps;
|
|
417
|
-
ep;
|
|
418
314
|
profile;
|
|
419
315
|
profileKey;
|
|
420
316
|
monitorLeaseToken = `ours-fleet-monitor-${process.pid}-${randomUUID()}`;
|
|
@@ -429,6 +325,7 @@ export class Monitor {
|
|
|
429
325
|
stopped = false;
|
|
430
326
|
bootDeadline = 0;
|
|
431
327
|
currentAbort = null;
|
|
328
|
+
initialBacklogPending = true;
|
|
432
329
|
// Refusal-wedge detector (issue #19): consecutive delivered wakes whose turn
|
|
433
330
|
// ended in an API error with no completed turn in between.
|
|
434
331
|
apiErrorStreak = 0;
|
|
@@ -441,8 +338,7 @@ export class Monitor {
|
|
|
441
338
|
this.cfg = o.cfg;
|
|
442
339
|
this.deps = o.deps;
|
|
443
340
|
this.profile = readClientProfile(o.deps.env);
|
|
444
|
-
this.
|
|
445
|
-
this.profileKey = this.profile ? clientProfileKey(this.profile) : this.ep.origin;
|
|
341
|
+
this.profileKey = clientProfileKey(this.profile);
|
|
446
342
|
this.statusPath = join(o.agentDir, '.monitor-status');
|
|
447
343
|
this.cursorPath = join(o.agentDir, '.notify-cursor');
|
|
448
344
|
this.statePath = join(o.agentDir, '.monitor-state.json');
|
|
@@ -470,14 +366,8 @@ export class Monitor {
|
|
|
470
366
|
}
|
|
471
367
|
catch (e) {
|
|
472
368
|
if (e instanceof AuthError) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
this.degrade('auth', e.message);
|
|
476
|
-
}
|
|
477
|
-
else {
|
|
478
|
-
this.fatal = true;
|
|
479
|
-
this.degrade('auth', e.message, 'failed');
|
|
480
|
-
}
|
|
369
|
+
this.cursor = null;
|
|
370
|
+
this.degrade('auth', e.message);
|
|
481
371
|
}
|
|
482
372
|
else {
|
|
483
373
|
this.cursor = null;
|
|
@@ -500,6 +390,41 @@ export class Monitor {
|
|
|
500
390
|
this.degrade('offline', 'session offline');
|
|
501
391
|
return;
|
|
502
392
|
}
|
|
393
|
+
// The native SessionStart hook is disabled for managed sessions. Check
|
|
394
|
+
// existing unread work AFTER the ready turn, without a model inbox ritual
|
|
395
|
+
// or touching read status. Keep retrying a failed probe/delivery before
|
|
396
|
+
// committing stream cursors, including on supervisor restarts.
|
|
397
|
+
if (this.initialBacklogPending) {
|
|
398
|
+
try {
|
|
399
|
+
const body = await this.readInitialUnread();
|
|
400
|
+
if (!Array.isArray(body.identities))
|
|
401
|
+
throw new Error('unread summary is malformed');
|
|
402
|
+
const row = body.identities.find(row => row.name === this.identity);
|
|
403
|
+
if (row && (!Number.isSafeInteger(row.count) || Number(row.count) < 0
|
|
404
|
+
|| !Number.isSafeInteger(row.files) || Number(row.files) < 0))
|
|
405
|
+
throw new Error('unread identity summary is malformed');
|
|
406
|
+
const messages = this.cfg.wake_sources.includes('message_received') ? Number(row?.count ?? 0) : 0;
|
|
407
|
+
const files = this.cfg.wake_sources.includes('file_received') ? Number(row?.files ?? 0) : 0;
|
|
408
|
+
if ((messages || files) && !await this.deliverLine(`${PREFIX} unread backlog: ${messages} messages, ${files} files — run get_messages; drain remaining unread batches and authorize files before retrieving them`)) {
|
|
409
|
+
await this.deps.sleep(BACKOFF_MAX_MS);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
this.initialBacklogPending = false;
|
|
413
|
+
this.recover('connectivity', 'auth');
|
|
414
|
+
}
|
|
415
|
+
catch (e) {
|
|
416
|
+
if (this.stopped)
|
|
417
|
+
return;
|
|
418
|
+
if (e instanceof AuthError)
|
|
419
|
+
this.degrade('auth', e.message);
|
|
420
|
+
else
|
|
421
|
+
this.degrade('connectivity', 'initial unread check unavailable; retrying');
|
|
422
|
+
await this.deps.sleep(BACKOFF_MAX_MS);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (this.stopped)
|
|
427
|
+
return;
|
|
503
428
|
let body;
|
|
504
429
|
try {
|
|
505
430
|
body = await this.doFetch(String(this.cursor ?? 0), LONGPOLL_STALL_MS, 'stall');
|
|
@@ -510,11 +435,6 @@ export class Monitor {
|
|
|
510
435
|
catch (e) {
|
|
511
436
|
if (this.stopped)
|
|
512
437
|
return;
|
|
513
|
-
if (e instanceof AuthError && !this.profile) {
|
|
514
|
-
this.fatal = true;
|
|
515
|
-
this.degrade('auth', e.message, 'failed');
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
438
|
backoff = Math.min(backoff + BACKOFF_STEP_MS, BACKOFF_MAX_MS);
|
|
519
439
|
if (e instanceof AuthError)
|
|
520
440
|
this.degrade('auth', e.message);
|
|
@@ -579,7 +499,9 @@ export class Monitor {
|
|
|
579
499
|
catch { /* no stragglers / abort — deliver what we have */ }
|
|
580
500
|
}
|
|
581
501
|
async deliver(pid, batch) {
|
|
582
|
-
|
|
502
|
+
return this.deliverLine(formatNotificationLine(batch));
|
|
503
|
+
}
|
|
504
|
+
async deliverLine(line) {
|
|
583
505
|
if (!this.deps.delivery) {
|
|
584
506
|
this.degrade('delivery', 'structured agent-session delivery is unavailable');
|
|
585
507
|
return false;
|
|
@@ -630,23 +552,19 @@ export class Monitor {
|
|
|
630
552
|
this.currentAbort = ctrl;
|
|
631
553
|
let timedOut = false;
|
|
632
554
|
const timer = this.deps.timers.set(() => { timedOut = true; ctrl.abort(); }, timeoutMs);
|
|
633
|
-
let resp;
|
|
634
555
|
try {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
return { cursor: page.cursor, events: page.events };
|
|
643
|
-
}
|
|
644
|
-
resp = await this.deps.fetch(`${this.ep.url(this.identity)}?since=${since}`, { headers: this.ep.headers, signal: ctrl.signal });
|
|
556
|
+
const client = await this.profileClient();
|
|
557
|
+
const page = await client.readNotificationPage(this.identity, {
|
|
558
|
+
since: since === 'tip' ? 'tip' : Number.parseInt(since, 10),
|
|
559
|
+
signal: ctrl.signal,
|
|
560
|
+
requestTimeoutMs: timeoutMs,
|
|
561
|
+
});
|
|
562
|
+
return { cursor: page.cursor, events: page.events };
|
|
645
563
|
}
|
|
646
564
|
catch (error) {
|
|
647
565
|
if (timedOut && timeoutKind === 'stall')
|
|
648
566
|
throw new Error(`notification stream stalled for ${Math.round(timeoutMs / 1000)}s`);
|
|
649
|
-
if (
|
|
567
|
+
if (/(?:HTTP\s*401|unauthori[sz]ed|API token)/i.test(msg(error)))
|
|
650
568
|
throw new AuthError(`daemon rejected the API token (401) — verify the credential file `
|
|
651
569
|
+ `${JSON.stringify(this.profile.credentialPath)} selected by `
|
|
652
570
|
+ `${JSON.stringify(this.profile.configPath)}`);
|
|
@@ -656,15 +574,8 @@ export class Monitor {
|
|
|
656
574
|
this.deps.timers.clear(timer);
|
|
657
575
|
this.currentAbort = null;
|
|
658
576
|
}
|
|
659
|
-
if (resp.status === 401)
|
|
660
|
-
throw new AuthError(`daemon rejected the API token (401) — ${authResolutionHint(this.ep)}`);
|
|
661
|
-
if (!resp.ok)
|
|
662
|
-
throw new Error(`daemon returned HTTP ${resp.status}`);
|
|
663
|
-
return resp.json();
|
|
664
577
|
}
|
|
665
578
|
profileClient() {
|
|
666
|
-
if (!this.profile)
|
|
667
|
-
throw new Error('explicit client profile is not selected');
|
|
668
579
|
if (!this.profileClientPromise) {
|
|
669
580
|
const { endpoint, expectedInstanceId, credentialPath } = this.profile;
|
|
670
581
|
const options = {
|
|
@@ -678,6 +589,32 @@ export class Monitor {
|
|
|
678
589
|
}
|
|
679
590
|
return this.profileClientPromise;
|
|
680
591
|
}
|
|
592
|
+
async readInitialUnread() {
|
|
593
|
+
const ctrl = new AbortController();
|
|
594
|
+
this.currentAbort = ctrl;
|
|
595
|
+
const timer = this.deps.timers.set(() => ctrl.abort(), 5_000);
|
|
596
|
+
let client;
|
|
597
|
+
try {
|
|
598
|
+
const { endpoint, expectedInstanceId, credentialPath } = this.profile;
|
|
599
|
+
const options = {
|
|
600
|
+
endpoint, expectedInstanceId, credentialPath,
|
|
601
|
+
sessionMode: 'external', leaseToken: this.monitorLeaseToken, env: {},
|
|
602
|
+
requestSignal: ctrl.signal,
|
|
603
|
+
};
|
|
604
|
+
client = await (this.deps.attachClient?.(options) ?? attachOursClient(options));
|
|
605
|
+
return await client.unread();
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
if (/(?:HTTP\s*401|unauthori[sz]ed|API token)/i.test(msg(error)))
|
|
609
|
+
throw new AuthError('daemon rejected the API token (401); initial unread check unavailable; retrying');
|
|
610
|
+
throw error;
|
|
611
|
+
}
|
|
612
|
+
finally {
|
|
613
|
+
this.deps.timers.clear(timer);
|
|
614
|
+
this.currentAbort = null;
|
|
615
|
+
await client?.close().catch(() => undefined);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
681
618
|
async disposeProfileClient() {
|
|
682
619
|
const pending = this.profileClientPromise;
|
|
683
620
|
this.profileClientPromise = undefined;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ProducerConfig } from './outbox.js';
|
|
2
|
+
/** Read durable supervisor ledgers without restarting agents or attaching a
|
|
3
|
+
* conversation controller. Each tick reads at most 256 KiB per role, from its
|
|
4
|
+
* checkpoint; it never loads a complete transcript or requests model history. */
|
|
5
|
+
export declare class FleetNotificationProducer {
|
|
6
|
+
private readonly roots;
|
|
7
|
+
private readonly stateDir;
|
|
8
|
+
private readonly config;
|
|
9
|
+
private readonly warn;
|
|
10
|
+
private readonly queues;
|
|
11
|
+
private readonly timer;
|
|
12
|
+
private readonly existing;
|
|
13
|
+
private cleanup?;
|
|
14
|
+
constructor(roots: string[], stateDir: string, config: ProducerConfig, warn?: (line: string) => void);
|
|
15
|
+
private names;
|
|
16
|
+
poll(): void;
|
|
17
|
+
drain(): Promise<void>;
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
}
|