@ours.network/fleet 1.2.0-nightly.6 → 1.2.0-nightly.60
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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as acp from '@agentclientprotocol/sdk';
|
|
2
|
-
import type { AdapterMeta, ConversationEventKind, ConversationPayload } from './conversation-types.js';
|
|
2
|
+
import type { AdapterMeta, BoundedJson, ConversationEventKind, ConversationPayload } from './conversation-types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Reduce one ACP v1 `session/update` into one conversation-domain event draft.
|
|
5
5
|
*
|
|
@@ -43,4 +43,5 @@ export interface NormalizedUpdate {
|
|
|
43
43
|
toolCallId?: string;
|
|
44
44
|
adapterMeta?: AdapterMeta[];
|
|
45
45
|
}
|
|
46
|
+
export declare function boundedJson(value: unknown): BoundedJson;
|
|
46
47
|
export declare function normalizeSessionUpdate(update: acp.SessionUpdate, options?: NormalizeOptions): NormalizedUpdate;
|
|
@@ -29,6 +29,7 @@ type EventDraft = Omit<ConversationEventV1, 'schemaVersion' | 'roleId' | 'eventI
|
|
|
29
29
|
export declare class ConversationEventStore {
|
|
30
30
|
private readonly dir;
|
|
31
31
|
private nextSeq;
|
|
32
|
+
private firstAvailableSeq?;
|
|
32
33
|
private segments;
|
|
33
34
|
private tail;
|
|
34
35
|
private readonly listeners;
|
|
@@ -81,7 +82,6 @@ export declare class ConversationEventStore {
|
|
|
81
82
|
private trackPromptState;
|
|
82
83
|
private segmentFd;
|
|
83
84
|
private writeManifest;
|
|
84
|
-
private firstStoredSeq;
|
|
85
85
|
private eventsAfter;
|
|
86
86
|
private markDegraded;
|
|
87
87
|
}
|
|
@@ -24,6 +24,7 @@ export class IdempotencyConflictError extends Error {
|
|
|
24
24
|
export class ConversationEventStore {
|
|
25
25
|
dir;
|
|
26
26
|
nextSeq = 1;
|
|
27
|
+
firstAvailableSeq;
|
|
27
28
|
segments = [];
|
|
28
29
|
tail = [];
|
|
29
30
|
listeners = new Set();
|
|
@@ -72,6 +73,7 @@ export class ConversationEventStore {
|
|
|
72
73
|
const fd = this.segmentFd(Buffer.byteLength(line));
|
|
73
74
|
writeSync(fd, line);
|
|
74
75
|
fsyncSync(fd);
|
|
76
|
+
this.firstAvailableSeq ??= event.seq;
|
|
75
77
|
this.nextSeq++;
|
|
76
78
|
this.activeBytes += Buffer.byteLength(line);
|
|
77
79
|
this.tail.push(event);
|
|
@@ -101,7 +103,10 @@ export class ConversationEventStore {
|
|
|
101
103
|
const events = this.eventsAfter(after, limit + 1);
|
|
102
104
|
const hasMore = events.length > limit;
|
|
103
105
|
const pageEvents = hasMore ? events.slice(0, limit) : events;
|
|
104
|
-
|
|
106
|
+
// This single-writer store never removes retained segments. Recovery and
|
|
107
|
+
// append already know the first readable sequence; paging the memory tail
|
|
108
|
+
// must not parse the first segment again, especially while skipping replay.
|
|
109
|
+
const firstStored = this.firstAvailableSeq;
|
|
105
110
|
return {
|
|
106
111
|
events: pageEvents,
|
|
107
112
|
...(firstStored !== undefined ? { firstAvailableCursor: String(firstStored) } : {}),
|
|
@@ -159,6 +164,7 @@ export class ConversationEventStore {
|
|
|
159
164
|
let maxSeq = 0;
|
|
160
165
|
for (const segment of this.segments) {
|
|
161
166
|
for (const event of this.readSegment(segment)) {
|
|
167
|
+
this.firstAvailableSeq ??= event.seq;
|
|
162
168
|
maxSeq = Math.max(maxSeq, event.seq);
|
|
163
169
|
this.tail.push(event);
|
|
164
170
|
if (this.tail.length > TAIL_EVENTS)
|
|
@@ -308,16 +314,6 @@ export class ConversationEventStore {
|
|
|
308
314
|
}
|
|
309
315
|
}
|
|
310
316
|
// ── reads ──────────────────────────────────────────────────────────────────
|
|
311
|
-
firstStoredSeq() {
|
|
312
|
-
if (this.tail.length && this.tail[0].seq === 1)
|
|
313
|
-
return 1;
|
|
314
|
-
for (const segment of this.segments) {
|
|
315
|
-
const events = this.readSegment(segment);
|
|
316
|
-
if (events.length)
|
|
317
|
-
return events[0].seq;
|
|
318
|
-
}
|
|
319
|
-
return this.tail[0]?.seq;
|
|
320
|
-
}
|
|
321
317
|
eventsAfter(after, limit) {
|
|
322
318
|
// Serve from the in-memory tail whenever the range allows it.
|
|
323
319
|
if (this.tail.length && after >= this.tail[0].seq - 1)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TaskCreatedNotice } from './task-notice.js';
|
|
1
2
|
import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Durable conversation domain schema for managed-session consoles.
|
|
@@ -7,11 +8,11 @@ import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.
|
|
|
7
8
|
* file touches the wire: transport updates are reduced into these shapes by a
|
|
8
9
|
* session adapter, and the store assigns `seq`/`eventId`/timestamps.
|
|
9
10
|
*/
|
|
10
|
-
export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
|
|
11
|
+
export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'file.attached' | 'fleet.task_created' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
|
|
11
12
|
/** A well-formed transport update this version cannot represent. Bounded, never a crash. */
|
|
12
13
|
| 'unsupported';
|
|
13
14
|
/** Where a conversation record came from. Typed provenance, never prompt text. */
|
|
14
|
-
export type ConversationSource = 'owner_admin_console' | 'owner_channel' | 'fleet_monitor' | 'scheduled_loop' | 'startup' | 'local_console' | 'agent' | 'agent_replay';
|
|
15
|
+
export type ConversationSource = 'owner_admin_console' | 'owner_channel' | 'fleet_monitor' | 'scheduled_loop' | 'startup' | 'local_console' | 'agent' | 'agent_replay' | 'fleet_lifecycle';
|
|
15
16
|
export interface NormalizedText {
|
|
16
17
|
type: 'text';
|
|
17
18
|
text: string;
|
|
@@ -175,6 +176,12 @@ export interface PromptAdmittedPayload {
|
|
|
175
176
|
}
|
|
176
177
|
export interface PromptStartedPayload {
|
|
177
178
|
queuedBehind?: number;
|
|
179
|
+
/** Present when one adapter turn carries several admitted prompts; `turnId` is the shared turn. */
|
|
180
|
+
batch?: {
|
|
181
|
+
turnId: string;
|
|
182
|
+
index: number;
|
|
183
|
+
size: number;
|
|
184
|
+
};
|
|
178
185
|
}
|
|
179
186
|
export interface PromptInterruptRequestedPayload {
|
|
180
187
|
commandId?: string;
|
|
@@ -227,7 +234,9 @@ export interface BoundedJson {
|
|
|
227
234
|
digest?: string;
|
|
228
235
|
redacted?: true;
|
|
229
236
|
}
|
|
230
|
-
export type ConversationPayload =
|
|
237
|
+
export type ConversationPayload = {
|
|
238
|
+
attachment: import('../file-delivery/types.js').DeliveredFile;
|
|
239
|
+
} | MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | MonitorDeliveryPayload | SessionLifecyclePayload | ErrorPayload | TaskCreatedNotice;
|
|
231
240
|
export interface ConversationEventV1 {
|
|
232
241
|
schemaVersion: 1;
|
|
233
242
|
roleId: string;
|
|
@@ -262,6 +271,9 @@ export interface ConversationEventV1 {
|
|
|
262
271
|
adapterMeta?: AdapterMeta[];
|
|
263
272
|
}
|
|
264
273
|
export interface SubmitPromptCommand {
|
|
274
|
+
expectedSessionGeneration?: string;
|
|
275
|
+
/** Live speech must not silently queue behind an unrelated turn. */
|
|
276
|
+
requireIdle?: boolean;
|
|
265
277
|
/** Idempotency-Key / clientRequestId. Reuse with a different body is a conflict. */
|
|
266
278
|
commandId: string;
|
|
267
279
|
text: string;
|
|
@@ -283,12 +295,25 @@ export interface PermissionDecisionCommand {
|
|
|
283
295
|
sessionGeneration: string;
|
|
284
296
|
optionId: string;
|
|
285
297
|
}
|
|
298
|
+
/** One admitted prompt not yet handed to the agent, as reported by the queue that owns it. */
|
|
299
|
+
export interface PendingPromptSummary {
|
|
300
|
+
promptId: string;
|
|
301
|
+
source: ConversationSource;
|
|
302
|
+
admittedAt: string;
|
|
303
|
+
bytes: number;
|
|
304
|
+
/** A bounded preview, present only for a body the ledger already holds. */
|
|
305
|
+
text?: string;
|
|
306
|
+
textTruncated?: boolean;
|
|
307
|
+
}
|
|
286
308
|
export interface ConversationSnapshot {
|
|
287
309
|
sessionGeneration: string;
|
|
288
310
|
readiness: 'starting' | 'idle' | 'running' | 'awaiting_permission' | 'failed' | 'offline';
|
|
289
311
|
queueDepth: number;
|
|
290
312
|
pendingPermissionIds: string[];
|
|
291
313
|
historyDegraded?: boolean;
|
|
314
|
+
/** Every waiting prompt, in delivery order; `pendingPromptCount` equals its length. */
|
|
315
|
+
pendingPrompts?: PendingPromptSummary[];
|
|
316
|
+
pendingPromptCount?: number;
|
|
292
317
|
}
|
|
293
318
|
export interface ConversationPage {
|
|
294
319
|
events: ConversationEventV1[];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ConversationSource, PendingPromptSummary } from './conversation-types.js';
|
|
2
|
+
import type { PromptOrigin, TurnResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A prompt the session has admitted and not yet handed to the adapter.
|
|
5
|
+
*
|
|
6
|
+
* Every admitted prompt keeps its own id, ledger records and completion. What
|
|
7
|
+
* changes at a turn boundary is how many of them one adapter turn carries.
|
|
8
|
+
*/
|
|
9
|
+
export interface PendingPrompt {
|
|
10
|
+
promptId: string;
|
|
11
|
+
text: string;
|
|
12
|
+
origin?: PromptOrigin;
|
|
13
|
+
source: ConversationSource;
|
|
14
|
+
/** Whether the ledger already holds this body; an external body is never copied out of the queue. */
|
|
15
|
+
persistBody: boolean;
|
|
16
|
+
admittedAt: string;
|
|
17
|
+
/** Whether the session recognised the text, at admission, as one of its own control operations. */
|
|
18
|
+
command?: boolean;
|
|
19
|
+
/** Set when a release takes this prompt; every member of that turn shares it. */
|
|
20
|
+
released?: Promise<TurnResult>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* How a waiting prompt takes part in a release.
|
|
24
|
+
*
|
|
25
|
+
* - `message`: something a person or a peer route submitted for the agent to
|
|
26
|
+
* read — the paired console, the owner channel, the local console, a
|
|
27
|
+
* monitor wake. Every waiting message is delivered at one boundary, in
|
|
28
|
+
* admission order, whatever its route.
|
|
29
|
+
* - `command`: a control operation the session itself supports — the native
|
|
30
|
+
* `/compact`, a command the ACP adapter advertised. It must reach the
|
|
31
|
+
* adapter as the entire prompt, so it is its own turn and a boundary
|
|
32
|
+
* between the messages before and after it. The session decides this at
|
|
33
|
+
* admission; text that merely starts with a slash is an ordinary message.
|
|
34
|
+
* - `internal`: startup, scheduled-loop and stall-watchdog prompts. They own
|
|
35
|
+
* their turn's lifecycle (and, for a loop, the redaction of its whole
|
|
36
|
+
* transcript), run alone, and never split the messages around them.
|
|
37
|
+
*/
|
|
38
|
+
export type PromptClass = 'message' | 'command' | 'internal';
|
|
39
|
+
export declare function promptClass(prompt: Pick<PendingPrompt, 'origin' | 'command'>): PromptClass;
|
|
40
|
+
/** The command name a prompt invokes, when its whole text has the shape of one. */
|
|
41
|
+
export declare function commandName(text: string): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Detach, in admission order, every pending prompt that is delivered with
|
|
44
|
+
* `head`. Synchronous on purpose: this is the snapshot boundary, and a prompt
|
|
45
|
+
* admitted after it returns belongs to the next release.
|
|
46
|
+
*/
|
|
47
|
+
export declare function takeBatch(pending: PendingPrompt[], head: PendingPrompt): PendingPrompt[];
|
|
48
|
+
/** Exact, server-computed identity of one member's body inside a shared turn. */
|
|
49
|
+
export interface MemberBinding {
|
|
50
|
+
index: number;
|
|
51
|
+
of: number;
|
|
52
|
+
source: ConversationSource;
|
|
53
|
+
bytes: number;
|
|
54
|
+
sha256: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function memberBindings(members: ReadonlyArray<Pick<PendingPrompt, 'text' | 'origin'>>, sourceOf: (origin: PromptOrigin | undefined) => ConversationSource): MemberBinding[];
|
|
57
|
+
/** What the server asserts about a member's route; never derived from the member's text. */
|
|
58
|
+
export declare function memberAuthority(source: ConversationSource): string;
|
|
59
|
+
/** What a client may show for prompts still waiting: all of them, in order, and never an unpersisted body. */
|
|
60
|
+
export declare function pendingInventory(pending: readonly PendingPrompt[]): {
|
|
61
|
+
pendingPrompts: PendingPromptSummary[];
|
|
62
|
+
pendingPromptCount: number;
|
|
63
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* The inventory names every waiting prompt — a client must be able to show the
|
|
4
|
+
* whole queue, not a count of what it could not see. What keeps a snapshot
|
|
5
|
+
* small is the body: each entry carries a short preview, not the prompt.
|
|
6
|
+
*/
|
|
7
|
+
const INVENTORY_TEXT_CHARS = 200;
|
|
8
|
+
const INTERNAL = new Set(['startup', 'scheduled-loop', 'stall-watchdog']);
|
|
9
|
+
export function promptClass(prompt) {
|
|
10
|
+
if (INTERNAL.has(prompt.origin?.kind ?? 'local-console'))
|
|
11
|
+
return 'internal';
|
|
12
|
+
return prompt.command ? 'command' : 'message';
|
|
13
|
+
}
|
|
14
|
+
/** The command name a prompt invokes, when its whole text has the shape of one. */
|
|
15
|
+
export function commandName(text) {
|
|
16
|
+
return /^\/([a-z][a-z0-9_-]*)(?:\s|$)/i.exec(text.trim())?.[1];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Detach, in admission order, every pending prompt that is delivered with
|
|
20
|
+
* `head`. Synchronous on purpose: this is the snapshot boundary, and a prompt
|
|
21
|
+
* admitted after it returns belongs to the next release.
|
|
22
|
+
*/
|
|
23
|
+
export function takeBatch(pending, head) {
|
|
24
|
+
const members = [];
|
|
25
|
+
if (promptClass(head) !== 'message')
|
|
26
|
+
members.push(head);
|
|
27
|
+
else {
|
|
28
|
+
for (const prompt of pending) {
|
|
29
|
+
const kind = promptClass(prompt);
|
|
30
|
+
if (kind === 'command')
|
|
31
|
+
break;
|
|
32
|
+
if (kind === 'message')
|
|
33
|
+
members.push(prompt);
|
|
34
|
+
}
|
|
35
|
+
if (!members.includes(head))
|
|
36
|
+
members.unshift(head);
|
|
37
|
+
}
|
|
38
|
+
for (const member of members) {
|
|
39
|
+
const at = pending.indexOf(member);
|
|
40
|
+
if (at >= 0)
|
|
41
|
+
pending.splice(at, 1);
|
|
42
|
+
}
|
|
43
|
+
return members;
|
|
44
|
+
}
|
|
45
|
+
export function memberBindings(members, sourceOf) {
|
|
46
|
+
return members.map((member, at) => ({
|
|
47
|
+
index: at + 1,
|
|
48
|
+
of: members.length,
|
|
49
|
+
source: sourceOf(member.origin),
|
|
50
|
+
bytes: Buffer.byteLength(member.text),
|
|
51
|
+
sha256: createHash('sha256').update(member.text).digest('hex'),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
/** What the server asserts about a member's route; never derived from the member's text. */
|
|
55
|
+
export function memberAuthority(source) {
|
|
56
|
+
switch (source) {
|
|
57
|
+
case 'owner_admin_console':
|
|
58
|
+
return 'direct owner input from the server-authenticated paired console';
|
|
59
|
+
case 'owner_channel':
|
|
60
|
+
return 'admitted through the authenticated Fleet owner channel';
|
|
61
|
+
case 'fleet_monitor':
|
|
62
|
+
return 'a Fleet monitor notification, not owner input';
|
|
63
|
+
default:
|
|
64
|
+
return 'local console input, not authenticated owner-console or owner-channel input';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** What a client may show for prompts still waiting: all of them, in order, and never an unpersisted body. */
|
|
68
|
+
export function pendingInventory(pending) {
|
|
69
|
+
return {
|
|
70
|
+
pendingPromptCount: pending.length,
|
|
71
|
+
pendingPrompts: pending.map(prompt => {
|
|
72
|
+
const display = prompt.origin?.kind === 'owner' ? prompt.origin.displayText
|
|
73
|
+
: prompt.persistBody ? prompt.text : undefined;
|
|
74
|
+
return {
|
|
75
|
+
promptId: prompt.promptId,
|
|
76
|
+
source: prompt.source,
|
|
77
|
+
admittedAt: prompt.admittedAt,
|
|
78
|
+
bytes: Buffer.byteLength(prompt.text),
|
|
79
|
+
...(display === undefined ? {} : {
|
|
80
|
+
text: display.slice(0, INVENTORY_TEXT_CHARS),
|
|
81
|
+
...(display.length > INVENTORY_TEXT_CHARS ? { textTruncated: true } : {}),
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ConversationEventStore } from './conversation-store.js';
|
|
2
|
+
export interface TaskNoticeBinding {
|
|
3
|
+
sessionGeneration: string;
|
|
4
|
+
acpSessionId: string;
|
|
5
|
+
promptId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TaskCreatedNotice {
|
|
8
|
+
operationId: string;
|
|
9
|
+
taskId: string;
|
|
10
|
+
title: string;
|
|
11
|
+
state: string;
|
|
12
|
+
}
|
|
13
|
+
/** Only the trusted Fleet audit completion calls this, never model output. */
|
|
14
|
+
export declare function appendTaskCreated(store: ConversationEventStore, binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Only the trusted Fleet audit completion calls this, never model output. */
|
|
2
|
+
export function appendTaskCreated(store, binding, notice) {
|
|
3
|
+
let after;
|
|
4
|
+
do {
|
|
5
|
+
const page = store.page({ after, limit: 1000 });
|
|
6
|
+
if (page.events.some(e => e.kind === 'fleet.task_created' && e.payload.operationId === notice.operationId))
|
|
7
|
+
return;
|
|
8
|
+
if (!page.hasMore)
|
|
9
|
+
break;
|
|
10
|
+
after = page.nextCursor;
|
|
11
|
+
} while (after);
|
|
12
|
+
store.append({ kind: 'fleet.task_created', source: 'fleet_lifecycle', ...binding, turnId: binding.promptId, payload: notice });
|
|
13
|
+
}
|
package/dist/session/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TaskCreatedNotice, TaskNoticeBinding } from './task-notice.js';
|
|
1
2
|
import type { SessionBackendId } from '../config.js';
|
|
2
3
|
import type { ConversationEventV1, ConversationSnapshot, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
|
|
3
4
|
/**
|
|
@@ -185,6 +186,8 @@ export interface SessionSnapshot {
|
|
|
185
186
|
backend: SessionBackendId;
|
|
186
187
|
alive: boolean;
|
|
187
188
|
readiness: SessionReadiness;
|
|
189
|
+
/** Typed source of the active prompt; excludes prompt bodies and command IDs. */
|
|
190
|
+
activePromptSource?: PromptOrigin['kind'];
|
|
188
191
|
sessionId?: string;
|
|
189
192
|
lastError?: string;
|
|
190
193
|
pendingPermissionId?: string;
|
|
@@ -283,12 +286,15 @@ export interface ConversationHandlePage {
|
|
|
283
286
|
* on any concrete transport which implements it.
|
|
284
287
|
*/
|
|
285
288
|
export interface AgentSession {
|
|
289
|
+
sendFileToChat?: (input: import('../file-delivery/types.js').FileDeliveryInput, signal: AbortSignal, copy: import('../file-delivery/types.js').CopyChatFile, policy: import('../config.js').CommonPermissions) => Promise<import('../file-delivery/types.js').DeliveredFile>;
|
|
286
290
|
readonly backend: SessionBackendId;
|
|
287
291
|
readonly pid: number;
|
|
288
292
|
/** Live capabilities; optional only for source compatibility with external adapters. */
|
|
289
293
|
readonly capabilities?: AgentSessionCapabilities;
|
|
290
294
|
isAlive(): boolean;
|
|
291
295
|
snapshot(): SessionSnapshot;
|
|
296
|
+
taskNoticeBinding?(): TaskNoticeBinding | undefined;
|
|
297
|
+
recordTaskCreated?(binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
|
|
292
298
|
conversationPage?(request: {
|
|
293
299
|
after?: string;
|
|
294
300
|
limit?: number;
|
|
@@ -301,6 +307,11 @@ export interface AgentSession {
|
|
|
301
307
|
* Hand the session a prompt and return as soon as it has accepted
|
|
302
308
|
* responsibility for it. Throws `SessionControlError` if it cannot.
|
|
303
309
|
*/
|
|
310
|
+
/**
|
|
311
|
+
* The turn that carries an admitted prompt when one adapter turn delivered
|
|
312
|
+
* several; absent means the prompt's own id is its turn id.
|
|
313
|
+
*/
|
|
314
|
+
sharedTurnId?(promptId: string): string | undefined;
|
|
304
315
|
queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
|
|
305
316
|
/** Queue a prompt and wait for its terminal result. */
|
|
306
317
|
submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
|
|
@@ -316,6 +327,9 @@ export interface AgentSession {
|
|
|
316
327
|
* keep compiling. Read it through `interruptOutcome`, never directly.
|
|
317
328
|
*/
|
|
318
329
|
interrupt(source?: TurnCancellationSource): Promise<InterruptResult>;
|
|
330
|
+
/** Atomically bind cancellation to one voice-owned turn. */
|
|
331
|
+
readonly liveVoiceSupported?: boolean;
|
|
332
|
+
interruptPrompt?(generation: string, promptId: string): Promise<InterruptResult>;
|
|
319
333
|
respondPermission(permissionId: string, optionId: string): boolean;
|
|
320
334
|
/** Generation-bound browser decision; stale/settled/invalid all fail closed. */
|
|
321
335
|
respondPermissionV2?(permissionId: string, optionId: string, sessionGeneration: string): 'accepted' | 'stale';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Exec } from './exec.js';
|
|
2
|
+
import type { WorkspacePayload } from './workspace-enrollment.js';
|
|
3
|
+
/**
|
|
4
|
+
* Check what the steps after the one-time root proof depend on, before that
|
|
5
|
+
* proof is sent: a failure afterwards cannot be retried with a fresh command.
|
|
6
|
+
*/
|
|
7
|
+
export declare function setupTunnelPreflight({ exec, platform, node }?: {
|
|
8
|
+
exec?: Exec;
|
|
9
|
+
platform?: NodeJS.Platform;
|
|
10
|
+
node?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
/** What the steps after the proof need, kept so they can be finished without a new command. */
|
|
13
|
+
export interface PendingTunnelSetup {
|
|
14
|
+
appOrigin: string;
|
|
15
|
+
origin: string;
|
|
16
|
+
hostWorkspaceId: string;
|
|
17
|
+
rootCid: string;
|
|
18
|
+
challenge: WorkspacePayload['challenge'];
|
|
19
|
+
/** Fleet configuration the setup started with; a resume must use the same one. */
|
|
20
|
+
configuration: string;
|
|
21
|
+
/** Every port sent to the account as the tunnel target. Without confirmedPort, the remote target may be any of these or the default. */
|
|
22
|
+
requestedPorts?: number[];
|
|
23
|
+
/** Last positively confirmed target; cleared before any new retarget request. */
|
|
24
|
+
confirmedPort?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function savePendingTunnelSetup(pending: PendingTunnelSetup): void;
|
|
27
|
+
export declare function clearPendingTunnelSetup(): void;
|
|
28
|
+
export declare function readPendingTunnelSetup(): PendingTunnelSetup;
|
|
29
|
+
export declare const DEFAULT_TUNNEL_PORT = 49271;
|
|
30
|
+
/**
|
|
31
|
+
* The port the web service must bind when the account can no longer retarget
|
|
32
|
+
* the tunnel. Unknown when a different port was requested and never confirmed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function requiredPortAfterExpiry(pending: PendingTunnelSetup): number;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { existsSync, lstatSync, readFileSync, rmSync } from 'node:fs';
|
|
2
|
+
import { userInfo } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { replaceFileAtomically } from './atomic-file.js';
|
|
5
|
+
import { realExec } from './exec.js';
|
|
6
|
+
import { stateRoot } from './paths.js';
|
|
7
|
+
const UNCHANGED = 'Nothing was changed and this host was not bound.';
|
|
8
|
+
/**
|
|
9
|
+
* Check what the steps after the one-time root proof depend on, before that
|
|
10
|
+
* proof is sent: a failure afterwards cannot be retried with a fresh command.
|
|
11
|
+
*/
|
|
12
|
+
export async function setupTunnelPreflight({ exec = realExec, platform = process.platform, node = process.versions.node } = {}) {
|
|
13
|
+
const [major, minor] = node.split('.').map(Number);
|
|
14
|
+
if (major < 22 || (major === 22 && minor < 13))
|
|
15
|
+
throw Error(`Tunnel setup requires Node.js 22.13 or newer; this is ${node}. Update Node.js, then run a fresh tunnel setup command. ${UNCHANGED}`);
|
|
16
|
+
if (platform === 'linux') {
|
|
17
|
+
const manager = await exec('systemctl', ['--user', 'show-environment'], { timeout: 10_000 });
|
|
18
|
+
if (manager.code !== 0)
|
|
19
|
+
throw Error(`The user service manager is not reachable from this shell (${manager.stderr.trim().split('\n')[0] || `systemctl --user exited ${manager.code}`}). `
|
|
20
|
+
+ `Log in directly as ${userInfo().username} (not through su or sudo), or run: sudo loginctl enable-linger ${userInfo().username} && export XDG_RUNTIME_DIR=/run/user/${process.getuid?.()} `
|
|
21
|
+
+ `Then run a fresh tunnel setup command. ${UNCHANGED}`);
|
|
22
|
+
}
|
|
23
|
+
const help = await exec('cloudflared', ['tunnel', 'run', '--help'], { timeout: 10_000 });
|
|
24
|
+
if (help.code === 127)
|
|
25
|
+
throw Error(`cloudflared is not installed or not on PATH. Install it, then run a fresh tunnel setup command. ${UNCHANGED}`);
|
|
26
|
+
if (help.code !== 0 || !`${help.stdout}\n${help.stderr}`.includes('--token-file'))
|
|
27
|
+
throw Error(`This cloudflared is too old for tunnel setup (no --token-file support). Update cloudflared, then run a fresh tunnel setup command. ${UNCHANGED}`);
|
|
28
|
+
}
|
|
29
|
+
const pendingPath = () => join(stateRoot(), 'workspace', 'pending-setup.json');
|
|
30
|
+
export function savePendingTunnelSetup(pending) {
|
|
31
|
+
replaceFileAtomically(pendingPath(), JSON.stringify(pending) + '\n', 0o600);
|
|
32
|
+
}
|
|
33
|
+
export function clearPendingTunnelSetup() { rmSync(pendingPath(), { force: true }); }
|
|
34
|
+
export function readPendingTunnelSetup() {
|
|
35
|
+
const path = pendingPath();
|
|
36
|
+
if (!existsSync(path))
|
|
37
|
+
throw Error('No unfinished tunnel setup on this host. Run the tunnel setup command from the App.');
|
|
38
|
+
const stat = lstatSync(path);
|
|
39
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077) !== 0)
|
|
40
|
+
throw Error('Unfinished tunnel setup record must be an owned private file');
|
|
41
|
+
const pending = JSON.parse(readFileSync(path, 'utf8'));
|
|
42
|
+
if (typeof pending?.appOrigin !== 'string' || typeof pending.origin !== 'string' || typeof pending.hostWorkspaceId !== 'string'
|
|
43
|
+
|| typeof pending.rootCid !== 'string' || !pending.challenge || !Number.isSafeInteger(pending.challenge.expiresAt) || typeof pending.configuration !== 'string'
|
|
44
|
+
|| (pending.requestedPorts !== undefined && (!Array.isArray(pending.requestedPorts) || !pending.requestedPorts.every(Number.isInteger))))
|
|
45
|
+
throw Error('Unfinished tunnel setup record is invalid');
|
|
46
|
+
if (pending.confirmedPort !== undefined && (!Number.isInteger(pending.confirmedPort) || pending.confirmedPort < 1024 || pending.confirmedPort > 65535))
|
|
47
|
+
throw Error('Unfinished tunnel setup record is invalid');
|
|
48
|
+
return pending;
|
|
49
|
+
}
|
|
50
|
+
export const DEFAULT_TUNNEL_PORT = 49_271;
|
|
51
|
+
/**
|
|
52
|
+
* The port the web service must bind when the account can no longer retarget
|
|
53
|
+
* the tunnel. Unknown when a different port was requested and never confirmed.
|
|
54
|
+
*/
|
|
55
|
+
export function requiredPortAfterExpiry(pending) {
|
|
56
|
+
if (pending.confirmedPort !== undefined)
|
|
57
|
+
return pending.confirmedPort;
|
|
58
|
+
const other = [...new Set(pending.requestedPorts ?? [])].filter(port => port !== DEFAULT_TUNNEL_PORT);
|
|
59
|
+
if (!other.length)
|
|
60
|
+
return DEFAULT_TUNNEL_PORT;
|
|
61
|
+
throw Error(`The setup window has expired and it is unknown whether the tunnel points at port ${[...other, DEFAULT_TUNNEL_PORT].join(' or ')}: the account's answer to a port request was not received. This setup cannot be finished automatically`);
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { lstatSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
/** Optional private socket directory for deeply nested, isolated Fleet homes. */
|
|
5
|
+
export function socketPath(logicalPath) {
|
|
6
|
+
const root = process.env.OURS_FLEET_SOCKET_ROOT;
|
|
7
|
+
if (!root) {
|
|
8
|
+
if (Buffer.byteLength(logicalPath) > 103)
|
|
9
|
+
throw new Error('Unix socket path is too long; configure a short private OURS_FLEET_SOCKET_ROOT');
|
|
10
|
+
return logicalPath;
|
|
11
|
+
}
|
|
12
|
+
if (!isAbsolute(root) || resolve(root) !== root)
|
|
13
|
+
throw new Error('OURS_FLEET_SOCKET_ROOT must be an absolute normalized path');
|
|
14
|
+
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
15
|
+
const stat = lstatSync(root);
|
|
16
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o777) !== 0o700)
|
|
17
|
+
throw new Error('OURS_FLEET_SOCKET_ROOT must be an owner-only 0700 directory');
|
|
18
|
+
const path = join(root, createHash('sha256').update(resolve(logicalPath)).digest('hex').slice(0, 24) + '.sock');
|
|
19
|
+
if (Buffer.byteLength(path) > 103)
|
|
20
|
+
throw new Error('OURS_FLEET_SOCKET_ROOT is too long');
|
|
21
|
+
return path;
|
|
22
|
+
}
|
package/dist/spawn.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type CreationDeps, type CreationProvenance } from './creation.js';
|
|
|
6
6
|
import './harness/claude-code.js';
|
|
7
7
|
import './harness/codex.js';
|
|
8
8
|
import './harness/hermes.js';
|
|
9
|
-
import { type SupervisorLauncher } from './temp-lifecycle.js';
|
|
9
|
+
import { type SupervisorLauncher, type TaskSupervisorOwner } from './temp-lifecycle.js';
|
|
10
10
|
/**
|
|
11
11
|
* The provenance record written by the most recent spawn in this process, so
|
|
12
12
|
* the CLI can print the same summary it persisted rather than rebuilding it.
|
|
@@ -15,6 +15,8 @@ export declare let lastProvenance: CreationProvenance | undefined;
|
|
|
15
15
|
export interface SpawnOpts {
|
|
16
16
|
name: string;
|
|
17
17
|
temp?: boolean;
|
|
18
|
+
/** Internal exact task-layout ownership, never a standalone manifest entry. */
|
|
19
|
+
taskOwner?: TaskSupervisorOwner;
|
|
18
20
|
brain?: AgentSelection;
|
|
19
21
|
role?: AgentSelection;
|
|
20
22
|
/** Trusted canonical definition used by room provisioning; never a second schema. */
|
|
@@ -85,3 +87,5 @@ export declare function spawnPermanent(o: SpawnOpts, deps: OpsDeps, creation?: C
|
|
|
85
87
|
export type { SupervisorLauncher } from './temp-lifecycle.js';
|
|
86
88
|
/** Temp spawn: live state under ~/.ours-fleet/tmp, independent transient supervision. */
|
|
87
89
|
export declare function spawnTemp(o: SpawnOpts, binPath: string, launch?: SupervisorLauncher, creation?: CreationDeps): Promise<string>;
|
|
90
|
+
/** Resume the exact durable task launch; no creation, invite issuance or state rotation. */
|
|
91
|
+
export declare function resumeTaskSupervisor(name: string, binPath: string): Promise<void>;
|
package/dist/spawn.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { taskSupervisorMayRun } from './task-supervision.js';
|
|
1
2
|
import { randomUUID } from 'node:crypto';
|
|
2
3
|
import { storeRoomSecret, storeTemporaryLaunch, preparePermanentAssignment } from './agent-ours/service.js';
|
|
4
|
+
import { ensureWorkspace } from './rooms-tasks/workspace.js';
|
|
3
5
|
import { spawn as spawnChild } from 'node:child_process';
|
|
4
6
|
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
7
|
import { join } from 'node:path';
|
|
@@ -15,7 +17,8 @@ import { recordGeneratedAgentSource } from './generated-agent-source.js';
|
|
|
15
17
|
import './harness/claude-code.js';
|
|
16
18
|
import './harness/codex.js';
|
|
17
19
|
import './harness/hermes.js';
|
|
18
|
-
import {
|
|
20
|
+
import { getAdapter } from './harness/registry.js';
|
|
21
|
+
import { archiveTempState, makeTempSupervisorLauncher, prepareTempSupervisor, reclaimStaleTempState, stopTempSupervisor, secureStoppedTempArchive, readTempSupervisor, requestedTempStopReason, } from './temp-lifecycle.js';
|
|
19
22
|
/**
|
|
20
23
|
* The provenance record written by the most recent spawn in this process, so
|
|
21
24
|
* the CLI can print the same summary it persisted rather than rebuilding it.
|
|
@@ -321,6 +324,14 @@ export async function spawnTemp(o, binPath, launch = independentSupervisor, crea
|
|
|
321
324
|
if (o.isolationFile)
|
|
322
325
|
readIsolationFile(o.isolationFile); // fail before reserving
|
|
323
326
|
const prepared = resolvedSpawn(o); // canonical validation before mutation
|
|
327
|
+
if ((o.taskOwner || o.roomMemberStartup?.task_id) && !getAdapter(prepared.role.harness).supportsResume)
|
|
328
|
+
throw Error('TASK_HARNESS_RESUME_UNSUPPORTED: task agents require a resumable harness');
|
|
329
|
+
if (o.roomMemberStartup?.workspace) {
|
|
330
|
+
const workspace = o.roomMemberStartup.workspace;
|
|
331
|
+
if (prepared.role.cwd !== workspace.path)
|
|
332
|
+
throw new Error('room member cwd must equal its recorded owned workspace');
|
|
333
|
+
ensureWorkspace(workspace);
|
|
334
|
+
}
|
|
324
335
|
// Retire only supervisors whose recorded owner is definitively stopped. This
|
|
325
336
|
// bounded pass keeps the active roster clean without deleting old evidence.
|
|
326
337
|
await reclaimStaleTempState();
|
|
@@ -351,7 +362,7 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
|
|
|
351
362
|
if (role.roomMemberStartup)
|
|
352
363
|
role.roomMemberStartup = { ...role.roomMemberStartup, invite: '' };
|
|
353
364
|
onStage?.('writing_role');
|
|
354
|
-
const dir = applyRole(role, { temp: true, identityGuarantee: 'unverified' });
|
|
365
|
+
const dir = applyRole(role, { temp: true, identityGuarantee: 'unverified', configPath: o.configPath });
|
|
355
366
|
const provenance = buildProvenance({
|
|
356
367
|
role: o.name, lifetime: 'temporary', fleetVersion: VERSION,
|
|
357
368
|
settings: provenanceSettings(o, cfg.defaults, preparedRole.temporaryLoops),
|
|
@@ -361,7 +372,14 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
|
|
|
361
372
|
lastProvenance = provenance;
|
|
362
373
|
tx.record({
|
|
363
374
|
stage: `temp state dir ${dir}`,
|
|
364
|
-
undo: () => {
|
|
375
|
+
undo: async () => {
|
|
376
|
+
if (o.taskOwner || role.roomMemberStartup?.task_id) {
|
|
377
|
+
await stopTempSupervisor(o.name);
|
|
378
|
+
const supervisor = readTempSupervisor(dir);
|
|
379
|
+
if (supervisor)
|
|
380
|
+
await secureStoppedTempArchive(o.name, supervisor.launchId);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
365
383
|
// A failed launch is still lifecycle evidence: briefing, provenance,
|
|
366
384
|
// metadata and supervisor output explain what happened. Remove it from
|
|
367
385
|
// the live roster by atomic archive, never recursive deletion.
|
|
@@ -374,7 +392,14 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
|
|
|
374
392
|
// out; a lone temp spawn still waits zero (time-based gate).
|
|
375
393
|
if (cfg.startStaggerMs > 0)
|
|
376
394
|
writeFileSync(join(dir, START_STAGGER_FILE), String(cfg.startStaggerMs));
|
|
377
|
-
prepareTempSupervisor(dir, o.name
|
|
395
|
+
prepareTempSupervisor(dir, o.name, o.taskOwner ?? (o.roomMemberStartup?.task_id ? {
|
|
396
|
+
taskId: o.roomMemberStartup.task_id,
|
|
397
|
+
roomId: o.roomMemberStartup.room_id,
|
|
398
|
+
roomIdentityCid: o.roomMemberStartup.room_identity_cid,
|
|
399
|
+
creationActionId: o.creationActionId,
|
|
400
|
+
} : undefined));
|
|
401
|
+
if (o.taskOwner || o.roomMemberStartup?.task_id)
|
|
402
|
+
taskSupervisorMayRun(o.name);
|
|
378
403
|
// Run the supervisor independently. On a service-managed host the temp
|
|
379
404
|
// runner gets its own transient unit/job, so stopping the coordinator's unit
|
|
380
405
|
// cannot kill a live worker in the coordinator's cgroup.
|
|
@@ -382,3 +407,14 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
|
|
|
382
407
|
await launch(binPath, ['_run-temp', o.name], dir);
|
|
383
408
|
return dir;
|
|
384
409
|
}
|
|
410
|
+
/** Resume the exact durable task launch; no creation, invite issuance or state rotation. */
|
|
411
|
+
export async function resumeTaskSupervisor(name, binPath) {
|
|
412
|
+
if (!taskSupervisorMayRun(name))
|
|
413
|
+
throw Error('TASK_SUPERVISOR_RETIRED');
|
|
414
|
+
const dir = agentDir(name, true);
|
|
415
|
+
if (requestedTempStopReason(dir))
|
|
416
|
+
throw Error('TASK_SUPERVISOR_STOP_REQUESTED');
|
|
417
|
+
const launcher = readTempSupervisor(dir)?.kind === 'detached'
|
|
418
|
+
? makeTempSupervisorLauncher({ spawnDetached, supervisor: 'none' }) : independentSupervisor;
|
|
419
|
+
await launcher(binPath, ['_run-temp', name], dir);
|
|
420
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Readiness is a separate turn after identity/profile and room admission succeed. */
|
|
2
|
+
export declare function managedStartupPrompt(stateDir: string, mode: 'fresh' | 'resume', hasPriorBoot?: boolean): string;
|
|
3
|
+
/** Configured work/continuity runs after readiness, never inside the fast turn. */
|
|
4
|
+
export declare function managedTaskPrompt(stateDir: string, mode: 'fresh' | 'resume', hasPriorBoot?: boolean): string;
|