@songsid/agend 2.3.4-beta.6 → 2.3.5-alpha.2
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/backend/claude-code.d.ts +15 -12
- package/dist/backend/claude-code.js +137 -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 +1271 -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 +6 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +59 -0
- 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 +62 -5
- package/dist/daemon.js +749 -267
- 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 +125 -2
- package/dist/fleet-manager.js +1157 -27
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-windows-runtime.d.ts +92 -0
- package/dist/fleet-windows-runtime.js +373 -0
- package/dist/fleet-windows-runtime.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 +20 -3
- package/dist/instance-lifecycle.js +358 -156
- package/dist/instance-lifecycle.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 +34 -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 +227 -0
- package/dist/native-pane-lifecycle.js.map +1 -0
- package/dist/native-pane-manager.d.ts +58 -0
- package/dist/native-pane-manager.js +563 -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 +1 -0
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +12 -1
- package/dist/needs-you.js +8 -1
- 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 +107 -0
- package/dist/pane-port.js +2 -0
- package/dist/pane-port.js.map +1 -0
- 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 +147 -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-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 +43 -0
- package/dist/runtime-pane-host.js +403 -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 +43 -0
- package/dist/runtime-pane-mcp.js +137 -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 +134 -0
- package/dist/runtime-pane-port.js +537 -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 +169 -0
- package/dist/runtime-pane-protocol.js +189 -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.js +58 -0
- package/dist/settings-api.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 +15 -1
- package/dist/settings-confirmation.js +46 -9
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.js +23 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +11 -2
- package/dist/settings-http-confirmation.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/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 +21 -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/native-instance-settings.js +47 -0
- package/dist/ui/native-pane-recovery.js +45 -0
- package/dist/ui/panel-chat.js +61 -32
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +99 -18
- package/dist/ui/panel-needs.js +152 -3
- package/dist/ui/panel-runtimes.js +231 -0
- package/dist/ui/panel-settings.js +14 -8
- 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 +14 -5
- package/dist/ui/settings-registry.js +5 -0
- package/dist/ui/settings-strings.js +14 -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 +20 -4
- package/dist/ui/shared/instance-switch.js +4 -3
- package/dist/ui/shared/ui-menu.js +28 -8
- package/dist/ui/shared/view-strings.js +6 -0
- package/dist/ui/windows-agents-nav.js +2 -0
- package/dist/ui/windows-cli-catalog.js +79 -0
- package/dist/update-check.d.ts +8 -2
- package/dist/update-check.js +5 -2
- package/dist/update-check.js.map +1 -1
- package/dist/web-api.d.ts +25 -0
- package/dist/web-api.js +171 -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-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 +112 -0
- package/dist/windows-agents.js +463 -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,6 @@
|
|
|
1
|
+
import { NativePaneRecoveryError } from "./native-pane-recovery.js";
|
|
2
|
+
import { NativePaneCrashBudget } from "./native-pane-crash-budget.js";
|
|
3
|
+
import { localWindowsCliEnabled, remoteRuntimeEnabled } from "./runtime-switches.js";
|
|
1
4
|
import { settingsUndo, undoSettingsPaths } from "./settings-transaction.js";
|
|
2
5
|
import { measureSyncWork } from "./sync-work-attribution.js";
|
|
3
6
|
import { REMOVED_BACKENDS, isRemovedBackend, removedBackendMessage } from "./backend/removed.js";
|
|
@@ -25,6 +28,7 @@ import { BACKEND_AUTH_CHECKS, checkAuthStatus, LOGIN_FLOWS } from "./login-flows
|
|
|
25
28
|
import { CHAT_PROFILE_LOGIN_BACKENDS, credentialProfileEnv, credentialProfileLoginCommand } from "./backend/credential-profile.js";
|
|
26
29
|
import { fetchClaudeUsage, fetchCodexUsage } from "./usage/providers.js";
|
|
27
30
|
import { assertExplicitInstanceRemoval, authorizeExplicitInstanceRemoval } from "./instance-removal.js";
|
|
31
|
+
import { WINDOWS_CREATE_REFUSED, isNativePaneInstance } from "./native-instance-registry.js";
|
|
28
32
|
import { capturePendingTargetReconciliation, finishTargetReconciliation, reconcileTargetBeforeStart, RECONCILIATION_WRITE_DRAIN_TIMEOUT_MS, retireCapturedTargetWindows, } from "./delivery-reconciliation.js";
|
|
29
33
|
import { noPlaceMarkers, placeRef } from "./topic-link.js";
|
|
30
34
|
export { isFleetStartCommandLine } from "./fleet-lock.js";
|
|
@@ -285,6 +289,7 @@ export class InstanceLifecycle {
|
|
|
285
289
|
activeTransition = new Map();
|
|
286
290
|
/** Bumped synchronously by stop/restart: a start begun under an older epoch must not publish. */
|
|
287
291
|
lifecycleEpochs = new Map();
|
|
292
|
+
nativeExitOwners = new Map();
|
|
288
293
|
/** Single wake flight per instance: concurrent wakes share it. */
|
|
289
294
|
wakeFlights = new Map();
|
|
290
295
|
/** Starts that begin their idle window now instead of at the persisted last inbound. */
|
|
@@ -682,7 +687,108 @@ export class InstanceLifecycle {
|
|
|
682
687
|
this.ctx.notifyInstanceTopic(name, t("delivery.cancelled_unsent", messages.length, name));
|
|
683
688
|
}, this.ctx.logger, `daemon.human_messages_cancelled[${name}]`));
|
|
684
689
|
}
|
|
690
|
+
nativeRecoveryPending(name) { return this.nativeExitOwners.has(name); }
|
|
691
|
+
cancelNativeRecovery(name, owner) {
|
|
692
|
+
for (const [target, run] of this.nativeExitOwners) {
|
|
693
|
+
if (name !== undefined && target !== name || owner !== undefined && run.token !== owner)
|
|
694
|
+
continue;
|
|
695
|
+
clearTimeout(run.timer);
|
|
696
|
+
this.nativeExitOwners.delete(target);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
resetNativeCrashBudget(name) {
|
|
700
|
+
this.cancelNativeRecovery(name);
|
|
701
|
+
const pin = this.ctx.nativePanePinnedSession?.(name);
|
|
702
|
+
if (pin) {
|
|
703
|
+
ensureInstanceDir(this.ctx.getInstanceDir(name));
|
|
704
|
+
new NativePaneCrashBudget(join(this.ctx.getInstanceDir(name), "native-crash-state.json")).reset(pin);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
async nativePaneExited(name, daemon, data) {
|
|
708
|
+
const config = this.ctx.fleetConfig?.instances[name], epoch = this.epochOf(name), pin = data.snapshot.sessionId, profilePin = this.ctx.nativePanePinnedSession?.(name) ?? undefined;
|
|
709
|
+
if (!isNativePaneInstance(config) || data.name !== name || this.daemons.get(name) !== daemon || !daemon.nativePaneExitCurrent(data.snapshot, data.owner)
|
|
710
|
+
|| pin !== undefined && profilePin !== undefined && profilePin !== pin || this.nativeExitOwners.has(name) || this.ctx.isPlannedRestart())
|
|
711
|
+
return;
|
|
712
|
+
const token = Symbol(name), run = { token, daemon, timer: undefined };
|
|
713
|
+
this.nativeExitOwners.set(name, run);
|
|
714
|
+
const current = () => this.nativeExitOwners.get(name) === run && this.daemons.get(name) === daemon && this.epochOf(name) === epoch
|
|
715
|
+
&& 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()
|
|
716
|
+
&& (config.machine_id ? remoteRuntimeEnabled() : localWindowsCliEnabled());
|
|
717
|
+
daemon.fenceDeliveryWritesForStop();
|
|
718
|
+
try {
|
|
719
|
+
const decision = pin && profilePin ? new NativePaneCrashBudget(join(this.ctx.getInstanceDir(name), "native-crash-state.json")).observe(pin, data.snapshot.exitCode, config.restart_policy) : null;
|
|
720
|
+
await this.runTransition(name, async () => {
|
|
721
|
+
if (!current())
|
|
722
|
+
return;
|
|
723
|
+
if (!await daemon.waitForDeliveryWritesToDrain(RECONCILIATION_WRITE_DRAIN_TIMEOUT_MS) || !current())
|
|
724
|
+
throw Error("Native input writes have not drained");
|
|
725
|
+
if (this.ctx.deliveryOutbox) {
|
|
726
|
+
this.ctx.deliveryOutbox.markTargetReconciliationPending(name, daemon.bootId);
|
|
727
|
+
if (!await daemon.reconcileNativeDeliveries(this.ctx.deliveryOutbox, current) || !current())
|
|
728
|
+
throw Error("Native delivery reconciliation is unconfirmed");
|
|
729
|
+
}
|
|
730
|
+
// Close finalizes the exact positive exit; no PID lookup or signal exists on this path.
|
|
731
|
+
await daemon.stop({ nativePane: "close" });
|
|
732
|
+
if (!current())
|
|
733
|
+
return;
|
|
734
|
+
this.ctx.eventLog?.insert(name, "native_pane_exited", { exitCode: data.snapshot.exitCode ?? null, sessionId: pin, decision: decision?.kind ?? "no-conversation", count: decision?.count ?? 0 });
|
|
735
|
+
if (!decision) {
|
|
736
|
+
this.ctx.holdNativePaneRecovery?.(name, new NativePaneRecoveryError({ kind: "session-unconfirmed", launchId: data.snapshot.launchId, sessionId: this.ctx.nativePanePinnedSession?.(name) ?? undefined, ...(config.backend === "codex" ? { provider: "codex" } : {}) }));
|
|
737
|
+
this.ctx.setTopicIcon(name, "red");
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
if (decision.kind !== "retry") {
|
|
741
|
+
if (decision.kind === "normal")
|
|
742
|
+
await this.ctx.notifyNormalExit(name);
|
|
743
|
+
else
|
|
744
|
+
this.notifyIncident(name, decision.kind === "loop" ? "crash_loop" : "supervision_ended", t("inst.respawn_paused", name));
|
|
745
|
+
this.ctx.setTopicIcon(name, "red");
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const timer = setTimeout(() => {
|
|
749
|
+
run.timer = undefined;
|
|
750
|
+
void this.runTransition(name, async () => {
|
|
751
|
+
if (!current())
|
|
752
|
+
return;
|
|
753
|
+
await this.stopInTransition(name, token);
|
|
754
|
+
// Our own stop advances once. An operator's concurrent stop/config change prevents publication.
|
|
755
|
+
if (this.nativeExitOwners.get(name) !== run || this.epochOf(name) !== epoch + 1 || this.daemons.has(name)
|
|
756
|
+
|| this.ctx.fleetConfig?.instances[name] !== config || this.ctx.nativePanePinnedSession?.(name) !== pin || this.isPaused(name) || this.ctx.isPlannedRestart()
|
|
757
|
+
|| !(config.machine_id ? remoteRuntimeEnabled() : localWindowsCliEnabled()))
|
|
758
|
+
return;
|
|
759
|
+
await this.startInTransition(name, config, true, { kind: "fleet-topic", backend: config.backend ?? "codex", model: config.model || "default" });
|
|
760
|
+
if (this.nativeExitOwners.get(name) !== run || this.epochOf(name) !== epoch + 1 || this.ctx.isPlannedRestart())
|
|
761
|
+
return;
|
|
762
|
+
await this.ctx.connectIpcToInstance(name);
|
|
763
|
+
}).catch(error => { if (this.nativeExitOwners.get(name) === run && !this.ctx.isPlannedRestart()) {
|
|
764
|
+
if (this.ctx.holdNativePaneRecovery?.(name, error))
|
|
765
|
+
return;
|
|
766
|
+
this.ctx.logger.error({ name, err: error }, "Native conversation resume failed; its pin was retained");
|
|
767
|
+
this.notifyIncident(name, "supervision_ended", t("inst.respawn_paused", name));
|
|
768
|
+
} })
|
|
769
|
+
.finally(() => { this.cancelNativeRecovery(name, token); this.ctx.onNativePaneRecoverySettled?.(name); });
|
|
770
|
+
}, decision.delay);
|
|
771
|
+
timer.unref?.();
|
|
772
|
+
run.timer = timer;
|
|
773
|
+
});
|
|
774
|
+
if (!run.timer)
|
|
775
|
+
this.cancelNativeRecovery(name, token);
|
|
776
|
+
}
|
|
777
|
+
catch (error) {
|
|
778
|
+
if (this.nativeExitOwners.get(name) === run && !this.ctx.isPlannedRestart()) {
|
|
779
|
+
this.ctx.logger.error({ name, err: error }, "Native crash recovery held without a fresh fallback");
|
|
780
|
+
this.notifyIncident(name, "supervision_ended", t("inst.respawn_paused", name));
|
|
781
|
+
}
|
|
782
|
+
this.cancelNativeRecovery(name, token);
|
|
783
|
+
}
|
|
784
|
+
finally {
|
|
785
|
+
if (!run.timer)
|
|
786
|
+
this.ctx.onNativePaneRecoverySettled?.(name);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
685
789
|
attachIncidentHandlers(name, daemon) {
|
|
790
|
+
if (daemon.usesNativePane?.())
|
|
791
|
+
daemon.on("native_pane_exited", safeHandler((data) => this.nativePaneExited(name, daemon, data), this.ctx.logger, `daemon.native_pane_exited[${name}]`));
|
|
686
792
|
daemon.on("capacity_nudge_cancelled", safeHandler((data) => {
|
|
687
793
|
const reason = data.reason === "the user cancelled" ? t("inst.codex_retry_cancel_reason_user")
|
|
688
794
|
: 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 +1087,22 @@ export class InstanceLifecycle {
|
|
|
981
1087
|
// labels, summaries and every exhaustive match for one picker's text.)
|
|
982
1088
|
// #1691: a prompt no table knows — what it asks (one sanitised, bounded line from the daemon, never the pane), and
|
|
983
1089
|
// that AgEnD will not press anything.
|
|
1090
|
+
// S-35: a Windows agent's instance name is windows-<uuid>; people know it by its display name.
|
|
1091
|
+
const label = this.ctx.fleetConfig?.instances[name]?.display_name?.trim() || name;
|
|
1092
|
+
const place = placeRef({ kind: "instance", name }, label);
|
|
984
1093
|
if (data.unrecognised) {
|
|
985
1094
|
// #1990: the question is a pane line — it may not name a place of its own.
|
|
986
1095
|
const asked = data.question ? t("inst.unrecognised_prompt_question", noPlaceMarkers(data.question)) : "";
|
|
987
|
-
this.notifyParked(name, "dialog_parked", t("inst.unrecognised_prompt",
|
|
1096
|
+
this.notifyParked(name, "dialog_parked", t("inst.unrecognised_prompt", label, asked), t("fleet.unrecognised_prompt", place, asked));
|
|
988
1097
|
return;
|
|
989
1098
|
}
|
|
990
1099
|
const category = data.kind && data.kind !== "dialog" ? interactionCategory(data.kind, data.backend) : null;
|
|
991
|
-
const text = category ? t("inst.interaction_parked",
|
|
1100
|
+
const text = category ? t("inst.interaction_parked", label, category) : data.holdOnly
|
|
992
1101
|
// #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",
|
|
1102
|
+
? t("inst.dialog_parked_hold", label, data.description) + (data.advice === "claude-resume" ? " " + t("inst.dialog_parked_hold_claude_resume") : "")
|
|
1103
|
+
: t("inst.dialog_parked_stuck", label, data.description) + (data.advice === "claude-resume" ? " " + t("inst.dialog_parked_stuck_claude_resume") : "");
|
|
995
1104
|
// #1990: in General, the instance's name links to its topic.
|
|
996
|
-
this.notifyParked(name, "dialog_parked", text, category ? t("fleet.interaction_parked",
|
|
1105
|
+
this.notifyParked(name, "dialog_parked", text, category ? t("fleet.interaction_parked", place, category) : t("fleet.dialog_parked", place, data.description));
|
|
997
1106
|
}, this.ctx.logger, `daemon.dialog_parked[${name}]`));
|
|
998
1107
|
// #2897: the held dialog is gone (closed, answered, auto-answered) — its notices go with it.
|
|
999
1108
|
daemon.on("dialog_unparked", safeHandler(() => this.ctx.resolveParkedNotice?.(name), this.ctx.logger, `daemon.dialog_unparked[${name}]`));
|
|
@@ -1030,6 +1139,21 @@ export class InstanceLifecycle {
|
|
|
1030
1139
|
daemon.on("pty_error", safeHandler(async (data) => {
|
|
1031
1140
|
this.ctx.eventLog?.insert(name, "pty_error", { type: data.type, action: data.action });
|
|
1032
1141
|
this.ctx.logger.warn({ name, errorType: data.type, action: data.action }, `PTY error: ${data.message}`);
|
|
1142
|
+
if (daemon.usesNativePane?.()) {
|
|
1143
|
+
// Native credentials and quotas belong to its runner. Never probe a Linux login or group its peers with it.
|
|
1144
|
+
if (this.daemons.get(name) !== daemon)
|
|
1145
|
+
return;
|
|
1146
|
+
this.notifyIncident(name, data.type, data.notice ?? data.message);
|
|
1147
|
+
if (data.action === "pause") {
|
|
1148
|
+
if (data.type === "auth_error") {
|
|
1149
|
+
daemon.confirmAuthFailure?.();
|
|
1150
|
+
daemon.requestPauseWhenIdle({ reconfirmAuth: true, reason: "auth" });
|
|
1151
|
+
}
|
|
1152
|
+
else
|
|
1153
|
+
daemon.requestPauseWhenIdle({ reason: "error" });
|
|
1154
|
+
}
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1033
1157
|
// Antigravity's account-level cap is visible ONLY here: the quota summary
|
|
1034
1158
|
// API keeps reporting its buckets as barely used while the CLI is blocked
|
|
1035
1159
|
// (verified live — 0% used and "Individual quota reached" in the same
|
|
@@ -1366,7 +1490,10 @@ export class InstanceLifecycle {
|
|
|
1366
1490
|
return this.lifecycleEpochs.get(name) ?? 0;
|
|
1367
1491
|
}
|
|
1368
1492
|
/** Invalidate every start/wake already running for `name` (they will not publish). */
|
|
1369
|
-
invalidate(name) {
|
|
1493
|
+
invalidate(name, nativeOwner) {
|
|
1494
|
+
const native = this.nativeExitOwners.get(name);
|
|
1495
|
+
if (native && native.token !== nativeOwner)
|
|
1496
|
+
this.cancelNativeRecovery(name);
|
|
1370
1497
|
this.lifecycleEpochs.set(name, this.epochOf(name) + 1);
|
|
1371
1498
|
}
|
|
1372
1499
|
/** Whether `transition` is `name`'s transition and is the one running now. */
|
|
@@ -1440,156 +1567,178 @@ export class InstanceLifecycle {
|
|
|
1440
1567
|
this.ctx.logger.info({ name }, "Instance already running, skipping");
|
|
1441
1568
|
return;
|
|
1442
1569
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
// Unless IS_SANDBOX=1 is set (recognized sandbox environment)
|
|
1470
|
-
if (process.getuid?.() === 0 && backendName === "claude-code" && !process.env.IS_SANDBOX) {
|
|
1471
|
-
const msg = `⚠️ claude-code cannot run with --dangerously-skip-permissions as root. Set IS_SANDBOX=1 or use a non-root user.`;
|
|
1472
|
-
this.ctx.logger.error({ name, backend: backendName }, msg);
|
|
1473
|
-
this.ctx.notifyInstanceTopic(name, t("inst.root_skip_perms"));
|
|
1474
|
-
return;
|
|
1475
|
-
}
|
|
1476
|
-
const backend = createBackend(backendName, instanceDir);
|
|
1477
|
-
const daemon = new Daemon(name, config, instanceDir, topicMode, backend, this.ctx.controlClient ?? undefined, this.ctx.logger, runtimeIdentity ?? {
|
|
1478
|
-
kind: "fleet-topic",
|
|
1479
|
-
backend: backendName,
|
|
1480
|
-
model: config.model ?? "default",
|
|
1481
|
-
}, this.ctx.spawnGate, this.ctx.stormWindow, this.ctx.backendOutage);
|
|
1482
|
-
daemon.setDeliveryOutboxPort(this.ctx.deliveryOutbox ?? undefined);
|
|
1483
|
-
daemon.setWorkLeaseCheck(() => this.hasWorkLease(name));
|
|
1484
|
-
if (seedNow)
|
|
1485
|
-
daemon.seedActivityNow();
|
|
1486
|
-
// Read at each spawn so a fleet.yaml reload is honoured (#984).
|
|
1487
|
-
daemon.setPeerWorkingDirectories(backendName === "kiro-cli"
|
|
1488
|
-
? this.ctx.kiroPeerWorkingDirectories ? () => this.ctx.kiroPeerWorkingDirectories(name) : undefined
|
|
1489
|
-
: () => peerWorkingDirectories(this.ctx.fleetConfig, name, backendName));
|
|
1490
|
-
daemon.setStatusEmojiAvoidList(() => this.ctx.statusEmojiAvoidList?.(name));
|
|
1491
|
-
// Before start: the first spawn builds the command and emits its launch
|
|
1492
|
-
// warning synchronously inside Daemon.start, long before
|
|
1493
|
-
// attachIncidentHandlers runs (#984).
|
|
1494
|
-
this.attachLaunchWarningHandler(name, daemon);
|
|
1495
|
-
this.attachContextLostHandler(name, daemon);
|
|
1496
|
-
daemon.on("durable_delivery_deferred", (data) => {
|
|
1497
|
-
// A daemon without its outbox port cannot update the row directly. The
|
|
1498
|
-
// lifecycle owns the same-process store and records a bounded pre-write
|
|
1499
|
-
// retry instead of leaving the lane in delivering forever.
|
|
1500
|
-
this.ctx.deliveryOutbox?.retryBeforeBegin(data.deliveryId, data.targetBootId, data.attemptNo, data.reason, 5_000);
|
|
1501
|
-
});
|
|
1502
|
-
daemon.on("mcp_tool_response_written", (data) => {
|
|
1503
|
-
if (!data.operationId || data.daemonBootId !== daemon.bootId)
|
|
1570
|
+
const native = isNativePaneInstance(config) ? await this.ctx.nativePaneFor?.(name, config, check) : undefined;
|
|
1571
|
+
let nativePublished = false;
|
|
1572
|
+
try {
|
|
1573
|
+
check();
|
|
1574
|
+
if (isNativePaneInstance(config) && !native)
|
|
1575
|
+
throw Error("Native pane ownership is unavailable; no local CLI was started");
|
|
1576
|
+
if (native)
|
|
1577
|
+
config = { ...config, agent_mode: "mcp" };
|
|
1578
|
+
if (!native && !existsSync(config.working_directory)) {
|
|
1579
|
+
this.ctx.logger.info({ name, working_directory: config.working_directory }, "Working directory does not exist — creating it");
|
|
1580
|
+
mkdirSync(config.working_directory, { recursive: true });
|
|
1581
|
+
}
|
|
1582
|
+
const instanceDir = this.ctx.getInstanceDir(name);
|
|
1583
|
+
ensureInstanceDir(instanceDir);
|
|
1584
|
+
// Daemon.start consumes the recovery marker after reading it. A start
|
|
1585
|
+
// that fails before reaching the daemon must leave that intent intact.
|
|
1586
|
+
const { Daemon } = await import("./daemon.js");
|
|
1587
|
+
const { createBackend } = await import("./backend/factory.js");
|
|
1588
|
+
check();
|
|
1589
|
+
const backendName = config.backend ?? this.ctx.fleetConfig?.defaults?.backend ?? "claude-code";
|
|
1590
|
+
// A removed backend (#1280): this instance refuses to start, says why and what to use instead, and the rest of
|
|
1591
|
+
// the fleet is unaffected. Never a fallback to another backend.
|
|
1592
|
+
if (isRemovedBackend(backendName)) {
|
|
1593
|
+
const message = removedBackendMessage(backendName, name);
|
|
1594
|
+
this.ctx.logger.error({ name, backend: backendName }, `Not starting: ${message}`);
|
|
1595
|
+
this.ctx.notifyInstanceTopic(name, t("inst.backend_removed", name, backendName, REMOVED_BACKENDS[backendName].replacement));
|
|
1504
1596
|
return;
|
|
1505
|
-
try {
|
|
1506
|
-
this.ctx.deliveryOutbox?.markResponseDelivered(name, data.operationId);
|
|
1507
1597
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1598
|
+
// Verify backend binary is in PATH before spawning
|
|
1599
|
+
const installation = BACKEND_INSTALLATION_INFO[backendName];
|
|
1600
|
+
if (!native && installation && !checkBinaryInstalled(installation.binary)) {
|
|
1601
|
+
this.ctx.logger.error({ binary: installation.binary, backend: backendName, instance: name }, `Backend binary "${installation.binary}" not found in PATH`);
|
|
1602
|
+
}
|
|
1603
|
+
// claude-code refuses --dangerously-skip-permissions as root — fail fast
|
|
1604
|
+
// Unless IS_SANDBOX=1 is set (recognized sandbox environment)
|
|
1605
|
+
if (!native && process.getuid?.() === 0 && backendName === "claude-code" && !process.env.IS_SANDBOX) {
|
|
1606
|
+
const msg = `⚠️ claude-code cannot run with --dangerously-skip-permissions as root. Set IS_SANDBOX=1 or use a non-root user.`;
|
|
1607
|
+
this.ctx.logger.error({ name, backend: backendName }, msg);
|
|
1608
|
+
this.ctx.notifyInstanceTopic(name, t("inst.root_skip_perms"));
|
|
1609
|
+
return;
|
|
1510
1610
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
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
|
-
|
|
1611
|
+
const backend = native?.backend ?? createBackend(backendName, instanceDir);
|
|
1612
|
+
const daemon = new Daemon(name, config, instanceDir, topicMode, backend, this.ctx.controlClient ?? undefined, this.ctx.logger, runtimeIdentity ?? {
|
|
1613
|
+
kind: "fleet-topic",
|
|
1614
|
+
backend: backendName,
|
|
1615
|
+
model: config.model ?? "default",
|
|
1616
|
+
}, this.ctx.spawnGate, this.ctx.stormWindow, this.ctx.backendOutage);
|
|
1617
|
+
if (native) {
|
|
1618
|
+
daemon.setNativePaneLifecycle(native);
|
|
1619
|
+
native.bindDaemon?.(daemon);
|
|
1620
|
+
}
|
|
1621
|
+
daemon.setDeliveryOutboxPort(this.ctx.deliveryOutbox ?? undefined);
|
|
1622
|
+
daemon.setWorkLeaseCheck(() => this.hasWorkLease(name));
|
|
1623
|
+
if (seedNow)
|
|
1624
|
+
daemon.seedActivityNow();
|
|
1625
|
+
// Read at each spawn so a fleet.yaml reload is honoured (#984).
|
|
1626
|
+
daemon.setPeerWorkingDirectories(backendName === "kiro-cli"
|
|
1627
|
+
? this.ctx.kiroPeerWorkingDirectories ? () => this.ctx.kiroPeerWorkingDirectories(name) : undefined
|
|
1628
|
+
: () => peerWorkingDirectories(this.ctx.fleetConfig, name, backendName));
|
|
1629
|
+
daemon.setStatusEmojiAvoidList(() => this.ctx.statusEmojiAvoidList?.(name));
|
|
1630
|
+
// Before start: the first spawn builds the command and emits its launch
|
|
1631
|
+
// warning synchronously inside Daemon.start, long before
|
|
1632
|
+
// attachIncidentHandlers runs (#984).
|
|
1633
|
+
this.attachLaunchWarningHandler(name, daemon);
|
|
1634
|
+
this.attachContextLostHandler(name, daemon);
|
|
1635
|
+
daemon.on("durable_delivery_deferred", (data) => {
|
|
1636
|
+
// A daemon without its outbox port cannot update the row directly. The
|
|
1637
|
+
// lifecycle owns the same-process store and records a bounded pre-write
|
|
1638
|
+
// retry instead of leaving the lane in delivering forever.
|
|
1639
|
+
this.ctx.deliveryOutbox?.retryBeforeBegin(data.deliveryId, data.targetBootId, data.attemptNo, data.reason, 5_000);
|
|
1640
|
+
});
|
|
1641
|
+
daemon.on("mcp_tool_response_written", (data) => {
|
|
1642
|
+
if (!data.operationId || data.daemonBootId !== daemon.bootId)
|
|
1643
|
+
return;
|
|
1644
|
+
try {
|
|
1645
|
+
this.ctx.deliveryOutbox?.markResponseDelivered(name, data.operationId);
|
|
1646
|
+
}
|
|
1647
|
+
catch (err) {
|
|
1648
|
+
this.ctx.logger.error({ name, operationId: data.operationId, err }, "Could not persist MCP response-delivered marker");
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
this.applyCapacityBackoffBaseline(name, backendName, daemon);
|
|
1652
|
+
// Catch errors from daemon internals (e.g. IPC server) to prevent crashing the fleet process
|
|
1653
|
+
daemon.on("error", (err) => {
|
|
1654
|
+
this.ctx.logger.error({ err, name }, "Daemon emitted error — instance isolated");
|
|
1655
|
+
});
|
|
1656
|
+
if (this.ctx.deliveryOutbox) {
|
|
1657
|
+
// Fence older-generation submissions and reconcile them before Daemon.start
|
|
1658
|
+
// reaches Strategy A's unconditional old-window kill.
|
|
1659
|
+
const recovered = this.ctx.deliveryOutbox.recoverTargetGeneration(name, daemon.bootId);
|
|
1660
|
+
if (recovered.queued || recovered.reconciliationPending) {
|
|
1661
|
+
this.ctx.logger.warn({ name, ...recovered }, "Preparing durable outbox rows before target generation start");
|
|
1662
|
+
}
|
|
1663
|
+
const reconciled = native
|
|
1664
|
+
? { uncertain: 0, safeToStart: await this.ctx.reconcileNativePaneBeforeStart?.(name, daemon) === true }
|
|
1665
|
+
: await reconcileTargetBeforeStart(this.ctx.deliveryOutbox, name, instanceDir, this.ctx.logger);
|
|
1666
|
+
if (reconciled.uncertain > 0) {
|
|
1667
|
+
this.ctx.logger.warn({ name, ...reconciled }, "Some durable submissions need operator reconciliation");
|
|
1668
|
+
}
|
|
1669
|
+
if (!reconciled.safeToStart) {
|
|
1670
|
+
const message = t("delivery.restart_blocked", name);
|
|
1671
|
+
this.ctx.logger.error({ name, ...reconciled }, message);
|
|
1672
|
+
this.ctx.notifyFleetError?.(message);
|
|
1673
|
+
await daemon.abortStartup().catch(err => this.ctx.logger.warn({ err, name }, "Failed to dispose daemon after reconciliation could not verify old CLI exit"));
|
|
1674
|
+
throw new Error(message);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
if (this.epochOf(name) !== epoch || execution && !execution.current()) {
|
|
1678
|
+
// A stop/restart arrived while this start was reconciling: do not spawn.
|
|
1679
|
+
await daemon.abortStartup().catch(() => { });
|
|
1680
|
+
throw new SupersededStartError(name);
|
|
1681
|
+
}
|
|
1682
|
+
// The startup scan can raise an incident (sign-in screen, fatal modal)
|
|
1683
|
+
// before the handlers below exist and before this daemon is registered;
|
|
1684
|
+
// hold it and deliver it once both are true.
|
|
1685
|
+
daemon.holdStartupIncidents?.();
|
|
1686
|
+
await InstanceLifecycle.startOrDispose(daemon, name, this.ctx.logger, execution || native ? check : undefined);
|
|
1687
|
+
// Publication fence (Phase 2a): the spawn cannot be cancelled, so a stop or
|
|
1688
|
+
// restart requested meanwhile has been waiting behind this transition. A
|
|
1689
|
+
// superseded start must not register, signal ready, or keep its window.
|
|
1690
|
+
if (this.epochOf(name) !== epoch || execution && !execution.current()) {
|
|
1691
|
+
await daemon.abortStartup().catch(err => this.ctx.logger.warn({ err, name }, "Failed to dispose a superseded start"));
|
|
1692
|
+
throw new SupersededStartError(name);
|
|
1693
|
+
}
|
|
1694
|
+
this.capacityBackoffBaselines.delete(name);
|
|
1695
|
+
this.daemons.set(name, daemon);
|
|
1696
|
+
nativePublished = !!native;
|
|
1697
|
+
published?.(daemon); // Exact publication, synchronously after the ownership fence.
|
|
1698
|
+
if (seedNow)
|
|
1699
|
+
this.noteWokeForWork(name);
|
|
1700
|
+
this.ctx.onDaemonReady?.(name, daemon.bootId);
|
|
1701
|
+
daemon.on("auto_pause_requested", safeHandler(async (data) => {
|
|
1702
|
+
await this.pause(name, data?.reason ?? "idle");
|
|
1703
|
+
}, this.ctx.logger, `autoPause[${name}]`));
|
|
1704
|
+
daemon.on("auto_paused", (data) => {
|
|
1705
|
+
this.ctx.eventLog?.insert(name, "instance_paused", { reason: "idle", paused_at: data.pausedAt });
|
|
1706
|
+
this.ctx.logger.info({ name, pausedAt: data.pausedAt }, "Instance auto-paused after idle timeout");
|
|
1707
|
+
this.ctx.setTopicIcon(name, "remove");
|
|
1708
|
+
this.ctx.onAttentionChanged?.(name);
|
|
1709
|
+
});
|
|
1710
|
+
daemon.on("auto_woke", () => {
|
|
1711
|
+
this.ctx.onAttentionChanged?.(name);
|
|
1712
|
+
this.ctx.eventLog?.insert(name, "instance_resumed", { reason: "message" });
|
|
1713
|
+
this.ctx.logger.info({ name }, "Instance auto-woke for delivery");
|
|
1714
|
+
this.ctx.setTopicIcon(name, "green");
|
|
1715
|
+
this.ctx.touchActivity(name);
|
|
1716
|
+
});
|
|
1717
|
+
this.attachIncidentHandlers(name, daemon);
|
|
1718
|
+
// #2897: a new daemon starts with no dialog held; a notice the last one left (a crash, a respawn) is out of date.
|
|
1719
|
+
this.ctx.resolveParkedNotice?.(name);
|
|
1720
|
+
daemon.on("pty_recovered", safeHandler((data) => {
|
|
1721
|
+
const mins = Math.floor(data.downtime_s / 60);
|
|
1722
|
+
const secs = data.downtime_s % 60;
|
|
1723
|
+
const duration = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
1724
|
+
this.ctx.eventLog?.insert(name, "pty_recovered", { downtime_s: data.downtime_s });
|
|
1725
|
+
this.ctx.logger.info({ name, downtime_s: data.downtime_s }, "PTY error recovered");
|
|
1726
|
+
this.ctx.notifyInstanceTopic(name, t("inst.recovered", name, duration));
|
|
1727
|
+
this.ctx.webhookEmit("pty_recovered", name, { downtime_s: data.downtime_s });
|
|
1728
|
+
}, this.ctx.logger, `daemon.pty_recovered[${name}]`));
|
|
1729
|
+
this.attachDeliveryStatusHandlers(name, daemon);
|
|
1572
1730
|
this.ctx.setTopicIcon(name, "green");
|
|
1573
1731
|
this.ctx.touchActivity(name);
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
this.ctx.notifyInstanceTopic(name, t("inst.recovered", name, duration));
|
|
1585
|
-
this.ctx.webhookEmit("pty_recovered", name, { downtime_s: data.downtime_s });
|
|
1586
|
-
}, this.ctx.logger, `daemon.pty_recovered[${name}]`));
|
|
1587
|
-
this.attachDeliveryStatusHandlers(name, daemon);
|
|
1588
|
-
this.ctx.setTopicIcon(name, "green");
|
|
1589
|
-
this.ctx.touchActivity(name);
|
|
1590
|
-
// Last: handlers attached and daemon registered, so a held startup incident
|
|
1591
|
-
// (pause, notify) finds both.
|
|
1592
|
-
daemon.releaseStartupIncidents?.();
|
|
1732
|
+
// Last: handlers attached and daemon registered, so a held startup incident
|
|
1733
|
+
// (pause, notify) finds both.
|
|
1734
|
+
daemon.releaseStartupIncidents?.();
|
|
1735
|
+
}
|
|
1736
|
+
catch (error) {
|
|
1737
|
+
// The factory registered helper authority before acquire(). A superseded pre-window start must release it too.
|
|
1738
|
+
if (native && !nativePublished)
|
|
1739
|
+
await native.release("detach").catch(err => this.ctx.logger.warn({ name, err }, "Prepared native authority could not detach"));
|
|
1740
|
+
throw error;
|
|
1741
|
+
}
|
|
1593
1742
|
}
|
|
1594
1743
|
isPaused(name) {
|
|
1595
1744
|
return this.daemons.get(name)?.isPaused ?? hasPausedMarker(this.ctx.getInstanceDir(name));
|
|
@@ -1598,11 +1747,30 @@ export class InstanceLifecycle {
|
|
|
1598
1747
|
return this.daemons.get(name)?.lastPausedAt ?? readPausedAt(this.ctx.getInstanceDir(name));
|
|
1599
1748
|
}
|
|
1600
1749
|
async pause(name, reason = "operator", admission) {
|
|
1750
|
+
this.cancelNativeRecovery(name);
|
|
1601
1751
|
// Final backstop shared by slash, MCP, Settings, warm-cap, and any future
|
|
1602
1752
|
// caller. General is the coordinator and must remain resident to route work.
|
|
1603
1753
|
if (isGeneralInstance(this.ctx.fleetConfig, name)) {
|
|
1604
1754
|
throw new Error(GENERAL_PAUSE_ERROR);
|
|
1605
1755
|
}
|
|
1756
|
+
const nativeDaemon = this.daemons.get(name);
|
|
1757
|
+
if (nativeDaemon?.usesNativePane?.()) {
|
|
1758
|
+
if (admission && !admission.current())
|
|
1759
|
+
return;
|
|
1760
|
+
await this.runTransition(name, async () => {
|
|
1761
|
+
if (this.daemons.get(name) !== nativeDaemon || admission && !admission.current())
|
|
1762
|
+
return;
|
|
1763
|
+
if (!nativeDaemon.nativePaneHasExited() && (!await nativeDaemon.nativePauseReady(admission) || this.daemons.get(name) !== nativeDaemon || !nativeDaemon.nativePauseStillReady()))
|
|
1764
|
+
return;
|
|
1765
|
+
if (this.daemons.get(name) !== nativeDaemon || admission && !admission.current())
|
|
1766
|
+
return;
|
|
1767
|
+
await this.stopInTransition(name);
|
|
1768
|
+
this.ctx.setNativePanePaused?.(name, true);
|
|
1769
|
+
writePausedMarker(this.ctx.getInstanceDir(name), Date.now(), reason);
|
|
1770
|
+
this.ctx.onAttentionChanged?.(name);
|
|
1771
|
+
});
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1606
1774
|
// B1: cancel any pending capacity backoff — a user-initiated pause should
|
|
1607
1775
|
// not be undone by a queued restart 30–120s later.
|
|
1608
1776
|
const pendingBackoff = this.capacityBackoffTimers.get(name);
|
|
@@ -1686,16 +1854,21 @@ export class InstanceLifecycle {
|
|
|
1686
1854
|
clearPausedMarker(instanceDir);
|
|
1687
1855
|
this.markActivitySeedNow(name);
|
|
1688
1856
|
try {
|
|
1857
|
+
if (isNativePaneInstance(this.ctx.fleetConfig?.instances[name]))
|
|
1858
|
+
this.ctx.setNativePanePaused?.(name, false);
|
|
1689
1859
|
await this.ctx.startPersistedPausedInstance(name, transition);
|
|
1690
1860
|
}
|
|
1691
1861
|
catch (err) {
|
|
1692
1862
|
this.clearActivitySeedNow(name);
|
|
1693
1863
|
writePausedMarker(instanceDir, pausedAt, reason);
|
|
1864
|
+
if (isNativePaneInstance(this.ctx.fleetConfig?.instances[name]))
|
|
1865
|
+
this.ctx.setNativePanePaused?.(name, true);
|
|
1694
1866
|
throw err;
|
|
1695
1867
|
}
|
|
1696
1868
|
}
|
|
1697
1869
|
this.noteWokeForWork(name);
|
|
1698
|
-
this.ctx.
|
|
1870
|
+
if (!isNativePaneInstance(this.ctx.fleetConfig?.instances[name]))
|
|
1871
|
+
this.ctx.startStatuslineWatcher(name);
|
|
1699
1872
|
}
|
|
1700
1873
|
/**
|
|
1701
1874
|
* Ownership boundary for a daemon that is not yet registered: if start()
|
|
@@ -1729,8 +1902,8 @@ export class InstanceLifecycle {
|
|
|
1729
1902
|
this.invalidate(name);
|
|
1730
1903
|
return this.runTransition(name, () => this.stopInTransition(name), transition);
|
|
1731
1904
|
}
|
|
1732
|
-
async stopInTransition(name) {
|
|
1733
|
-
this.invalidate(name);
|
|
1905
|
+
async stopInTransition(name, nativeOwner) {
|
|
1906
|
+
this.invalidate(name, nativeOwner);
|
|
1734
1907
|
this.wokeAt.delete(name);
|
|
1735
1908
|
this.ctx.setTopicIcon(name, "remove");
|
|
1736
1909
|
// #2897: a stopped instance holds no dialog — its "needs a human" notices are out of date.
|
|
@@ -1755,11 +1928,20 @@ export class InstanceLifecycle {
|
|
|
1755
1928
|
if (!drained)
|
|
1756
1929
|
this.ctx.logger.warn({ name }, "Pane write did not drain before durable reconciliation capture; relying on the Enter write-ahead fence");
|
|
1757
1930
|
this.ctx.deliveryOutbox.markTargetReconciliationPending(name, daemon.bootId);
|
|
1758
|
-
|
|
1931
|
+
if (daemon.usesNativePane?.()) {
|
|
1932
|
+
const reconciled = await daemon.reconcileNativeDeliveries(this.ctx.deliveryOutbox, () => this.daemons.get(name) === daemon);
|
|
1933
|
+
if (!reconciled)
|
|
1934
|
+
this.ctx.logger.warn({ name }, "Native stop could not settle every old delivery; retained attempts will not be replayed");
|
|
1935
|
+
}
|
|
1936
|
+
if (!daemon.usesNativePane?.())
|
|
1937
|
+
captured = await capturePendingTargetReconciliation(this.ctx.deliveryOutbox, name, this.ctx.getInstanceDir(name), getTmuxSession(), this.ctx.logger);
|
|
1759
1938
|
}
|
|
1760
1939
|
let stopped = false;
|
|
1761
1940
|
try {
|
|
1762
|
-
|
|
1941
|
+
if (daemon.usesNativePane?.())
|
|
1942
|
+
await daemon.stop({ nativePane: "close" });
|
|
1943
|
+
else
|
|
1944
|
+
await daemon.stop();
|
|
1763
1945
|
stopped = true;
|
|
1764
1946
|
}
|
|
1765
1947
|
finally {
|
|
@@ -1789,6 +1971,11 @@ export class InstanceLifecycle {
|
|
|
1789
1971
|
if (this.daemons.get(name) === daemon)
|
|
1790
1972
|
this.daemons.delete(name);
|
|
1791
1973
|
}
|
|
1974
|
+
else if (isNativePaneInstance(this.ctx.fleetConfig?.instances[name])) {
|
|
1975
|
+
if (!this.ctx.closeRetainedNativePane)
|
|
1976
|
+
throw Error("Retained native pane owner is unavailable; no local PID was signalled");
|
|
1977
|
+
await this.ctx.closeRetainedNativePane(name);
|
|
1978
|
+
}
|
|
1792
1979
|
else {
|
|
1793
1980
|
const instanceDir = this.ctx.getInstanceDir(name);
|
|
1794
1981
|
const pidPath = join(instanceDir, "daemon.pid");
|
|
@@ -1975,6 +2162,21 @@ export class InstanceLifecycle {
|
|
|
1975
2162
|
async handleCreate(args, respond, adapterId, execution) {
|
|
1976
2163
|
const check = () => execution?.assert();
|
|
1977
2164
|
check();
|
|
2165
|
+
if (args.runtime !== undefined && args.runtime !== "wsl" && args.runtime !== "windows") {
|
|
2166
|
+
respond(null, "Unknown instance runtime");
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
// M-2239 P1-1: a Windows agent is created only from the admin web dashboard (native-instance-api.ts), never through
|
|
2170
|
+
// create_instance, deploy_template or any other path that reaches here — an agent holding create_instance could
|
|
2171
|
+
// otherwise start one on the Windows host, in any drive path, with write access.
|
|
2172
|
+
if (args.runtime === "windows") {
|
|
2173
|
+
respond(null, WINDOWS_CREATE_REFUSED);
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
if (args.sandbox !== undefined) {
|
|
2177
|
+
respond(null, "sandbox is supported only by the Windows runtime");
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
1978
2180
|
const rawDirectory = args.directory;
|
|
1979
2181
|
const directory = rawDirectory ? rawDirectory.replace(/^~/, process.env.HOME || "~") : undefined;
|
|
1980
2182
|
const topicName = args.topic_name || (directory ? basename(directory) : undefined);
|