@ours.network/fleet 1.2.0-nightly.6 → 1.2.0-nightly.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +287 -65
- package/dist/account-origin.d.ts +2 -0
- package/dist/account-origin.js +6 -0
- package/dist/agent-ours/bridge.js +35 -9
- package/dist/agent-ours/correspondence.d.ts +10 -0
- package/dist/agent-ours/correspondence.js +1 -0
- package/dist/agent-ours/file-rpc.d.ts +12 -0
- package/dist/agent-ours/file-rpc.js +18 -4
- package/dist/agent-ours/harness.js +9 -1
- package/dist/agent-ours/mcp-endpoint.d.ts +4 -0
- package/dist/agent-ours/mcp-endpoint.js +5 -0
- package/dist/agent-ours/runtime.d.ts +9 -1
- package/dist/agent-ours/runtime.js +50 -2
- package/dist/agent-ours/service.d.ts +21 -1
- package/dist/agent-ours/service.js +94 -14
- package/dist/application/codex-models.d.ts +15 -0
- package/dist/application/codex-models.js +56 -0
- package/dist/application/conversation-history.d.ts +27 -0
- package/dist/application/conversation-history.js +212 -0
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +2 -2
- package/dist/application/legacy-supervisor-identity.d.ts +7 -0
- package/dist/application/legacy-supervisor-identity.js +43 -0
- package/dist/application/log-service.js +8 -8
- package/dist/application/model-catalog.d.ts +1 -1
- package/dist/application/model-catalog.js +5 -2
- package/dist/application/preset-provenance.d.ts +19 -0
- package/dist/application/preset-provenance.js +59 -0
- package/dist/application/role-creation-service.js +3 -2
- package/dist/application/role-removal-service.js +9 -1
- package/dist/application/role-repository.js +19 -2
- package/dist/application/room-layout-definitions.d.ts +45 -0
- package/dist/application/room-layout-definitions.js +130 -0
- package/dist/application/session-control.d.ts +30 -0
- package/dist/application/session-control.js +72 -3
- package/dist/application/supervisor-ours-tools.d.ts +159 -0
- package/dist/application/supervisor-ours-tools.js +115 -0
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +259 -0
- package/dist/application/task-room-service.d.ts +99 -3
- package/dist/application/task-room-service.js +285 -32
- package/dist/application/types.d.ts +2 -0
- package/dist/atomic-file.d.ts +5 -0
- package/dist/atomic-file.js +62 -1
- package/dist/briefing.d.ts +3 -1
- package/dist/briefing.js +70 -30
- package/dist/build-info.json +7 -4
- package/dist/capabilities.d.ts +6 -1
- package/dist/capabilities.js +8 -0
- package/dist/cli.js +407 -37
- package/dist/client-profile.d.ts +5 -17
- package/dist/client-profile.js +4 -127
- package/dist/config.d.ts +45 -0
- package/dist/config.js +57 -6
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +4 -4
- package/dist/daemon-recovery.d.ts +1 -8
- package/dist/daemon-recovery.js +8 -113
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +123 -19
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +55 -60
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/file-delivery/reader.d.ts +15 -0
- package/dist/file-delivery/reader.js +63 -0
- package/dist/file-delivery/store.d.ts +15 -0
- package/dist/file-delivery/store.js +124 -0
- package/dist/file-delivery/types.d.ts +19 -0
- package/dist/file-delivery/types.js +1 -0
- package/dist/fleet-command-audit.d.ts +7 -0
- package/dist/fleet-command-audit.js +26 -9
- package/dist/harness/agent-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +1 -1
- package/dist/harness/claude-code.js +20 -11
- package/dist/harness/claude-runtime.d.ts +12 -0
- package/dist/harness/claude-runtime.js +43 -0
- package/dist/harness/codex-app-server-proxy.d.ts +4 -1
- package/dist/harness/codex-app-server-proxy.js +41 -5
- package/dist/harness/codex-reasoning.d.ts +5 -0
- package/dist/harness/codex-reasoning.js +12 -0
- package/dist/harness/codex-runtime.d.ts +11 -1
- package/dist/harness/codex-runtime.js +31 -4
- package/dist/harness/codex-session.js +2 -2
- package/dist/harness/codex.js +23 -12
- package/dist/init-wizard.d.ts +2 -0
- package/dist/init-wizard.js +38 -19
- package/dist/isolation/policy.js +6 -1
- package/dist/isolation/types.d.ts +5 -0
- package/dist/managed-cli.d.ts +253 -0
- package/dist/managed-cli.js +923 -0
- package/dist/managed-recovery.d.ts +13 -0
- package/dist/managed-recovery.js +31 -0
- package/dist/minimal-setup.d.ts +2 -0
- package/dist/minimal-setup.js +44 -0
- package/dist/monitor.d.ts +8 -34
- package/dist/monitor.js +89 -152
- package/dist/notifications/fleet-producer.d.ts +19 -0
- package/dist/notifications/fleet-producer.js +208 -0
- package/dist/notifications/outbox.d.ts +46 -0
- package/dist/notifications/outbox.js +158 -0
- package/dist/notifications/target-cleanup.d.ts +8 -0
- package/dist/notifications/target-cleanup.js +41 -0
- package/dist/notifications/task-producer.d.ts +18 -0
- package/dist/notifications/task-producer.js +67 -0
- package/dist/ops.d.ts +2 -0
- package/dist/ops.js +20 -3
- package/dist/owner-channel/channel.js +17 -6
- package/dist/owner-channel/commands.d.ts +4 -0
- package/dist/owner-channel/commands.js +8 -0
- package/dist/owner-channel/lifecycle-outbox.js +4 -3
- package/dist/owner-channel/ours-client.js +2 -17
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +2 -0
- package/dist/preset-migration.js +25 -0
- package/dist/resolved-plan.js +1 -0
- package/dist/rooms-tasks/add-member.d.ts +48 -0
- package/dist/rooms-tasks/add-member.js +83 -0
- package/dist/rooms-tasks/archived-absence.d.ts +8 -0
- package/dist/rooms-tasks/archived-absence.js +48 -0
- package/dist/rooms-tasks/cli.js +65 -5
- package/dist/rooms-tasks/close.d.ts +6 -2
- package/dist/rooms-tasks/close.js +246 -37
- package/dist/rooms-tasks/config.d.ts +1 -1
- package/dist/rooms-tasks/config.js +11 -4
- package/dist/rooms-tasks/cowork-adapter.d.ts +2 -4
- package/dist/rooms-tasks/cowork-adapter.js +7 -121
- package/dist/rooms-tasks/cowork-http.js +29 -1
- package/dist/rooms-tasks/deletion.d.ts +1 -1
- package/dist/rooms-tasks/deletion.js +84 -5
- package/dist/rooms-tasks/erasure.d.ts +6 -0
- package/dist/rooms-tasks/erasure.js +173 -0
- package/dist/rooms-tasks/external-worker.d.ts +1 -1
- package/dist/rooms-tasks/external-worker.js +3 -4
- package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
- package/dist/rooms-tasks/layout-binding-client.js +56 -0
- package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
- package/dist/rooms-tasks/layout-binding-grants.js +128 -0
- package/dist/rooms-tasks/layout-cli.d.ts +4 -0
- package/dist/rooms-tasks/layout-cli.js +107 -0
- package/dist/rooms-tasks/layout-config.d.ts +11 -0
- package/dist/rooms-tasks/layout-config.js +89 -0
- package/dist/rooms-tasks/layout-control.d.ts +21 -0
- package/dist/rooms-tasks/layout-control.js +52 -0
- package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
- package/dist/rooms-tasks/layout-member-retirement.js +90 -0
- package/dist/rooms-tasks/layout-service.d.ts +43 -0
- package/dist/rooms-tasks/layout-service.js +203 -0
- package/dist/rooms-tasks/layout.d.ts +121 -0
- package/dist/rooms-tasks/layout.js +285 -0
- package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
- package/dist/rooms-tasks/legacy-task-member.js +116 -0
- package/dist/rooms-tasks/live-readiness.d.ts +18 -0
- package/dist/rooms-tasks/live-readiness.js +85 -0
- package/dist/rooms-tasks/member-ownership.d.ts +5 -0
- package/dist/rooms-tasks/member-ownership.js +40 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +2 -0
- package/dist/rooms-tasks/provision.d.ts +3 -0
- package/dist/rooms-tasks/provision.js +101 -49
- package/dist/rooms-tasks/recovery.d.ts +19 -0
- package/dist/rooms-tasks/recovery.js +110 -0
- package/dist/rooms-tasks/room-state.d.ts +4 -2
- package/dist/rooms-tasks/room-state.js +47 -8
- package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
- package/dist/rooms-tasks/task-service-retirement.js +21 -0
- package/dist/rooms-tasks/task-state.d.ts +51 -8
- package/dist/rooms-tasks/task-state.js +245 -25
- package/dist/rooms-tasks/types.d.ts +40 -0
- package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
- package/dist/rooms-tasks/workspace-artifacts.js +93 -0
- package/dist/rooms-tasks/workspace.d.ts +35 -0
- package/dist/rooms-tasks/workspace.js +325 -0
- package/dist/runner.d.ts +25 -3
- package/dist/runner.js +291 -49
- package/dist/session/acp.d.ts +53 -1
- package/dist/session/acp.js +216 -40
- package/dist/session/arbiter.d.ts +11 -0
- package/dist/session/arbiter.js +43 -2
- package/dist/session/codex-app-server.d.ts +32 -0
- package/dist/session/codex-app-server.js +137 -23
- package/dist/session/control.d.ts +12 -1
- package/dist/session/control.js +68 -3
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-store.d.ts +1 -1
- package/dist/session/conversation-store.js +7 -11
- package/dist/session/conversation-types.d.ts +28 -3
- package/dist/session/prompt-batch.d.ts +63 -0
- package/dist/session/prompt-batch.js +86 -0
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +14 -0
- package/dist/setup-tunnel-preflight.d.ts +34 -0
- package/dist/setup-tunnel-preflight.js +62 -0
- package/dist/socket-path.d.ts +2 -0
- package/dist/socket-path.js +22 -0
- package/dist/spawn.d.ts +5 -1
- package/dist/spawn.js +40 -4
- package/dist/startup-prompt.d.ts +4 -0
- package/dist/startup-prompt.js +36 -0
- package/dist/startup-readiness.d.ts +13 -0
- package/dist/startup-readiness.js +38 -0
- package/dist/startup-telemetry.d.ts +16 -0
- package/dist/startup-telemetry.js +46 -0
- package/dist/subscriptions/cli.d.ts +91 -0
- package/dist/subscriptions/cli.js +223 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +75 -0
- package/dist/subscriptions/login.js +182 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +140 -0
- package/dist/supervisor/adoption.d.ts +8 -0
- package/dist/supervisor/adoption.js +78 -0
- package/dist/supervisor/catalog.d.ts +62 -0
- package/dist/supervisor/catalog.js +254 -0
- package/dist/supervisor/fleet.d.ts +8 -0
- package/dist/supervisor/fleet.js +89 -0
- package/dist/supervisor/index.js +3 -6
- package/dist/supervisor/launchd.d.ts +1 -1
- package/dist/supervisor/launchd.js +26 -13
- package/dist/supervisor/legacy.d.ts +35 -0
- package/dist/supervisor/legacy.js +524 -0
- package/dist/supervisor/manager.d.ts +15 -0
- package/dist/supervisor/manager.js +270 -0
- package/dist/supervisor/scope.d.ts +4 -0
- package/dist/supervisor/scope.js +10 -0
- package/dist/supervisor/systemd.d.ts +2 -2
- package/dist/supervisor/systemd.js +19 -33
- package/dist/task-supervision.d.ts +9 -0
- package/dist/task-supervision.js +145 -0
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +23 -8
- package/dist/temp-lifecycle.js +113 -65
- package/dist/temp-supervisor-recovery.d.ts +1 -1
- package/dist/temp-supervisor-recovery.js +2 -2
- package/dist/tunnel-setup-completion.d.ts +7 -0
- package/dist/tunnel-setup-completion.js +13 -0
- package/dist/tunnel-setup-input.d.ts +19 -0
- package/dist/tunnel-setup-input.js +124 -0
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +63 -2
- package/dist/web/auth.js +191 -10
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/control.d.ts +3 -3
- package/dist/web/control.js +10 -8
- package/dist/web/fleet-config-service.d.ts +4 -1
- package/dist/web/fleet-config-service.js +46 -15
- package/dist/web/prefix-gateway.d.ts +32 -0
- package/dist/web/prefix-gateway.js +238 -0
- package/dist/web/runtime.d.ts +3 -1
- package/dist/web/runtime.js +116 -31
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.js +654 -55
- package/dist/web/service.d.ts +11 -2
- package/dist/web/service.js +30 -4
- package/dist/web/workspace-devices.d.ts +107 -0
- package/dist/web/workspace-devices.js +277 -0
- package/dist/web/workspace-tunnel.d.ts +1 -0
- package/dist/web/workspace-tunnel.js +34 -0
- package/dist/workspace-enrollment.d.ts +82 -0
- package/dist/workspace-enrollment.js +566 -0
- package/dist/workspace-replacement.d.ts +66 -0
- package/dist/workspace-replacement.js +220 -0
- package/docs/acp-files.md +146 -0
- package/docs/fleet-migration.md +54 -0
- package/docs/live-voice.md +13 -0
- package/docs/room-layouts.md +227 -0
- package/docs/task-workspaces.md +225 -0
- package/docs/validation/managed-cli-permissions.md +421 -0
- package/examples/room-layouts/fresh.yaml +27 -0
- package/examples/room-layouts/scoped.yaml +21 -0
- package/examples/room-layouts/shared.yaml +19 -0
- package/package.json +20 -19
- package/presets/README.md +78 -0
- package/presets/brain-catalog.json +8 -2
- package/presets/fleet/agent_templates/Critic.yaml +1 -1
- package/presets/fleet/agent_templates/Developer.yaml +1 -1
- package/presets/fleet/agent_templates/Engineer.yaml +5 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
- package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
- package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +34 -11
- package/presets/fleet/roles/Engineer.yaml +40 -0
- package/presets/fleet/room_layouts/engineering.yaml +25 -0
- package/presets/fleet/room_layouts/pair.yaml +24 -0
- package/presets/fleet/room_layouts/single.yaml +17 -0
- package/presets/fleet/room_layouts/team.yaml +30 -0
- package/presets/fleet/room_templates/engineering.yaml +19 -0
- package/presets/manifest.json +2 -2
- package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
- package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
- package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
- package/dist/web-app/icons/ours-fleet.svg +0 -4
- package/dist/web-app/index.html +0 -17
- package/dist/web-app/manifest.webmanifest +0 -15
- package/dist/web-app/offline.html +0 -18
- package/dist/web-app/sw.js +0 -51
|
@@ -883,8 +883,15 @@ export class OwnerChannel {
|
|
|
883
883
|
const recovered = [];
|
|
884
884
|
for (const claim of this.messageRecovery.list()) {
|
|
885
885
|
const item = await this.client.getHistoryItem(claim.wireId);
|
|
886
|
-
if (!item)
|
|
887
|
-
|
|
886
|
+
if (!item) {
|
|
887
|
+
// The daemon has definitively lost this body. Retrying the claim would
|
|
888
|
+
// block every later owner message, including after a supervisor restart.
|
|
889
|
+
// Keep transient lookup errors retryable; only an explicit absence skips.
|
|
890
|
+
this.messageRecovery.pruneHandled(wireId => wireId === claim.wireId);
|
|
891
|
+
this.options.log(`[${this.options.role}] skipped journaled owner message ${claim.wireId} `
|
|
892
|
+
+ `(seq=${claim.seq}): missing from persistent history`);
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
888
895
|
recovered.push(this.historyMessage(item, claim));
|
|
889
896
|
}
|
|
890
897
|
const listed = await this.client.listIncomingMessages();
|
|
@@ -1391,6 +1398,7 @@ export class OwnerChannel {
|
|
|
1391
1398
|
await this.fleetOps.provisionTask(task.task_id);
|
|
1392
1399
|
return outcome;
|
|
1393
1400
|
}),
|
|
1401
|
+
observeTaskReadiness: taskId => new TaskRoomApplicationService(this.options.configPath).observeTaskReadiness(taskId),
|
|
1394
1402
|
taskProvisioningOutcome: taskId => new TaskRoomApplicationService(this.options.configPath).taskProvisioningOutcome(taskId),
|
|
1395
1403
|
listTasks: filter => new TaskRoomApplicationService(this.options.configPath).listTasks(filter),
|
|
1396
1404
|
groupedTasks: filter => new TaskRoomApplicationService(this.options.configPath).groupedTasks(filter),
|
|
@@ -1977,6 +1985,9 @@ export class OwnerChannel {
|
|
|
1977
1985
|
const progressMs = this.options.config.progress_interval_ms;
|
|
1978
1986
|
let lastSeq = activityCursor;
|
|
1979
1987
|
let startedAt;
|
|
1988
|
+
// When one turn delivers several waiting prompts, its events carry the turn's
|
|
1989
|
+
// id, not this request's: follow the turn that actually carries this request.
|
|
1990
|
+
const inTurn = (turnId) => turnId === (this.options.session.sharedTurnId?.(queued.promptId) ?? queued.promptId);
|
|
1980
1991
|
let phase = 'starting request';
|
|
1981
1992
|
let timer;
|
|
1982
1993
|
const flushCommentary = () => {
|
|
@@ -2033,7 +2044,7 @@ export class OwnerChannel {
|
|
|
2033
2044
|
};
|
|
2034
2045
|
const acceptCommentary = (event) => {
|
|
2035
2046
|
if (!this.commentsEnabled
|
|
2036
|
-
|| active.commentaryDisabled || active.finalizing || event.turnId
|
|
2047
|
+
|| active.commentaryDisabled || active.finalizing || !inTurn(event.turnId)
|
|
2037
2048
|
|| event.kind !== 'agent_text' || event.messagePhase !== 'commentary'
|
|
2038
2049
|
|| event.replayed || event.origin?.kind !== 'owner'
|
|
2039
2050
|
|| event.origin.requestId !== active.requestId
|
|
@@ -2074,7 +2085,7 @@ export class OwnerChannel {
|
|
|
2074
2085
|
const reportProgress = () => {
|
|
2075
2086
|
const events = this.options.session.eventsSince(lastSeq);
|
|
2076
2087
|
lastSeq = Math.max(lastSeq, this.latestEventSeq(events));
|
|
2077
|
-
const activity = events.filter(event => event.turnId
|
|
2088
|
+
const activity = events.filter(event => inTurn(event.turnId));
|
|
2078
2089
|
if (!activity.length)
|
|
2079
2090
|
return;
|
|
2080
2091
|
startedAt ??= Date.parse(activity[0].at) || Date.now();
|
|
@@ -2099,10 +2110,10 @@ export class OwnerChannel {
|
|
|
2099
2110
|
const startProgress = (event) => {
|
|
2100
2111
|
if (timer || progressMs <= 0)
|
|
2101
2112
|
return;
|
|
2102
|
-
if (event && event.turnId
|
|
2113
|
+
if (event && !inTurn(event.turnId))
|
|
2103
2114
|
return;
|
|
2104
2115
|
const observed = event ? [event] : this.options.session.eventsSince(activityCursor)
|
|
2105
|
-
.filter(item => item.turnId
|
|
2116
|
+
.filter(item => inTurn(item.turnId));
|
|
2106
2117
|
if (!observed.length)
|
|
2107
2118
|
return;
|
|
2108
2119
|
startedAt = Date.parse(observed[0].at) || Date.now();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TaskReadinessIssue } from '../rooms-tasks/live-readiness.js';
|
|
1
2
|
import type { InterruptOutcome, SessionEvent, SessionSnapshot } from '../session/types.js';
|
|
2
3
|
import type { RoomOrchestrationRecord, TaskOutcome, TaskRecord, TaskTerminalIntent, TaskListRecord } from '../rooms-tasks/types.js';
|
|
3
4
|
import { type OwnerCommentsState } from './notices.js';
|
|
@@ -58,6 +59,9 @@ export interface OwnerCommandContext {
|
|
|
58
59
|
terminalTask(taskId: string, kind: TaskTerminalIntent['kind'], outcome?: TaskOutcome): Promise<void>;
|
|
59
60
|
createTask(input: Omit<CreateTaskRequest, 'actor'>): Promise<TaskRecord>;
|
|
60
61
|
startTask(taskId: string): Promise<TaskProvisioningOutcome | TaskRecord>;
|
|
62
|
+
observeTaskReadiness?(taskId: string): Promise<{
|
|
63
|
+
state: 'ready';
|
|
64
|
+
} | TaskReadinessIssue>;
|
|
61
65
|
taskProvisioningOutcome?(taskId: string): TaskProvisioningOutcome;
|
|
62
66
|
listTasks(filter?: {
|
|
63
67
|
state?: TaskState | TaskState[];
|
|
@@ -47,6 +47,11 @@ function isKnownOwnerRoomState(message) {
|
|
|
47
47
|
].some(pattern => pattern.test(message));
|
|
48
48
|
}
|
|
49
49
|
function ownerTaskFailure(error) {
|
|
50
|
+
if (error instanceof TaskRoomApplicationError && error.code === 'task_not_ready')
|
|
51
|
+
return {
|
|
52
|
+
kind: 'state', detail: error.message,
|
|
53
|
+
action: 'Ask Fleet Coordinator to inspect room and member status and choose supported recovery.',
|
|
54
|
+
};
|
|
50
55
|
if (error instanceof TaskListError)
|
|
51
56
|
return {
|
|
52
57
|
kind: error.code === 'list_not_found' ? 'not_found'
|
|
@@ -301,6 +306,7 @@ export const ownerCommands = [
|
|
|
301
306
|
const trailingLines = argLines.slice(1).join('\n').trim() || undefined;
|
|
302
307
|
const showTask = async (id) => {
|
|
303
308
|
const { task: t } = ctx.getTask(id);
|
|
309
|
+
const readiness = t.state === 'active' ? await ctx.observeTaskReadiness?.(id) : undefined;
|
|
304
310
|
await ctx.reply(renderMarkdownResult({
|
|
305
311
|
icon: '📋', title: 'Task details',
|
|
306
312
|
fields: [
|
|
@@ -308,6 +314,8 @@ export const ownerCommands = [
|
|
|
308
314
|
{ label: 'Title', value: t.title },
|
|
309
315
|
{ label: 'Status', value: taskStatus(t.state), kind: 'markdown' },
|
|
310
316
|
{ label: 'List', value: t.list_name ?? 'default', kind: 'code' },
|
|
317
|
+
...(readiness ? [{ label: 'Readiness', value: readiness.state },
|
|
318
|
+
...('reason' in readiness ? [{ label: 'Reason', value: readiness.reason }] : [])] : []),
|
|
311
319
|
...(t.blocked ? [{ label: 'Blocked', value: t.blocked.reason }] : []),
|
|
312
320
|
...(t.template ? [{ label: 'Template', value: `${t.template.name}@${t.template.version}`, kind: 'code' }] : []),
|
|
313
321
|
...(t.room_id ? [{ label: 'Room', value: t.room_id, kind: 'code' }] : []),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { redactErasedContent, writePrivacyFilteredLedger } from '../erased-resources.js';
|
|
1
2
|
import { createHash } from 'node:crypto';
|
|
2
3
|
import { chmodSync, existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { replaceFileAtomically } from '../atomic-file.js';
|
|
4
4
|
import { lifecycleEventDigestBasis, validateFleetAuditPresentations, } from '../fleet-command-audit.js';
|
|
5
5
|
const DIGEST = /^[a-f0-9]{64}$/u;
|
|
6
6
|
const LIMIT = 5_000;
|
|
@@ -63,7 +63,7 @@ export class FleetLifecycleOutbox {
|
|
|
63
63
|
}
|
|
64
64
|
pending() {
|
|
65
65
|
this.assertHealthy();
|
|
66
|
-
return this.entries.filter(entry => entry.delivery === 'pending').map(entry => structuredClone(entry));
|
|
66
|
+
return redactErasedContent(this.entries).filter(entry => entry.delivery === 'pending').map(entry => structuredClone(entry));
|
|
67
67
|
}
|
|
68
68
|
finish(digest, delivery) {
|
|
69
69
|
this.assertHealthy();
|
|
@@ -82,6 +82,7 @@ export class FleetLifecycleOutbox {
|
|
|
82
82
|
throw new Error(this.corruptReason);
|
|
83
83
|
}
|
|
84
84
|
persist() {
|
|
85
|
-
|
|
85
|
+
this.entries = redactErasedContent(this.entries);
|
|
86
|
+
writePrivacyFilteredLedger(this.path, { version: 1, entries: this.entries });
|
|
86
87
|
}
|
|
87
88
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { extname
|
|
4
|
-
import { readDaemonConfig, resolveEndpoint } from '../monitor.js';
|
|
3
|
+
import { extname } from 'node:path';
|
|
5
4
|
import { readClientProfile } from '../client-profile.js';
|
|
6
5
|
import { OursError, attachOursClient, } from '@ours.network/sdk/client';
|
|
7
6
|
/** Any failure of a daemon operation. Never carries a message body or a token. */
|
|
@@ -131,24 +130,10 @@ export class OursSdkClient {
|
|
|
131
130
|
return;
|
|
132
131
|
const environment = { ...process.env, ...this.env };
|
|
133
132
|
const profile = readClientProfile(environment);
|
|
134
|
-
|
|
135
|
-
// daemon capability before reading the client's protected token delivery file.
|
|
136
|
-
const endpoint = !profile && environment.OURS_DAEMON_ID
|
|
137
|
-
? resolveEndpoint(environment, false) : undefined;
|
|
138
|
-
const token = endpoint ? environment.OURS_API_TOKEN?.trim() || readDaemonConfig(environment).apiToken : undefined;
|
|
139
|
-
const options = profile ? {
|
|
133
|
+
const options = {
|
|
140
134
|
endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
|
|
141
135
|
credentialPath: profile.credentialPath,
|
|
142
136
|
sessionMode: 'external', leaseToken: this.leaseToken, env: {},
|
|
143
|
-
} : endpoint ? {
|
|
144
|
-
endpoint: endpoint.origin, expectedInstanceId: environment.OURS_DAEMON_ID,
|
|
145
|
-
sessionMode: 'external', leaseToken: this.leaseToken,
|
|
146
|
-
...(token ? { token } : { credentialPath: join(endpoint.stateDir, 'daemon-token') }),
|
|
147
|
-
} : {
|
|
148
|
-
env: environment,
|
|
149
|
-
leaseToken: this.leaseToken,
|
|
150
|
-
clientPid: process.pid,
|
|
151
|
-
fetch: notificationDeadlineFetch(this.deps.fetch ?? globalThis.fetch, this.deps.notificationRequestDeadlineMs ?? NOTIFICATION_REQUEST_DEADLINE_MS),
|
|
152
137
|
};
|
|
153
138
|
this.client = await (this.deps.attachClient?.(options) ?? attachOursClient(options));
|
|
154
139
|
this.terminalReleasePending = true;
|
package/dist/paths.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare const home: () => string;
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function deriveXdgRuntimeDir(env?: NodeJS.ProcessEnv, uid?: number | undefined, exists?: (p: string) => boolean): string | undefined;
|
|
13
13
|
export declare const stateRoot: () => string;
|
|
14
|
+
/** The Owner invitation file that tunnel setup writes itself after enrollment. */
|
|
15
|
+
export declare const workspaceOwnerInvite: () => string;
|
|
14
16
|
export declare const agentsRoot: () => string;
|
|
15
17
|
export declare const tmpRoot: () => string;
|
|
16
18
|
export declare const logsRoot: () => string;
|
package/dist/paths.js
CHANGED
|
@@ -21,6 +21,8 @@ export function deriveXdgRuntimeDir(env = process.env, uid = process.getuid?.(),
|
|
|
21
21
|
return env.XDG_RUNTIME_DIR;
|
|
22
22
|
}
|
|
23
23
|
export const stateRoot = () => join(home(), '.ours-fleet');
|
|
24
|
+
/** The Owner invitation file that tunnel setup writes itself after enrollment. */
|
|
25
|
+
export const workspaceOwnerInvite = () => join(stateRoot(), 'workspace', 'owner.invite');
|
|
24
26
|
export const agentsRoot = () => join(stateRoot(), 'agents');
|
|
25
27
|
export const tmpRoot = () => join(stateRoot(), 'tmp');
|
|
26
28
|
export const logsRoot = () => join(stateRoot(), 'logs');
|
package/dist/preset-migration.js
CHANGED
|
@@ -67,10 +67,21 @@ const V5_GENERATED_ROLE_DEFAULT_FINGERPRINTS = Object.freeze({
|
|
|
67
67
|
'agent_templates/Developer.yaml': 'fdd953aab72d042e62780dd273598745aae59521b39edf4876d7676bb7189c83',
|
|
68
68
|
'agent_templates/Critic.yaml': '3e98a28f17876061cfadf984351aa59fdbe19629e514eff52c74546545c64a91',
|
|
69
69
|
});
|
|
70
|
+
// The packaged Coordinator role of revisions 8 and 9 addressed a named owner channel that a
|
|
71
|
+
// fresh installation does not have. Untouched copies adopt the current role; edited ones stay.
|
|
72
|
+
const OWNER_CHANNEL_COORDINATOR_FINGERPRINTS = Object.freeze({
|
|
73
|
+
'roles/Coordinator.yaml': [
|
|
74
|
+
'8c8ad28d9bb9ddf9dba8c5c9c7859f25edd8fa10ebf833e2340124a6e49583ec',
|
|
75
|
+
'f0d8b169ad0a18051b57e5280b93cf01e05faa5c12f4e12bdf89973edf2ef58a',
|
|
76
|
+
],
|
|
77
|
+
});
|
|
70
78
|
const CURRENT_ROLE_DEFAULTS = new Set([
|
|
71
79
|
'roles/Coordinator.yaml', 'roles/LocalCoordinator.yaml', 'roles/Developer.yaml', 'roles/Critic.yaml',
|
|
80
|
+
'roles/Engineer.yaml',
|
|
72
81
|
'agent_templates/LocalCoordinator.yaml', 'agent_templates/Developer.yaml', 'agent_templates/Critic.yaml',
|
|
82
|
+
'agent_templates/Engineer.yaml',
|
|
73
83
|
'room_templates/single.yaml', 'room_templates/pair.yaml', 'room_templates/team.yaml',
|
|
84
|
+
'room_templates/engineering.yaml',
|
|
74
85
|
'agents/FleetCoordinator.yaml',
|
|
75
86
|
]);
|
|
76
87
|
export const legacyStarterMigrationManifest = Object.freeze({
|
|
@@ -193,6 +204,7 @@ export function migratePackagedRoleDefaults(configuration, options = {}, hooks =
|
|
|
193
204
|
...Object.keys(V3_ROLE_DEFAULT_FINGERPRINTS),
|
|
194
205
|
...Object.keys(V4_ROLE_DEFAULT_FINGERPRINTS),
|
|
195
206
|
...Object.keys(V5_ROLE_DEFAULT_FINGERPRINTS),
|
|
207
|
+
...Object.keys(OWNER_CHANNEL_COORDINATOR_FINGERPRINTS),
|
|
196
208
|
]);
|
|
197
209
|
for (const relative of known) {
|
|
198
210
|
const path = join(root, relative);
|
|
@@ -206,6 +218,7 @@ export function migratePackagedRoleDefaults(configuration, options = {}, hooks =
|
|
|
206
218
|
V4_GENERATED_ROLE_DEFAULT_FINGERPRINTS[relative],
|
|
207
219
|
V5_ROLE_DEFAULT_FINGERPRINTS[relative],
|
|
208
220
|
V5_GENERATED_ROLE_DEFAULT_FINGERPRINTS[relative],
|
|
221
|
+
...(OWNER_CHANNEL_COORDINATOR_FINGERPRINTS[relative] ?? []),
|
|
209
222
|
].some(expected => expected !== undefined && actual === expected);
|
|
210
223
|
if (recognized)
|
|
211
224
|
(CURRENT_ROLE_DEFAULTS.has(relative) ? replacements : removals).push(path);
|
|
@@ -258,6 +271,18 @@ export function migratePackagedRoleDefaults(configuration, options = {}, hooks =
|
|
|
258
271
|
unlinkSync(target);
|
|
259
272
|
copyFileSync(join(source, relative), target, constants.COPYFILE_EXCL);
|
|
260
273
|
chmodSync(target, 0o600);
|
|
274
|
+
// New Engineer seats use the existing Developer's selected brain. This
|
|
275
|
+
// preserves wizard/custom provider choices without copying permissions.
|
|
276
|
+
if (relative === 'agent_templates/Engineer.yaml' && classified.additions.includes(path)) {
|
|
277
|
+
const developer = join(root, 'agent_templates/Developer.yaml');
|
|
278
|
+
if (existsSync(developer)) {
|
|
279
|
+
const value = parseFleetDocument(developer, readFileSync(developer, 'utf8'), 'strict').value;
|
|
280
|
+
if (value.brain !== undefined && JSON.stringify(value.brain) !== JSON.stringify({ ref: 'claude-default' })) {
|
|
281
|
+
const bytes = readFileSync(target, 'utf8').replace('brain: { ref: claude-default }', () => `brain: ${JSON.stringify(value.brain)}`);
|
|
282
|
+
writeFileSync(target, bytes, { mode: 0o600 });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
261
286
|
fsyncPath(target);
|
|
262
287
|
}
|
|
263
288
|
for (const kind of ['roles', 'agent_templates', 'room_templates', 'agents'])
|
package/dist/resolved-plan.js
CHANGED
|
@@ -103,6 +103,7 @@ export function resolvedRolePlan(role, manifestDir = dirname(role.sourceFile)) {
|
|
|
103
103
|
isolation: role.isolation ?? null,
|
|
104
104
|
worklog: role.worklog ?? null,
|
|
105
105
|
authProxy: role.auth_proxy ?? null,
|
|
106
|
+
managedCli: role.managed_cli ?? [],
|
|
106
107
|
oversee: role.oversee ?? [],
|
|
107
108
|
harnessOptions: redactSensitive(role.harness_options ?? null),
|
|
108
109
|
env: {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FleetConfig } from '../config.js';
|
|
2
|
+
import { TaskStateError } from './task-state.js';
|
|
3
|
+
import { provisionMembers } from './provision.js';
|
|
4
|
+
import type { CoworkAdapter } from './cowork-adapter.js';
|
|
5
|
+
export declare class MemberAdditionRejected extends TaskStateError {
|
|
6
|
+
readonly accepted = false;
|
|
7
|
+
}
|
|
8
|
+
export interface AddMemberRequest {
|
|
9
|
+
requestId: string;
|
|
10
|
+
slot: string;
|
|
11
|
+
role: string;
|
|
12
|
+
brain: string;
|
|
13
|
+
agentTemplate: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function memberAddition(taskId: string, requestId: string): {
|
|
16
|
+
requestId: string;
|
|
17
|
+
taskId: string;
|
|
18
|
+
roleId: string;
|
|
19
|
+
state: "running" | "succeeded" | "attention" | "failed";
|
|
20
|
+
error?: string;
|
|
21
|
+
} | {
|
|
22
|
+
state: string;
|
|
23
|
+
error: string;
|
|
24
|
+
requestId: string;
|
|
25
|
+
taskId: string;
|
|
26
|
+
roleId: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function requestMemberAddition(input: {
|
|
29
|
+
taskId: string;
|
|
30
|
+
request: AddMemberRequest;
|
|
31
|
+
cfg: FleetConfig;
|
|
32
|
+
cowork: CoworkAdapter;
|
|
33
|
+
configPath?: string;
|
|
34
|
+
binPath: string;
|
|
35
|
+
provision?: typeof provisionMembers;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
requestId: string;
|
|
38
|
+
taskId: string;
|
|
39
|
+
roleId: string;
|
|
40
|
+
state: "running" | "succeeded" | "attention" | "failed";
|
|
41
|
+
error?: string;
|
|
42
|
+
} | {
|
|
43
|
+
state: string;
|
|
44
|
+
error: string;
|
|
45
|
+
requestId: string;
|
|
46
|
+
taskId: string;
|
|
47
|
+
roleId: string;
|
|
48
|
+
}>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
|
|
5
|
+
import { canonicalJson } from '../canonical-json.js';
|
|
6
|
+
import { stateRoot } from '../paths.js';
|
|
7
|
+
import { getTask, TaskStateError } from './task-state.js';
|
|
8
|
+
import { getRoomRecord } from './room-state.js';
|
|
9
|
+
import { prepareExecutionPlan } from './member-overrides.js';
|
|
10
|
+
import { sealTemplateSnapshot } from './templates.js';
|
|
11
|
+
import { provisionMembers } from './provision.js';
|
|
12
|
+
export class MemberAdditionRejected extends TaskStateError {
|
|
13
|
+
accepted = false;
|
|
14
|
+
}
|
|
15
|
+
const running = new Set();
|
|
16
|
+
function pathFor(taskId, requestId) {
|
|
17
|
+
if (!/^[a-z0-9]{10,40}$/.test(taskId) || !/^[a-zA-Z0-9_-]{8,80}$/.test(requestId))
|
|
18
|
+
throw new TaskStateError('Invalid task or request ID');
|
|
19
|
+
return join(stateRoot(), 'member-additions', taskId, requestId + '.json');
|
|
20
|
+
}
|
|
21
|
+
export function memberAddition(taskId, requestId) {
|
|
22
|
+
getTask(taskId);
|
|
23
|
+
const path = pathFor(taskId, requestId);
|
|
24
|
+
if (!existsSync(path))
|
|
25
|
+
throw new TaskStateError('Member request not found');
|
|
26
|
+
const receipt = JSON.parse(readFileSync(path, 'utf8'));
|
|
27
|
+
const { hash, ...view } = receipt;
|
|
28
|
+
return receipt.state === 'running' && !running.has(path) ? { ...view, state: 'attention', error: 'The server stopped observing this launch. Inspect the existing agent before any recovery.' } : view;
|
|
29
|
+
}
|
|
30
|
+
export async function requestMemberAddition(input) {
|
|
31
|
+
const { request: r, taskId } = input;
|
|
32
|
+
if (!r || typeof r.slot !== 'string' || !/^[A-Za-z][A-Za-z0-9_-]{0,31}$/.test(r.slot)
|
|
33
|
+
|| ![r.role, r.brain, r.agentTemplate].every(v => typeof v === 'string' && v.length > 0 && v.length <= 128))
|
|
34
|
+
// No receipt lookup has happened yet: this request ID may already be accepted.
|
|
35
|
+
throw new TaskStateError('Slot, Role, Brain and Agent Template are required');
|
|
36
|
+
const path = pathFor(taskId, r.requestId);
|
|
37
|
+
const hash = createHash('sha256').update(canonicalJson(r)).digest('hex');
|
|
38
|
+
mkdirSync(join(stateRoot(), 'member-additions', taskId), { recursive: true, mode: 0o700 });
|
|
39
|
+
return withFileLock(path + '.lock', async () => {
|
|
40
|
+
if (existsSync(path)) {
|
|
41
|
+
const old = JSON.parse(readFileSync(path, 'utf8'));
|
|
42
|
+
if (old.hash !== hash)
|
|
43
|
+
throw new TaskStateError('Request ID was already used with different settings');
|
|
44
|
+
return memberAddition(taskId, r.requestId);
|
|
45
|
+
}
|
|
46
|
+
const task = getTask(taskId);
|
|
47
|
+
const room = task.room_id && getRoomRecord(task.room_id);
|
|
48
|
+
if (!room || !['active', 'review'].includes(task.state) || task.terminal_intent || room.state !== 'active'
|
|
49
|
+
|| room.task_id !== taskId || room.room_identity_cid !== task.room_identity_cid)
|
|
50
|
+
throw new MemberAdditionRejected('Adding an agent requires an active task room');
|
|
51
|
+
const roleId = `${taskId.slice(0, 8)}-${r.slot}-1`;
|
|
52
|
+
if (room.member_seats.some(s => s.role_name === roleId))
|
|
53
|
+
throw new MemberAdditionRejected('This member slot already exists');
|
|
54
|
+
const plan = (() => {
|
|
55
|
+
try {
|
|
56
|
+
return prepareExecutionPlan({ name: 'additional-member', version: 1, description: 'Additional task participant',
|
|
57
|
+
contract: room.template_snapshot?.contract, members: [{ slot: r.slot, role: r.role, count: 1, agent_template: r.agentTemplate }] }, input.cfg, { [r.slot]: { role: r.role, brain: r.brain } });
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
throw new MemberAdditionRejected(error instanceof Error ? error.message : 'Invalid member configuration');
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
const template = sealTemplateSnapshot(plan.snapshot, input.cfg.agentTemplates ?? {}, plan.launchDefinitions);
|
|
64
|
+
const receipt = { taskId, requestId: r.requestId, roleId, hash, state: 'running' };
|
|
65
|
+
const save = () => replaceFileAtomically(path, JSON.stringify(receipt) + '\n', 0o600);
|
|
66
|
+
save();
|
|
67
|
+
running.add(path);
|
|
68
|
+
void (input.provision ?? provisionMembers)({ cfg: input.cfg, cowork: input.cowork, configPath: input.configPath, binPath: input.binPath,
|
|
69
|
+
taskId, roomId: room.room_id, template, goal: task.title, brief: task.brief, append: true }).then(result => {
|
|
70
|
+
const seat = result.member_seats.find(s => s.role_name === roleId);
|
|
71
|
+
receipt.state = seat?.seat_state === 'active' && getTask(taskId).member_roles.some(m => m.name === roleId) ? 'succeeded' : 'attention';
|
|
72
|
+
if (receipt.state === 'attention')
|
|
73
|
+
receipt.error = 'Admission is not confirmed. Inspect the existing launch; no automatic retry was made.';
|
|
74
|
+
}).catch(() => { receipt.state = 'failed'; receipt.error = 'Member launch failed. Inspect the task and agent logs before recovery.'; })
|
|
75
|
+
.finally(() => { try {
|
|
76
|
+
save();
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
running.delete(path);
|
|
80
|
+
} }).catch(() => { running.delete(path); });
|
|
81
|
+
return memberAddition(taskId, r.requestId);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ArchivedMemberAbsence, RoomMemberSeat } from './types.js';
|
|
2
|
+
/** Revalidate live facts; a persisted timestamp is never cleanup authority. */
|
|
3
|
+
export declare function verifyArchivedAbsence(proof: ArchivedMemberAbsence): Promise<void>;
|
|
4
|
+
/** After the verified archive has been consumed by explicit workspace deletion,
|
|
5
|
+
* still fence replacement live state and a recreated daemon identity on every retry.
|
|
6
|
+
*/
|
|
7
|
+
export declare function verifyArchivedMemberStillAbsent(proof: ArchivedMemberAbsence): Promise<void>;
|
|
8
|
+
export declare function proveArchivedAbsence(seat: RoomMemberSeat): Promise<ArchivedMemberAbsence>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { agentDir } from '../paths.js';
|
|
4
|
+
import { tempArchiveForLaunch, tempArchiveForCreationAction, tempSupervisorLiveness } from '../temp-lifecycle.js';
|
|
5
|
+
import { assertMemberIdentityAbsent } from './close.js';
|
|
6
|
+
/** Revalidate live facts; a persisted timestamp is never cleanup authority. */
|
|
7
|
+
export async function verifyArchivedAbsence(proof) {
|
|
8
|
+
const absent = () => {
|
|
9
|
+
if (existsSync(agentDir(proof.name, true)))
|
|
10
|
+
throw new Error('Archived member has replacement live state');
|
|
11
|
+
};
|
|
12
|
+
absent();
|
|
13
|
+
const archive = tempArchiveForLaunch(proof.name, proof.launch_id);
|
|
14
|
+
const action = tempArchiveForCreationAction(proof.name, proof.action_id);
|
|
15
|
+
if (!archive || archive !== proof.archive_path || action?.path !== archive
|
|
16
|
+
|| action.launchId !== proof.launch_id
|
|
17
|
+
|| readFileSync(join(archive, '.identity'), 'utf8').trim() !== proof.name)
|
|
18
|
+
throw new Error('Archived member absence ownership proof mismatch');
|
|
19
|
+
if (await tempSupervisorLiveness(archive) !== 'stopped')
|
|
20
|
+
throw new Error('Archived member supervisor absence is not proven');
|
|
21
|
+
await verifyArchivedMemberStillAbsent(proof);
|
|
22
|
+
}
|
|
23
|
+
/** After the verified archive has been consumed by explicit workspace deletion,
|
|
24
|
+
* still fence replacement live state and a recreated daemon identity on every retry.
|
|
25
|
+
*/
|
|
26
|
+
export async function verifyArchivedMemberStillAbsent(proof) {
|
|
27
|
+
const absent = () => {
|
|
28
|
+
if (existsSync(agentDir(proof.name, true)))
|
|
29
|
+
throw new Error('Archived member has replacement live state');
|
|
30
|
+
};
|
|
31
|
+
absent();
|
|
32
|
+
await assertMemberIdentityAbsent({
|
|
33
|
+
role_name: proof.name, slot: 'archived', cowork_role: 'archived', seat_state: 'removed',
|
|
34
|
+
});
|
|
35
|
+
absent();
|
|
36
|
+
}
|
|
37
|
+
export async function proveArchivedAbsence(seat) {
|
|
38
|
+
if (seat.identity_cid || seat.retirement?.phase !== 'identity_absent'
|
|
39
|
+
|| !seat.launch?.launch_id || !seat.launch.action_id
|
|
40
|
+
|| seat.launch.launch_id !== seat.retirement.launch_id || !seat.retirement.archive_path)
|
|
41
|
+
throw new Error('Missing exact archived member absence evidence');
|
|
42
|
+
const proof = {
|
|
43
|
+
name: seat.role_name, launch_id: seat.launch.launch_id, action_id: seat.launch.action_id,
|
|
44
|
+
archive_path: seat.retirement.archive_path, checked_at: new Date().toISOString(),
|
|
45
|
+
};
|
|
46
|
+
await verifyArchivedAbsence(proof);
|
|
47
|
+
return proof;
|
|
48
|
+
}
|
package/dist/rooms-tasks/cli.js
CHANGED
|
@@ -75,6 +75,11 @@ async function presentDetachedProvisioningOutcome(outcome) {
|
|
|
75
75
|
function taskRoomPublicFailure(error) {
|
|
76
76
|
const f = error.fields;
|
|
77
77
|
switch (error.code) {
|
|
78
|
+
case 'task_not_ready': return {
|
|
79
|
+
legacy: `task readiness ${f.readiness}: ${f.reason}`, kind: 'state',
|
|
80
|
+
detail: `Task ${f.task} readiness is ${f.readiness}: ${f.reason}${f.member ? ` (${f.member})` : ''}.`,
|
|
81
|
+
action: 'Ask Fleet Coordinator to inspect room and member status and choose supported recovery. Do not blindly relaunch agents or reuse invites.',
|
|
82
|
+
};
|
|
78
83
|
case 'task_confirmation_mismatch': return {
|
|
79
84
|
legacy: 'confirmation ID must match task ID', kind: 'usage',
|
|
80
85
|
detail: 'The two task IDs must match.', action: 'Repeat the same task ID twice.',
|
|
@@ -242,6 +247,8 @@ const taskListMarkdown = (tasks, title = 'Tasks') => renderMarkdownList({
|
|
|
242
247
|
icon: '📋', title, empty: 'No tasks found.',
|
|
243
248
|
records: tasks.map(t => `${taskStatus(t.state)} ${markdownCode(t.task_id)} — ${markdownProse(t.title)}`
|
|
244
249
|
+ ` — List ${markdownCode(t.list_name ?? 'default')}`
|
|
250
|
+
+ (t.deletion?.status === 'pending' ? ' — Deletion pending'
|
|
251
|
+
+ (t.deletion.error ? `: ${markdownProse(t.deletion.error)}` : '') : '')
|
|
245
252
|
+ (t.blocked ? ` — 🚧 Blocked: ${markdownProse(t.blocked.reason)}` : '')),
|
|
246
253
|
});
|
|
247
254
|
const taskActionMarkdown = (title, task, fields = []) => {
|
|
@@ -515,10 +522,10 @@ function taskRoomService(configuration) {
|
|
|
515
522
|
function allTemplates(cfg) {
|
|
516
523
|
return cfg.roomTemplates ?? {};
|
|
517
524
|
}
|
|
518
|
-
function coworkFor(cfg) {
|
|
525
|
+
function coworkFor(cfg, options) {
|
|
519
526
|
if (!cfg.rooms)
|
|
520
527
|
throw new ConfigError('rooms: configuration is required before creating or querying rooms');
|
|
521
|
-
return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config });
|
|
528
|
+
return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config, ...options });
|
|
522
529
|
}
|
|
523
530
|
function resolveRoomTemplate(cfg, name) {
|
|
524
531
|
if (!name)
|
|
@@ -709,6 +716,7 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
709
716
|
.option('--state <state>', 'filter by state (backlog|active|provisioning|review|done|cancelled|failed|all)')
|
|
710
717
|
.option('--list <name>', 'filter by task list')
|
|
711
718
|
.option('--group-by-list', 'group deterministic results by list (JSON)')
|
|
719
|
+
.option('--include-deleting', 'include tasks whose accepted deletion is still pending')
|
|
712
720
|
.option('--json', 'JSON output')
|
|
713
721
|
.action(async (opts) => {
|
|
714
722
|
try {
|
|
@@ -717,7 +725,8 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
717
725
|
stateFilter = opts.state;
|
|
718
726
|
}
|
|
719
727
|
const service = taskRoomService(opts.configuration);
|
|
720
|
-
const filter = { ...(stateFilter ? { state: stateFilter } : {}), ...(opts.list ? { list: opts.list } : {})
|
|
728
|
+
const filter = { ...(stateFilter ? { state: stateFilter } : {}), ...(opts.list ? { list: opts.list } : {}),
|
|
729
|
+
...(opts.includeDeleting ? { includeDeleting: true } : {}) };
|
|
721
730
|
const tasks = service.listTasks(filter);
|
|
722
731
|
if (opts.json) {
|
|
723
732
|
console.log(JSON.stringify(opts.groupByList
|
|
@@ -827,16 +836,19 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
827
836
|
dieTaskRoom(e);
|
|
828
837
|
}
|
|
829
838
|
});
|
|
830
|
-
taskCmd.command('show <id>')
|
|
839
|
+
cOpt(taskCmd.command('show <id>'))
|
|
831
840
|
.description('show task details')
|
|
832
841
|
.option('--json', 'JSON output')
|
|
833
842
|
.action(async (id, opts) => {
|
|
834
843
|
try {
|
|
835
|
-
const service = taskRoomService();
|
|
844
|
+
const service = taskRoomService(opts.configuration);
|
|
836
845
|
const { task: t, orchestration: room } = service.getTask(id);
|
|
846
|
+
const readiness = t.state === 'active' && t.deletion?.status !== 'pending'
|
|
847
|
+
? await service.observeTaskReadiness(id) : undefined;
|
|
837
848
|
if (opts.json) {
|
|
838
849
|
console.log(JSON.stringify({
|
|
839
850
|
schema_version: 1, task: t, orchestration: room ?? null,
|
|
851
|
+
...(readiness ? { readiness } : {}),
|
|
840
852
|
}, null, 2));
|
|
841
853
|
return;
|
|
842
854
|
}
|
|
@@ -846,6 +858,13 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
846
858
|
{ label: 'ID', value: t.task_id, kind: 'code' },
|
|
847
859
|
{ label: 'Title', value: t.title },
|
|
848
860
|
{ label: 'Status', value: taskStatus(t.state), kind: 'markdown' },
|
|
861
|
+
...(t.deletion?.status === 'pending' ? [
|
|
862
|
+
{ label: 'Deletion', value: 'Pending — cleanup is not complete' },
|
|
863
|
+
...(t.deletion.error ? [{ label: 'Cleanup error', value: t.deletion.error }] : []),
|
|
864
|
+
{ label: 'Retry', value: `ours-fleet task delete ${t.task_id} ${t.task_id}`, kind: 'code' },
|
|
865
|
+
] : []),
|
|
866
|
+
...(readiness ? [{ label: 'Readiness', value: readiness.state },
|
|
867
|
+
...('reason' in readiness ? [{ label: 'Reason', value: readiness.reason }] : [])] : []),
|
|
849
868
|
...(t.blocked ? [{ label: 'Blocked', value: t.blocked.reason }] : []),
|
|
850
869
|
...(t.template ? [{ label: 'Template', value: `${t.template.name}@${t.template.version}`, kind: 'code' }] : []),
|
|
851
870
|
...(t.room_id ? [{ label: 'Room', value: t.room_id, kind: 'code' }] : []),
|
|
@@ -872,6 +891,27 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
872
891
|
dieTaskRoom(e);
|
|
873
892
|
}
|
|
874
893
|
});
|
|
894
|
+
cOpt(taskCmd.command('recover-members <id>'))
|
|
895
|
+
.description('resume proven stopped task members in-place; never create identities or replay invites')
|
|
896
|
+
.option('--json', 'JSON output')
|
|
897
|
+
.action(async (id, opts) => {
|
|
898
|
+
try {
|
|
899
|
+
const { recoverTaskMembers } = await import('./recovery.js');
|
|
900
|
+
const task = getTask(id), cfg = loadConfig(opts.configuration);
|
|
901
|
+
const members = await recoverTaskMembers({ taskId: id, binPath: getBinPath(),
|
|
902
|
+
cowork: task.layout ? undefined : createCoworkAdapter({ configPath: cfg.rooms?.cowork?.config }) });
|
|
903
|
+
if (opts.json)
|
|
904
|
+
console.log(JSON.stringify({ schema_version: 1, task_id: id, members }, null, 2));
|
|
905
|
+
else
|
|
906
|
+
for (const member of members)
|
|
907
|
+
console.log(`${member.name}: ${member.status}`);
|
|
908
|
+
}
|
|
909
|
+
catch (e) {
|
|
910
|
+
if (opts.json)
|
|
911
|
+
die(e);
|
|
912
|
+
dieTaskRoom(e);
|
|
913
|
+
}
|
|
914
|
+
});
|
|
875
915
|
cOpt(taskCmd.command('start <id>'))
|
|
876
916
|
.description('idempotently select a plan, provision, and start a task')
|
|
877
917
|
.option('--template <name>', 'room template')
|
|
@@ -1176,6 +1216,26 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
1176
1216
|
dieTaskRoom(e);
|
|
1177
1217
|
}
|
|
1178
1218
|
});
|
|
1219
|
+
cOpt(taskCmd.command('_layout <id> <operation> [room]', { hidden: true }))
|
|
1220
|
+
.description('internal: run an accepted layout room operation (open, close-room, close)')
|
|
1221
|
+
.option('--json', 'JSON output')
|
|
1222
|
+
.option('--operation-id <id>', 'accepted operation ID; status updates apply only while it is current')
|
|
1223
|
+
.action(async (id, operation, room, opts) => {
|
|
1224
|
+
try {
|
|
1225
|
+
if (!['open', 'close-room', 'close'].includes(operation))
|
|
1226
|
+
throw new Error(`unknown layout operation: ${operation}`);
|
|
1227
|
+
const view = await taskRoomService(opts.configuration).runTaskLayoutOperation({
|
|
1228
|
+
actor: { kind: 'internal_worker', surface: 'cli' }, taskId: id,
|
|
1229
|
+
operation: operation, room, operationId: opts.operationId,
|
|
1230
|
+
});
|
|
1231
|
+
console.log(JSON.stringify({ schema_version: 1, layout: view }, null, 2));
|
|
1232
|
+
}
|
|
1233
|
+
catch (e) {
|
|
1234
|
+
if (opts.json)
|
|
1235
|
+
die(e);
|
|
1236
|
+
dieTaskRoom(e);
|
|
1237
|
+
}
|
|
1238
|
+
});
|
|
1179
1239
|
cOpt(taskCmd.command('_settle_delete <id>', { hidden: true }))
|
|
1180
1240
|
.description('internal: settle a previously accepted task deletion')
|
|
1181
1241
|
.option('--json', 'JSON output')
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { retireTaskMemberService } from './task-service-retirement.js';
|
|
1
2
|
import { withFileLock } from '../atomic-file.js';
|
|
2
3
|
import { type TempLifecycleDeps } from '../temp-lifecycle.js';
|
|
3
4
|
import { type CoworkAdapter } from './cowork-adapter.js';
|
|
4
5
|
import type { RoomMemberSeat, RoomOrchestrationRecord } from './types.js';
|
|
6
|
+
export declare const CLOSE_LOCK_STALE_MS: number;
|
|
5
7
|
export declare function roomCloseLockPath(roomId: string): string;
|
|
6
8
|
export interface RoomCloseDeps {
|
|
9
|
+
retireTaskService?: typeof retireTaskMemberService;
|
|
7
10
|
inspectMember?(seat: RoomMemberSeat): Promise<{
|
|
8
11
|
launchId: string;
|
|
9
12
|
}>;
|
|
@@ -20,12 +23,13 @@ export declare function waitForLivenessAbsent(role: string, launchId: string, li
|
|
|
20
23
|
/** Report whether any daemon identity — under any name — carries this exact CID. */
|
|
21
24
|
export declare function identityCidPresent(cid: string): Promise<boolean>;
|
|
22
25
|
export declare function removeExactMemberIdentity(seat: RoomMemberSeat): Promise<void>;
|
|
26
|
+
export declare function assertMemberIdentityAbsent(seat: RoomMemberSeat): Promise<void>;
|
|
23
27
|
/** One forward-only room close saga shared by every Fleet entry point. */
|
|
24
28
|
export declare function acceptManagedRoomClose(roomId: string): Promise<RoomOrchestrationRecord>;
|
|
25
29
|
export declare function recordManagedRoomCloseError(roomId: string, error: string, recoveryHint: string): Promise<RoomOrchestrationRecord>;
|
|
26
30
|
export declare function closeManagedRoom(input: {
|
|
27
31
|
roomId: string;
|
|
28
|
-
cowork: Pick<CoworkAdapter, 'closeRoom'
|
|
32
|
+
cowork: Pick<CoworkAdapter, 'closeRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
29
33
|
deps?: RoomCloseDeps;
|
|
30
34
|
}): Promise<RoomOrchestrationRecord>;
|
|
31
35
|
export interface ManagedRoomDeleteResult {
|
|
@@ -39,6 +43,6 @@ export declare function deleteLegacyClosedRooms(input: {
|
|
|
39
43
|
/** Retire live resources through the existing cursor, then delete retained state. */
|
|
40
44
|
export declare function deleteManagedRoom(input: {
|
|
41
45
|
roomId: string;
|
|
42
|
-
cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'
|
|
46
|
+
cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
43
47
|
deps?: RoomCloseDeps;
|
|
44
48
|
}): Promise<ManagedRoomDeleteResult>;
|