@songsid/agend 2.3.5-alpha.5 → 2.3.5-beta.1
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 +0 -2
- package/README.zh-TW.md +0 -2
- package/THIRD_PARTY_NOTICES.md +0 -68
- package/dist/agent-endpoint.d.ts +1 -5
- package/dist/agent-endpoint.js +2 -12
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.js +1 -1
- package/dist/agent-file-read.js.map +1 -1
- package/dist/auth-api.d.ts +0 -48
- package/dist/auth-api.js +4 -250
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/session-authorizations.d.ts +2 -0
- package/dist/authority/session-authorizations.js +7 -1
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +2 -12
- package/dist/authority/web-authority.js +4 -25
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/claude-code.d.ts +12 -15
- package/dist/backend/claude-code.js +133 -152
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-footer-hints.d.ts +0 -3
- package/dist/backend/codex-footer-hints.js +0 -14
- package/dist/backend/codex-footer-hints.js.map +1 -1
- package/dist/backend/codex-package.d.ts +2 -5
- package/dist/backend/codex-package.js +5 -1
- package/dist/backend/codex-package.js.map +1 -1
- package/dist/backend/codex-quota-history.js +19 -4
- package/dist/backend/codex-quota-history.js.map +1 -1
- package/dist/backend/codex.d.ts +115 -142
- package/dist/backend/codex.js +1094 -1187
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.d.ts +0 -2
- package/dist/backend/grok.js +0 -22
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/types.d.ts +2 -7
- package/dist/backend/types.js.map +1 -1
- package/dist/bundled-tmux-guard.d.ts +21 -0
- package/dist/bundled-tmux-guard.js +96 -0
- package/dist/bundled-tmux-guard.js.map +1 -0
- package/dist/channel/ipc-bridge.d.ts +0 -2
- package/dist/channel/mcp-tools.js +2 -2
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +2 -0
- package/dist/classic-channel-manager.js +5 -1
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +30 -127
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +13 -74
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +3 -17
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +5 -72
- package/dist/daemon.js +275 -869
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +3 -15
- package/dist/delivery-consumed-watch.js +1 -23
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.d.ts +0 -5
- package/dist/delivery-outbox.js +4 -32
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +42 -2
- package/dist/delivery-reconciliation.js +164 -2
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/doctor.js +9 -20
- package/dist/doctor.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 +0 -2
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +9 -498
- package/dist/fleet-manager.js +202 -2849
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-instance.d.ts +0 -7
- package/dist/general-instance.js +3 -20
- package/dist/general-instance.js.map +1 -1
- package/dist/general-knowledge/skills/concepts/SKILL.md +18 -50
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +2 -5
- package/dist/general-knowledge/skills/fleet-health/SKILL.md +2 -2
- package/dist/general-knowledge/skills/session-management/SKILL.md +1 -1
- package/dist/general-knowledge/skills/tui-effort/SKILL.md +10 -10
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +13 -23
- package/dist/instance-config-impact.js +4 -8
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +3 -22
- package/dist/instance-lifecycle.js +176 -393
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +0 -2
- package/dist/instructions.js +0 -6
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +2 -147
- package/dist/locale.js.map +1 -1
- package/dist/login-flows.d.ts +7 -8
- package/dist/login-flows.js +1 -24
- package/dist/login-flows.js.map +1 -1
- package/dist/ls-rows.js +4 -3
- package/dist/ls-rows.js.map +1 -1
- package/dist/muse-usage-relay.d.ts +2 -0
- package/dist/muse-usage-relay.js +5 -3
- package/dist/muse-usage-relay.js.map +1 -1
- package/dist/needs-you-hub.d.ts +0 -5
- package/dist/needs-you-hub.js +2 -18
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +2 -45
- package/dist/needs-you.js +2 -26
- package/dist/needs-you.js.map +1 -1
- package/dist/office-share-page.js +3 -3
- package/dist/office-share-page.js.map +1 -1
- package/dist/office-share.d.ts +0 -11
- package/dist/office-share.js +0 -14
- package/dist/office-share.js.map +1 -1
- package/dist/outbound-handlers.d.ts +2 -30
- package/dist/outbound-handlers.js +4 -109
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +1 -71
- package/dist/outbound-schemas.js +14 -36
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-quota-history.d.ts +0 -2
- package/dist/pane-quota-history.js +0 -20
- package/dist/pane-quota-history.js.map +1 -1
- package/dist/pause-marker.d.ts +1 -1
- package/dist/pause-marker.js +1 -1
- package/dist/pause-marker.js.map +1 -1
- package/dist/public-web-gateway.js +0 -16
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +0 -11
- package/dist/public-web-link.js +0 -13
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.js +5 -9
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +0 -6
- package/dist/quickstart.js +6 -44
- package/dist/quickstart.js.map +1 -1
- package/dist/quota-notice-config.d.ts +22 -0
- package/dist/quota-notice-config.js +41 -0
- package/dist/quota-notice-config.js.map +1 -0
- package/dist/scheduler/task-board-text.js +1 -1
- package/dist/scheduler/task-board-text.js.map +1 -1
- package/dist/scheduler/task-board.d.ts +0 -4
- package/dist/scheduler/task-board.js +3 -9
- package/dist/scheduler/task-board.js.map +1 -1
- package/dist/service-installer.d.ts +2 -7
- package/dist/service-installer.js +10 -13
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.d.ts +0 -12
- package/dist/settings-api.js +7 -487
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.d.ts +0 -7
- package/dist/settings-baseline.js +1 -3
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.js +7 -35
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +1 -16
- package/dist/settings-confirmation.js +9 -47
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.d.ts +0 -17
- package/dist/settings-effect.js +1 -155
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +0 -4
- package/dist/settings-http-confirmation.js +3 -43
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-instance-patch.js +1 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/settings-request-capability.d.ts +0 -2
- package/dist/settings-request-capability.js +0 -4
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/settings-transaction.d.ts +0 -4
- package/dist/settings-transaction.js +0 -9
- package/dist/settings-transaction.js.map +1 -1
- package/dist/setup-form.js +3 -6
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-i18n.js +0 -3
- package/dist/setup-i18n.js.map +1 -1
- package/dist/setup-wizard.js +2 -6
- package/dist/setup-wizard.js.map +1 -1
- package/dist/task-board-tool.d.ts +1 -2
- package/dist/task-board-tool.js +6 -62
- package/dist/task-board-tool.js.map +1 -1
- package/dist/tmux-control.d.ts +1 -2
- package/dist/tmux-control.js +4 -4
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.js +1 -32
- package/dist/tmux-exec-helper.js.map +1 -1
- package/dist/tmux-manager.d.ts +2 -3
- package/dist/tmux-manager.js +36 -45
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.js +3 -4
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.js +1 -2
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +5 -9
- 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 +0 -3
- package/dist/transcript-monitor.js +51 -27
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +0 -5
- package/dist/transcript-sources.js +79 -8
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +3 -29
- package/dist/ui/app.html +8 -1
- package/dist/ui/backend-signin.js +21 -39
- package/dist/ui/chat-ambient.js +1 -1
- package/dist/ui/chat-md-strings.js +9 -3
- package/dist/ui/chat-render.js +670 -3
- package/dist/ui/chat-store.js +3 -14
- package/dist/ui/chat-strings.js +285 -3
- package/dist/ui/chat-thread.js +969 -3
- package/dist/ui/chat-time.js +80 -3
- package/dist/ui/chat-tour.js +1 -1
- package/dist/ui/fleet-office-pack.d.ts +0 -9
- package/dist/ui/fleet-office-pack.js +4 -76
- package/dist/ui/fleet-office-skin.js +5 -23
- package/dist/ui/fleet-office-store.js +0 -5
- package/dist/ui/fleet-office.js +6 -173
- package/dist/ui/fleet-task-card.js +4 -8
- package/dist/ui/fleet-task-common.js +2 -2
- package/dist/ui/fleet-tasks.js +39 -125
- package/dist/ui/html-attachment.js +40 -3
- package/dist/ui/office-share-page.js +2 -4
- package/dist/ui/panel-chat.js +75 -90
- package/dist/ui/panel-details.js +2 -3
- package/dist/ui/panel-fleet.js +18 -105
- package/dist/ui/panel-log.js +2 -2
- package/dist/ui/panel-needs.js +4 -162
- package/dist/ui/panel-notices.js +4 -3
- package/dist/ui/panel-settings.js +202 -281
- package/dist/ui/preview-pages.js +1 -1
- package/dist/ui/preview-panel.js +13 -21
- package/dist/ui/preview-versions.js +1 -1
- package/dist/ui/preview.js +476 -3
- package/dist/ui/search-dialog.js +3 -4
- package/dist/ui/settings-appearance.js +23 -122
- package/dist/ui/settings-catalog.js +10 -37
- package/dist/ui/settings-confirm.js +1 -3
- package/dist/ui/settings-dialogs.js +20 -48
- package/dist/ui/settings-guests.js +14 -27
- package/dist/ui/settings-model.js +1 -10
- package/dist/ui/settings-quota-notice.js +100 -0
- package/dist/ui/settings-registry.js +5 -15
- package/dist/ui/settings-strings.js +32 -105
- package/dist/ui/settings-web-authority.js +13 -18
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-route.js +3 -12
- package/dist/ui/shared/app-session.js +2 -6
- package/dist/ui/shared/app-shell.js +26 -87
- package/dist/ui/shared/app-store.js +2 -3
- package/dist/ui/shared/app-stream.js +1 -3
- package/dist/ui/shared/app.css +5 -1368
- package/dist/ui/shared/app.js +5 -17
- package/dist/ui/shared/header-tools.js +9 -9
- package/dist/ui/shared/instance-nav.js +7 -34
- package/dist/ui/shared/instance-switch.js +3 -4
- package/dist/ui/shared/loading.css +37 -0
- package/dist/ui/shared/signin.js +6 -211
- package/dist/ui/shared/tokens.css +0 -1
- package/dist/ui/shared/ui-dialog.js +2 -2
- package/dist/ui/shared/ui-menu.js +10 -30
- package/dist/ui/shared/ui-states.js +14 -3
- package/dist/ui/shared/vendor/vendor.json +2 -19
- package/dist/ui/shared/view-strings.js +0 -8
- package/dist/ui/signin.html +5 -23
- package/dist/unattended-install.js +1 -2
- package/dist/unattended-install.js.map +1 -1
- package/dist/usage/providers.d.ts +5 -0
- package/dist/usage/providers.js +6 -2
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/quota-notices.d.ts +38 -0
- package/dist/usage/quota-notices.js +160 -0
- package/dist/usage/quota-notices.js.map +1 -0
- package/dist/usage/usage-api.d.ts +1 -0
- package/dist/usage/usage-api.js +16 -0
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/view-api.js +7 -5
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +2 -80
- package/dist/web-api.js +10 -513
- package/dist/web-api.js.map +1 -1
- package/dist/web-backend-login.d.ts +1 -23
- package/dist/web-backend-login.js +17 -11
- package/dist/web-backend-login.js.map +1 -1
- package/dist/web-chat-history.d.ts +2 -19
- package/dist/web-chat-history.js +3 -72
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-office-skins.d.ts +0 -9
- package/dist/web-office-skins.js +1 -16
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-only-fleet.d.ts +0 -20
- package/dist/web-only-fleet.js +0 -21
- package/dist/web-only-fleet.js.map +1 -1
- package/dist/web-session.d.ts +0 -42
- package/dist/web-session.js +0 -9
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +1 -3
- package/dist/web-settings-patch.js +1 -4
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +1 -10
- package/dist/web-shell-routes.js +2 -14
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-terminal.d.ts +30 -4
- package/dist/web-terminal.js +6 -9
- package/dist/web-terminal.js.map +1 -1
- package/dist/yaml-shared-nodes.js +3 -8
- package/dist/yaml-shared-nodes.js.map +1 -1
- package/launcher/agend-install.cjs +1 -8
- package/launcher/postinstall.cjs +2 -27
- package/package.json +3 -10
- package/templates/launchd.plist.ejs +1 -3
- package/dist/accounts-view.d.ts +0 -97
- package/dist/accounts-view.js +0 -116
- package/dist/accounts-view.js.map +0 -1
- package/dist/agent-runtime-api.d.ts +0 -4
- package/dist/agent-runtime-api.js +0 -59
- package/dist/agent-runtime-api.js.map +0 -1
- package/dist/agent-runtime-change.d.ts +0 -76
- package/dist/agent-runtime-change.js +0 -114
- package/dist/agent-runtime-change.js.map +0 -1
- package/dist/agent-workspace.d.ts +0 -93
- package/dist/agent-workspace.js +0 -353
- package/dist/agent-workspace.js.map +0 -1
- package/dist/backend/grok-model-cache.d.ts +0 -7
- package/dist/backend/grok-model-cache.js +0 -65
- package/dist/backend/grok-model-cache.js.map +0 -1
- package/dist/backend/native-pane.d.ts +0 -11
- package/dist/backend/native-pane.js +0 -59
- package/dist/backend/native-pane.js.map +0 -1
- package/dist/build-provenance-cli.d.ts +0 -3
- package/dist/build-provenance-cli.js +0 -11
- package/dist/build-provenance-cli.js.map +0 -1
- package/dist/build-provenance.d.ts +0 -20
- package/dist/build-provenance.js +0 -67
- package/dist/build-provenance.js.map +0 -1
- package/dist/build-provenance.json +0 -1
- package/dist/claude-auth-status.d.ts +0 -48
- package/dist/claude-auth-status.js +0 -149
- package/dist/claude-auth-status.js.map +0 -1
- package/dist/fleet-windows-runtime.d.ts +0 -98
- package/dist/fleet-windows-runtime.js +0 -467
- package/dist/fleet-windows-runtime.js.map +0 -1
- package/dist/general-binding.d.ts +0 -85
- package/dist/general-binding.js +0 -298
- package/dist/general-binding.js.map +0 -1
- package/dist/general-host-owner.d.ts +0 -8
- package/dist/general-host-owner.js +0 -26
- package/dist/general-host-owner.js.map +0 -1
- package/dist/general-role.d.ts +0 -5
- package/dist/general-role.js +0 -27
- package/dist/general-role.js.map +0 -1
- package/dist/hub/admission.d.ts +0 -28
- package/dist/hub/admission.js +0 -62
- package/dist/hub/admission.js.map +0 -1
- package/dist/hub/attachments/limits.d.ts +0 -20
- package/dist/hub/attachments/limits.js +0 -48
- package/dist/hub/attachments/limits.js.map +0 -1
- package/dist/hub/attachments/store.d.ts +0 -116
- package/dist/hub/attachments/store.js +0 -246
- package/dist/hub/attachments/store.js.map +0 -1
- package/dist/hub/audit/index.d.ts +0 -62
- package/dist/hub/audit/index.js +0 -344
- package/dist/hub/audit/index.js.map +0 -1
- package/dist/hub/browser-certificate.d.ts +0 -38
- package/dist/hub/browser-certificate.js +0 -247
- package/dist/hub/browser-certificate.js.map +0 -1
- package/dist/hub/buttons-model.d.ts +0 -9
- package/dist/hub/buttons-model.js +0 -42
- package/dist/hub/buttons-model.js.map +0 -1
- package/dist/hub/buttons.d.ts +0 -54
- package/dist/hub/buttons.js +0 -346
- package/dist/hub/buttons.js.map +0 -1
- package/dist/hub/catalog.d.ts +0 -74
- package/dist/hub/catalog.js +0 -195
- package/dist/hub/catalog.js.map +0 -1
- package/dist/hub/client.d.ts +0 -69
- package/dist/hub/client.js +0 -300
- package/dist/hub/client.js.map +0 -1
- package/dist/hub/compose/member.d.ts +0 -139
- package/dist/hub/compose/member.js +0 -450
- package/dist/hub/compose/member.js.map +0 -1
- package/dist/hub/compose/server.d.ts +0 -77
- package/dist/hub/compose/server.js +0 -349
- package/dist/hub/compose/server.js.map +0 -1
- package/dist/hub/compose/views.d.ts +0 -12
- package/dist/hub/compose/views.js +0 -4
- package/dist/hub/compose/views.js.map +0 -1
- package/dist/hub/db.d.ts +0 -56
- package/dist/hub/db.js +0 -188
- package/dist/hub/db.js.map +0 -1
- package/dist/hub/directory/config.d.ts +0 -39
- package/dist/hub/directory/config.js +0 -108
- package/dist/hub/directory/config.js.map +0 -1
- package/dist/hub/directory/directory.d.ts +0 -18
- package/dist/hub/directory/directory.js +0 -320
- package/dist/hub/directory/directory.js.map +0 -1
- package/dist/hub/directory/index.d.ts +0 -7
- package/dist/hub/directory/index.js +0 -4
- package/dist/hub/directory/index.js.map +0 -1
- package/dist/hub/directory/profiles.d.ts +0 -41
- package/dist/hub/directory/profiles.js +0 -90
- package/dist/hub/directory/profiles.js.map +0 -1
- package/dist/hub/directory/types.d.ts +0 -71
- package/dist/hub/directory/types.js +0 -14
- package/dist/hub/directory/types.js.map +0 -1
- package/dist/hub/execution/cli-provider.d.ts +0 -23
- package/dist/hub/execution/cli-provider.js +0 -341
- package/dist/hub/execution/cli-provider.js.map +0 -1
- package/dist/hub/execution/index.d.ts +0 -13
- package/dist/hub/execution/index.js +0 -8
- package/dist/hub/execution/index.js.map +0 -1
- package/dist/hub/execution/model-broker.d.ts +0 -24
- package/dist/hub/execution/model-broker.js +0 -208
- package/dist/hub/execution/model-broker.js.map +0 -1
- package/dist/hub/execution/provider-setup.d.ts +0 -11
- package/dist/hub/execution/provider-setup.js +0 -21
- package/dist/hub/execution/provider-setup.js.map +0 -1
- package/dist/hub/execution/sandbox-runner.d.ts +0 -1
- package/dist/hub/execution/sandbox-runner.js +0 -221
- package/dist/hub/execution/sandbox-runner.js.map +0 -1
- package/dist/hub/execution/service.d.ts +0 -136
- package/dist/hub/execution/service.js +0 -459
- package/dist/hub/execution/service.js.map +0 -1
- package/dist/hub/execution/store.d.ts +0 -61
- package/dist/hub/execution/store.js +0 -182
- package/dist/hub/execution/store.js.map +0 -1
- package/dist/hub/execution/views.d.ts +0 -20
- package/dist/hub/execution/views.js +0 -48
- package/dist/hub/execution/views.js.map +0 -1
- package/dist/hub/http/compose.d.ts +0 -20
- package/dist/hub/http/compose.js +0 -518
- package/dist/hub/http/compose.js.map +0 -1
- package/dist/hub/http/core.d.ts +0 -49
- package/dist/hub/http/core.js +0 -124
- package/dist/hub/http/core.js.map +0 -1
- package/dist/hub/http/deps.d.ts +0 -61
- package/dist/hub/http/deps.js +0 -2
- package/dist/hub/http/deps.js.map +0 -1
- package/dist/hub/http/schema.d.ts +0 -14
- package/dist/hub/http/schema.js +0 -80
- package/dist/hub/http/schema.js.map +0 -1
- package/dist/hub/identity.d.ts +0 -32
- package/dist/hub/identity.js +0 -80
- package/dist/hub/identity.js.map +0 -1
- package/dist/hub/init/browser-certificate.d.ts +0 -9
- package/dist/hub/init/browser-certificate.js +0 -78
- package/dist/hub/init/browser-certificate.js.map +0 -1
- package/dist/hub/init/browser-tls.d.ts +0 -18
- package/dist/hub/init/browser-tls.js +0 -62
- package/dist/hub/init/browser-tls.js.map +0 -1
- package/dist/hub/init/cli.d.ts +0 -3
- package/dist/hub/init/cli.js +0 -83
- package/dist/hub/init/cli.js.map +0 -1
- package/dist/hub/init/directory-certificate.d.ts +0 -24
- package/dist/hub/init/directory-certificate.js +0 -222
- package/dist/hub/init/directory-certificate.js.map +0 -1
- package/dist/hub/init/existing-fleet.d.ts +0 -6
- package/dist/hub/init/existing-fleet.js +0 -58
- package/dist/hub/init/existing-fleet.js.map +0 -1
- package/dist/hub/init/handoff.d.ts +0 -8
- package/dist/hub/init/handoff.js +0 -36
- package/dist/hub/init/handoff.js.map +0 -1
- package/dist/hub/init/identity.d.ts +0 -5
- package/dist/hub/init/identity.js +0 -24
- package/dist/hub/init/identity.js.map +0 -1
- package/dist/hub/init/initializer.d.ts +0 -24
- package/dist/hub/init/initializer.js +0 -385
- package/dist/hub/init/initializer.js.map +0 -1
- package/dist/hub/init/inventory.d.ts +0 -17
- package/dist/hub/init/inventory.js +0 -33
- package/dist/hub/init/inventory.js.map +0 -1
- package/dist/hub/init/layout.d.ts +0 -32
- package/dist/hub/init/layout.js +0 -53
- package/dist/hub/init/layout.js.map +0 -1
- package/dist/hub/init/network.d.ts +0 -18
- package/dist/hub/init/network.js +0 -104
- package/dist/hub/init/network.js.map +0 -1
- package/dist/hub/init/plan-digest.d.ts +0 -5
- package/dist/hub/init/plan-digest.js +0 -47
- package/dist/hub/init/plan-digest.js.map +0 -1
- package/dist/hub/init/prompt.d.ts +0 -26
- package/dist/hub/init/prompt.js +0 -110
- package/dist/hub/init/prompt.js.map +0 -1
- package/dist/hub/init/secret-file.d.ts +0 -1
- package/dist/hub/init/secret-file.js +0 -59
- package/dist/hub/init/secret-file.js.map +0 -1
- package/dist/hub/init/text.d.ts +0 -127
- package/dist/hub/init/text.js +0 -247
- package/dist/hub/init/text.js.map +0 -1
- package/dist/hub/init/types.d.ts +0 -114
- package/dist/hub/init/types.js +0 -9
- package/dist/hub/init/types.js.map +0 -1
- package/dist/hub/init/wizard.d.ts +0 -34
- package/dist/hub/init/wizard.js +0 -554
- package/dist/hub/init/wizard.js.map +0 -1
- package/dist/hub/initialization.d.ts +0 -23
- package/dist/hub/initialization.js +0 -28
- package/dist/hub/initialization.js.map +0 -1
- package/dist/hub/member/agent-mode.d.ts +0 -6
- package/dist/hub/member/agent-mode.js +0 -23
- package/dist/hub/member/agent-mode.js.map +0 -1
- package/dist/hub/member/attachments.d.ts +0 -29
- package/dist/hub/member/attachments.js +0 -107
- package/dist/hub/member/attachments.js.map +0 -1
- package/dist/hub/member/exposure-api.d.ts +0 -87
- package/dist/hub/member/exposure-api.js +0 -64
- package/dist/hub/member/exposure-api.js.map +0 -1
- package/dist/hub/member/exposures.d.ts +0 -123
- package/dist/hub/member/exposures.js +0 -282
- package/dist/hub/member/exposures.js.map +0 -1
- package/dist/hub/member/pairing-api.d.ts +0 -85
- package/dist/hub/member/pairing-api.js +0 -385
- package/dist/hub/member/pairing-api.js.map +0 -1
- package/dist/hub/member/quota.d.ts +0 -20
- package/dist/hub/member/quota.js +0 -98
- package/dist/hub/member/quota.js.map +0 -1
- package/dist/hub/member-journal.d.ts +0 -104
- package/dist/hub/member-journal.js +0 -336
- package/dist/hub/member-journal.js.map +0 -1
- package/dist/hub/member-reconciliation.d.ts +0 -14
- package/dist/hub/member-reconciliation.js +0 -97
- package/dist/hub/member-reconciliation.js.map +0 -1
- package/dist/hub/mount.d.ts +0 -39
- package/dist/hub/mount.js +0 -123
- package/dist/hub/mount.js.map +0 -1
- package/dist/hub/pairing-client.d.ts +0 -17
- package/dist/hub/pairing-client.js +0 -108
- package/dist/hub/pairing-client.js.map +0 -1
- package/dist/hub/pairing.d.ts +0 -65
- package/dist/hub/pairing.js +0 -211
- package/dist/hub/pairing.js.map +0 -1
- package/dist/hub/policy.d.ts +0 -63
- package/dist/hub/policy.js +0 -147
- package/dist/hub/policy.js.map +0 -1
- package/dist/hub/preview.d.ts +0 -32
- package/dist/hub/preview.js +0 -64
- package/dist/hub/preview.js.map +0 -1
- package/dist/hub/private-files.d.ts +0 -5
- package/dist/hub/private-files.js +0 -44
- package/dist/hub/private-files.js.map +0 -1
- package/dist/hub/profile.d.ts +0 -59
- package/dist/hub/profile.js +0 -73
- package/dist/hub/profile.js.map +0 -1
- package/dist/hub/protocol.d.ts +0 -779
- package/dist/hub/protocol.js +0 -93
- package/dist/hub/protocol.js.map +0 -1
- package/dist/hub/quota.d.ts +0 -24
- package/dist/hub/quota.js +0 -112
- package/dist/hub/quota.js.map +0 -1
- package/dist/hub/representative.d.ts +0 -141
- package/dist/hub/representative.js +0 -528
- package/dist/hub/representative.js.map +0 -1
- package/dist/hub/retention.d.ts +0 -17
- package/dist/hub/retention.js +0 -45
- package/dist/hub/retention.js.map +0 -1
- package/dist/hub/rooms.d.ts +0 -120
- package/dist/hub/rooms.js +0 -535
- package/dist/hub/rooms.js.map +0 -1
- package/dist/hub/runtime.d.ts +0 -106
- package/dist/hub/runtime.js +0 -298
- package/dist/hub/runtime.js.map +0 -1
- package/dist/hub/server.d.ts +0 -56
- package/dist/hub/server.js +0 -202
- package/dist/hub/server.js.map +0 -1
- package/dist/hub/service-start.d.ts +0 -17
- package/dist/hub/service-start.js +0 -109
- package/dist/hub/service-start.js.map +0 -1
- package/dist/hub/sessions.d.ts +0 -53
- package/dist/hub/sessions.js +0 -196
- package/dist/hub/sessions.js.map +0 -1
- package/dist/hub/socket.d.ts +0 -24
- package/dist/hub/socket.js +0 -79
- package/dist/hub/socket.js.map +0 -1
- package/dist/hub/store.d.ts +0 -77
- package/dist/hub/store.js +0 -88
- package/dist/hub/store.js.map +0 -1
- package/dist/hub/tls.d.ts +0 -31
- package/dist/hub/tls.js +0 -135
- package/dist/hub/tls.js.map +0 -1
- package/dist/hub/types.d.ts +0 -401
- package/dist/hub/types.js +0 -2
- package/dist/hub/types.js.map +0 -1
- package/dist/hub/validation.d.ts +0 -33
- package/dist/hub/validation.js +0 -136
- package/dist/hub/validation.js.map +0 -1
- package/dist/hub/version-floor.d.ts +0 -10
- package/dist/hub/version-floor.js +0 -45
- package/dist/hub/version-floor.js.map +0 -1
- package/dist/hub-browser-certificate-policy.d.ts +0 -31
- package/dist/hub-browser-certificate-policy.js +0 -25
- package/dist/hub-browser-certificate-policy.js.map +0 -1
- package/dist/hub-membership-settings.d.ts +0 -6
- package/dist/hub-membership-settings.js +0 -21
- package/dist/hub-membership-settings.js.map +0 -1
- package/dist/hub-mode.d.ts +0 -15
- package/dist/hub-mode.js +0 -17
- package/dist/hub-mode.js.map +0 -1
- package/dist/hub-pairing-summary.d.ts +0 -48
- package/dist/hub-pairing-summary.js +0 -36
- package/dist/hub-pairing-summary.js.map +0 -1
- package/dist/hub-report-target.d.ts +0 -32
- package/dist/hub-report-target.js +0 -33
- package/dist/hub-report-target.js.map +0 -1
- package/dist/hub-retention-policy.d.ts +0 -14
- package/dist/hub-retention-policy.js +0 -15
- package/dist/hub-retention-policy.js.map +0 -1
- package/dist/launchd-service-domain.d.ts +0 -5
- package/dist/launchd-service-domain.js +0 -21
- package/dist/launchd-service-domain.js.map +0 -1
- package/dist/local-pane-endpoint.d.ts +0 -46
- package/dist/local-pane-endpoint.js +0 -189
- package/dist/local-pane-endpoint.js.map +0 -1
- package/dist/local-pane-launcher.d.ts +0 -2
- package/dist/local-pane-launcher.js +0 -38
- package/dist/local-pane-launcher.js.map +0 -1
- package/dist/local-pane-stage.ps1 +0 -101
- package/dist/model-catalog-defaults.d.ts +0 -14
- package/dist/model-catalog-defaults.js +0 -20
- package/dist/model-catalog-defaults.js.map +0 -1
- package/dist/native-agent-admission.d.ts +0 -7
- package/dist/native-agent-admission.js +0 -26
- package/dist/native-agent-admission.js.map +0 -1
- package/dist/native-daemon-client.d.ts +0 -13
- package/dist/native-daemon-client.js +0 -28
- package/dist/native-daemon-client.js.map +0 -1
- package/dist/native-instance-api.d.ts +0 -13
- package/dist/native-instance-api.js +0 -217
- package/dist/native-instance-api.js.map +0 -1
- package/dist/native-instance-input.d.ts +0 -87
- package/dist/native-instance-input.js +0 -59
- package/dist/native-instance-input.js.map +0 -1
- package/dist/native-instance-registry.d.ts +0 -38
- package/dist/native-instance-registry.js +0 -129
- package/dist/native-instance-registry.js.map +0 -1
- package/dist/native-mcp.d.ts +0 -43
- package/dist/native-mcp.js +0 -291
- package/dist/native-mcp.js.map +0 -1
- package/dist/native-model-catalog.d.ts +0 -5
- package/dist/native-model-catalog.js +0 -76
- package/dist/native-model-catalog.js.map +0 -1
- package/dist/native-pane-crash-budget.d.ts +0 -20
- package/dist/native-pane-crash-budget.js +0 -60
- package/dist/native-pane-crash-budget.js.map +0 -1
- package/dist/native-pane-create.d.ts +0 -26
- package/dist/native-pane-create.js +0 -53
- package/dist/native-pane-create.js.map +0 -1
- package/dist/native-pane-lifecycle.d.ts +0 -73
- package/dist/native-pane-lifecycle.js +0 -239
- package/dist/native-pane-lifecycle.js.map +0 -1
- package/dist/native-pane-manager.d.ts +0 -59
- package/dist/native-pane-manager.js +0 -592
- package/dist/native-pane-manager.js.map +0 -1
- package/dist/native-pane-output-log.d.ts +0 -15
- package/dist/native-pane-output-log.js +0 -108
- package/dist/native-pane-output-log.js.map +0 -1
- package/dist/native-pane-reconciliation.d.ts +0 -4
- package/dist/native-pane-reconciliation.js +0 -40
- package/dist/native-pane-reconciliation.js.map +0 -1
- package/dist/native-pane-recovery.d.ts +0 -12
- package/dist/native-pane-recovery.js +0 -10
- package/dist/native-pane-recovery.js.map +0 -1
- package/dist/native-pane-tools.d.ts +0 -2
- package/dist/native-pane-tools.js +0 -14
- package/dist/native-pane-tools.js.map +0 -1
- package/dist/office-talk.d.ts +0 -26
- package/dist/office-talk.js +0 -50
- package/dist/office-talk.js.map +0 -1
- package/dist/pane-port.d.ts +0 -118
- package/dist/pane-port.js +0 -2
- package/dist/pane-port.js.map +0 -1
- package/dist/runtime-api.d.ts +0 -10
- package/dist/runtime-api.js +0 -189
- package/dist/runtime-api.js.map +0 -1
- package/dist/runtime-assets/@xterm/addon-serialize/LICENSE +0 -21
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.js +0 -2
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.mjs +0 -19
- package/dist/runtime-assets/@xterm/addon-serialize/package.json +0 -29
- package/dist/runtime-assets/@xterm/headless/LICENSE +0 -21
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.js +0 -2
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.mjs +0 -46
- package/dist/runtime-assets/@xterm/headless/package.json +0 -29
- package/dist/runtime-assets/node-pty/CONPTY-LICENSE +0 -21
- package/dist/runtime-assets/node-pty/CONPTY-NOTICE.md +0 -503
- package/dist/runtime-assets/node-pty/LICENSE +0 -69
- package/dist/runtime-assets/node-pty/lib/conpty_console_list_agent.js +0 -16
- package/dist/runtime-assets/node-pty/lib/eventEmitter2.js +0 -47
- package/dist/runtime-assets/node-pty/lib/index.js +0 -52
- package/dist/runtime-assets/node-pty/lib/interfaces.js +0 -7
- package/dist/runtime-assets/node-pty/lib/shared/conout.js +0 -11
- package/dist/runtime-assets/node-pty/lib/terminal.js +0 -190
- package/dist/runtime-assets/node-pty/lib/types.js +0 -7
- package/dist/runtime-assets/node-pty/lib/unixTerminal.js +0 -346
- package/dist/runtime-assets/node-pty/lib/utils.js +0 -39
- package/dist/runtime-assets/node-pty/lib/windowsConoutConnection.js +0 -125
- package/dist/runtime-assets/node-pty/lib/windowsPtyAgent.js +0 -320
- package/dist/runtime-assets/node-pty/lib/windowsTerminal.js +0 -199
- package/dist/runtime-assets/node-pty/lib/worker/conoutSocketWorker.js +0 -22
- package/dist/runtime-assets/node-pty/package.json +0 -64
- 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-build-info.d.ts +0 -9
- package/dist/runtime-build-info.js +0 -59
- package/dist/runtime-build-info.js.map +0 -1
- package/dist/runtime-bundle.d.ts +0 -22
- package/dist/runtime-bundle.js +0 -158
- package/dist/runtime-bundle.js.map +0 -1
- package/dist/runtime-cli.d.ts +0 -14
- package/dist/runtime-cli.js +0 -271
- package/dist/runtime-cli.js.map +0 -1
- package/dist/runtime-client-store.d.ts +0 -75
- package/dist/runtime-client-store.js +0 -372
- package/dist/runtime-client-store.js.map +0 -1
- package/dist/runtime-client.d.ts +0 -174
- package/dist/runtime-client.js +0 -1010
- package/dist/runtime-client.js.map +0 -1
- package/dist/runtime-connection.d.ts +0 -22
- package/dist/runtime-connection.js +0 -93
- package/dist/runtime-connection.js.map +0 -1
- package/dist/runtime-coordinator.d.ts +0 -98
- package/dist/runtime-coordinator.js +0 -1089
- package/dist/runtime-coordinator.js.map +0 -1
- package/dist/runtime-credential-profiles.d.ts +0 -78
- package/dist/runtime-credential-profiles.js +0 -280
- package/dist/runtime-credential-profiles.js.map +0 -1
- package/dist/runtime-general-protocol.d.ts +0 -22
- package/dist/runtime-general-protocol.js +0 -57
- package/dist/runtime-general-protocol.js.map +0 -1
- package/dist/runtime-general-workspace.d.ts +0 -17
- package/dist/runtime-general-workspace.js +0 -213
- package/dist/runtime-general-workspace.js.map +0 -1
- package/dist/runtime-install.d.ts +0 -50
- package/dist/runtime-install.js +0 -186
- package/dist/runtime-install.js.map +0 -1
- package/dist/runtime-pane-assets.d.ts +0 -17
- package/dist/runtime-pane-assets.js +0 -23
- package/dist/runtime-pane-assets.js.map +0 -1
- package/dist/runtime-pane-boot.d.ts +0 -9
- package/dist/runtime-pane-boot.js +0 -47
- package/dist/runtime-pane-boot.js.map +0 -1
- package/dist/runtime-pane-codex-index.d.ts +0 -10
- package/dist/runtime-pane-codex-index.js +0 -151
- package/dist/runtime-pane-codex-index.js.map +0 -1
- package/dist/runtime-pane-config.d.ts +0 -16
- package/dist/runtime-pane-config.js +0 -54
- package/dist/runtime-pane-config.js.map +0 -1
- package/dist/runtime-pane-host.d.ts +0 -63
- package/dist/runtime-pane-host.js +0 -467
- package/dist/runtime-pane-host.js.map +0 -1
- package/dist/runtime-pane-job-owner.d.ts +0 -1
- package/dist/runtime-pane-job-owner.js +0 -29
- package/dist/runtime-pane-job-owner.js.map +0 -1
- package/dist/runtime-pane-job.ps1 +0 -116
- package/dist/runtime-pane-link.d.ts +0 -47
- package/dist/runtime-pane-link.js +0 -337
- package/dist/runtime-pane-link.js.map +0 -1
- package/dist/runtime-pane-mcp-protocol.d.ts +0 -32
- package/dist/runtime-pane-mcp-protocol.js +0 -39
- package/dist/runtime-pane-mcp-protocol.js.map +0 -1
- package/dist/runtime-pane-mcp-relay.d.ts +0 -18
- package/dist/runtime-pane-mcp-relay.js +0 -80
- package/dist/runtime-pane-mcp-relay.js.map +0 -1
- package/dist/runtime-pane-mcp.d.ts +0 -55
- package/dist/runtime-pane-mcp.js +0 -153
- package/dist/runtime-pane-mcp.js.map +0 -1
- package/dist/runtime-pane-native.d.ts +0 -75
- package/dist/runtime-pane-native.js +0 -114
- package/dist/runtime-pane-native.js.map +0 -1
- package/dist/runtime-pane-output.d.ts +0 -19
- package/dist/runtime-pane-output.js +0 -53
- package/dist/runtime-pane-output.js.map +0 -1
- package/dist/runtime-pane-port.d.ts +0 -144
- package/dist/runtime-pane-port.js +0 -574
- package/dist/runtime-pane-port.js.map +0 -1
- package/dist/runtime-pane-private.d.ts +0 -14
- package/dist/runtime-pane-private.js +0 -51
- package/dist/runtime-pane-private.js.map +0 -1
- package/dist/runtime-pane-private.ps1 +0 -14
- package/dist/runtime-pane-process.d.ts +0 -4
- package/dist/runtime-pane-process.js +0 -117
- package/dist/runtime-pane-process.js.map +0 -1
- package/dist/runtime-pane-protocol.d.ts +0 -182
- package/dist/runtime-pane-protocol.js +0 -217
- package/dist/runtime-pane-protocol.js.map +0 -1
- package/dist/runtime-pane-quota-history.d.ts +0 -6
- package/dist/runtime-pane-quota-history.js +0 -44
- package/dist/runtime-pane-quota-history.js.map +0 -1
- package/dist/runtime-pane-screen.d.ts +0 -19
- package/dist/runtime-pane-screen.js +0 -76
- package/dist/runtime-pane-screen.js.map +0 -1
- package/dist/runtime-pane-service.d.ts +0 -16
- package/dist/runtime-pane-service.js +0 -256
- package/dist/runtime-pane-service.js.map +0 -1
- package/dist/runtime-pane-stdio-protocol.d.ts +0 -54
- package/dist/runtime-pane-stdio-protocol.js +0 -94
- package/dist/runtime-pane-stdio-protocol.js.map +0 -1
- package/dist/runtime-pane-stdio.d.ts +0 -3
- package/dist/runtime-pane-stdio.js +0 -123
- package/dist/runtime-pane-stdio.js.map +0 -1
- package/dist/runtime-pane-store.d.ts +0 -33
- package/dist/runtime-pane-store.js +0 -164
- package/dist/runtime-pane-store.js.map +0 -1
- package/dist/runtime-pane-transcript-protocol.d.ts +0 -43
- package/dist/runtime-pane-transcript-protocol.js +0 -58
- package/dist/runtime-pane-transcript-protocol.js.map +0 -1
- package/dist/runtime-pane-transcript.d.ts +0 -50
- package/dist/runtime-pane-transcript.js +0 -666
- package/dist/runtime-pane-transcript.js.map +0 -1
- package/dist/runtime-pane-worker.d.ts +0 -1
- package/dist/runtime-pane-worker.js +0 -167
- package/dist/runtime-pane-worker.js.map +0 -1
- package/dist/runtime-protocol.d.ts +0 -177
- package/dist/runtime-protocol.js +0 -49
- package/dist/runtime-protocol.js.map +0 -1
- package/dist/runtime-switches.d.ts +0 -79
- package/dist/runtime-switches.js +0 -90
- package/dist/runtime-switches.js.map +0 -1
- package/dist/runtime-transcript-delta-reader.d.ts +0 -23
- package/dist/runtime-transcript-delta-reader.js +0 -74
- package/dist/runtime-transcript-delta-reader.js.map +0 -1
- package/dist/runtime-transcript-source.d.ts +0 -36
- package/dist/runtime-transcript-source.js +0 -189
- package/dist/runtime-transcript-source.js.map +0 -1
- package/dist/runtime-update-activity.d.ts +0 -21
- package/dist/runtime-update-activity.js +0 -51
- package/dist/runtime-update-activity.js.map +0 -1
- package/dist/runtime-update-artifact.d.ts +0 -31
- package/dist/runtime-update-artifact.js +0 -252
- package/dist/runtime-update-artifact.js.map +0 -1
- package/dist/runtime-update-install.d.ts +0 -31
- package/dist/runtime-update-install.js +0 -205
- package/dist/runtime-update-install.js.map +0 -1
- package/dist/runtime-update-journal.d.ts +0 -44
- package/dist/runtime-update-journal.js +0 -121
- package/dist/runtime-update-journal.js.map +0 -1
- package/dist/runtime-update-lock.d.ts +0 -48
- package/dist/runtime-update-lock.js +0 -217
- package/dist/runtime-update-lock.js.map +0 -1
- package/dist/runtime-update-owners.d.ts +0 -29
- package/dist/runtime-update-owners.js +0 -240
- package/dist/runtime-update-owners.js.map +0 -1
- package/dist/runtime-update-protocol.d.ts +0 -15
- package/dist/runtime-update-protocol.js +0 -13
- package/dist/runtime-update-protocol.js.map +0 -1
- package/dist/runtime-windows-bridge.d.ts +0 -42
- package/dist/runtime-windows-bridge.js +0 -167
- package/dist/runtime-windows-bridge.js.map +0 -1
- package/dist/service-drain.d.ts +0 -19
- package/dist/service-drain.js +0 -64
- package/dist/service-drain.js.map +0 -1
- package/dist/settings-route-lifetime.d.ts +0 -14
- package/dist/settings-route-lifetime.js +0 -48
- package/dist/settings-route-lifetime.js.map +0 -1
- package/dist/tmux-binary.d.ts +0 -59
- package/dist/tmux-binary.js +0 -200
- package/dist/tmux-binary.js.map +0 -1
- package/dist/tmux-pane-host.d.ts +0 -26
- package/dist/tmux-pane-host.js +0 -25
- package/dist/tmux-pane-host.js.map +0 -1
- package/dist/transcript-needles.d.ts +0 -42
- package/dist/transcript-needles.js +0 -166
- package/dist/transcript-needles.js.map +0 -1
- package/dist/transcript-records.d.ts +0 -21
- package/dist/transcript-records.js +0 -141
- package/dist/transcript-records.js.map +0 -1
- package/dist/ui/account-identity.js +0 -27
- package/dist/ui/accounts-view.js +0 -214
- package/dist/ui/agent-proposals.js +0 -90
- package/dist/ui/agent-runtime-settings.js +0 -68
- package/dist/ui/agent-runtime.js +0 -124
- package/dist/ui/cli-picker.js +0 -42
- package/dist/ui/credential-profile-select.js +0 -54
- package/dist/ui/fleet-office-dialogue.d.ts +0 -30
- package/dist/ui/fleet-office-dialogue.js +0 -382
- package/dist/ui/fleet-task-menu.js +0 -188
- package/dist/ui/fleet-task-stats.js +0 -124
- package/dist/ui/fleet-task-view.js +0 -340
- package/dist/ui/general-location.js +0 -71
- package/dist/ui/hub-agent-copy.js +0 -23
- package/dist/ui/hub-button-actions.js +0 -65
- package/dist/ui/hub-chat-store.js +0 -158
- package/dist/ui/hub-chat-strings.js +0 -77
- package/dist/ui/hub-client.js +0 -329
- package/dist/ui/hub-owner-strings.js +0 -51
- package/dist/ui/hub-provider-guidance.js +0 -31
- package/dist/ui/hub-quota.js +0 -85
- package/dist/ui/hub-strings.js +0 -162
- package/dist/ui/hub-switcher.js +0 -27
- package/dist/ui/native-instance-settings.js +0 -44
- package/dist/ui/native-pane-recovery.js +0 -45
- package/dist/ui/panel-hub.js +0 -619
- package/dist/ui/panel-runtimes.js +0 -425
- package/dist/ui/panel-windows-agent.js +0 -86
- package/dist/ui/panel-windows-cli.js +0 -189
- package/dist/ui/provider-marks.js +0 -83
- package/dist/ui/runtime-catalog.js +0 -55
- package/dist/ui/runtime-commands.d.ts +0 -4
- package/dist/ui/runtime-commands.js +0 -59
- package/dist/ui/settings-access-strings.js +0 -42
- package/dist/ui/settings-agent-filters.js +0 -94
- package/dist/ui/settings-build-version.js +0 -35
- package/dist/ui/settings-devices.js +0 -253
- package/dist/ui/settings-hub-browser-certificate.js +0 -74
- package/dist/ui/settings-hub-membership.js +0 -72
- package/dist/ui/settings-hub-retention.js +0 -52
- package/dist/ui/settings-hub.js +0 -196
- package/dist/ui/settings-layout.js +0 -242
- package/dist/ui/settings-outside.js +0 -242
- package/dist/ui/settings-shared-strings.js +0 -143
- package/dist/ui/settings-shared.js +0 -345
- package/dist/ui/settings-shortcuts.js +0 -65
- package/dist/ui/shared/accounts.css +0 -15
- package/dist/ui/shared/chat-composer.js +0 -68
- package/dist/ui/shared/chat-md-strings.js +0 -9
- package/dist/ui/shared/chat-render.js +0 -682
- package/dist/ui/shared/chat-strings.js +0 -333
- package/dist/ui/shared/chat-thread.js +0 -969
- package/dist/ui/shared/chat-time.js +0 -80
- package/dist/ui/shared/html-attachment.js +0 -42
- package/dist/ui/shared/hub-chat.css +0 -85
- package/dist/ui/shared/hub-owner.css +0 -33
- package/dist/ui/shared/hub-quota.css +0 -8
- package/dist/ui/shared/hub.css +0 -71
- package/dist/ui/shared/machine-name.js +0 -13
- package/dist/ui/shared/page-head.js +0 -8
- package/dist/ui/shared/preview.js +0 -476
- package/dist/ui/shared/qrcode.module.js +0 -2237
- package/dist/ui/shared/runtime-install.css +0 -26
- package/dist/ui/shared/settings-width.js +0 -31
- package/dist/ui/shared/side-rail.js +0 -15
- package/dist/ui/shared/task-board.css +0 -95
- package/dist/ui/shared/vendor/qrcode-generator.LICENSE +0 -27
- package/dist/ui/shared/workspace.css +0 -20
- package/dist/ui/windows-agents-nav.js +0 -2
- package/dist/ui/windows-cli-catalog.js +0 -108
- package/dist/ui/workspace-panel.js +0 -189
- package/dist/ui/workspace-strings.js +0 -35
- package/dist/web-device-login.d.ts +0 -153
- package/dist/web-device-login.js +0 -278
- package/dist/web-device-login.js.map +0 -1
- package/dist/web-remote-access.d.ts +0 -152
- package/dist/web-remote-access.js +0 -368
- package/dist/web-remote-access.js.map +0 -1
- package/dist/windows-agents.d.ts +0 -127
- package/dist/windows-agents.js +0 -491
- package/dist/windows-agents.js.map +0 -1
- package/dist/windows-cli-api.d.ts +0 -34
- package/dist/windows-cli-api.js +0 -185
- package/dist/windows-cli-api.js.map +0 -1
- package/dist/windows-cli-providers.d.ts +0 -106
- package/dist/windows-cli-providers.js +0 -424
- package/dist/windows-cli-providers.js.map +0 -1
- package/dist/windows-cli-worker.d.ts +0 -83
- package/dist/windows-cli-worker.js +0 -570
- package/dist/windows-cli-worker.js.map +0 -1
- package/dist/windows-cli.d.ts +0 -126
- package/dist/windows-cli.js +0 -416
- package/dist/windows-cli.js.map +0 -1
- package/dist/windows-native-mcp.d.ts +0 -19
- package/dist/windows-native-mcp.js +0 -143
- package/dist/windows-native-mcp.js.map +0 -1
- package/dist/windows-pane-mcp.d.ts +0 -26
- package/dist/windows-pane-mcp.js +0 -187
- package/dist/windows-pane-mcp.js.map +0 -1
- package/launcher/launchd-session-type.cjs +0 -14
- package/launcher/tmux-bundle.cjs +0 -247
- package/templates/runtime-assets/conpty-LICENSE +0 -21
- package/templates/runtime-assets/conpty-NOTICE.md +0 -503
- package/templates/runtime-assets/local-pane-stage.ps1 +0 -101
- package/templates/runtime-assets/runtime-pane-job.ps1 +0 -116
- package/templates/runtime-assets/runtime-pane-private.ps1 +0 -14
- package/templates/runtime-assets/xterm-LICENSE +0 -21
- package/templates/runtime-install/install.ps1 +0 -270
package/dist/daemon.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { generalByName } from "./general-instance.js";
|
|
1
|
+
import { quotaNoticeProblem } from "./quota-notice-config.js";
|
|
3
2
|
import { quotaHistoryCount, quotaAfterInput } from "./pane-quota-history.js";
|
|
4
3
|
import { dialogScreenText } from "./dialog-screen-text.js";
|
|
5
4
|
import { readActiveKiroModel } from "./backend/kiro.js";
|
|
@@ -23,7 +22,7 @@ import { assertNoSessionOomStop, readSessionOomStop, writeSessionOomStop, Sessio
|
|
|
23
22
|
import { mcpServerState } from "./mcp-liveness.js";
|
|
24
23
|
import { clearPausedMarker, writePausedMarker } from "./pause-marker.js";
|
|
25
24
|
import { writeBackgroundWorkEndedMarker } from "./background-work-ended.js";
|
|
26
|
-
import { resolveTmuxLogicalSize } from "./tmux-manager.js";
|
|
25
|
+
import { TmuxManager, resolveTmuxLogicalSize } from "./tmux-manager.js";
|
|
27
26
|
import { TranscriptMonitor } from "./transcript-monitor.js";
|
|
28
27
|
import { createTranscriptSource } from "./transcript-sources.js";
|
|
29
28
|
import { TranscriptTurnLedger } from "./transcript-turns.js";
|
|
@@ -51,7 +50,6 @@ import { HangDetector } from "./hang-detector.js";
|
|
|
51
50
|
import { writeSecretFile } from "./secret-file.js";
|
|
52
51
|
import { PaneWriteLock } from "./pane-write-lock.js";
|
|
53
52
|
import { answerRemoteCard } from "./remote-card-answer.js";
|
|
54
|
-
import { tmuxPaneHost } from "./tmux-pane-host.js";
|
|
55
53
|
import { buildFleetInstructions } from "./instructions.js";
|
|
56
54
|
import { formatHumanInboundMessage, prepareDeliveryWire, steerInboundEnvelope, BTW_INBOUND_PREFIX, humanBodyHash, humanOwnerObjectId } from "./human-delivery-receipts.js";
|
|
57
55
|
import { formatCrossInstanceInboundMessage, renderCrossInstanceHandoffMetadata, } from "./cross-instance-envelope.js";
|
|
@@ -61,7 +59,6 @@ import { CLAUDE_CREDIT_BALANCE_LOW, CLAUDE_MODEL_USAGE_LIMIT, CLAUDE_USAGE_LIMIT
|
|
|
61
59
|
import { t } from "./locale.js";
|
|
62
60
|
import { claudeResetInstant, claudeResetTime, quotaPausedLine } from "./quota-notice.js";
|
|
63
61
|
import { MuseUsageRelay, clearMuseUsageSnapshot } from "./muse-usage-relay.js";
|
|
64
|
-
import { reconcileNativePaneTarget } from "./native-pane-reconciliation.js";
|
|
65
62
|
import { deliveryContentDigest } from "./delivery-outbox.js";
|
|
66
63
|
import { consumedWatches } from "./delivery-consumed-watch.js";
|
|
67
64
|
import { queueResumePolicyForAttempt } from "./delivery-queue-evidence.js";
|
|
@@ -1121,7 +1118,6 @@ export class Daemon extends EventEmitter {
|
|
|
1121
1118
|
spawnGate;
|
|
1122
1119
|
stormWindow;
|
|
1123
1120
|
backendOutage;
|
|
1124
|
-
paneTransport;
|
|
1125
1121
|
/** #1314: fleet-directory fallbacks already reported to the topic (once per daemon, per field and path). */
|
|
1126
1122
|
promptFileFallbackNoticed = new Set();
|
|
1127
1123
|
/** Identity of this live Daemon object; changes on object stop/restart. */
|
|
@@ -1800,7 +1796,6 @@ export class Daemon extends EventEmitter {
|
|
|
1800
1796
|
// still booting. Its new tmux window starts empty before resume restores the
|
|
1801
1797
|
// old transcript, so pre-ready scans must not lower this seeded baseline.
|
|
1802
1798
|
seededErrorCountBaselines = new Map();
|
|
1803
|
-
nativeQuotaReplayTaken = false;
|
|
1804
1799
|
quotaReplay = null;
|
|
1805
1800
|
paneQuotaPatterns() {
|
|
1806
1801
|
if (!["codex", "grok"].includes(this.backend?.binaryName ?? ""))
|
|
@@ -1836,11 +1831,7 @@ export class Daemon extends EventEmitter {
|
|
|
1836
1831
|
}
|
|
1837
1832
|
/** Before admission, this launch may absorb ONLY rows positively known before its resume. */
|
|
1838
1833
|
takeQuotaReplayBaseline(pane) {
|
|
1839
|
-
|
|
1840
|
-
const native = !this.nativeQuotaReplayTaken ? this.nativePaneLifecycle?.quotaReplayHistory?.() : null;
|
|
1841
|
-
if (this.nativePaneLifecycle)
|
|
1842
|
-
this.nativeQuotaReplayTaken = true;
|
|
1843
|
-
const history = this.quotaReplay ?? (native ? { ...native, spawn: this.spawnGeneration, fence: this.launchFenceEpoch, attempt: this.launchAttempt } : null);
|
|
1834
|
+
const history = this.quotaReplay;
|
|
1844
1835
|
if (!history)
|
|
1845
1836
|
return;
|
|
1846
1837
|
this.quotaReplay = null;
|
|
@@ -1906,15 +1897,6 @@ export class Daemon extends EventEmitter {
|
|
|
1906
1897
|
static USAGE_PAUSE_NOTICE_WINDOW_MS = 30 * 60_000;
|
|
1907
1898
|
/** The usage-pause notice told last: when (monotonic), Claude's words for the reset, and that reset (wall clock). */
|
|
1908
1899
|
usagePauseNotice = null;
|
|
1909
|
-
/** Coarse status for the representative quota hint; never exports model names or transcript text. */
|
|
1910
|
-
quotaPaused() {
|
|
1911
|
-
if (this.usageLimitHold)
|
|
1912
|
-
return true;
|
|
1913
|
-
const pause = this.usagePauseNotice;
|
|
1914
|
-
return !!pause && (pause.resetAt === null
|
|
1915
|
-
? performance.now() - pause.at < Daemon.USAGE_PAUSE_NOTICE_WINDOW_MS
|
|
1916
|
-
: Date.now() < pause.resetAt);
|
|
1917
|
-
}
|
|
1918
1900
|
/**
|
|
1919
1901
|
* #2834 (#816): Claude paused itself until its usage window opens — the same notice the screen pattern gave. `at`: when
|
|
1920
1902
|
* Claude wrote it (its record's timestamp). One notice per pause: a reset time already past is not this pause (an old
|
|
@@ -2081,94 +2063,9 @@ export class Daemon extends EventEmitter {
|
|
|
2081
2063
|
this.errorRecoveryDeadlineAt = 0;
|
|
2082
2064
|
this.activeErrorPatternKey = null;
|
|
2083
2065
|
}
|
|
2084
|
-
/** Lazy default also preserves bare-prototype diagnostic/test construction. */
|
|
2085
|
-
get paneHost() { return this.paneTransport ?? tmuxPaneHost; }
|
|
2086
|
-
nativePaneLifecycle;
|
|
2087
|
-
nativeFleetBridge;
|
|
2088
|
-
nativeTranscriptSource;
|
|
2089
|
-
usesNativePane() { return !!this.nativePaneLifecycle; }
|
|
2090
|
-
/** cc3ce4fe: the CLI version this pane's launch actually ran, as its helper recorded it (undefined: not known). */
|
|
2091
|
-
nativePaneCliVersion() { try {
|
|
2092
|
-
return this.nativePaneLifecycle?.snapshot?.()?.cliVersion;
|
|
2093
|
-
}
|
|
2094
|
-
catch {
|
|
2095
|
-
return undefined;
|
|
2096
|
-
} }
|
|
2097
|
-
logNativeInputRefusal(details) {
|
|
2098
|
-
this.logger.warn({ component: "runtime-pane-host", reason: "expected_seq_changed", ...details }, "Native pane input refused before write");
|
|
2099
|
-
}
|
|
2100
|
-
logNativeToolFailure(details) {
|
|
2101
|
-
const turn = this.turnReplyGuard.snapshot();
|
|
2102
|
-
this.logger.warn({ ...details, currentMessageId: turn?.target.messageId ?? null,
|
|
2103
|
-
guardGeneration: turn?.generation ?? null, guardPhase: turn?.phase ?? null }, "Native pane tool operation failed");
|
|
2104
|
-
}
|
|
2105
|
-
nativePaneCurrent() { return this.nativePaneLifecycle?.current() ?? false; }
|
|
2106
|
-
nativeEnterHold = null;
|
|
2107
|
-
/** Per-launch attention for a native delivery whose bounded input attempts were refused or uncertain, including non-outbox input. */
|
|
2108
|
-
nativeDeliveryHold() {
|
|
2109
|
-
const hold = this.nativeEnterHold;
|
|
2110
|
-
return hold && this.nativePaneLifecycle && !this.deliveryWritesStopping && hold.spawn === this.spawnGeneration && hold.fence === this.launchFenceEpoch
|
|
2111
|
-
? { key: hold.key, since: hold.since } : null;
|
|
2112
|
-
}
|
|
2113
|
-
nativePaneHasExited() {
|
|
2114
|
-
const snapshot = this.nativePaneLifecycle?.snapshot?.();
|
|
2115
|
-
return snapshot?.state === "exited" && snapshot.instance === this.name && this.tmux?.getWindowId() === snapshot.paneId;
|
|
2116
|
-
}
|
|
2117
|
-
/** Positive native exit evidence only, fenced to this exact launch and Daemon owner. */
|
|
2118
|
-
nativePaneExitCurrent(snapshot, owner) {
|
|
2119
|
-
const actual = this.nativePaneLifecycle?.snapshot?.();
|
|
2120
|
-
return !!actual && actual.state === "exited" && snapshot.state === "exited"
|
|
2121
|
-
&& sameInteractionOwner(owner, this.interactionOwner()) && !this.runtimeMonitorsFrozen && !this.startupAborted
|
|
2122
|
-
&& ["hostBootId", "paneId", "launchId", "agentId", "instance", "sessionId", "commandSequence", "exitCode"].every(key => actual[key] === snapshot[key])
|
|
2123
|
-
&& this.tmux?.getWindowId() === snapshot.paneId;
|
|
2124
|
-
}
|
|
2125
|
-
async reconcileNativeDeliveries(outbox, current) {
|
|
2126
|
-
if (!this.nativePaneLifecycle)
|
|
2127
|
-
return false;
|
|
2128
|
-
return reconcileNativePaneTarget(outbox, this.name, this.nativePaneLifecycle, current);
|
|
2129
|
-
}
|
|
2130
|
-
/** Same-process transport for the owned native daemon; never exposed as a runner RPC. */
|
|
2131
|
-
setNativeFleetBridge(bridge) {
|
|
2132
|
-
if (!this.nativePaneLifecycle || this.nativeFleetBridge?.current())
|
|
2133
|
-
throw Error("Native Fleet bridge requires one bound pane owner");
|
|
2134
|
-
this.nativeFleetBridge = bridge;
|
|
2135
|
-
}
|
|
2136
|
-
/** Fleet admission and generation checks happen before this synchronous handoff. */
|
|
2137
|
-
acceptNativeFleetMessage(message) {
|
|
2138
|
-
if (!this.nativePaneLifecycle || !this.nativeFleetBridge?.current() || this.deliveryWritesStopping || this.runtimeMonitorsFrozen)
|
|
2139
|
-
return false;
|
|
2140
|
-
if (typeof message.type === "string" && FLEET_RESPONSE_TYPES.has(message.type)) {
|
|
2141
|
-
this.routeFleetResponse(message);
|
|
2142
|
-
return true;
|
|
2143
|
-
}
|
|
2144
|
-
const bridge = this.nativeFleetBridge;
|
|
2145
|
-
const current = () => this.nativeFleetBridge === bridge && bridge.current() && !this.deliveryWritesStopping && !this.runtimeMonitorsFrozen;
|
|
2146
|
-
return this.handleFleetMessage(message, reply => { if (current())
|
|
2147
|
-
this.broadcastFleetMessage(reply); }, current);
|
|
2148
|
-
}
|
|
2149
|
-
broadcastFleetMessage(message) {
|
|
2150
|
-
if (this.nativePaneLifecycle) {
|
|
2151
|
-
if (this.nativeFleetBridge?.current() && !this.runtimeMonitorsFrozen && !this.deliveryWritesStopping)
|
|
2152
|
-
this.nativeFleetBridge.send(message);
|
|
2153
|
-
}
|
|
2154
|
-
else
|
|
2155
|
-
this.ipcServer?.broadcast(message);
|
|
2156
|
-
}
|
|
2157
|
-
fleetTransportAvailable() {
|
|
2158
|
-
return this.nativePaneLifecycle ? !!this.nativeFleetBridge?.current() && !this.runtimeMonitorsFrozen : !!this.ipcServer;
|
|
2159
|
-
}
|
|
2160
|
-
/** Internal lifecycle injection, before start. Native paths and provider files stay on their runner. */
|
|
2161
|
-
setNativePaneLifecycle(native) {
|
|
2162
|
-
if (this.tmux || this.ipcServer || this.nativePaneLifecycle)
|
|
2163
|
-
throw Error("Native pane adapter must be bound before daemon startup");
|
|
2164
|
-
this.nativePaneLifecycle = native;
|
|
2165
|
-
this.backend = native.backend;
|
|
2166
|
-
this.paneTransport = native.host;
|
|
2167
|
-
this.controlClient = native.observation;
|
|
2168
|
-
}
|
|
2169
2066
|
constructor(name, config, instanceDir, topicMode = false, backend, controlClient, rootLogger, runtimeIdentity, spawnGate, stormWindow,
|
|
2170
2067
|
/** Fleet-level "is this CLI's backend down?" memory — see backend-outage.ts. */
|
|
2171
|
-
backendOutage
|
|
2068
|
+
backendOutage) {
|
|
2172
2069
|
super();
|
|
2173
2070
|
this.name = name;
|
|
2174
2071
|
this.config = config;
|
|
@@ -2180,7 +2077,6 @@ export class Daemon extends EventEmitter {
|
|
|
2180
2077
|
this.spawnGate = spawnGate;
|
|
2181
2078
|
this.stormWindow = stormWindow;
|
|
2182
2079
|
this.backendOutage = backendOutage;
|
|
2183
|
-
this.paneTransport = paneTransport;
|
|
2184
2080
|
// The live process owns its adopted configuration. Fleet defaults may be re-resolved in place after a save;
|
|
2185
2081
|
// sharing that object would activate cold changes before the normal restart/apply boundary.
|
|
2186
2082
|
this.config = structuredClone(config);
|
|
@@ -2203,8 +2099,7 @@ export class Daemon extends EventEmitter {
|
|
|
2203
2099
|
this.messageBus.setLogger(this.logger);
|
|
2204
2100
|
// General is the dispatcher — it must stay warm to route messages, so it is
|
|
2205
2101
|
// never auto-paused regardless of auto_pause_after.
|
|
2206
|
-
|
|
2207
|
-
const isGeneral = config.general_topic === true || generalByName(name, config);
|
|
2102
|
+
const isGeneral = config.general_topic === true || name === "general";
|
|
2208
2103
|
const autoPauseMinutes = isGeneral ? 0 : (typeof config.auto_pause_after === "number" ? config.auto_pause_after : 0); // default: disabled
|
|
2209
2104
|
this.autoPauseController = new AutoPauseController(Math.max(0, autoPauseMinutes) * 60_000, readLastInboundAt(instanceDir) ?? Date.now());
|
|
2210
2105
|
// #1209: every real completion clears the in-flight marker, so a
|
|
@@ -2266,19 +2161,12 @@ export class Daemon extends EventEmitter {
|
|
|
2266
2161
|
return outcome === "begun";
|
|
2267
2162
|
}
|
|
2268
2163
|
async durableAttemptEvidence(windowId, handingOffToNativeQueue, steer, rawPaste = false) {
|
|
2269
|
-
let checkpoint = null
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
if (!runtimeTranscript || !this.nativePaneLifecycle.current(runtimeTranscript))
|
|
2273
|
-
throw Error("Native transcript checkpoint is not current; no delivery was written");
|
|
2164
|
+
let checkpoint = null;
|
|
2165
|
+
try {
|
|
2166
|
+
checkpoint = await this.transcriptMonitor?.reconciliationCheckpoint() ?? null;
|
|
2274
2167
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
checkpoint = await this.transcriptMonitor?.reconciliationCheckpoint() ?? null;
|
|
2278
|
-
}
|
|
2279
|
-
catch (err) {
|
|
2280
|
-
this.logger.debug({ err }, "Could not checkpoint transcript before durable delivery");
|
|
2281
|
-
}
|
|
2168
|
+
catch (err) {
|
|
2169
|
+
this.logger.debug({ err }, "Could not checkpoint transcript before durable delivery");
|
|
2282
2170
|
}
|
|
2283
2171
|
const submissionMode = rawPaste ? "raw_paste" : steer
|
|
2284
2172
|
? "steer"
|
|
@@ -2294,9 +2182,8 @@ export class Daemon extends EventEmitter {
|
|
|
2294
2182
|
backendVersion,
|
|
2295
2183
|
windowId: windowId ?? this.tmux?.getWindowId() ?? null,
|
|
2296
2184
|
transcriptPath: checkpoint?.path ?? null,
|
|
2297
|
-
transcriptOffset:
|
|
2298
|
-
transcriptSessionId:
|
|
2299
|
-
...(runtimeTranscript ? { runtimeTranscript } : {}),
|
|
2185
|
+
transcriptOffset: checkpoint?.offset ?? null,
|
|
2186
|
+
transcriptSessionId: checkpoint?.sessionId ?? null,
|
|
2300
2187
|
submissionMode,
|
|
2301
2188
|
queueResumePolicy: queueResumePolicyForAttempt(backend, backendVersion, submissionMode),
|
|
2302
2189
|
};
|
|
@@ -2339,25 +2226,17 @@ export class Daemon extends EventEmitter {
|
|
|
2339
2226
|
const outbox = this.deliveryOutbox;
|
|
2340
2227
|
if (!checkpoint || !outbox?.markConsumed)
|
|
2341
2228
|
return;
|
|
2342
|
-
if (this.nativePaneLifecycle && !checkpoint.runtime)
|
|
2343
|
-
return;
|
|
2344
2229
|
if (verdict.submissionMode !== "steer" && verdict.submissionMode !== "native_queue_handoff")
|
|
2345
2230
|
return;
|
|
2346
2231
|
if (!["claude-code", "codex"].includes(checkpoint.backend))
|
|
2347
2232
|
return;
|
|
2348
2233
|
const spawn = this.spawnGeneration, fence = this.launchFenceEpoch, boot = this.bootId;
|
|
2349
|
-
let location;
|
|
2350
|
-
try {
|
|
2351
|
-
location = checkpoint.runtime ? { reader: this.nativeTranscriptReader(checkpoint.runtime, delivery.deliveryId) } : { path: checkpoint.path, offset: checkpoint.offset };
|
|
2352
|
-
}
|
|
2353
|
-
catch {
|
|
2354
|
-
return;
|
|
2355
|
-
} // The owner changed; an unavailable consumed watch proves nothing.
|
|
2356
2234
|
consumedWatches.start({
|
|
2357
2235
|
deliveryId: delivery.deliveryId,
|
|
2358
2236
|
attemptNo: delivery.attemptNo,
|
|
2359
2237
|
backend: checkpoint.backend,
|
|
2360
|
-
|
|
2238
|
+
path: checkpoint.path,
|
|
2239
|
+
offset: checkpoint.offset,
|
|
2361
2240
|
current: () => !this.deliveryWritesStopping && spawn === this.spawnGeneration && fence === this.launchFenceEpoch,
|
|
2362
2241
|
consumed: (via, evidence) => {
|
|
2363
2242
|
try {
|
|
@@ -2399,18 +2278,15 @@ export class Daemon extends EventEmitter {
|
|
|
2399
2278
|
: humanVerificationId ? `[agend-human-id:${humanVerificationId}]` : null;
|
|
2400
2279
|
if (!marker || !formatted.startsWith(marker))
|
|
2401
2280
|
return;
|
|
2402
|
-
let
|
|
2403
|
-
if (!
|
|
2281
|
+
let checkpoint = verdict.transcriptCheckpoint ?? null;
|
|
2282
|
+
if (!checkpoint) {
|
|
2404
2283
|
try {
|
|
2405
|
-
|
|
2284
|
+
checkpoint = await this.transcriptMonitor?.reconciliationCheckpoint() ?? null;
|
|
2406
2285
|
}
|
|
2407
2286
|
catch (err) {
|
|
2408
2287
|
this.logger.debug({ err }, "Could not checkpoint the transcript before a queued hand-off");
|
|
2409
2288
|
}
|
|
2410
2289
|
}
|
|
2411
|
-
// main→alpha sync: a hand-off record is judged against a local transcript file. A native or remote runtime's
|
|
2412
|
-
// transcript (no local path) has none: it runs as before (✅ at the hand-off), as with no checkpoint at all.
|
|
2413
|
-
const checkpoint = found && typeof found.path === "string" && typeof found.offset === "number" ? { path: found.path, offset: found.offset } : null;
|
|
2414
2290
|
if (!checkpoint)
|
|
2415
2291
|
return; // nothing could judge it later: it runs as before (✅ at the hand-off)
|
|
2416
2292
|
const entry = {
|
|
@@ -2678,34 +2554,24 @@ export class Daemon extends EventEmitter {
|
|
|
2678
2554
|
const spawn = this.spawnGeneration;
|
|
2679
2555
|
const fence = this.launchFenceEpoch;
|
|
2680
2556
|
let last = "unavailable";
|
|
2681
|
-
|
|
2682
|
-
let
|
|
2683
|
-
let evidence = native ? "runtime-transcript-unconfirmed" : OUTPUT_EDGE_ONLY_EVIDENCE;
|
|
2557
|
+
let outcome = "delivered";
|
|
2558
|
+
let evidence = OUTPUT_EDGE_ONLY_EVIDENCE;
|
|
2684
2559
|
// #1647: a raw paste has no marker; its text is the needle, and its pane proof already failed — so without the turn
|
|
2685
2560
|
// in the transcript it stays uncertain (with the pane's reason), never the output-edge outcome.
|
|
2686
2561
|
const needle = rawPaste ? { rawText: rawPaste.text } : delivery.deliveryId;
|
|
2687
2562
|
let found = false;
|
|
2688
2563
|
try {
|
|
2689
|
-
if (this.nativePaneLifecycle && !checkpoint.runtime)
|
|
2690
|
-
throw Error("Native proof cannot read a coordinator-local transcript path");
|
|
2691
|
-
const nativeReader = checkpoint.runtime ? this.nativeTranscriptReader(checkpoint.runtime, needle) : null;
|
|
2692
2564
|
for (let polls = 0; polls <= TRANSCRIPT_PROOF_WINDOW_MS / TRANSCRIPT_PROOF_POLL_MS; polls++) {
|
|
2693
2565
|
if (this.deliveryWritesStopping)
|
|
2694
2566
|
return; // reconciliation owns the row now
|
|
2695
|
-
const look =
|
|
2696
|
-
if (this.deliveryWritesStopping)
|
|
2697
|
-
return;
|
|
2698
|
-
if (spawn !== this.spawnGeneration || fence !== this.launchFenceEpoch) {
|
|
2699
|
-
last = "unavailable";
|
|
2700
|
-
break;
|
|
2701
|
-
}
|
|
2567
|
+
const look = await scanTranscriptForDeliveryMarker(checkpoint.path, checkpoint.offset, checkpoint.backend, needle);
|
|
2702
2568
|
if (look === "user" || look === "absorbed" || look === "queued") {
|
|
2703
2569
|
found = true;
|
|
2704
2570
|
outcome = "delivered";
|
|
2705
2571
|
evidence = transcriptMarkerEvidence(look, !!rawPaste);
|
|
2706
2572
|
break;
|
|
2707
2573
|
}
|
|
2708
|
-
last = look
|
|
2574
|
+
last = look;
|
|
2709
2575
|
if (spawn !== this.spawnGeneration || fence !== this.launchFenceEpoch) {
|
|
2710
2576
|
last = "unavailable";
|
|
2711
2577
|
break;
|
|
@@ -2717,13 +2583,13 @@ export class Daemon extends EventEmitter {
|
|
|
2717
2583
|
// `uncertain`: re-check the same fixed epochs after the last await, before settling (#1207 P2).
|
|
2718
2584
|
if (spawn !== this.spawnGeneration || fence !== this.launchFenceEpoch)
|
|
2719
2585
|
last = "unavailable";
|
|
2720
|
-
if (last === "no-match" &&
|
|
2586
|
+
if (last === "no-match" && evidence === OUTPUT_EDGE_ONLY_EVIDENCE) {
|
|
2721
2587
|
outcome = "uncertain";
|
|
2722
2588
|
evidence = "unverifiable-no-transcript-marker";
|
|
2723
2589
|
}
|
|
2724
2590
|
}
|
|
2725
2591
|
catch (err) {
|
|
2726
|
-
this.logger.debug({ err }, "Transcript proof
|
|
2592
|
+
this.logger.debug({ err }, "Transcript proof of a delivery failed — keeping the output-edge outcome");
|
|
2727
2593
|
}
|
|
2728
2594
|
if (rawPaste && !found) {
|
|
2729
2595
|
outcome = "uncertain";
|
|
@@ -2910,143 +2776,128 @@ export class Daemon extends EventEmitter {
|
|
|
2910
2776
|
}
|
|
2911
2777
|
}
|
|
2912
2778
|
catch { /* corrupt/missing — ignore */ }
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
sessions.push(sessionName);
|
|
2954
|
-
}
|
|
2779
|
+
// 1. IPC server — bridge between MCP server (Claude's child) and daemon
|
|
2780
|
+
const sockPath = join(this.instanceDir, "channel.sock");
|
|
2781
|
+
this.ipcServer = new IpcServer(sockPath, this.logger);
|
|
2782
|
+
// Forward IPC server errors as daemon events (prevents unhandled 'error' crash).
|
|
2783
|
+
// Guard: only forward post-listen errors — startup errors are handled by listen() rejection.
|
|
2784
|
+
let ipcListening = false;
|
|
2785
|
+
this.ipcServer.on("error", (err) => {
|
|
2786
|
+
if (!ipcListening)
|
|
2787
|
+
return; // startup errors handled by listen() rejection
|
|
2788
|
+
this.logger.error({ err, name: this.name }, "IPC server error");
|
|
2789
|
+
this.emit("error", err);
|
|
2790
|
+
});
|
|
2791
|
+
await this.ipcServer.listen();
|
|
2792
|
+
this.startupAdmission?.();
|
|
2793
|
+
ipcListening = true;
|
|
2794
|
+
// Permanent IPC dispatcher: routes responses to pending requests by type+id key
|
|
2795
|
+
this.ipcServer.on("message", (msg) => this.routeFleetResponse(msg));
|
|
2796
|
+
// IPC message relay: when daemon wants to push a channel message to Claude,
|
|
2797
|
+
// it broadcasts to all IPC clients (the MCP server is one of them).
|
|
2798
|
+
// When MCP server sends a tool_call, daemon handles it via the messageBus.
|
|
2799
|
+
this.ipcServer.on("message", (msg, socket) => {
|
|
2800
|
+
if (msg.type === "tool_call") {
|
|
2801
|
+
// MCP server forwarding a Claude tool call (reply, react, edit, download)
|
|
2802
|
+
this.handleToolCall(msg, socket);
|
|
2803
|
+
}
|
|
2804
|
+
else if (msg.type === "mcp_ready") {
|
|
2805
|
+
this.handleMcpReady(msg, socket);
|
|
2806
|
+
}
|
|
2807
|
+
else if (msg.type === "pong") {
|
|
2808
|
+
this.handleMcpPong(msg, socket);
|
|
2809
|
+
}
|
|
2810
|
+
else if (msg.type === "query_sessions") {
|
|
2811
|
+
// Fleet manager asks for all registered session names (catches sessions
|
|
2812
|
+
// that sent mcp_ready before fleet manager connected).
|
|
2813
|
+
const sessions = [];
|
|
2814
|
+
for (const [s, sessionName] of this.socketSessionNames) {
|
|
2815
|
+
if (!s.destroyed && sessionName !== this.name) {
|
|
2816
|
+
// Individual mcp_ready for initial registration path
|
|
2817
|
+
this.ipcServer?.send(socket, { type: "mcp_ready", sessionName });
|
|
2818
|
+
sessions.push(sessionName);
|
|
2955
2819
|
}
|
|
2956
|
-
// Batch response for prune path
|
|
2957
|
-
this.ipcServer?.send(socket, { type: "query_sessions_response", sessions });
|
|
2958
2820
|
}
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
}
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
this.
|
|
2969
|
-
|
|
2970
|
-
|
|
2821
|
+
// Batch response for prune path
|
|
2822
|
+
this.ipcServer?.send(socket, { type: "query_sessions_response", sessions });
|
|
2823
|
+
}
|
|
2824
|
+
else if (msg.type === "fleet_inbound") {
|
|
2825
|
+
// Fleet manager routed a message to us (topic mode)
|
|
2826
|
+
const meta = msg.meta;
|
|
2827
|
+
const targetSession = msg.targetSession;
|
|
2828
|
+
const deliveryEpoch = this.captureDeliveryEpoch(msg.delivery_epoch);
|
|
2829
|
+
void this.wake().then(() => {
|
|
2830
|
+
this.pushChannelMessage(msg.content, meta, targetSession, deliveryEpoch);
|
|
2831
|
+
}).catch(err => {
|
|
2832
|
+
this.deferDurableDelivery(meta, `target wake failed before pane submission: ${err.message}`);
|
|
2833
|
+
this.logger.error({ err: err.message }, "Wake failed for inbound delivery");
|
|
2971
2834
|
});
|
|
2972
|
-
this.tmux = acquired.pane;
|
|
2973
|
-
this.nativeTranscriptSource = acquired.source;
|
|
2974
|
-
nativeDisposition = acquired.disposition;
|
|
2975
|
-
this.lastSpawnAt = Date.now();
|
|
2976
|
-
this.setProcessStatus("running");
|
|
2977
|
-
this.bindInstanceStateOutputListener(this.tmux.getWindowId());
|
|
2978
|
-
this.saveSessionId();
|
|
2979
|
-
// New/resumed native processes can still be painting their first frame. Keep deliveries behind the same
|
|
2980
|
-
// bounded dialog/readiness scan as local startup. An already-running reattachment may be busy: do not
|
|
2981
|
-
// wait for that work to finish or inject a startup key into it.
|
|
2982
|
-
if (acquired.disposition === "reattached") {
|
|
2983
|
-
if (this.backend?.binaryName === "codex") {
|
|
2984
|
-
const native = this.nativePaneLifecycle, spawn = this.spawnGeneration, fence = this.launchFenceEpoch, attempt = this.launchAttempt;
|
|
2985
|
-
try {
|
|
2986
|
-
const pane = await acquired.pane.capturePane();
|
|
2987
|
-
this.startupAdmission?.();
|
|
2988
|
-
if (!this.startupAborted && !this.deliveryWritesStopping && this.nativePaneLifecycle === native && this.tmux === acquired.pane
|
|
2989
|
-
&& spawn === this.spawnGeneration && fence === this.launchFenceEpoch && attempt === this.launchAttempt && native.current())
|
|
2990
|
-
this.takeQuotaReplayBaseline(pane);
|
|
2991
|
-
}
|
|
2992
|
-
catch { /* An old runner or unavailable proof keeps the existing fail-closed scanner. */ }
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
2995
|
-
else {
|
|
2996
|
-
if (!await this.finishStartupScan(120_000))
|
|
2997
|
-
throw Error("Native CLI exited during startup; retained session was not replaced");
|
|
2998
|
-
this.startupAdmission?.();
|
|
2999
|
-
if (this.startupAborted || this.deliveryWritesStopping || !this.nativePaneLifecycle.current())
|
|
3000
|
-
throw Error("Native launch was superseded");
|
|
3001
|
-
}
|
|
3002
2835
|
}
|
|
3003
|
-
|
|
3004
|
-
this.
|
|
2836
|
+
else if (msg.type === "raw_paste") {
|
|
2837
|
+
this.handleRawPasteIpcMessage(msg);
|
|
3005
2838
|
}
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
// 2. Tmux — ensure session, create window if not alive
|
|
3009
|
-
await this.paneHost.ensureSession(this.tmuxSessionName);
|
|
3010
|
-
this.startupAdmission?.();
|
|
3011
|
-
this.tmux = this.paneHost.bind(this.tmuxSessionName, "", resolveTmuxLogicalSize(this.config.terminal), this.controlClient);
|
|
3012
|
-
// Strategy A: always start fresh Claude window (MCP server has no reconnection)
|
|
3013
|
-
// Kill any existing window from previous run
|
|
3014
|
-
const windowIdFile = join(this.instanceDir, "window-id");
|
|
3015
|
-
if (existsSync(windowIdFile)) {
|
|
3016
|
-
const savedId = readFileSync(windowIdFile, "utf-8").trim();
|
|
3017
|
-
if (savedId) {
|
|
3018
|
-
const oldTmux = this.paneHost.bind(this.tmuxSessionName, savedId);
|
|
3019
|
-
if (await oldTmux.isWindowAlive()) {
|
|
3020
|
-
this.startupAdmission?.();
|
|
3021
|
-
await this.checkpointSessionId();
|
|
3022
|
-
this.startupAdmission?.();
|
|
3023
|
-
await oldTmux.killWindow();
|
|
3024
|
-
this.startupAdmission?.();
|
|
3025
|
-
this.logger.info({ savedId }, "Killed old tmux window for fresh start");
|
|
3026
|
-
}
|
|
3027
|
-
}
|
|
2839
|
+
else if (msg.type === "config_update") {
|
|
2840
|
+
this.applyConfigUpdate(msg.config);
|
|
3028
2841
|
}
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
if (!resumed) {
|
|
3033
|
-
await this.injectSnapshotMessage(this.startupAdmission);
|
|
3034
|
-
this.startupAdmission?.();
|
|
2842
|
+
else if (msg.type === "steer") {
|
|
2843
|
+
const meta = (msg.meta ?? {});
|
|
2844
|
+
this.steerMessage(msg.content, meta, this.captureDeliveryEpoch(msg.delivery_epoch));
|
|
3035
2845
|
}
|
|
3036
|
-
else {
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
2846
|
+
else if (msg.type === "btw") {
|
|
2847
|
+
const meta = (msg.meta ?? {});
|
|
2848
|
+
this.btwMessage(msg.content, meta, this.captureDeliveryEpoch(msg.delivery_epoch));
|
|
2849
|
+
}
|
|
2850
|
+
else if (msg.type === "fleet_schedule_trigger") {
|
|
2851
|
+
const payload = msg.payload;
|
|
2852
|
+
const meta = msg.meta;
|
|
2853
|
+
const deliveryEpoch = this.captureDeliveryEpoch(msg.delivery_epoch);
|
|
2854
|
+
void this.wake().then(() => this.pushChannelMessage(payload.message, meta, undefined, deliveryEpoch)).catch(err => {
|
|
2855
|
+
this.logger.error({ err: err.message }, "Wake failed for scheduled delivery");
|
|
2856
|
+
});
|
|
2857
|
+
}
|
|
2858
|
+
else if (msg.type === "query_instance_state") {
|
|
2859
|
+
void this.respondToInstanceStateQuery(msg, socket);
|
|
2860
|
+
}
|
|
2861
|
+
});
|
|
2862
|
+
// 2. Tmux — ensure session, create window if not alive
|
|
2863
|
+
await TmuxManager.ensureSession(this.tmuxSessionName);
|
|
2864
|
+
this.startupAdmission?.();
|
|
2865
|
+
this.tmux = new TmuxManager(this.tmuxSessionName, "", resolveTmuxLogicalSize(this.config.terminal), this.controlClient);
|
|
2866
|
+
// Strategy A: always start fresh Claude window (MCP server has no reconnection)
|
|
2867
|
+
// Kill any existing window from previous run
|
|
2868
|
+
const windowIdFile = join(this.instanceDir, "window-id");
|
|
2869
|
+
if (existsSync(windowIdFile)) {
|
|
2870
|
+
const savedId = readFileSync(windowIdFile, "utf-8").trim();
|
|
2871
|
+
if (savedId) {
|
|
2872
|
+
const oldTmux = new TmuxManager(this.tmuxSessionName, savedId);
|
|
2873
|
+
if (await oldTmux.isWindowAlive()) {
|
|
2874
|
+
this.startupAdmission?.();
|
|
2875
|
+
await this.checkpointSessionId();
|
|
2876
|
+
this.startupAdmission?.();
|
|
2877
|
+
await oldTmux.killWindow();
|
|
2878
|
+
this.startupAdmission?.();
|
|
2879
|
+
this.logger.info({ savedId }, "Killed old tmux window for fresh start");
|
|
3040
2880
|
}
|
|
3041
|
-
catch { /* may not exist */ }
|
|
3042
2881
|
}
|
|
3043
2882
|
}
|
|
3044
|
-
|
|
3045
|
-
|
|
2883
|
+
const resumed = await this.spawnClaudeWindow();
|
|
2884
|
+
this.startupAdmission?.();
|
|
2885
|
+
this.isNewSession = !resumed;
|
|
2886
|
+
if (!resumed) {
|
|
2887
|
+
await this.injectSnapshotMessage(this.startupAdmission);
|
|
2888
|
+
this.startupAdmission?.();
|
|
2889
|
+
}
|
|
2890
|
+
else {
|
|
2891
|
+
// Clean up stale snapshot file — resume restored full context, snapshot not needed
|
|
2892
|
+
try {
|
|
2893
|
+
unlinkSync(join(this.instanceDir, "rotation-state.json"));
|
|
2894
|
+
}
|
|
2895
|
+
catch { /* may not exist */ }
|
|
2896
|
+
}
|
|
3046
2897
|
// #1209: conditional continuation for the turn interrupted by the last
|
|
3047
2898
|
// restart, if the gates allow. Detached; the gate
|
|
3048
2899
|
// consumes its one-shot marker first and never throws into boot.
|
|
3049
|
-
const legacyResume = this.
|
|
2900
|
+
const legacyResume = this.maybeResumeInterruptedTurn().catch(() => "unknown");
|
|
3050
2901
|
const recoveryOwner = JSON.stringify(this.interactionOwner());
|
|
3051
2902
|
void Promise.allSettled([legacyResume]).then(() => {
|
|
3052
2903
|
if (JSON.stringify(this.interactionOwner()) === recoveryOwner) {
|
|
@@ -3065,7 +2916,7 @@ export class Daemon extends EventEmitter {
|
|
|
3065
2916
|
// (statusline transcript); codex/kiro/opencode read their CLI's own
|
|
3066
2917
|
// conversation store via a pluggable source. Backends with no known
|
|
3067
2918
|
// source stay inert exactly as before.
|
|
3068
|
-
this.transcriptMonitor = this.buildTranscriptMonitor(
|
|
2919
|
+
this.transcriptMonitor = this.buildTranscriptMonitor(createTranscriptSource(this.config.backend ?? "claude-code", this.config.working_directory, this.credentialProfileStore(), () => this.backend?.transcriptLaunch?.() ?? null));
|
|
3069
2920
|
const transcriptMonitor = this.transcriptMonitor;
|
|
3070
2921
|
const transcriptFence = this.launchFenceEpoch;
|
|
3071
2922
|
// Baseline in the isolate before this daemon accepts new work. A
|
|
@@ -3121,15 +2972,13 @@ export class Daemon extends EventEmitter {
|
|
|
3121
2972
|
if (hangConfig?.enabled !== false) {
|
|
3122
2973
|
this.hangDetector = new HangDetector();
|
|
3123
2974
|
}
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
this.
|
|
3130
|
-
|
|
3131
|
-
});
|
|
3132
|
-
}
|
|
2975
|
+
// 8. Context guardian
|
|
2976
|
+
const statusFile = join(this.instanceDir, "statusline.json");
|
|
2977
|
+
this.guardian = new ContextGuardian(this.config.context_guardian ?? {}, this.logger, statusFile);
|
|
2978
|
+
this.guardian.startWatching();
|
|
2979
|
+
this.guardian.on("status_update", () => {
|
|
2980
|
+
this.saveSessionId();
|
|
2981
|
+
});
|
|
3133
2982
|
// Context rotation removed: all CLI backends have built-in auto-compact.
|
|
3134
2983
|
// Crash recovery (health check + respawn with snapshot) is retained below.
|
|
3135
2984
|
}
|
|
@@ -3182,7 +3031,7 @@ export class Daemon extends EventEmitter {
|
|
|
3182
3031
|
this.socketPids.delete(socket);
|
|
3183
3032
|
// Notify fleet manager so it can clean up sessionRegistry
|
|
3184
3033
|
if (sessionName !== this.name) {
|
|
3185
|
-
this.
|
|
3034
|
+
this.ipcServer?.broadcast({ type: "session_disconnected", sessionName });
|
|
3186
3035
|
}
|
|
3187
3036
|
});
|
|
3188
3037
|
}
|
|
@@ -3198,16 +3047,11 @@ export class Daemon extends EventEmitter {
|
|
|
3198
3047
|
// sub-agent's server may have left a dead pid in the slot).
|
|
3199
3048
|
this.noteMcpProofOfLife("mcp_ready", typeof msg.pid === "number" ? msg.pid : undefined);
|
|
3200
3049
|
}
|
|
3201
|
-
this.
|
|
3050
|
+
this.ipcServer?.broadcast({ type: "mcp_ready", sessionName });
|
|
3202
3051
|
}
|
|
3203
3052
|
checkMcpServerAlive() {
|
|
3204
3053
|
if (this.isPaused)
|
|
3205
3054
|
return;
|
|
3206
|
-
if (this.nativePaneLifecycle) {
|
|
3207
|
-
if (this.nativePaneLifecycle.mcpProof() === "alive")
|
|
3208
|
-
this.noteMcpProofOfLife("connection");
|
|
3209
|
-
return; // No native PID/socket guessing or restart from an unknown helper observation.
|
|
3210
|
-
}
|
|
3211
3055
|
const status = mcpServerState(this.instanceDir);
|
|
3212
3056
|
if (status.state === "alive") {
|
|
3213
3057
|
this.mcpServedGeneration = this.spawnGeneration;
|
|
@@ -3291,8 +3135,6 @@ export class Daemon extends EventEmitter {
|
|
|
3291
3135
|
* server from a third-party one, and failed the whole launch for either.
|
|
3292
3136
|
*/
|
|
3293
3137
|
checkFleetMcpNeverConnected() {
|
|
3294
|
-
if (this.nativePaneLifecycle)
|
|
3295
|
-
return; // Native helper presence owns this observation.
|
|
3296
3138
|
if (this.config.agent_mode === "cli")
|
|
3297
3139
|
return; // no MCP server by design
|
|
3298
3140
|
if (this.lastSpawnAt === 0 || this.mcpServedGeneration === this.spawnGeneration)
|
|
@@ -3503,8 +3345,6 @@ export class Daemon extends EventEmitter {
|
|
|
3503
3345
|
* proof that tools are being served, whatever channel.mcp.pid says.
|
|
3504
3346
|
*/
|
|
3505
3347
|
mcpServerAlive() {
|
|
3506
|
-
if (this.nativePaneLifecycle)
|
|
3507
|
-
return this.nativePaneLifecycle.mcpProof() === "alive" ? { alive: true, source: "connection" } : { alive: false, source: "none" };
|
|
3508
3348
|
const status = mcpServerState(this.instanceDir);
|
|
3509
3349
|
if (status.state === "alive")
|
|
3510
3350
|
return { alive: true, source: "pid", pid: status.pid };
|
|
@@ -3569,7 +3409,7 @@ export class Daemon extends EventEmitter {
|
|
|
3569
3409
|
this.mcpDeathNotifiedForPid = null;
|
|
3570
3410
|
this.mcpDeathDeferredForPid = null;
|
|
3571
3411
|
this.clearMcpRestartRequest();
|
|
3572
|
-
if (
|
|
3412
|
+
if (pid && mcpServerState(this.instanceDir).state !== "alive")
|
|
3573
3413
|
this.repairMcpPidSlot(pid, source);
|
|
3574
3414
|
}
|
|
3575
3415
|
emitMcpRecovered(source, pid) {
|
|
@@ -3616,26 +3456,6 @@ export class Daemon extends EventEmitter {
|
|
|
3616
3456
|
// ended this instance's health loop because scheduleNext() sat after the
|
|
3617
3457
|
// throwing code. Catch, log, and keep checking.
|
|
3618
3458
|
try {
|
|
3619
|
-
if (this.nativePaneLifecycle) {
|
|
3620
|
-
if (this.healthCheckPaused) {
|
|
3621
|
-
scheduleNext();
|
|
3622
|
-
return;
|
|
3623
|
-
}
|
|
3624
|
-
const native = this.nativePaneLifecycle, pane = this.tmux;
|
|
3625
|
-
const status = await pane?.getPaneStatus();
|
|
3626
|
-
if (this.runtimeMonitorsFrozen || native !== this.nativePaneLifecycle || pane !== this.tmux)
|
|
3627
|
-
return;
|
|
3628
|
-
const snapshot = native.snapshot?.();
|
|
3629
|
-
if (status?.alive === false && snapshot?.state === "exited") {
|
|
3630
|
-
this.healthCheckPaused = true;
|
|
3631
|
-
this.setProcessStatus(snapshot.exitCode === 0 ? "stopped" : "crashed");
|
|
3632
|
-
this.emit("native_pane_exited", { name: this.name, snapshot, owner: this.interactionOwner() });
|
|
3633
|
-
}
|
|
3634
|
-
else if (status?.alive)
|
|
3635
|
-
this.checkMcpServerAlive();
|
|
3636
|
-
scheduleNext();
|
|
3637
|
-
return;
|
|
3638
|
-
}
|
|
3639
3459
|
// Instance directory removed externally (e.g. `rm -rf ~/.agend/instances/<name>`).
|
|
3640
3460
|
// Stop the loop permanently — otherwise every tick triggers a respawn, whose
|
|
3641
3461
|
// writeRotationSnapshot fails with ENOENT and gets caught as "Failed to respawn",
|
|
@@ -3771,13 +3591,13 @@ export class Daemon extends EventEmitter {
|
|
|
3771
3591
|
let inWindowLossBurst = false;
|
|
3772
3592
|
let nullReason;
|
|
3773
3593
|
if (!paneStatus) {
|
|
3774
|
-
const serverAlive = await
|
|
3594
|
+
const serverAlive = await TmuxManager.sessionExists(this.tmuxSessionName);
|
|
3775
3595
|
if (discardStaleHealth())
|
|
3776
3596
|
return;
|
|
3777
3597
|
// A server may have already restarted before this daemon's health
|
|
3778
3598
|
// tick. The new PID is the durable generation boundary: treat it as
|
|
3779
3599
|
// a fleet storm even though `has-session` is true again.
|
|
3780
|
-
const serverPid = serverAlive ? await
|
|
3600
|
+
const serverPid = serverAlive ? await TmuxManager.getServerPid(this.tmuxSessionName) : null;
|
|
3781
3601
|
if (discardStaleHealth())
|
|
3782
3602
|
return;
|
|
3783
3603
|
const generationChanged = serverAlive && this.stormWindow?.observeServerAlive(serverPid) === true;
|
|
@@ -3806,7 +3626,7 @@ export class Daemon extends EventEmitter {
|
|
|
3806
3626
|
// the window truly no longer exists vs a transient query glitch.
|
|
3807
3627
|
nullReason = "no_window";
|
|
3808
3628
|
try {
|
|
3809
|
-
const windows = await
|
|
3629
|
+
const windows = await TmuxManager.listWindowsStrict(this.tmuxSessionName, this.controlClient);
|
|
3810
3630
|
if (discardStaleHealth())
|
|
3811
3631
|
return;
|
|
3812
3632
|
this.windowQueryFailureTicks = 0;
|
|
@@ -4053,10 +3873,10 @@ export class Daemon extends EventEmitter {
|
|
|
4053
3873
|
// Wrapped in try-catch: if tmux server is dead, listWindows throws —
|
|
4054
3874
|
// must not block spawnClaudeWindow (which calls ensureSession).
|
|
4055
3875
|
try {
|
|
4056
|
-
const windows = await
|
|
3876
|
+
const windows = await TmuxManager.listWindows(this.tmuxSessionName);
|
|
4057
3877
|
for (const w of windows) {
|
|
4058
3878
|
if (w.name === this.name) {
|
|
4059
|
-
const tm =
|
|
3879
|
+
const tm = new TmuxManager(this.tmuxSessionName, w.id);
|
|
4060
3880
|
await tm.killWindow();
|
|
4061
3881
|
}
|
|
4062
3882
|
}
|
|
@@ -4201,7 +4021,7 @@ export class Daemon extends EventEmitter {
|
|
|
4201
4021
|
// Force the next ready capture to emit a fresh transition after respawn.
|
|
4202
4022
|
this.instanceState = "working";
|
|
4203
4023
|
}
|
|
4204
|
-
this.
|
|
4024
|
+
this.ipcServer?.broadcast({
|
|
4205
4025
|
type: "instance_process_state",
|
|
4206
4026
|
instanceName: this.name,
|
|
4207
4027
|
status,
|
|
@@ -4397,15 +4217,12 @@ export class Daemon extends EventEmitter {
|
|
|
4397
4217
|
for (const key of dialog.keys) {
|
|
4398
4218
|
if (stale())
|
|
4399
4219
|
return;
|
|
4400
|
-
const keyScreen = this.nativePaneLifecycle ? await pollTmux.capturePane() : currentPane;
|
|
4401
|
-
if (stale() || !Daemon.dialogMatches(dialog, keyScreen))
|
|
4402
|
-
return;
|
|
4403
4220
|
let sent = false;
|
|
4404
4221
|
if (SPECIAL_KEYS.has(key)) {
|
|
4405
|
-
sent = await
|
|
4222
|
+
sent = await pollTmux.sendSpecialKey(key);
|
|
4406
4223
|
}
|
|
4407
4224
|
else if (dialog.literalKeys) {
|
|
4408
|
-
sent = await
|
|
4225
|
+
sent = await pollTmux.sendKeys(key); // typed, no Enter (#2872)
|
|
4409
4226
|
}
|
|
4410
4227
|
else {
|
|
4411
4228
|
sent = await pollTmux.pasteText(key, this.systemPasteOptions());
|
|
@@ -4776,20 +4593,7 @@ export class Daemon extends EventEmitter {
|
|
|
4776
4593
|
*/
|
|
4777
4594
|
async sendEscape() {
|
|
4778
4595
|
const cancelKey = this.backend?.getCancelKey() ?? "Escape";
|
|
4779
|
-
|
|
4780
|
-
if (!tmux)
|
|
4781
|
-
return;
|
|
4782
|
-
if (this.nativePaneLifecycle) {
|
|
4783
|
-
// A native pane's composer proof cannot see a permission dialog, so an unproved key is withheld there. The cancel
|
|
4784
|
-
// is the person's own interrupt, keyed on the screen read just before (as the dialog answer path is): what Esc
|
|
4785
|
-
// does on Linux's tmux pane, on the same screen, with the same key.
|
|
4786
|
-
const screen = await tmux.capturePane().catch(() => null);
|
|
4787
|
-
if (screen === null)
|
|
4788
|
-
return;
|
|
4789
|
-
await tmux.sendSpecialKey(cancelKey, undefined, { kind: "dialog", screen });
|
|
4790
|
-
return;
|
|
4791
|
-
}
|
|
4792
|
-
await tmux.sendSpecialKey(cancelKey);
|
|
4596
|
+
await this.tmux?.sendSpecialKey(cancelKey);
|
|
4793
4597
|
}
|
|
4794
4598
|
/**
|
|
4795
4599
|
* Drop every not-yet-started pane delivery which predates a user cancel.
|
|
@@ -4855,7 +4659,7 @@ export class Daemon extends EventEmitter {
|
|
|
4855
4659
|
return;
|
|
4856
4660
|
const outcome = follower.look(pane);
|
|
4857
4661
|
if (outcome) {
|
|
4858
|
-
this.
|
|
4662
|
+
this.ipcServer?.broadcast({ type: "compact_pane_result", id, owner, outcome });
|
|
4859
4663
|
return;
|
|
4860
4664
|
}
|
|
4861
4665
|
}
|
|
@@ -4875,7 +4679,7 @@ export class Daemon extends EventEmitter {
|
|
|
4875
4679
|
const reportSwitch = (result) => {
|
|
4876
4680
|
if (!ownSwitch)
|
|
4877
4681
|
return;
|
|
4878
|
-
this.
|
|
4682
|
+
this.ipcServer?.broadcast({ type: "runtime_switch_result", id: ownSwitch.id, ...result });
|
|
4879
4683
|
};
|
|
4880
4684
|
// Board 003648ac: the fleet follows a web /compact from just before its paste is written: the transcript's end then
|
|
4881
4685
|
// (taken here, under this launch, before the write) and the launch it was written under ride with the notice — once.
|
|
@@ -4890,7 +4694,7 @@ export class Daemon extends EventEmitter {
|
|
|
4890
4694
|
if (!notifyWritten || told)
|
|
4891
4695
|
return;
|
|
4892
4696
|
told = true;
|
|
4893
|
-
this.
|
|
4697
|
+
this.ipcServer?.broadcast({ type: "raw_paste_written", id: notifyWritten, outcome: written ? "written" : "not_written",
|
|
4894
4698
|
...(written ? { owner, checkpoint, ...(paneFollower ? { pane: true } : {}) } : {}) });
|
|
4895
4699
|
if (written && paneFollower)
|
|
4896
4700
|
void this.followCompactPane(notifyWritten, owner, paneFollower);
|
|
@@ -5052,11 +4856,10 @@ export class Daemon extends EventEmitter {
|
|
|
5052
4856
|
const press = (target, cursor, key) => this.paneWriteLock.run(async () => {
|
|
5053
4857
|
if (this.tmux !== tmux)
|
|
5054
4858
|
return false;
|
|
5055
|
-
const
|
|
5056
|
-
const now = claudeSwitchDialog(screen);
|
|
4859
|
+
const now = claudeSwitchDialog(await read());
|
|
5057
4860
|
if (!now || now.kind !== "model" || now.target !== target || (cursor !== null && now.cursor !== cursor))
|
|
5058
4861
|
return false;
|
|
5059
|
-
return
|
|
4862
|
+
return tmux.sendSpecialKey(key);
|
|
5060
4863
|
});
|
|
5061
4864
|
const gone = async () => {
|
|
5062
4865
|
const until = performance.now() + OWN_SWITCH_SETTLE_MS;
|
|
@@ -5145,12 +4948,9 @@ export class Daemon extends EventEmitter {
|
|
|
5145
4948
|
return false;
|
|
5146
4949
|
const specialKeys = new Set(["Up", "Down", "Enter", "Escape", "Right", "Left"]);
|
|
5147
4950
|
for (const key of dialog.keys) {
|
|
5148
|
-
const keyScreen = this.nativePaneLifecycle ? await this.tmux.capturePane() : currentPane;
|
|
5149
|
-
if (!matches(keyScreen))
|
|
5150
|
-
return false;
|
|
5151
4951
|
const ok = specialKeys.has(key)
|
|
5152
|
-
? await
|
|
5153
|
-
: await
|
|
4952
|
+
? await this.tmux.sendSpecialKey(key)
|
|
4953
|
+
: await this.tmux.sendKeys(key);
|
|
5154
4954
|
if (!ok)
|
|
5155
4955
|
return false;
|
|
5156
4956
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -5393,7 +5193,7 @@ export class Daemon extends EventEmitter {
|
|
|
5393
5193
|
await this.tmux.sendSpecialKey("Escape").catch(() => false);
|
|
5394
5194
|
return true;
|
|
5395
5195
|
}
|
|
5396
|
-
async stop(
|
|
5196
|
+
async stop() {
|
|
5397
5197
|
this.publishWorkingState("before_stop");
|
|
5398
5198
|
this.logger.info("Stopping daemon instance");
|
|
5399
5199
|
this.clearQuitRelaunchWatch();
|
|
@@ -5415,18 +5215,8 @@ export class Daemon extends EventEmitter {
|
|
|
5415
5215
|
}
|
|
5416
5216
|
if (this.adapter)
|
|
5417
5217
|
await this.adapter.stop();
|
|
5418
|
-
if (this.nativePaneLifecycle) {
|
|
5419
|
-
this.healthCheckPaused = true;
|
|
5420
|
-
this.saveSessionId();
|
|
5421
|
-
await this.nativePaneLifecycle.release(options.nativePane ?? "detach");
|
|
5422
|
-
try {
|
|
5423
|
-
unlinkSync(join(this.instanceDir, "daemon.pid"));
|
|
5424
|
-
}
|
|
5425
|
-
catch { /* metadata only */ }
|
|
5426
|
-
return;
|
|
5427
|
-
}
|
|
5428
5218
|
// Notify MCP servers of graceful shutdown (prevents reconnect attempts)
|
|
5429
|
-
this.
|
|
5219
|
+
this.ipcServer?.broadcast({ type: "shutdown" });
|
|
5430
5220
|
// Quit CLI FIRST — this kills MCP server child processes cleanly.
|
|
5431
5221
|
// IPC must stay open during quit so MCP servers receive the shutdown message.
|
|
5432
5222
|
if (this.tmux) {
|
|
@@ -5572,24 +5362,6 @@ export class Daemon extends EventEmitter {
|
|
|
5572
5362
|
freshChoice: this.recoveryFreshChoice || this.isNewSession && !this.bootSkippedResume, crashLoopFresh: this.recoveryCrashLoopFresh,
|
|
5573
5363
|
cancelled: this.recoveryCancelled, background: this.workingBackgroundObservation };
|
|
5574
5364
|
}
|
|
5575
|
-
/** Observe this host General before its approved switch. No keys, process signals or provider writes. */
|
|
5576
|
-
async generalHostOwner() {
|
|
5577
|
-
const pane = this.tmux, owner = JSON.stringify(this.interactionOwner());
|
|
5578
|
-
if (!this.config.general_topic || this.nativePaneLifecycle || !pane || !/^@\d+$/.test(pane.getWindowId()))
|
|
5579
|
-
throw Error("General host owner is unavailable");
|
|
5580
|
-
const status = await pane.getPaneStatus();
|
|
5581
|
-
if (!status?.alive || !status.pid || status.pid <= 1)
|
|
5582
|
-
throw Error("General host process cannot be proven");
|
|
5583
|
-
const checkpoint = await this.transcriptMonitor?.reconciliationCheckpoint();
|
|
5584
|
-
if (this.tmux !== pane || owner !== JSON.stringify(this.interactionOwner()))
|
|
5585
|
-
throw Error("General host owner changed during observation");
|
|
5586
|
-
const backend = this.config.backend ?? "claude-code";
|
|
5587
|
-
let sessionId = this.backend?.getSessionId() ?? undefined;
|
|
5588
|
-
if (backend === "codex" && checkpoint)
|
|
5589
|
-
sessionId = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i.exec(checkpoint.path)?.[1];
|
|
5590
|
-
return { kind: "tmux", windowId: pane.getWindowId(), pid: status.pid,
|
|
5591
|
-
...(typeof sessionId === "string" && sessionId.length > 0 && sessionId.length <= 256 && !/[\p{Cc}\p{Cf}]/u.test(sessionId) ? { pin: { backend, sessionId } } : {}) };
|
|
5592
|
-
}
|
|
5593
5365
|
/** Local system work: no user turn, channel reply target, wake or replay of an original request. */
|
|
5594
5366
|
async deliverWorkingRecovery(content, delivery, admitted) {
|
|
5595
5367
|
const tmux = this.tmux, owner = JSON.stringify(this.interactionOwner()), epoch = this.deliveryEpoch;
|
|
@@ -5610,11 +5382,7 @@ export class Daemon extends EventEmitter {
|
|
|
5610
5382
|
|| !this.paneAuthoritativelyIdle(pane) || this.inputTransientInPane(pane)
|
|
5611
5383
|
|| this.backend?.backgroundWorkRunning?.(pane) === true)
|
|
5612
5384
|
return;
|
|
5613
|
-
if (
|
|
5614
|
-
|| !!this.backend?.isDeliveryInputReadyPane && !this.backend.isDeliveryInputReadyPane(pane)
|
|
5615
|
-
: await tmux.getPaneInputMode?.() !== "raw")
|
|
5616
|
-
return;
|
|
5617
|
-
if (!current())
|
|
5385
|
+
if (await tmux.getPaneInputMode?.() !== "raw" || !current())
|
|
5618
5386
|
return;
|
|
5619
5387
|
const evidence = await this.durableAttemptEvidence(tmux.getWindowId(), false, false);
|
|
5620
5388
|
if (!current())
|
|
@@ -5705,7 +5473,7 @@ export class Daemon extends EventEmitter {
|
|
|
5705
5473
|
this.logger.debug({ err }, "Interaction listener failed");
|
|
5706
5474
|
}
|
|
5707
5475
|
try {
|
|
5708
|
-
this.
|
|
5476
|
+
this.ipcServer?.broadcast({ type: "instance_interaction", instanceName: this.name, interaction });
|
|
5709
5477
|
}
|
|
5710
5478
|
catch (err) {
|
|
5711
5479
|
this.logger.debug({ err }, "Interaction broadcast failed");
|
|
@@ -5793,56 +5561,6 @@ export class Daemon extends EventEmitter {
|
|
|
5793
5561
|
}
|
|
5794
5562
|
return true;
|
|
5795
5563
|
}
|
|
5796
|
-
/** Shared Fleet inputs: socket and native transports retain the same wake, epoch and raw-paste semantics. */
|
|
5797
|
-
handleFleetMessage(msg, send, current = () => true) {
|
|
5798
|
-
if (msg.type === "query_sessions") {
|
|
5799
|
-
send({ type: "query_sessions_response", sessions: [] });
|
|
5800
|
-
}
|
|
5801
|
-
else if (msg.type === "fleet_inbound") {
|
|
5802
|
-
const meta = msg.meta;
|
|
5803
|
-
const targetSession = msg.targetSession;
|
|
5804
|
-
const deliveryEpoch = this.captureDeliveryEpoch(msg.delivery_epoch);
|
|
5805
|
-
void this.wake().then(() => {
|
|
5806
|
-
if (!current()) {
|
|
5807
|
-
this.deferDurableDelivery(meta, "native channel owner changed before pane submission");
|
|
5808
|
-
return;
|
|
5809
|
-
}
|
|
5810
|
-
this.pushChannelMessage(msg.content, meta, targetSession, deliveryEpoch);
|
|
5811
|
-
}).catch(err => {
|
|
5812
|
-
this.deferDurableDelivery(meta, `target wake failed before pane submission: ${err.message}`);
|
|
5813
|
-
this.logger.error({ err: err.message }, "Wake failed for inbound delivery");
|
|
5814
|
-
});
|
|
5815
|
-
}
|
|
5816
|
-
else if (msg.type === "raw_paste") {
|
|
5817
|
-
this.handleRawPasteIpcMessage(msg);
|
|
5818
|
-
}
|
|
5819
|
-
else if (msg.type === "config_update") {
|
|
5820
|
-
this.applyConfigUpdate(msg.config);
|
|
5821
|
-
}
|
|
5822
|
-
else if (msg.type === "steer") {
|
|
5823
|
-
const meta = (msg.meta ?? {});
|
|
5824
|
-
this.steerMessage(msg.content, meta, this.captureDeliveryEpoch(msg.delivery_epoch));
|
|
5825
|
-
}
|
|
5826
|
-
else if (msg.type === "btw") {
|
|
5827
|
-
const meta = (msg.meta ?? {});
|
|
5828
|
-
this.btwMessage(msg.content, meta, this.captureDeliveryEpoch(msg.delivery_epoch));
|
|
5829
|
-
}
|
|
5830
|
-
else if (msg.type === "fleet_schedule_trigger") {
|
|
5831
|
-
const payload = msg.payload;
|
|
5832
|
-
const meta = msg.meta;
|
|
5833
|
-
const deliveryEpoch = this.captureDeliveryEpoch(msg.delivery_epoch);
|
|
5834
|
-
void this.wake().then(() => { if (current())
|
|
5835
|
-
this.pushChannelMessage(payload.message, meta, undefined, deliveryEpoch); }).catch(err => {
|
|
5836
|
-
this.logger.error({ err: err.message }, "Wake failed for scheduled delivery");
|
|
5837
|
-
});
|
|
5838
|
-
}
|
|
5839
|
-
else if (msg.type === "query_instance_state") {
|
|
5840
|
-
void this.respondToInstanceStateQuery(msg, undefined, send);
|
|
5841
|
-
}
|
|
5842
|
-
else
|
|
5843
|
-
return false;
|
|
5844
|
-
return true;
|
|
5845
|
-
}
|
|
5846
5564
|
/**
|
|
5847
5565
|
* Answer a FleetManager state query. Most callers only need the cached state,
|
|
5848
5566
|
* but lifecycle decisions such as post-reply Cancel retirement need an
|
|
@@ -5850,7 +5568,7 @@ export class Daemon extends EventEmitter {
|
|
|
5850
5568
|
* the last transition can stay "working" even though the CLI has since
|
|
5851
5569
|
* settled without emitting another control-mode output record.
|
|
5852
5570
|
*/
|
|
5853
|
-
async respondToInstanceStateQuery(msg, socket
|
|
5571
|
+
async respondToInstanceStateQuery(msg, socket) {
|
|
5854
5572
|
try {
|
|
5855
5573
|
if (msg.deliveryIdle === true) {
|
|
5856
5574
|
await this.captureAndEvaluateInstanceState("delivery_idle_gate");
|
|
@@ -5859,7 +5577,7 @@ export class Daemon extends EventEmitter {
|
|
|
5859
5577
|
await this.captureAndEvaluateInstanceState("state_query");
|
|
5860
5578
|
}
|
|
5861
5579
|
const snapshot = this.getInstanceStateSnapshot();
|
|
5862
|
-
|
|
5580
|
+
this.ipcServer?.send(socket, {
|
|
5863
5581
|
type: "instance_state_response",
|
|
5864
5582
|
requestId: msg.requestId,
|
|
5865
5583
|
instanceName: this.name,
|
|
@@ -5867,11 +5585,7 @@ export class Daemon extends EventEmitter {
|
|
|
5867
5585
|
state: this.isPaused ? "paused" : snapshot.state,
|
|
5868
5586
|
processStatus: this.processStatus,
|
|
5869
5587
|
pausedAt: this.lastPausedAt,
|
|
5870
|
-
};
|
|
5871
|
-
if (send)
|
|
5872
|
-
send(reply);
|
|
5873
|
-
else if (socket)
|
|
5874
|
-
this.ipcServer?.send(socket, reply);
|
|
5588
|
+
});
|
|
5875
5589
|
}
|
|
5876
5590
|
catch (err) {
|
|
5877
5591
|
this.logger.debug({ err: err.message }, "Instance state query failed");
|
|
@@ -5911,49 +5625,7 @@ export class Daemon extends EventEmitter {
|
|
|
5911
5625
|
static AUTH_RECONFIRM_ROWS = 15;
|
|
5912
5626
|
/** Why the deferred pause was requested; what its marker records (Phase 2a). */
|
|
5913
5627
|
pendingPauseReason = "auth";
|
|
5914
|
-
nativePauseProof = null;
|
|
5915
|
-
/** Consume the exact idle proof synchronously after the lifecycle's await, before fencing and closing. */
|
|
5916
|
-
nativePauseStillReady() {
|
|
5917
|
-
const proof = this.nativePauseProof;
|
|
5918
|
-
this.nativePauseProof = null;
|
|
5919
|
-
if (proof?.())
|
|
5920
|
-
return true;
|
|
5921
|
-
this.pauseRequested = false;
|
|
5922
|
-
return false;
|
|
5923
|
-
}
|
|
5924
|
-
/** Native lifecycle pause uses the ordinary idle/background/admission proof before closing its owned Job. */
|
|
5925
|
-
async nativePauseReady(admission) {
|
|
5926
|
-
this.nativePauseProof = null;
|
|
5927
|
-
const native = this.nativePaneLifecycle, pane = this.tmux, owner = this.interactionOwner();
|
|
5928
|
-
const allowStuck = this.pauseAllowStuck;
|
|
5929
|
-
this.pauseAllowStuck = false;
|
|
5930
|
-
const ready = () => !!native && native === this.nativePaneLifecycle && native.current() && this.tmux === pane
|
|
5931
|
-
&& sameInteractionOwner(owner, this.interactionOwner()) && !this.runtimeMonitorsFrozen && !this.spawning
|
|
5932
|
-
&& this.processStatus === "running" && this.pasteQueueDepth === 0
|
|
5933
|
-
&& (this.instanceState === "idle" || allowStuck && this.instanceState === "stuck") && (!admission || admission.current());
|
|
5934
|
-
if (!pane || !ready()) {
|
|
5935
|
-
this.pauseRequested = false;
|
|
5936
|
-
return false;
|
|
5937
|
-
}
|
|
5938
|
-
let text;
|
|
5939
|
-
try {
|
|
5940
|
-
text = await pane.capturePane();
|
|
5941
|
-
}
|
|
5942
|
-
catch {
|
|
5943
|
-
this.pauseRequested = false;
|
|
5944
|
-
return false;
|
|
5945
|
-
}
|
|
5946
|
-
if (!ready() || admission && !admission.accepts(text) || this.backend?.backgroundWorkRunning?.(text)
|
|
5947
|
-
|| !allowStuck && !this.paneAuthoritativelyIdle(text)) {
|
|
5948
|
-
this.pauseRequested = false;
|
|
5949
|
-
return false;
|
|
5950
|
-
}
|
|
5951
|
-
this.nativePauseProof = ready;
|
|
5952
|
-
return true;
|
|
5953
|
-
}
|
|
5954
5628
|
async pause(reason = "operator", admission) {
|
|
5955
|
-
if (this.nativePaneLifecycle)
|
|
5956
|
-
throw Error("Native pause is owned by its Fleet lifecycle transition");
|
|
5957
5629
|
if (admission && !admission.current())
|
|
5958
5630
|
return;
|
|
5959
5631
|
if (this.pauseWakeState === "paused")
|
|
@@ -6049,7 +5721,7 @@ export class Daemon extends EventEmitter {
|
|
|
6049
5721
|
writePausedMarker(this.instanceDir, this.lastPausedAt ?? Date.now(), reason);
|
|
6050
5722
|
this.publishWorkingState("execution");
|
|
6051
5723
|
this.logger.info({ pausedAt: this.lastPausedAt }, "Instance auto-paused");
|
|
6052
|
-
this.
|
|
5724
|
+
this.ipcServer?.broadcast({
|
|
6053
5725
|
type: "instance_state", instanceName: this.name, state: "paused", pausedAt: this.lastPausedAt,
|
|
6054
5726
|
});
|
|
6055
5727
|
this.emit("auto_paused", { name: this.name, pausedAt: this.lastPausedAt });
|
|
@@ -6144,7 +5816,7 @@ export class Daemon extends EventEmitter {
|
|
|
6144
5816
|
this.resumeRuntimeMonitors();
|
|
6145
5817
|
this.publishWorkingState("execution");
|
|
6146
5818
|
this.logger.info("Instance auto-woke");
|
|
6147
|
-
this.
|
|
5819
|
+
this.ipcServer?.broadcast({
|
|
6148
5820
|
type: "instance_state", instanceName: this.name, state: this.instanceState, pausedAt: null,
|
|
6149
5821
|
});
|
|
6150
5822
|
this.emit("auto_woke", { name: this.name });
|
|
@@ -6308,7 +5980,7 @@ export class Daemon extends EventEmitter {
|
|
|
6308
5980
|
this.logStateEdge(previous, snapshot);
|
|
6309
5981
|
this.publishWorkingState("execution");
|
|
6310
5982
|
this.emit("instance_state", { name: this.name, ...snapshot });
|
|
6311
|
-
this.
|
|
5983
|
+
this.ipcServer?.broadcast({ type: "instance_state", instanceName: this.name, ...snapshot });
|
|
6312
5984
|
if (snapshot.state === "stuck" && pane && this.instanceStateReadyPattern) {
|
|
6313
5985
|
this.handleStuckTransition(pane, snapshot, this.instanceStateReadyPattern);
|
|
6314
5986
|
}
|
|
@@ -6410,7 +6082,7 @@ export class Daemon extends EventEmitter {
|
|
|
6410
6082
|
// writing a marker would re-inject a continuation for a finished turn.
|
|
6411
6083
|
// #3030: a message only queued in the busy CLI has not started a turn: the interrupted turn is still the running one,
|
|
6412
6084
|
// and a queued message lost to a restart is the hand-off record's to redeliver, not a continuation's.
|
|
6413
|
-
if (!
|
|
6085
|
+
if (!meta.resumedContinuationOf && !armed.completionDelivered && !queuedHandoff) {
|
|
6414
6086
|
const resumeBackend = this.config.backend ?? this.backend?.binaryName ?? this.runtimeIdentity?.backend;
|
|
6415
6087
|
const resumeCwd = this.config.working_directory ?? "";
|
|
6416
6088
|
writeInFlightTurnMarker(this.instanceDir, {
|
|
@@ -6642,7 +6314,7 @@ export class Daemon extends EventEmitter {
|
|
|
6642
6314
|
// outbound action suppresses a duplicate proxy; only a delivered
|
|
6643
6315
|
// human-facing channel action satisfies the completion guard below.
|
|
6644
6316
|
if (!turn.outboundDelivered && this.config.mcp_proxy_reply === true
|
|
6645
|
-
&&
|
|
6317
|
+
&& mcpServerState(this.instanceDir).state === "dead") {
|
|
6646
6318
|
this.turnReplyGuard.complete(turn.generation);
|
|
6647
6319
|
void this.sendProxyReply(pane, turn.target);
|
|
6648
6320
|
return;
|
|
@@ -7019,7 +6691,7 @@ export class Daemon extends EventEmitter {
|
|
|
7019
6691
|
}
|
|
7020
6692
|
});
|
|
7021
6693
|
}
|
|
7022
|
-
if (!this.
|
|
6694
|
+
if (!this.ipcServer) {
|
|
7023
6695
|
this.logger.error(`${logLabel} failed — no adapter or fleet IPC route`);
|
|
7024
6696
|
return Promise.resolve(false);
|
|
7025
6697
|
}
|
|
@@ -7043,7 +6715,7 @@ export class Daemon extends EventEmitter {
|
|
|
7043
6715
|
resolve(delivered);
|
|
7044
6716
|
});
|
|
7045
6717
|
try {
|
|
7046
|
-
this.
|
|
6718
|
+
this.ipcServer.broadcast({
|
|
7047
6719
|
type: "fleet_outbound",
|
|
7048
6720
|
tool: "reply",
|
|
7049
6721
|
args,
|
|
@@ -7614,7 +7286,7 @@ export class Daemon extends EventEmitter {
|
|
|
7614
7286
|
if (next === this.currentActivity)
|
|
7615
7287
|
return;
|
|
7616
7288
|
this.currentActivity = next;
|
|
7617
|
-
this.
|
|
7289
|
+
this.ipcServer?.broadcast({
|
|
7618
7290
|
type: "instance_activity",
|
|
7619
7291
|
instanceName: this.name,
|
|
7620
7292
|
activity: next,
|
|
@@ -7667,6 +7339,10 @@ export class Daemon extends EventEmitter {
|
|
|
7667
7339
|
else if (update.reply_completion_guard === null) {
|
|
7668
7340
|
delete this.config.reply_completion_guard;
|
|
7669
7341
|
}
|
|
7342
|
+
if (update.quota_notice === null)
|
|
7343
|
+
delete this.config.quota_notice;
|
|
7344
|
+
else if (update.quota_notice !== undefined && !quotaNoticeProblem(update.quota_notice))
|
|
7345
|
+
this.config.quota_notice = structuredClone(update.quota_notice);
|
|
7670
7346
|
if (typeof update.mcp_proxy_reply === "boolean")
|
|
7671
7347
|
this.config.mcp_proxy_reply = update.mcp_proxy_reply;
|
|
7672
7348
|
else if (update.mcp_proxy_reply === null)
|
|
@@ -7691,7 +7367,7 @@ export class Daemon extends EventEmitter {
|
|
|
7691
7367
|
else
|
|
7692
7368
|
this.config.auto_pause_after = nextAutoPause;
|
|
7693
7369
|
if (nextAutoPause !== previousAutoPause) {
|
|
7694
|
-
const isGeneral = this.config.general_topic === true ||
|
|
7370
|
+
const isGeneral = this.config.general_topic === true || this.name === "general";
|
|
7695
7371
|
this.autoPauseController.reconfigure((isGeneral ? 0 : nextAutoPause) * 60_000);
|
|
7696
7372
|
}
|
|
7697
7373
|
}
|
|
@@ -7771,7 +7447,7 @@ export class Daemon extends EventEmitter {
|
|
|
7771
7447
|
return;
|
|
7772
7448
|
this.lastProgressBroadcast = rendered;
|
|
7773
7449
|
this.lastProgressBroadcastAt = Date.now();
|
|
7774
|
-
this.
|
|
7450
|
+
this.ipcServer?.broadcast({
|
|
7775
7451
|
type: "instance_progress",
|
|
7776
7452
|
instanceName: this.name,
|
|
7777
7453
|
progress: rendered,
|
|
@@ -7787,7 +7463,7 @@ export class Daemon extends EventEmitter {
|
|
|
7787
7463
|
if (this.lastProgressBroadcast !== "") {
|
|
7788
7464
|
this.lastProgressBroadcast = "";
|
|
7789
7465
|
this.lastProgressBroadcastAt = Date.now();
|
|
7790
|
-
this.
|
|
7466
|
+
this.ipcServer?.broadcast({ type: "instance_progress", instanceName: this.name, progress: "" });
|
|
7791
7467
|
}
|
|
7792
7468
|
}
|
|
7793
7469
|
/**
|
|
@@ -7954,7 +7630,7 @@ export class Daemon extends EventEmitter {
|
|
|
7954
7630
|
reportCrossInstanceDeliveryFailure(meta, verdict, error) {
|
|
7955
7631
|
if (!meta.from_instance)
|
|
7956
7632
|
return;
|
|
7957
|
-
this.
|
|
7633
|
+
this.ipcServer?.broadcast({
|
|
7958
7634
|
type: "cross_instance_delivery_failed",
|
|
7959
7635
|
senderSession: meta.from_instance,
|
|
7960
7636
|
targetInstance: this.name,
|
|
@@ -9335,14 +9011,13 @@ export class Daemon extends EventEmitter {
|
|
|
9335
9011
|
if (this.remoteCardAnswering)
|
|
9336
9012
|
return { outcome: "refused", reason: "another answer to this card is being keyed in" };
|
|
9337
9013
|
this.remoteCardAnswering = true;
|
|
9338
|
-
let answerScreen = null;
|
|
9339
9014
|
try {
|
|
9340
9015
|
const outcome = await answerRemoteCard({
|
|
9341
9016
|
locked: fn => this.paneWriteLock.run(fn),
|
|
9342
9017
|
// An unreadable screen (a failed capture, another spawn's pane) is unknown — never "the card closed".
|
|
9343
|
-
read:
|
|
9344
|
-
key: key => this.tmux !== tmux
|
|
9345
|
-
paste: text => this.tmux !== tmux
|
|
9018
|
+
read: () => this.tmux === tmux ? tmux.capturePane().catch(() => null) : Promise.resolve(null),
|
|
9019
|
+
key: key => this.tmux !== tmux ? Promise.resolve(false) : key === "Space" ? tmux.sendKeys(" ") : tmux.sendSpecialKey(key),
|
|
9020
|
+
paste: text => this.tmux !== tmux ? Promise.resolve(false) : tmux.pasteBuffer(text),
|
|
9346
9021
|
sleep: ms => new Promise(resolve => setTimeout(resolve, ms)),
|
|
9347
9022
|
now: () => performance.now(),
|
|
9348
9023
|
}, pane => {
|
|
@@ -9613,19 +9288,12 @@ export class Daemon extends EventEmitter {
|
|
|
9613
9288
|
if (!check || !this.tmux)
|
|
9614
9289
|
return !check;
|
|
9615
9290
|
try {
|
|
9616
|
-
const
|
|
9617
|
-
|
|
9618
|
-
: await this.tmux.getPaneInputMode?.() === "raw";
|
|
9619
|
-
// ConPTY has no POSIX termios mode. Its closed launch plus current helper handshake is the input barrier;
|
|
9620
|
-
// the same strict composer detector below is still required. Never grant native unknown-layout fallback.
|
|
9621
|
-
if (!inputActive) {
|
|
9291
|
+
const mode = await this.tmux.getPaneInputMode?.();
|
|
9292
|
+
if (mode !== "raw") {
|
|
9622
9293
|
this.resetFooterFallback();
|
|
9623
9294
|
return false;
|
|
9624
9295
|
}
|
|
9625
|
-
|
|
9626
|
-
if (this.nativePaneLifecycle && (!this.nativePaneLifecycle.current() || this.nativePaneLifecycle.mcpProof() !== "alive"))
|
|
9627
|
-
return false;
|
|
9628
|
-
return this.deliveryInputReadyPane(pane);
|
|
9296
|
+
return this.deliveryInputReadyPane(await this.tmux.capturePane());
|
|
9629
9297
|
}
|
|
9630
9298
|
catch {
|
|
9631
9299
|
this.resetFooterFallback();
|
|
@@ -10399,86 +10067,34 @@ export class Daemon extends EventEmitter {
|
|
|
10399
10067
|
// tmux object and window — so the spawn generation and launch fence are part of the fence too: an Enter meant for
|
|
10400
10068
|
// the CLI this paste went to is never sent to its successor.
|
|
10401
10069
|
const tmux = this.tmux;
|
|
10402
|
-
const backend = this.backend;
|
|
10403
|
-
const native = !!this.nativePaneLifecycle;
|
|
10404
10070
|
const generation = this.spawnGeneration;
|
|
10405
10071
|
const fence = this.launchFenceEpoch;
|
|
10406
|
-
const windowId = native ? tmux?.getWindowId() : undefined;
|
|
10407
|
-
// M-2290 (#2985 review, Fable): the mode wait can last up to 10 minutes, and a respawn or relaunch reuses the same
|
|
10408
|
-
// tmux object and window — so the spawn generation and launch fence are part of every pane's fence: an Enter meant
|
|
10409
|
-
// for the CLI this paste went to is never sent to its successor. A native Windows pane keeps #2958's full fence too
|
|
10410
|
-
// (its launch can be replaced under the same handle).
|
|
10411
10072
|
const current = () => this.tmux === tmux && this.spawnGeneration === generation && this.launchFenceEpoch === fence
|
|
10412
|
-
&& !this.deliveryWritesStopping && (!stillCurrent || stillCurrent())
|
|
10413
|
-
&& (!native || (!!windowId && !!backend && this.backend === backend && tmux.getWindowId() === windowId));
|
|
10073
|
+
&& !this.deliveryWritesStopping && (!stillCurrent || stillCurrent());
|
|
10414
10074
|
if (!current())
|
|
10415
10075
|
return false;
|
|
10416
10076
|
// The pasted text may still be in the box: the caller keeps it uncertain (no false failure, no second paste).
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
if (reason === "output_changed" && current() && !this.nativeDeliveryHold())
|
|
10421
|
-
this.nativeEnterHold = {
|
|
10422
|
-
key: `${this.bootId}:${generation}:${fence}`, since: Date.now(), spawn: generation, fence,
|
|
10423
|
-
};
|
|
10424
|
-
if (reason === "pane-in-mode")
|
|
10425
|
-
this.logger.warn({ phase, reason }, "The pane stayed in a tmux mode; Enter withheld");
|
|
10426
|
-
else
|
|
10427
|
-
this.logger.warn({ ...tmux?.getLastInputDiagnostic?.(), phase, reason, retryCount: positiveRefusals }, "Native delivery Enter withheld by its safety check");
|
|
10077
|
+
const hold = () => {
|
|
10078
|
+
onInputHeld?.("pane-in-mode");
|
|
10079
|
+
this.logger.warn({ phase }, "The pane stayed in a tmux mode; Enter withheld");
|
|
10428
10080
|
return false;
|
|
10429
10081
|
};
|
|
10430
10082
|
// M-2267 (#2971): a pane in a tmux mode (a person left it in copy-mode) would take this Enter. Wait for the mode to
|
|
10431
10083
|
// end, then look once more within the same deadline — a pane flickering back into a mode is waited out again, never
|
|
10432
|
-
// past the bound.
|
|
10433
|
-
//
|
|
10434
|
-
// The fresh capture still binds the native host output sequence; ownership and positive-ACK-only retries remain.
|
|
10084
|
+
// past the bound. (beta.5: #2958's composer proof that used to sit between the two looks is reverted, decision
|
|
10085
|
+
// f57474aa: it rejected Codex's footer after a resume and while busy. #2957 is open again.)
|
|
10435
10086
|
const modeDeadline = performance.now() + PANE_MODE_ENTER_WAIT_MS;
|
|
10436
|
-
let pane;
|
|
10437
|
-
let positiveRefusals = 0, enterMarked = false, positiveRetryDeadline = Infinity, linuxDialogRead = false;
|
|
10438
10087
|
for (;;) {
|
|
10439
|
-
const mode = await this.waitWhilePaneInMode(phase, current,
|
|
10088
|
+
const mode = await this.waitWhilePaneInMode(phase, current, modeDeadline);
|
|
10440
10089
|
if (mode === "stale")
|
|
10441
10090
|
return false;
|
|
10442
10091
|
if (mode === "held")
|
|
10443
|
-
return hold(
|
|
10444
|
-
if (native) {
|
|
10445
|
-
// S-35: a native pane's capture refuses while output is still arriving ("Pane changed during capture; observe it
|
|
10446
|
-
// again"). Right after a turn the CLI repaints for a moment; one refused read left the message unsent for ever.
|
|
10447
|
-
// Read again a few times — reading types nothing — and still hold if it never settles.
|
|
10448
|
-
let captured;
|
|
10449
|
-
for (let attempt = 0; captured === undefined; attempt++) {
|
|
10450
|
-
try {
|
|
10451
|
-
captured = await tmux.capturePane();
|
|
10452
|
-
}
|
|
10453
|
-
catch {
|
|
10454
|
-
if (!current())
|
|
10455
|
-
return false;
|
|
10456
|
-
if (attempt >= 4)
|
|
10457
|
-
return hold("capture_failed");
|
|
10458
|
-
await new Promise(done => setTimeout(done, 150 * (attempt + 1)));
|
|
10459
|
-
if (!current())
|
|
10460
|
-
return false;
|
|
10461
|
-
}
|
|
10462
|
-
}
|
|
10463
|
-
const screen = captured;
|
|
10464
|
-
pane = screen;
|
|
10465
|
-
if (!current())
|
|
10466
|
-
return false;
|
|
10467
|
-
try {
|
|
10468
|
-
if (backend?.getRuntimeDialogs?.().some(dialog => Daemon.dialogMatches(dialog, screen)))
|
|
10469
|
-
return hold("dialog");
|
|
10470
|
-
}
|
|
10471
|
-
catch {
|
|
10472
|
-
return hold("check_failed");
|
|
10473
|
-
}
|
|
10474
|
-
if (!current())
|
|
10475
|
-
return false;
|
|
10476
|
-
}
|
|
10092
|
+
return hold();
|
|
10477
10093
|
if (await this.paneInTmuxMode(phase)) {
|
|
10478
10094
|
if (!current())
|
|
10479
10095
|
return false;
|
|
10480
10096
|
if (performance.now() >= modeDeadline)
|
|
10481
|
-
return hold(
|
|
10097
|
+
return hold();
|
|
10482
10098
|
await new Promise(r => setTimeout(r, PANE_MODE_POLL_MS));
|
|
10483
10099
|
if (!current())
|
|
10484
10100
|
return false;
|
|
@@ -10486,143 +10102,54 @@ export class Daemon extends EventEmitter {
|
|
|
10486
10102
|
}
|
|
10487
10103
|
if (!current())
|
|
10488
10104
|
return false;
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
catch {
|
|
10502
|
-
finalPane = null;
|
|
10503
|
-
}
|
|
10504
|
-
if (!current())
|
|
10505
|
-
return false;
|
|
10506
|
-
let dialog;
|
|
10507
|
-
try {
|
|
10508
|
-
dialog = finalPane === null ? undefined : (this.backend?.getRuntimeDialogs?.() ?? []).find(d => Daemon.dialogMatches(d, finalPane))?.description;
|
|
10509
|
-
}
|
|
10510
|
-
catch {
|
|
10511
|
-
dialog = undefined;
|
|
10512
|
-
}
|
|
10513
|
-
if (dialog !== undefined) {
|
|
10514
|
-
onInputHeld("dialog");
|
|
10515
|
-
this.logger.warn({ phase, dialog }, "A dialog is on the pane; the delivery's Enter is withheld (it would answer it)");
|
|
10516
|
-
return false;
|
|
10517
|
-
}
|
|
10518
|
-
}
|
|
10519
|
-
if (positiveRefusals && performance.now() >= positiveRetryDeadline)
|
|
10520
|
-
return hold("output_changed");
|
|
10521
|
-
// W1: persist the "Enter may have happened" boundary before tmux receives
|
|
10522
|
-
// the key. A crash after this commit is never auto-replayed without a
|
|
10523
|
-
// positive transcript marker, even if the stale pane still shows composer.
|
|
10524
|
-
if (!enterMarked && durableAttempt && !this.deliveryOutbox?.markEnterStarted(durableAttempt.deliveryId, this.bootId, durableAttempt.attemptNo)) {
|
|
10525
|
-
this.logger.error({ phase, deliveryId: durableAttempt.deliveryId }, "Could not commit durable Enter write-ahead fence");
|
|
10526
|
-
return false;
|
|
10527
|
-
}
|
|
10528
|
-
enterMarked = true;
|
|
10529
|
-
const sent = await (native && pane !== undefined ? tmux.sendSpecialKey("Enter", undefined, { kind: "delivery", screen: pane, retryCount: positiveRefusals }) : tmux.sendSpecialKey("Enter"));
|
|
10530
|
-
// A busy renderer can change seq after our capture. Only a positive zero-input ACK admits a NEW proof/key;
|
|
10531
|
-
// An Enter retry never re-pastes, retries an uncertain write, reuses stale proof or re-commits the durable boundary.
|
|
10532
|
-
if (!sent && native && tmux.lastInputWasNotSent?.() === true
|
|
10533
|
-
&& tmux.getLastSendSpecialKeyError() === "Pane changed after observation; input was not sent"
|
|
10534
|
-
&& current()) {
|
|
10535
|
-
if (!positiveRefusals)
|
|
10536
|
-
positiveRetryDeadline = Math.min(modeDeadline, performance.now() + 2000);
|
|
10537
|
-
if (positiveRefusals >= 4 || performance.now() >= positiveRetryDeadline)
|
|
10538
|
-
return hold("output_changed");
|
|
10539
|
-
positiveRefusals++;
|
|
10540
|
-
await new Promise(done => setTimeout(done, 100));
|
|
10541
|
-
if (!current())
|
|
10542
|
-
return false;
|
|
10543
|
-
if (performance.now() >= positiveRetryDeadline)
|
|
10544
|
-
return hold("output_changed");
|
|
10545
|
-
continue;
|
|
10546
|
-
}
|
|
10547
|
-
if (!sent) {
|
|
10548
|
-
const details = { phase, tmuxError: this.tmux.getLastSendSpecialKeyError() ?? "unknown tmux send-keys failure" };
|
|
10549
|
-
if (native)
|
|
10550
|
-
this.logger.warn({ ...tmux?.getLastInputDiagnostic?.(), ...details, retryCount: positiveRefusals }, "Native delivery Enter gave up");
|
|
10551
|
-
else
|
|
10552
|
-
this.logger.error(details, "tmux send-keys Enter failed during message delivery");
|
|
10553
|
-
}
|
|
10554
|
-
if (sent && native && current())
|
|
10555
|
-
this.nativeEnterHold = null;
|
|
10556
|
-
return sent;
|
|
10557
|
-
}
|
|
10558
|
-
}
|
|
10559
|
-
/** A pre-existing native busy-paste race: retry bytes only after an exact, owned zero-input acknowledgement. */
|
|
10560
|
-
async sendDeliveryPaste(text, stillCurrent) {
|
|
10561
|
-
const pane = this.tmux, native = this.nativePaneLifecycle;
|
|
10562
|
-
if (!native)
|
|
10563
|
-
return pane.pasteBuffer(text);
|
|
10564
|
-
const backend = this.backend, generation = this.spawnGeneration, fence = this.launchFenceEpoch, windowId = pane.getWindowId();
|
|
10565
|
-
const current = () => !!windowId && this.tmux === pane && this.nativePaneLifecycle === native && this.backend === backend
|
|
10566
|
-
&& this.spawnGeneration === generation && this.launchFenceEpoch === fence && pane.getWindowId() === windowId
|
|
10567
|
-
&& !this.deliveryWritesStopping && (!stillCurrent || stillCurrent());
|
|
10568
|
-
let retryCount = 0;
|
|
10569
|
-
const hold = (reason) => {
|
|
10570
|
-
if (current() && !this.nativeDeliveryHold())
|
|
10571
|
-
this.nativeEnterHold = { key: `${this.bootId}:${generation}:${fence}`, since: Date.now(), spawn: generation, fence };
|
|
10572
|
-
this.logger.warn({ ...pane.getLastInputDiagnostic?.(), reason, retryCount }, "Native delivery paste held by its safety check");
|
|
10573
|
-
return false;
|
|
10574
|
-
};
|
|
10575
|
-
const deadline = performance.now() + 2000;
|
|
10576
|
-
for (let attempt = 0; attempt < 5; attempt++) {
|
|
10577
|
-
retryCount = attempt;
|
|
10578
|
-
if (!current())
|
|
10579
|
-
return false;
|
|
10580
|
-
if (performance.now() >= deadline)
|
|
10581
|
-
return hold("output_changed");
|
|
10582
|
-
let screen;
|
|
10583
|
-
for (let read = 0; read < 5 && screen === undefined; read++) {
|
|
10584
|
-
try {
|
|
10585
|
-
screen = await pane.capturePane();
|
|
10586
|
-
}
|
|
10587
|
-
catch { /* Reads do not construct an input operation. */ }
|
|
10588
|
-
if (!current())
|
|
10589
|
-
return false;
|
|
10590
|
-
if (performance.now() >= deadline)
|
|
10591
|
-
return hold("capture_failed");
|
|
10592
|
-
if (screen === undefined && read < 4)
|
|
10593
|
-
await new Promise(done => setTimeout(done, 100));
|
|
10594
|
-
}
|
|
10595
|
-
if (screen === undefined)
|
|
10596
|
-
return hold("capture_failed");
|
|
10105
|
+
break;
|
|
10106
|
+
}
|
|
10107
|
+
// M-2290 (the simple half of the #2957 redesign, leader xmsg-1793712561468): a dialog the backend RECOGNISES
|
|
10108
|
+
// (runtimeDialogs: a permission card, the dangerous-command card, …) that painted between the paste and this Enter
|
|
10109
|
+
// would take the key as its answer. Read the pane once more: such a dialog withholds the Enter, the caller keeps the
|
|
10110
|
+
// delivery uncertain (Needs-you), and the dialog scanner parks the dialog for a person. Nothing else is judged here
|
|
10111
|
+
// — an unknown or unreadable screen sends, exactly as before: #2958's composer proof (decision f57474aa) is NOT back.
|
|
10112
|
+
// Only a caller that can hold (onInputHeld: the delivery's initial submit, settled uncertain → Needs-you) asks: one
|
|
10113
|
+
// that cannot would read `false` as a failure and paste again. Only the backend's OWN dialogs count — not AgEnD's
|
|
10114
|
+
// unrecognised-prompt guess — so an unknown screen still sends.
|
|
10115
|
+
if (onInputHeld) {
|
|
10116
|
+
let finalPane = null;
|
|
10597
10117
|
try {
|
|
10598
|
-
|
|
10599
|
-
return hold("dialog");
|
|
10118
|
+
finalPane = await tmux.capturePane();
|
|
10600
10119
|
}
|
|
10601
10120
|
catch {
|
|
10602
|
-
|
|
10121
|
+
finalPane = null;
|
|
10603
10122
|
}
|
|
10604
10123
|
if (!current())
|
|
10605
10124
|
return false;
|
|
10606
|
-
|
|
10607
|
-
return hold("output_changed");
|
|
10608
|
-
let sent;
|
|
10125
|
+
let dialog;
|
|
10609
10126
|
try {
|
|
10610
|
-
|
|
10127
|
+
dialog = finalPane === null ? undefined : (this.backend?.getRuntimeDialogs?.() ?? []).find(d => Daemon.dialogMatches(d, finalPane))?.description;
|
|
10611
10128
|
}
|
|
10612
10129
|
catch {
|
|
10613
|
-
|
|
10130
|
+
dialog = undefined;
|
|
10614
10131
|
}
|
|
10615
|
-
if (
|
|
10616
|
-
|
|
10617
|
-
|
|
10132
|
+
if (dialog !== undefined) {
|
|
10133
|
+
onInputHeld?.("dialog");
|
|
10134
|
+
this.logger.warn({ phase, dialog }, "A dialog is on the pane; the delivery's Enter is withheld (it would answer it)");
|
|
10618
10135
|
return false;
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10136
|
+
}
|
|
10137
|
+
}
|
|
10138
|
+
// W1: persist the "Enter may have happened" boundary before tmux receives
|
|
10139
|
+
// the key. A crash after this commit is never auto-replayed without a
|
|
10140
|
+
// positive transcript marker, even if the stale pane still shows composer.
|
|
10141
|
+
if (durableAttempt && !this.deliveryOutbox?.markEnterStarted(durableAttempt.deliveryId, this.bootId, durableAttempt.attemptNo)) {
|
|
10142
|
+
this.logger.error({ phase, deliveryId: durableAttempt.deliveryId }, "Could not commit durable Enter write-ahead fence");
|
|
10143
|
+
return false;
|
|
10144
|
+
}
|
|
10145
|
+
const sent = await tmux.sendSpecialKey("Enter");
|
|
10146
|
+
if (!sent) {
|
|
10147
|
+
this.logger.error({
|
|
10148
|
+
phase,
|
|
10149
|
+
tmuxError: this.tmux.getLastSendSpecialKeyError() ?? "unknown tmux send-keys failure",
|
|
10150
|
+
}, "tmux send-keys Enter failed during message delivery");
|
|
10624
10151
|
}
|
|
10625
|
-
return
|
|
10152
|
+
return sent;
|
|
10626
10153
|
}
|
|
10627
10154
|
async writeMessageToPane(formatted, initialWindowId, handingOffToNativeQueue, status, submissionId,
|
|
10628
10155
|
// Last and defaulted so the positional callers that ignore the outcome stay
|
|
@@ -10660,9 +10187,6 @@ export class Daemon extends EventEmitter {
|
|
|
10660
10187
|
const tmuxAtWrite = this.tmux;
|
|
10661
10188
|
const steerCurrent = () => (!stillCurrent || stillCurrent()) && !this.deliveryWritesStopping
|
|
10662
10189
|
&& this.tmux === tmuxAtWrite && this.spawnGeneration === spawnAtWrite;
|
|
10663
|
-
// Alpha (S-36, Prism #2989 P2): a NATIVE pane keeps #2958's pre-paste owner fence through the initial Enter and every
|
|
10664
|
-
// retry Enter (a pane replaced while the paste awaits never takes this delivery's Enter); a tmux pane follows main.
|
|
10665
|
-
const nativeOwner = this.nativePaneLifecycle ? steerCurrent : undefined;
|
|
10666
10190
|
// Bug A: paste with backoff. Transient failures are usually a stale window id
|
|
10667
10191
|
// after a crash/respawn — recover by name and retry (max 3 attempts, 2s apart).
|
|
10668
10192
|
const maxAttempts = 3;
|
|
@@ -10730,8 +10254,8 @@ export class Daemon extends EventEmitter {
|
|
|
10730
10254
|
}
|
|
10731
10255
|
verdict.durableBeginCommitted = true;
|
|
10732
10256
|
verdict.submissionMode = attemptEvidence.submissionMode;
|
|
10733
|
-
if (attemptEvidence.
|
|
10734
|
-
verdict.transcriptCheckpoint =
|
|
10257
|
+
if (attemptEvidence.transcriptPath && attemptEvidence.transcriptOffset !== null) {
|
|
10258
|
+
verdict.transcriptCheckpoint = {
|
|
10735
10259
|
backend: attemptEvidence.backend,
|
|
10736
10260
|
path: attemptEvidence.transcriptPath,
|
|
10737
10261
|
offset: attemptEvidence.transcriptOffset,
|
|
@@ -10807,15 +10331,7 @@ export class Daemon extends EventEmitter {
|
|
|
10807
10331
|
}
|
|
10808
10332
|
const pasteGeneration = this.spawnGeneration;
|
|
10809
10333
|
beforePaste?.();
|
|
10810
|
-
const pasted = await this.
|
|
10811
|
-
if (!pasted && this.nativePaneLifecycle) {
|
|
10812
|
-
// The native write attempt is retained as uncertain, including exhausted positive refusals. Never route an
|
|
10813
|
-
// unknown/partial write through legacy window recovery or abort it back to an automatically replayable row.
|
|
10814
|
-
verdict.paneWriteStarted = true;
|
|
10815
|
-
verdict.phase = "paste";
|
|
10816
|
-
verdict.proof = "native-paste-held";
|
|
10817
|
-
return false;
|
|
10818
|
-
}
|
|
10334
|
+
const pasted = await this.tmux.pasteBuffer(formatted);
|
|
10819
10335
|
if (pasted)
|
|
10820
10336
|
this.rememberPaste(formatted, pasteGeneration);
|
|
10821
10337
|
if (!pasted) {
|
|
@@ -10902,18 +10418,15 @@ export class Daemon extends EventEmitter {
|
|
|
10902
10418
|
const enterMono = performance.now();
|
|
10903
10419
|
const steerEnterCurrent = () => steerCurrent() && performance.now() <= steerEnterDeadline;
|
|
10904
10420
|
let inputHeld = null;
|
|
10905
|
-
if (!(await this.sendDeliveryEnter("initial-submit", steerComposerProof
|
|
10421
|
+
if (!(await this.sendDeliveryEnter("initial-submit", steerComposerProof ? steerEnterCurrent : undefined, durableAttempt, (why) => { inputHeld = why; }))) {
|
|
10906
10422
|
if (inputHeld) {
|
|
10907
10423
|
// #2971: held in a tmux mode past the bound; M-2290: a recognised dialog on the pane. The paste may still be in
|
|
10908
10424
|
// the CLI: keep it uncertain (Needs-you), never re-paste, never answer the dialog.
|
|
10909
10425
|
verdict.phase = "submit-enter";
|
|
10910
|
-
|
|
10911
|
-
// and each native safety check say which.
|
|
10912
|
-
verdict.proof = inputHeld === "pane-in-mode" ? "pane-in-mode-held" : nativeOwner ? `native-input-${inputHeld}`
|
|
10913
|
-
: inputHeld === "dialog" ? "dialog-on-pane" : `input-held-${inputHeld}`;
|
|
10426
|
+
verdict.proof = inputHeld === "dialog" ? "dialog-on-pane" : "pane-in-mode-held";
|
|
10914
10427
|
return false;
|
|
10915
10428
|
}
|
|
10916
|
-
if (
|
|
10429
|
+
if (steerComposerProof && !steerCurrent()) {
|
|
10917
10430
|
verdict.phase = "submit-enter";
|
|
10918
10431
|
verdict.proof = "fenced-before-enter";
|
|
10919
10432
|
return false;
|
|
@@ -10943,7 +10456,7 @@ export class Daemon extends EventEmitter {
|
|
|
10943
10456
|
if (!rawPaste && !steerComposerProof && this.backend?.requiresDeliveryEnterRetry?.() === true) {
|
|
10944
10457
|
await new Promise(r => setTimeout(r, 1_000));
|
|
10945
10458
|
const retryAt = Date.now();
|
|
10946
|
-
if (await this.sendDeliveryEnter("queue-less-defensive-retry"
|
|
10459
|
+
if (await this.sendDeliveryEnter("queue-less-defensive-retry")) {
|
|
10947
10460
|
enterAt = retryAt;
|
|
10948
10461
|
enterRetry = true;
|
|
10949
10462
|
this.logger.debug("Sent defensive Enter retry (queue-less TUI can swallow the first)");
|
|
@@ -11081,7 +10594,7 @@ export class Daemon extends EventEmitter {
|
|
|
11081
10594
|
// again. The prompt is back now, so an Enter can land.
|
|
11082
10595
|
this.logger.warn("Message still in the input row after idle — submitting the existing text instead of pasting it again");
|
|
11083
10596
|
const strandedAt = Date.now();
|
|
11084
|
-
if (!(await this.sendDeliveryEnter("native-queue-stranded-submit"
|
|
10597
|
+
if (!(await this.sendDeliveryEnter("native-queue-stranded-submit"))) {
|
|
11085
10598
|
return this.failDelivery(verdict, status, "native-queue-submit", "tmux-send-keys-failed");
|
|
11086
10599
|
}
|
|
11087
10600
|
// The recovery Enter can be accepted before Codex paints its new
|
|
@@ -11134,7 +10647,7 @@ export class Daemon extends EventEmitter {
|
|
|
11134
10647
|
}
|
|
11135
10648
|
await new Promise(r => setTimeout(r, NORMAL_ENTER_SETTLE_MS));
|
|
11136
10649
|
const retryAt = Date.now();
|
|
11137
|
-
if (!(await this.sendDeliveryEnter("native-queue-idle-redelivery"
|
|
10650
|
+
if (!(await this.sendDeliveryEnter("native-queue-idle-redelivery"))) {
|
|
11138
10651
|
return this.failDelivery(verdict, status, "native-queue-redelivery", "tmux-send-keys-failed");
|
|
11139
10652
|
}
|
|
11140
10653
|
if (windowId && this.controlClient) {
|
|
@@ -11186,7 +10699,7 @@ export class Daemon extends EventEmitter {
|
|
|
11186
10699
|
this.logger.warn("Message not submitted after Enter — waiting for the prompt, then re-sending Enter once");
|
|
11187
10700
|
const promptBack = await this.waitForPaneReadyForDelivery(windowId, STRANDED_RETRY_READY_WAIT_MS);
|
|
11188
10701
|
const retryAt = Date.now();
|
|
11189
|
-
if (promptBack && !(await this.sendDeliveryEnter("stranded-text-retry"
|
|
10702
|
+
if (promptBack && !(await this.sendDeliveryEnter("stranded-text-retry"))) {
|
|
11190
10703
|
return this.failDelivery(verdict, status, "stranded-text-retry", "tmux-send-keys-failed");
|
|
11191
10704
|
}
|
|
11192
10705
|
submitted = promptBack && await this.confirmSubmittedAfterEnter(windowId, retryAt, formatted);
|
|
@@ -11274,7 +10787,7 @@ export class Daemon extends EventEmitter {
|
|
|
11274
10787
|
}
|
|
11275
10788
|
// No control client to observe output: fall back to the legacy double-Enter.
|
|
11276
10789
|
await new Promise(r => setTimeout(r, 1000));
|
|
11277
|
-
await this.sendDeliveryEnter("unobserved-defensive-retry"
|
|
10790
|
+
await this.sendDeliveryEnter("unobserved-defensive-retry");
|
|
11278
10791
|
if (status)
|
|
11279
10792
|
this.emit("message_confirmed", status); // ✅ (best-effort)
|
|
11280
10793
|
}
|
|
@@ -11494,22 +11007,14 @@ export class Daemon extends EventEmitter {
|
|
|
11494
11007
|
* and the caller's own fence — so a look that lands after any of them is never used (#1380 review).
|
|
11495
11008
|
*/
|
|
11496
11009
|
transcriptProofFor(checkpoint, needle, spawnAtWrite, stillCurrent, onProof) {
|
|
11497
|
-
if (this.nativePaneLifecycle && !checkpoint.runtime)
|
|
11498
|
-
throw Error("Native proof cannot read a coordinator-local transcript path");
|
|
11499
11010
|
const launchAtWrite = this.launchFenceEpoch;
|
|
11500
11011
|
return {
|
|
11501
|
-
reader:
|
|
11012
|
+
reader: new TranscriptDeltaReader(checkpoint.path, checkpoint.offset, checkpoint.backend, needle),
|
|
11502
11013
|
current: () => !this.deliveryWritesStopping && this.spawnGeneration === spawnAtWrite
|
|
11503
|
-
&& this.launchFenceEpoch === launchAtWrite && (stillCurrent?.() ?? true)
|
|
11504
|
-
&& (!checkpoint.runtime || this.nativePaneLifecycle?.current(checkpoint.runtime) === true),
|
|
11014
|
+
&& this.launchFenceEpoch === launchAtWrite && (stillCurrent?.() ?? true),
|
|
11505
11015
|
onProof,
|
|
11506
11016
|
};
|
|
11507
11017
|
}
|
|
11508
|
-
nativeTranscriptReader(reference, needle) {
|
|
11509
|
-
if (!this.nativePaneLifecycle || !this.nativePaneLifecycle.current(reference))
|
|
11510
|
-
throw Error("Native delivery transcript owner is unavailable");
|
|
11511
|
-
return this.nativePaneLifecycle.proofReader(reference, needle);
|
|
11512
|
-
}
|
|
11513
11018
|
/** The CLI this daemon drives, for log lines shared by every backend ("claude-code", "codex", …). */
|
|
11514
11019
|
cliLabel() {
|
|
11515
11020
|
return this.config.backend ?? this.backend?.binaryName ?? "CLI";
|
|
@@ -11759,14 +11264,7 @@ export class Daemon extends EventEmitter {
|
|
|
11759
11264
|
* (the retries included). Without a guard it is exactly the old unconditional path.
|
|
11760
11265
|
*/
|
|
11761
11266
|
async submitSystemPaste(text, label, guard, admission) {
|
|
11762
|
-
|
|
11763
|
-
// (#2958's fence, reverted on main for tmux panes) — a pane replaced while the paste awaits never takes its Enter.
|
|
11764
|
-
const native = !!this.nativePaneLifecycle;
|
|
11765
|
-
const ownerTmux = this.tmux, ownerGeneration = this.spawnGeneration, ownerFence = this.launchFenceEpoch;
|
|
11766
|
-
const ownerWindow = native ? ownerTmux?.getWindowId() : undefined;
|
|
11767
|
-
const owner = () => !native || (!!ownerTmux && !!ownerWindow && this.tmux === ownerTmux && ownerTmux.getWindowId() === ownerWindow
|
|
11768
|
-
&& this.spawnGeneration === ownerGeneration && this.launchFenceEpoch === ownerFence && !this.deliveryWritesStopping);
|
|
11769
|
-
const current = guard || admission || native ? () => { admission?.(); return owner() && (guard?.current() ?? true); } : undefined;
|
|
11267
|
+
const current = guard || admission ? () => { admission?.(); return guard?.current() ?? true; } : undefined;
|
|
11770
11268
|
if (current && !current())
|
|
11771
11269
|
return false;
|
|
11772
11270
|
if (!this.tmux)
|
|
@@ -11784,10 +11282,6 @@ export class Daemon extends EventEmitter {
|
|
|
11784
11282
|
if (!current() || !guard.accept(pane))
|
|
11785
11283
|
return false;
|
|
11786
11284
|
baseline = this.paneEvidence(pane, signature);
|
|
11787
|
-
if (native && this.backend?.binaryName === "codex") {
|
|
11788
|
-
const counts = this.paneQuotaPatterns().map(ep => ({ key: Daemon.errorPatternKey(ep), count: Daemon.countOccurrences(ep.pattern, pane) }));
|
|
11789
|
-
baseline.quotaHistory = { spawn: ownerGeneration, fence: ownerFence, attempt: this.launchAttempt, tmux: ownerTmux, window: ownerWindow, counts, marker: signature.value, occurrences: baseline.payload };
|
|
11790
|
-
}
|
|
11791
11285
|
}
|
|
11792
11286
|
else {
|
|
11793
11287
|
baseline = await this.capturePaneEvidence(signature);
|
|
@@ -11891,13 +11385,13 @@ export class Daemon extends EventEmitter {
|
|
|
11891
11385
|
&& sameInteractionOwner(recoveryOwner, this.interactionOwner());
|
|
11892
11386
|
const previousWindowId = this.tmux?.getWindowId();
|
|
11893
11387
|
try {
|
|
11894
|
-
const windows = await
|
|
11388
|
+
const windows = await TmuxManager.listWindows(this.tmuxSessionName, this.controlClient);
|
|
11895
11389
|
if (!recoveryCurrent() || this.tmux !== previousTmux)
|
|
11896
11390
|
return undefined;
|
|
11897
11391
|
const match = windows.find(w => w.name === this.name);
|
|
11898
11392
|
if (!match)
|
|
11899
11393
|
return undefined;
|
|
11900
|
-
this.tmux =
|
|
11394
|
+
this.tmux = new TmuxManager(this.tmuxSessionName, match.id, resolveTmuxLogicalSize(this.config.terminal), this.controlClient);
|
|
11901
11395
|
const recoveredTmux = this.tmux;
|
|
11902
11396
|
writeFileSync(join(this.instanceDir, "window-id"), match.id);
|
|
11903
11397
|
// The window we were talking to is gone; leaving it registered means the
|
|
@@ -11960,8 +11454,6 @@ export class Daemon extends EventEmitter {
|
|
|
11960
11454
|
return false;
|
|
11961
11455
|
}
|
|
11962
11456
|
getWindowId() {
|
|
11963
|
-
if (this.nativePaneLifecycle)
|
|
11964
|
-
return this.nativePaneLifecycle.current() ? this.tmux?.getWindowId() : undefined;
|
|
11965
11457
|
try {
|
|
11966
11458
|
return readFileSync(join(this.instanceDir, "window-id"), "utf-8").trim() || undefined;
|
|
11967
11459
|
}
|
|
@@ -11993,55 +11485,7 @@ export class Daemon extends EventEmitter {
|
|
|
11993
11485
|
* Handle a tool call from the MCP server (forwarded by Claude).
|
|
11994
11486
|
* Routes to the channel adapter via MessageBus.
|
|
11995
11487
|
*/
|
|
11996
|
-
|
|
11997
|
-
handlePaneToolCall(input, lease) {
|
|
11998
|
-
const refusal = nativePaneToolRefusal(input.tool, input.args);
|
|
11999
|
-
if (refusal)
|
|
12000
|
-
return Promise.resolve({ result: null, error: refusal });
|
|
12001
|
-
if (!lease.current() || !lease.allowed(input.tool, input.args) || this.deliveryWritesStopping)
|
|
12002
|
-
return Promise.resolve({ result: null, error: "Pane tool permission is no longer current" });
|
|
12003
|
-
const fence = this.launchFenceEpoch;
|
|
12004
|
-
const current = () => lease.current() && lease.allowed(input.tool, input.args) && !this.deliveryWritesStopping && fence === this.launchFenceEpoch;
|
|
12005
|
-
return new Promise(resolve => {
|
|
12006
|
-
let settled = false;
|
|
12007
|
-
const finish = (value) => { if (settled)
|
|
12008
|
-
return; settled = true; clearTimeout(timer); resolve(value); };
|
|
12009
|
-
const timer = setTimeout(() => finish({ result: null, error: "Pane tool result is unconfirmed; inspect its operation before retrying" }), daemonBudgetMs(input.tool) + 1000);
|
|
12010
|
-
timer.unref?.();
|
|
12011
|
-
try {
|
|
12012
|
-
this.handleToolCall({ ...input, requestId: ++this.fleetRequestSeq }, undefined, {
|
|
12013
|
-
current,
|
|
12014
|
-
dispatch: (tool, args, respond) => {
|
|
12015
|
-
if (!current()) {
|
|
12016
|
-
respond(null, "Pane tool permission was revoked before dispatch");
|
|
12017
|
-
return true;
|
|
12018
|
-
}
|
|
12019
|
-
const dispatched = lease.dispatch?.(tool, args);
|
|
12020
|
-
if (!dispatched)
|
|
12021
|
-
return false;
|
|
12022
|
-
void dispatched.then(result => respond(result), () => respond(null, "Pane tool operation was refused"));
|
|
12023
|
-
return true;
|
|
12024
|
-
},
|
|
12025
|
-
// Resolving the relay is not proof that its HTTP response reached the provider. No response-written receipt yet.
|
|
12026
|
-
send: value => {
|
|
12027
|
-
finish({ result: value.result, ...(typeof value.error === "string" ? { error: value.error } : {}),
|
|
12028
|
-
...(typeof value.errorCode === "string" || typeof value.errorCode === "number" ? { errorCode: value.errorCode } : {}) });
|
|
12029
|
-
return false;
|
|
12030
|
-
},
|
|
12031
|
-
});
|
|
12032
|
-
}
|
|
12033
|
-
catch {
|
|
12034
|
-
finish({ result: null, error: "Pane tool operation failed" });
|
|
12035
|
-
}
|
|
12036
|
-
});
|
|
12037
|
-
}
|
|
12038
|
-
/** Only the authority lease with a verified helper stdout ACK calls this internal barrier. */
|
|
12039
|
-
paneToolResponseWritten(operationId, current) {
|
|
12040
|
-
if (!current() || this.deliveryWritesStopping || !/^[a-f0-9-]{36}$/i.test(operationId))
|
|
12041
|
-
return;
|
|
12042
|
-
this.emit("mcp_tool_response_written", { operationId, daemonBootId: this.bootId });
|
|
12043
|
-
}
|
|
12044
|
-
handleToolCall(msg, socket, peer) {
|
|
11488
|
+
handleToolCall(msg, socket) {
|
|
12045
11489
|
const tool = msg.tool;
|
|
12046
11490
|
const args = (msg.args ?? {});
|
|
12047
11491
|
const requestId = msg.requestId;
|
|
@@ -12049,20 +11493,20 @@ export class Daemon extends EventEmitter {
|
|
|
12049
11493
|
this.logger.debug({ tool, requestId }, "Tool call from MCP server");
|
|
12050
11494
|
// A tool call can only come from a live MCP server of ours — proof of life
|
|
12051
11495
|
// that outranks whatever the pid slot says.
|
|
12052
|
-
if (
|
|
12053
|
-
this.noteMcpProofOfLife("tool_call",
|
|
11496
|
+
if (this.socketSessionNames.get(socket) === this.name) {
|
|
11497
|
+
this.noteMcpProofOfLife("tool_call", this.socketPids.get(socket));
|
|
12054
11498
|
}
|
|
12055
11499
|
// A tool invocation is not delivery evidence. Capture which obligation it
|
|
12056
11500
|
// belongs to now, then settle it only after the adapter/fleet responds.
|
|
12057
11501
|
// Explicitly mapped sibling sessions must not satisfy this instance's turn;
|
|
12058
11502
|
// an unmapped socket is retained for legacy/tests where mcp_ready was not
|
|
12059
11503
|
// observed before the first tool call.
|
|
12060
|
-
const sourceSession =
|
|
11504
|
+
const sourceSession = this.socketSessionNames.get(socket);
|
|
12061
11505
|
const replyAttempt = TURN_OUTBOUND_TOOLS.has(tool) && (!sourceSession || sourceSession === this.name)
|
|
12062
11506
|
? this.turnReplyGuard.beginToolAttempt(tool === "reply", TURN_COMPLETION_TOOLS.has(tool))
|
|
12063
11507
|
: null;
|
|
12064
11508
|
// For now, log and respond. Full adapter routing will be wired in fleet manager.
|
|
12065
|
-
const respond = (result, error
|
|
11509
|
+
const respond = (result, error) => {
|
|
12066
11510
|
// A message that verifiably went out stands down the dead-MCP proxy reply
|
|
12067
11511
|
// for this turn: the agent proved it can still speak for itself.
|
|
12068
11512
|
if (!error && result != null && TURN_OUTBOUND_TOOLS.has(tool)) {
|
|
@@ -12103,21 +11547,14 @@ export class Daemon extends EventEmitter {
|
|
|
12103
11547
|
// failed" and report unknown immediately rather than starting recovery.
|
|
12104
11548
|
this.turnReplyGuard.settleToolAttempt(replyAttempt, false);
|
|
12105
11549
|
}
|
|
12106
|
-
const
|
|
12107
|
-
const sent = peer ? peer.current() && peer.send(packet) : socket ? this.ipcServer?.send(socket, packet) ?? false : false;
|
|
11550
|
+
const sent = this.ipcServer?.send(socket, { requestId, result, error, operationId }) ?? false;
|
|
12108
11551
|
if (!sent) {
|
|
12109
|
-
|
|
12110
|
-
this.logger.debug({ tool, requestId }, "Native MCP result awaits transport-written confirmation");
|
|
12111
|
-
else
|
|
12112
|
-
this.logger.warn({ tool, requestId }, "Tool result could not be returned — originating MCP socket is closed");
|
|
11552
|
+
this.logger.warn({ tool, requestId }, "Tool result could not be returned — originating MCP socket is closed");
|
|
12113
11553
|
}
|
|
12114
11554
|
else if (operationId) {
|
|
12115
11555
|
this.emit("mcp_tool_response_written", { operationId, daemonBootId: this.bootId });
|
|
12116
11556
|
}
|
|
12117
11557
|
};
|
|
12118
|
-
// Native Fleet/task operations carry their lease to the existing dispatcher mutation admission points.
|
|
12119
|
-
if (peer?.dispatch?.(tool, args, respond))
|
|
12120
|
-
return;
|
|
12121
11558
|
// Repo checkout — handled locally in daemon (no fleet-manager)
|
|
12122
11559
|
if (tool === "checkout_repo") {
|
|
12123
11560
|
this.handleCheckoutRepo(args, respond);
|
|
@@ -12146,7 +11583,7 @@ export class Daemon extends EventEmitter {
|
|
|
12146
11583
|
clearTimeout(timeout);
|
|
12147
11584
|
respond(respMsg.result, respMsg.error);
|
|
12148
11585
|
});
|
|
12149
|
-
this.
|
|
11586
|
+
this.ipcServer?.broadcast({
|
|
12150
11587
|
type,
|
|
12151
11588
|
payload: args,
|
|
12152
11589
|
meta: { instance_name: this.name },
|
|
@@ -12172,7 +11609,7 @@ export class Daemon extends EventEmitter {
|
|
|
12172
11609
|
clearTimeout(timeout);
|
|
12173
11610
|
resolve({ result: respMsg.result, error: respMsg.error });
|
|
12174
11611
|
});
|
|
12175
|
-
this.
|
|
11612
|
+
this.ipcServer?.broadcast({ type: WEB_THEME_IPC[tool], payload, meta: { instance_name: this.name }, fleetRequestId: fleetReqId });
|
|
12176
11613
|
});
|
|
12177
11614
|
void (async () => {
|
|
12178
11615
|
if (tool === "preview_web_appearance") {
|
|
@@ -12249,7 +11686,7 @@ export class Daemon extends EventEmitter {
|
|
|
12249
11686
|
clearTimeout(timeout);
|
|
12250
11687
|
respond(respMsg.result, respMsg.error);
|
|
12251
11688
|
});
|
|
12252
|
-
this.
|
|
11689
|
+
this.ipcServer?.broadcast({
|
|
12253
11690
|
type: "fleet_task",
|
|
12254
11691
|
payload: args,
|
|
12255
11692
|
meta: { instance_name: this.name },
|
|
@@ -12272,7 +11709,7 @@ export class Daemon extends EventEmitter {
|
|
|
12272
11709
|
clearTimeout(timeout);
|
|
12273
11710
|
respond(respMsg.result, respMsg.error);
|
|
12274
11711
|
});
|
|
12275
|
-
this.
|
|
11712
|
+
this.ipcServer?.broadcast({
|
|
12276
11713
|
type: typeMap[tool],
|
|
12277
11714
|
payload: args,
|
|
12278
11715
|
meta: { instance_name: this.name, working_directory: this.config.working_directory },
|
|
@@ -12299,7 +11736,7 @@ export class Daemon extends EventEmitter {
|
|
|
12299
11736
|
clearTimeout(timeout);
|
|
12300
11737
|
respond(respMsg.result, respMsg.error);
|
|
12301
11738
|
});
|
|
12302
|
-
this.
|
|
11739
|
+
this.ipcServer?.broadcast({
|
|
12303
11740
|
type: typeMap[tool],
|
|
12304
11741
|
payload: args,
|
|
12305
11742
|
meta: {
|
|
@@ -12314,11 +11751,11 @@ export class Daemon extends EventEmitter {
|
|
|
12314
11751
|
}
|
|
12315
11752
|
if (CROSS_INSTANCE_TOOLS.has(tool)) {
|
|
12316
11753
|
// Route to fleet manager via IPC (topic mode only)
|
|
12317
|
-
if (this.topicMode && this.
|
|
11754
|
+
if (this.topicMode && this.ipcServer) {
|
|
12318
11755
|
// Use fleetRequestId (not requestId) to avoid MCP server resolving the
|
|
12319
11756
|
// pending tool call prematurely when it receives the broadcast.
|
|
12320
11757
|
const fleetReqId = `xmsg_${++this.fleetRequestSeq}_${requestId}`;
|
|
12321
|
-
const senderSessionName =
|
|
11758
|
+
const senderSessionName = this.socketSessionNames.get(socket);
|
|
12322
11759
|
// Shared table, so delete_instance and the deployment tools get the same
|
|
12323
11760
|
// budget here as the MCP client expects (the ad-hoc list omitted them).
|
|
12324
11761
|
const crossTimeoutMs = daemonBudgetMs(tool);
|
|
@@ -12330,7 +11767,7 @@ export class Daemon extends EventEmitter {
|
|
|
12330
11767
|
clearTimeout(timeout);
|
|
12331
11768
|
respond(respMsg.result, respMsg.error);
|
|
12332
11769
|
});
|
|
12333
|
-
this.
|
|
11770
|
+
this.ipcServer.broadcast({
|
|
12334
11771
|
type: "fleet_outbound",
|
|
12335
11772
|
tool,
|
|
12336
11773
|
args,
|
|
@@ -12384,12 +11821,12 @@ export class Daemon extends EventEmitter {
|
|
|
12384
11821
|
}, daemonBudgetMs(tool));
|
|
12385
11822
|
this.pendingIpcRequests.set(outboundKey, (respMsg) => {
|
|
12386
11823
|
clearTimeout(timeout);
|
|
12387
|
-
respond(respMsg.result, respMsg.error
|
|
11824
|
+
respond(respMsg.result, respMsg.error);
|
|
12388
11825
|
});
|
|
12389
11826
|
// Register the waiter before broadcasting. A fast/mock adapter can settle
|
|
12390
11827
|
// immediately; broadcasting first left a response-before-registration
|
|
12391
11828
|
// window that degraded into a timeout despite a completed POST.
|
|
12392
|
-
this.
|
|
11829
|
+
this.ipcServer?.broadcast({
|
|
12393
11830
|
type: "fleet_outbound",
|
|
12394
11831
|
tool,
|
|
12395
11832
|
args,
|
|
@@ -12520,7 +11957,7 @@ export class Daemon extends EventEmitter {
|
|
|
12520
11957
|
// The daemon used to read `general_topic` alone while `isGeneralInstance`
|
|
12521
11958
|
// also accepted the name, so an instance called `general` without the flag
|
|
12522
11959
|
// was a worker here and a general everywhere else.
|
|
12523
|
-
const isGeneral = this.config.general_topic === true ||
|
|
11960
|
+
const isGeneral = this.config.general_topic === true || this.name === "general";
|
|
12524
11961
|
// No third argument for an ordinary instance: the default is `worker` now,
|
|
12525
11962
|
// and naming it here would be a second place to change it.
|
|
12526
11963
|
const toolSet = isGeneral
|
|
@@ -12683,7 +12120,6 @@ export class Daemon extends EventEmitter {
|
|
|
12683
12120
|
this.cancelCapacityNudge("the instance was stopped, paused or respawned");
|
|
12684
12121
|
this.lastErrorEpisode = null;
|
|
12685
12122
|
this.quotaReplay = null;
|
|
12686
|
-
this.nativeQuotaReplayTaken = false;
|
|
12687
12123
|
this.quotaInput = null;
|
|
12688
12124
|
this.nudgeBaselines = null;
|
|
12689
12125
|
// A relaunch settles any outstanding quit watch: the CLI came back.
|
|
@@ -12899,8 +12335,6 @@ export class Daemon extends EventEmitter {
|
|
|
12899
12335
|
catch { /* best effort */ }
|
|
12900
12336
|
}
|
|
12901
12337
|
async spawnClaudeWindow() {
|
|
12902
|
-
if (this.nativePaneLifecycle)
|
|
12903
|
-
throw Error("Native panes never enter local resume/fresh fallback");
|
|
12904
12338
|
this.assertSessionOomAdmission();
|
|
12905
12339
|
this.beginSpawn();
|
|
12906
12340
|
let resumedSuccessfully = false;
|
|
@@ -13487,14 +12921,6 @@ export class Daemon extends EventEmitter {
|
|
|
13487
12921
|
await this.museUsageRelay.stop().catch(() => { });
|
|
13488
12922
|
this.museUsageRelay = null;
|
|
13489
12923
|
}
|
|
13490
|
-
if (this.nativePaneLifecycle) {
|
|
13491
|
-
await this.nativePaneLifecycle.release("detach");
|
|
13492
|
-
try {
|
|
13493
|
-
unlinkSync(join(this.instanceDir, "daemon.pid"));
|
|
13494
|
-
}
|
|
13495
|
-
catch { /* metadata only */ }
|
|
13496
|
-
return;
|
|
13497
|
-
}
|
|
13498
12924
|
try {
|
|
13499
12925
|
await this.killProcessTree("SIGTERM", "startup aborted");
|
|
13500
12926
|
}
|
|
@@ -13524,15 +12950,13 @@ export class Daemon extends EventEmitter {
|
|
|
13524
12950
|
}
|
|
13525
12951
|
/** Kill the entire process tree of the current tmux pane (CLI + MCP server). */
|
|
13526
12952
|
async killProcessTree(signal = "SIGTERM", reason = "unspecified") {
|
|
13527
|
-
if (this.nativePaneLifecycle)
|
|
13528
|
-
throw Error("Native processes can only be closed through their owned runtime pane");
|
|
13529
12953
|
const windowId = this.tmux?.getWindowId();
|
|
13530
12954
|
// Before createWindow succeeds there is no pane owned by this daemon.
|
|
13531
12955
|
// tmux interprets an empty selector as the session's active window.
|
|
13532
12956
|
if (!windowId?.trim())
|
|
13533
12957
|
return;
|
|
13534
12958
|
try {
|
|
13535
|
-
const pid = await
|
|
12959
|
+
const pid = await TmuxManager.getPanePid(this.tmuxSessionName, windowId);
|
|
13536
12960
|
if (pid) {
|
|
13537
12961
|
this.noteStopRequest(signal, reason);
|
|
13538
12962
|
process.kill(-pid, signal);
|
|
@@ -13751,7 +13175,7 @@ export class Daemon extends EventEmitter {
|
|
|
13751
13175
|
whatsNewRoles() {
|
|
13752
13176
|
if (this.runtimeIdentity?.kind === "classic")
|
|
13753
13177
|
return ["classic"];
|
|
13754
|
-
if (this.config.general_topic === true ||
|
|
13178
|
+
if (this.config.general_topic === true || this.name === "general")
|
|
13755
13179
|
return ["general"];
|
|
13756
13180
|
const set = resolveToolSet(this.config, this.name);
|
|
13757
13181
|
return set === "coordinator" || set === "full" ? ["worker", "coordinator"] : ["worker"];
|
|
@@ -13778,8 +13202,6 @@ export class Daemon extends EventEmitter {
|
|
|
13778
13202
|
}
|
|
13779
13203
|
}
|
|
13780
13204
|
async trySpawnInsideGate(reuseWindow = false, startupTimeoutMs) {
|
|
13781
|
-
if (this.nativePaneLifecycle)
|
|
13782
|
-
throw Error("Native relaunch requires its owned exit and a new lifecycle reservation");
|
|
13783
13205
|
this.assertSessionOomAdmission();
|
|
13784
13206
|
this.startupAdmission?.();
|
|
13785
13207
|
const launchFence = this.launchFenceEpoch;
|
|
@@ -13892,8 +13314,8 @@ export class Daemon extends EventEmitter {
|
|
|
13892
13314
|
this.emit("backend_launch_warning", { name: this.name, message: note, quiet: true });
|
|
13893
13315
|
}
|
|
13894
13316
|
// Ensure tmux session exists (may have been destroyed if all windows died)
|
|
13895
|
-
await
|
|
13896
|
-
if (this.stormWindow?.observeServerAlive(await
|
|
13317
|
+
await TmuxManager.ensureSession(this.tmuxSessionName);
|
|
13318
|
+
if (this.stormWindow?.observeServerAlive(await TmuxManager.getServerPid(this.tmuxSessionName))) {
|
|
13897
13319
|
this.emit("tmux_server_crash", this.name);
|
|
13898
13320
|
}
|
|
13899
13321
|
this.startupAdmission?.();
|
|
@@ -14170,15 +13592,12 @@ export class Daemon extends EventEmitter {
|
|
|
14170
13592
|
// each have seen a respawn, pause or stop.
|
|
14171
13593
|
if (!owned())
|
|
14172
13594
|
return false;
|
|
14173
|
-
const keyScreen = this.nativePaneLifecycle ? await this.tmux.capturePane() : answeredPane;
|
|
14174
|
-
if (!owned() || !Daemon.dialogMatches(dialog, keyScreen))
|
|
14175
|
-
return false;
|
|
14176
13595
|
if (key === "Up" || key === "Down" || key === "Enter" || key === "Escape") {
|
|
14177
|
-
if (!await
|
|
13596
|
+
if (!await this.tmux.sendSpecialKey(key))
|
|
14178
13597
|
return false;
|
|
14179
13598
|
}
|
|
14180
13599
|
else {
|
|
14181
|
-
if (!await
|
|
13600
|
+
if (!await this.tmux.sendKeys(key))
|
|
14182
13601
|
return false;
|
|
14183
13602
|
}
|
|
14184
13603
|
await new Promise(r => setTimeout(r, 200));
|
|
@@ -14192,8 +13611,7 @@ export class Daemon extends EventEmitter {
|
|
|
14192
13611
|
// Wait for next screen to render — bounded by what is left of the budget.
|
|
14193
13612
|
const renderWait = Math.max(0, Math.min(10_000, remaining()));
|
|
14194
13613
|
if (this.controlClient) {
|
|
14195
|
-
const wid = this.
|
|
14196
|
-
: readFileSync(join(this.instanceDir, "window-id"), "utf-8").trim();
|
|
13614
|
+
const wid = readFileSync(join(this.instanceDir, "window-id"), "utf-8").trim();
|
|
14197
13615
|
await this.controlClient.waitForIdle(wid, renderWait);
|
|
14198
13616
|
}
|
|
14199
13617
|
else {
|
|
@@ -14229,9 +13647,7 @@ export class Daemon extends EventEmitter {
|
|
|
14229
13647
|
// scan parked on the old limit text.
|
|
14230
13648
|
const codexReady = this.backend.binaryName !== "codex"
|
|
14231
13649
|
|| this.isCodexLivePaneSnapshot(pane);
|
|
14232
|
-
|
|
14233
|
-
? this.backend.readInputRow(pane) !== null : this.backend?.isDeliveryInputReadyPane?.(pane) === true);
|
|
14234
|
-
if (readyPatternMatches && codexReady && nativeComposerReady) {
|
|
13650
|
+
if (readyPatternMatches && codexReady) {
|
|
14235
13651
|
cleanReadyPolls++;
|
|
14236
13652
|
if (cleanReadyPolls >= 2 || remaining() <= 0) {
|
|
14237
13653
|
// A real ready prompt (with no fatal dialog on screen — those are
|
|
@@ -14360,16 +13776,6 @@ export class Daemon extends EventEmitter {
|
|
|
14360
13776
|
void refresh.call(this.backend).then(() => this.saveSessionId(), () => { });
|
|
14361
13777
|
}
|
|
14362
13778
|
saveSessionId() {
|
|
14363
|
-
if (this.nativePaneLifecycle) {
|
|
14364
|
-
try {
|
|
14365
|
-
this.nativePaneLifecycle.checkpointSession();
|
|
14366
|
-
this.ownedWorkingSession = this.backend?.getSessionId() ?? null;
|
|
14367
|
-
}
|
|
14368
|
-
catch (err) {
|
|
14369
|
-
this.logger.warn({ err }, "Native conversation checkpoint is unconfirmed");
|
|
14370
|
-
}
|
|
14371
|
-
return;
|
|
14372
|
-
}
|
|
14373
13779
|
// When a resume failure has forced a fresh start, don't persist the stale id
|
|
14374
13780
|
// back from statusline.json — that would re-arm --continue and re-loop.
|
|
14375
13781
|
if (this.skipResume)
|