@ours.network/fleet 1.2.0-nightly.8 → 1.2.0-nightly.81
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 +34 -0
- package/dist/application/conversation-history.js +294 -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 +1 -1
- package/dist/application/role-repository.js +30 -7
- package/dist/application/room-layout-definitions.d.ts +45 -0
- package/dist/application/room-layout-definitions.js +130 -0
- package/dist/application/session-control.d.ts +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 +3 -1
- package/dist/briefing.js +120 -31
- package/dist/build-info.json +9 -4
- package/dist/capabilities.d.ts +9 -1
- package/dist/capabilities.js +13 -0
- package/dist/cli.js +402 -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 +227 -19
- package/dist/doctor.d.ts +4 -1
- package/dist/doctor.js +75 -60
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/file-delivery/reader.d.ts +15 -0
- package/dist/file-delivery/reader.js +63 -0
- package/dist/file-delivery/store.d.ts +15 -0
- package/dist/file-delivery/store.js +124 -0
- package/dist/file-delivery/types.d.ts +19 -0
- package/dist/file-delivery/types.js +1 -0
- package/dist/fleet-command-audit.d.ts +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 +33 -4
- package/dist/runner.js +410 -62
- package/dist/session/acp.d.ts +75 -2
- package/dist/session/acp.js +345 -82
- package/dist/session/arbiter.d.ts +98 -0
- package/dist/session/arbiter.js +272 -3
- package/dist/session/codex-app-server.d.ts +45 -1
- package/dist/session/codex-app-server.js +225 -32
- package/dist/session/control.d.ts +17 -3
- package/dist/session/control.js +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 +32 -0
- package/dist/startup-readiness.js +101 -0
- package/dist/startup-telemetry.d.ts +16 -0
- package/dist/startup-telemetry.js +46 -0
- package/dist/subscriptions/cli.d.ts +91 -0
- package/dist/subscriptions/cli.js +223 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +77 -0
- package/dist/subscriptions/login.js +215 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +143 -0
- package/dist/supervisor/adoption.d.ts +8 -0
- package/dist/supervisor/adoption.js +78 -0
- package/dist/supervisor/catalog.d.ts +62 -0
- package/dist/supervisor/catalog.js +254 -0
- package/dist/supervisor/fleet.d.ts +8 -0
- package/dist/supervisor/fleet.js +89 -0
- package/dist/supervisor/index.js +3 -6
- package/dist/supervisor/launchd.d.ts +1 -1
- package/dist/supervisor/launchd.js +26 -13
- package/dist/supervisor/legacy.d.ts +35 -0
- package/dist/supervisor/legacy.js +524 -0
- package/dist/supervisor/manager.d.ts +15 -0
- package/dist/supervisor/manager.js +270 -0
- package/dist/supervisor/registration-refresh.d.ts +45 -0
- package/dist/supervisor/registration-refresh.js +266 -0
- package/dist/supervisor/scope.d.ts +4 -0
- package/dist/supervisor/scope.js +10 -0
- package/dist/supervisor/systemd.d.ts +2 -2
- package/dist/supervisor/systemd.js +19 -33
- package/dist/task-supervision.d.ts +9 -0
- package/dist/task-supervision.js +145 -0
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +23 -8
- package/dist/temp-lifecycle.js +123 -66
- package/dist/temp-supervisor-recovery.d.ts +1 -1
- package/dist/temp-supervisor-recovery.js +2 -2
- package/dist/tunnel-setup-completion.d.ts +7 -0
- package/dist/tunnel-setup-completion.js +13 -0
- package/dist/tunnel-setup-input.d.ts +19 -0
- package/dist/tunnel-setup-input.js +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 +135 -0
- package/dist/web/resource-views.js +494 -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,87 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { replaceFileAtomically, withSynchronousFileLock } from './atomic-file.js';
|
|
5
|
+
import { stateRoot } from './paths.js';
|
|
6
|
+
const registryPath = () => join(stateRoot(), 'erased-resources.json');
|
|
7
|
+
const lockPath = () => join(stateRoot(), 'locks', 'audit-erasure');
|
|
8
|
+
const ledgerNames = ['.fleet-command-audit.json', '.owner-channel-command-audit.json', '.owner-channel-lifecycle-outbox.json'];
|
|
9
|
+
export const erasedArg = (value) => `[erased:${createHash('sha256').update(value).digest('hex')}]`;
|
|
10
|
+
function registry() {
|
|
11
|
+
if (!existsSync(registryPath()))
|
|
12
|
+
return new Set();
|
|
13
|
+
const value = JSON.parse(readFileSync(registryPath(), 'utf8'));
|
|
14
|
+
if (!Array.isArray(value) || value.some(v => typeof v !== 'string'))
|
|
15
|
+
throw new Error('Invalid erasure registry');
|
|
16
|
+
return new Set(value);
|
|
17
|
+
}
|
|
18
|
+
/** Preserve delivery/deduplication metadata while removing owned presentation content. */
|
|
19
|
+
function redact(value, erased) {
|
|
20
|
+
if (Array.isArray(value))
|
|
21
|
+
return value.map(item => redact(item, erased));
|
|
22
|
+
if (!value || typeof value !== 'object')
|
|
23
|
+
return value;
|
|
24
|
+
const next = { ...value };
|
|
25
|
+
const kind = value.kind === 'lifecycle_failure' ? value.resource?.toLowerCase() : value.kind === 'agent_started' ? 'agent' : value.kind;
|
|
26
|
+
if (typeof value.id === 'string' && erased.has(`${kind}:${value.id}`)) {
|
|
27
|
+
for (const key of ['title', 'reason', 'roomName', 'label', 'template', 'configuration', 'model', 'permissions'])
|
|
28
|
+
delete next[key];
|
|
29
|
+
if (kind === 'task')
|
|
30
|
+
next.agents = [];
|
|
31
|
+
if (kind === 'room') {
|
|
32
|
+
delete next.name;
|
|
33
|
+
next.participants = [];
|
|
34
|
+
}
|
|
35
|
+
if (kind === 'agent') {
|
|
36
|
+
next.name = 'erased';
|
|
37
|
+
next.brain = '[erased]';
|
|
38
|
+
next.role = '[erased]';
|
|
39
|
+
next.inherited = [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (typeof value.roomId === 'string' && erased.has(`room:${value.roomId}`)) {
|
|
43
|
+
delete next.roomName;
|
|
44
|
+
if (kind === 'task')
|
|
45
|
+
next.agents = [];
|
|
46
|
+
}
|
|
47
|
+
const resources = value.outcome?.resourceIds;
|
|
48
|
+
const ownsAttempt = resources && Object.entries(resources).some(([key, id]) => erased.has(`${key}:${id}`));
|
|
49
|
+
const ownsPresentation = value.outcome?.presentations?.some((p) => erased.has(`${p.kind === 'agent_started' ? 'agent' : p.kind}:${p.id}`));
|
|
50
|
+
if ((ownsAttempt || ownsPresentation) && Array.isArray(value.argv) && !value.erased) {
|
|
51
|
+
next.argv = value.argv.map(erasedArg);
|
|
52
|
+
next.erased = true;
|
|
53
|
+
}
|
|
54
|
+
for (const key of Object.keys(next))
|
|
55
|
+
if (typeof next[key] === 'object')
|
|
56
|
+
next[key] = redact(next[key], erased);
|
|
57
|
+
return next;
|
|
58
|
+
}
|
|
59
|
+
export function redactErasedContent(value) { return redact(value, registry()); }
|
|
60
|
+
/** Every cooperative writer filters stale in-memory snapshots under the same lock as erasure. */
|
|
61
|
+
export function writePrivacyFilteredLedger(path, value) {
|
|
62
|
+
withSynchronousFileLock(lockPath(), () => replaceFileAtomically(path, JSON.stringify(redact(value, registry())) + '\n'));
|
|
63
|
+
}
|
|
64
|
+
/** Content-free resource IDs persist to prevent active writers resurrecting erased labels. */
|
|
65
|
+
export function eraseResourcePresentations(resources) {
|
|
66
|
+
withSynchronousFileLock(lockPath(), () => {
|
|
67
|
+
const erased = registry();
|
|
68
|
+
for (const resource of resources)
|
|
69
|
+
erased.add(`${resource.kind}:${resource.id}`);
|
|
70
|
+
replaceFileAtomically(registryPath(), JSON.stringify([...erased]));
|
|
71
|
+
for (const root of [join(stateRoot(), 'agents'), join(stateRoot(), 'tmp'), join(stateRoot(), 'recovery', 'temporary')]) {
|
|
72
|
+
if (!existsSync(root))
|
|
73
|
+
continue;
|
|
74
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
75
|
+
if (!entry.isDirectory() || entry.isSymbolicLink())
|
|
76
|
+
continue;
|
|
77
|
+
for (const name of ledgerNames) {
|
|
78
|
+
const path = join(root, entry.name, name);
|
|
79
|
+
if (!existsSync(path) || !lstatSync(path).isFile() || lstatSync(path).isSymbolicLink())
|
|
80
|
+
continue;
|
|
81
|
+
const old = JSON.parse(readFileSync(path, 'utf8'));
|
|
82
|
+
replaceFileAtomically(path, JSON.stringify(redact(old, erased)) + '\n');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type FileHandle } from 'node:fs/promises';
|
|
2
|
+
export declare const MAX_FILE_BYTES: number;
|
|
3
|
+
/** Pin every component; neither trusted root ancestors nor agent components follow symlinks. */
|
|
4
|
+
export declare function openDirectory(path: string): Promise<FileHandle>;
|
|
5
|
+
/** The agent's provided path, resolved from its working directory; no export subtree. */
|
|
6
|
+
export declare function chatFilePath(cwd: string, input: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Runs in the harness bridge, never in the supervisor's OS context. Ancestor
|
|
9
|
+
* symlinks resolve normally; the named file itself must be one regular,
|
|
10
|
+
* singly-linked file within the size limit. `path` is the opened file's real path.
|
|
11
|
+
*/
|
|
12
|
+
export declare function openChatFile(cwd: string, input: string): Promise<{
|
|
13
|
+
file: FileHandle;
|
|
14
|
+
path: string;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { open, readlink } from 'node:fs/promises';
|
|
3
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
4
|
+
export const MAX_FILE_BYTES = 20 * 1024 * 1024;
|
|
5
|
+
const FLAGS = constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK;
|
|
6
|
+
/** Pin every component; neither trusted root ancestors nor agent components follow symlinks. */
|
|
7
|
+
export async function openDirectory(path) {
|
|
8
|
+
if (process.platform !== 'linux' || !isAbsolute(path) || path !== resolve(path))
|
|
9
|
+
throw Error('FILE_DELIVERY_REQUIRES_LINUX_ROOT');
|
|
10
|
+
let dir = await open('/', FLAGS | constants.O_DIRECTORY);
|
|
11
|
+
try {
|
|
12
|
+
for (const part of path.split('/').filter(Boolean)) {
|
|
13
|
+
const next = await open(`/proc/self/fd/${dir.fd}/${part}`, FLAGS | constants.O_DIRECTORY);
|
|
14
|
+
await dir.close();
|
|
15
|
+
dir = next;
|
|
16
|
+
}
|
|
17
|
+
return dir;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
await dir.close();
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** The agent's provided path, resolved from its working directory; no export subtree. */
|
|
25
|
+
export function chatFilePath(cwd, input) {
|
|
26
|
+
if (typeof input !== 'string' || !input || input.length > 4096 || /[\x00-\x1f]/.test(input))
|
|
27
|
+
throw Error('INVALID_CHAT_FILE_PATH');
|
|
28
|
+
return resolve(cwd, input);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Runs in the harness bridge, never in the supervisor's OS context. Ancestor
|
|
32
|
+
* symlinks resolve normally; the named file itself must be one regular,
|
|
33
|
+
* singly-linked file within the size limit. `path` is the opened file's real path.
|
|
34
|
+
*/
|
|
35
|
+
export async function openChatFile(cwd, input) {
|
|
36
|
+
if (process.platform !== 'linux')
|
|
37
|
+
throw Error('CHAT_FILE_REQUIRES_LINUX');
|
|
38
|
+
let file;
|
|
39
|
+
try {
|
|
40
|
+
file = await open(chatFilePath(cwd, input), FLAGS);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const code = error.code;
|
|
44
|
+
if (error instanceof Error && error.message === 'INVALID_CHAT_FILE_PATH')
|
|
45
|
+
throw error;
|
|
46
|
+
throw Error(code === 'ELOOP' ? 'CHAT_FILE_IS_SYMLINK' : code === 'ENOENT' || code === 'ENOTDIR' ? 'CHAT_FILE_NOT_FOUND'
|
|
47
|
+
: code === 'EACCES' || code === 'EPERM' ? 'CHAT_FILE_NOT_READABLE' : 'CHAT_FILE_OPEN_FAILED');
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const stat = await file.stat();
|
|
51
|
+
if (!stat.isFile())
|
|
52
|
+
throw Error('CHAT_FILE_NOT_REGULAR');
|
|
53
|
+
if (stat.nlink !== 1)
|
|
54
|
+
throw Error('CHAT_FILE_HARDLINKED');
|
|
55
|
+
if (stat.size > MAX_FILE_BYTES)
|
|
56
|
+
throw Error('FILE_EXCEEDS_20_MIB');
|
|
57
|
+
return { file, path: await readlink(`/proc/self/fd/${file.fd}`) };
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
await file.close();
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DeliveredFile, FileDeliveryBinding } from './types.js';
|
|
2
|
+
export declare function artifactDirectory(stateDir: string): string;
|
|
3
|
+
export declare class ArtifactStore {
|
|
4
|
+
private readonly stateDir;
|
|
5
|
+
constructor(stateDir: string);
|
|
6
|
+
copy(source: {
|
|
7
|
+
size: number;
|
|
8
|
+
body: ReadableStream<Uint8Array>;
|
|
9
|
+
close(): Promise<void>;
|
|
10
|
+
}, name: string, mimeType: string, binding: FileDeliveryBinding, signal: AbortSignal): Promise<DeliveredFile>;
|
|
11
|
+
}
|
|
12
|
+
export declare function readDeliveredFile(stateDir: string, id: string): Promise<{
|
|
13
|
+
record: DeliveredFile;
|
|
14
|
+
bytes: Buffer;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { constants, mkdirSync, readFileSync, readdirSync, lstatSync, openSync, fstatSync, closeSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { open, unlink } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { stateRoot } from '../paths.js';
|
|
6
|
+
import { openDirectory, MAX_FILE_BYTES } from './reader.js';
|
|
7
|
+
export function artifactDirectory(stateDir) {
|
|
8
|
+
const incarnation = readFileSync(join(stateDir, '.session-id'), 'utf8').trim();
|
|
9
|
+
if (!/^[a-f0-9-]{36}$/.test(incarnation))
|
|
10
|
+
throw Error('INVALID_ROLE_INCARNATION');
|
|
11
|
+
const key = createHash('sha256').update(JSON.stringify([stateDir, incarnation])).digest('hex');
|
|
12
|
+
return join(stateRoot(), 'private-file-delivery', key);
|
|
13
|
+
}
|
|
14
|
+
function privateDirectory(path) {
|
|
15
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
16
|
+
const stat = lstatSync(path);
|
|
17
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || stat.mode & 0o077)
|
|
18
|
+
throw Error('INVALID_ARTIFACT_DIRECTORY');
|
|
19
|
+
}
|
|
20
|
+
export class ArtifactStore {
|
|
21
|
+
stateDir;
|
|
22
|
+
constructor(stateDir) {
|
|
23
|
+
this.stateDir = stateDir;
|
|
24
|
+
}
|
|
25
|
+
async copy(source, name, mimeType, binding, signal) {
|
|
26
|
+
if (!Number.isSafeInteger(source.size) || source.size < 0 || source.size > MAX_FILE_BYTES)
|
|
27
|
+
throw Error('FILE_EXCEEDS_20_MIB');
|
|
28
|
+
const path = artifactDirectory(this.stateDir);
|
|
29
|
+
privateDirectory(join(stateRoot(), 'private-file-delivery'));
|
|
30
|
+
privateDirectory(path);
|
|
31
|
+
const root = await openDirectory(path);
|
|
32
|
+
const id = randomUUID(), base = `/proc/self/fd/${root.fd}/`, partial = base + id + '.part';
|
|
33
|
+
let file;
|
|
34
|
+
const reader = source.body.getReader();
|
|
35
|
+
try {
|
|
36
|
+
// Orphans count toward the same bounded quota. They are never republished.
|
|
37
|
+
const entries = readdirSync(base).filter(p => /\.(data|part)$/.test(p));
|
|
38
|
+
const bytes = entries.reduce((sum, p) => sum + lstatSync(base + p).size, 0);
|
|
39
|
+
if (entries.length >= 100 || bytes + source.size > 200 * 1024 * 1024)
|
|
40
|
+
throw Error('ARTIFACT_QUOTA_EXCEEDED');
|
|
41
|
+
file = await open(partial, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
42
|
+
const hash = createHash('sha256');
|
|
43
|
+
let size = 0;
|
|
44
|
+
for (;;) {
|
|
45
|
+
signal.throwIfAborted();
|
|
46
|
+
const chunk = await reader.read();
|
|
47
|
+
if (chunk.done)
|
|
48
|
+
break;
|
|
49
|
+
size += chunk.value.length;
|
|
50
|
+
if (size > source.size || size > MAX_FILE_BYTES)
|
|
51
|
+
throw Error('SOURCE_SIZE_CHANGED');
|
|
52
|
+
hash.update(chunk.value);
|
|
53
|
+
let offset = 0;
|
|
54
|
+
while (offset < chunk.value.length) {
|
|
55
|
+
const { bytesWritten } = await file.write(chunk.value, offset, chunk.value.length - offset);
|
|
56
|
+
if (!bytesWritten)
|
|
57
|
+
throw Error('SHORT_ARTIFACT_WRITE');
|
|
58
|
+
offset += bytesWritten;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (size !== source.size)
|
|
62
|
+
throw Error('SOURCE_SIZE_CHANGED');
|
|
63
|
+
signal.throwIfAborted();
|
|
64
|
+
await file.chmod(0o400);
|
|
65
|
+
await file.sync();
|
|
66
|
+
await file.close();
|
|
67
|
+
file = undefined;
|
|
68
|
+
const record = { id, name, mimeType, size, sha256: hash.digest('hex'), ...binding };
|
|
69
|
+
renameSync(partial, base + id + '.data');
|
|
70
|
+
writeFileSync(base + id + '.json', JSON.stringify(record), { flag: 'wx', mode: 0o400, flush: true });
|
|
71
|
+
// No pending-send record or recovery: a later failure leaves only unreferenced stored bytes.
|
|
72
|
+
await root.sync();
|
|
73
|
+
// The newly created incarnation directory and store root must also survive
|
|
74
|
+
// a crash before a durable conversation event can reference this file.
|
|
75
|
+
for (const parent of [join(stateRoot(), 'private-file-delivery'), stateRoot()]) {
|
|
76
|
+
const handle = await openDirectory(parent);
|
|
77
|
+
try {
|
|
78
|
+
await handle.sync();
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
await handle.close();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return record;
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await file?.close();
|
|
88
|
+
await reader.cancel().catch(() => { });
|
|
89
|
+
await source.close();
|
|
90
|
+
await unlink(partial).catch(() => { });
|
|
91
|
+
await root.close();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export async function readDeliveredFile(stateDir, id) {
|
|
96
|
+
if (!/^[a-f0-9-]{36}$/.test(id))
|
|
97
|
+
throw Error('ARTIFACT_NOT_FOUND');
|
|
98
|
+
const root = await openDirectory(artifactDirectory(stateDir));
|
|
99
|
+
const read = (suffix, max) => {
|
|
100
|
+
const fd = openSync(`/proc/self/fd/${root.fd}/${id}.${suffix}`, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
101
|
+
try {
|
|
102
|
+
const stat = fstatSync(fd);
|
|
103
|
+
if (!stat.isFile() || stat.nlink !== 1 || stat.uid !== process.getuid?.() || stat.size > max)
|
|
104
|
+
throw Error('INVALID_STORED_ARTIFACT');
|
|
105
|
+
const bytes = readFileSync(fd);
|
|
106
|
+
if (bytes.length > max)
|
|
107
|
+
throw Error('ARTIFACT_TOO_LARGE');
|
|
108
|
+
return bytes;
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
closeSync(fd);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
try {
|
|
115
|
+
const record = JSON.parse(read('json', 4096).toString());
|
|
116
|
+
const bytes = read('data', MAX_FILE_BYTES);
|
|
117
|
+
if (record.id !== id || record.size !== bytes.length || record.sha256 !== createHash('sha256').update(bytes).digest('hex') || typeof record.name !== 'string')
|
|
118
|
+
throw Error('ARTIFACT_INTEGRITY_FAILED');
|
|
119
|
+
return { record, bytes };
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
await root.close();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FileDeliveryBinding {
|
|
2
|
+
sessionGeneration: string;
|
|
3
|
+
acpSessionId: string;
|
|
4
|
+
turnId: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DeliveredFile extends FileDeliveryBinding {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
mimeType: string;
|
|
10
|
+
size: number;
|
|
11
|
+
sha256: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FileDeliveryInput {
|
|
14
|
+
path: string;
|
|
15
|
+
filename?: string;
|
|
16
|
+
mime?: string;
|
|
17
|
+
}
|
|
18
|
+
export type CopyChatFile = (binding: FileDeliveryBinding) => Promise<DeliveredFile>;
|
|
19
|
+
export type SendChatFile = (input: FileDeliveryInput, signal: AbortSignal, copy: CopyChatFile) => Promise<DeliveredFile>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -80,6 +80,12 @@ export type FleetAuditPresentation = {
|
|
|
80
80
|
export declare const FLEET_LIFECYCLE_EVENT_KINDS: readonly ["agent_started", "task", "room", "lifecycle_failure"];
|
|
81
81
|
/** Stable semantic dedupe basis: resource kind + stable resource ID + transition/action ID. */
|
|
82
82
|
export declare function lifecycleEventDigestBasis(value: FleetAuditPresentation): string;
|
|
83
|
+
/** The managed agent the supervisor authenticated for this CLI process (fleet_audit_begin) and its state directory. */
|
|
84
|
+
export declare function setVerifiedFleetCaller(caller: string, stateDir: string): void;
|
|
85
|
+
export declare function verifiedFleetCaller(): {
|
|
86
|
+
caller: string;
|
|
87
|
+
stateDir: string;
|
|
88
|
+
} | undefined;
|
|
83
89
|
export declare function beginFleetAuditCollection(): void;
|
|
84
90
|
export declare function setFleetAuditLifecycleCheckpoint(checkpoint: ((presentations: FleetAuditPresentation[]) => Promise<void>) | undefined): void;
|
|
85
91
|
/**
|
|
@@ -113,6 +119,7 @@ export interface FleetCommandClassification {
|
|
|
113
119
|
decision: FleetCommandDecision;
|
|
114
120
|
}
|
|
115
121
|
export interface FleetAuditAttempt {
|
|
122
|
+
erased?: boolean;
|
|
116
123
|
version: 1;
|
|
117
124
|
correlationId: string;
|
|
118
125
|
requestId: string;
|
|
@@ -144,6 +151,12 @@ export declare const fleetProxyTopLevelInventory: Readonly<{
|
|
|
144
151
|
}>;
|
|
145
152
|
/** Classify before Commander parsing. Unknown and internal paths fail closed. */
|
|
146
153
|
export declare function classifyFleetArgv(argv: readonly string[]): FleetCommandClassification;
|
|
154
|
+
/**
|
|
155
|
+
* The pinned configuration of a managed entry (src/managed-cli.ts) is recorded
|
|
156
|
+
* as a fingerprint, not as its path: diagnostics must tell which configuration a
|
|
157
|
+
* row ran under without the ledger holding the path itself.
|
|
158
|
+
*/
|
|
159
|
+
export declare const managedPinMarker: (configuration: string) => string;
|
|
147
160
|
/** Faithful ordered argv with deterministic structural redaction. */
|
|
148
161
|
export declare function redactFleetArgv(argv: readonly string[]): string[];
|
|
149
162
|
/** Durable write-once attempt ledger; contains redacted argv only. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { erasedArg, redactErasedContent, writePrivacyFilteredLedger } from './erased-resources.js';
|
|
1
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
4
|
import { Buffer } from 'node:buffer';
|
|
4
|
-
import { replaceFileAtomically } from './atomic-file.js';
|
|
5
5
|
import { isSensitiveConfigKey } from './sensitive-config.js';
|
|
6
6
|
import { mandatoryConfigurationFits } from './lifecycle-summary.js';
|
|
7
7
|
import { MARKDOWN_MAX_BYTES, MARKDOWN_MAX_CODE_POINTS, markdownCode, markdownProse, } from './rooms-tasks/markdown.js';
|
|
@@ -26,6 +26,10 @@ export function lifecycleEventDigestBasis(value) {
|
|
|
26
26
|
const resourceKind = value.kind === 'lifecycle_failure' ? value.resource : value.kind;
|
|
27
27
|
return `${resourceKind}\0${value.id}\0${value.eventId}`;
|
|
28
28
|
}
|
|
29
|
+
let verifiedCaller;
|
|
30
|
+
/** The managed agent the supervisor authenticated for this CLI process (fleet_audit_begin) and its state directory. */
|
|
31
|
+
export function setVerifiedFleetCaller(caller, stateDir) { verifiedCaller = { caller, stateDir }; }
|
|
32
|
+
export function verifiedFleetCaller() { return verifiedCaller; }
|
|
29
33
|
let collection;
|
|
30
34
|
export function beginFleetAuditCollection() { collection = { resourceIds: {}, presentations: [] }; }
|
|
31
35
|
let lifecycleCheckpoint;
|
|
@@ -91,7 +95,7 @@ export function recordFleetAuditPresentation(value) {
|
|
|
91
95
|
: value.kind === 'lifecycle_failure'
|
|
92
96
|
? { label: fleetPresentationLabel(value.label) }
|
|
93
97
|
: {};
|
|
94
|
-
const presentation = structuredClone({ ...value, ...labels, eventId: basis });
|
|
98
|
+
const presentation = redactErasedContent(structuredClone({ ...value, ...labels, eventId: basis }));
|
|
95
99
|
const digest = lifecycleEventDigestBasis(presentation);
|
|
96
100
|
if (!collection.presentations.some(existing => lifecycleEventDigestBasis(existing) === digest))
|
|
97
101
|
collection.presentations.push(presentation);
|
|
@@ -120,7 +124,8 @@ const AGENT_SURFACES = {
|
|
|
120
124
|
ours: new Set(['tools', 'call']),
|
|
121
125
|
template: new Set(['list', 'show', 'validate']),
|
|
122
126
|
task: new Set(['create', 'list', 'lists', 'list-create', 'list-rename', 'list-delete', 'move',
|
|
123
|
-
'show', 'start', 'block', 'unblock', 'review', 'done', 'cancel', 'delete', 'work', 'finish'
|
|
127
|
+
'show', 'start', 'block', 'unblock', 'review', 'done', 'cancel', 'delete', 'work', 'finish',
|
|
128
|
+
'progress', 'review-package']),
|
|
124
129
|
room: new Set(['create', 'list', 'show', 'open', 'members', 'delete', 'close']),
|
|
125
130
|
};
|
|
126
131
|
export const fleetProxyCommandInventory = Object.freeze(Object.fromEntries(Object.entries(AGENT_SURFACES).map(([surface, commands]) => [surface, [...commands]])));
|
|
@@ -135,7 +140,8 @@ export const fleetProxyTopLevelInventory = Object.freeze({
|
|
|
135
140
|
], denied: [...DENIED],
|
|
136
141
|
hidden: ['_run', '_run-temp', '_run-temp-worker', '_run-watchdog', '_run-watchdogs'], aliases: ['man'],
|
|
137
142
|
});
|
|
138
|
-
|
|
143
|
+
// `--managed-configuration <file>` is the pinned managed entry form (src/managed-cli.ts).
|
|
144
|
+
const globalValueOptions = new Set(['-c', '--configuration', '--managed-configuration']);
|
|
139
145
|
/** Classify before Commander parsing. Unknown and internal paths fail closed. */
|
|
140
146
|
export function classifyFleetArgv(argv) {
|
|
141
147
|
let command = '';
|
|
@@ -186,12 +192,19 @@ export function classifyFleetArgv(argv) {
|
|
|
186
192
|
return { command, route: 'supervisor-proxy/public', decision: 'allow' };
|
|
187
193
|
}
|
|
188
194
|
const marker = (value) => value === '' ? '[REDACTED:empty]' : '[REDACTED:value]';
|
|
195
|
+
/**
|
|
196
|
+
* The pinned configuration of a managed entry (src/managed-cli.ts) is recorded
|
|
197
|
+
* as a fingerprint, not as its path: diagnostics must tell which configuration a
|
|
198
|
+
* row ran under without the ledger holding the path itself.
|
|
199
|
+
*/
|
|
200
|
+
export const managedPinMarker = (configuration) => `[PIN:${createHash('sha256').update(configuration).digest('hex').slice(0, 16)}]`;
|
|
189
201
|
const sensitiveValueFlags = new Set([
|
|
190
202
|
'--identity', '--invite', '--token', '--api-token', '--password', '--password-file',
|
|
191
203
|
'--env', '--brief', '--brief-file', '--bio-file', '--persona-file', '--isolation-file', '--loops-file',
|
|
192
|
-
'--configuration', '-c', '--public-invite', '--public-invite-file', '--invite-file',
|
|
204
|
+
'--configuration', '-c', '--managed-configuration', '--public-invite', '--public-invite-file', '--invite-file',
|
|
193
205
|
'--args-file', '--summary-file', '--text', '--message', '--summary', '--reason', '--goal', '--cwd',
|
|
194
206
|
'--identity-cid', '--owner-cid', '--contact-cid', '--codex-config', '--add-dir',
|
|
207
|
+
'--text-file', '--markdown', '--markdown-file', '--attach',
|
|
195
208
|
]);
|
|
196
209
|
function redactUrl(value) {
|
|
197
210
|
try {
|
|
@@ -249,6 +262,11 @@ export function redactFleetArgv(argv) {
|
|
|
249
262
|
result[index] = `${equal[1]}=${marker(equal[2])}`;
|
|
250
263
|
continue;
|
|
251
264
|
}
|
|
265
|
+
if (index === 0 && arg === '--managed-configuration' && result.length > 1) {
|
|
266
|
+
result[1] = managedPinMarker(result[1]);
|
|
267
|
+
index++;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
252
270
|
if (sensitiveValueFlags.has(arg) && index + 1 < result.length) {
|
|
253
271
|
result[index + 1] = marker(result[index + 1]);
|
|
254
272
|
index++;
|
|
@@ -305,11 +323,12 @@ export class FleetCommandAuditStore {
|
|
|
305
323
|
if (recovered)
|
|
306
324
|
this.persist();
|
|
307
325
|
}
|
|
308
|
-
list() { return this.attempts.map(item => structuredClone(item)); }
|
|
326
|
+
list() { return redactErasedContent(this.attempts).map(item => structuredClone(item)); }
|
|
309
327
|
begin(requestId, caller, argv) {
|
|
328
|
+
this.attempts = redactErasedContent(this.attempts);
|
|
310
329
|
const existing = this.attempts.find(item => item.caller === caller && item.requestId === requestId);
|
|
311
330
|
if (existing) {
|
|
312
|
-
if (JSON.stringify(existing.argv) !== JSON.stringify(redactFleetArgv(argv)))
|
|
331
|
+
if (JSON.stringify(existing.argv) !== JSON.stringify(existing.erased ? redactFleetArgv(argv).map(erasedArg) : redactFleetArgv(argv)))
|
|
313
332
|
throw new Error('fleet command request ID was reused with different argv');
|
|
314
333
|
return structuredClone(existing);
|
|
315
334
|
}
|
|
@@ -329,6 +348,8 @@ export class FleetCommandAuditStore {
|
|
|
329
348
|
return structuredClone(attempt);
|
|
330
349
|
}
|
|
331
350
|
finish(correlationId, caller, outcome) {
|
|
351
|
+
this.attempts = redactErasedContent(this.attempts);
|
|
352
|
+
outcome = redactErasedContent({ outcome }).outcome;
|
|
332
353
|
const attempt = this.owned(correlationId, caller);
|
|
333
354
|
if (!attempt.outcome)
|
|
334
355
|
attempt.outcome = { ...outcome, completedAt: this.deps.now().toISOString(), delivery: 'sending' };
|
|
@@ -360,7 +381,8 @@ export class FleetCommandAuditStore {
|
|
|
360
381
|
return attempt;
|
|
361
382
|
}
|
|
362
383
|
persist() {
|
|
363
|
-
|
|
384
|
+
this.attempts = redactErasedContent(this.attempts);
|
|
385
|
+
writePrivacyFilteredLedger(this.path, { version: 1, attempts: this.attempts });
|
|
364
386
|
}
|
|
365
387
|
}
|
|
366
388
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
@@ -30,6 +30,10 @@ export interface AgentSessionStartOptions {
|
|
|
30
30
|
cwd: string;
|
|
31
31
|
stateDir: string;
|
|
32
32
|
mode: 'fresh' | 'resume';
|
|
33
|
+
/** Durable task context must never silently fall back to a fresh session. */
|
|
34
|
+
requireResume?: boolean;
|
|
35
|
+
/** Hold recovered never-started prompts until AgentSession.activateRecoveredPrompts(). */
|
|
36
|
+
deferRecoveredPrompts?: boolean;
|
|
33
37
|
permissions: CommonPermissions;
|
|
34
38
|
permissionMode: {
|
|
35
39
|
fleetMode: FleetPermissionMode;
|
|
@@ -24,7 +24,7 @@ export class ClaudeCodeAgentSessionAdapter {
|
|
|
24
24
|
return this.transport({
|
|
25
25
|
name: role.name, harness: role.harness,
|
|
26
26
|
argv: launch.argv, cwd: options.cwd, env: launch.env,
|
|
27
|
-
stateDir: options.stateDir, mode: options.mode, permissions: options.permissions,
|
|
27
|
+
stateDir: options.stateDir, mode: options.mode, requireResume: options.requireResume, deferRecoveredPrompts: options.deferRecoveredPrompts, permissions: options.permissions,
|
|
28
28
|
modeId: this.strategy.permissionModeId(role),
|
|
29
29
|
mcpServers: options.managedOurs ? [...(this.strategy.mcpServers(role) ?? []).filter(s => s.name !== 'ours'), options.managedOurs.server] : this.strategy.mcpServers(role),
|
|
30
30
|
inheritEnvironment: options.managedOurs ? false : undefined,
|
|
@@ -6,7 +6,8 @@ import { realExec } from '../exec.js';
|
|
|
6
6
|
import { registerAdapter } from './registry.js';
|
|
7
7
|
import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
|
|
8
8
|
import { harnessRuntimeDir } from '../isolation/policy.js';
|
|
9
|
-
import { bundledAcpAgent } from './acp-agent.js';
|
|
9
|
+
import { bundledAcpAgent, resolveBundledAcpAgent } from './acp-agent.js';
|
|
10
|
+
import { hostClaude } from './claude-runtime.js';
|
|
10
11
|
import { ClaudeCodeAgentSessionAdapter } from './claude-code-session.js';
|
|
11
12
|
const OPTION_KEYS = [
|
|
12
13
|
'plugins', 'mem_palace', 'mem_palace_midsession_autosave', 'permission_mode', 'effort',
|
|
@@ -283,6 +284,13 @@ export function makeClaudeCodeAdapter(exec = realExec, transport) {
|
|
|
283
284
|
};
|
|
284
285
|
if (!memPalace)
|
|
285
286
|
env.MEMPALACE_DISABLED = 'true';
|
|
287
|
+
// The bundled adapter runs the Claude Code shipped with its SDK unless told otherwise. A host
|
|
288
|
+
// Claude Code at least as new as that copy is the one the person updates, so sessions run it.
|
|
289
|
+
if (!customAcpCommand(role)) {
|
|
290
|
+
const host = hostClaude(resolveBundledAcpAgent('@agentclientprotocol/claude-agent-acp', 'claude-agent-acp', 'claude-agent-acp').manifestPath, { ...process.env, ...role.env }, dirs.runCwd);
|
|
291
|
+
if (host)
|
|
292
|
+
env.CLAUDE_CODE_EXECUTABLE = host.path;
|
|
293
|
+
}
|
|
286
294
|
// Per-role harness runtime home. Created before sandbox entry so the
|
|
287
295
|
// bind has something to mount; harmless for un-isolated roles.
|
|
288
296
|
// Only a role that declares `isolation:` gets a sandbox, and only a
|
|
@@ -377,16 +385,18 @@ export function makeClaudeCodeAdapter(exec = realExec, transport) {
|
|
|
377
385
|
supervisedWakeNote: () => 'Your mail wake-ups are delivered by the fleet supervisor directly into this console as ' +
|
|
378
386
|
'`[fleet-monitor]` lines — do NOT arm an in-session Monitor. When such a line appears, run ' +
|
|
379
387
|
'**get_messages** to drain the mail.',
|
|
380
|
-
launchNote: name => `You were launched
|
|
381
|
-
restartPrompt: (id, worklog, role) =>
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
388
|
+
launchNote: name => `You were launched as Fleet role \`${name}\` under a Claude session. Announce console readiness before task details.`,
|
|
389
|
+
restartPrompt: (id, worklog, role) => role?.monitor?.mode === 'fleet'
|
|
390
|
+
? `Session restarted. The supervisor has verified assigned identity "${id}"; ` +
|
|
391
|
+
'accept that readiness and continue without rebinding or profile reconciliation. ' +
|
|
392
|
+
'Your mail wakes arrive as `[fleet-monitor]` console lines from the supervisor — ' +
|
|
393
|
+
'do NOT arm an in-session Monitor. ' +
|
|
394
|
+
'Announce console readiness first without tools, then end that readiness turn. ' +
|
|
395
|
+
`For a separate continuation task, read ${worklog} once for continuity if it records previous work; ` +
|
|
396
|
+
'do not read it again later in this session. ' +
|
|
397
|
+
'Do not re-run whatever crashed you.'
|
|
398
|
+
: `Session restarted. Re-bind your ours identity now (choose_identity name "${id}" force=true), ` +
|
|
399
|
+
`then ${armMonitor(id)}, then continue from ${worklog}. Do not re-run whatever crashed you.`,
|
|
390
400
|
},
|
|
391
401
|
exitPolicy: { cleanExitIsFresh: true, fastFailSecs: 20 },
|
|
392
402
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The Claude Code version shipped inside the adapter's own SDK dependency. */
|
|
2
|
+
export declare function bundledClaudeVersion(adapterManifest: string): string | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* The host's own Claude Code, when ACP sessions should run it instead of the copy bundled with the adapter.
|
|
5
|
+
* The person signs in to, updates and checks the host Claude Code, and a newer one knows models the bundled
|
|
6
|
+
* one does not. It is used only when it is at least as new as the bundled copy; an explicit
|
|
7
|
+
* CLAUDE_CODE_EXECUTABLE, in the role or the service environment, always decides instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare function hostClaude(adapterManifest: string | undefined, env: NodeJS.ProcessEnv, cwd?: string, version?: (path: string, env: NodeJS.ProcessEnv) => string | undefined): {
|
|
10
|
+
path: string;
|
|
11
|
+
version: string;
|
|
12
|
+
} | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { codexVersionAtLeast, executableOnPath } from './codex-runtime.js';
|
|
6
|
+
const versionOf = (text) => text.match(/\b(\d+\.\d+\.\d+)\b/)?.[1];
|
|
7
|
+
function installedClaudeVersion(path, env) {
|
|
8
|
+
const result = spawnSync(path, ['--version'], { env, encoding: 'utf8', timeout: 5_000, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
9
|
+
return result.status === 0 ? versionOf(result.stdout ?? '') : undefined;
|
|
10
|
+
}
|
|
11
|
+
/** The Claude Code version shipped inside the adapter's own SDK dependency. */
|
|
12
|
+
export function bundledClaudeVersion(adapterManifest) {
|
|
13
|
+
try {
|
|
14
|
+
const sdk = dirname(createRequire(adapterManifest).resolve('@anthropic-ai/claude-agent-sdk'));
|
|
15
|
+
const version = JSON.parse(readFileSync(join(sdk, 'package.json'), 'utf8')).claudeCodeVersion;
|
|
16
|
+
return typeof version === 'string' ? version : undefined;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The host's own Claude Code, when ACP sessions should run it instead of the copy bundled with the adapter.
|
|
24
|
+
* The person signs in to, updates and checks the host Claude Code, and a newer one knows models the bundled
|
|
25
|
+
* one does not. It is used only when it is at least as new as the bundled copy; an explicit
|
|
26
|
+
* CLAUDE_CODE_EXECUTABLE, in the role or the service environment, always decides instead.
|
|
27
|
+
*/
|
|
28
|
+
export function hostClaude(adapterManifest, env, cwd = process.cwd(), version = installedClaudeVersion) {
|
|
29
|
+
if (env.CLAUDE_CODE_EXECUTABLE !== undefined || !adapterManifest)
|
|
30
|
+
return undefined;
|
|
31
|
+
const bundled = bundledClaudeVersion(adapterManifest);
|
|
32
|
+
if (!bundled)
|
|
33
|
+
return undefined;
|
|
34
|
+
let path;
|
|
35
|
+
try {
|
|
36
|
+
path = executableOnPath('claude', env, cwd);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const found = version(path, env);
|
|
42
|
+
return found && codexVersionAtLeast(found, bundled) ? { path, version: found } : undefined;
|
|
43
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
type JsonObject = Record<string, unknown>;
|
|
2
3
|
interface TerminalRecoveryOptions {
|
|
3
4
|
sendToCodex(line: string): void;
|
|
4
5
|
emitToClient(line: string): void;
|
|
@@ -39,6 +40,8 @@ export declare class CodexTerminalRecovery {
|
|
|
39
40
|
private finishTurn;
|
|
40
41
|
}
|
|
41
42
|
/** Transform one app-server NDJSON request; malformed input passes through. */
|
|
42
|
-
export declare function rewriteCodexAppServerRequest(line: string, approval: string, expectedSandbox: string, disableInheritedMcp?: boolean): string;
|
|
43
|
+
export declare function rewriteCodexAppServerRequest(line: string, approval: string, expectedSandbox: string, disableInheritedMcp?: boolean, managedOursTools?: JsonObject): string;
|
|
44
|
+
/** ACP only carries transport fields; read policy from Fleet's complete config. */
|
|
45
|
+
export declare function managedCodexToolPolicy(env: NodeJS.ProcessEnv): JsonObject | undefined;
|
|
43
46
|
export declare function runCodexAppServerProxy(): void;
|
|
44
47
|
export {};
|