@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,20 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type ReminderStore } from './store.js';
|
|
3
|
+
/**
|
|
4
|
+
* What the agent's managed MCP endpoint needs from its runner. Absent until
|
|
5
|
+
* the runner has bound the store to this exact runtime instance and identity.
|
|
6
|
+
*/
|
|
7
|
+
export interface ReminderToolBackend {
|
|
8
|
+
store: ReminderStore;
|
|
9
|
+
/** Re-arm the dispatcher after a schedule change. */
|
|
10
|
+
changed(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare const REMINDER_TOOL_NAMES: readonly ["fleet_reminder_create", "fleet_reminder_list", "fleet_reminder_update", "fleet_reminder_cancel", "fleet_reminder_inspect", "fleet_reminder_ack"];
|
|
13
|
+
/**
|
|
14
|
+
* Register the self-reminder tools on the agent's own fixed-identity MCP
|
|
15
|
+
* server. No argument names an agent, identity or recipient: the server is the
|
|
16
|
+
* caller's own supervisor, so every operation is implicitly self-scoped.
|
|
17
|
+
*/
|
|
18
|
+
export declare function registerReminderTools(server: McpServer, backend: () => ReminderToolBackend | undefined,
|
|
19
|
+
/** The endpoint's runtime admission; nothing is read or changed unless it admits. */
|
|
20
|
+
admit: () => Promise<() => void>): void;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ReminderError } from './store.js';
|
|
3
|
+
export const REMINDER_TOOL_NAMES = Object.freeze([
|
|
4
|
+
'fleet_reminder_create', 'fleet_reminder_list', 'fleet_reminder_update',
|
|
5
|
+
'fleet_reminder_cancel', 'fleet_reminder_inspect', 'fleet_reminder_ack',
|
|
6
|
+
]);
|
|
7
|
+
const schedule = {
|
|
8
|
+
local_time: z.string().describe('Calendar date and wall-clock time WITHOUT an offset, e.g. "2027-01-20T16:00". Always a real date: resolve "tomorrow" yourself.'),
|
|
9
|
+
time_zone: z.string().describe('IANA zone the time is meant in, e.g. "Europe/London", "America/New_York" or "UTC". Use the zone of the person or task, not a guess.'),
|
|
10
|
+
fold: z.union([z.literal(0), z.literal(1)]).optional().describe('Only for a wall time that occurs twice when clocks go back: 0 = first occurrence, 1 = second.'),
|
|
11
|
+
late_window_seconds: z.number().int().optional().describe('How late the wake may still be delivered if this agent or the host was offline or busy at the due time (60..604800, default 3600). After it the reminder expires without a wake.'),
|
|
12
|
+
interrupt: z.boolean().optional().describe('Default false: the wake waits until you are idle. true only for a return that is genuinely time-bound: '
|
|
13
|
+
+ 'when due and you are busy with interruptible work, Fleet asks your current turn to stop (session and context are kept) and wakes you with this reminder instead of waiting. '
|
|
14
|
+
+ 'At most one interruption per reminder revision. It never pre-empts owner requests, the owner console, startup, a pending permission, queued work or another reminder; '
|
|
15
|
+
+ 'then it waits like an ordinary reminder. Not a hard real-time alarm: no wake while the host or agent is down, and model start-up still takes time.'),
|
|
16
|
+
};
|
|
17
|
+
function result(value) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
|
|
20
|
+
structuredContent: value,
|
|
21
|
+
isError: false,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function failure(code, message) {
|
|
25
|
+
const value = { error: code, message };
|
|
26
|
+
return { content: [{ type: 'text', text: JSON.stringify(value) }], isError: true };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register the self-reminder tools on the agent's own fixed-identity MCP
|
|
30
|
+
* server. No argument names an agent, identity or recipient: the server is the
|
|
31
|
+
* caller's own supervisor, so every operation is implicitly self-scoped.
|
|
32
|
+
*/
|
|
33
|
+
export function registerReminderTools(server, backend,
|
|
34
|
+
/** The endpoint's runtime admission; nothing is read or changed unless it admits. */
|
|
35
|
+
admit) {
|
|
36
|
+
const run = async (operation, mutates) => {
|
|
37
|
+
let release;
|
|
38
|
+
try {
|
|
39
|
+
release = await admit();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return failure('runtime_not_ready', 'the managed runtime is not admitting tool calls right now; nothing was read or changed');
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const target = backend();
|
|
46
|
+
if (!target)
|
|
47
|
+
return failure('reminders_unavailable', 'self-reminders are not available in this session (the supervisor has not bound them, or this session cannot take scheduled prompts)');
|
|
48
|
+
try {
|
|
49
|
+
const value = operation(target);
|
|
50
|
+
if (mutates)
|
|
51
|
+
target.changed();
|
|
52
|
+
return result(value);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof ReminderError)
|
|
56
|
+
return failure(error.code, error.message);
|
|
57
|
+
return failure('reminder_store_failed', 'the reminder could not be recorded; nothing was changed');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
release();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
server.registerTool('fleet_reminder_create', {
|
|
65
|
+
description: 'Schedule a one-time reminder that wakes YOU (this agent) at a future date and time. '
|
|
66
|
+
+ 'It sends nothing to anyone: when due, Fleet starts a turn for you with the reminder, and you decide what to do. '
|
|
67
|
+
+ 'Use it to come back to something later instead of polling or waiting. Repeating a call with the same request_key '
|
|
68
|
+
+ 'and input returns the existing reminder instead of creating another.',
|
|
69
|
+
inputSchema: {
|
|
70
|
+
request_key: z.string().describe('Stable key for this scheduling decision, so a retried call cannot create a duplicate (e.g. "release-check-2027-01-20").'),
|
|
71
|
+
title: z.string().describe('Short label shown in the wake (max 200 characters).'),
|
|
72
|
+
note: z.string().optional().describe('Private context for your future self: what to check and why (max 4000 characters). Returned by inspect, not in the wake text.'),
|
|
73
|
+
...schedule,
|
|
74
|
+
},
|
|
75
|
+
}, async (args) => run(({ store }) => store.create(args.request_key, args), true));
|
|
76
|
+
server.registerTool('fleet_reminder_list', {
|
|
77
|
+
description: 'List your own reminders. state: "open" (default: scheduled or delivered but not acknowledged), "closed", or "all". '
|
|
78
|
+
+ 'Pages with limit (1..100, default 50) and after (the id from the previous page).',
|
|
79
|
+
inputSchema: {
|
|
80
|
+
state: z.enum(['open', 'closed', 'all']).optional(),
|
|
81
|
+
limit: z.number().int().optional(),
|
|
82
|
+
after: z.string().optional(),
|
|
83
|
+
},
|
|
84
|
+
}, async (args) => run(({ store }) => store.list(args), false));
|
|
85
|
+
server.registerTool('fleet_reminder_update', {
|
|
86
|
+
description: 'Change one of your reminders, e.g. to postpone it. Pass the id and the revision you last saw '
|
|
87
|
+
+ '(expected_revision) plus only the fields to change. Any wake already issued for the old revision becomes void.',
|
|
88
|
+
inputSchema: {
|
|
89
|
+
id: z.string(),
|
|
90
|
+
expected_revision: z.number().int(),
|
|
91
|
+
title: z.string().optional(),
|
|
92
|
+
note: z.string().optional(),
|
|
93
|
+
local_time: schedule.local_time.optional(),
|
|
94
|
+
time_zone: schedule.time_zone.optional(),
|
|
95
|
+
fold: schedule.fold,
|
|
96
|
+
late_window_seconds: schedule.late_window_seconds,
|
|
97
|
+
interrupt: schedule.interrupt,
|
|
98
|
+
},
|
|
99
|
+
}, async ({ id, expected_revision, ...changes }) => run(({ store }) => store.update(id, expected_revision, changes), true));
|
|
100
|
+
server.registerTool('fleet_reminder_cancel', {
|
|
101
|
+
description: 'Cancel one of your reminders (id + expected_revision). A wake already waiting for it will not be delivered.',
|
|
102
|
+
inputSchema: { id: z.string(), expected_revision: z.number().int() },
|
|
103
|
+
}, async ({ id, expected_revision }) => run(({ store }) => store.cancel(id, expected_revision), true));
|
|
104
|
+
server.registerTool('fleet_reminder_inspect', {
|
|
105
|
+
description: 'Read the reminder behind a [fleet-reminder] wake, including its note, whether the wake is still current and eligible, '
|
|
106
|
+
+ 'and for an urgent reminder what its interruption request did (interrupt.state).',
|
|
107
|
+
inputSchema: { event_id: z.string() },
|
|
108
|
+
}, async ({ event_id }) => run(({ store }) => store.inspect(event_id), false));
|
|
109
|
+
server.registerTool('fleet_reminder_ack', {
|
|
110
|
+
description: 'Record that you handled a [fleet-reminder] wake (event_id + revision from the wake). '
|
|
111
|
+
+ 'It closes the reminder and sends nothing; it does not claim any external action happened. Safe to repeat.',
|
|
112
|
+
inputSchema: { event_id: z.string(), expected_revision: z.number().int() },
|
|
113
|
+
}, async ({ event_id, expected_revision }) => run(({ store }) => store.ack(event_id, expected_revision), true));
|
|
114
|
+
}
|
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,84 @@
|
|
|
1
|
+
import { publishFleetResourceCommit } from '../application/resource-observer.js';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
|
|
6
|
+
import { canonicalJson } from '../canonical-json.js';
|
|
7
|
+
import { stateRoot } from '../paths.js';
|
|
8
|
+
import { getTask, TaskStateError } from './task-state.js';
|
|
9
|
+
import { getRoomRecord } from './room-state.js';
|
|
10
|
+
import { prepareExecutionPlan } from './member-overrides.js';
|
|
11
|
+
import { sealTemplateSnapshot } from './templates.js';
|
|
12
|
+
import { provisionMembers } from './provision.js';
|
|
13
|
+
export class MemberAdditionRejected extends TaskStateError {
|
|
14
|
+
accepted = false;
|
|
15
|
+
}
|
|
16
|
+
const running = new Set();
|
|
17
|
+
function pathFor(taskId, requestId) {
|
|
18
|
+
if (!/^[a-z0-9]{10,40}$/.test(taskId) || !/^[a-zA-Z0-9_-]{8,80}$/.test(requestId))
|
|
19
|
+
throw new TaskStateError('Invalid task or request ID');
|
|
20
|
+
return join(stateRoot(), 'member-additions', taskId, requestId + '.json');
|
|
21
|
+
}
|
|
22
|
+
export function memberAddition(taskId, requestId) {
|
|
23
|
+
getTask(taskId);
|
|
24
|
+
const path = pathFor(taskId, requestId);
|
|
25
|
+
if (!existsSync(path))
|
|
26
|
+
throw new TaskStateError('Member request not found');
|
|
27
|
+
const receipt = JSON.parse(readFileSync(path, 'utf8'));
|
|
28
|
+
const { hash, ...view } = receipt;
|
|
29
|
+
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;
|
|
30
|
+
}
|
|
31
|
+
export async function requestMemberAddition(input) {
|
|
32
|
+
const { request: r, taskId } = input;
|
|
33
|
+
if (!r || typeof r.slot !== 'string' || !/^[A-Za-z][A-Za-z0-9_-]{0,31}$/.test(r.slot)
|
|
34
|
+
|| ![r.role, r.brain, r.agentTemplate].every(v => typeof v === 'string' && v.length > 0 && v.length <= 128))
|
|
35
|
+
// No receipt lookup has happened yet: this request ID may already be accepted.
|
|
36
|
+
throw new TaskStateError('Slot, Role, Brain and Agent Template are required');
|
|
37
|
+
const path = pathFor(taskId, r.requestId);
|
|
38
|
+
const hash = createHash('sha256').update(canonicalJson(r)).digest('hex');
|
|
39
|
+
mkdirSync(join(stateRoot(), 'member-additions', taskId), { recursive: true, mode: 0o700 });
|
|
40
|
+
return withFileLock(path + '.lock', async () => {
|
|
41
|
+
if (existsSync(path)) {
|
|
42
|
+
const old = JSON.parse(readFileSync(path, 'utf8'));
|
|
43
|
+
if (old.hash !== hash)
|
|
44
|
+
throw new TaskStateError('Request ID was already used with different settings');
|
|
45
|
+
return memberAddition(taskId, r.requestId);
|
|
46
|
+
}
|
|
47
|
+
const task = getTask(taskId);
|
|
48
|
+
const room = task.room_id && getRoomRecord(task.room_id);
|
|
49
|
+
if (!room || !['active', 'review'].includes(task.state) || task.terminal_intent || room.state !== 'active'
|
|
50
|
+
|| room.task_id !== taskId || room.room_identity_cid !== task.room_identity_cid)
|
|
51
|
+
throw new MemberAdditionRejected('Adding an agent requires an active task room');
|
|
52
|
+
const roleId = `${taskId.slice(0, 8)}-${r.slot}-1`;
|
|
53
|
+
if (room.member_seats.some(s => s.role_name === roleId))
|
|
54
|
+
throw new MemberAdditionRejected('This member slot already exists');
|
|
55
|
+
const plan = (() => {
|
|
56
|
+
try {
|
|
57
|
+
return prepareExecutionPlan({ name: 'additional-member', version: 1, description: 'Additional task participant',
|
|
58
|
+
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 } });
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new MemberAdditionRejected(error instanceof Error ? error.message : 'Invalid member configuration');
|
|
62
|
+
}
|
|
63
|
+
})();
|
|
64
|
+
const template = sealTemplateSnapshot(plan.snapshot, input.cfg.agentTemplates ?? {}, plan.launchDefinitions);
|
|
65
|
+
const receipt = { taskId, requestId: r.requestId, roleId, hash, state: 'running' };
|
|
66
|
+
const save = () => { replaceFileAtomically(path, JSON.stringify(receipt) + '\n', 0o600); publishFleetResourceCommit(path); };
|
|
67
|
+
save();
|
|
68
|
+
running.add(path);
|
|
69
|
+
void (input.provision ?? provisionMembers)({ cfg: input.cfg, cowork: input.cowork, configPath: input.configPath, binPath: input.binPath,
|
|
70
|
+
taskId, roomId: room.room_id, template, goal: task.title, brief: task.brief, append: true }).then(result => {
|
|
71
|
+
const seat = result.member_seats.find(s => s.role_name === roleId);
|
|
72
|
+
receipt.state = seat?.seat_state === 'active' && getTask(taskId).member_roles.some(m => m.name === roleId) ? 'succeeded' : 'attention';
|
|
73
|
+
if (receipt.state === 'attention')
|
|
74
|
+
receipt.error = 'Admission is not confirmed. Inspect the existing launch; no automatic retry was made.';
|
|
75
|
+
}).catch(() => { receipt.state = 'failed'; receipt.error = 'Member launch failed. Inspect the task and agent logs before recovery.'; })
|
|
76
|
+
.finally(() => { try {
|
|
77
|
+
save();
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
running.delete(path);
|
|
81
|
+
} }).catch(() => { running.delete(path); });
|
|
82
|
+
return memberAddition(taskId, r.requestId);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { ArchivedMemberAbsence, RoomMemberSeat } from './types.js';
|
|
2
2
|
/** Revalidate live facts; a persisted timestamp is never cleanup authority. */
|
|
3
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>;
|
|
4
8
|
export declare function proveArchivedAbsence(seat: RoomMemberSeat): Promise<ArchivedMemberAbsence>;
|
|
@@ -18,6 +18,17 @@ export async function verifyArchivedAbsence(proof) {
|
|
|
18
18
|
throw new Error('Archived member absence ownership proof mismatch');
|
|
19
19
|
if (await tempSupervisorLiveness(archive) !== 'stopped')
|
|
20
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();
|
|
21
32
|
await assertMemberIdentityAbsent({
|
|
22
33
|
role_name: proof.name, slot: 'archived', cowork_role: 'archived', seat_state: 'removed',
|
|
23
34
|
});
|
package/dist/rooms-tasks/cli.js
CHANGED
|
@@ -45,6 +45,8 @@ import { createCoworkAdapter } from './cowork-adapter.js';
|
|
|
45
45
|
import { markdownCode, markdownProse, renderMarkdownFailure, renderMarkdownList, renderMarkdownResult, roomStatus, taskStatus, } from './markdown.js';
|
|
46
46
|
import { recordTaskProvisioningOutcome, TaskRoomApplicationError, TaskRoomApplicationService, } from '../application/task-room-service.js';
|
|
47
47
|
import { TaskListError } from './task-lists.js';
|
|
48
|
+
import { appendTaskProgress, attachTaskReviewArtifact, detachTaskReviewArtifact, getTaskReview, listTaskProgress, openTaskWorkspaceFile, publicProgressEntry, publicReview, setTaskReviewMarkdown, TaskReviewError, } from './task-review.js';
|
|
49
|
+
import { verifiedFleetCaller } from '../fleet-command-audit.js';
|
|
48
50
|
import { beginFleetAuditCollection, consumeFleetAuditCollection, recordFleetAuditFailure, recordFleetAuditPresentation, recordFleetAuditResource, } from '../fleet-command-audit.js';
|
|
49
51
|
import { renderAgentConfiguration } from '../lifecycle-summary.js';
|
|
50
52
|
import { withFileLock } from '../atomic-file.js';
|
|
@@ -75,6 +77,11 @@ async function presentDetachedProvisioningOutcome(outcome) {
|
|
|
75
77
|
function taskRoomPublicFailure(error) {
|
|
76
78
|
const f = error.fields;
|
|
77
79
|
switch (error.code) {
|
|
80
|
+
case 'task_not_ready': return {
|
|
81
|
+
legacy: `task readiness ${f.readiness}: ${f.reason}`, kind: 'state',
|
|
82
|
+
detail: `Task ${f.task} readiness is ${f.readiness}: ${f.reason}${f.member ? ` (${f.member})` : ''}.`,
|
|
83
|
+
action: 'Ask Fleet Coordinator to inspect room and member status and choose supported recovery. Do not blindly relaunch agents or reuse invites.',
|
|
84
|
+
};
|
|
78
85
|
case 'task_confirmation_mismatch': return {
|
|
79
86
|
legacy: 'confirmation ID must match task ID', kind: 'usage',
|
|
80
87
|
detail: 'The two task IDs must match.', action: 'Repeat the same task ID twice.',
|
|
@@ -130,6 +137,28 @@ function taskRoomPublicFailure(error) {
|
|
|
130
137
|
};
|
|
131
138
|
}
|
|
132
139
|
}
|
|
140
|
+
/** A supervisor-verified managed agent is attributed as itself; otherwise the local operator. */
|
|
141
|
+
function cliContributionAuthor(taskId) {
|
|
142
|
+
const verified = verifiedFleetCaller();
|
|
143
|
+
if (!verified)
|
|
144
|
+
return { kind: 'local_control', surface: 'cli' };
|
|
145
|
+
// The same identity CID the agent's MCP tools use, so retries match across both surfaces.
|
|
146
|
+
const cid = getTask(taskId).member_roles.find(item => item.name === verified.caller)?.identity_cid ?? bridgeIdentityCid(verified.stateDir);
|
|
147
|
+
return { kind: 'agent', role: verified.caller, ...(cid ? { identity_cid: cid } : {}), surface: 'cli' };
|
|
148
|
+
}
|
|
149
|
+
/** The managed runtime CID its supervisor recorded for the agent's MCP bridge, when present. */
|
|
150
|
+
function bridgeIdentityCid(stateDir) {
|
|
151
|
+
try {
|
|
152
|
+
const cid = JSON.parse(readFileSync(join(stateDir, '.ours-bridge', 'descriptor.json'), 'utf8')).cid;
|
|
153
|
+
return typeof cid === 'string' && /^[A-Fa-f0-9]{64}$/.test(cid) ? cid : undefined;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function contributionAuthorLabel(author) {
|
|
160
|
+
return author.kind === 'agent' ? `${author.role} (agent, ${author.surface})` : `local ${author.surface}`;
|
|
161
|
+
}
|
|
133
162
|
function die(e) {
|
|
134
163
|
const msg = e instanceof TaskRoomPublicError
|
|
135
164
|
? taskRoomPublicFailure(e).legacy : e instanceof Error ? e.message : String(e);
|
|
@@ -196,6 +225,19 @@ function dieTaskRoom(e) {
|
|
|
196
225
|
recordFleetAuditFailure({ class: 'validation', effect: 'not_started' });
|
|
197
226
|
process.exit(1);
|
|
198
227
|
}
|
|
228
|
+
if (e instanceof TaskReviewError) {
|
|
229
|
+
const output = renderMarkdownFailure({
|
|
230
|
+
kind: e.code === 'not_found' ? 'not_found' : e.code === 'conflict' || e.code === 'idempotency_conflict' ? 'state' : 'usage',
|
|
231
|
+
subject: 'ours-fleet task progress/review-package',
|
|
232
|
+
detail: e.message,
|
|
233
|
+
action: e.code === 'conflict' ? 'Show the current review package and retry against it.'
|
|
234
|
+
: e.code === 'idempotency_conflict' ? 'Use a new --request-key for different content.'
|
|
235
|
+
: 'Correct the request and retry.',
|
|
236
|
+
});
|
|
237
|
+
process.stderr.write(`${output}\n`);
|
|
238
|
+
recordFleetAuditFailure({ class: 'validation', effect: 'not_started' });
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
199
241
|
if (e instanceof TaskListError) {
|
|
200
242
|
const notFound = e.code === 'list_not_found';
|
|
201
243
|
const conflict = ['duplicate_name', 'reserved_name', 'default_immutable',
|
|
@@ -242,6 +284,8 @@ const taskListMarkdown = (tasks, title = 'Tasks') => renderMarkdownList({
|
|
|
242
284
|
icon: '📋', title, empty: 'No tasks found.',
|
|
243
285
|
records: tasks.map(t => `${taskStatus(t.state)} ${markdownCode(t.task_id)} — ${markdownProse(t.title)}`
|
|
244
286
|
+ ` — List ${markdownCode(t.list_name ?? 'default')}`
|
|
287
|
+
+ (t.deletion?.status === 'pending' ? ' — Deletion pending'
|
|
288
|
+
+ (t.deletion.error ? `: ${markdownProse(t.deletion.error)}` : '') : '')
|
|
245
289
|
+ (t.blocked ? ` — 🚧 Blocked: ${markdownProse(t.blocked.reason)}` : '')),
|
|
246
290
|
});
|
|
247
291
|
const taskActionMarkdown = (title, task, fields = []) => {
|
|
@@ -515,10 +559,10 @@ function taskRoomService(configuration) {
|
|
|
515
559
|
function allTemplates(cfg) {
|
|
516
560
|
return cfg.roomTemplates ?? {};
|
|
517
561
|
}
|
|
518
|
-
function coworkFor(cfg) {
|
|
562
|
+
function coworkFor(cfg, options) {
|
|
519
563
|
if (!cfg.rooms)
|
|
520
564
|
throw new ConfigError('rooms: configuration is required before creating or querying rooms');
|
|
521
|
-
return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config });
|
|
565
|
+
return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config, ...options });
|
|
522
566
|
}
|
|
523
567
|
function resolveRoomTemplate(cfg, name) {
|
|
524
568
|
if (!name)
|
|
@@ -709,6 +753,7 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
709
753
|
.option('--state <state>', 'filter by state (backlog|active|provisioning|review|done|cancelled|failed|all)')
|
|
710
754
|
.option('--list <name>', 'filter by task list')
|
|
711
755
|
.option('--group-by-list', 'group deterministic results by list (JSON)')
|
|
756
|
+
.option('--include-deleting', 'include tasks whose accepted deletion is still pending')
|
|
712
757
|
.option('--json', 'JSON output')
|
|
713
758
|
.action(async (opts) => {
|
|
714
759
|
try {
|
|
@@ -717,7 +762,8 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
717
762
|
stateFilter = opts.state;
|
|
718
763
|
}
|
|
719
764
|
const service = taskRoomService(opts.configuration);
|
|
720
|
-
const filter = { ...(stateFilter ? { state: stateFilter } : {}), ...(opts.list ? { list: opts.list } : {})
|
|
765
|
+
const filter = { ...(stateFilter ? { state: stateFilter } : {}), ...(opts.list ? { list: opts.list } : {}),
|
|
766
|
+
...(opts.includeDeleting ? { includeDeleting: true } : {}) };
|
|
721
767
|
const tasks = service.listTasks(filter);
|
|
722
768
|
if (opts.json) {
|
|
723
769
|
console.log(JSON.stringify(opts.groupByList
|
|
@@ -827,16 +873,19 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
827
873
|
dieTaskRoom(e);
|
|
828
874
|
}
|
|
829
875
|
});
|
|
830
|
-
taskCmd.command('show <id>')
|
|
876
|
+
cOpt(taskCmd.command('show <id>'))
|
|
831
877
|
.description('show task details')
|
|
832
878
|
.option('--json', 'JSON output')
|
|
833
879
|
.action(async (id, opts) => {
|
|
834
880
|
try {
|
|
835
|
-
const service = taskRoomService();
|
|
881
|
+
const service = taskRoomService(opts.configuration);
|
|
836
882
|
const { task: t, orchestration: room } = service.getTask(id);
|
|
883
|
+
const readiness = t.state === 'active' && t.deletion?.status !== 'pending'
|
|
884
|
+
? await service.observeTaskReadiness(id) : undefined;
|
|
837
885
|
if (opts.json) {
|
|
838
886
|
console.log(JSON.stringify({
|
|
839
887
|
schema_version: 1, task: t, orchestration: room ?? null,
|
|
888
|
+
...(readiness ? { readiness } : {}),
|
|
840
889
|
}, null, 2));
|
|
841
890
|
return;
|
|
842
891
|
}
|
|
@@ -846,6 +895,13 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
846
895
|
{ label: 'ID', value: t.task_id, kind: 'code' },
|
|
847
896
|
{ label: 'Title', value: t.title },
|
|
848
897
|
{ label: 'Status', value: taskStatus(t.state), kind: 'markdown' },
|
|
898
|
+
...(t.deletion?.status === 'pending' ? [
|
|
899
|
+
{ label: 'Deletion', value: 'Pending — cleanup is not complete' },
|
|
900
|
+
...(t.deletion.error ? [{ label: 'Cleanup error', value: t.deletion.error }] : []),
|
|
901
|
+
{ label: 'Retry', value: `ours-fleet task delete ${t.task_id} ${t.task_id}`, kind: 'code' },
|
|
902
|
+
] : []),
|
|
903
|
+
...(readiness ? [{ label: 'Readiness', value: readiness.state },
|
|
904
|
+
...('reason' in readiness ? [{ label: 'Reason', value: readiness.reason }] : [])] : []),
|
|
849
905
|
...(t.blocked ? [{ label: 'Blocked', value: t.blocked.reason }] : []),
|
|
850
906
|
...(t.template ? [{ label: 'Template', value: `${t.template.name}@${t.template.version}`, kind: 'code' }] : []),
|
|
851
907
|
...(t.room_id ? [{ label: 'Room', value: t.room_id, kind: 'code' }] : []),
|
|
@@ -872,6 +928,27 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
872
928
|
dieTaskRoom(e);
|
|
873
929
|
}
|
|
874
930
|
});
|
|
931
|
+
cOpt(taskCmd.command('recover-members <id>'))
|
|
932
|
+
.description('resume proven stopped task members in-place; never create identities or replay invites')
|
|
933
|
+
.option('--json', 'JSON output')
|
|
934
|
+
.action(async (id, opts) => {
|
|
935
|
+
try {
|
|
936
|
+
const { recoverTaskMembers } = await import('./recovery.js');
|
|
937
|
+
const task = getTask(id), cfg = loadConfig(opts.configuration);
|
|
938
|
+
const members = await recoverTaskMembers({ taskId: id, binPath: getBinPath(),
|
|
939
|
+
cowork: task.layout ? undefined : createCoworkAdapter({ configPath: cfg.rooms?.cowork?.config }) });
|
|
940
|
+
if (opts.json)
|
|
941
|
+
console.log(JSON.stringify({ schema_version: 1, task_id: id, members }, null, 2));
|
|
942
|
+
else
|
|
943
|
+
for (const member of members)
|
|
944
|
+
console.log(`${member.name}: ${member.status}`);
|
|
945
|
+
}
|
|
946
|
+
catch (e) {
|
|
947
|
+
if (opts.json)
|
|
948
|
+
die(e);
|
|
949
|
+
dieTaskRoom(e);
|
|
950
|
+
}
|
|
951
|
+
});
|
|
875
952
|
cOpt(taskCmd.command('start <id>'))
|
|
876
953
|
.description('idempotently select a plan, provision, and start a task')
|
|
877
954
|
.option('--template <name>', 'room template')
|
|
@@ -988,6 +1065,86 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
988
1065
|
dieTaskRoom(e);
|
|
989
1066
|
}
|
|
990
1067
|
});
|
|
1068
|
+
taskCmd.command('progress <id>')
|
|
1069
|
+
.description('read the task Progress log, or append one significant milestone with --text')
|
|
1070
|
+
.option('--text <text>', 'milestone text to append, kept exactly as written')
|
|
1071
|
+
.option('--text-file <path>', 'milestone text to append, from a file')
|
|
1072
|
+
.option('--request-key <key>', 'retry key: repeating the same key and text returns the original entry')
|
|
1073
|
+
.option('--json', 'JSON output')
|
|
1074
|
+
.action((id, opts) => {
|
|
1075
|
+
try {
|
|
1076
|
+
if (opts.text !== undefined && opts.textFile !== undefined)
|
|
1077
|
+
throw new Error('use --text or --text-file, not both');
|
|
1078
|
+
const text = opts.textFile !== undefined ? readFileSync(opts.textFile, 'utf8') : opts.text;
|
|
1079
|
+
if (text === undefined) {
|
|
1080
|
+
if (opts.requestKey !== undefined)
|
|
1081
|
+
throw new Error('--request-key applies only when appending');
|
|
1082
|
+
const progress = listTaskProgress(id).map(publicProgressEntry);
|
|
1083
|
+
if (opts.json) {
|
|
1084
|
+
console.log(JSON.stringify({ schema_version: 1, task_id: id, progress }, null, 2));
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
console.log(progress.length ? progress.map(entry => `- ${entry.at} — ${contributionAuthorLabel(entry.author)}\n\n${entry.text}\n`).join('\n')
|
|
1088
|
+
: `Task ${id} has no progress entries.`);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
const result = appendTaskProgress(id, { text, requestKey: opts.requestKey, author: cliContributionAuthor(id) });
|
|
1092
|
+
if (opts.json) {
|
|
1093
|
+
console.log(JSON.stringify({ schema_version: 1, task_id: id, entry: publicProgressEntry(result.entry), replayed: result.replayed }, null, 2));
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
console.log(result.replayed ? `Progress entry ${result.entry.id} was already recorded.` : `Progress entry ${result.entry.id} added to task ${id}.`);
|
|
1097
|
+
}
|
|
1098
|
+
catch (e) {
|
|
1099
|
+
if (opts.json)
|
|
1100
|
+
die(e);
|
|
1101
|
+
dieTaskRoom(e);
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
taskCmd.command('review-package <id>')
|
|
1105
|
+
.description('show or prepare the task To review package (Markdown and retained files)')
|
|
1106
|
+
.option('--markdown <text>', 'replace the review Markdown')
|
|
1107
|
+
.option('--markdown-file <path>', 'replace the review Markdown from a file')
|
|
1108
|
+
.option('--attach <path>', 'retain a file from the task workspace in the package (repeatable)', (value, all) => [...all, value], [])
|
|
1109
|
+
.option('--detach <artifact-id>', 'remove a file from the package (repeatable)', (value, all) => [...all, value], [])
|
|
1110
|
+
.option('--request-key <key>', 'retry key for a single --attach: repeating it with the same file returns the original artifact')
|
|
1111
|
+
.option('--json', 'JSON output')
|
|
1112
|
+
.action(async (id, opts) => {
|
|
1113
|
+
try {
|
|
1114
|
+
if (opts.markdown !== undefined && opts.markdownFile !== undefined)
|
|
1115
|
+
throw new Error('use --markdown or --markdown-file, not both');
|
|
1116
|
+
if (opts.requestKey !== undefined && opts.attach.length !== 1)
|
|
1117
|
+
throw new Error('--request-key needs exactly one --attach');
|
|
1118
|
+
const markdown = opts.markdownFile !== undefined ? readFileSync(opts.markdownFile, 'utf8') : opts.markdown;
|
|
1119
|
+
const author = markdown !== undefined || opts.attach.length || opts.detach.length ? cliContributionAuthor(id) : undefined;
|
|
1120
|
+
const attached = [];
|
|
1121
|
+
if (markdown !== undefined)
|
|
1122
|
+
setTaskReviewMarkdown(id, { markdown, expectedMarkdown: getTaskReview(id)?.markdown ?? '', author: author });
|
|
1123
|
+
for (const artifactId of opts.detach)
|
|
1124
|
+
detachTaskReviewArtifact(id, artifactId, { author: author });
|
|
1125
|
+
for (const path of opts.attach) {
|
|
1126
|
+
const source = await openTaskWorkspaceFile(getTask(id), path);
|
|
1127
|
+
attached.push(await attachTaskReviewArtifact(id, { name: source.name, source, author: author, requestKey: opts.requestKey }));
|
|
1128
|
+
}
|
|
1129
|
+
const review = getTaskReview(id);
|
|
1130
|
+
if (opts.json) {
|
|
1131
|
+
console.log(JSON.stringify({ schema_version: 1, task_id: id, review: review ? publicReview(review) : null }, null, 2));
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
if (!review) {
|
|
1135
|
+
console.log(`Task ${id} has no To review package yet.`);
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
const files = review.artifacts.map(artifact => `- \`${artifact.id}\` ${artifact.name} (${artifact.mime}, ${artifact.size} bytes)`).join('\n');
|
|
1139
|
+
console.log(`## To review — task ${id}\n\n${review.markdown || '_No review Markdown yet._'}\n\n### Files\n\n${files || '_No files._'}`
|
|
1140
|
+
+ (attached.some(item => item.replayed) ? '\n\n(The attached file was already recorded.)' : ''));
|
|
1141
|
+
}
|
|
1142
|
+
catch (e) {
|
|
1143
|
+
if (opts.json)
|
|
1144
|
+
die(e);
|
|
1145
|
+
dieTaskRoom(e);
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
991
1148
|
cOpt(taskCmd.command('done <id>'))
|
|
992
1149
|
.description('complete a task')
|
|
993
1150
|
.option('--summary <text>', 'completion summary')
|
|
@@ -1176,6 +1333,26 @@ export function registerTaskCommands(parent, cOpt) {
|
|
|
1176
1333
|
dieTaskRoom(e);
|
|
1177
1334
|
}
|
|
1178
1335
|
});
|
|
1336
|
+
cOpt(taskCmd.command('_layout <id> <operation> [room]', { hidden: true }))
|
|
1337
|
+
.description('internal: run an accepted layout room operation (open, close-room, close)')
|
|
1338
|
+
.option('--json', 'JSON output')
|
|
1339
|
+
.option('--operation-id <id>', 'accepted operation ID; status updates apply only while it is current')
|
|
1340
|
+
.action(async (id, operation, room, opts) => {
|
|
1341
|
+
try {
|
|
1342
|
+
if (!['open', 'close-room', 'close'].includes(operation))
|
|
1343
|
+
throw new Error(`unknown layout operation: ${operation}`);
|
|
1344
|
+
const view = await taskRoomService(opts.configuration).runTaskLayoutOperation({
|
|
1345
|
+
actor: { kind: 'internal_worker', surface: 'cli' }, taskId: id,
|
|
1346
|
+
operation: operation, room, operationId: opts.operationId,
|
|
1347
|
+
});
|
|
1348
|
+
console.log(JSON.stringify({ schema_version: 1, layout: view }, null, 2));
|
|
1349
|
+
}
|
|
1350
|
+
catch (e) {
|
|
1351
|
+
if (opts.json)
|
|
1352
|
+
die(e);
|
|
1353
|
+
dieTaskRoom(e);
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1179
1356
|
cOpt(taskCmd.command('_settle_delete <id>', { hidden: true }))
|
|
1180
1357
|
.description('internal: settle a previously accepted task deletion')
|
|
1181
1358
|
.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
|
}>;
|
|
@@ -26,7 +29,7 @@ export declare function acceptManagedRoomClose(roomId: string): Promise<RoomOrch
|
|
|
26
29
|
export declare function recordManagedRoomCloseError(roomId: string, error: string, recoveryHint: string): Promise<RoomOrchestrationRecord>;
|
|
27
30
|
export declare function closeManagedRoom(input: {
|
|
28
31
|
roomId: string;
|
|
29
|
-
cowork: Pick<CoworkAdapter, 'closeRoom'
|
|
32
|
+
cowork: Pick<CoworkAdapter, 'closeRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
30
33
|
deps?: RoomCloseDeps;
|
|
31
34
|
}): Promise<RoomOrchestrationRecord>;
|
|
32
35
|
export interface ManagedRoomDeleteResult {
|
|
@@ -40,6 +43,6 @@ export declare function deleteLegacyClosedRooms(input: {
|
|
|
40
43
|
/** Retire live resources through the existing cursor, then delete retained state. */
|
|
41
44
|
export declare function deleteManagedRoom(input: {
|
|
42
45
|
roomId: string;
|
|
43
|
-
cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'
|
|
46
|
+
cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
|
|
44
47
|
deps?: RoomCloseDeps;
|
|
45
48
|
}): Promise<ManagedRoomDeleteResult>;
|