@songsid/agend 2.3.4-beta.7 → 2.3.5-alpha.3
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 +2 -0
- package/README.zh-TW.md +2 -0
- package/THIRD_PARTY_NOTICES.md +53 -0
- package/dist/agent-endpoint.d.ts +5 -1
- package/dist/agent-endpoint.js +12 -2
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/auth-api.d.ts +21 -0
- package/dist/auth-api.js +89 -2
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/web-authority.d.ts +12 -2
- package/dist/authority/web-authority.js +25 -4
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/claude-code.d.ts +15 -12
- package/dist/backend/claude-code.js +152 -133
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-package.d.ts +5 -2
- package/dist/backend/codex-package.js +1 -5
- package/dist/backend/codex-package.js.map +1 -1
- package/dist/backend/codex.d.ts +136 -113
- package/dist/backend/codex.js +1281 -1219
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok-model-cache.d.ts +7 -0
- package/dist/backend/grok-model-cache.js +65 -0
- package/dist/backend/grok-model-cache.js.map +1 -0
- package/dist/backend/grok.d.ts +2 -0
- package/dist/backend/grok.js +22 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/native-pane.d.ts +9 -0
- package/dist/backend/native-pane.js +59 -0
- package/dist/backend/native-pane.js.map +1 -0
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/ipc-bridge.d.ts +2 -0
- package/dist/channel/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +71 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +16 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +67 -5
- package/dist/daemon.js +823 -266
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +15 -3
- package/dist/delivery-consumed-watch.js +23 -1
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.d.ts +5 -0
- package/dist/delivery-outbox.js +32 -4
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +2 -35
- package/dist/delivery-reconciliation.js +2 -156
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -2
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +238 -3
- package/dist/fleet-manager.js +1826 -104
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-windows-runtime.d.ts +92 -0
- package/dist/fleet-windows-runtime.js +380 -0
- package/dist/fleet-windows-runtime.js.map +1 -0
- package/dist/general-binding.d.ts +85 -0
- package/dist/general-binding.js +298 -0
- package/dist/general-binding.js.map +1 -0
- package/dist/general-host-owner.d.ts +8 -0
- package/dist/general-host-owner.js +26 -0
- package/dist/general-host-owner.js.map +1 -0
- package/dist/general-instance.d.ts +7 -0
- package/dist/general-instance.js +20 -3
- package/dist/general-instance.js.map +1 -1
- package/dist/general-role.d.ts +5 -0
- package/dist/general-role.js +26 -0
- package/dist/general-role.js.map +1 -0
- package/dist/instance-config-impact.js +4 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +21 -3
- package/dist/instance-lifecycle.js +378 -162
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +2 -0
- package/dist/instructions.js +6 -0
- package/dist/instructions.js.map +1 -1
- package/dist/local-pane-endpoint.d.ts +46 -0
- package/dist/local-pane-endpoint.js +189 -0
- package/dist/local-pane-endpoint.js.map +1 -0
- package/dist/local-pane-launcher.d.ts +2 -0
- package/dist/local-pane-launcher.js +38 -0
- package/dist/local-pane-launcher.js.map +1 -0
- package/dist/local-pane-stage.ps1 +101 -0
- package/dist/locale.js +85 -0
- package/dist/locale.js.map +1 -1
- package/dist/model-catalog-defaults.d.ts +14 -0
- package/dist/model-catalog-defaults.js +20 -0
- package/dist/model-catalog-defaults.js.map +1 -0
- package/dist/native-agent-admission.d.ts +7 -0
- package/dist/native-agent-admission.js +26 -0
- package/dist/native-agent-admission.js.map +1 -0
- package/dist/native-daemon-client.d.ts +13 -0
- package/dist/native-daemon-client.js +28 -0
- package/dist/native-daemon-client.js.map +1 -0
- package/dist/native-instance-api.d.ts +14 -0
- package/dist/native-instance-api.js +205 -0
- package/dist/native-instance-api.js.map +1 -0
- package/dist/native-instance-input.d.ts +84 -0
- package/dist/native-instance-input.js +54 -0
- package/dist/native-instance-input.js.map +1 -0
- package/dist/native-instance-registry.d.ts +32 -0
- package/dist/native-instance-registry.js +105 -0
- package/dist/native-instance-registry.js.map +1 -0
- package/dist/native-mcp.d.ts +40 -0
- package/dist/native-mcp.js +278 -0
- package/dist/native-mcp.js.map +1 -0
- package/dist/native-model-catalog.d.ts +5 -0
- package/dist/native-model-catalog.js +76 -0
- package/dist/native-model-catalog.js.map +1 -0
- package/dist/native-pane-crash-budget.d.ts +20 -0
- package/dist/native-pane-crash-budget.js +60 -0
- package/dist/native-pane-crash-budget.js.map +1 -0
- package/dist/native-pane-create.d.ts +26 -0
- package/dist/native-pane-create.js +53 -0
- package/dist/native-pane-create.js.map +1 -0
- package/dist/native-pane-lifecycle.d.ts +65 -0
- package/dist/native-pane-lifecycle.js +230 -0
- package/dist/native-pane-lifecycle.js.map +1 -0
- package/dist/native-pane-manager.d.ts +59 -0
- package/dist/native-pane-manager.js +584 -0
- package/dist/native-pane-manager.js.map +1 -0
- package/dist/native-pane-output-log.d.ts +15 -0
- package/dist/native-pane-output-log.js +108 -0
- package/dist/native-pane-output-log.js.map +1 -0
- package/dist/native-pane-reconciliation.d.ts +4 -0
- package/dist/native-pane-reconciliation.js +40 -0
- package/dist/native-pane-reconciliation.js.map +1 -0
- package/dist/native-pane-recovery.d.ts +12 -0
- package/dist/native-pane-recovery.js +10 -0
- package/dist/native-pane-recovery.js.map +1 -0
- package/dist/native-pane-tools.d.ts +2 -0
- package/dist/native-pane-tools.js +14 -0
- package/dist/native-pane-tools.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -0
- package/dist/needs-you-hub.js +2 -1
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +19 -1
- package/dist/needs-you.js +12 -2
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +16 -2
- package/dist/outbound-handlers.js +67 -3
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +38 -0
- package/dist/outbound-schemas.js +12 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-port.d.ts +118 -0
- package/dist/pane-port.js +2 -0
- package/dist/pane-port.js.map +1 -0
- package/dist/public-web-gateway.js +9 -0
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +5 -0
- package/dist/public-web-link.js +4 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.js +9 -5
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +1 -0
- package/dist/quickstart.js +4 -1
- package/dist/quickstart.js.map +1 -1
- package/dist/runtime-api.d.ts +8 -0
- package/dist/runtime-api.js +96 -0
- package/dist/runtime-api.js.map +1 -0
- package/dist/runtime-assets/@xterm/addon-serialize/LICENSE +21 -0
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.js +2 -0
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.mjs +19 -0
- package/dist/runtime-assets/@xterm/addon-serialize/package.json +29 -0
- package/dist/runtime-assets/@xterm/headless/LICENSE +21 -0
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.js +2 -0
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.mjs +46 -0
- package/dist/runtime-assets/@xterm/headless/package.json +29 -0
- package/dist/runtime-assets/node-pty/CONPTY-LICENSE +21 -0
- package/dist/runtime-assets/node-pty/CONPTY-NOTICE.md +503 -0
- package/dist/runtime-assets/node-pty/LICENSE +69 -0
- package/dist/runtime-assets/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/dist/runtime-assets/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/runtime-assets/node-pty/lib/index.js +52 -0
- package/dist/runtime-assets/node-pty/lib/interfaces.js +7 -0
- package/dist/runtime-assets/node-pty/lib/shared/conout.js +11 -0
- package/dist/runtime-assets/node-pty/lib/terminal.js +190 -0
- package/dist/runtime-assets/node-pty/lib/types.js +7 -0
- package/dist/runtime-assets/node-pty/lib/unixTerminal.js +346 -0
- package/dist/runtime-assets/node-pty/lib/utils.js +39 -0
- package/dist/runtime-assets/node-pty/lib/windowsConoutConnection.js +125 -0
- package/dist/runtime-assets/node-pty/lib/windowsPtyAgent.js +320 -0
- package/dist/runtime-assets/node-pty/lib/windowsTerminal.js +199 -0
- package/dist/runtime-assets/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/runtime-assets/node-pty/package.json +64 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/dist/runtime-bundle.d.ts +17 -0
- package/dist/runtime-bundle.js +150 -0
- package/dist/runtime-bundle.js.map +1 -0
- package/dist/runtime-cli.d.ts +2 -0
- package/dist/runtime-cli.js +117 -0
- package/dist/runtime-cli.js.map +1 -0
- package/dist/runtime-client-store.d.ts +49 -0
- package/dist/runtime-client-store.js +292 -0
- package/dist/runtime-client-store.js.map +1 -0
- package/dist/runtime-client.d.ts +100 -0
- package/dist/runtime-client.js +700 -0
- package/dist/runtime-client.js.map +1 -0
- package/dist/runtime-coordinator.d.ts +82 -0
- package/dist/runtime-coordinator.js +864 -0
- package/dist/runtime-coordinator.js.map +1 -0
- package/dist/runtime-general-protocol.d.ts +22 -0
- package/dist/runtime-general-protocol.js +57 -0
- package/dist/runtime-general-protocol.js.map +1 -0
- package/dist/runtime-general-workspace.d.ts +17 -0
- package/dist/runtime-general-workspace.js +213 -0
- package/dist/runtime-general-workspace.js.map +1 -0
- package/dist/runtime-pane-assets.d.ts +17 -0
- package/dist/runtime-pane-assets.js +23 -0
- package/dist/runtime-pane-assets.js.map +1 -0
- package/dist/runtime-pane-boot.d.ts +2 -0
- package/dist/runtime-pane-boot.js +24 -0
- package/dist/runtime-pane-boot.js.map +1 -0
- package/dist/runtime-pane-codex-index.d.ts +1 -0
- package/dist/runtime-pane-codex-index.js +47 -0
- package/dist/runtime-pane-codex-index.js.map +1 -0
- package/dist/runtime-pane-config.d.ts +16 -0
- package/dist/runtime-pane-config.js +54 -0
- package/dist/runtime-pane-config.js.map +1 -0
- package/dist/runtime-pane-host.d.ts +44 -0
- package/dist/runtime-pane-host.js +424 -0
- package/dist/runtime-pane-host.js.map +1 -0
- package/dist/runtime-pane-job-owner.d.ts +1 -0
- package/dist/runtime-pane-job-owner.js +29 -0
- package/dist/runtime-pane-job-owner.js.map +1 -0
- package/dist/runtime-pane-job.ps1 +116 -0
- package/dist/runtime-pane-link.d.ts +40 -0
- package/dist/runtime-pane-link.js +246 -0
- package/dist/runtime-pane-link.js.map +1 -0
- package/dist/runtime-pane-mcp-protocol.d.ts +32 -0
- package/dist/runtime-pane-mcp-protocol.js +39 -0
- package/dist/runtime-pane-mcp-protocol.js.map +1 -0
- package/dist/runtime-pane-mcp-relay.d.ts +17 -0
- package/dist/runtime-pane-mcp-relay.js +70 -0
- package/dist/runtime-pane-mcp-relay.js.map +1 -0
- package/dist/runtime-pane-mcp.d.ts +51 -0
- package/dist/runtime-pane-mcp.js +150 -0
- package/dist/runtime-pane-mcp.js.map +1 -0
- package/dist/runtime-pane-native.d.ts +45 -0
- package/dist/runtime-pane-native.js +65 -0
- package/dist/runtime-pane-native.js.map +1 -0
- package/dist/runtime-pane-output.d.ts +19 -0
- package/dist/runtime-pane-output.js +53 -0
- package/dist/runtime-pane-output.js.map +1 -0
- package/dist/runtime-pane-port.d.ts +139 -0
- package/dist/runtime-pane-port.js +558 -0
- package/dist/runtime-pane-port.js.map +1 -0
- package/dist/runtime-pane-private.d.ts +14 -0
- package/dist/runtime-pane-private.js +51 -0
- package/dist/runtime-pane-private.js.map +1 -0
- package/dist/runtime-pane-private.ps1 +14 -0
- package/dist/runtime-pane-process.d.ts +4 -0
- package/dist/runtime-pane-process.js +108 -0
- package/dist/runtime-pane-process.js.map +1 -0
- package/dist/runtime-pane-protocol.d.ts +172 -0
- package/dist/runtime-pane-protocol.js +195 -0
- package/dist/runtime-pane-protocol.js.map +1 -0
- package/dist/runtime-pane-screen.d.ts +19 -0
- package/dist/runtime-pane-screen.js +76 -0
- package/dist/runtime-pane-screen.js.map +1 -0
- package/dist/runtime-pane-service.d.ts +11 -0
- package/dist/runtime-pane-service.js +221 -0
- package/dist/runtime-pane-service.js.map +1 -0
- package/dist/runtime-pane-stdio-protocol.d.ts +54 -0
- package/dist/runtime-pane-stdio-protocol.js +94 -0
- package/dist/runtime-pane-stdio-protocol.js.map +1 -0
- package/dist/runtime-pane-stdio.d.ts +3 -0
- package/dist/runtime-pane-stdio.js +123 -0
- package/dist/runtime-pane-stdio.js.map +1 -0
- package/dist/runtime-pane-store.d.ts +33 -0
- package/dist/runtime-pane-store.js +164 -0
- package/dist/runtime-pane-store.js.map +1 -0
- package/dist/runtime-pane-transcript-protocol.d.ts +43 -0
- package/dist/runtime-pane-transcript-protocol.js +58 -0
- package/dist/runtime-pane-transcript-protocol.js.map +1 -0
- package/dist/runtime-pane-transcript.d.ts +45 -0
- package/dist/runtime-pane-transcript.js +605 -0
- package/dist/runtime-pane-transcript.js.map +1 -0
- package/dist/runtime-pane-worker.d.ts +1 -0
- package/dist/runtime-pane-worker.js +154 -0
- package/dist/runtime-pane-worker.js.map +1 -0
- package/dist/runtime-protocol.d.ts +149 -0
- package/dist/runtime-protocol.js +19 -0
- package/dist/runtime-protocol.js.map +1 -0
- package/dist/runtime-switches.d.ts +79 -0
- package/dist/runtime-switches.js +90 -0
- package/dist/runtime-switches.js.map +1 -0
- package/dist/runtime-transcript-delta-reader.d.ts +23 -0
- package/dist/runtime-transcript-delta-reader.js +74 -0
- package/dist/runtime-transcript-delta-reader.js.map +1 -0
- package/dist/runtime-transcript-source.d.ts +36 -0
- package/dist/runtime-transcript-source.js +189 -0
- package/dist/runtime-transcript-source.js.map +1 -0
- package/dist/runtime-windows-bridge.d.ts +41 -0
- package/dist/runtime-windows-bridge.js +157 -0
- package/dist/runtime-windows-bridge.js.map +1 -0
- package/dist/settings-api.d.ts +5 -0
- package/dist/settings-api.js +95 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.d.ts +1 -0
- package/dist/settings-baseline.js +1 -1
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.js +28 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +16 -1
- package/dist/settings-confirmation.js +47 -9
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.d.ts +4 -0
- package/dist/settings-effect.js +58 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +1 -0
- package/dist/settings-http-confirmation.js +15 -2
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-request-capability.d.ts +2 -0
- package/dist/settings-request-capability.js +4 -0
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/settings-route-lifetime.d.ts +14 -0
- package/dist/settings-route-lifetime.js +48 -0
- package/dist/settings-route-lifetime.js.map +1 -0
- package/dist/settings-transaction.d.ts +4 -0
- package/dist/settings-transaction.js +9 -0
- package/dist/settings-transaction.js.map +1 -1
- package/dist/setup-form.js +6 -3
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-i18n.js +3 -0
- package/dist/setup-i18n.js.map +1 -1
- package/dist/tmux-control.d.ts +2 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +2 -1
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-pane-host.d.ts +26 -0
- package/dist/tmux-pane-host.js +25 -0
- package/dist/tmux-pane-host.js.map +1 -0
- package/dist/tool-permissions.js +2 -1
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +3 -0
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.d.ts +1 -1
- package/dist/transcript-delta-reader.js +1 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-monitor.d.ts +3 -0
- package/dist/transcript-monitor.js +22 -46
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-needles.d.ts +35 -0
- package/dist/transcript-needles.js +158 -0
- package/dist/transcript-needles.js.map +1 -0
- package/dist/transcript-records.d.ts +21 -0
- package/dist/transcript-records.js +140 -0
- package/dist/transcript-records.js.map +1 -0
- package/dist/transcript-sources.d.ts +5 -0
- package/dist/transcript-sources.js +8 -79
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/ui/agent-proposals.js +90 -0
- package/dist/ui/agent-runtime.js +106 -0
- package/dist/ui/chat-store.js +13 -2
- package/dist/ui/chat-strings.js +48 -0
- package/dist/ui/cli-picker.js +42 -0
- package/dist/ui/general-location.js +71 -0
- package/dist/ui/native-instance-settings.js +47 -0
- package/dist/ui/native-pane-recovery.js +45 -0
- package/dist/ui/panel-chat.js +63 -32
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +99 -18
- package/dist/ui/panel-needs.js +154 -3
- package/dist/ui/panel-runtimes.js +231 -0
- package/dist/ui/panel-settings.js +19 -9
- package/dist/ui/panel-windows-agent.js +86 -0
- package/dist/ui/panel-windows-cli.js +143 -0
- package/dist/ui/provider-marks.js +83 -0
- package/dist/ui/runtime-catalog.js +55 -0
- package/dist/ui/settings-catalog.js +37 -10
- package/dist/ui/settings-confirm.js +3 -1
- package/dist/ui/settings-dialogs.js +22 -7
- package/dist/ui/settings-model.js +2 -1
- package/dist/ui/settings-outside.js +176 -0
- package/dist/ui/settings-registry.js +6 -0
- package/dist/ui/settings-strings.js +16 -0
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-route.js +6 -2
- package/dist/ui/shared/app-shell.js +3 -2
- package/dist/ui/shared/app-store.js +1 -0
- package/dist/ui/shared/app-stream.js +3 -1
- package/dist/ui/shared/app.css +301 -0
- package/dist/ui/shared/app.js +4 -0
- package/dist/ui/shared/header-tools.js +6 -4
- package/dist/ui/shared/instance-nav.js +33 -7
- package/dist/ui/shared/instance-switch.js +4 -3
- package/dist/ui/shared/qrcode.module.js +2237 -0
- package/dist/ui/shared/signin.js +39 -5
- package/dist/ui/shared/ui-menu.js +28 -8
- package/dist/ui/shared/vendor/qrcode-generator.LICENSE +27 -0
- package/dist/ui/shared/vendor/vendor.json +19 -2
- package/dist/ui/shared/view-strings.js +8 -0
- package/dist/ui/windows-agents-nav.js +2 -0
- package/dist/ui/windows-cli-catalog.js +79 -0
- package/dist/web-api.d.ts +37 -0
- package/dist/web-api.js +248 -6
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +19 -2
- package/dist/web-chat-history.js +72 -3
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-only-fleet.d.ts +20 -0
- package/dist/web-only-fleet.js +21 -0
- package/dist/web-only-fleet.js.map +1 -1
- package/dist/web-remote-access.d.ts +152 -0
- package/dist/web-remote-access.js +368 -0
- package/dist/web-remote-access.js.map +1 -0
- package/dist/web-session.d.ts +7 -0
- package/dist/web-session.js +2 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -1
- package/dist/web-shell-routes.js +7 -2
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/windows-agents.d.ts +124 -0
- package/dist/windows-agents.js +487 -0
- package/dist/windows-agents.js.map +1 -0
- package/dist/windows-cli-api.d.ts +23 -0
- package/dist/windows-cli-api.js +158 -0
- package/dist/windows-cli-api.js.map +1 -0
- package/dist/windows-cli-providers.d.ts +115 -0
- package/dist/windows-cli-providers.js +429 -0
- package/dist/windows-cli-providers.js.map +1 -0
- package/dist/windows-cli-worker.d.ts +58 -0
- package/dist/windows-cli-worker.js +479 -0
- package/dist/windows-cli-worker.js.map +1 -0
- package/dist/windows-cli.d.ts +115 -0
- package/dist/windows-cli.js +402 -0
- package/dist/windows-cli.js.map +1 -0
- package/dist/windows-native-mcp.d.ts +19 -0
- package/dist/windows-native-mcp.js +143 -0
- package/dist/windows-native-mcp.js.map +1 -0
- package/dist/windows-pane-mcp.d.ts +26 -0
- package/dist/windows-pane-mcp.js +187 -0
- package/dist/windows-pane-mcp.js.map +1 -0
- package/package.json +9 -3
- package/templates/runtime-assets/conpty-LICENSE +21 -0
- package/templates/runtime-assets/conpty-NOTICE.md +503 -0
- package/templates/runtime-assets/local-pane-stage.ps1 +101 -0
- package/templates/runtime-assets/runtime-pane-job.ps1 +116 -0
- package/templates/runtime-assets/runtime-pane-private.ps1 +14 -0
- package/templates/runtime-assets/xterm-LICENSE +21 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { NativePaneRecoveryError } from "./native-pane-recovery.js";
|
|
2
|
+
import { addsSecondGeneral } from "./web-only-fleet.js";
|
|
3
|
+
import { NativePaneCrashBudget } from "./native-pane-crash-budget.js";
|
|
4
|
+
import { localWindowsCliEnabled, remoteRuntimeEnabled } from "./runtime-switches.js";
|
|
1
5
|
import { settingsUndo, undoSettingsPaths } from "./settings-transaction.js";
|
|
2
6
|
import { measureSyncWork } from "./sync-work-attribution.js";
|
|
3
7
|
import { REMOVED_BACKENDS, isRemovedBackend, removedBackendMessage } from "./backend/removed.js";
|
|
@@ -25,6 +29,7 @@ import { BACKEND_AUTH_CHECKS, checkAuthStatus, LOGIN_FLOWS } from "./login-flows
|
|
|
25
29
|
import { CHAT_PROFILE_LOGIN_BACKENDS, credentialProfileEnv, credentialProfileLoginCommand } from "./backend/credential-profile.js";
|
|
26
30
|
import { fetchClaudeUsage, fetchCodexUsage } from "./usage/providers.js";
|
|
27
31
|
import { assertExplicitInstanceRemoval, authorizeExplicitInstanceRemoval } from "./instance-removal.js";
|
|
32
|
+
import { WINDOWS_CREATE_REFUSED, isNativePaneInstance } from "./native-instance-registry.js";
|
|
28
33
|
import { capturePendingTargetReconciliation, finishTargetReconciliation, reconcileTargetBeforeStart, RECONCILIATION_WRITE_DRAIN_TIMEOUT_MS, retireCapturedTargetWindows, } from "./delivery-reconciliation.js";
|
|
29
34
|
import { noPlaceMarkers, placeRef } from "./topic-link.js";
|
|
30
35
|
export { isFleetStartCommandLine } from "./fleet-lock.js";
|
|
@@ -285,6 +290,7 @@ export class InstanceLifecycle {
|
|
|
285
290
|
activeTransition = new Map();
|
|
286
291
|
/** Bumped synchronously by stop/restart: a start begun under an older epoch must not publish. */
|
|
287
292
|
lifecycleEpochs = new Map();
|
|
293
|
+
nativeExitOwners = new Map();
|
|
288
294
|
/** Single wake flight per instance: concurrent wakes share it. */
|
|
289
295
|
wakeFlights = new Map();
|
|
290
296
|
/** Starts that begin their idle window now instead of at the persisted last inbound. */
|
|
@@ -682,7 +688,108 @@ export class InstanceLifecycle {
|
|
|
682
688
|
this.ctx.notifyInstanceTopic(name, t("delivery.cancelled_unsent", messages.length, name));
|
|
683
689
|
}, this.ctx.logger, `daemon.human_messages_cancelled[${name}]`));
|
|
684
690
|
}
|
|
691
|
+
nativeRecoveryPending(name) { return this.nativeExitOwners.has(name); }
|
|
692
|
+
cancelNativeRecovery(name, owner) {
|
|
693
|
+
for (const [target, run] of this.nativeExitOwners) {
|
|
694
|
+
if (name !== undefined && target !== name || owner !== undefined && run.token !== owner)
|
|
695
|
+
continue;
|
|
696
|
+
clearTimeout(run.timer);
|
|
697
|
+
this.nativeExitOwners.delete(target);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
resetNativeCrashBudget(name) {
|
|
701
|
+
this.cancelNativeRecovery(name);
|
|
702
|
+
const pin = this.ctx.nativePanePinnedSession?.(name);
|
|
703
|
+
if (pin) {
|
|
704
|
+
ensureInstanceDir(this.ctx.getInstanceDir(name));
|
|
705
|
+
new NativePaneCrashBudget(join(this.ctx.getInstanceDir(name), "native-crash-state.json")).reset(pin);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
async nativePaneExited(name, daemon, data) {
|
|
709
|
+
const config = this.ctx.fleetConfig?.instances[name], epoch = this.epochOf(name), pin = data.snapshot.sessionId, profilePin = this.ctx.nativePanePinnedSession?.(name) ?? undefined;
|
|
710
|
+
if (!isNativePaneInstance(config) || data.name !== name || this.daemons.get(name) !== daemon || !daemon.nativePaneExitCurrent(data.snapshot, data.owner)
|
|
711
|
+
|| pin !== undefined && profilePin !== undefined && profilePin !== pin || this.nativeExitOwners.has(name) || this.ctx.isPlannedRestart())
|
|
712
|
+
return;
|
|
713
|
+
const token = Symbol(name), run = { token, daemon, timer: undefined };
|
|
714
|
+
this.nativeExitOwners.set(name, run);
|
|
715
|
+
const current = () => this.nativeExitOwners.get(name) === run && this.daemons.get(name) === daemon && this.epochOf(name) === epoch
|
|
716
|
+
&& this.ctx.fleetConfig?.instances[name] === config && ((this.ctx.nativePanePinnedSession?.(name) ?? undefined) === profilePin || profilePin === undefined && pin !== undefined && this.ctx.nativePanePinnedSession?.(name) === pin) && !this.isPaused(name) && !this.ctx.isPlannedRestart()
|
|
717
|
+
&& (config.machine_id ? remoteRuntimeEnabled() : localWindowsCliEnabled());
|
|
718
|
+
daemon.fenceDeliveryWritesForStop();
|
|
719
|
+
try {
|
|
720
|
+
const decision = pin && profilePin ? new NativePaneCrashBudget(join(this.ctx.getInstanceDir(name), "native-crash-state.json")).observe(pin, data.snapshot.exitCode, config.restart_policy) : null;
|
|
721
|
+
await this.runTransition(name, async () => {
|
|
722
|
+
if (!current())
|
|
723
|
+
return;
|
|
724
|
+
if (!await daemon.waitForDeliveryWritesToDrain(RECONCILIATION_WRITE_DRAIN_TIMEOUT_MS) || !current())
|
|
725
|
+
throw Error("Native input writes have not drained");
|
|
726
|
+
if (this.ctx.deliveryOutbox) {
|
|
727
|
+
this.ctx.deliveryOutbox.markTargetReconciliationPending(name, daemon.bootId);
|
|
728
|
+
if (!await daemon.reconcileNativeDeliveries(this.ctx.deliveryOutbox, current) || !current())
|
|
729
|
+
throw Error("Native delivery reconciliation is unconfirmed");
|
|
730
|
+
}
|
|
731
|
+
// Close finalizes the exact positive exit; no PID lookup or signal exists on this path.
|
|
732
|
+
await daemon.stop({ nativePane: "close" });
|
|
733
|
+
if (!current())
|
|
734
|
+
return;
|
|
735
|
+
this.ctx.eventLog?.insert(name, "native_pane_exited", { exitCode: data.snapshot.exitCode ?? null, sessionId: pin, decision: decision?.kind ?? "no-conversation", count: decision?.count ?? 0 });
|
|
736
|
+
if (!decision) {
|
|
737
|
+
this.ctx.holdNativePaneRecovery?.(name, new NativePaneRecoveryError({ kind: "session-unconfirmed", launchId: data.snapshot.launchId, sessionId: this.ctx.nativePanePinnedSession?.(name) ?? undefined, ...(config.backend === "codex" ? { provider: "codex" } : {}) }));
|
|
738
|
+
this.ctx.setTopicIcon(name, "red");
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
if (decision.kind !== "retry") {
|
|
742
|
+
if (decision.kind === "normal")
|
|
743
|
+
await this.ctx.notifyNormalExit(name);
|
|
744
|
+
else
|
|
745
|
+
this.notifyIncident(name, decision.kind === "loop" ? "crash_loop" : "supervision_ended", t("inst.respawn_paused", name));
|
|
746
|
+
this.ctx.setTopicIcon(name, "red");
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const timer = setTimeout(() => {
|
|
750
|
+
run.timer = undefined;
|
|
751
|
+
void this.runTransition(name, async () => {
|
|
752
|
+
if (!current())
|
|
753
|
+
return;
|
|
754
|
+
await this.stopInTransition(name, token);
|
|
755
|
+
// Our own stop advances once. An operator's concurrent stop/config change prevents publication.
|
|
756
|
+
if (this.nativeExitOwners.get(name) !== run || this.epochOf(name) !== epoch + 1 || this.daemons.has(name)
|
|
757
|
+
|| this.ctx.fleetConfig?.instances[name] !== config || this.ctx.nativePanePinnedSession?.(name) !== pin || this.isPaused(name) || this.ctx.isPlannedRestart()
|
|
758
|
+
|| !(config.machine_id ? remoteRuntimeEnabled() : localWindowsCliEnabled()))
|
|
759
|
+
return;
|
|
760
|
+
await this.startInTransition(name, config, true, { kind: "fleet-topic", backend: config.backend ?? "codex", model: config.model || "default" });
|
|
761
|
+
if (this.nativeExitOwners.get(name) !== run || this.epochOf(name) !== epoch + 1 || this.ctx.isPlannedRestart())
|
|
762
|
+
return;
|
|
763
|
+
await this.ctx.connectIpcToInstance(name);
|
|
764
|
+
}).catch(error => { if (this.nativeExitOwners.get(name) === run && !this.ctx.isPlannedRestart()) {
|
|
765
|
+
if (this.ctx.holdNativePaneRecovery?.(name, error))
|
|
766
|
+
return;
|
|
767
|
+
this.ctx.logger.error({ name, err: error }, "Native conversation resume failed; its pin was retained");
|
|
768
|
+
this.notifyIncident(name, "supervision_ended", t("inst.respawn_paused", name));
|
|
769
|
+
} })
|
|
770
|
+
.finally(() => { this.cancelNativeRecovery(name, token); this.ctx.onNativePaneRecoverySettled?.(name); });
|
|
771
|
+
}, decision.delay);
|
|
772
|
+
timer.unref?.();
|
|
773
|
+
run.timer = timer;
|
|
774
|
+
});
|
|
775
|
+
if (!run.timer)
|
|
776
|
+
this.cancelNativeRecovery(name, token);
|
|
777
|
+
}
|
|
778
|
+
catch (error) {
|
|
779
|
+
if (this.nativeExitOwners.get(name) === run && !this.ctx.isPlannedRestart()) {
|
|
780
|
+
this.ctx.logger.error({ name, err: error }, "Native crash recovery held without a fresh fallback");
|
|
781
|
+
this.notifyIncident(name, "supervision_ended", t("inst.respawn_paused", name));
|
|
782
|
+
}
|
|
783
|
+
this.cancelNativeRecovery(name, token);
|
|
784
|
+
}
|
|
785
|
+
finally {
|
|
786
|
+
if (!run.timer)
|
|
787
|
+
this.ctx.onNativePaneRecoverySettled?.(name);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
685
790
|
attachIncidentHandlers(name, daemon) {
|
|
791
|
+
if (daemon.usesNativePane?.())
|
|
792
|
+
daemon.on("native_pane_exited", safeHandler((data) => this.nativePaneExited(name, daemon, data), this.ctx.logger, `daemon.native_pane_exited[${name}]`));
|
|
686
793
|
daemon.on("capacity_nudge_cancelled", safeHandler((data) => {
|
|
687
794
|
const reason = data.reason === "the user cancelled" ? t("inst.codex_retry_cancel_reason_user")
|
|
688
795
|
: data.reason === "the instance was stopped, paused or respawned" || data.reason === "the instance is not running" ? t("inst.codex_retry_cancel_reason_stopped")
|
|
@@ -981,19 +1088,22 @@ export class InstanceLifecycle {
|
|
|
981
1088
|
// labels, summaries and every exhaustive match for one picker's text.)
|
|
982
1089
|
// #1691: a prompt no table knows — what it asks (one sanitised, bounded line from the daemon, never the pane), and
|
|
983
1090
|
// that AgEnD will not press anything.
|
|
1091
|
+
// S-35: a Windows agent's instance name is windows-<uuid>; people know it by its display name.
|
|
1092
|
+
const label = this.ctx.fleetConfig?.instances[name]?.display_name?.trim() || name;
|
|
1093
|
+
const place = placeRef({ kind: "instance", name }, label);
|
|
984
1094
|
if (data.unrecognised) {
|
|
985
1095
|
// #1990: the question is a pane line — it may not name a place of its own.
|
|
986
1096
|
const asked = data.question ? t("inst.unrecognised_prompt_question", noPlaceMarkers(data.question)) : "";
|
|
987
|
-
this.notifyParked(name, "dialog_parked", t("inst.unrecognised_prompt",
|
|
1097
|
+
this.notifyParked(name, "dialog_parked", t("inst.unrecognised_prompt", label, asked), t("fleet.unrecognised_prompt", place, asked));
|
|
988
1098
|
return;
|
|
989
1099
|
}
|
|
990
1100
|
const category = data.kind && data.kind !== "dialog" ? interactionCategory(data.kind, data.backend) : null;
|
|
991
|
-
const text = category ? t("inst.interaction_parked",
|
|
1101
|
+
const text = category ? t("inst.interaction_parked", label, category) : data.holdOnly
|
|
992
1102
|
// #2872: the Claude session-resume advice only for that prompt (it read as nonsense under a grok or kiro dialog).
|
|
993
|
-
? t("inst.dialog_parked_hold",
|
|
994
|
-
: t("inst.dialog_parked_stuck",
|
|
1103
|
+
? t("inst.dialog_parked_hold", label, data.description) + (data.advice === "claude-resume" ? " " + t("inst.dialog_parked_hold_claude_resume") : "")
|
|
1104
|
+
: t("inst.dialog_parked_stuck", label, data.description) + (data.advice === "claude-resume" ? " " + t("inst.dialog_parked_stuck_claude_resume") : "");
|
|
995
1105
|
// #1990: in General, the instance's name links to its topic.
|
|
996
|
-
this.notifyParked(name, "dialog_parked", text, category ? t("fleet.interaction_parked",
|
|
1106
|
+
this.notifyParked(name, "dialog_parked", text, category ? t("fleet.interaction_parked", place, category) : t("fleet.dialog_parked", place, data.description));
|
|
997
1107
|
}, this.ctx.logger, `daemon.dialog_parked[${name}]`));
|
|
998
1108
|
// #2897: the held dialog is gone (closed, answered, auto-answered) — its notices go with it.
|
|
999
1109
|
daemon.on("dialog_unparked", safeHandler(() => this.ctx.resolveParkedNotice?.(name), this.ctx.logger, `daemon.dialog_unparked[${name}]`));
|
|
@@ -1030,6 +1140,21 @@ export class InstanceLifecycle {
|
|
|
1030
1140
|
daemon.on("pty_error", safeHandler(async (data) => {
|
|
1031
1141
|
this.ctx.eventLog?.insert(name, "pty_error", { type: data.type, action: data.action });
|
|
1032
1142
|
this.ctx.logger.warn({ name, errorType: data.type, action: data.action }, `PTY error: ${data.message}`);
|
|
1143
|
+
if (daemon.usesNativePane?.()) {
|
|
1144
|
+
// Native credentials and quotas belong to its runner. Never probe a Linux login or group its peers with it.
|
|
1145
|
+
if (this.daemons.get(name) !== daemon)
|
|
1146
|
+
return;
|
|
1147
|
+
this.notifyIncident(name, data.type, data.notice ?? data.message);
|
|
1148
|
+
if (data.action === "pause") {
|
|
1149
|
+
if (data.type === "auth_error") {
|
|
1150
|
+
daemon.confirmAuthFailure?.();
|
|
1151
|
+
daemon.requestPauseWhenIdle({ reconfirmAuth: true, reason: "auth" });
|
|
1152
|
+
}
|
|
1153
|
+
else
|
|
1154
|
+
daemon.requestPauseWhenIdle({ reason: "error" });
|
|
1155
|
+
}
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1033
1158
|
// Antigravity's account-level cap is visible ONLY here: the quota summary
|
|
1034
1159
|
// API keeps reporting its buckets as barely used while the CLI is blocked
|
|
1035
1160
|
// (verified live — 0% used and "Individual quota reached" in the same
|
|
@@ -1366,7 +1491,10 @@ export class InstanceLifecycle {
|
|
|
1366
1491
|
return this.lifecycleEpochs.get(name) ?? 0;
|
|
1367
1492
|
}
|
|
1368
1493
|
/** Invalidate every start/wake already running for `name` (they will not publish). */
|
|
1369
|
-
invalidate(name) {
|
|
1494
|
+
invalidate(name, nativeOwner) {
|
|
1495
|
+
const native = this.nativeExitOwners.get(name);
|
|
1496
|
+
if (native && native.token !== nativeOwner)
|
|
1497
|
+
this.cancelNativeRecovery(name);
|
|
1370
1498
|
this.lifecycleEpochs.set(name, this.epochOf(name) + 1);
|
|
1371
1499
|
}
|
|
1372
1500
|
/** Whether `transition` is `name`'s transition and is the one running now. */
|
|
@@ -1434,170 +1562,194 @@ export class InstanceLifecycle {
|
|
|
1434
1562
|
const check = () => { execution?.assert(); if (this.epochOf(name) !== epoch)
|
|
1435
1563
|
throw new SupersededStartError(name); };
|
|
1436
1564
|
check();
|
|
1565
|
+
this.ctx.assertGeneralBindingStart?.(name, config);
|
|
1437
1566
|
assertNoSessionOomStop(this.ctx.getInstanceDir(name));
|
|
1438
1567
|
const seedNow = this.activitySeedNow.delete(name);
|
|
1439
1568
|
if (this.daemons.has(name)) {
|
|
1440
1569
|
this.ctx.logger.info({ name }, "Instance already running, skipping");
|
|
1441
1570
|
return;
|
|
1442
1571
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
const instanceDir = this.ctx.getInstanceDir(name);
|
|
1448
|
-
ensureInstanceDir(instanceDir);
|
|
1449
|
-
// Daemon.start consumes the recovery marker after reading it. A start
|
|
1450
|
-
// that fails before reaching the daemon must leave that intent intact.
|
|
1451
|
-
const { Daemon } = await import("./daemon.js");
|
|
1452
|
-
const { createBackend } = await import("./backend/factory.js");
|
|
1453
|
-
check();
|
|
1454
|
-
const backendName = config.backend ?? this.ctx.fleetConfig?.defaults?.backend ?? "claude-code";
|
|
1455
|
-
// A removed backend (#1280): this instance refuses to start, says why and what to use instead, and the rest of
|
|
1456
|
-
// the fleet is unaffected. Never a fallback to another backend.
|
|
1457
|
-
if (isRemovedBackend(backendName)) {
|
|
1458
|
-
const message = removedBackendMessage(backendName, name);
|
|
1459
|
-
this.ctx.logger.error({ name, backend: backendName }, `Not starting: ${message}`);
|
|
1460
|
-
this.ctx.notifyInstanceTopic(name, t("inst.backend_removed", name, backendName, REMOVED_BACKENDS[backendName].replacement));
|
|
1461
|
-
return;
|
|
1462
|
-
}
|
|
1463
|
-
// Verify backend binary is in PATH before spawning. Off-loop resolve pins a
|
|
1464
|
-
// hint so createBackend's resolveBinary does not run synchronous `which`
|
|
1465
|
-
// (#1490 row 67). Missing still only logs; start continues.
|
|
1466
|
-
const installation = BACKEND_INSTALLATION_INFO[backendName];
|
|
1467
|
-
if (installation) {
|
|
1468
|
-
const { resolveBackendBinary } = await import("./backend-availability.js");
|
|
1469
|
-
const path = await resolveBackendBinary(backendName);
|
|
1470
|
-
noteResolvedBinary(installation.binary, path ?? installation.binary);
|
|
1572
|
+
const native = isNativePaneInstance(config) ? await this.ctx.nativePaneFor?.(name, config, check) : undefined;
|
|
1573
|
+
let nativePublished = false;
|
|
1574
|
+
try {
|
|
1471
1575
|
check();
|
|
1472
|
-
if (!
|
|
1473
|
-
|
|
1576
|
+
if (isNativePaneInstance(config) && !native)
|
|
1577
|
+
throw Error("Native pane ownership is unavailable; no local CLI was started");
|
|
1578
|
+
if (native)
|
|
1579
|
+
config = { ...config, agent_mode: "mcp" };
|
|
1580
|
+
if (!native && !existsSync(config.working_directory)) {
|
|
1581
|
+
this.ctx.logger.info({ name, working_directory: config.working_directory }, "Working directory does not exist — creating it");
|
|
1582
|
+
mkdirSync(config.working_directory, { recursive: true });
|
|
1474
1583
|
}
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
}, this.ctx.spawnGate, this.ctx.stormWindow, this.ctx.backendOutage);
|
|
1490
|
-
daemon.setDeliveryOutboxPort(this.ctx.deliveryOutbox ?? undefined);
|
|
1491
|
-
daemon.setWorkLeaseCheck(() => this.hasWorkLease(name));
|
|
1492
|
-
if (seedNow)
|
|
1493
|
-
daemon.seedActivityNow();
|
|
1494
|
-
// Read at each spawn so a fleet.yaml reload is honoured (#984).
|
|
1495
|
-
daemon.setPeerWorkingDirectories(backendName === "kiro-cli"
|
|
1496
|
-
? this.ctx.kiroPeerWorkingDirectories ? () => this.ctx.kiroPeerWorkingDirectories(name) : undefined
|
|
1497
|
-
: () => peerWorkingDirectories(this.ctx.fleetConfig, name, backendName));
|
|
1498
|
-
daemon.setStatusEmojiAvoidList(() => this.ctx.statusEmojiAvoidList?.(name));
|
|
1499
|
-
// Before start: the first spawn builds the command and emits its launch
|
|
1500
|
-
// warning synchronously inside Daemon.start, long before
|
|
1501
|
-
// attachIncidentHandlers runs (#984).
|
|
1502
|
-
this.attachLaunchWarningHandler(name, daemon);
|
|
1503
|
-
this.attachContextLostHandler(name, daemon);
|
|
1504
|
-
daemon.on("durable_delivery_deferred", (data) => {
|
|
1505
|
-
// A daemon without its outbox port cannot update the row directly. The
|
|
1506
|
-
// lifecycle owns the same-process store and records a bounded pre-write
|
|
1507
|
-
// retry instead of leaving the lane in delivering forever.
|
|
1508
|
-
this.ctx.deliveryOutbox?.retryBeforeBegin(data.deliveryId, data.targetBootId, data.attemptNo, data.reason, 5_000);
|
|
1509
|
-
});
|
|
1510
|
-
daemon.on("mcp_tool_response_written", (data) => {
|
|
1511
|
-
if (!data.operationId || data.daemonBootId !== daemon.bootId)
|
|
1584
|
+
const instanceDir = this.ctx.getInstanceDir(name);
|
|
1585
|
+
ensureInstanceDir(instanceDir);
|
|
1586
|
+
// Daemon.start consumes the recovery marker after reading it. A start
|
|
1587
|
+
// that fails before reaching the daemon must leave that intent intact.
|
|
1588
|
+
const { Daemon } = await import("./daemon.js");
|
|
1589
|
+
const { createBackend } = await import("./backend/factory.js");
|
|
1590
|
+
check();
|
|
1591
|
+
const backendName = config.backend ?? this.ctx.fleetConfig?.defaults?.backend ?? "claude-code";
|
|
1592
|
+
// A removed backend (#1280): this instance refuses to start, says why and what to use instead, and the rest of
|
|
1593
|
+
// the fleet is unaffected. Never a fallback to another backend.
|
|
1594
|
+
if (isRemovedBackend(backendName)) {
|
|
1595
|
+
const message = removedBackendMessage(backendName, name);
|
|
1596
|
+
this.ctx.logger.error({ name, backend: backendName }, `Not starting: ${message}`);
|
|
1597
|
+
this.ctx.notifyInstanceTopic(name, t("inst.backend_removed", name, backendName, REMOVED_BACKENDS[backendName].replacement));
|
|
1512
1598
|
return;
|
|
1513
|
-
try {
|
|
1514
|
-
this.ctx.deliveryOutbox?.markResponseDelivered(name, data.operationId);
|
|
1515
1599
|
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1600
|
+
// Verify backend binary is in PATH before spawning. Off-loop resolve pins a
|
|
1601
|
+
// hint so createBackend's resolveBinary does not run synchronous `which`
|
|
1602
|
+
// (#1490 row 67). Missing still only logs; start continues.
|
|
1603
|
+
const installation = BACKEND_INSTALLATION_INFO[backendName];
|
|
1604
|
+
// alpha: a native Windows pane's CLI is on that PC — nothing to look for on this one.
|
|
1605
|
+
if (!native && installation) {
|
|
1606
|
+
const { resolveBackendBinary } = await import("./backend-availability.js");
|
|
1607
|
+
const path = await resolveBackendBinary(backendName);
|
|
1608
|
+
noteResolvedBinary(installation.binary, path ?? installation.binary);
|
|
1609
|
+
check();
|
|
1610
|
+
if (!path) {
|
|
1611
|
+
this.ctx.logger.error({ binary: installation.binary, backend: backendName, instance: name }, `Backend binary "${installation.binary}" not found in PATH`);
|
|
1612
|
+
}
|
|
1518
1613
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
const
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
if (
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
this.ctx.
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1614
|
+
// claude-code refuses --dangerously-skip-permissions as root — fail fast
|
|
1615
|
+
// Unless IS_SANDBOX=1 is set (recognized sandbox environment)
|
|
1616
|
+
if (!native && process.getuid?.() === 0 && backendName === "claude-code" && !process.env.IS_SANDBOX) {
|
|
1617
|
+
const msg = `⚠️ claude-code cannot run with --dangerously-skip-permissions as root. Set IS_SANDBOX=1 or use a non-root user.`;
|
|
1618
|
+
this.ctx.logger.error({ name, backend: backendName }, msg);
|
|
1619
|
+
this.ctx.notifyInstanceTopic(name, t("inst.root_skip_perms"));
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
const backend = native?.backend ?? createBackend(backendName, instanceDir);
|
|
1623
|
+
const daemon = new Daemon(name, config, instanceDir, topicMode, backend, this.ctx.controlClient ?? undefined, this.ctx.logger, runtimeIdentity ?? {
|
|
1624
|
+
kind: "fleet-topic",
|
|
1625
|
+
backend: backendName,
|
|
1626
|
+
model: config.model ?? "default",
|
|
1627
|
+
}, this.ctx.spawnGate, this.ctx.stormWindow, this.ctx.backendOutage);
|
|
1628
|
+
if (native) {
|
|
1629
|
+
daemon.setNativePaneLifecycle(native);
|
|
1630
|
+
native.bindDaemon?.(daemon);
|
|
1631
|
+
}
|
|
1632
|
+
daemon.setDeliveryOutboxPort(this.ctx.deliveryOutbox ?? undefined);
|
|
1633
|
+
daemon.setWorkLeaseCheck(() => this.hasWorkLease(name));
|
|
1634
|
+
if (seedNow)
|
|
1635
|
+
daemon.seedActivityNow();
|
|
1636
|
+
// Read at each spawn so a fleet.yaml reload is honoured (#984).
|
|
1637
|
+
daemon.setPeerWorkingDirectories(backendName === "kiro-cli"
|
|
1638
|
+
? this.ctx.kiroPeerWorkingDirectories ? () => this.ctx.kiroPeerWorkingDirectories(name) : undefined
|
|
1639
|
+
: () => peerWorkingDirectories(this.ctx.fleetConfig, name, backendName));
|
|
1640
|
+
daemon.setStatusEmojiAvoidList(() => this.ctx.statusEmojiAvoidList?.(name));
|
|
1641
|
+
// Before start: the first spawn builds the command and emits its launch
|
|
1642
|
+
// warning synchronously inside Daemon.start, long before
|
|
1643
|
+
// attachIncidentHandlers runs (#984).
|
|
1644
|
+
this.attachLaunchWarningHandler(name, daemon);
|
|
1645
|
+
this.attachContextLostHandler(name, daemon);
|
|
1646
|
+
daemon.on("durable_delivery_deferred", (data) => {
|
|
1647
|
+
// A daemon without its outbox port cannot update the row directly. The
|
|
1648
|
+
// lifecycle owns the same-process store and records a bounded pre-write
|
|
1649
|
+
// retry instead of leaving the lane in delivering forever.
|
|
1650
|
+
this.ctx.deliveryOutbox?.retryBeforeBegin(data.deliveryId, data.targetBootId, data.attemptNo, data.reason, 5_000);
|
|
1651
|
+
});
|
|
1652
|
+
daemon.on("mcp_tool_response_written", (data) => {
|
|
1653
|
+
if (!data.operationId || data.daemonBootId !== daemon.bootId)
|
|
1654
|
+
return;
|
|
1655
|
+
try {
|
|
1656
|
+
this.ctx.deliveryOutbox?.markResponseDelivered(name, data.operationId);
|
|
1657
|
+
}
|
|
1658
|
+
catch (err) {
|
|
1659
|
+
this.ctx.logger.error({ name, operationId: data.operationId, err }, "Could not persist MCP response-delivered marker");
|
|
1660
|
+
}
|
|
1661
|
+
});
|
|
1662
|
+
this.applyCapacityBackoffBaseline(name, backendName, daemon);
|
|
1663
|
+
// Catch errors from daemon internals (e.g. IPC server) to prevent crashing the fleet process
|
|
1664
|
+
daemon.on("error", (err) => {
|
|
1665
|
+
this.ctx.logger.error({ err, name }, "Daemon emitted error — instance isolated");
|
|
1666
|
+
});
|
|
1667
|
+
if (this.ctx.deliveryOutbox) {
|
|
1668
|
+
// Fence older-generation submissions and reconcile them before Daemon.start
|
|
1669
|
+
// reaches Strategy A's unconditional old-window kill.
|
|
1670
|
+
const recovered = this.ctx.deliveryOutbox.recoverTargetGeneration(name, daemon.bootId);
|
|
1671
|
+
if (recovered.queued || recovered.reconciliationPending) {
|
|
1672
|
+
this.ctx.logger.warn({ name, ...recovered }, "Preparing durable outbox rows before target generation start");
|
|
1673
|
+
}
|
|
1674
|
+
const reconciled = native
|
|
1675
|
+
? { uncertain: 0, safeToStart: await this.ctx.reconcileNativePaneBeforeStart?.(name, daemon) === true }
|
|
1676
|
+
: await reconcileTargetBeforeStart(this.ctx.deliveryOutbox, name, instanceDir, this.ctx.logger);
|
|
1677
|
+
if (reconciled.uncertain > 0) {
|
|
1678
|
+
this.ctx.logger.warn({ name, ...reconciled }, "Some durable submissions need operator reconciliation");
|
|
1679
|
+
}
|
|
1680
|
+
if (!reconciled.safeToStart) {
|
|
1681
|
+
const message = t("delivery.restart_blocked", name);
|
|
1682
|
+
this.ctx.logger.error({ name, ...reconciled }, message);
|
|
1683
|
+
this.ctx.notifyFleetError?.(message);
|
|
1684
|
+
await daemon.abortStartup().catch(err => this.ctx.logger.warn({ err, name }, "Failed to dispose daemon after reconciliation could not verify old CLI exit"));
|
|
1685
|
+
throw new Error(message);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
if (this.epochOf(name) !== epoch || execution && !execution.current()) {
|
|
1689
|
+
// A stop/restart arrived while this start was reconciling: do not spawn.
|
|
1690
|
+
await daemon.abortStartup().catch(() => { });
|
|
1691
|
+
throw new SupersededStartError(name);
|
|
1692
|
+
}
|
|
1693
|
+
// The startup scan can raise an incident (sign-in screen, fatal modal)
|
|
1694
|
+
// before the handlers below exist and before this daemon is registered;
|
|
1695
|
+
// hold it and deliver it once both are true.
|
|
1696
|
+
daemon.holdStartupIncidents?.();
|
|
1697
|
+
await InstanceLifecycle.startOrDispose(daemon, name, this.ctx.logger, execution || native ? check : undefined);
|
|
1698
|
+
// Publication fence (Phase 2a): the spawn cannot be cancelled, so a stop or
|
|
1699
|
+
// restart requested meanwhile has been waiting behind this transition. A
|
|
1700
|
+
// superseded start must not register, signal ready, or keep its window.
|
|
1701
|
+
if (this.epochOf(name) !== epoch || execution && !execution.current()) {
|
|
1702
|
+
await daemon.abortStartup().catch(err => this.ctx.logger.warn({ err, name }, "Failed to dispose a superseded start"));
|
|
1703
|
+
throw new SupersededStartError(name);
|
|
1704
|
+
}
|
|
1705
|
+
this.capacityBackoffBaselines.delete(name);
|
|
1706
|
+
this.daemons.set(name, daemon);
|
|
1707
|
+
nativePublished = !!native;
|
|
1708
|
+
published?.(daemon); // Exact publication, synchronously after the ownership fence.
|
|
1709
|
+
if (seedNow)
|
|
1710
|
+
this.noteWokeForWork(name);
|
|
1711
|
+
this.ctx.onDaemonReady?.(name, daemon.bootId);
|
|
1712
|
+
daemon.on("auto_pause_requested", safeHandler(async (data) => {
|
|
1713
|
+
await this.pause(name, data?.reason ?? "idle");
|
|
1714
|
+
}, this.ctx.logger, `autoPause[${name}]`));
|
|
1715
|
+
daemon.on("auto_paused", (data) => {
|
|
1716
|
+
this.ctx.eventLog?.insert(name, "instance_paused", { reason: "idle", paused_at: data.pausedAt });
|
|
1717
|
+
this.ctx.logger.info({ name, pausedAt: data.pausedAt }, "Instance auto-paused after idle timeout");
|
|
1718
|
+
this.ctx.setTopicIcon(name, "remove");
|
|
1719
|
+
this.ctx.onAttentionChanged?.(name);
|
|
1720
|
+
});
|
|
1721
|
+
daemon.on("auto_woke", () => {
|
|
1722
|
+
this.ctx.onAttentionChanged?.(name);
|
|
1723
|
+
this.ctx.eventLog?.insert(name, "instance_resumed", { reason: "message" });
|
|
1724
|
+
this.ctx.logger.info({ name }, "Instance auto-woke for delivery");
|
|
1725
|
+
this.ctx.setTopicIcon(name, "green");
|
|
1726
|
+
this.ctx.touchActivity(name);
|
|
1727
|
+
});
|
|
1728
|
+
this.attachIncidentHandlers(name, daemon);
|
|
1729
|
+
// #2897: a new daemon starts with no dialog held; a notice the last one left (a crash, a respawn) is out of date.
|
|
1730
|
+
this.ctx.resolveParkedNotice?.(name);
|
|
1731
|
+
daemon.on("pty_recovered", safeHandler((data) => {
|
|
1732
|
+
const mins = Math.floor(data.downtime_s / 60);
|
|
1733
|
+
const secs = data.downtime_s % 60;
|
|
1734
|
+
const duration = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
1735
|
+
this.ctx.eventLog?.insert(name, "pty_recovered", { downtime_s: data.downtime_s });
|
|
1736
|
+
this.ctx.logger.info({ name, downtime_s: data.downtime_s }, "PTY error recovered");
|
|
1737
|
+
this.ctx.notifyInstanceTopic(name, t("inst.recovered", name, duration));
|
|
1738
|
+
this.ctx.webhookEmit("pty_recovered", name, { downtime_s: data.downtime_s });
|
|
1739
|
+
}, this.ctx.logger, `daemon.pty_recovered[${name}]`));
|
|
1740
|
+
this.attachDeliveryStatusHandlers(name, daemon);
|
|
1580
1741
|
this.ctx.setTopicIcon(name, "green");
|
|
1581
1742
|
this.ctx.touchActivity(name);
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
this.ctx.notifyInstanceTopic(name, t("inst.recovered", name, duration));
|
|
1593
|
-
this.ctx.webhookEmit("pty_recovered", name, { downtime_s: data.downtime_s });
|
|
1594
|
-
}, this.ctx.logger, `daemon.pty_recovered[${name}]`));
|
|
1595
|
-
this.attachDeliveryStatusHandlers(name, daemon);
|
|
1596
|
-
this.ctx.setTopicIcon(name, "green");
|
|
1597
|
-
this.ctx.touchActivity(name);
|
|
1598
|
-
// Last: handlers attached and daemon registered, so a held startup incident
|
|
1599
|
-
// (pause, notify) finds both.
|
|
1600
|
-
daemon.releaseStartupIncidents?.();
|
|
1743
|
+
// Last: handlers attached and daemon registered, so a held startup incident
|
|
1744
|
+
// (pause, notify) finds both.
|
|
1745
|
+
daemon.releaseStartupIncidents?.();
|
|
1746
|
+
}
|
|
1747
|
+
catch (error) {
|
|
1748
|
+
// The factory registered helper authority before acquire(). A superseded pre-window start must release it too.
|
|
1749
|
+
if (native && !nativePublished)
|
|
1750
|
+
await native.release("detach").catch(err => this.ctx.logger.warn({ name, err }, "Prepared native authority could not detach"));
|
|
1751
|
+
throw error;
|
|
1752
|
+
}
|
|
1601
1753
|
}
|
|
1602
1754
|
isPaused(name) {
|
|
1603
1755
|
return this.daemons.get(name)?.isPaused ?? hasPausedMarker(this.ctx.getInstanceDir(name));
|
|
@@ -1606,11 +1758,30 @@ export class InstanceLifecycle {
|
|
|
1606
1758
|
return this.daemons.get(name)?.lastPausedAt ?? readPausedAt(this.ctx.getInstanceDir(name));
|
|
1607
1759
|
}
|
|
1608
1760
|
async pause(name, reason = "operator", admission) {
|
|
1761
|
+
this.cancelNativeRecovery(name);
|
|
1609
1762
|
// Final backstop shared by slash, MCP, Settings, warm-cap, and any future
|
|
1610
1763
|
// caller. General is the coordinator and must remain resident to route work.
|
|
1611
1764
|
if (isGeneralInstance(this.ctx.fleetConfig, name)) {
|
|
1612
1765
|
throw new Error(GENERAL_PAUSE_ERROR);
|
|
1613
1766
|
}
|
|
1767
|
+
const nativeDaemon = this.daemons.get(name);
|
|
1768
|
+
if (nativeDaemon?.usesNativePane?.()) {
|
|
1769
|
+
if (admission && !admission.current())
|
|
1770
|
+
return;
|
|
1771
|
+
await this.runTransition(name, async () => {
|
|
1772
|
+
if (this.daemons.get(name) !== nativeDaemon || admission && !admission.current())
|
|
1773
|
+
return;
|
|
1774
|
+
if (!nativeDaemon.nativePaneHasExited() && (!await nativeDaemon.nativePauseReady(admission) || this.daemons.get(name) !== nativeDaemon || !nativeDaemon.nativePauseStillReady()))
|
|
1775
|
+
return;
|
|
1776
|
+
if (this.daemons.get(name) !== nativeDaemon || admission && !admission.current())
|
|
1777
|
+
return;
|
|
1778
|
+
await this.stopInTransition(name);
|
|
1779
|
+
this.ctx.setNativePanePaused?.(name, true);
|
|
1780
|
+
writePausedMarker(this.ctx.getInstanceDir(name), Date.now(), reason);
|
|
1781
|
+
this.ctx.onAttentionChanged?.(name);
|
|
1782
|
+
});
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1614
1785
|
// B1: cancel any pending capacity backoff — a user-initiated pause should
|
|
1615
1786
|
// not be undone by a queued restart 30–120s later.
|
|
1616
1787
|
const pendingBackoff = this.capacityBackoffTimers.get(name);
|
|
@@ -1694,16 +1865,21 @@ export class InstanceLifecycle {
|
|
|
1694
1865
|
clearPausedMarker(instanceDir);
|
|
1695
1866
|
this.markActivitySeedNow(name);
|
|
1696
1867
|
try {
|
|
1868
|
+
if (isNativePaneInstance(this.ctx.fleetConfig?.instances[name]))
|
|
1869
|
+
this.ctx.setNativePanePaused?.(name, false);
|
|
1697
1870
|
await this.ctx.startPersistedPausedInstance(name, transition);
|
|
1698
1871
|
}
|
|
1699
1872
|
catch (err) {
|
|
1700
1873
|
this.clearActivitySeedNow(name);
|
|
1701
1874
|
writePausedMarker(instanceDir, pausedAt, reason);
|
|
1875
|
+
if (isNativePaneInstance(this.ctx.fleetConfig?.instances[name]))
|
|
1876
|
+
this.ctx.setNativePanePaused?.(name, true);
|
|
1702
1877
|
throw err;
|
|
1703
1878
|
}
|
|
1704
1879
|
}
|
|
1705
1880
|
this.noteWokeForWork(name);
|
|
1706
|
-
this.ctx.
|
|
1881
|
+
if (!isNativePaneInstance(this.ctx.fleetConfig?.instances[name]))
|
|
1882
|
+
this.ctx.startStatuslineWatcher(name);
|
|
1707
1883
|
}
|
|
1708
1884
|
/**
|
|
1709
1885
|
* Ownership boundary for a daemon that is not yet registered: if start()
|
|
@@ -1737,8 +1913,8 @@ export class InstanceLifecycle {
|
|
|
1737
1913
|
this.invalidate(name);
|
|
1738
1914
|
return this.runTransition(name, () => this.stopInTransition(name), transition);
|
|
1739
1915
|
}
|
|
1740
|
-
async stopInTransition(name) {
|
|
1741
|
-
this.invalidate(name);
|
|
1916
|
+
async stopInTransition(name, nativeOwner) {
|
|
1917
|
+
this.invalidate(name, nativeOwner);
|
|
1742
1918
|
this.wokeAt.delete(name);
|
|
1743
1919
|
this.ctx.setTopicIcon(name, "remove");
|
|
1744
1920
|
// #2897: a stopped instance holds no dialog — its "needs a human" notices are out of date.
|
|
@@ -1763,11 +1939,20 @@ export class InstanceLifecycle {
|
|
|
1763
1939
|
if (!drained)
|
|
1764
1940
|
this.ctx.logger.warn({ name }, "Pane write did not drain before durable reconciliation capture; relying on the Enter write-ahead fence");
|
|
1765
1941
|
this.ctx.deliveryOutbox.markTargetReconciliationPending(name, daemon.bootId);
|
|
1766
|
-
|
|
1942
|
+
if (daemon.usesNativePane?.()) {
|
|
1943
|
+
const reconciled = await daemon.reconcileNativeDeliveries(this.ctx.deliveryOutbox, () => this.daemons.get(name) === daemon);
|
|
1944
|
+
if (!reconciled)
|
|
1945
|
+
this.ctx.logger.warn({ name }, "Native stop could not settle every old delivery; retained attempts will not be replayed");
|
|
1946
|
+
}
|
|
1947
|
+
if (!daemon.usesNativePane?.())
|
|
1948
|
+
captured = await capturePendingTargetReconciliation(this.ctx.deliveryOutbox, name, this.ctx.getInstanceDir(name), getTmuxSession(), this.ctx.logger);
|
|
1767
1949
|
}
|
|
1768
1950
|
let stopped = false;
|
|
1769
1951
|
try {
|
|
1770
|
-
|
|
1952
|
+
if (daemon.usesNativePane?.())
|
|
1953
|
+
await daemon.stop({ nativePane: "close" });
|
|
1954
|
+
else
|
|
1955
|
+
await daemon.stop();
|
|
1771
1956
|
stopped = true;
|
|
1772
1957
|
}
|
|
1773
1958
|
finally {
|
|
@@ -1797,6 +1982,11 @@ export class InstanceLifecycle {
|
|
|
1797
1982
|
if (this.daemons.get(name) === daemon)
|
|
1798
1983
|
this.daemons.delete(name);
|
|
1799
1984
|
}
|
|
1985
|
+
else if (isNativePaneInstance(this.ctx.fleetConfig?.instances[name])) {
|
|
1986
|
+
if (!this.ctx.closeRetainedNativePane)
|
|
1987
|
+
throw Error("Retained native pane owner is unavailable; no local PID was signalled");
|
|
1988
|
+
await this.ctx.closeRetainedNativePane(name);
|
|
1989
|
+
}
|
|
1800
1990
|
else {
|
|
1801
1991
|
const instanceDir = this.ctx.getInstanceDir(name);
|
|
1802
1992
|
const pidPath = join(instanceDir, "daemon.pid");
|
|
@@ -1983,6 +2173,27 @@ export class InstanceLifecycle {
|
|
|
1983
2173
|
async handleCreate(args, respond, adapterId, execution) {
|
|
1984
2174
|
const check = () => execution?.assert();
|
|
1985
2175
|
check();
|
|
2176
|
+
if (args.runtime !== undefined && args.runtime !== "wsl" && args.runtime !== "windows") {
|
|
2177
|
+
respond(null, "Unknown instance runtime");
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
// M-2239 P1-1: a Windows agent is created only from the admin web dashboard (native-instance-api.ts), never through
|
|
2181
|
+
// create_instance, deploy_template or any other path that reaches here — an agent holding create_instance could
|
|
2182
|
+
// otherwise start one on the Windows host, in any drive path, with write access.
|
|
2183
|
+
if (args.runtime === "windows") {
|
|
2184
|
+
respond(null, WINDOWS_CREATE_REFUSED);
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
// #3021 review: on a fleet with no chat connection a new agent never becomes a second General (it would inherit
|
|
2188
|
+
// defaults.general_topic: true while the fleet has one).
|
|
2189
|
+
if (this.ctx.fleetConfig && addsSecondGeneral(this.ctx.fleetConfig)) {
|
|
2190
|
+
respond(null, "one_general: this fleet already has its General, and a new agent would inherit defaults.general_topic: true — set it to false in the defaults first");
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
if (args.sandbox !== undefined) {
|
|
2194
|
+
respond(null, "sandbox is supported only by the Windows runtime");
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
1986
2197
|
const rawDirectory = args.directory;
|
|
1987
2198
|
const directory = rawDirectory ? rawDirectory.replace(/^~/, process.env.HOME || "~") : undefined;
|
|
1988
2199
|
const topicName = args.topic_name || (directory ? basename(directory) : undefined);
|
|
@@ -2273,6 +2484,11 @@ export class InstanceLifecycle {
|
|
|
2273
2484
|
createdConfig = instanceConfig;
|
|
2274
2485
|
const beforeCreate = structuredClone(this.ctx.fleetConfig);
|
|
2275
2486
|
const persist = () => {
|
|
2487
|
+
// #3021 review r2: asked again at the commit, after every await — two creates that both saw no General at entry
|
|
2488
|
+
// (defaults.general_topic: true) must not both become one.
|
|
2489
|
+
if (addsSecondGeneral(this.ctx.fleetConfig, { general_topic: instanceConfig.general_topic })) {
|
|
2490
|
+
throw new Error("one_general: this fleet already has its General, and a new agent would inherit defaults.general_topic: true — set it to false in the defaults first");
|
|
2491
|
+
}
|
|
2276
2492
|
this.ctx.fleetConfig.instances[newInstanceName] = instanceConfig;
|
|
2277
2493
|
if (createdTopicId != null)
|
|
2278
2494
|
this.ctx.routing.register(createdTopicId, { kind: "instance", name: newInstanceName });
|