@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
package/dist/runner.js
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
|
+
import { readProvenance } from './creation.js';
|
|
2
|
+
import { firstManagedSessionMayStart, managedRecoveryPath, readManagedRecovery, writeManagedRecovery } from './managed-recovery.js';
|
|
3
|
+
import { StartupTelemetry } from './startup-telemetry.js';
|
|
4
|
+
import { managedStartupPrompt, managedTaskPrompt } from './startup-prompt.js';
|
|
5
|
+
import { createLayoutControl } from './rooms-tasks/layout-control.js';
|
|
6
|
+
import { TemporaryChatIdle } from './temp-idle.js';
|
|
7
|
+
import { taskSupervisorMayRun, taskMemberRetirementProof } from './task-supervision.js';
|
|
1
8
|
import { prepareManagedAgent, releaseManagedAgent } from './agent-ours/service.js';
|
|
2
9
|
import { prepareManagedHarness } from './agent-ours/harness.js';
|
|
10
|
+
import { prepareManagedCliLaunch } from './managed-cli.js';
|
|
3
11
|
import { existsSync, readFileSync, writeFileSync, rmSync, mkdirSync, realpathSync } from 'node:fs';
|
|
4
12
|
import { join } from 'node:path';
|
|
5
13
|
import { fileURLToPath } from 'node:url';
|
|
6
14
|
import { randomUUID } from 'node:crypto';
|
|
7
15
|
import { parse } from 'yaml';
|
|
8
16
|
import { agentDir, stateRoot } from './paths.js';
|
|
9
|
-
import { loadConfig, findRole, isolationContextFor,
|
|
17
|
+
import { loadConfig, findRole, isolationContextFor, resolveSnapshotMonitor, resolvePermissions, } from './config.js';
|
|
10
18
|
import { getAdapter } from './harness/registry.js';
|
|
11
19
|
import { createMonitor, probeIdentityPresence, } from './monitor.js';
|
|
12
20
|
import { DaemonGenerationObserver, RoleRecoveryController, probeDaemonGeneration, } from './daemon-recovery.js';
|
|
13
21
|
import { realExec } from './exec.js';
|
|
14
22
|
import { resolveIsolation } from './isolation/policy.js';
|
|
23
|
+
import { pinSubscriptionForLaunch } from './subscriptions/launch.js';
|
|
15
24
|
import { selectIsolationBackend } from './isolation/registry.js';
|
|
16
25
|
import { resourceArgs, cpuControllerDelegated } from './isolation/resources.js';
|
|
17
26
|
import { resolveLaunchRuntime } from './isolation/runtime.js';
|
|
@@ -27,7 +36,7 @@ import { ScheduledLoopManager, } from './loops/manager.js';
|
|
|
27
36
|
import { FLEET_PROXY_CALLER_ENV, FLEET_PROXY_STATE_DIR_ENV, } from './fleet-proxy.js';
|
|
28
37
|
import { effectivePermissionMode } from './permissions.js';
|
|
29
38
|
import { assertModelPinReachesChild, effectiveRoleModel, repinModelEnv } from './model-env.js';
|
|
30
|
-
import { archiveTempState, markTempSupervisorActive, requestedTempStopReason, } from './temp-lifecycle.js';
|
|
39
|
+
import { archiveTempState, markTempSupervisorActive, requestedTempStopReason, readTempSupervisor, } from './temp-lifecycle.js';
|
|
31
40
|
import { FleetCommandAuditStore } from './fleet-command-audit.js';
|
|
32
41
|
export const SUPERVISOR_RECYCLE_REQUIRED = 'OWNER_CHANNEL_SUPERVISOR_RECYCLE_REQUIRED';
|
|
33
42
|
export class SupervisorRecycleRequiredError extends Error {
|
|
@@ -75,12 +84,16 @@ const defaultDeps = () => ({
|
|
|
75
84
|
});
|
|
76
85
|
const MONITOR_OWNER_FILE = '.monitor-owner';
|
|
77
86
|
const OBSOLETE_OURS_AUTOSTART_ENV = 'OURS_AUTOSTART';
|
|
78
|
-
function localFleetAuditor(stateDir, caller, log) {
|
|
87
|
+
export function localFleetAuditor(stateDir, caller, log, session) {
|
|
88
|
+
const bindings = new Map();
|
|
79
89
|
const store = new FleetCommandAuditStore(join(stateDir, '.fleet-command-audit.json'));
|
|
80
90
|
return {
|
|
81
91
|
async begin(requestId, argv) {
|
|
82
92
|
let attempt = store.begin(requestId, caller, argv);
|
|
83
93
|
if (attempt.invocation === 'sending') {
|
|
94
|
+
const binding = session.taskNoticeBinding?.();
|
|
95
|
+
if (binding)
|
|
96
|
+
bindings.set(attempt.correlationId, binding);
|
|
84
97
|
log(`[${caller}] fleet proxy command ${attempt.correlationId} `
|
|
85
98
|
+ `route=${attempt.classification.route} decision=${attempt.classification.decision}`);
|
|
86
99
|
attempt = store.invocation(attempt.correlationId, caller, 'delivered');
|
|
@@ -94,6 +107,19 @@ function localFleetAuditor(stateDir, caller, log) {
|
|
|
94
107
|
...(input.resourceIds ? { resourceIds: input.resourceIds } : {}),
|
|
95
108
|
...(input.presentations ? { presentations: input.presentations } : {}),
|
|
96
109
|
});
|
|
110
|
+
const binding = bindings.get(attempt.correlationId);
|
|
111
|
+
if (binding && attempt.outcome?.class === 'success' && attempt.outcome.effect === 'completed') {
|
|
112
|
+
for (const p of attempt.outcome.presentations ?? [])
|
|
113
|
+
if (p.kind === 'task' && p.operation === 'create') {
|
|
114
|
+
try {
|
|
115
|
+
session.recordTaskCreated?.(binding, { operationId: p.eventId, taskId: p.id, title: p.title ?? p.id, state: p.newState });
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
log(`[${caller}] task-created conversation notice could not be persisted`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
bindings.delete(attempt.correlationId);
|
|
122
|
+
}
|
|
97
123
|
if (attempt.outcome?.delivery === 'sending')
|
|
98
124
|
attempt = store.outcome(attempt.correlationId, caller, 'delivered');
|
|
99
125
|
return attempt;
|
|
@@ -414,7 +440,7 @@ export function loadTempRole(name) {
|
|
|
414
440
|
// Upgrade snapshots written before monitor.mode/interrupt existed. A snapshot
|
|
415
441
|
// with no monitor block keeps the historical native/no-supervisor behavior.
|
|
416
442
|
if (role.monitor)
|
|
417
|
-
role.monitor =
|
|
443
|
+
role.monitor = resolveSnapshotMonitor(role.monitor);
|
|
418
444
|
role.__temp = true;
|
|
419
445
|
return role;
|
|
420
446
|
}
|
|
@@ -427,7 +453,7 @@ export function loadTempRole(name) {
|
|
|
427
453
|
* with "no such role". An empty/missing marker means "use the default", same as
|
|
428
454
|
* no -c was ever given.
|
|
429
455
|
*/
|
|
430
|
-
function resolveConfigPath(dir, explicit) {
|
|
456
|
+
export function resolveConfigPath(dir, explicit) {
|
|
431
457
|
if (explicit)
|
|
432
458
|
return explicit;
|
|
433
459
|
const marker = join(dir, '.config-path');
|
|
@@ -448,6 +474,8 @@ export function isRecoverableTempStartupCancellation(temp, result) {
|
|
|
448
474
|
/** One session lifecycle. `runSupervised` (or a one-shot caller) drives it. */
|
|
449
475
|
export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
450
476
|
const deps = { ...defaultDeps(), ...partialDeps };
|
|
477
|
+
const startupTelemetry = new StartupTelemetry(deps.now, line => deps.log(`[${name}] ${line}`));
|
|
478
|
+
startupTelemetry.mark('supervisor_started');
|
|
451
479
|
const temp = opts.temp === true;
|
|
452
480
|
const dir = agentDir(name, temp);
|
|
453
481
|
const configPath = temp ? opts.configPath : resolveConfigPath(dir, opts.configPath);
|
|
@@ -486,14 +514,43 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
486
514
|
deps.log(`[${name}] worklog rotation deferred: concurrent modification detected`);
|
|
487
515
|
else if (rotation.rotated)
|
|
488
516
|
deps.log(`[${name}] worklog rotated: ${rotation.beforeBytes} -> ${rotation.afterBytes} bytes`);
|
|
517
|
+
const durableTask = Boolean(readTempSupervisor(dir)?.taskOwner);
|
|
518
|
+
const retainedManaged = durableTask || Boolean(deps.suspendOnStop && adapter.supportsResume);
|
|
489
519
|
const sidFile = join(dir, '.session-id');
|
|
520
|
+
const backendSidFile = join(dir, role.session === 'codex-app-server' ? '.session-id' : '.acp-session-id');
|
|
521
|
+
let recovery = retainedManaged ? readManagedRecovery(dir) : undefined;
|
|
522
|
+
// Native Codex shares .session-id with the runner's pre-launch UUID, so file
|
|
523
|
+
// existence alone is not evidence that its first backend thread was created.
|
|
524
|
+
const firstSessionRetry = retainedManaged && existsSync(join(dir, '.booted'))
|
|
525
|
+
&& (!existsSync(backendSidFile) || (role.session === 'codex-app-server' && recovery?.session === 'pending'))
|
|
526
|
+
&& firstManagedSessionMayStart(dir);
|
|
527
|
+
if (retainedManaged && existsSync(join(dir, '.booted'))
|
|
528
|
+
&& (!existsSync(sidFile) || !existsSync(backendSidFile)) && !firstSessionRetry)
|
|
529
|
+
throw Error('TASK_CONTEXT_RESUME_UNAVAILABLE');
|
|
490
530
|
if (!existsSync(sidFile))
|
|
491
531
|
writeFileSync(sidFile, randomUUID() + '\n');
|
|
492
532
|
const sessionId = readFileSync(sidFile, 'utf8').trim();
|
|
493
533
|
const bootedFile = join(dir, '.booted');
|
|
494
534
|
const exitFile = join(dir, '.exit-status');
|
|
495
535
|
const booted = existsSync(bootedFile);
|
|
496
|
-
|
|
536
|
+
if (durableTask && !adapter.supportsResume)
|
|
537
|
+
throw Error('TASK_HARNESS_RESUME_UNSUPPORTED');
|
|
538
|
+
const mode = booted && adapter.supportsResume && !firstSessionRetry ? 'resume' : 'fresh';
|
|
539
|
+
const requireResume = retainedManaged && mode === 'resume';
|
|
540
|
+
if (retainedManaged && !recovery) {
|
|
541
|
+
// Older admitted sessions have no cursor. Continue once, without replaying
|
|
542
|
+
// their assignment; fresh sessions record intent before the first attempt.
|
|
543
|
+
recovery = { version: 1, session: booted ? 'established' : 'pending', readiness: booted,
|
|
544
|
+
initial: booted ? 'dispatching' : 'pending', active: booted };
|
|
545
|
+
writeManagedRecovery(dir, recovery);
|
|
546
|
+
}
|
|
547
|
+
const recoveryBefore = recovery ? { ...recovery } : undefined;
|
|
548
|
+
const saveRecovery = (update) => {
|
|
549
|
+
if (!recovery)
|
|
550
|
+
return;
|
|
551
|
+
recovery = { ...recovery, ...update };
|
|
552
|
+
writeManagedRecovery(dir, recovery);
|
|
553
|
+
};
|
|
497
554
|
// Stamp EVERY attempt, not just the first. `.booted` used to be written only
|
|
498
555
|
// on the fresh path, so after a restart — including one the supervisor never
|
|
499
556
|
// saw, like an OOM-kill — its mtime still read the original boot and any
|
|
@@ -502,10 +559,22 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
502
559
|
writeFileSync(bootedFile, `${new Date(deps.now()).toISOString()} ${mode}\n`);
|
|
503
560
|
const runCwd = role.cwd && existsSync(role.cwd) ? role.cwd : dir;
|
|
504
561
|
role = { ...role, monitor: { ...role.monitor, mode: 'fleet' } };
|
|
505
|
-
|
|
562
|
+
// Native policy for Fleet commands run from the harness command sandbox. This
|
|
563
|
+
// is the same step for configured, spawned and task-room agents alike.
|
|
564
|
+
const prep = prepareManagedCliLaunch(role, {
|
|
565
|
+
// A temporary agent has no config path threaded through its detached
|
|
566
|
+
// supervisor; spawn records the one it was created from beside its snapshot.
|
|
567
|
+
stateDir: dir, runCwd, configPath: configPath ?? resolveConfigPath(dir), temp,
|
|
568
|
+
prep: await adapter.prepareSession(role, { stateDir: dir, runCwd }), log: deps.log,
|
|
569
|
+
});
|
|
506
570
|
const sessionBackend = role.session ?? 'acp';
|
|
507
571
|
const sessionLabel = sessionBackend === 'acp' ? 'ACP' : 'Codex app-server';
|
|
508
572
|
let launch = adapter.agentSession.prepareLaunch(role, prep);
|
|
573
|
+
// Resolve the fleet-wide active subscription profile once, now: a later switch
|
|
574
|
+
// never changes this session (the operator restarts agents to move them).
|
|
575
|
+
const subscription = pinSubscriptionForLaunch(role, dir);
|
|
576
|
+
if (subscription?.pin.home)
|
|
577
|
+
deps.log(`[${name}] subscription: ${subscription.pin.provider} profile ${subscription.pin.profileId}`);
|
|
509
578
|
// Preserve the role's existing isolation policy.
|
|
510
579
|
let wrappedArgv = launch.argv;
|
|
511
580
|
if (role.isolation) {
|
|
@@ -516,6 +585,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
516
585
|
launch = { ...launch, argv: runtime.argv };
|
|
517
586
|
const ctx = {
|
|
518
587
|
...isolationContextFor(role), stateDir: dir, runCwd,
|
|
588
|
+
subscriptionHome: subscription?.writablePath,
|
|
519
589
|
runtimeReadPaths: [...runtime.readPaths, ...resolveLaunchRuntime([process.execPath, fileURLToPath(new URL('./agent-ours/bridge.js', import.meta.url))]).readPaths],
|
|
520
590
|
};
|
|
521
591
|
const policy = resolveIsolation(role.isolation, ctx);
|
|
@@ -538,9 +608,12 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
538
608
|
if (rprefix.length)
|
|
539
609
|
wrappedArgv = [...rprefix, ...wrappedArgv];
|
|
540
610
|
}
|
|
611
|
+
startupTelemetry.mark('identity_prepare_started');
|
|
541
612
|
const managedService = await deps.prepareAgentOurs(role, dir, opts.identityLifetime ? opts.identityLifetime === 'temporary' : temp);
|
|
613
|
+
startupTelemetry.mark('identity_ready');
|
|
614
|
+
let layoutRetiring = false;
|
|
542
615
|
try {
|
|
543
|
-
const managedHarness = prepareManagedHarness(role, dir, runCwd, managedService.descriptor, harnessChildEnv(role, launch.env, dir));
|
|
616
|
+
const managedHarness = prepareManagedHarness(role, dir, runCwd, managedService.descriptor, { ...harnessChildEnv(role, launch.env, dir), ...subscription?.env });
|
|
544
617
|
// Start-stagger: space this launch at least start_stagger_ms after the previous
|
|
545
618
|
// agent launch across the whole host, so a burst of boots (systemd starts every
|
|
546
619
|
// user unit concurrently on boot; `ours-fleet up`/restart-all bulk-start) does not
|
|
@@ -556,10 +629,9 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
556
629
|
}
|
|
557
630
|
}
|
|
558
631
|
// Prime the supervisor mail monitor's notification cursor at the
|
|
559
|
-
// stream tip BEFORE the session launches so no arrival is missed during boot
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
// treated as native (monitor may be undefined on an old role.yaml).
|
|
632
|
+
// stream tip BEFORE the session launches so no arrival is missed during boot.
|
|
633
|
+
// Monitor.run checks the body-free initial unread summary after readiness;
|
|
634
|
+
// managed native hooks do not own backlog delivery.
|
|
563
635
|
let sessionHandle;
|
|
564
636
|
let modelRecovery;
|
|
565
637
|
const resolvedMonitorDeps = monitorDeps(deps, role.env);
|
|
@@ -599,6 +671,16 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
599
671
|
let unsubscribeRecovery;
|
|
600
672
|
let monitorLoop;
|
|
601
673
|
let sessionStartupComplete = false;
|
|
674
|
+
let startupRecoveryAllowed = false;
|
|
675
|
+
let successfulTurnObserved = false;
|
|
676
|
+
let monitorMayStart = false;
|
|
677
|
+
let monitorStarted = false;
|
|
678
|
+
const startMonitorAfterStartup = () => {
|
|
679
|
+
if (!monitorStarted && monitorMayStart && sessionStartupComplete && !deps.shouldStop?.()) {
|
|
680
|
+
monitorStarted = true;
|
|
681
|
+
monitorLoop = monitor?.run(pid);
|
|
682
|
+
}
|
|
683
|
+
};
|
|
602
684
|
let sessionClosed = false;
|
|
603
685
|
let ownerChannel;
|
|
604
686
|
let ownerBinder;
|
|
@@ -617,23 +699,56 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
617
699
|
if (perms.unattended === 'deny')
|
|
618
700
|
deps.log(`[${name}] permission policy: unattended=deny — with no console attached, ` +
|
|
619
701
|
`permission requests are automatically denied once each (reject_once) and the turn continues`);
|
|
702
|
+
startupTelemetry.mark('harness_starting');
|
|
620
703
|
agentSession = await managedService.runtime.startHarness(() => deps.startAgentSession(adapter.agentSession, {
|
|
621
704
|
managedOurs: managedHarness.ours,
|
|
622
705
|
role, prep,
|
|
623
706
|
launch: { ...launch, argv: wrappedArgv, env: managedHarness.env },
|
|
624
|
-
cwd: runCwd, stateDir: dir, mode, permissions: perms,
|
|
707
|
+
cwd: runCwd, stateDir: dir, mode, requireResume, permissions: perms,
|
|
625
708
|
permissionMode: effectivePermissionMode(role), log: deps.log,
|
|
626
709
|
}));
|
|
710
|
+
managedService.setFileDelivery?.(agentSession.sendFileToChat?.bind(agentSession));
|
|
711
|
+
startupTelemetry.mark('harness_ready');
|
|
712
|
+
saveRecovery({ session: 'established' });
|
|
627
713
|
pid = agentSession.pid;
|
|
628
714
|
arbiter = new RoleTurnArbiter(agentSession);
|
|
629
715
|
sessionHandle = arbiter;
|
|
630
|
-
|
|
716
|
+
const unsubscribeFailure = agentSession.subscribe(event => {
|
|
631
717
|
if (event.kind !== 'error' || !event.text || event.origin?.kind === 'stall-watchdog')
|
|
632
718
|
return;
|
|
633
719
|
const evidence = classifyFailureText(event.text, sessionBackend, new Date(deps.now()).toISOString());
|
|
634
720
|
if (evidence)
|
|
635
721
|
resolvedMonitorDeps.onFailureEvidence?.(evidence);
|
|
636
722
|
});
|
|
723
|
+
const unsubscribeTelemetry = agentSession.subscribeConversation?.(event => startupTelemetry.observe(event));
|
|
724
|
+
const unsubscribeStartup = agentSession.subscribeConversation?.(event => {
|
|
725
|
+
if (event.kind !== 'turn.completed' || !('outcome' in event.payload) || event.payload.outcome !== 'completed')
|
|
726
|
+
return;
|
|
727
|
+
successfulTurnObserved = true;
|
|
728
|
+
if (startupRecoveryAllowed) {
|
|
729
|
+
sessionStartupComplete = true;
|
|
730
|
+
startMonitorAfterStartup();
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
const activePrompts = new Set();
|
|
734
|
+
const unsubscribeContinuity = agentSession.subscribeConversation?.(event => {
|
|
735
|
+
if (!recovery?.readiness)
|
|
736
|
+
return;
|
|
737
|
+
if (event.kind === 'prompt.started') {
|
|
738
|
+
if (event.promptId)
|
|
739
|
+
activePrompts.add(event.promptId);
|
|
740
|
+
saveRecovery({ active: true });
|
|
741
|
+
}
|
|
742
|
+
else if (event.kind === 'turn.completed' && 'outcome' in event.payload) {
|
|
743
|
+
if (event.promptId)
|
|
744
|
+
activePrompts.delete(event.promptId);
|
|
745
|
+
// A shutdown/failed turn needs continuation; a successful terminal turn
|
|
746
|
+
// proves it may stay idle. Never store prompt bodies in this cursor.
|
|
747
|
+
if (event.payload.outcome === 'completed')
|
|
748
|
+
saveRecovery({ active: activePrompts.size > 0 });
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
unsubscribeRecovery = () => { unsubscribeFailure(); unsubscribeStartup?.(); unsubscribeTelemetry?.(); unsubscribeContinuity?.(); };
|
|
637
752
|
if (role.owner_channel) {
|
|
638
753
|
try {
|
|
639
754
|
ownerBinder = await deps.acquireOwnerBinder(dir, name, role.owner_channel.identity);
|
|
@@ -670,11 +785,18 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
670
785
|
...(configPath ? { configPath } : {}),
|
|
671
786
|
});
|
|
672
787
|
control = deps.createControlServer(dir, arbiter, deps.log);
|
|
788
|
+
control.setCorrespondence?.({ contacts: () => managedService.runtime.readContacts(), history: query => managedService.runtime.readHistory(query) });
|
|
673
789
|
control.setFleetAuditor(ownerChannel ? {
|
|
674
790
|
begin: (requestId, argv) => ownerChannel.beginFleetCommandAudit(requestId, argv),
|
|
675
791
|
finish: input => ownerChannel.finishFleetCommandAudit(input),
|
|
676
792
|
present: presentations => ownerChannel.notifyFleetLifecycle(presentations),
|
|
677
|
-
} : localFleetAuditor(dir, name, deps.log));
|
|
793
|
+
} : localFleetAuditor(dir, name, deps.log, agentSession));
|
|
794
|
+
control.setLayoutControl?.(createLayoutControl({
|
|
795
|
+
agent: name, temporary: temp, standalone: !role.roomMemberStartup,
|
|
796
|
+
runtime: managedService.runtime, session: arbiter,
|
|
797
|
+
stopping: () => Boolean(deps.shouldStop?.()),
|
|
798
|
+
retire: async () => { layoutRetiring = true; await arbiter.close(); },
|
|
799
|
+
}));
|
|
678
800
|
await control.start();
|
|
679
801
|
}
|
|
680
802
|
catch (error) {
|
|
@@ -705,10 +827,8 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
705
827
|
// refusal or a cancellation reached the agent and was not acted on, so
|
|
706
828
|
// the monitor must keep its cursor and try again.
|
|
707
829
|
submit: async (text, options) => {
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
// steer into the live turn instead; after it completes, honor the
|
|
711
|
-
// configured interrupt policy normally.
|
|
830
|
+
// Delivery starts after the protected startup turn succeeds. Honor the
|
|
831
|
+
// configured interrupt policy for subsequent turns.
|
|
712
832
|
const policy = options?.interrupt;
|
|
713
833
|
const interrupt = policy === true && sessionStartupComplete;
|
|
714
834
|
const promptOptions = {
|
|
@@ -716,8 +836,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
716
836
|
...(interrupt ? { interruptSource: 'fleet-monitor' } : {}),
|
|
717
837
|
origin: { kind: 'fleet-monitor' },
|
|
718
838
|
};
|
|
719
|
-
//
|
|
720
|
-
// steer rather than waiting on/cancelling the runner-owned first turn.
|
|
839
|
+
// after_tool waits for a safe boundary in subsequent active turns.
|
|
721
840
|
const result = policy === 'after_tool' && sessionStartupComplete
|
|
722
841
|
? await arbiter.submitPromptAfterTool(text, promptOptions)
|
|
723
842
|
: await arbiter.submitPrompt(text, promptOptions);
|
|
@@ -746,17 +865,20 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
746
865
|
};
|
|
747
866
|
},
|
|
748
867
|
};
|
|
749
|
-
const firstPrompt = mode
|
|
750
|
-
? `Read and follow ${join(dir, 'briefing.md')} now.`
|
|
751
|
-
: `Your supervisor has verified your assigned identity and room readiness. Read ${join(dir, 'WORKLOG.md')} and ${join(dir, 'briefing.md')}, then continue using the available ours tools.`;
|
|
868
|
+
const firstPrompt = managedStartupPrompt(dir, mode, booted);
|
|
752
869
|
// Wait for the first turn's TERMINAL result. An agent that accepts the
|
|
753
870
|
// startup prompt and then refuses it has not started; logging the role as
|
|
754
|
-
// up would hide a role that never
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
//
|
|
759
|
-
|
|
871
|
+
// up would hide a role that never completed its readiness turn.
|
|
872
|
+
const retainedResume = retainedManaged && mode === 'resume' && recoveryBefore?.readiness === true;
|
|
873
|
+
if (!retainedResume)
|
|
874
|
+
startupTelemetry.mark('startup_submitted');
|
|
875
|
+
// The backend already verified the saved conversation. Resuming a managed
|
|
876
|
+
// member admits new wakes/console input without replaying startup or work.
|
|
877
|
+
const starting = retainedResume
|
|
878
|
+
? Promise.resolve({ accepted: false, succeeded: true, outcome: 'completed', detail: 'retained backend resumed; no readiness prompt submitted' })
|
|
879
|
+
: arbiter.submitPrompt(firstPrompt, { origin: { kind: 'startup' } });
|
|
880
|
+
// Keep the early cursor baseline; do not deliver wakes into the protected
|
|
881
|
+
// first turn. Steering can pre-empt startup just like cancellation.
|
|
760
882
|
// Owner traffic and agent replies must be observed during a long first
|
|
761
883
|
// turn. Ordinary owner input steers until startup has proved successful.
|
|
762
884
|
if (ownerChannel) {
|
|
@@ -778,6 +900,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
778
900
|
}
|
|
779
901
|
}
|
|
780
902
|
const started = await starting;
|
|
903
|
+
startupTelemetry.finish();
|
|
781
904
|
// A temporary role's first turn can be the active turn when an ours wake
|
|
782
905
|
// needs immediate attention. A typed console/monitor cancellation ends
|
|
783
906
|
// only that turn: the already-live agent session and any queued wake remain
|
|
@@ -816,7 +939,38 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
816
939
|
else if (interruptedForWake)
|
|
817
940
|
deps.log(`[${name}] ${sessionLabel} startup prompt cancelled by ${started.cancellationSource}; `
|
|
818
941
|
+ 'keeping temporary supervisor alive');
|
|
819
|
-
|
|
942
|
+
startupRecoveryAllowed = interruptedForWake;
|
|
943
|
+
sessionStartupComplete = started.succeeded || (interruptedForWake && successfulTurnObserved);
|
|
944
|
+
if (started.succeeded && !retainedResume)
|
|
945
|
+
startupTelemetry.mark('readiness_turn_completed');
|
|
946
|
+
if (started.succeeded)
|
|
947
|
+
saveRecovery({ readiness: true });
|
|
948
|
+
// Readiness is now complete. Configured work (or retained continuity) is
|
|
949
|
+
// admitted as a distinct turn; its terminal result must not block console
|
|
950
|
+
// readiness, mail delivery, or supervisor liveness. Empty fresh agents wait
|
|
951
|
+
// for authenticated console input or the monitor's unread/arrival wake.
|
|
952
|
+
const configuredWork = Boolean(role.mission?.trim() || role.roomMemberStartup?.task?.trim() || role.briefing_file?.trim());
|
|
953
|
+
const initialPending = retainedManaged && recoveryBefore?.initial === 'pending';
|
|
954
|
+
const interruptedWork = retainedManaged && (recoveryBefore?.active || recoveryBefore?.initial === 'dispatching');
|
|
955
|
+
const workPrompt = retainedManaged
|
|
956
|
+
? initialPending && configuredWork ? managedTaskPrompt(dir, 'fresh', false)
|
|
957
|
+
: interruptedWork ? 'Fleet supervisor restarted. Continue pending work in the restored conversation; do not redo completed steps. '
|
|
958
|
+
+ (recoveryBefore?.initial === 'dispatching' ? `If you have not yet received your assignment, read ${join(dir, 'briefing.md')} once before acting. ` : '')
|
|
959
|
+
+ 'Read the continuation log only as needed to recover your next action. If no work remains, end this turn and wait for a concrete task or supervisor wake.' : undefined
|
|
960
|
+
: configuredWork || booted ? managedTaskPrompt(dir, mode, booted) : undefined;
|
|
961
|
+
if (started.succeeded && !deps.shouldStop?.() && workPrompt) {
|
|
962
|
+
saveRecovery({ initial: 'dispatching', active: true });
|
|
963
|
+
const queued = await arbiter.queuePrompt(workPrompt, {
|
|
964
|
+
origin: { kind: 'startup' },
|
|
965
|
+
});
|
|
966
|
+
void queued.completion.then(result => {
|
|
967
|
+
if (result.succeeded)
|
|
968
|
+
saveRecovery({ initial: 'completed', active: activePrompts.size > 0 });
|
|
969
|
+
deps.log(`[${name}] configured task turn ${result.outcome}`);
|
|
970
|
+
}, () => deps.log(`[${name}] configured task turn failed`));
|
|
971
|
+
}
|
|
972
|
+
else if (started.succeeded && initialPending && !configuredWork)
|
|
973
|
+
saveRecovery({ initial: 'completed' });
|
|
820
974
|
reloadLoopConfig = async () => {
|
|
821
975
|
const nextRole = findRole(loadConfig(configPath), name);
|
|
822
976
|
const definitions = nextRole.loops ?? [];
|
|
@@ -873,9 +1027,10 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
873
1027
|
}
|
|
874
1028
|
}
|
|
875
1029
|
deps.log(`[${name}] up; pid=${pid} cwd=${runCwd} harness=${role.harness} session=${sessionBackend} mode=${mode}`);
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
|
|
1030
|
+
// Keep arrivals behind the early prime() cursor; never re-prime at startup.
|
|
1031
|
+
// Recoverable cancellation preserves the supervisor, not monitor readiness.
|
|
1032
|
+
monitorMayStart = true;
|
|
1033
|
+
startMonitorAfterStartup();
|
|
879
1034
|
recoveryController = new RoleRecoveryController({
|
|
880
1035
|
role: name, identity: role.identity, stateDir: dir, now: deps.now, sleep: deps.sleep,
|
|
881
1036
|
log: deps.log,
|
|
@@ -902,6 +1057,14 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
902
1057
|
}
|
|
903
1058
|
},
|
|
904
1059
|
});
|
|
1060
|
+
let chatIdle;
|
|
1061
|
+
try {
|
|
1062
|
+
if (temp && !role.roomMemberStartup && !readTempSupervisor(dir)?.taskOwner)
|
|
1063
|
+
chatIdle = new TemporaryChatIdle(dir, deps.now());
|
|
1064
|
+
}
|
|
1065
|
+
catch {
|
|
1066
|
+
deps.log(`[${name}] automatic idle closure disabled: activity state is unreadable`);
|
|
1067
|
+
}
|
|
905
1068
|
const start = deps.now();
|
|
906
1069
|
let nextLoopReloadAt = deps.now() + 30_000;
|
|
907
1070
|
let nextIdentityPollAt = deps.now();
|
|
@@ -925,6 +1088,19 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
925
1088
|
void recoveryController.recover(observation.generation).catch(error => deps.log(`[${name}] daemon recovery controller failed: ${error?.name ?? 'Error'}`));
|
|
926
1089
|
}
|
|
927
1090
|
}
|
|
1091
|
+
let idleExpired = false;
|
|
1092
|
+
try {
|
|
1093
|
+
idleExpired = chatIdle?.observe(sessionHandle.snapshot(), sessionHandle.conversationSnapshot?.().queueDepth ?? -1, now) ?? false;
|
|
1094
|
+
}
|
|
1095
|
+
catch {
|
|
1096
|
+
chatIdle = undefined;
|
|
1097
|
+
deps.log(`[${name}] automatic idle closure disabled: activity state could not be saved`);
|
|
1098
|
+
}
|
|
1099
|
+
if (idleExpired && await arbiter.retireIfIdle((snapshot, queue) => chatIdle.observe(snapshot, queue, deps.now()))) {
|
|
1100
|
+
retirementReason = 'idle-timeout';
|
|
1101
|
+
sessionClosed = true;
|
|
1102
|
+
break;
|
|
1103
|
+
}
|
|
928
1104
|
if (deps.shouldStop?.()) {
|
|
929
1105
|
if (temp) {
|
|
930
1106
|
retirementReason = requestedTempStopReason(dir) ?? 'supervisor-signal';
|
|
@@ -936,7 +1112,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
936
1112
|
}
|
|
937
1113
|
if (temp && now >= nextIdentityPollAt) {
|
|
938
1114
|
nextIdentityPollAt = now + TEMP_IDENTITY_POLL_MS;
|
|
939
|
-
const presence = await probeIdentityPresence(role.identity, deps.fetch, resolvedMonitorDeps.env);
|
|
1115
|
+
const presence = await probeIdentityPresence(role.identity, deps.fetch, resolvedMonitorDeps.env, deps.identityProbeDeps);
|
|
940
1116
|
if (presence.state === 'present') {
|
|
941
1117
|
identityObserved = true;
|
|
942
1118
|
identityAbsentSince = undefined;
|
|
@@ -973,6 +1149,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
973
1149
|
}
|
|
974
1150
|
}
|
|
975
1151
|
}
|
|
1152
|
+
monitorMayStart = false;
|
|
976
1153
|
if (loopManager) {
|
|
977
1154
|
control?.setLoopManager(undefined);
|
|
978
1155
|
await loopManager.stop();
|
|
@@ -1018,11 +1195,12 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
1018
1195
|
const rotate = (why) => {
|
|
1019
1196
|
writeFileSync(sidFile, randomUUID() + '\n');
|
|
1020
1197
|
rmSync(bootedFile, { force: true });
|
|
1198
|
+
rmSync(managedRecoveryPath(dir), { force: true });
|
|
1021
1199
|
rotated = true;
|
|
1022
1200
|
deps.log(`[${name}] ${why} -> rotated session-id; next start is FRESH`);
|
|
1023
1201
|
};
|
|
1024
|
-
if (!temp && deps.shouldStop?.())
|
|
1025
|
-
deps.log(`[${name}] supervisor
|
|
1202
|
+
if (readTempSupervisor(dir)?.taskOwner || ((!temp || deps.suspendOnStop) && deps.shouldStop?.()))
|
|
1203
|
+
deps.log(`[${name}] supervisor/context retained -> next start RESUMES context`);
|
|
1026
1204
|
else if (exitRecord.detail.includes(ACP_CANCEL_DEADLINE_EXCEEDED)
|
|
1027
1205
|
|| exitRecord.detail.includes(CODEX_APP_SERVER_CANCEL_DEADLINE_EXCEEDED))
|
|
1028
1206
|
// This is a deliberate adapter reclamation, not evidence that resume state
|
|
@@ -1053,11 +1231,11 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
1053
1231
|
throw new SupervisorRecycleRequiredError();
|
|
1054
1232
|
return {
|
|
1055
1233
|
elapsedSecs: elapsed, exit: exitRecord, rotated, mode, modelRecovery,
|
|
1056
|
-
...(retirementReason ? { retirementReason } : {}),
|
|
1234
|
+
...(layoutRetiring ? { retirementReason: 'operator-stop' } : retirementReason ? { retirementReason } : {}),
|
|
1057
1235
|
};
|
|
1058
1236
|
}
|
|
1059
1237
|
finally {
|
|
1060
|
-
await managedService.close(
|
|
1238
|
+
await managedService.close(layoutRetiring);
|
|
1061
1239
|
}
|
|
1062
1240
|
}
|
|
1063
1241
|
/**
|
|
@@ -1072,11 +1250,13 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
1072
1250
|
*/
|
|
1073
1251
|
export async function runSupervised(name, opts = {}, partialDeps = {}, attempt = runOnce) {
|
|
1074
1252
|
const deps = { ...defaultDeps(), ...partialDeps };
|
|
1075
|
-
const
|
|
1253
|
+
const taskMember = opts.temp === true;
|
|
1254
|
+
const dir = agentDir(name, taskMember);
|
|
1076
1255
|
mkdirSync(dir, { recursive: true });
|
|
1077
1256
|
let stopping = false;
|
|
1078
1257
|
const requestStop = () => { stopping = true; };
|
|
1079
|
-
const shouldStop = () => stopping || (partialDeps.shouldStop?.() ?? false)
|
|
1258
|
+
const shouldStop = () => stopping || (partialDeps.shouldStop?.() ?? false)
|
|
1259
|
+
|| (taskMember && requestedTempStopReason(dir) === 'operator-stop');
|
|
1080
1260
|
deps.shouldStop = shouldStop;
|
|
1081
1261
|
const stamp = () => new Date(deps.now()).toISOString();
|
|
1082
1262
|
// Record how the PREVIOUS supervisor process ended before doing anything
|
|
@@ -1104,10 +1284,12 @@ export async function runSupervised(name, opts = {}, partialDeps = {}, attempt =
|
|
|
1104
1284
|
process.on('SIGINT', requestStop);
|
|
1105
1285
|
try {
|
|
1106
1286
|
while (!shouldStop()) {
|
|
1287
|
+
if (taskMember && !taskSupervisorMayRun(name))
|
|
1288
|
+
break;
|
|
1107
1289
|
let ledger = readRestartLedger(dir);
|
|
1108
1290
|
try {
|
|
1109
1291
|
const configPath = resolveConfigPath(dir, opts.configPath);
|
|
1110
|
-
const role = findRole(loadConfig(configPath), name);
|
|
1292
|
+
const role = taskMember ? loadTempRole(name) : findRole(loadConfig(configPath), name);
|
|
1111
1293
|
reconcileModelRecovery(dir, role, stamp());
|
|
1112
1294
|
if (modelRecoveryHeld(dir)) {
|
|
1113
1295
|
await deps.sleep(HELD_DOWN_POLL_MS);
|
|
@@ -1123,18 +1305,26 @@ export async function runSupervised(name, opts = {}, partialDeps = {}, attempt =
|
|
|
1123
1305
|
await deps.sleep(HELD_DOWN_POLL_MS);
|
|
1124
1306
|
continue;
|
|
1125
1307
|
}
|
|
1308
|
+
if (attempt === runOnce && taskMember) {
|
|
1309
|
+
// Boot-time daemon unavailability must not consume the harness crash budget.
|
|
1310
|
+
const { waitForRoleDaemon } = await import('./startup-readiness.js');
|
|
1311
|
+
await waitForRoleDaemon(name, undefined, {}, true);
|
|
1312
|
+
}
|
|
1313
|
+
if (taskMember && (shouldStop() || !taskSupervisorMayRun(name)))
|
|
1314
|
+
break;
|
|
1126
1315
|
let result;
|
|
1127
1316
|
try {
|
|
1128
1317
|
// Service-manager boot and automatic retry bypass the operator-facing
|
|
1129
1318
|
// up/restart commands. Reconcile again immediately before every real
|
|
1130
1319
|
// permanent harness attempt; the operation is idempotent and releases its
|
|
1131
1320
|
// provisioning lease before the agent or owner channel binds.
|
|
1132
|
-
if (attempt === runOnce) {
|
|
1321
|
+
if (attempt === runOnce && !taskMember) {
|
|
1133
1322
|
const configPath = resolveConfigPath(dir, opts.configPath);
|
|
1134
1323
|
const role = findRole(loadConfig(configPath), name);
|
|
1135
1324
|
await reconcilePermanentRoleIdentities(role, undefined, deps.log);
|
|
1136
1325
|
}
|
|
1137
|
-
result = await attempt(name, { configPath: opts.configPath,
|
|
1326
|
+
result = await attempt(name, { configPath: opts.configPath, ...(taskMember ? { temp: true } : {}),
|
|
1327
|
+
allowResumeRotation: taskMember ? false : !ledger.resumeDiscarded }, deps);
|
|
1138
1328
|
}
|
|
1139
1329
|
catch (e) {
|
|
1140
1330
|
if (e instanceof SupervisorRecycleRequiredError) {
|
|
@@ -1156,7 +1346,7 @@ export async function runSupervised(name, opts = {}, partialDeps = {}, attempt =
|
|
|
1156
1346
|
mode: 'fresh',
|
|
1157
1347
|
};
|
|
1158
1348
|
}
|
|
1159
|
-
if (stopping)
|
|
1349
|
+
if (stopping || (taskMember && (shouldStop() || result.retirementReason)))
|
|
1160
1350
|
break;
|
|
1161
1351
|
// Re-read: the attempt itself may have taken minutes, and an operator may
|
|
1162
1352
|
// have reset the ledger meanwhile.
|
|
@@ -1174,7 +1364,8 @@ export async function runSupervised(name, opts = {}, partialDeps = {}, attempt =
|
|
|
1174
1364
|
await deps.sleep(HELD_DOWN_POLL_MS);
|
|
1175
1365
|
continue;
|
|
1176
1366
|
}
|
|
1177
|
-
const fastFailSecs =
|
|
1367
|
+
const fastFailSecs = taskMember ? getAdapter(loadTempRole(name).harness).exitPolicy.fastFailSecs
|
|
1368
|
+
: fastFailSecsFor(name, opts.configPath);
|
|
1178
1369
|
// The fast-fail boundary starts a recovery episode; it must not also be
|
|
1179
1370
|
// the boundary that declares recovery successful. Otherwise alternating
|
|
1180
1371
|
// 19s and 20s deaths erase one another forever. Require the configured
|
|
@@ -1211,7 +1402,7 @@ export async function runSupervised(name, opts = {}, partialDeps = {}, attempt =
|
|
|
1211
1402
|
next.nextDelayMs = 0;
|
|
1212
1403
|
writeRestartLedger(dir, next);
|
|
1213
1404
|
deps.log(`[${name}] HELD DOWN after ${failures} immediate failures at ${next.openedAt} — ` +
|
|
1214
|
-
`${reason};
|
|
1405
|
+
`${reason}; recover with: ${taskMember ? `ours-fleet task recover-members ${readTempSupervisor(dir).taskOwner.taskId}` : `ours-fleet restart ${name}`}`);
|
|
1215
1406
|
continue;
|
|
1216
1407
|
}
|
|
1217
1408
|
writeRestartLedger(dir, next);
|
|
@@ -1226,7 +1417,7 @@ export async function runSupervised(name, opts = {}, partialDeps = {}, attempt =
|
|
|
1226
1417
|
process.off('SIGINT', requestStop);
|
|
1227
1418
|
// An orderly shutdown clears the marker; an unhandled signal or OOM-kill
|
|
1228
1419
|
// leaves it so the successor can identify an abrupt termination.
|
|
1229
|
-
if (shouldStop())
|
|
1420
|
+
if (!taskMember && shouldStop())
|
|
1230
1421
|
await deps.releaseAgentOurs(findRole(loadConfig(opts.configPath), name));
|
|
1231
1422
|
releaseSupervisorRun(dir);
|
|
1232
1423
|
}
|
|
@@ -1246,8 +1437,58 @@ function fastFailSecsFor(name, configPath) {
|
|
|
1246
1437
|
}
|
|
1247
1438
|
}
|
|
1248
1439
|
/** Temp-agent entrypoint: run once, journal why it ended, then archive its evidence. */
|
|
1440
|
+
/** The parent uses the same adapter-relative sustained-uptime reset boundary. */
|
|
1441
|
+
export function stableSupervisorWindow(name, temp, configPath) {
|
|
1442
|
+
try {
|
|
1443
|
+
const role = temp ? loadTempRole(name) : findRole(loadConfig(configPath), name);
|
|
1444
|
+
return getAdapter(role.harness).exitPolicy.fastFailSecs * RESTART_FAIL_THRESHOLD;
|
|
1445
|
+
}
|
|
1446
|
+
catch {
|
|
1447
|
+
return 20 * RESTART_FAIL_THRESHOLD;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1249
1450
|
export async function runTemp(name, deps = {}, attempt = runOnce) {
|
|
1250
1451
|
const dir = agentDir(name, true);
|
|
1452
|
+
const metadata = readTempSupervisor(dir);
|
|
1453
|
+
// Non-resumable standalone temporaries retain their prior finite lifecycle:
|
|
1454
|
+
// a parent stop retires them rather than promising retained conversation.
|
|
1455
|
+
if (!metadata?.taskOwner && deps.suspendOnStop && !getAdapter(loadTempRole(name).harness).supportsResume)
|
|
1456
|
+
deps = { ...deps, suspendOnStop: false };
|
|
1457
|
+
if (!metadata?.taskOwner) {
|
|
1458
|
+
const role = loadTempRole(name);
|
|
1459
|
+
const provenance = readProvenance(dir);
|
|
1460
|
+
if (role.roomMemberStartup?.task_id
|
|
1461
|
+
|| (name.startsWith('layout-') && provenance?.creationActionId?.startsWith('task-')))
|
|
1462
|
+
throw Error('TASK_SUPERVISOR_OWNER_MISSING');
|
|
1463
|
+
}
|
|
1464
|
+
if (metadata?.taskOwner) {
|
|
1465
|
+
// Serialize the entire process lifetime before metadata/session writes.
|
|
1466
|
+
const lease = await acquireOwnerBinderLease(join(dir, '.task-supervisor'), 'task-supervisor', name);
|
|
1467
|
+
let ownershipVerified = false;
|
|
1468
|
+
try {
|
|
1469
|
+
const mayRun = taskSupervisorMayRun(name);
|
|
1470
|
+
ownershipVerified = true;
|
|
1471
|
+
if (!mayRun)
|
|
1472
|
+
return;
|
|
1473
|
+
await markTempSupervisorActive(dir);
|
|
1474
|
+
await runSupervised(name, { temp: true }, deps, attempt);
|
|
1475
|
+
}
|
|
1476
|
+
finally {
|
|
1477
|
+
try {
|
|
1478
|
+
if (ownershipVerified && requestedTempStopReason(dir)) {
|
|
1479
|
+
// Parent shutdown suspends; an explicit stop retires the exact saved
|
|
1480
|
+
// owner even when no harness attempt ran (for example held circuits).
|
|
1481
|
+
await (deps.releaseAgentOurs ?? releaseManagedAgent)(loadTempRole(name), taskMemberRetirementProof(name));
|
|
1482
|
+
const archived = archiveTempState(name, 'operator-stop', 'retired', 'explicit task member retirement');
|
|
1483
|
+
deps.log?.(`[${name}] task member retired: operator-stop${archived ? `; evidence archived at ${archived}` : ''}`);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
finally {
|
|
1487
|
+
lease.release();
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1251
1492
|
await markTempSupervisorActive(dir);
|
|
1252
1493
|
let signal;
|
|
1253
1494
|
const onTerm = () => { signal = 'SIGTERM'; };
|
|
@@ -1274,7 +1515,8 @@ export async function runTemp(name, deps = {}, attempt = runOnce) {
|
|
|
1274
1515
|
process.off('SIGTERM', onTerm);
|
|
1275
1516
|
process.off('SIGINT', onInt);
|
|
1276
1517
|
// A recycle replaces the supervisor process, not the logical temporary agent.
|
|
1277
|
-
if (!(
|
|
1518
|
+
if (!((signal || deps.shouldStop?.()) && deps.suspendOnStop && !requestedTempStopReason(dir))
|
|
1519
|
+
&& (!(failure instanceof SupervisorRecycleRequiredError) || signal || deps.shouldStop?.())) {
|
|
1278
1520
|
const requested = requestedTempStopReason(dir);
|
|
1279
1521
|
const reason = requested
|
|
1280
1522
|
?? result?.retirementReason
|