@ours.network/fleet 1.2.0-nightly.6 → 1.2.0-nightly.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +287 -65
- package/dist/account-origin.d.ts +2 -0
- package/dist/account-origin.js +6 -0
- package/dist/agent-ours/bridge.js +35 -9
- package/dist/agent-ours/correspondence.d.ts +10 -0
- package/dist/agent-ours/correspondence.js +1 -0
- package/dist/agent-ours/file-rpc.d.ts +12 -0
- package/dist/agent-ours/file-rpc.js +18 -4
- package/dist/agent-ours/harness.js +9 -1
- package/dist/agent-ours/mcp-endpoint.d.ts +4 -0
- package/dist/agent-ours/mcp-endpoint.js +5 -0
- package/dist/agent-ours/runtime.d.ts +9 -1
- package/dist/agent-ours/runtime.js +50 -2
- package/dist/agent-ours/service.d.ts +21 -1
- package/dist/agent-ours/service.js +94 -14
- package/dist/application/codex-models.d.ts +15 -0
- package/dist/application/codex-models.js +56 -0
- package/dist/application/conversation-history.d.ts +27 -0
- package/dist/application/conversation-history.js +212 -0
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +2 -2
- package/dist/application/legacy-supervisor-identity.d.ts +7 -0
- package/dist/application/legacy-supervisor-identity.js +43 -0
- package/dist/application/log-service.js +8 -8
- package/dist/application/model-catalog.d.ts +1 -1
- package/dist/application/model-catalog.js +5 -2
- package/dist/application/preset-provenance.d.ts +19 -0
- package/dist/application/preset-provenance.js +59 -0
- package/dist/application/role-creation-service.js +3 -2
- package/dist/application/role-removal-service.js +9 -1
- package/dist/application/role-repository.js +19 -2
- package/dist/application/room-layout-definitions.d.ts +45 -0
- package/dist/application/room-layout-definitions.js +130 -0
- package/dist/application/session-control.d.ts +30 -0
- package/dist/application/session-control.js +72 -3
- package/dist/application/supervisor-ours-tools.d.ts +159 -0
- package/dist/application/supervisor-ours-tools.js +115 -0
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +259 -0
- package/dist/application/task-room-service.d.ts +99 -3
- package/dist/application/task-room-service.js +285 -32
- package/dist/application/types.d.ts +2 -0
- package/dist/atomic-file.d.ts +5 -0
- package/dist/atomic-file.js +62 -1
- package/dist/briefing.d.ts +3 -1
- package/dist/briefing.js +70 -30
- package/dist/build-info.json +7 -4
- package/dist/capabilities.d.ts +6 -1
- package/dist/capabilities.js +8 -0
- package/dist/cli.js +407 -37
- package/dist/client-profile.d.ts +5 -17
- package/dist/client-profile.js +4 -127
- package/dist/config.d.ts +45 -0
- package/dist/config.js +57 -6
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +4 -4
- package/dist/daemon-recovery.d.ts +1 -8
- package/dist/daemon-recovery.js +8 -113
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +123 -19
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +55 -60
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/file-delivery/reader.d.ts +15 -0
- package/dist/file-delivery/reader.js +63 -0
- package/dist/file-delivery/store.d.ts +15 -0
- package/dist/file-delivery/store.js +124 -0
- package/dist/file-delivery/types.d.ts +19 -0
- package/dist/file-delivery/types.js +1 -0
- package/dist/fleet-command-audit.d.ts +7 -0
- package/dist/fleet-command-audit.js +26 -9
- package/dist/harness/agent-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +1 -1
- package/dist/harness/claude-code.js +20 -11
- package/dist/harness/claude-runtime.d.ts +12 -0
- package/dist/harness/claude-runtime.js +43 -0
- package/dist/harness/codex-app-server-proxy.d.ts +4 -1
- package/dist/harness/codex-app-server-proxy.js +41 -5
- package/dist/harness/codex-reasoning.d.ts +5 -0
- package/dist/harness/codex-reasoning.js +12 -0
- package/dist/harness/codex-runtime.d.ts +11 -1
- package/dist/harness/codex-runtime.js +31 -4
- package/dist/harness/codex-session.js +2 -2
- package/dist/harness/codex.js +23 -12
- package/dist/init-wizard.d.ts +2 -0
- package/dist/init-wizard.js +38 -19
- package/dist/isolation/policy.js +6 -1
- package/dist/isolation/types.d.ts +5 -0
- package/dist/managed-cli.d.ts +253 -0
- package/dist/managed-cli.js +923 -0
- package/dist/managed-recovery.d.ts +13 -0
- package/dist/managed-recovery.js +31 -0
- package/dist/minimal-setup.d.ts +2 -0
- package/dist/minimal-setup.js +44 -0
- package/dist/monitor.d.ts +8 -34
- package/dist/monitor.js +89 -152
- package/dist/notifications/fleet-producer.d.ts +19 -0
- package/dist/notifications/fleet-producer.js +208 -0
- package/dist/notifications/outbox.d.ts +46 -0
- package/dist/notifications/outbox.js +158 -0
- package/dist/notifications/target-cleanup.d.ts +8 -0
- package/dist/notifications/target-cleanup.js +41 -0
- package/dist/notifications/task-producer.d.ts +18 -0
- package/dist/notifications/task-producer.js +67 -0
- package/dist/ops.d.ts +2 -0
- package/dist/ops.js +20 -3
- package/dist/owner-channel/channel.js +17 -6
- package/dist/owner-channel/commands.d.ts +4 -0
- package/dist/owner-channel/commands.js +8 -0
- package/dist/owner-channel/lifecycle-outbox.js +4 -3
- package/dist/owner-channel/ours-client.js +2 -17
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +2 -0
- package/dist/preset-migration.js +25 -0
- package/dist/resolved-plan.js +1 -0
- package/dist/rooms-tasks/add-member.d.ts +48 -0
- package/dist/rooms-tasks/add-member.js +83 -0
- package/dist/rooms-tasks/archived-absence.d.ts +8 -0
- package/dist/rooms-tasks/archived-absence.js +48 -0
- package/dist/rooms-tasks/cli.js +65 -5
- package/dist/rooms-tasks/close.d.ts +6 -2
- package/dist/rooms-tasks/close.js +246 -37
- package/dist/rooms-tasks/config.d.ts +1 -1
- package/dist/rooms-tasks/config.js +11 -4
- package/dist/rooms-tasks/cowork-adapter.d.ts +2 -4
- package/dist/rooms-tasks/cowork-adapter.js +7 -121
- package/dist/rooms-tasks/cowork-http.js +29 -1
- package/dist/rooms-tasks/deletion.d.ts +1 -1
- package/dist/rooms-tasks/deletion.js +84 -5
- package/dist/rooms-tasks/erasure.d.ts +6 -0
- package/dist/rooms-tasks/erasure.js +173 -0
- package/dist/rooms-tasks/external-worker.d.ts +1 -1
- package/dist/rooms-tasks/external-worker.js +3 -4
- package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
- package/dist/rooms-tasks/layout-binding-client.js +56 -0
- package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
- package/dist/rooms-tasks/layout-binding-grants.js +128 -0
- package/dist/rooms-tasks/layout-cli.d.ts +4 -0
- package/dist/rooms-tasks/layout-cli.js +107 -0
- package/dist/rooms-tasks/layout-config.d.ts +11 -0
- package/dist/rooms-tasks/layout-config.js +89 -0
- package/dist/rooms-tasks/layout-control.d.ts +21 -0
- package/dist/rooms-tasks/layout-control.js +52 -0
- package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
- package/dist/rooms-tasks/layout-member-retirement.js +90 -0
- package/dist/rooms-tasks/layout-service.d.ts +43 -0
- package/dist/rooms-tasks/layout-service.js +203 -0
- package/dist/rooms-tasks/layout.d.ts +121 -0
- package/dist/rooms-tasks/layout.js +285 -0
- package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
- package/dist/rooms-tasks/legacy-task-member.js +116 -0
- package/dist/rooms-tasks/live-readiness.d.ts +18 -0
- package/dist/rooms-tasks/live-readiness.js +85 -0
- package/dist/rooms-tasks/member-ownership.d.ts +5 -0
- package/dist/rooms-tasks/member-ownership.js +40 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +2 -0
- package/dist/rooms-tasks/provision.d.ts +3 -0
- package/dist/rooms-tasks/provision.js +101 -49
- package/dist/rooms-tasks/recovery.d.ts +19 -0
- package/dist/rooms-tasks/recovery.js +110 -0
- package/dist/rooms-tasks/room-state.d.ts +4 -2
- package/dist/rooms-tasks/room-state.js +47 -8
- package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
- package/dist/rooms-tasks/task-service-retirement.js +21 -0
- package/dist/rooms-tasks/task-state.d.ts +51 -8
- package/dist/rooms-tasks/task-state.js +245 -25
- package/dist/rooms-tasks/types.d.ts +40 -0
- package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
- package/dist/rooms-tasks/workspace-artifacts.js +93 -0
- package/dist/rooms-tasks/workspace.d.ts +35 -0
- package/dist/rooms-tasks/workspace.js +325 -0
- package/dist/runner.d.ts +25 -3
- package/dist/runner.js +291 -49
- package/dist/session/acp.d.ts +53 -1
- package/dist/session/acp.js +216 -40
- package/dist/session/arbiter.d.ts +11 -0
- package/dist/session/arbiter.js +43 -2
- package/dist/session/codex-app-server.d.ts +32 -0
- package/dist/session/codex-app-server.js +137 -23
- package/dist/session/control.d.ts +12 -1
- package/dist/session/control.js +68 -3
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-store.d.ts +1 -1
- package/dist/session/conversation-store.js +7 -11
- package/dist/session/conversation-types.d.ts +28 -3
- package/dist/session/prompt-batch.d.ts +63 -0
- package/dist/session/prompt-batch.js +86 -0
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +14 -0
- package/dist/setup-tunnel-preflight.d.ts +34 -0
- package/dist/setup-tunnel-preflight.js +62 -0
- package/dist/socket-path.d.ts +2 -0
- package/dist/socket-path.js +22 -0
- package/dist/spawn.d.ts +5 -1
- package/dist/spawn.js +40 -4
- package/dist/startup-prompt.d.ts +4 -0
- package/dist/startup-prompt.js +36 -0
- package/dist/startup-readiness.d.ts +13 -0
- package/dist/startup-readiness.js +38 -0
- package/dist/startup-telemetry.d.ts +16 -0
- package/dist/startup-telemetry.js +46 -0
- package/dist/subscriptions/cli.d.ts +91 -0
- package/dist/subscriptions/cli.js +223 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +75 -0
- package/dist/subscriptions/login.js +182 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +140 -0
- package/dist/supervisor/adoption.d.ts +8 -0
- package/dist/supervisor/adoption.js +78 -0
- package/dist/supervisor/catalog.d.ts +62 -0
- package/dist/supervisor/catalog.js +254 -0
- package/dist/supervisor/fleet.d.ts +8 -0
- package/dist/supervisor/fleet.js +89 -0
- package/dist/supervisor/index.js +3 -6
- package/dist/supervisor/launchd.d.ts +1 -1
- package/dist/supervisor/launchd.js +26 -13
- package/dist/supervisor/legacy.d.ts +35 -0
- package/dist/supervisor/legacy.js +524 -0
- package/dist/supervisor/manager.d.ts +15 -0
- package/dist/supervisor/manager.js +270 -0
- package/dist/supervisor/scope.d.ts +4 -0
- package/dist/supervisor/scope.js +10 -0
- package/dist/supervisor/systemd.d.ts +2 -2
- package/dist/supervisor/systemd.js +19 -33
- package/dist/task-supervision.d.ts +9 -0
- package/dist/task-supervision.js +145 -0
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +23 -8
- package/dist/temp-lifecycle.js +113 -65
- package/dist/temp-supervisor-recovery.d.ts +1 -1
- package/dist/temp-supervisor-recovery.js +2 -2
- package/dist/tunnel-setup-completion.d.ts +7 -0
- package/dist/tunnel-setup-completion.js +13 -0
- package/dist/tunnel-setup-input.d.ts +19 -0
- package/dist/tunnel-setup-input.js +124 -0
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +63 -2
- package/dist/web/auth.js +191 -10
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/control.d.ts +3 -3
- package/dist/web/control.js +10 -8
- package/dist/web/fleet-config-service.d.ts +4 -1
- package/dist/web/fleet-config-service.js +46 -15
- package/dist/web/prefix-gateway.d.ts +32 -0
- package/dist/web/prefix-gateway.js +238 -0
- package/dist/web/runtime.d.ts +3 -1
- package/dist/web/runtime.js +116 -31
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.js +654 -55
- package/dist/web/service.d.ts +11 -2
- package/dist/web/service.js +30 -4
- package/dist/web/workspace-devices.d.ts +107 -0
- package/dist/web/workspace-devices.js +277 -0
- package/dist/web/workspace-tunnel.d.ts +1 -0
- package/dist/web/workspace-tunnel.js +34 -0
- package/dist/workspace-enrollment.d.ts +82 -0
- package/dist/workspace-enrollment.js +566 -0
- package/dist/workspace-replacement.d.ts +66 -0
- package/dist/workspace-replacement.js +220 -0
- package/docs/acp-files.md +146 -0
- package/docs/fleet-migration.md +54 -0
- package/docs/live-voice.md +13 -0
- package/docs/room-layouts.md +227 -0
- package/docs/task-workspaces.md +225 -0
- package/docs/validation/managed-cli-permissions.md +421 -0
- package/examples/room-layouts/fresh.yaml +27 -0
- package/examples/room-layouts/scoped.yaml +21 -0
- package/examples/room-layouts/shared.yaml +19 -0
- package/package.json +20 -19
- package/presets/README.md +78 -0
- package/presets/brain-catalog.json +8 -2
- package/presets/fleet/agent_templates/Critic.yaml +1 -1
- package/presets/fleet/agent_templates/Developer.yaml +1 -1
- package/presets/fleet/agent_templates/Engineer.yaml +5 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
- package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
- package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +34 -11
- package/presets/fleet/roles/Engineer.yaml +40 -0
- package/presets/fleet/room_layouts/engineering.yaml +25 -0
- package/presets/fleet/room_layouts/pair.yaml +24 -0
- package/presets/fleet/room_layouts/single.yaml +17 -0
- package/presets/fleet/room_layouts/team.yaml +30 -0
- package/presets/fleet/room_templates/engineering.yaml +19 -0
- package/presets/manifest.json +2 -2
- package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
- package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
- package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
- package/dist/web-app/icons/ours-fleet.svg +0 -4
- package/dist/web-app/index.html +0 -17
- package/dist/web-app/manifest.webmanifest +0 -15
- package/dist/web-app/offline.html +0 -18
- package/dist/web-app/sw.js +0 -51
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { open, readFile, readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
const HISTORICAL_KINDS = ['file.attached', 'fleet.task_created', 'prompt.admitted', 'message.chunk', 'message.replace', 'tool.upsert', 'tool.content_chunk', 'turn.completed'];
|
|
6
|
+
/** Whether a ledger event belongs in the conversation: the live generation, or history of the resumed ACP session. */
|
|
7
|
+
export function conversationEventVisible(event, sessionGeneration, resumedSessionId) {
|
|
8
|
+
return event.source !== 'agent_replay' && (event.sessionGeneration === sessionGeneration || (!!resumedSessionId && HISTORICAL_KINDS.includes(event.kind) && event.acpSessionId === resumedSessionId));
|
|
9
|
+
}
|
|
10
|
+
/** Newest-first lines of a file, read in chunks from its end; `visit` returns false to stop. */
|
|
11
|
+
async function readLinesBackward(path, visit) {
|
|
12
|
+
const file = await open(path, 'r');
|
|
13
|
+
try {
|
|
14
|
+
let position = (await file.stat()).size;
|
|
15
|
+
let carry = Buffer.alloc(0);
|
|
16
|
+
while (position > 0) {
|
|
17
|
+
const size = Math.min(256 * 1024, position);
|
|
18
|
+
position -= size;
|
|
19
|
+
const chunk = Buffer.alloc(size);
|
|
20
|
+
await file.read(chunk, 0, size, position);
|
|
21
|
+
let buffer = Buffer.concat([chunk, carry]);
|
|
22
|
+
let end = buffer.length;
|
|
23
|
+
for (let i = buffer.length - 1; i >= 0; i--) {
|
|
24
|
+
if (buffer[i] !== 10)
|
|
25
|
+
continue;
|
|
26
|
+
if (end > i + 1 && !visit(buffer.toString('utf8', i + 1, end)))
|
|
27
|
+
return false;
|
|
28
|
+
end = i;
|
|
29
|
+
}
|
|
30
|
+
carry = buffer.subarray(0, end);
|
|
31
|
+
}
|
|
32
|
+
if (carry.length && !visit(carry.toString('utf8')))
|
|
33
|
+
return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await file.close();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** The last event cursor in a segment, read from its tail; undefined when none is readable. */
|
|
41
|
+
async function lastSeq(path) {
|
|
42
|
+
let seq;
|
|
43
|
+
await readLinesBackward(path, line => { try {
|
|
44
|
+
const value = Number(JSON.parse(line).seq);
|
|
45
|
+
if (Number.isSafeInteger(value)) {
|
|
46
|
+
seq = value;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch { } return true; });
|
|
51
|
+
return seq;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The newest `limit` visible events before `before` (or the newest overall),
|
|
55
|
+
* read backwards from the ledger so opening a long session costs one page.
|
|
56
|
+
* `nextCursor` is the newest ledger position seen, for forward `after` paging.
|
|
57
|
+
*/
|
|
58
|
+
export async function conversationTailPage(stateDir, request, snapshot, resumedSessionId) {
|
|
59
|
+
const before = request.before === undefined ? Infinity : Number(request.before);
|
|
60
|
+
if (before !== Infinity && (!Number.isSafeInteger(before) || before < 0))
|
|
61
|
+
throw new Error('before must be a ledger cursor');
|
|
62
|
+
const limit = Math.min(1000, Math.max(1, Number.isFinite(request.limit) ? Math.floor(request.limit) : 200));
|
|
63
|
+
let files = [];
|
|
64
|
+
try {
|
|
65
|
+
files = (await readdir(join(stateDir, '.conversation'))).filter(n => /^events-\d{6}\.jsonl$/.test(n)).sort().reverse();
|
|
66
|
+
}
|
|
67
|
+
catch { }
|
|
68
|
+
const events = [];
|
|
69
|
+
let newest;
|
|
70
|
+
let hasOlder = false;
|
|
71
|
+
const pending = new Set(snapshot.pendingPermissionIds);
|
|
72
|
+
let capabilities;
|
|
73
|
+
const context = [];
|
|
74
|
+
// Context only accompanies the newest page; older pages stop as soon as they are full.
|
|
75
|
+
const wantsContext = () => before === Infinity && (!capabilities || pending.size > 0);
|
|
76
|
+
const generation = `"sessionGeneration":${JSON.stringify(snapshot.sessionGeneration)}`;
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const more = await readLinesBackward(join(stateDir, '.conversation', file), line => {
|
|
79
|
+
if (hasOlder) {
|
|
80
|
+
// The page is full; only the current generation's context kinds matter. Generations are
|
|
81
|
+
// appended in order, so the first line of an older one ends the search.
|
|
82
|
+
if (!line.includes(generation))
|
|
83
|
+
return !line.includes('"sessionGeneration":') && wantsContext();
|
|
84
|
+
if (!line.includes('"capabilities.updated"') && !line.includes('"permission.requested"'))
|
|
85
|
+
return wantsContext();
|
|
86
|
+
}
|
|
87
|
+
let event;
|
|
88
|
+
try {
|
|
89
|
+
event = JSON.parse(line);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
const seq = Number(event.seq);
|
|
95
|
+
if (!Number.isSafeInteger(seq))
|
|
96
|
+
return true;
|
|
97
|
+
newest ??= seq;
|
|
98
|
+
if (seq < before && conversationEventVisible(event, snapshot.sessionGeneration, resumedSessionId)) {
|
|
99
|
+
const inPage = !hasOlder && events.length < limit;
|
|
100
|
+
if (event.sessionGeneration === snapshot.sessionGeneration) {
|
|
101
|
+
if (event.kind === 'capabilities.updated' && !capabilities) {
|
|
102
|
+
capabilities = event;
|
|
103
|
+
if (!inPage)
|
|
104
|
+
context.push(event);
|
|
105
|
+
}
|
|
106
|
+
if (event.kind === 'permission.requested' && event.permissionId && pending.delete(event.permissionId) && !inPage)
|
|
107
|
+
context.push(event);
|
|
108
|
+
}
|
|
109
|
+
if (inPage)
|
|
110
|
+
events.push(event);
|
|
111
|
+
else
|
|
112
|
+
hasOlder = true;
|
|
113
|
+
}
|
|
114
|
+
return !hasOlder || wantsContext();
|
|
115
|
+
});
|
|
116
|
+
if (!more)
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
events.reverse();
|
|
120
|
+
context.reverse();
|
|
121
|
+
return { events, snapshot, hasOlder, context, hasMore: false,
|
|
122
|
+
...(events.length ? { olderCursor: String(events[0].seq) } : {}),
|
|
123
|
+
...(before === Infinity && newest !== undefined ? { nextCursor: String(newest) } : {}) };
|
|
124
|
+
}
|
|
125
|
+
/** Read the existing ACP session ledger without opening its writer/recovery store. */
|
|
126
|
+
export async function resumedConversationPage(stateDir, request, live, expectedSessionId) {
|
|
127
|
+
let sessionId;
|
|
128
|
+
let files;
|
|
129
|
+
try {
|
|
130
|
+
sessionId = (await readFile(join(stateDir, '.acp-session-id'), 'utf8')).trim();
|
|
131
|
+
files = (await readdir(join(stateDir, '.conversation'))).filter(n => /^events-\d{6}\.jsonl$/.test(n)).sort();
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return live;
|
|
135
|
+
}
|
|
136
|
+
if (!sessionId || sessionId !== expectedSessionId || !files.length)
|
|
137
|
+
return live;
|
|
138
|
+
const after = Number(request.after ?? 0);
|
|
139
|
+
if (!Number.isSafeInteger(after) || after < 0)
|
|
140
|
+
return live;
|
|
141
|
+
const limit = Math.min(1000, Math.max(1, Number.isFinite(request.limit) ? Math.floor(request.limit) : 200));
|
|
142
|
+
const events = [];
|
|
143
|
+
let next = String(after);
|
|
144
|
+
let first;
|
|
145
|
+
let hasMore = false;
|
|
146
|
+
scan: for (const file of files) {
|
|
147
|
+
// Forward polling asks for the newest few events: skip whole segments that end at or before the cursor.
|
|
148
|
+
const end = await lastSeq(join(stateDir, '.conversation', file));
|
|
149
|
+
if (end !== undefined && end <= after)
|
|
150
|
+
continue;
|
|
151
|
+
const input = createReadStream(join(stateDir, '.conversation', file), { encoding: 'utf8' });
|
|
152
|
+
const lines = createInterface({ input, crlfDelay: Infinity });
|
|
153
|
+
try {
|
|
154
|
+
for await (const line of lines) {
|
|
155
|
+
let event;
|
|
156
|
+
try {
|
|
157
|
+
event = JSON.parse(line);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const cursor = Number(event.seq);
|
|
163
|
+
if (!Number.isSafeInteger(cursor) || cursor <= after)
|
|
164
|
+
continue;
|
|
165
|
+
const historical = ['file.attached', 'fleet.task_created', 'prompt.admitted', 'message.chunk', 'message.replace', 'tool.upsert', 'tool.content_chunk', 'turn.completed'].includes(event.kind);
|
|
166
|
+
const visible = event.source !== 'agent_replay' && (event.sessionGeneration === live.snapshot.sessionGeneration || (historical && event.acpSessionId === sessionId));
|
|
167
|
+
if (!visible) {
|
|
168
|
+
next = String(cursor);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (events.length === limit) {
|
|
172
|
+
hasMore = true;
|
|
173
|
+
break scan;
|
|
174
|
+
}
|
|
175
|
+
first ??= String(cursor);
|
|
176
|
+
events.push(event);
|
|
177
|
+
next = String(cursor);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
lines.close();
|
|
182
|
+
input.destroy();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// If a fresh/resumed session changed during the read, use the live page only.
|
|
186
|
+
if ((await readFile(join(stateDir, '.acp-session-id'), 'utf8')).trim() !== sessionId)
|
|
187
|
+
return live;
|
|
188
|
+
return { ...live, events, firstAvailableCursor: first, nextCursor: next, hasMore };
|
|
189
|
+
}
|
|
190
|
+
/** Download authorization requires an actual published attachment, never an orphan copy. */
|
|
191
|
+
export async function conversationHasAttachment(stateDir, attachment) {
|
|
192
|
+
const dir = join(stateDir, '.conversation');
|
|
193
|
+
const names = (await readdir(dir)).filter(n => /^events-\d+\.jsonl$/.test(n)).sort().reverse();
|
|
194
|
+
let found = false;
|
|
195
|
+
for (const name of names) {
|
|
196
|
+
await readLinesBackward(join(dir, name), line => {
|
|
197
|
+
try {
|
|
198
|
+
const e = JSON.parse(line);
|
|
199
|
+
const a = e.payload.attachment;
|
|
200
|
+
if (e.kind === 'file.attached' && e.source === 'agent' && a?.id === attachment.id
|
|
201
|
+
&& e.sessionGeneration === attachment.sessionGeneration && e.acpSessionId === attachment.acpSessionId
|
|
202
|
+
&& e.turnId === attachment.turnId && JSON.stringify(a) === JSON.stringify(attachment))
|
|
203
|
+
found = true;
|
|
204
|
+
}
|
|
205
|
+
catch { /* unreadable lines cannot authorize a download */ }
|
|
206
|
+
return !found;
|
|
207
|
+
});
|
|
208
|
+
if (found)
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
return found;
|
|
212
|
+
}
|
|
@@ -24,7 +24,7 @@ export declare class FleetQueryService {
|
|
|
24
24
|
private readonly options;
|
|
25
25
|
private readonly control;
|
|
26
26
|
constructor(options: FleetQueryOptions);
|
|
27
|
-
list(): Promise<Array<{
|
|
27
|
+
list(includeTemporary?: boolean): Promise<Array<{
|
|
28
28
|
role: RoleRecord;
|
|
29
29
|
status: RoleStatus;
|
|
30
30
|
capabilities: RoleCapabilities;
|
|
@@ -75,9 +75,9 @@ export class FleetQueryService {
|
|
|
75
75
|
this.options = options;
|
|
76
76
|
this.control = options.control ?? controlRequest;
|
|
77
77
|
}
|
|
78
|
-
async list() {
|
|
78
|
+
async list(includeTemporary = false) {
|
|
79
79
|
const roles = (await this.options.repository.list())
|
|
80
|
-
.filter(role => role.configured && role.lifetime === 'permanent');
|
|
80
|
+
.filter(role => (role.configured && role.lifetime === 'permanent') || (includeTemporary && role.lifetime === 'temporary'));
|
|
81
81
|
return Promise.all(roles.map(async (role) => {
|
|
82
82
|
const status = await this.status(role);
|
|
83
83
|
return { role, status, capabilities: roleCapabilities(role, status, this.options.capabilityContext) };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Read-only compatibility proof for supervisors predating descriptor identity metadata. */
|
|
2
|
+
export declare function legacySupervisorIdentity(role: string, name: string, temporary: boolean, generation: number): {
|
|
3
|
+
name: string;
|
|
4
|
+
cid: string;
|
|
5
|
+
generation: number;
|
|
6
|
+
proof: string;
|
|
7
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { stateRoot } from '../paths.js';
|
|
5
|
+
import { binderKey } from '../agent-ours/state.js';
|
|
6
|
+
import { FleetError } from './errors.js';
|
|
7
|
+
/** Read-only compatibility proof for supervisors predating descriptor identity metadata. */
|
|
8
|
+
export function legacySupervisorIdentity(role, name, temporary, generation) {
|
|
9
|
+
const root = join(stateRoot(), 'private-ours');
|
|
10
|
+
try {
|
|
11
|
+
const matches = [];
|
|
12
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
13
|
+
if (!entry.isDirectory() || !/^[a-f0-9]{64}$/.test(entry.name))
|
|
14
|
+
continue;
|
|
15
|
+
const dir = join(root, entry.name);
|
|
16
|
+
const instance = JSON.parse(readFileSync(join(dir, 'instance.json'), 'utf8'));
|
|
17
|
+
if (instance.role !== role)
|
|
18
|
+
continue;
|
|
19
|
+
const state = JSON.parse(readFileSync(join(dir, 'state.json'), 'utf8'));
|
|
20
|
+
const pin = JSON.parse(readFileSync(join(dir, 'identity-pin.json'), 'utf8'));
|
|
21
|
+
if (!Number.isSafeInteger(generation) || generation < 1
|
|
22
|
+
|| typeof state.action !== 'string' || !state.action
|
|
23
|
+
|| instance.temporary !== temporary || typeof instance.instance !== 'string' || !instance.instance
|
|
24
|
+
|| state.version !== 1 || state.instance !== instance.instance
|
|
25
|
+
|| state.name !== name || state.lifetime !== (temporary ? 'temporary' : 'permanent')
|
|
26
|
+
|| state.generation !== generation || !['READY', 'SERVING'].includes(state.phase)
|
|
27
|
+
|| typeof state.daemon !== 'string' || !state.daemon || binderKey(state.daemon, name) !== entry.name
|
|
28
|
+
|| !/^[a-f0-9]{64}$/i.test(state.cid ?? '')
|
|
29
|
+
|| pin.daemon !== state.daemon || pin.name !== name || pin.cid !== state.cid)
|
|
30
|
+
throw new Error('mismatched legacy ownership proof');
|
|
31
|
+
matches.push({ name, cid: state.cid, generation, proof: createHash('sha256').update(JSON.stringify([
|
|
32
|
+
instance.instance, state.action, state.daemon, name, state.cid, state.lifetime, generation,
|
|
33
|
+
])).digest('hex') });
|
|
34
|
+
}
|
|
35
|
+
if (matches.length !== 1)
|
|
36
|
+
throw new Error('missing or ambiguous legacy ownership proof');
|
|
37
|
+
return matches[0];
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// The private directory also contains ownership material: never echo parse errors.
|
|
41
|
+
throw new FleetError('capability_unavailable', 'legacy supervisor ownership proof is missing, ambiguous, or mismatched');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -3,7 +3,6 @@ import { createHmac, randomBytes } from 'node:crypto';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { realExec } from '../exec.js';
|
|
5
5
|
import { logsRoot } from '../paths.js';
|
|
6
|
-
import { unitFor } from '../supervisor/systemd.js';
|
|
7
6
|
import { ROLE_NAME_RE } from '../config.js';
|
|
8
7
|
import { FleetError } from './errors.js';
|
|
9
8
|
const STANDARD_REDACTIONS = [
|
|
@@ -78,12 +77,13 @@ export class StructuredLogService {
|
|
|
78
77
|
}
|
|
79
78
|
async tail(roleId, requested, cursor) {
|
|
80
79
|
const limit = Math.min(Math.max(requested, 1), 1_000);
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
const source = this.backend.logsArgs(roleId, false);
|
|
81
|
+
const args = { cmd: source.cmd, args: [...source.args] };
|
|
82
|
+
const count = args.args.indexOf('-n');
|
|
83
|
+
if (count >= 0)
|
|
84
|
+
args.args[count + 1] = String(limit);
|
|
85
|
+
if (args.cmd === 'journalctl')
|
|
86
|
+
args.args.push('-o', 'json', '--no-pager', '-n', String(limit));
|
|
87
87
|
if (!['journalctl', 'tail', 'tmux'].includes(args.cmd))
|
|
88
88
|
throw new FleetError('capability_unavailable', 'log backend is unsupported');
|
|
89
89
|
const result = await this.exec(args.cmd, args.args);
|
|
@@ -93,7 +93,7 @@ export class StructuredLogService {
|
|
|
93
93
|
const parsed = lines.map((line, index) => {
|
|
94
94
|
let text = line;
|
|
95
95
|
let at;
|
|
96
|
-
if (
|
|
96
|
+
if (args.cmd === 'journalctl') {
|
|
97
97
|
try {
|
|
98
98
|
const json = JSON.parse(line);
|
|
99
99
|
text = typeof json.MESSAGE === 'string' ? json.MESSAGE : line;
|
|
@@ -14,7 +14,7 @@ export interface HarnessModelCatalog {
|
|
|
14
14
|
export declare function codexModelCatalog(path?: string): HarnessModelCatalog;
|
|
15
15
|
/**
|
|
16
16
|
* Claude Code 2.1 has no typed model-list endpoint. These exact IDs are the
|
|
17
|
-
* versioned adapter contract
|
|
17
|
+
* versioned adapter contract verified with CLI 2.1.281, not aliases and
|
|
18
18
|
* not a claim about account entitlement (which Claude validates at launch).
|
|
19
19
|
*/
|
|
20
20
|
export declare function claudeModelCatalog(): HarnessModelCatalog;
|
|
@@ -41,17 +41,20 @@ export function codexModelCatalog(path = join(homedir(), '.codex', 'models_cache
|
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Claude Code 2.1 has no typed model-list endpoint. These exact IDs are the
|
|
44
|
-
* versioned adapter contract
|
|
44
|
+
* versioned adapter contract verified with CLI 2.1.281, not aliases and
|
|
45
45
|
* not a claim about account entitlement (which Claude validates at launch).
|
|
46
46
|
*/
|
|
47
47
|
export function claudeModelCatalog() {
|
|
48
48
|
const reasoningEfforts = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
49
49
|
return {
|
|
50
50
|
models: [
|
|
51
|
+
{ id: 'claude-fable-5-1', label: 'Claude Fable 5.1', reasoningEfforts, source: 'claude-adapter-2.1' },
|
|
52
|
+
{ id: 'claude-opus-5-5', label: 'Claude Opus 5.5', reasoningEfforts, source: 'claude-adapter-2.1' },
|
|
53
|
+
{ id: 'claude-haiku-4-5-20251001', label: 'Claude Haiku 4.5', reasoningEfforts: [], source: 'claude-adapter-2.1' },
|
|
51
54
|
{ id: 'claude-fable-5', label: 'Claude Fable 5', reasoningEfforts, source: 'claude-adapter-2.1' },
|
|
52
55
|
{ id: 'claude-opus-5', label: 'Claude Opus 5', reasoningEfforts, source: 'claude-adapter-2.1' },
|
|
53
56
|
{ id: 'claude-sonnet-5', label: 'Claude Sonnet 5', reasoningEfforts, source: 'claude-adapter-2.1' },
|
|
54
57
|
],
|
|
55
|
-
warnings: ['Claude Code exposes no typed model-list endpoint; choices
|
|
58
|
+
warnings: ['Claude Code exposes no typed model-list endpoint; choices require a current Claude runtime (verified with 2.1.281); older bundled SDKs need CLAUDE_CODE_EXECUTABLE. Entitlement is validated at launch.'],
|
|
56
59
|
};
|
|
57
60
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const PROVENANCE_KINDS: {
|
|
2
|
+
readonly role: "roles";
|
|
3
|
+
readonly brain: "brains";
|
|
4
|
+
readonly template: "agent_templates";
|
|
5
|
+
readonly layout: "room_layouts";
|
|
6
|
+
};
|
|
7
|
+
export type ProvenanceKind = keyof typeof PROVENANCE_KINDS;
|
|
8
|
+
export type ProvenanceStatus = 'predefined' | 'changed' | 'custom';
|
|
9
|
+
export interface ProvenanceEntry {
|
|
10
|
+
status: ProvenanceStatus;
|
|
11
|
+
preset?: string;
|
|
12
|
+
}
|
|
13
|
+
export type Provenance = Record<ProvenanceKind, Record<string, ProvenanceEntry>>;
|
|
14
|
+
export declare class PresetProvenance {
|
|
15
|
+
private configPath?;
|
|
16
|
+
private presetRoot;
|
|
17
|
+
constructor(configPath?: string | undefined, presetRoot?: string);
|
|
18
|
+
read(): Provenance;
|
|
19
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Where each configured definition came from, compared with the packaged presets.
|
|
2
|
+
* A definition is `predefined` when it has the same value as the shipped preset of
|
|
3
|
+
* the same name, `changed` when a preset of that name exists but the value differs,
|
|
4
|
+
* and `custom` otherwise. Values are compared after parsing, so the formatting the
|
|
5
|
+
* configuration editor writes does not count as a change. Preset text is returned
|
|
6
|
+
* so users can see exactly what ships; it contains no host data.
|
|
7
|
+
*/
|
|
8
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
9
|
+
import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
|
|
10
|
+
import { basename, extname, join } from 'node:path';
|
|
11
|
+
import { parse } from 'yaml';
|
|
12
|
+
import { defaultConfigPath } from '../paths.js';
|
|
13
|
+
import { splitRootFor } from '../config.js';
|
|
14
|
+
import { packagedPresetRoot } from '../preset-bootstrap.js';
|
|
15
|
+
export const PROVENANCE_KINDS = { role: 'roles', brain: 'brains', template: 'agent_templates', layout: 'room_layouts' };
|
|
16
|
+
const MAX_BYTES = 256 * 1024;
|
|
17
|
+
/** Regular, bounded YAML files of one directory, by definition name. Anything else is skipped. */
|
|
18
|
+
function yamlFiles(dir) {
|
|
19
|
+
const files = new Map();
|
|
20
|
+
if (!existsSync(dir) || !lstatSync(dir).isDirectory())
|
|
21
|
+
return files;
|
|
22
|
+
for (const file of readdirSync(dir).sort()) {
|
|
23
|
+
if (!/\.ya?ml$/.test(file))
|
|
24
|
+
continue;
|
|
25
|
+
const path = join(dir, file), stat = lstatSync(path);
|
|
26
|
+
if (!stat.isFile() || stat.size > MAX_BYTES)
|
|
27
|
+
continue;
|
|
28
|
+
files.set(basename(file, extname(file)), readFileSync(path, 'utf8'));
|
|
29
|
+
}
|
|
30
|
+
return files;
|
|
31
|
+
}
|
|
32
|
+
const parsed = (text) => { try {
|
|
33
|
+
return parse(text);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return Symbol('unparseable');
|
|
37
|
+
} };
|
|
38
|
+
export class PresetProvenance {
|
|
39
|
+
configPath;
|
|
40
|
+
presetRoot;
|
|
41
|
+
constructor(configPath, presetRoot = join(packagedPresetRoot(), 'fleet')) {
|
|
42
|
+
this.configPath = configPath;
|
|
43
|
+
this.presetRoot = presetRoot;
|
|
44
|
+
}
|
|
45
|
+
read() {
|
|
46
|
+
const split = splitRootFor(this.configPath ?? defaultConfigPath());
|
|
47
|
+
const result = {};
|
|
48
|
+
for (const [kind, dir] of Object.entries(PROVENANCE_KINDS)) {
|
|
49
|
+
const presets = yamlFiles(join(this.presetRoot, dir)), installed = yamlFiles(join(split, dir));
|
|
50
|
+
result[kind] = Object.fromEntries([...installed].map(([name, text]) => {
|
|
51
|
+
const preset = presets.get(name);
|
|
52
|
+
if (preset === undefined)
|
|
53
|
+
return [name, { status: 'custom' }];
|
|
54
|
+
return [name, { status: isDeepStrictEqual(parsed(text), parsed(preset)) ? 'predefined' : 'changed', preset }];
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -59,7 +59,8 @@ export class RoleCreationService {
|
|
|
59
59
|
}
|
|
60
60
|
async createManaged(caller, requested) {
|
|
61
61
|
const plan = this.previewSpawn({ origin: 'managed', caller, options: requested });
|
|
62
|
-
const creationActionId =
|
|
62
|
+
const creationActionId = requested.roomMemberStartup?.task_id
|
|
63
|
+
? requested.creationActionId ?? randomUUID() : randomUUID();
|
|
63
64
|
plan.options.creationActionId = creationActionId;
|
|
64
65
|
const statePath = await this.launchSync(plan.options);
|
|
65
66
|
const selectionSummary = (kind) => {
|
|
@@ -138,7 +139,7 @@ export class RoleCreationService {
|
|
|
138
139
|
reasoningEffort: resolved.effort,
|
|
139
140
|
cwd, lifetime: request.lifetime,
|
|
140
141
|
permissions: resolvePermissions(defaults.permissions, request.permissions),
|
|
141
|
-
monitor: resolveMonitorConfig(defaults.monitor, request.monitor),
|
|
142
|
+
monitor: resolveMonitorConfig(defaults.monitor, request.monitor, { harness: resolved.harness }),
|
|
142
143
|
};
|
|
143
144
|
const warnings = [];
|
|
144
145
|
if (request.permissions.approval === 'allow')
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { retireNotificationTarget } from '../notifications/target-cleanup.js';
|
|
1
2
|
import { cpSync, existsSync, mkdirSync, readdirSync, renameSync } from 'node:fs';
|
|
2
3
|
import { basename, dirname, join } from 'node:path';
|
|
3
4
|
import { loadConfig, ROLE_NAME_RE } from '../config.js';
|
|
4
5
|
import { agentDir, stateRoot } from '../paths.js';
|
|
5
|
-
import { rmRole } from '../ops.js';
|
|
6
|
+
import { assertStandaloneRoleRemoval, rmRole } from '../ops.js';
|
|
6
7
|
import { FleetError } from './errors.js';
|
|
7
8
|
import { provesGeneratedAgentSource } from '../generated-agent-source.js';
|
|
8
9
|
export class RoleRemovalService {
|
|
@@ -18,6 +19,12 @@ export class RoleRemovalService {
|
|
|
18
19
|
if (!ROLE_NAME_RE.test(requested))
|
|
19
20
|
throw new FleetError('invalid_request', 'invalid role name');
|
|
20
21
|
const cfg = loadConfig(this.options.configPath);
|
|
22
|
+
try {
|
|
23
|
+
assertStandaloneRoleRemoval(cfg, requested);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw new FleetError('conflict', error instanceof Error ? error.message : String(error));
|
|
27
|
+
}
|
|
21
28
|
const names = new Set(cfg.roles.map(role => role.name));
|
|
22
29
|
for (const root of [dirname(agentDir('_')), dirname(agentDir('_', true))]) {
|
|
23
30
|
try {
|
|
@@ -87,6 +94,7 @@ export class RoleRemovalService {
|
|
|
87
94
|
await this.options.ops.backend.uninstall(preview.role);
|
|
88
95
|
if (existsSync(sourceState))
|
|
89
96
|
renameSync(sourceState, join(recoveryPath, 'orphan-state'));
|
|
97
|
+
await retireNotificationTarget(`/fleet/chats?chat=${encodeURIComponent(preview.role)}`).catch(() => { });
|
|
90
98
|
this.options.ops.log(`removed orphaned backend/state '${preview.role}'`);
|
|
91
99
|
}
|
|
92
100
|
return { ...preview, removed: true, recoveryPath };
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import { lstatSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
2
2
|
import { join, relative } from 'node:path';
|
|
3
3
|
import { parse } from 'yaml';
|
|
4
|
-
import { loadConfig,
|
|
4
|
+
import { loadConfig, resolveSnapshotMonitor, resolvePermissions, ROLE_NAME_RE, } from '../config.js';
|
|
5
5
|
import { agentsRoot, tmpRoot } from '../paths.js';
|
|
6
6
|
import { readSpawnLineage } from '../web/topology.js';
|
|
7
7
|
const MAX_SNAPSHOT_BYTES = 256 * 1024;
|
|
8
|
+
function retainedTaskId(dir, name) {
|
|
9
|
+
try {
|
|
10
|
+
const path = join(dir, '.temp-supervisor.json');
|
|
11
|
+
const stat = lstatSync(path);
|
|
12
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 16 * 1024)
|
|
13
|
+
return undefined;
|
|
14
|
+
const record = JSON.parse(readFileSync(path, 'utf8'));
|
|
15
|
+
const id = record?.taskOwner?.taskId;
|
|
16
|
+
return record?.version === 1 && record?.role === name && typeof id === 'string'
|
|
17
|
+
&& /^[0-9a-z]{9}[0-9a-f]{8}$/.test(id) ? id : undefined;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
8
23
|
function safeDirs(root) {
|
|
9
24
|
try {
|
|
10
25
|
return readdirSync(root, { withFileTypes: true })
|
|
@@ -54,7 +69,7 @@ function snapshot(path, name) {
|
|
|
54
69
|
session, identity: typeof raw.identity === 'string' ? raw.identity : name,
|
|
55
70
|
permissions: resolvePermissions(undefined, raw.permissions),
|
|
56
71
|
permissionsDeclared: raw.permissions !== undefined,
|
|
57
|
-
monitor:
|
|
72
|
+
monitor: resolveSnapshotMonitor(raw.monitor),
|
|
58
73
|
sourceFile: '(temp)',
|
|
59
74
|
},
|
|
60
75
|
};
|
|
@@ -128,10 +143,12 @@ export class RoleRepository {
|
|
|
128
143
|
const stateRef = inTemporary ? { lifetime: 'temporary' }
|
|
129
144
|
: inPermanent ? { lifetime: 'permanent' } : undefined;
|
|
130
145
|
const tempStateDir = inTemporary ? join(temporaryRoot, name) : undefined;
|
|
146
|
+
const taskId = !config && tempStateDir ? retainedTaskId(tempStateDir, name) : undefined;
|
|
131
147
|
return {
|
|
132
148
|
id: name,
|
|
133
149
|
lifetime: config ? 'permanent' : inTemporary ? 'temporary' : 'orphan',
|
|
134
150
|
configured: Boolean(config),
|
|
151
|
+
...(taskId ? { taskId } : {}),
|
|
135
152
|
config: config ? view(config) : tempRole ? view(tempRole) : undefined,
|
|
136
153
|
stateRef,
|
|
137
154
|
stateHealth,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { loadConfig } from '../config.js';
|
|
2
|
+
import { type RoomLayoutDefinition } from '../rooms-tasks/layout-config.js';
|
|
3
|
+
export declare const ABSENT_REVISION = "absent";
|
|
4
|
+
export type LayoutDefinitionBody = Omit<RoomLayoutDefinition, 'sourceFile'>;
|
|
5
|
+
export type LayoutListEntry = {
|
|
6
|
+
name: string;
|
|
7
|
+
revision: string;
|
|
8
|
+
file: string;
|
|
9
|
+
definition: LayoutDefinitionBody;
|
|
10
|
+
issues: string[];
|
|
11
|
+
definition_hash: string;
|
|
12
|
+
} | {
|
|
13
|
+
name: string;
|
|
14
|
+
revision: string;
|
|
15
|
+
file: string;
|
|
16
|
+
error: string;
|
|
17
|
+
};
|
|
18
|
+
export declare class RoomLayoutDefinitions {
|
|
19
|
+
private configPath?;
|
|
20
|
+
private deps;
|
|
21
|
+
constructor(configPath?: string | undefined, deps?: {
|
|
22
|
+
loadConfiguration?: typeof loadConfig;
|
|
23
|
+
});
|
|
24
|
+
private root;
|
|
25
|
+
private pathFor;
|
|
26
|
+
private currentRevision;
|
|
27
|
+
/** Agent-template references that do not resolve in the current Fleet configuration. */
|
|
28
|
+
private templateIssues;
|
|
29
|
+
/** The configured default (`rooms.defaults.template`, else `tasks.default_room_template`) when it names a usable layout. */
|
|
30
|
+
defaultLayout(entries?: LayoutListEntry[]): string | undefined;
|
|
31
|
+
list(): LayoutListEntry[];
|
|
32
|
+
validate(raw: unknown): {
|
|
33
|
+
definition?: LayoutDefinitionBody;
|
|
34
|
+
issues: string[];
|
|
35
|
+
};
|
|
36
|
+
save(name: string, expectedRevision: string, raw: unknown): Promise<{
|
|
37
|
+
name: string;
|
|
38
|
+
revision: string;
|
|
39
|
+
definition: LayoutDefinitionBody;
|
|
40
|
+
}>;
|
|
41
|
+
remove(name: string, expectedRevision: string): Promise<{
|
|
42
|
+
name: string;
|
|
43
|
+
deleted: boolean;
|
|
44
|
+
}>;
|
|
45
|
+
}
|