@ours.network/fleet 1.2.0-nightly.9 → 2.0.1
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 +280 -68
- package/dist/account-origin.d.ts +5 -0
- package/dist/account-origin.js +31 -0
- package/dist/agent-ours/bridge.js +26 -9
- package/dist/agent-ours/correspondence.d.ts +10 -0
- package/dist/agent-ours/correspondence.js +1 -0
- package/dist/agent-ours/file-rpc.d.ts +12 -0
- package/dist/agent-ours/file-rpc.js +18 -4
- package/dist/agent-ours/harness.js +9 -1
- package/dist/agent-ours/mcp-endpoint.d.ts +22 -0
- package/dist/agent-ours/mcp-endpoint.js +101 -25
- package/dist/agent-ours/runtime.d.ts +9 -1
- package/dist/agent-ours/runtime.js +50 -2
- package/dist/agent-ours/service.d.ts +27 -1
- package/dist/agent-ours/service.js +107 -13
- package/dist/application/codex-models.d.ts +15 -0
- package/dist/application/codex-models.js +56 -0
- package/dist/application/conversation-history.d.ts +31 -0
- package/dist/application/conversation-history.js +339 -0
- package/dist/application/conversation-role-observer.d.ts +62 -0
- package/dist/application/conversation-role-observer.js +206 -0
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +3 -3
- package/dist/application/log-service.js +8 -8
- package/dist/application/model-catalog.d.ts +1 -1
- package/dist/application/model-catalog.js +5 -2
- package/dist/application/preset-provenance.d.ts +19 -0
- package/dist/application/preset-provenance.js +59 -0
- package/dist/application/resource-observer.d.ts +43 -0
- package/dist/application/resource-observer.js +323 -0
- package/dist/application/role-creation-service.js +3 -2
- package/dist/application/role-removal-service.js +17 -3
- package/dist/application/role-repository.d.ts +3 -1
- package/dist/application/role-repository.js +89 -54
- 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 +63 -17
- package/dist/application/session-control.js +221 -23
- package/dist/application/supervisor-ours-tools.js +5 -11
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +261 -0
- package/dist/application/task-room-service.d.ts +101 -3
- package/dist/application/task-room-service.js +286 -33
- package/dist/application/types.d.ts +2 -0
- package/dist/atomic-file.d.ts +34 -1
- package/dist/atomic-file.js +161 -18
- package/dist/briefing.d.ts +5 -1
- package/dist/briefing.js +138 -31
- package/dist/build-info.json +10 -5
- package/dist/capabilities.d.ts +9 -1
- package/dist/capabilities.js +13 -0
- package/dist/cli.js +391 -38
- package/dist/client-profile.d.ts +5 -17
- package/dist/client-profile.js +4 -127
- package/dist/config.d.ts +45 -0
- package/dist/config.js +57 -6
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +4 -4
- package/dist/daemon-recovery.d.ts +14 -9
- package/dist/daemon-recovery.js +124 -115
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +402 -20
- package/dist/doctor.d.ts +4 -1
- package/dist/doctor.js +75 -60
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/file-delivery/reader.d.ts +15 -0
- package/dist/file-delivery/reader.js +63 -0
- package/dist/file-delivery/store.d.ts +15 -0
- package/dist/file-delivery/store.js +124 -0
- package/dist/file-delivery/types.d.ts +19 -0
- package/dist/file-delivery/types.js +1 -0
- package/dist/fleet-command-audit.d.ts +13 -0
- package/dist/fleet-command-audit.js +31 -9
- package/dist/harness/agent-session.d.ts +4 -0
- package/dist/harness/claude-code-session.js +1 -1
- package/dist/harness/claude-code.js +21 -11
- package/dist/harness/claude-runtime.d.ts +12 -0
- package/dist/harness/claude-runtime.js +43 -0
- package/dist/harness/codex-app-server-proxy.d.ts +4 -1
- package/dist/harness/codex-app-server-proxy.js +41 -5
- package/dist/harness/codex-reasoning.d.ts +5 -0
- package/dist/harness/codex-reasoning.js +12 -0
- package/dist/harness/codex-runtime.d.ts +11 -1
- package/dist/harness/codex-runtime.js +31 -4
- package/dist/harness/codex-session.js +2 -2
- package/dist/harness/codex.js +24 -12
- package/dist/init-wizard.d.ts +2 -0
- package/dist/init-wizard.js +38 -19
- package/dist/isolation/policy.js +6 -1
- package/dist/isolation/types.d.ts +5 -0
- package/dist/managed-cli.d.ts +253 -0
- package/dist/managed-cli.js +923 -0
- package/dist/managed-recovery.d.ts +13 -0
- package/dist/managed-recovery.js +31 -0
- package/dist/minimal-setup.d.ts +2 -0
- package/dist/minimal-setup.js +44 -0
- package/dist/monitor.d.ts +9 -34
- package/dist/monitor.js +90 -153
- package/dist/notifications/fleet-producer.d.ts +31 -0
- package/dist/notifications/fleet-producer.js +351 -0
- package/dist/notifications/outbox.d.ts +59 -0
- package/dist/notifications/outbox.js +199 -0
- package/dist/notifications/target-cleanup.d.ts +16 -0
- package/dist/notifications/target-cleanup.js +75 -0
- package/dist/notifications/task-producer.d.ts +20 -0
- package/dist/notifications/task-producer.js +100 -0
- package/dist/ops.d.ts +2 -0
- package/dist/ops.js +20 -3
- package/dist/owner-channel/channel.js +17 -6
- package/dist/owner-channel/commands.d.ts +4 -0
- package/dist/owner-channel/commands.js +8 -0
- package/dist/owner-channel/lifecycle-outbox.js +4 -3
- package/dist/owner-channel/ours-client.js +2 -17
- package/dist/paths.d.ts +5 -0
- package/dist/paths.js +5 -0
- package/dist/preset-migration.js +55 -0
- package/dist/process-incarnation.d.ts +23 -0
- package/dist/process-incarnation.js +42 -0
- package/dist/reminders/manager.d.ts +75 -0
- package/dist/reminders/manager.js +278 -0
- package/dist/reminders/runtime.d.ts +27 -0
- package/dist/reminders/runtime.js +32 -0
- package/dist/reminders/schedule.d.ts +37 -0
- package/dist/reminders/schedule.js +104 -0
- package/dist/reminders/store.d.ts +341 -0
- package/dist/reminders/store.js +762 -0
- package/dist/reminders/tools.d.ts +20 -0
- package/dist/reminders/tools.js +114 -0
- package/dist/resolved-plan.js +1 -0
- package/dist/rooms-tasks/add-member.d.ts +48 -0
- package/dist/rooms-tasks/add-member.js +84 -0
- package/dist/rooms-tasks/archived-absence.d.ts +4 -0
- package/dist/rooms-tasks/archived-absence.js +11 -0
- package/dist/rooms-tasks/cli.js +182 -5
- package/dist/rooms-tasks/close.d.ts +5 -2
- package/dist/rooms-tasks/close.js +224 -36
- package/dist/rooms-tasks/config.d.ts +1 -1
- package/dist/rooms-tasks/config.js +11 -4
- package/dist/rooms-tasks/cowork-adapter.d.ts +12 -5
- package/dist/rooms-tasks/cowork-adapter.js +15 -121
- package/dist/rooms-tasks/cowork-http.js +56 -6
- package/dist/rooms-tasks/deletion.d.ts +1 -1
- package/dist/rooms-tasks/deletion.js +66 -10
- package/dist/rooms-tasks/erasure.d.ts +6 -0
- package/dist/rooms-tasks/erasure.js +173 -0
- package/dist/rooms-tasks/external-worker.d.ts +1 -1
- package/dist/rooms-tasks/external-worker.js +3 -4
- package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
- package/dist/rooms-tasks/layout-binding-client.js +56 -0
- package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
- package/dist/rooms-tasks/layout-binding-grants.js +128 -0
- package/dist/rooms-tasks/layout-cli.d.ts +4 -0
- package/dist/rooms-tasks/layout-cli.js +107 -0
- package/dist/rooms-tasks/layout-config.d.ts +11 -0
- package/dist/rooms-tasks/layout-config.js +89 -0
- package/dist/rooms-tasks/layout-control.d.ts +21 -0
- package/dist/rooms-tasks/layout-control.js +52 -0
- package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
- package/dist/rooms-tasks/layout-member-retirement.js +90 -0
- package/dist/rooms-tasks/layout-service.d.ts +43 -0
- package/dist/rooms-tasks/layout-service.js +203 -0
- package/dist/rooms-tasks/layout.d.ts +121 -0
- package/dist/rooms-tasks/layout.js +286 -0
- package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
- package/dist/rooms-tasks/legacy-task-member.js +116 -0
- package/dist/rooms-tasks/live-readiness.d.ts +18 -0
- package/dist/rooms-tasks/live-readiness.js +85 -0
- package/dist/rooms-tasks/member-ownership.d.ts +5 -0
- package/dist/rooms-tasks/member-ownership.js +40 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +2 -0
- package/dist/rooms-tasks/provision.d.ts +3 -0
- package/dist/rooms-tasks/provision.js +101 -49
- package/dist/rooms-tasks/recovery.d.ts +19 -0
- package/dist/rooms-tasks/recovery.js +110 -0
- package/dist/rooms-tasks/room-state.d.ts +4 -2
- package/dist/rooms-tasks/room-state.js +47 -8
- package/dist/rooms-tasks/task-review.d.ts +113 -0
- package/dist/rooms-tasks/task-review.js +561 -0
- 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 -5
- package/dist/rooms-tasks/task-state.js +358 -50
- package/dist/rooms-tasks/task-tools.d.ts +35 -0
- package/dist/rooms-tasks/task-tools.js +134 -0
- package/dist/rooms-tasks/types.d.ts +78 -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 +23 -4
- package/dist/runner.js +409 -61
- package/dist/session/acp.d.ts +75 -2
- package/dist/session/acp.js +345 -82
- package/dist/session/arbiter.d.ts +98 -0
- package/dist/session/arbiter.js +272 -3
- package/dist/session/codex-app-server.d.ts +45 -1
- package/dist/session/codex-app-server.js +225 -32
- package/dist/session/control.d.ts +17 -3
- package/dist/session/control.js +219 -23
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-observation.d.ts +25 -0
- package/dist/session/conversation-observation.js +100 -0
- package/dist/session/conversation-replay.d.ts +50 -0
- package/dist/session/conversation-replay.js +203 -0
- package/dist/session/conversation-store.d.ts +15 -1
- package/dist/session/conversation-store.js +213 -26
- package/dist/session/conversation-types.d.ts +57 -4
- package/dist/session/prompt-batch.d.ts +79 -0
- package/dist/session/prompt-batch.js +120 -0
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +42 -1
- package/dist/setup-tunnel-preflight.d.ts +34 -0
- package/dist/setup-tunnel-preflight.js +62 -0
- package/dist/socket-path.d.ts +2 -0
- package/dist/socket-path.js +22 -0
- package/dist/spawn.d.ts +5 -1
- package/dist/spawn.js +40 -4
- package/dist/startup-prompt.d.ts +15 -0
- package/dist/startup-prompt.js +71 -0
- package/dist/startup-readiness.d.ts +20 -1
- package/dist/startup-readiness.js +66 -3
- package/dist/startup-telemetry.d.ts +16 -0
- package/dist/startup-telemetry.js +46 -0
- package/dist/subscriptions/cli.d.ts +91 -0
- package/dist/subscriptions/cli.js +223 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +77 -0
- package/dist/subscriptions/login.js +215 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +143 -0
- package/dist/supervisor/adoption.d.ts +8 -0
- package/dist/supervisor/adoption.js +78 -0
- package/dist/supervisor/catalog.d.ts +62 -0
- package/dist/supervisor/catalog.js +254 -0
- package/dist/supervisor/fleet.d.ts +8 -0
- package/dist/supervisor/fleet.js +89 -0
- package/dist/supervisor/index.js +3 -6
- package/dist/supervisor/launchd.d.ts +1 -1
- package/dist/supervisor/launchd.js +26 -13
- package/dist/supervisor/legacy.d.ts +35 -0
- package/dist/supervisor/legacy.js +524 -0
- package/dist/supervisor/manager.d.ts +15 -0
- package/dist/supervisor/manager.js +270 -0
- package/dist/supervisor/registration-refresh.d.ts +45 -0
- package/dist/supervisor/registration-refresh.js +266 -0
- package/dist/supervisor/scope.d.ts +4 -0
- package/dist/supervisor/scope.js +10 -0
- package/dist/supervisor/systemd.d.ts +2 -2
- package/dist/supervisor/systemd.js +18 -37
- package/dist/task-supervision.d.ts +9 -0
- package/dist/task-supervision.js +145 -0
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +23 -8
- package/dist/temp-lifecycle.js +123 -66
- package/dist/temp-supervisor-recovery.d.ts +1 -1
- package/dist/temp-supervisor-recovery.js +2 -2
- package/dist/tunnel-setup-completion.d.ts +7 -0
- package/dist/tunnel-setup-completion.js +13 -0
- package/dist/tunnel-setup-input.d.ts +19 -0
- package/dist/tunnel-setup-input.js +130 -0
- package/dist/watchdog/query.d.ts +3 -1
- package/dist/watchdog/query.js +2 -1
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +65 -2
- package/dist/web/auth.js +201 -11
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/control.d.ts +3 -3
- package/dist/web/control.js +10 -8
- package/dist/web/conversation-stream-codec.d.ts +23 -0
- package/dist/web/conversation-stream-codec.js +110 -0
- package/dist/web/conversation-stream.d.ts +26 -0
- package/dist/web/conversation-stream.js +239 -0
- package/dist/web/events.d.ts +2 -0
- package/dist/web/events.js +9 -0
- package/dist/web/fleet-config-service.d.ts +7 -1
- package/dist/web/fleet-config-service.js +61 -16
- package/dist/web/prefix-gateway.d.ts +32 -0
- package/dist/web/prefix-gateway.js +248 -0
- package/dist/web/resource-views.d.ts +138 -0
- package/dist/web/resource-views.js +519 -0
- package/dist/web/runtime.d.ts +3 -1
- package/dist/web/runtime.js +132 -34
- package/dist/web/server.d.ts +19 -0
- package/dist/web/server.js +893 -71
- package/dist/web/service.d.ts +11 -2
- package/dist/web/service.js +30 -4
- package/dist/web/workspace-devices.d.ts +107 -0
- package/dist/web/workspace-devices.js +277 -0
- package/dist/web/workspace-tunnel.d.ts +1 -0
- package/dist/web/workspace-tunnel.js +34 -0
- package/dist/workspace-enrollment.d.ts +83 -0
- package/dist/workspace-enrollment.js +605 -0
- package/dist/workspace-replacement.d.ts +66 -0
- package/dist/workspace-replacement.js +238 -0
- package/docs/acp-files.md +146 -0
- package/docs/conversation-stream.md +216 -0
- package/docs/fleet-migration.md +54 -0
- package/docs/live-voice.md +13 -0
- package/docs/room-layouts.md +227 -0
- package/docs/self-reminders.md +374 -0
- package/docs/task-progress-review.md +143 -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 +25 -20
- package/presets/README.md +78 -0
- package/presets/brain-catalog.json +8 -2
- package/presets/fleet/agent_templates/Critic.yaml +1 -1
- package/presets/fleet/agent_templates/Developer.yaml +1 -1
- package/presets/fleet/agent_templates/Engineer.yaml +5 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +6 -3
- 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 +21 -13
- package/presets/fleet/roles/Critic.yaml +24 -0
- package/presets/fleet/roles/Developer.yaml +32 -0
- package/presets/fleet/roles/Engineer.yaml +72 -0
- package/presets/fleet/roles/LocalCoordinator.yaml +17 -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,35 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { publicProgressEntry } from './task-review.js';
|
|
3
|
+
import type { TaskContributionAuthor, TaskProgressEntry } from './types.js';
|
|
4
|
+
/** The task this agent belongs to, from supervisor launch records; never from tool arguments. */
|
|
5
|
+
export interface TaskToolBinding {
|
|
6
|
+
taskId: string;
|
|
7
|
+
role: string;
|
|
8
|
+
identityCid?: string;
|
|
9
|
+
/** Launched as a task-owned temporary member (layout participant). */
|
|
10
|
+
taskOwned: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const TASK_TOOL_NAMES: readonly ["fleet_task_progress_list", "fleet_task_progress_append", "fleet_task_review_show", "fleet_task_review_set", "fleet_task_review_detach"];
|
|
13
|
+
export declare const PROGRESS_PAGE_MAX = 50;
|
|
14
|
+
/** One chronological page of the log; `next_after` continues after the last returned entry. */
|
|
15
|
+
export declare function progressPage(entries: TaskProgressEntry[], input: {
|
|
16
|
+
after?: string;
|
|
17
|
+
limit?: number;
|
|
18
|
+
}): {
|
|
19
|
+
progress: ReturnType<typeof publicProgressEntry>[];
|
|
20
|
+
total: number;
|
|
21
|
+
next_after?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Confirm the binding against the task record: a listed member must match by
|
|
25
|
+
* name and identity; an unlisted caller must be a task-owned launch.
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifiedTaskAuthor(binding: TaskToolBinding): TaskContributionAuthor;
|
|
28
|
+
/**
|
|
29
|
+
* Task Progress and To review tools on the agent's own managed MCP endpoint.
|
|
30
|
+
* The task and author come from the caller's supervisor, so an agent can only
|
|
31
|
+
* read and write the task it was launched for. Review files are attached with
|
|
32
|
+
* `ours-fleet task review-package <id> --attach <path>`, which reads the file
|
|
33
|
+
* under the agent's own permissions.
|
|
34
|
+
*/
|
|
35
|
+
export declare function registerTaskTools(server: McpServer, binding: () => TaskToolBinding | undefined, admit: () => Promise<() => void>): void;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { appendTaskProgress, detachTaskReviewArtifact, getTaskReview, listTaskProgress, publicProgressEntry, publicReview, setTaskReviewMarkdown, TaskReviewError, PROGRESS_TEXT_MAX, REVIEW_MARKDOWN_MAX, } from './task-review.js';
|
|
3
|
+
import { getTask, TaskStateError } from './task-state.js';
|
|
4
|
+
export const TASK_TOOL_NAMES = Object.freeze([
|
|
5
|
+
'fleet_task_progress_list', 'fleet_task_progress_append',
|
|
6
|
+
'fleet_task_review_show', 'fleet_task_review_set', 'fleet_task_review_detach',
|
|
7
|
+
]);
|
|
8
|
+
/** Compact JSON: a result is carried twice (text and structured) inside one bounded bridge frame. */
|
|
9
|
+
function result(value) {
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: 'text', text: JSON.stringify(value) }],
|
|
12
|
+
structuredContent: value,
|
|
13
|
+
isError: false,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export const PROGRESS_PAGE_MAX = 50;
|
|
17
|
+
/** Serialized entry bytes per page, well inside the bridge's frame limit even at maximal escaping. */
|
|
18
|
+
const PROGRESS_PAGE_BYTES = 200_000;
|
|
19
|
+
/** One chronological page of the log; `next_after` continues after the last returned entry. */
|
|
20
|
+
export function progressPage(entries, input) {
|
|
21
|
+
const limit = input.limit ?? PROGRESS_PAGE_MAX;
|
|
22
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > PROGRESS_PAGE_MAX)
|
|
23
|
+
throw new TaskReviewError('invalid_request', `limit must be 1..${PROGRESS_PAGE_MAX}`);
|
|
24
|
+
let start = 0;
|
|
25
|
+
if (input.after !== undefined) {
|
|
26
|
+
start = entries.findIndex(entry => entry.id === input.after) + 1;
|
|
27
|
+
if (!start)
|
|
28
|
+
throw new TaskReviewError('invalid_request', 'after must be the id of an entry in this log');
|
|
29
|
+
}
|
|
30
|
+
const page = [];
|
|
31
|
+
let bytes = 0;
|
|
32
|
+
for (const entry of entries.slice(start, start + limit)) {
|
|
33
|
+
const visible = publicProgressEntry(entry), size = Buffer.byteLength(JSON.stringify(visible));
|
|
34
|
+
if (page.length && bytes + size > PROGRESS_PAGE_BYTES)
|
|
35
|
+
break;
|
|
36
|
+
page.push(visible);
|
|
37
|
+
bytes += size;
|
|
38
|
+
}
|
|
39
|
+
const end = start + page.length;
|
|
40
|
+
return { progress: page, total: entries.length, ...(end < entries.length ? { next_after: entries[end - 1].id } : {}) };
|
|
41
|
+
}
|
|
42
|
+
function failure(code, message) {
|
|
43
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: code, message }) }], isError: true };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Confirm the binding against the task record: a listed member must match by
|
|
47
|
+
* name and identity; an unlisted caller must be a task-owned launch.
|
|
48
|
+
*/
|
|
49
|
+
export function verifiedTaskAuthor(binding) {
|
|
50
|
+
const task = getTask(binding.taskId);
|
|
51
|
+
const member = task.member_roles.find(item => item.name === binding.role);
|
|
52
|
+
if (member ? (binding.identityCid && member.identity_cid !== binding.identityCid) : !binding.taskOwned)
|
|
53
|
+
throw new TaskReviewError('conflict', `agent ${binding.role} is not a member of task ${binding.taskId}`);
|
|
54
|
+
return { kind: 'agent', role: binding.role, ...(binding.identityCid ? { identity_cid: binding.identityCid } : {}), surface: 'mcp' };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Task Progress and To review tools on the agent's own managed MCP endpoint.
|
|
58
|
+
* The task and author come from the caller's supervisor, so an agent can only
|
|
59
|
+
* read and write the task it was launched for. Review files are attached with
|
|
60
|
+
* `ours-fleet task review-package <id> --attach <path>`, which reads the file
|
|
61
|
+
* under the agent's own permissions.
|
|
62
|
+
*/
|
|
63
|
+
export function registerTaskTools(server, binding, admit) {
|
|
64
|
+
const run = async (operation) => {
|
|
65
|
+
let release;
|
|
66
|
+
try {
|
|
67
|
+
release = await admit();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return failure('runtime_not_ready', 'the managed runtime is not admitting tool calls right now; nothing was read or changed');
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const bound = binding();
|
|
74
|
+
if (!bound)
|
|
75
|
+
return failure('task_unavailable', 'this agent was not launched for a Fleet task');
|
|
76
|
+
try {
|
|
77
|
+
return result(operation(bound, verifiedTaskAuthor(bound)));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error instanceof TaskReviewError)
|
|
81
|
+
return failure(error.code, error.message);
|
|
82
|
+
if (error instanceof TaskStateError)
|
|
83
|
+
return failure('task_unavailable', error.message);
|
|
84
|
+
return failure('task_store_failed', 'the task could not be read or updated; nothing was changed');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
release();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
server.registerTool('fleet_task_progress_list', {
|
|
92
|
+
description: 'Read the Progress milestone log of the task you were launched for, oldest first, one page at a time. '
|
|
93
|
+
+ 'When next_after is present, call again with after set to it for the following entries.',
|
|
94
|
+
inputSchema: {
|
|
95
|
+
after: z.string().optional().describe('Entry id from the previous page\'s next_after; omit for the first page.'),
|
|
96
|
+
limit: z.number().int().optional().describe(`Maximum entries per page (1..${PROGRESS_PAGE_MAX}, default ${PROGRESS_PAGE_MAX}). Pages are also bounded in size.`),
|
|
97
|
+
},
|
|
98
|
+
}, async (args) => run(bound => ({ task_id: bound.taskId, ...progressPage(listTaskProgress(bound.taskId), args) })));
|
|
99
|
+
server.registerTool('fleet_task_progress_append', {
|
|
100
|
+
description: 'Append ONE significant, verified milestone to your task\'s Progress log (e.g. root cause found, PR opened with link, '
|
|
101
|
+
+ 'measured result with its scope, final deliverable ready). Not for routine status, handoffs or review chatter. '
|
|
102
|
+
+ 'Entries are permanent and shown to the Owner as written. Repeating a call with the same request_key and text returns the original entry.',
|
|
103
|
+
inputSchema: {
|
|
104
|
+
text: z.string().describe(`Free-form milestone text, kept exactly as written (max ${PROGRESS_TEXT_MAX} characters).`),
|
|
105
|
+
request_key: z.string().optional().describe('Stable key for this milestone so a retried call cannot add it twice (e.g. "pr-opened-123").'),
|
|
106
|
+
},
|
|
107
|
+
}, async (args) => run((bound, author) => {
|
|
108
|
+
const appended = appendTaskProgress(bound.taskId, { text: args.text, requestKey: args.request_key, author });
|
|
109
|
+
return { task_id: bound.taskId, entry: publicProgressEntry(appended.entry), replayed: appended.replayed };
|
|
110
|
+
}));
|
|
111
|
+
server.registerTool('fleet_task_review_show', {
|
|
112
|
+
description: 'Read your task\'s To review package: its Markdown and the retained files attached to it.',
|
|
113
|
+
inputSchema: {},
|
|
114
|
+
}, async () => run(bound => {
|
|
115
|
+
const review = getTaskReview(bound.taskId);
|
|
116
|
+
return { task_id: bound.taskId, review: review ? publicReview(review) : null };
|
|
117
|
+
}));
|
|
118
|
+
server.registerTool('fleet_task_review_set', {
|
|
119
|
+
description: 'Replace the Markdown of your task\'s To review package: the self-contained material the Owner reviews without reading the room or task description '
|
|
120
|
+
+ '(outcome, clickable PR/spec links, validation and CI, independent verdict, limits, decisions needed). '
|
|
121
|
+
+ 'Pass the Markdown you last read as expected_markdown ("" when empty); a concurrent change is refused instead of overwritten.',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
markdown: z.string().describe(`Review Markdown (max ${REVIEW_MARKDOWN_MAX} characters). Links use the same safe rules as task descriptions.`),
|
|
124
|
+
expected_markdown: z.string().describe('The current Markdown as you last read it, or "" if there is none.'),
|
|
125
|
+
},
|
|
126
|
+
}, async (args) => run((bound, author) => ({
|
|
127
|
+
task_id: bound.taskId,
|
|
128
|
+
review: publicReview(setTaskReviewMarkdown(bound.taskId, { markdown: args.markdown, expectedMarkdown: args.expected_markdown, author })),
|
|
129
|
+
})));
|
|
130
|
+
server.registerTool('fleet_task_review_detach', {
|
|
131
|
+
description: 'Remove one file from your task\'s To review package by artifact_id (from fleet_task_review_show).',
|
|
132
|
+
inputSchema: { artifact_id: z.string() },
|
|
133
|
+
}, async (args) => run((bound, author) => ({ task_id: bound.taskId, detached: detachTaskReviewArtifact(bound.taskId, args.artifact_id, { author }) })));
|
|
134
|
+
}
|
|
@@ -62,6 +62,8 @@ export type TaskDeletionMemberPhase = 'pending' | 'stop_requested' | 'liveness_a
|
|
|
62
62
|
export interface TaskDeletionMemberCursor {
|
|
63
63
|
name: string;
|
|
64
64
|
identity_cid: string;
|
|
65
|
+
action_id?: string;
|
|
66
|
+
task_supervised?: boolean;
|
|
65
67
|
phase: TaskDeletionMemberPhase;
|
|
66
68
|
launch_id?: string;
|
|
67
69
|
archive_path?: string;
|
|
@@ -88,13 +90,79 @@ export interface TaskDeletionIntent {
|
|
|
88
90
|
/** Snapshot of managed members at acceptance; the missing-room retirement evidence. */
|
|
89
91
|
members: TaskDeletionMemberCursor[];
|
|
90
92
|
archived_absences?: ArchivedMemberAbsence[];
|
|
93
|
+
absent_members?: string[];
|
|
94
|
+
/** Archive proofs were verified before owned workspace cleanup may consume them. */
|
|
95
|
+
workspace_cleanup_started_at?: string;
|
|
91
96
|
error?: string;
|
|
92
97
|
error_at?: string;
|
|
93
98
|
recovery_hint?: string;
|
|
94
99
|
first_failure?: string;
|
|
95
100
|
first_recovery_hint?: string;
|
|
96
101
|
}
|
|
102
|
+
export interface TaskLayoutLink {
|
|
103
|
+
name: string;
|
|
104
|
+
/** Deterministic `task-<task_id>` Room Layout run ID. */
|
|
105
|
+
run_id: string;
|
|
106
|
+
/** sha256 of the canonical source layout definition the run must snapshot. */
|
|
107
|
+
definition_hash: string;
|
|
108
|
+
}
|
|
109
|
+
export interface TaskNotificationEvent {
|
|
110
|
+
eventId: string;
|
|
111
|
+
title: string;
|
|
112
|
+
body: string;
|
|
113
|
+
target: {
|
|
114
|
+
kind: 'task' | 'task-deleted';
|
|
115
|
+
taskId: string;
|
|
116
|
+
};
|
|
117
|
+
taskId: string;
|
|
118
|
+
}
|
|
119
|
+
/** Who wrote a progress entry or review change, as established by the Fleet surface. */
|
|
120
|
+
export type TaskContributionAuthor = {
|
|
121
|
+
kind: 'agent';
|
|
122
|
+
role: string;
|
|
123
|
+
identity_cid?: string;
|
|
124
|
+
surface: 'mcp' | 'cli';
|
|
125
|
+
} | {
|
|
126
|
+
kind: 'local_control';
|
|
127
|
+
surface: 'cli' | 'web';
|
|
128
|
+
};
|
|
129
|
+
/** One append-only milestone; text is stored exactly as authored. */
|
|
130
|
+
export interface TaskProgressEntry {
|
|
131
|
+
id: string;
|
|
132
|
+
at: string;
|
|
133
|
+
author: TaskContributionAuthor;
|
|
134
|
+
text: string;
|
|
135
|
+
/** Caller retry key, scoped to the author. */
|
|
136
|
+
request_key?: string;
|
|
137
|
+
}
|
|
138
|
+
/** Metadata of a retained review file; bytes live in Fleet's private task review store. */
|
|
139
|
+
export interface TaskReviewArtifact {
|
|
140
|
+
id: string;
|
|
141
|
+
name: string;
|
|
142
|
+
mime: string;
|
|
143
|
+
size: number;
|
|
144
|
+
sha256: string;
|
|
145
|
+
added_at: string;
|
|
146
|
+
added_by: TaskContributionAuthor;
|
|
147
|
+
request_key?: string;
|
|
148
|
+
}
|
|
149
|
+
/** Self-contained material the Owner reviews: Markdown plus retained files. */
|
|
150
|
+
export interface TaskReview {
|
|
151
|
+
/** Increases with every change to the Markdown or the files; absent on packages written before it. */
|
|
152
|
+
revision?: number;
|
|
153
|
+
markdown: string;
|
|
154
|
+
updated_at: string;
|
|
155
|
+
updated_by: TaskContributionAuthor;
|
|
156
|
+
artifacts: TaskReviewArtifact[];
|
|
157
|
+
}
|
|
97
158
|
export interface TaskRecord {
|
|
159
|
+
/** Optional milestone log; absent on tasks that never recorded one. */
|
|
160
|
+
progress?: TaskProgressEntry[];
|
|
161
|
+
/** Optional To review package; absent until an agent prepares it. */
|
|
162
|
+
review?: TaskReview;
|
|
163
|
+
/** Pending lifecycle events, committed atomically with their task change. */
|
|
164
|
+
notification_events?: TaskNotificationEvent[];
|
|
165
|
+
workspace?: import('./workspace.js').OwnedWorkspace;
|
|
98
166
|
task_id: string;
|
|
99
167
|
/** Stable organizational list identifier. Missing legacy values mean `default`. */
|
|
100
168
|
list_id: string;
|
|
@@ -115,6 +183,12 @@ export interface TaskRecord {
|
|
|
115
183
|
plan_hash: string;
|
|
116
184
|
};
|
|
117
185
|
no_room?: boolean;
|
|
186
|
+
/** Multi-room task: rooms and participants come from a Room Layout run. */
|
|
187
|
+
layout?: TaskLayoutLink;
|
|
188
|
+
/** Set when the room plan (layout or one-room template) was changed after creation, before start. */
|
|
189
|
+
room_plan_changed_at?: string;
|
|
190
|
+
/** Fingerprint of the room plan requested at creation; idempotent retries compare against it after later plan edits. */
|
|
191
|
+
creation_plan?: string;
|
|
118
192
|
room_id?: string;
|
|
119
193
|
room_identity_cid?: string;
|
|
120
194
|
member_roles: TaskMemberRole[];
|
|
@@ -153,6 +227,7 @@ export interface RoomRoleBriefingDefinition {
|
|
|
153
227
|
last_error?: string;
|
|
154
228
|
}
|
|
155
229
|
export interface RoomMemberLaunchState {
|
|
230
|
+
task_supervised?: boolean;
|
|
156
231
|
state: 'pending' | 'intent' | 'launched' | 'stopped' | 'failed';
|
|
157
232
|
attempt: number;
|
|
158
233
|
action_id?: string;
|
|
@@ -209,6 +284,7 @@ export type RoomHistoryEvidence = {
|
|
|
209
284
|
};
|
|
210
285
|
export type MemberRetirementPhase = 'stop_requested' | 'liveness_absent' | 'archive_secured' | 'identity_absent';
|
|
211
286
|
export interface MemberRetirement {
|
|
287
|
+
absence_verified?: boolean;
|
|
212
288
|
phase: MemberRetirementPhase;
|
|
213
289
|
launch_id: string;
|
|
214
290
|
updated_at: string;
|
|
@@ -235,12 +311,14 @@ export interface RoomMemberSeat {
|
|
|
235
311
|
retirement?: MemberRetirement;
|
|
236
312
|
}
|
|
237
313
|
export interface RoomOrchestrationRecord {
|
|
314
|
+
workspace?: import('./workspace.js').OwnedWorkspace;
|
|
238
315
|
room_id: string;
|
|
239
316
|
room_identity_cid?: string;
|
|
240
317
|
room_name: string;
|
|
241
318
|
goal?: string;
|
|
242
319
|
task_id?: string;
|
|
243
320
|
template_snapshot?: TemplateSnapshot;
|
|
321
|
+
additional_member_templates?: TemplateSnapshot[];
|
|
244
322
|
/** Resolved once at launch; legacy absence means non-anonymous. */
|
|
245
323
|
room_policy?: RoomLaunchPolicy;
|
|
246
324
|
saga: SagaCursor;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type OwnedWorkspace } from './workspace.js';
|
|
2
|
+
/** Runtime control state stays in Fleet's live roster and recovery store. Its
|
|
3
|
+
* durable launch descriptor, not a name prefix or caller-supplied path, proves
|
|
4
|
+
* artifact ownership. Audit receipts/journals intentionally outlive deletion.
|
|
5
|
+
*/
|
|
6
|
+
export declare function collectWorkspaceArchives(workspace: OwnedWorkspace): void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { lstatSync, mkdirSync, readdirSync, readFileSync, renameSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
import { stateRoot } from '../paths.js';
|
|
5
|
+
import { assertSafeAncestors, auditWorkspaceGit, validateWorkspace, ensureWorkspace, WorkspaceError } from './workspace.js';
|
|
6
|
+
/** Runtime control state stays in Fleet's live roster and recovery store. Its
|
|
7
|
+
* durable launch descriptor, not a name prefix or caller-supplied path, proves
|
|
8
|
+
* artifact ownership. Audit receipts/journals intentionally outlive deletion.
|
|
9
|
+
*/
|
|
10
|
+
export function collectWorkspaceArchives(workspace) {
|
|
11
|
+
validateWorkspace(workspace);
|
|
12
|
+
const root = join(stateRoot(), 'recovery', 'temporary');
|
|
13
|
+
assertSafeAncestors(root);
|
|
14
|
+
let entries;
|
|
15
|
+
try {
|
|
16
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
if (e.code === 'ENOENT')
|
|
20
|
+
return;
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
const owned = [];
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry.isDirectory() || entry.isSymbolicLink())
|
|
26
|
+
continue;
|
|
27
|
+
const path = join(root, entry.name);
|
|
28
|
+
const roleFile = join(path, 'role.yaml');
|
|
29
|
+
let role;
|
|
30
|
+
try {
|
|
31
|
+
const s = lstatSync(roleFile);
|
|
32
|
+
if (!s.isFile() || s.isSymbolicLink())
|
|
33
|
+
continue;
|
|
34
|
+
role = parse(readFileSync(roleFile, 'utf8'));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
continue;
|
|
38
|
+
} // no ownership proof: never adopt a foreign archive
|
|
39
|
+
const recorded = role?.roomMemberStartup?.workspace;
|
|
40
|
+
if (recorded?.owner !== workspace.owner || recorded.id !== workspace.id)
|
|
41
|
+
continue;
|
|
42
|
+
if (JSON.stringify(recorded) !== JSON.stringify(workspace))
|
|
43
|
+
throw new WorkspaceError('workspace archive ownership mismatch');
|
|
44
|
+
assertSafeAncestors(path);
|
|
45
|
+
const termination = join(path, 'termination.jsonl');
|
|
46
|
+
if (!lstatSync(termination).isFile() || lstatSync(termination).isSymbolicLink())
|
|
47
|
+
throw new WorkspaceError('unsafe workspace archive termination evidence');
|
|
48
|
+
const supervisorPath = join(path, '.temp-supervisor.json');
|
|
49
|
+
let supervisor;
|
|
50
|
+
try {
|
|
51
|
+
if (!lstatSync(supervisorPath).isFile() || lstatSync(supervisorPath).isSymbolicLink())
|
|
52
|
+
throw new WorkspaceError('unsafe workspace archive supervisor evidence');
|
|
53
|
+
supervisor = JSON.parse(readFileSync(supervisorPath, 'utf8'));
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
if (e.code !== 'ENOENT')
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
if (supervisor && (supervisor.role !== role.name || !supervisor.launchId))
|
|
60
|
+
throw new WorkspaceError('workspace archive launch ownership mismatch');
|
|
61
|
+
const terminated = readFileSync(termination, 'utf8').trim().split('\n').some(line => {
|
|
62
|
+
const value = JSON.parse(line);
|
|
63
|
+
return value.version === 1 && value.role === role.name
|
|
64
|
+
&& value.launchId === supervisor?.launchId
|
|
65
|
+
&& ['retired', 'reclaimed', 'failed'].includes(value.outcome);
|
|
66
|
+
});
|
|
67
|
+
if (!terminated || entry.name.endsWith('.retiring'))
|
|
68
|
+
throw new WorkspaceError('workspace archive retirement is incomplete');
|
|
69
|
+
auditWorkspaceGit(path, { forDeletion: true });
|
|
70
|
+
owned.push(path);
|
|
71
|
+
}
|
|
72
|
+
// Preflight the entire set before mutation; task/room record remains until all succeed.
|
|
73
|
+
if (!owned.length)
|
|
74
|
+
return;
|
|
75
|
+
ensureWorkspace(workspace);
|
|
76
|
+
const destination = join(workspace.path, '.fleet-retired-agents');
|
|
77
|
+
assertSafeAncestors(destination);
|
|
78
|
+
mkdirSync(destination, { recursive: true, mode: 0o700 });
|
|
79
|
+
for (const path of owned) {
|
|
80
|
+
const target = join(destination, basename(path));
|
|
81
|
+
try {
|
|
82
|
+
lstatSync(target);
|
|
83
|
+
throw new WorkspaceError('archive collection destination exists');
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
if (e.code !== 'ENOENT')
|
|
87
|
+
throw e;
|
|
88
|
+
}
|
|
89
|
+
// Atomic transfer before workspace deletion: a crash never loses ownership
|
|
90
|
+
// evidence halfway through recursively removing a global recovery archive.
|
|
91
|
+
renameSync(path, target);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Persisted before allocation. Never infer ownership from an Agent's cwd. */
|
|
2
|
+
export interface OwnedWorkspace {
|
|
3
|
+
version: 1;
|
|
4
|
+
owner: 'task' | 'room';
|
|
5
|
+
id: string;
|
|
6
|
+
path: string;
|
|
7
|
+
token: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class WorkspaceError extends Error {
|
|
10
|
+
}
|
|
11
|
+
export declare function assertSafeAncestors(path: string): void;
|
|
12
|
+
export declare function planWorkspace(owner: OwnedWorkspace['owner'], id: string): OwnedWorkspace;
|
|
13
|
+
export declare function validateWorkspace(w: OwnedWorkspace, owner?: "task" | "room", id?: string): void;
|
|
14
|
+
/** Read-only recovery proof; never allocate a replacement for a missing workspace. */
|
|
15
|
+
export declare function assertWorkspacePresent(w: OwnedWorkspace, owner: OwnedWorkspace['owner'], id: string): void;
|
|
16
|
+
/** Caller must first prove the exact workspace marker or retired archive
|
|
17
|
+
* provenance, and hold its lifecycle lock with all managed writers retired.
|
|
18
|
+
* Directories need owner rwx for recursive removal; ordinary files do not.
|
|
19
|
+
*/
|
|
20
|
+
export declare function prepareOwnedDeletionTree(path: string): void;
|
|
21
|
+
/** Atomic directory publication; retry uses the durable token, never adopts another folder. */
|
|
22
|
+
export declare function ensureWorkspace(w: OwnedWorkspace): string;
|
|
23
|
+
/** Audit both directions of Git worktree registration, without executing repository config/hooks.
|
|
24
|
+
* All registrations and common dirs must be inside this workspace. Removing the complete
|
|
25
|
+
* workspace then removes their registries atomically with the owned repositories; never prune.
|
|
26
|
+
*/
|
|
27
|
+
export declare function auditWorkspaceGit(path: string, options?: {
|
|
28
|
+
forDeletion?: boolean;
|
|
29
|
+
}): void;
|
|
30
|
+
/** Called only after all managed writers retire, under the owner's lifecycle lock.
|
|
31
|
+
* The tombstone is derived from the durable unguessable token. A crash during rm
|
|
32
|
+
* resumes that exact tombstone even if rm already removed its marker.
|
|
33
|
+
*/
|
|
34
|
+
export declare function assertWorkspaceDeletable(w: OwnedWorkspace, owner: OwnedWorkspace['owner'], id: string): void;
|
|
35
|
+
export declare function deleteWorkspace(w: OwnedWorkspace, owner: OwnedWorkspace['owner'], id: string): void;
|