@ours.network/fleet 1.2.0-nightly.7 → 1.2.0-nightly.71
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 +279 -68
- package/dist/account-origin.d.ts +2 -0
- package/dist/account-origin.js +6 -0
- package/dist/agent-ours/bridge.js +26 -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 +19 -0
- package/dist/agent-ours/mcp-endpoint.js +98 -25
- package/dist/agent-ours/runtime.d.ts +9 -1
- package/dist/agent-ours/runtime.js +50 -2
- package/dist/agent-ours/service.d.ts +24 -1
- package/dist/agent-ours/service.js +97 -13
- package/dist/application/codex-models.d.ts +15 -0
- package/dist/application/codex-models.js +56 -0
- package/dist/application/conversation-history.d.ts +34 -0
- package/dist/application/conversation-history.js +280 -0
- package/dist/application/conversation-role-observer.d.ts +62 -0
- package/dist/application/conversation-role-observer.js +206 -0
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +3 -3
- 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/resource-observer.d.ts +40 -0
- package/dist/application/resource-observer.js +278 -0
- package/dist/application/role-creation-service.js +3 -2
- package/dist/application/role-removal-service.js +17 -3
- package/dist/application/role-repository.d.ts +1 -1
- package/dist/application/role-repository.js +30 -7
- 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 +61 -17
- package/dist/application/session-control.js +207 -23
- package/dist/application/supervisor-ours-tools.js +5 -11
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +261 -0
- package/dist/application/task-room-service.d.ts +101 -3
- package/dist/application/task-room-service.js +286 -33
- package/dist/application/types.d.ts +2 -0
- package/dist/atomic-file.d.ts +34 -1
- package/dist/atomic-file.js +161 -18
- package/dist/briefing.d.ts +3 -1
- package/dist/briefing.js +97 -31
- package/dist/build-info.json +9 -4
- package/dist/capabilities.d.ts +9 -1
- package/dist/capabilities.js +13 -0
- package/dist/cli.js +400 -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 +14 -9
- package/dist/daemon-recovery.js +124 -115
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +207 -19
- package/dist/doctor.d.ts +4 -1
- package/dist/doctor.js +75 -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 +24 -8
- package/dist/harness/agent-session.d.ts +4 -0
- package/dist/harness/claude-code-session.js +1 -1
- package/dist/harness/claude-code.js +21 -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 +24 -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 +9 -34
- package/dist/monitor.js +90 -153
- package/dist/notifications/fleet-producer.d.ts +22 -0
- package/dist/notifications/fleet-producer.js +237 -0
- package/dist/notifications/outbox.d.ts +46 -0
- package/dist/notifications/outbox.js +158 -0
- package/dist/notifications/target-cleanup.d.ts +11 -0
- package/dist/notifications/target-cleanup.js +63 -0
- package/dist/notifications/task-producer.d.ts +20 -0
- package/dist/notifications/task-producer.js +100 -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 +43 -0
- package/dist/process-incarnation.d.ts +23 -0
- package/dist/process-incarnation.js +42 -0
- package/dist/reminders/manager.d.ts +75 -0
- package/dist/reminders/manager.js +278 -0
- package/dist/reminders/runtime.d.ts +27 -0
- package/dist/reminders/runtime.js +32 -0
- package/dist/reminders/schedule.d.ts +37 -0
- package/dist/reminders/schedule.js +104 -0
- package/dist/reminders/store.d.ts +341 -0
- package/dist/reminders/store.js +762 -0
- package/dist/reminders/tools.d.ts +20 -0
- package/dist/reminders/tools.js +114 -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 +84 -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 +12 -5
- package/dist/rooms-tasks/cowork-adapter.js +15 -121
- package/dist/rooms-tasks/cowork-http.js +56 -6
- 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 +286 -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 +52 -8
- package/dist/rooms-tasks/task-state.js +251 -26
- 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 +33 -4
- package/dist/runner.js +410 -62
- package/dist/session/acp.d.ts +75 -2
- package/dist/session/acp.js +345 -82
- package/dist/session/arbiter.d.ts +98 -0
- package/dist/session/arbiter.js +272 -3
- package/dist/session/codex-app-server.d.ts +45 -1
- package/dist/session/codex-app-server.js +225 -32
- package/dist/session/control.d.ts +17 -3
- package/dist/session/control.js +213 -23
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-observation.d.ts +25 -0
- package/dist/session/conversation-observation.js +100 -0
- package/dist/session/conversation-replay.d.ts +50 -0
- package/dist/session/conversation-replay.js +203 -0
- package/dist/session/conversation-store.d.ts +15 -1
- package/dist/session/conversation-store.js +206 -26
- package/dist/session/conversation-types.d.ts +57 -4
- package/dist/session/prompt-batch.d.ts +79 -0
- package/dist/session/prompt-batch.js +120 -0
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +42 -1
- 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 +15 -0
- package/dist/startup-prompt.js +71 -0
- package/dist/startup-readiness.d.ts +32 -0
- package/dist/startup-readiness.js +101 -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 +77 -0
- package/dist/subscriptions/login.js +215 -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 +143 -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/registration-refresh.d.ts +45 -0
- package/dist/supervisor/registration-refresh.js +266 -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 +123 -66
- 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/watchdog/query.d.ts +3 -1
- package/dist/watchdog/query.js +2 -1
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +65 -2
- package/dist/web/auth.js +201 -11
- 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/conversation-stream-codec.d.ts +23 -0
- package/dist/web/conversation-stream-codec.js +110 -0
- package/dist/web/conversation-stream.d.ts +25 -0
- package/dist/web/conversation-stream.js +231 -0
- package/dist/web/events.d.ts +2 -0
- package/dist/web/events.js +9 -0
- 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 +248 -0
- package/dist/web/resource-views.d.ts +124 -0
- package/dist/web/resource-views.js +424 -0
- package/dist/web/runtime.d.ts +3 -1
- package/dist/web/runtime.js +132 -34
- package/dist/web/server.d.ts +19 -0
- package/dist/web/server.js +802 -67
- 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 +83 -0
- package/dist/workspace-enrollment.js +580 -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/conversation-stream.md +196 -0
- package/docs/fleet-migration.md +54 -0
- package/docs/live-voice.md +13 -0
- package/docs/room-layouts.md +227 -0
- package/docs/self-reminders.md +374 -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 +24 -20
- 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 +4 -2
- 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 +12 -11
- package/presets/fleet/roles/Critic.yaml +13 -0
- package/presets/fleet/roles/Developer.yaml +13 -0
- package/presets/fleet/roles/Engineer.yaml +53 -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,13 @@ 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
|
-
|
|
137
|
-
export declare function authResolutionHint(ep: DaemonEndpoint): string;
|
|
111
|
+
export declare function classifyIdentityPresence(name: string, identities: unknown): IdentityPresence;
|
|
138
112
|
/** Keep only the events whose type the role asked to wake on. */
|
|
139
113
|
export declare function filterEvents(events: NotifyEvent[], wakeSources: string[]): NotifyEvent[];
|
|
140
114
|
/**
|
|
@@ -196,8 +170,7 @@ export declare class Monitor {
|
|
|
196
170
|
private readonly identity;
|
|
197
171
|
private readonly cfg;
|
|
198
172
|
private readonly deps;
|
|
199
|
-
private readonly
|
|
200
|
-
private readonly profile?;
|
|
173
|
+
private readonly profile;
|
|
201
174
|
private readonly profileKey;
|
|
202
175
|
private readonly monitorLeaseToken;
|
|
203
176
|
private profileClientPromise?;
|
|
@@ -211,6 +184,7 @@ export declare class Monitor {
|
|
|
211
184
|
private stopped;
|
|
212
185
|
private bootDeadline;
|
|
213
186
|
private currentAbort;
|
|
187
|
+
private initialBacklogPending;
|
|
214
188
|
private apiErrorStreak;
|
|
215
189
|
private readonly turnFailThreshold;
|
|
216
190
|
/** Active degradations, keyed by cause. Empty means armed. */
|
|
@@ -230,6 +204,7 @@ export declare class Monitor {
|
|
|
230
204
|
/** Gather stragglers arriving within batch_ms so a burst lands as one line. */
|
|
231
205
|
private coalesce;
|
|
232
206
|
private deliver;
|
|
207
|
+
private deliverLine;
|
|
233
208
|
/** Update the consecutive-API-error streak and derive `.monitor-status` from it. */
|
|
234
209
|
private recordTurn;
|
|
235
210
|
/**
|
|
@@ -242,6 +217,7 @@ export declare class Monitor {
|
|
|
242
217
|
*/
|
|
243
218
|
private doFetch;
|
|
244
219
|
private profileClient;
|
|
220
|
+
private readInitialUnread;
|
|
245
221
|
private disposeProfileClient;
|
|
246
222
|
private advance;
|
|
247
223
|
private persistCursor;
|
|
@@ -263,4 +239,3 @@ export declare class Monitor {
|
|
|
263
239
|
private writeStatus;
|
|
264
240
|
}
|
|
265
241
|
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,127 +41,31 @@ 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
|
-
function classifyIdentityPresence(name, identities) {
|
|
68
|
+
export function classifyIdentityPresence(name, identities) {
|
|
166
69
|
if (!Array.isArray(identities))
|
|
167
70
|
return { state: 'unknown', detail: 'identity index response is malformed' };
|
|
168
71
|
// A healthy daemon normally has at least its Human identity. During daemon
|
|
@@ -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,22 @@
|
|
|
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 observation;
|
|
12
|
+
private continuation?;
|
|
13
|
+
private stopped;
|
|
14
|
+
private readonly existing;
|
|
15
|
+
private cleanup?;
|
|
16
|
+
constructor(roots: string[], stateDir: string, config: ProducerConfig, warn?: (line: string) => void);
|
|
17
|
+
private names;
|
|
18
|
+
poll(): void;
|
|
19
|
+
private resume;
|
|
20
|
+
drain(): Promise<void>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|