@felan-ai/felan 0.28.4 → 0.30.0
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/NOTICE +20 -0
- package/README.md +127 -40
- package/dist/acp/daemon-session.d.ts +34 -0
- package/dist/acp/daemon-session.d.ts.map +1 -0
- package/dist/acp/daemon-session.js +142 -0
- package/dist/acp/daemon-session.js.map +1 -0
- package/dist/acp/login.d.ts +4 -2
- package/dist/acp/login.d.ts.map +1 -1
- package/dist/acp/login.js +155 -251
- package/dist/acp/login.js.map +1 -1
- package/dist/acp/protocol-interactions.d.ts +25 -0
- package/dist/acp/protocol-interactions.d.ts.map +1 -0
- package/dist/acp/protocol-interactions.js +297 -0
- package/dist/acp/protocol-interactions.js.map +1 -0
- package/dist/acp/protocol-updates.d.ts +20 -0
- package/dist/acp/protocol-updates.d.ts.map +1 -0
- package/dist/acp/protocol-updates.js +114 -0
- package/dist/acp/protocol-updates.js.map +1 -0
- package/dist/acp/session-registry.d.ts +4 -9
- package/dist/acp/session-registry.d.ts.map +1 -1
- package/dist/acp/session-registry.js +178 -386
- package/dist/acp/session-registry.js.map +1 -1
- package/dist/cli-config.d.ts +7 -0
- package/dist/cli-config.d.ts.map +1 -0
- package/dist/cli-config.js +18 -0
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-main.d.ts +12 -7
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli-main.js +106 -105
- package/dist/cli-main.js.map +1 -1
- package/dist/client/agent-host.d.ts +52 -0
- package/dist/client/agent-host.d.ts.map +1 -0
- package/dist/client/agent-host.js +413 -0
- package/dist/client/agent-host.js.map +1 -0
- package/dist/client/agents-presenter.d.ts +12 -0
- package/dist/client/agents-presenter.d.ts.map +1 -0
- package/dist/client/agents-presenter.js +66 -0
- package/dist/client/agents-presenter.js.map +1 -0
- package/dist/client/client.d.ts +181 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +806 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/daemon-blocked.d.ts +12 -0
- package/dist/client/daemon-blocked.d.ts.map +1 -0
- package/dist/client/daemon-blocked.js +27 -0
- package/dist/client/daemon-blocked.js.map +1 -0
- package/dist/client/daemon-stop.d.ts +5 -0
- package/dist/client/daemon-stop.d.ts.map +1 -0
- package/dist/client/daemon-stop.js +36 -0
- package/dist/client/daemon-stop.js.map +1 -0
- package/dist/client/diagnostics.d.ts +55 -0
- package/dist/client/diagnostics.d.ts.map +1 -0
- package/dist/client/diagnostics.js +47 -0
- package/dist/client/diagnostics.js.map +1 -0
- package/dist/client/hint-renderers.d.ts +16 -0
- package/dist/client/hint-renderers.d.ts.map +1 -0
- package/dist/client/hint-renderers.js +28 -0
- package/dist/client/hint-renderers.js.map +1 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/message-display.d.ts +21 -0
- package/dist/client/message-display.d.ts.map +1 -0
- package/dist/client/message-display.js +115 -0
- package/dist/client/message-display.js.map +1 -0
- package/dist/client/powerline-presenter.d.ts +13 -0
- package/dist/client/powerline-presenter.d.ts.map +1 -0
- package/dist/client/powerline-presenter.js +67 -0
- package/dist/client/powerline-presenter.js.map +1 -0
- package/dist/client/presenters.d.ts +43 -0
- package/dist/client/presenters.d.ts.map +1 -0
- package/dist/client/presenters.js +118 -0
- package/dist/client/presenters.js.map +1 -0
- package/dist/client/reducer.d.ts +37 -0
- package/dist/client/reducer.d.ts.map +1 -0
- package/dist/client/reducer.js +173 -0
- package/dist/client/reducer.js.map +1 -0
- package/dist/client/session-title.d.ts +6 -0
- package/dist/client/session-title.d.ts.map +1 -0
- package/dist/client/session-title.js +13 -0
- package/dist/client/session-title.js.map +1 -0
- package/dist/client/transport.d.ts +14 -0
- package/dist/client/transport.d.ts.map +1 -0
- package/dist/client/transport.js +46 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/client/ui.d.ts +25 -0
- package/dist/client/ui.d.ts.map +1 -0
- package/dist/client/ui.js +123 -0
- package/dist/client/ui.js.map +1 -0
- package/dist/client-application.d.ts +37 -0
- package/dist/client-application.d.ts.map +1 -0
- package/dist/client-application.js +126 -0
- package/dist/client-application.js.map +1 -0
- package/dist/compaction-presentation.d.ts +6 -4
- package/dist/compaction-presentation.d.ts.map +1 -1
- package/dist/compaction-presentation.js +11 -37
- package/dist/compaction-presentation.js.map +1 -1
- package/dist/daemon-command.d.ts +10 -0
- package/dist/daemon-command.d.ts.map +1 -0
- package/dist/daemon-command.js +163 -0
- package/dist/daemon-command.js.map +1 -0
- package/dist/daemon-entrypoint.d.ts +5 -0
- package/dist/daemon-entrypoint.d.ts.map +1 -0
- package/dist/daemon-entrypoint.js +17 -0
- package/dist/daemon-entrypoint.js.map +1 -0
- package/dist/daemon-host.d.ts +2 -0
- package/dist/daemon-host.d.ts.map +1 -0
- package/dist/daemon-host.js +18 -0
- package/dist/daemon-host.js.map +1 -0
- package/dist/dependency-onboarding.js +3 -3
- package/dist/dependency-onboarding.js.map +1 -1
- package/dist/execution-completion.d.ts +3 -0
- package/dist/execution-completion.d.ts.map +1 -0
- package/dist/execution-completion.js +2 -0
- package/dist/execution-completion.js.map +1 -0
- package/dist/headless.d.ts +39 -0
- package/dist/headless.d.ts.map +1 -0
- package/dist/headless.js +315 -0
- package/dist/headless.js.map +1 -0
- package/dist/host.json +55 -0
- package/dist/index.d.ts +9 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -10
- package/dist/index.js.map +1 -1
- package/dist/memory/{history-view.d.ts → history-renderer.d.ts} +13 -6
- package/dist/memory/history-renderer.d.ts.map +1 -0
- package/dist/memory/{history-view.js → history-renderer.js} +34 -30
- package/dist/memory/history-renderer.js.map +1 -0
- package/dist/memory/history.d.ts +1 -31
- package/dist/memory/history.d.ts.map +1 -1
- package/dist/memory/history.js +1 -306
- package/dist/memory/history.js.map +1 -1
- package/dist/memory/ui.d.ts +5 -0
- package/dist/memory/ui.d.ts.map +1 -0
- package/dist/memory/ui.js +2 -0
- package/dist/memory/ui.js.map +1 -0
- package/dist/process-restart.d.ts +4 -6
- package/dist/process-restart.d.ts.map +1 -1
- package/dist/process-restart.js +17 -96
- package/dist/process-restart.js.map +1 -1
- package/dist/{browser → providers/browser}/authorization-host.d.ts +2 -1
- package/dist/providers/browser/authorization-host.d.ts.map +1 -0
- package/dist/{browser → providers/browser}/authorization-host.js +9 -22
- package/dist/providers/browser/authorization-host.js.map +1 -0
- package/dist/providers/browser/chrome-devtools.d.ts.map +1 -0
- package/dist/providers/browser/chrome-devtools.js.map +1 -0
- package/dist/providers/browser/connection-lease.d.ts.map +1 -0
- package/dist/providers/browser/connection-lease.js.map +1 -0
- package/dist/providers/browser-authorization.d.ts +6 -0
- package/dist/providers/browser-authorization.d.ts.map +1 -0
- package/dist/providers/browser-authorization.js +30 -0
- package/dist/providers/browser-authorization.js.map +1 -0
- package/dist/providers/classifier.d.ts.map +1 -0
- package/dist/providers/classifier.js.map +1 -0
- package/dist/providers/codemode.d.ts.map +1 -0
- package/dist/providers/codemode.js.map +1 -0
- package/dist/providers/configuration.d.ts +23 -0
- package/dist/providers/configuration.d.ts.map +1 -0
- package/dist/providers/configuration.js +154 -0
- package/dist/providers/configuration.js.map +1 -0
- package/dist/providers/credential-storage.d.ts +10 -0
- package/dist/providers/credential-storage.d.ts.map +1 -0
- package/dist/providers/credential-storage.js +57 -0
- package/dist/providers/credential-storage.js.map +1 -0
- package/dist/providers/dependencies.d.ts +3 -0
- package/dist/providers/dependencies.d.ts.map +1 -0
- package/dist/providers/dependencies.js +31 -0
- package/dist/providers/dependencies.js.map +1 -0
- package/dist/providers/execution-binding.d.ts +7 -0
- package/dist/providers/execution-binding.d.ts.map +1 -0
- package/dist/providers/execution-binding.js +180 -0
- package/dist/providers/execution-binding.js.map +1 -0
- package/dist/providers/execution-services.d.ts +24 -0
- package/dist/providers/execution-services.d.ts.map +1 -0
- package/dist/providers/execution-services.js +91 -0
- package/dist/providers/execution-services.js.map +1 -0
- package/dist/providers/extension-catalog.d.ts +30 -0
- package/dist/providers/extension-catalog.d.ts.map +1 -0
- package/dist/providers/extension-catalog.js +39 -0
- package/dist/providers/extension-catalog.js.map +1 -0
- package/dist/providers/extension-services.d.ts +14 -0
- package/dist/providers/extension-services.d.ts.map +1 -0
- package/dist/providers/extension-services.js +2 -0
- package/dist/providers/extension-services.js.map +1 -0
- package/dist/providers/extensions.d.ts +7 -0
- package/dist/providers/extensions.d.ts.map +1 -0
- package/dist/providers/extensions.js +32 -0
- package/dist/providers/extensions.js.map +1 -0
- package/dist/providers/felan-platform.d.ts +6 -0
- package/dist/providers/felan-platform.d.ts.map +1 -0
- package/dist/providers/felan-platform.js +11 -0
- package/dist/providers/felan-platform.js.map +1 -0
- package/dist/providers/global-settings.d.ts +46 -0
- package/dist/providers/global-settings.d.ts.map +1 -0
- package/dist/providers/global-settings.js +187 -0
- package/dist/providers/global-settings.js.map +1 -0
- package/dist/providers/llama/extension.d.ts +10 -0
- package/dist/providers/llama/extension.d.ts.map +1 -0
- package/dist/providers/llama/extension.js +34 -0
- package/dist/providers/llama/extension.js.map +1 -0
- package/dist/providers/llama/management.d.ts +5 -0
- package/dist/providers/llama/management.d.ts.map +1 -0
- package/dist/providers/llama/management.js +176 -0
- package/dist/providers/llama/management.js.map +1 -0
- package/dist/providers/llama/presentation.d.ts +32 -0
- package/dist/providers/llama/presentation.d.ts.map +1 -0
- package/dist/providers/llama/presentation.js +141 -0
- package/dist/providers/llama/presentation.js.map +1 -0
- package/dist/providers/llama/sdk.d.ts +71 -0
- package/dist/providers/llama/sdk.d.ts.map +1 -0
- package/dist/providers/llama/sdk.js +25 -0
- package/dist/providers/llama/sdk.js.map +1 -0
- package/dist/providers/local-model-runtime.d.ts +4 -0
- package/dist/providers/local-model-runtime.d.ts.map +1 -0
- package/dist/providers/local-model-runtime.js +11 -0
- package/dist/providers/local-model-runtime.js.map +1 -0
- package/dist/providers/local-resources.d.ts +6 -0
- package/dist/providers/local-resources.d.ts.map +1 -0
- package/dist/providers/local-resources.js +13 -0
- package/dist/providers/local-resources.js.map +1 -0
- package/dist/providers/mcp/callback-server.d.ts +3 -0
- package/dist/providers/mcp/callback-server.d.ts.map +1 -0
- package/dist/{mcp → providers/mcp}/callback-server.js +5 -1
- package/dist/providers/mcp/callback-server.js.map +1 -0
- package/dist/providers/mcp-callback.d.ts +6 -0
- package/dist/providers/mcp-callback.d.ts.map +1 -0
- package/dist/providers/mcp-callback.js +67 -0
- package/dist/providers/mcp-callback.js.map +1 -0
- package/dist/providers/model-defaults.d.ts.map +1 -0
- package/dist/providers/model-defaults.js.map +1 -0
- package/dist/providers/models-subscription.d.ts +14 -0
- package/dist/providers/models-subscription.d.ts.map +1 -0
- package/dist/{powerline.js → providers/models-subscription.js} +28 -83
- package/dist/providers/models-subscription.js.map +1 -0
- package/dist/providers/models.d.ts +18 -0
- package/dist/providers/models.d.ts.map +1 -0
- package/dist/providers/models.js +371 -0
- package/dist/providers/models.js.map +1 -0
- package/dist/providers/pi-lock.d.ts.map +1 -0
- package/dist/{pi-lock.js → providers/pi-lock.js} +1 -1
- package/dist/providers/pi-lock.js.map +1 -0
- package/dist/providers/platform.d.ts +3 -0
- package/dist/providers/platform.d.ts.map +1 -0
- package/dist/providers/platform.js +14 -0
- package/dist/providers/platform.js.map +1 -0
- package/dist/providers/process-adapter.d.ts +3 -0
- package/dist/providers/process-adapter.d.ts.map +1 -0
- package/dist/providers/process-adapter.js +46 -0
- package/dist/providers/process-adapter.js.map +1 -0
- package/dist/providers/process-bootstrap.d.ts +17 -0
- package/dist/providers/process-bootstrap.d.ts.map +1 -0
- package/dist/providers/process-bootstrap.js +87 -0
- package/dist/providers/process-bootstrap.js.map +1 -0
- package/dist/providers/project-trust.d.ts +8 -0
- package/dist/providers/project-trust.d.ts.map +1 -0
- package/dist/providers/project-trust.js +112 -0
- package/dist/providers/project-trust.js.map +1 -0
- package/dist/providers/runtime-dependencies.d.ts +6 -0
- package/dist/providers/runtime-dependencies.d.ts.map +1 -0
- package/dist/providers/runtime-dependencies.js +31 -0
- package/dist/providers/runtime-dependencies.js.map +1 -0
- package/dist/providers/runtime.d.ts +6 -0
- package/dist/providers/runtime.d.ts.map +1 -0
- package/dist/providers/runtime.js +15 -0
- package/dist/providers/runtime.js.map +1 -0
- package/dist/{savings.d.ts → providers/savings.d.ts} +7 -0
- package/dist/providers/savings.d.ts.map +1 -0
- package/dist/{savings.js → providers/savings.js} +46 -1
- package/dist/providers/savings.js.map +1 -0
- package/dist/providers/secrets.d.ts +15 -0
- package/dist/providers/secrets.d.ts.map +1 -0
- package/dist/providers/secrets.js +233 -0
- package/dist/providers/secrets.js.map +1 -0
- package/dist/providers/session-runtime.d.ts +16 -0
- package/dist/providers/session-runtime.d.ts.map +1 -0
- package/dist/providers/session-runtime.js +193 -0
- package/dist/providers/session-runtime.js.map +1 -0
- package/dist/providers/sessions.d.ts +6 -0
- package/dist/providers/sessions.d.ts.map +1 -0
- package/dist/providers/sessions.js +97 -0
- package/dist/providers/sessions.js.map +1 -0
- package/dist/providers/settings-store.d.ts +4 -0
- package/dist/providers/settings-store.d.ts.map +1 -0
- package/dist/providers/settings-store.js +70 -0
- package/dist/providers/settings-store.js.map +1 -0
- package/dist/{settings.d.ts → providers/settings.d.ts} +7 -24
- package/dist/providers/settings.d.ts.map +1 -0
- package/dist/providers/settings.js +170 -0
- package/dist/providers/settings.js.map +1 -0
- package/dist/providers/setup/auth-driver.d.ts +16 -0
- package/dist/providers/setup/auth-driver.d.ts.map +1 -0
- package/dist/providers/setup/auth-driver.js +92 -0
- package/dist/providers/setup/auth-driver.js.map +1 -0
- package/dist/providers/setup/auth-wire.d.ts +51 -0
- package/dist/providers/setup/auth-wire.d.ts.map +1 -0
- package/dist/providers/setup/auth-wire.js +17 -0
- package/dist/providers/setup/auth-wire.js.map +1 -0
- package/dist/providers/setup/auth-worker.d.ts +14 -0
- package/dist/providers/setup/auth-worker.d.ts.map +1 -0
- package/dist/providers/setup/auth-worker.js +187 -0
- package/dist/providers/setup/auth-worker.js.map +1 -0
- package/dist/providers/setup/manager.d.ts +45 -0
- package/dist/providers/setup/manager.d.ts.map +1 -0
- package/dist/providers/setup/manager.js +283 -0
- package/dist/providers/setup/manager.js.map +1 -0
- package/dist/providers/setup/parent-guard.d.ts +3 -0
- package/dist/providers/setup/parent-guard.d.ts.map +1 -0
- package/dist/providers/setup/parent-guard.js +14 -0
- package/dist/providers/setup/parent-guard.js.map +1 -0
- package/dist/providers/setup-open.d.ts +9 -0
- package/dist/providers/setup-open.d.ts.map +1 -0
- package/dist/providers/setup-open.js +32 -0
- package/dist/providers/setup-open.js.map +1 -0
- package/dist/providers/system-prompt.d.ts.map +1 -0
- package/dist/providers/system-prompt.js.map +1 -0
- package/dist/providers/tool-policy.d.ts +2 -0
- package/dist/providers/tool-policy.d.ts.map +1 -0
- package/dist/providers/tool-policy.js +14 -0
- package/dist/providers/tool-policy.js.map +1 -0
- package/dist/providers/ui/extension-ui.d.ts +7 -0
- package/dist/providers/ui/extension-ui.d.ts.map +1 -0
- package/dist/providers/ui/extension-ui.js +42 -0
- package/dist/providers/ui/extension-ui.js.map +1 -0
- package/dist/providers/ui/port.d.ts +24 -0
- package/dist/providers/ui/port.d.ts.map +1 -0
- package/dist/providers/ui/port.js +2 -0
- package/dist/providers/ui/port.js.map +1 -0
- package/dist/savings-command.d.ts +1 -1
- package/dist/savings-command.d.ts.map +1 -1
- package/dist/savings-command.js +1 -1
- package/dist/savings-command.js.map +1 -1
- package/dist/session-picker.d.ts +13 -12
- package/dist/session-picker.d.ts.map +1 -1
- package/dist/session-picker.js +13 -23
- package/dist/session-picker.js.map +1 -1
- package/dist/subagents/agent-navigator.d.ts +24 -11
- package/dist/subagents/agent-navigator.d.ts.map +1 -1
- package/dist/subagents/agent-navigator.js +154 -86
- package/dist/subagents/agent-navigator.js.map +1 -1
- package/dist/subagents/agent-transcript.d.ts +8 -2
- package/dist/subagents/agent-transcript.d.ts.map +1 -1
- package/dist/subagents/agent-transcript.js +312 -29
- package/dist/subagents/agent-transcript.js.map +1 -1
- package/dist/subagents/completion-presentation.d.ts +13 -0
- package/dist/subagents/completion-presentation.d.ts.map +1 -1
- package/dist/subagents/completion-presentation.js +15 -42
- package/dist/subagents/completion-presentation.js.map +1 -1
- package/dist/subagents/transcript-components.d.ts +107 -0
- package/dist/subagents/transcript-components.d.ts.map +1 -0
- package/dist/subagents/transcript-components.js +306 -0
- package/dist/subagents/transcript-components.js.map +1 -0
- package/dist/subagents/types.d.ts +77 -0
- package/dist/subagents/types.d.ts.map +1 -0
- package/dist/subagents/types.js +2 -0
- package/dist/subagents/types.js.map +1 -0
- package/dist/themes/felan-dark.json +1 -1
- package/dist/tool-activity/mode.d.ts +5 -0
- package/dist/tool-activity/mode.d.ts.map +1 -0
- package/dist/tool-activity/mode.js +17 -0
- package/dist/tool-activity/mode.js.map +1 -0
- package/dist/tool-activity/presentation.d.ts.map +1 -1
- package/dist/tool-activity/presentation.js +104 -28
- package/dist/tool-activity/presentation.js.map +1 -1
- package/dist/tool-activity/state.d.ts +9 -2
- package/dist/tool-activity/state.d.ts.map +1 -1
- package/dist/tool-activity/state.js +43 -3
- package/dist/tool-activity/state.js.map +1 -1
- package/dist/tui/ask-user-preferences.d.ts +9 -0
- package/dist/tui/ask-user-preferences.d.ts.map +1 -0
- package/dist/tui/ask-user-preferences.js +16 -0
- package/dist/tui/ask-user-preferences.js.map +1 -0
- package/dist/tui/command-help.d.ts +13 -0
- package/dist/tui/command-help.d.ts.map +1 -0
- package/dist/tui/command-help.js +57 -0
- package/dist/tui/command-help.js.map +1 -0
- package/dist/tui/commands.d.ts +22 -0
- package/dist/tui/commands.d.ts.map +1 -0
- package/dist/tui/commands.js +404 -0
- package/dist/tui/commands.js.map +1 -0
- package/dist/tui/completion-text.d.ts +9 -0
- package/dist/tui/completion-text.d.ts.map +1 -0
- package/dist/tui/completion-text.js +33 -0
- package/dist/tui/completion-text.js.map +1 -0
- package/dist/tui/controller.d.ts +110 -0
- package/dist/tui/controller.d.ts.map +1 -0
- package/dist/tui/controller.js +579 -0
- package/dist/tui/controller.js.map +1 -0
- package/dist/tui/dialogs.d.ts +57 -0
- package/dist/tui/dialogs.d.ts.map +1 -0
- package/dist/tui/dialogs.js +242 -0
- package/dist/tui/dialogs.js.map +1 -0
- package/dist/tui/generic-ui.d.ts +4 -0
- package/dist/tui/generic-ui.d.ts.map +1 -0
- package/dist/tui/generic-ui.js +132 -0
- package/dist/tui/generic-ui.js.map +1 -0
- package/dist/tui/herdr.d.ts +56 -0
- package/dist/tui/herdr.d.ts.map +1 -0
- package/dist/tui/herdr.js +219 -0
- package/dist/tui/herdr.js.map +1 -0
- package/dist/tui/interactions.d.ts +36 -0
- package/dist/tui/interactions.d.ts.map +1 -0
- package/dist/tui/interactions.js +253 -0
- package/dist/tui/interactions.js.map +1 -0
- package/dist/tui/keybindings.d.ts +15 -0
- package/dist/tui/keybindings.d.ts.map +1 -0
- package/dist/tui/keybindings.js +101 -0
- package/dist/tui/keybindings.js.map +1 -0
- package/dist/tui/markdown.d.ts +4 -0
- package/dist/tui/markdown.d.ts.map +1 -0
- package/dist/tui/markdown.js +6 -0
- package/dist/tui/markdown.js.map +1 -0
- package/dist/tui/preferences-schema.d.ts +121 -0
- package/dist/tui/preferences-schema.d.ts.map +1 -0
- package/dist/tui/preferences-schema.js +42 -0
- package/dist/tui/preferences-schema.js.map +1 -0
- package/dist/tui/preferences-store.d.ts +22 -0
- package/dist/tui/preferences-store.d.ts.map +1 -0
- package/dist/tui/preferences-store.js +240 -0
- package/dist/tui/preferences-store.js.map +1 -0
- package/dist/tui/preferences.d.ts +42 -0
- package/dist/tui/preferences.d.ts.map +1 -0
- package/dist/tui/preferences.js +246 -0
- package/dist/tui/preferences.js.map +1 -0
- package/dist/tui/presentation-preferences.d.ts +11 -0
- package/dist/tui/presentation-preferences.d.ts.map +1 -0
- package/dist/tui/presentation-preferences.js +29 -0
- package/dist/tui/presentation-preferences.js.map +1 -0
- package/dist/tui/presentation-ui.d.ts +7 -0
- package/dist/tui/presentation-ui.d.ts.map +1 -0
- package/dist/tui/presentation-ui.js +17 -0
- package/dist/tui/presentation-ui.js.map +1 -0
- package/dist/tui/presenters.d.ts +18 -0
- package/dist/tui/presenters.d.ts.map +1 -0
- package/dist/tui/presenters.js +118 -0
- package/dist/tui/presenters.js.map +1 -0
- package/dist/tui/remote.d.ts +7 -0
- package/dist/tui/remote.d.ts.map +1 -0
- package/dist/tui/remote.js +139 -0
- package/dist/tui/remote.js.map +1 -0
- package/dist/tui/renderers/ask-user/single-select-layout.d.ts +20 -0
- package/dist/tui/renderers/ask-user/single-select-layout.d.ts.map +1 -0
- package/dist/tui/renderers/ask-user/single-select-layout.js +111 -0
- package/dist/tui/renderers/ask-user/single-select-layout.js.map +1 -0
- package/dist/tui/renderers/ask-user.d.ts +21 -0
- package/dist/tui/renderers/ask-user.d.ts.map +1 -0
- package/dist/tui/renderers/ask-user.js +1348 -0
- package/dist/tui/renderers/ask-user.js.map +1 -0
- package/dist/tui/renderers/codebase-memory.d.ts +3 -0
- package/dist/tui/renderers/codebase-memory.d.ts.map +1 -0
- package/dist/tui/renderers/codebase-memory.js +38 -0
- package/dist/tui/renderers/codebase-memory.js.map +1 -0
- package/dist/tui/renderers/codex.d.ts +5 -0
- package/dist/tui/renderers/codex.d.ts.map +1 -0
- package/dist/tui/renderers/codex.js +9 -0
- package/dist/tui/renderers/codex.js.map +1 -0
- package/dist/tui/renderers/context-view.d.ts +3 -0
- package/dist/tui/renderers/context-view.d.ts.map +1 -0
- package/dist/tui/renderers/context-view.js +69 -0
- package/dist/tui/renderers/context-view.js.map +1 -0
- package/dist/{fusion → tui/renderers/fusion}/model-picker.d.ts +2 -1
- package/dist/tui/renderers/fusion/model-picker.d.ts.map +1 -0
- package/dist/{fusion → tui/renderers/fusion}/model-picker.js +1 -0
- package/dist/tui/renderers/fusion/model-picker.js.map +1 -0
- package/dist/tui/renderers/fusion.d.ts +7 -0
- package/dist/tui/renderers/fusion.d.ts.map +1 -0
- package/dist/tui/renderers/fusion.js +266 -0
- package/dist/tui/renderers/fusion.js.map +1 -0
- package/dist/tui/renderers/insights/charts.d.ts +14 -0
- package/dist/tui/renderers/insights/charts.d.ts.map +1 -0
- package/dist/tui/renderers/insights/charts.js +77 -0
- package/dist/tui/renderers/insights/charts.js.map +1 -0
- package/dist/tui/renderers/insights/panel.d.ts +55 -0
- package/dist/tui/renderers/insights/panel.d.ts.map +1 -0
- package/dist/tui/renderers/insights/panel.js +310 -0
- package/dist/tui/renderers/insights/panel.js.map +1 -0
- package/dist/tui/renderers/insights.d.ts +4 -0
- package/dist/tui/renderers/insights.d.ts.map +1 -0
- package/dist/tui/renderers/insights.js +51 -0
- package/dist/tui/renderers/insights.js.map +1 -0
- package/dist/tui/renderers/memory.d.ts +5 -0
- package/dist/tui/renderers/memory.d.ts.map +1 -0
- package/dist/tui/renderers/memory.js +99 -0
- package/dist/tui/renderers/memory.js.map +1 -0
- package/dist/tui/renderers/navigation.d.ts +7 -0
- package/dist/tui/renderers/navigation.d.ts.map +1 -0
- package/dist/tui/renderers/navigation.js +14 -0
- package/dist/tui/renderers/navigation.js.map +1 -0
- package/dist/tui/renderers/powerline/colors.d.ts +18 -0
- package/dist/tui/renderers/powerline/colors.d.ts.map +1 -0
- package/dist/tui/renderers/powerline/colors.js +42 -0
- package/dist/tui/renderers/powerline/colors.js.map +1 -0
- package/dist/tui/renderers/powerline/config.d.ts +44 -0
- package/dist/tui/renderers/powerline/config.d.ts.map +1 -0
- package/dist/tui/renderers/powerline/config.js +123 -0
- package/dist/tui/renderers/powerline/config.js.map +1 -0
- package/dist/tui/renderers/powerline/footer-renderer.d.ts +7 -0
- package/dist/tui/renderers/powerline/footer-renderer.d.ts.map +1 -0
- package/dist/tui/renderers/powerline/footer-renderer.js +74 -0
- package/dist/tui/renderers/powerline/footer-renderer.js.map +1 -0
- package/dist/tui/renderers/powerline/projected-footer.d.ts +24 -0
- package/dist/tui/renderers/powerline/projected-footer.d.ts.map +1 -0
- package/dist/tui/renderers/powerline/projected-footer.js +33 -0
- package/dist/tui/renderers/powerline/projected-footer.js.map +1 -0
- package/dist/tui/renderers/powerline/segments.d.ts +18 -0
- package/dist/tui/renderers/powerline/segments.d.ts.map +1 -0
- package/dist/tui/renderers/powerline/segments.js +331 -0
- package/dist/tui/renderers/powerline/segments.js.map +1 -0
- package/dist/tui/renderers/powerline/symbols.d.ts +27 -0
- package/dist/tui/renderers/powerline/symbols.d.ts.map +1 -0
- package/dist/tui/renderers/powerline/symbols.js +17 -0
- package/dist/tui/renderers/powerline/symbols.js.map +1 -0
- package/dist/tui/renderers/powerline.d.ts +4 -0
- package/dist/tui/renderers/powerline.d.ts.map +1 -0
- package/dist/tui/renderers/powerline.js +4 -0
- package/dist/tui/renderers/powerline.js.map +1 -0
- package/dist/tui/renderers/prewalk/plan-review.d.ts +28 -0
- package/dist/tui/renderers/prewalk/plan-review.d.ts.map +1 -0
- package/dist/tui/renderers/prewalk/plan-review.js +414 -0
- package/dist/tui/renderers/prewalk/plan-review.js.map +1 -0
- package/dist/tui/renderers/prewalk.d.ts +5 -0
- package/dist/tui/renderers/prewalk.d.ts.map +1 -0
- package/dist/tui/renderers/prewalk.js +43 -0
- package/dist/tui/renderers/prewalk.js.map +1 -0
- package/dist/tui/renderers/processes/background-bash-view.d.ts +45 -0
- package/dist/tui/renderers/processes/background-bash-view.d.ts.map +1 -0
- package/dist/tui/renderers/processes/background-bash-view.js +405 -0
- package/dist/tui/renderers/processes/background-bash-view.js.map +1 -0
- package/dist/tui/renderers/processes/completion-message.d.ts +26 -0
- package/dist/tui/renderers/processes/completion-message.d.ts.map +1 -0
- package/dist/tui/renderers/processes/completion-message.js +97 -0
- package/dist/tui/renderers/processes/completion-message.js.map +1 -0
- package/dist/tui/renderers/processes/process-view.d.ts +40 -0
- package/dist/tui/renderers/processes/process-view.d.ts.map +1 -0
- package/dist/tui/renderers/processes/process-view.js +250 -0
- package/dist/tui/renderers/processes/process-view.js.map +1 -0
- package/dist/tui/renderers/processes.d.ts +12 -0
- package/dist/tui/renderers/processes.d.ts.map +1 -0
- package/dist/tui/renderers/processes.js +80 -0
- package/dist/tui/renderers/processes.js.map +1 -0
- package/dist/tui/renderers/prompt-history/picker.d.ts +64 -0
- package/dist/tui/renderers/prompt-history/picker.d.ts.map +1 -0
- package/dist/tui/renderers/prompt-history/picker.js +430 -0
- package/dist/tui/renderers/prompt-history/picker.js.map +1 -0
- package/dist/tui/renderers/prompt-history.d.ts +16 -0
- package/dist/tui/renderers/prompt-history.d.ts.map +1 -0
- package/dist/tui/renderers/prompt-history.js +113 -0
- package/dist/tui/renderers/prompt-history.js.map +1 -0
- package/dist/tui/renderers/tasks/tasks-overlay.d.ts +37 -0
- package/dist/tui/renderers/tasks/tasks-overlay.d.ts.map +1 -0
- package/dist/tui/renderers/tasks/tasks-overlay.js +461 -0
- package/dist/tui/renderers/tasks/tasks-overlay.js.map +1 -0
- package/dist/tui/renderers/tasks.d.ts +18 -0
- package/dist/tui/renderers/tasks.d.ts.map +1 -0
- package/dist/tui/renderers/tasks.js +97 -0
- package/dist/tui/renderers/tasks.js.map +1 -0
- package/dist/tui/run.d.ts +22 -0
- package/dist/tui/run.d.ts.map +1 -0
- package/dist/tui/run.js +249 -0
- package/dist/tui/run.js.map +1 -0
- package/dist/tui/screen.d.ts +73 -0
- package/dist/tui/screen.d.ts.map +1 -0
- package/dist/tui/screen.js +371 -0
- package/dist/tui/screen.js.map +1 -0
- package/dist/tui/session-navigator.d.ts +53 -0
- package/dist/tui/session-navigator.d.ts.map +1 -0
- package/dist/tui/session-navigator.js +256 -0
- package/dist/tui/session-navigator.js.map +1 -0
- package/dist/tui/settings-menu.d.ts +31 -0
- package/dist/tui/settings-menu.d.ts.map +1 -0
- package/dist/tui/settings-menu.js +78 -0
- package/dist/tui/settings-menu.js.map +1 -0
- package/dist/tui/setup-ui.d.ts +14 -0
- package/dist/tui/setup-ui.d.ts.map +1 -0
- package/dist/tui/setup-ui.js +122 -0
- package/dist/tui/setup-ui.js.map +1 -0
- package/dist/tui/setup.d.ts +29 -0
- package/dist/tui/setup.d.ts.map +1 -0
- package/dist/tui/setup.js +414 -0
- package/dist/tui/setup.js.map +1 -0
- package/dist/tui/shell-execution.d.ts +20 -0
- package/dist/tui/shell-execution.d.ts.map +1 -0
- package/dist/tui/shell-execution.js +64 -0
- package/dist/tui/shell-execution.js.map +1 -0
- package/dist/tui/startup-header.d.ts +4 -0
- package/dist/tui/startup-header.d.ts.map +1 -0
- package/dist/tui/startup-header.js +19 -0
- package/dist/tui/startup-header.js.map +1 -0
- package/dist/tui/streaming-markdown.d.ts +21 -0
- package/dist/tui/streaming-markdown.d.ts.map +1 -0
- package/dist/tui/streaming-markdown.js +118 -0
- package/dist/tui/streaming-markdown.js.map +1 -0
- package/dist/tui/theme-config.d.ts +26 -0
- package/dist/tui/theme-config.d.ts.map +1 -0
- package/dist/tui/theme-config.js +87 -0
- package/dist/tui/theme-config.js.map +1 -0
- package/dist/tui/theme-picker.d.ts +23 -0
- package/dist/tui/theme-picker.d.ts.map +1 -0
- package/dist/tui/theme-picker.js +91 -0
- package/dist/tui/theme-picker.js.map +1 -0
- package/dist/tui/theme.d.ts +15 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +216 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/tool-inspector.d.ts +24 -0
- package/dist/tui/tool-inspector.d.ts.map +1 -0
- package/dist/tui/tool-inspector.js +81 -0
- package/dist/tui/tool-inspector.js.map +1 -0
- package/dist/tui/tool-presentation.d.ts +3 -0
- package/dist/tui/tool-presentation.d.ts.map +1 -0
- package/dist/tui/tool-presentation.js +22 -0
- package/dist/tui/tool-presentation.js.map +1 -0
- package/dist/tui/transcript.d.ts +6 -0
- package/dist/tui/transcript.d.ts.map +1 -0
- package/dist/tui/transcript.js +78 -0
- package/dist/tui/transcript.js.map +1 -0
- package/dist/tui/tree-navigator.d.ts +71 -0
- package/dist/tui/tree-navigator.d.ts.map +1 -0
- package/dist/tui/tree-navigator.js +522 -0
- package/dist/tui/tree-navigator.js.map +1 -0
- package/npm-shrinkwrap.json +598 -116
- package/package.json +79 -30
- package/dist/acp/interactions.d.ts +0 -22
- package/dist/acp/interactions.d.ts.map +0 -1
- package/dist/acp/interactions.js +0 -353
- package/dist/acp/interactions.js.map +0 -1
- package/dist/application.d.ts +0 -23
- package/dist/application.d.ts.map +0 -1
- package/dist/application.js +0 -267
- package/dist/application.js.map +0 -1
- package/dist/browser/authorization-host.d.ts.map +0 -1
- package/dist/browser/authorization-host.js.map +0 -1
- package/dist/browser/chrome-devtools.d.ts.map +0 -1
- package/dist/browser/chrome-devtools.js.map +0 -1
- package/dist/browser/connection-lease.d.ts.map +0 -1
- package/dist/browser/connection-lease.js.map +0 -1
- package/dist/classifier-settings.d.ts +0 -10
- package/dist/classifier-settings.d.ts.map +0 -1
- package/dist/classifier-settings.js +0 -98
- package/dist/classifier-settings.js.map +0 -1
- package/dist/classifier.d.ts.map +0 -1
- package/dist/classifier.js.map +0 -1
- package/dist/codemode.d.ts.map +0 -1
- package/dist/codemode.js.map +0 -1
- package/dist/codex.d.ts +0 -3
- package/dist/codex.d.ts.map +0 -1
- package/dist/codex.js +0 -8
- package/dist/codex.js.map +0 -1
- package/dist/command-autocomplete.d.ts +0 -3
- package/dist/command-autocomplete.d.ts.map +0 -1
- package/dist/command-autocomplete.js +0 -10
- package/dist/command-autocomplete.js.map +0 -1
- package/dist/cwd-command.d.ts +0 -13
- package/dist/cwd-command.d.ts.map +0 -1
- package/dist/cwd-command.js +0 -176
- package/dist/cwd-command.js.map +0 -1
- package/dist/dependencies.d.ts +0 -37
- package/dist/dependencies.d.ts.map +0 -1
- package/dist/dependencies.js +0 -372
- package/dist/dependencies.js.map +0 -1
- package/dist/extension-settings.d.ts +0 -12
- package/dist/extension-settings.d.ts.map +0 -1
- package/dist/extension-settings.js +0 -241
- package/dist/extension-settings.js.map +0 -1
- package/dist/extensions.d.ts +0 -62
- package/dist/extensions.d.ts.map +0 -1
- package/dist/extensions.js +0 -265
- package/dist/extensions.js.map +0 -1
- package/dist/fusion/host.d.ts +0 -3
- package/dist/fusion/host.d.ts.map +0 -1
- package/dist/fusion/host.js +0 -333
- package/dist/fusion/host.js.map +0 -1
- package/dist/fusion/model-picker.d.ts.map +0 -1
- package/dist/fusion/model-picker.js.map +0 -1
- package/dist/herdr.d.ts +0 -29
- package/dist/herdr.d.ts.map +0 -1
- package/dist/herdr.js +0 -247
- package/dist/herdr.js.map +0 -1
- package/dist/insights.d.ts +0 -5
- package/dist/insights.d.ts.map +0 -1
- package/dist/insights.js +0 -140
- package/dist/insights.js.map +0 -1
- package/dist/lock.d.ts +0 -27
- package/dist/lock.d.ts.map +0 -1
- package/dist/lock.js +0 -432
- package/dist/lock.js.map +0 -1
- package/dist/logger.d.ts +0 -7
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -48
- package/dist/logger.js.map +0 -1
- package/dist/mcp/callback-server.d.ts +0 -11
- package/dist/mcp/callback-server.d.ts.map +0 -1
- package/dist/mcp/callback-server.js.map +0 -1
- package/dist/mcp/config.d.ts +0 -20
- package/dist/mcp/config.d.ts.map +0 -1
- package/dist/mcp/config.js +0 -352
- package/dist/mcp/config.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -3
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js +0 -25
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/oauth-host.d.ts +0 -42
- package/dist/mcp/oauth-host.d.ts.map +0 -1
- package/dist/mcp/oauth-host.js +0 -524
- package/dist/mcp/oauth-host.js.map +0 -1
- package/dist/mcp/oauth-store.d.ts +0 -27
- package/dist/mcp/oauth-store.d.ts.map +0 -1
- package/dist/mcp/oauth-store.js +0 -138
- package/dist/mcp/oauth-store.js.map +0 -1
- package/dist/memory/control.d.ts +0 -8
- package/dist/memory/control.d.ts.map +0 -1
- package/dist/memory/control.js +0 -167
- package/dist/memory/control.js.map +0 -1
- package/dist/memory/coordinator.d.ts +0 -53
- package/dist/memory/coordinator.d.ts.map +0 -1
- package/dist/memory/coordinator.js +0 -807
- package/dist/memory/coordinator.js.map +0 -1
- package/dist/memory/dreamer.d.ts +0 -50
- package/dist/memory/dreamer.d.ts.map +0 -1
- package/dist/memory/dreamer.js +0 -527
- package/dist/memory/dreamer.js.map +0 -1
- package/dist/memory/history-view.d.ts.map +0 -1
- package/dist/memory/history-view.js.map +0 -1
- package/dist/memory/lease.d.ts +0 -13
- package/dist/memory/lease.d.ts.map +0 -1
- package/dist/memory/lease.js +0 -188
- package/dist/memory/lease.js.map +0 -1
- package/dist/memory/project.d.ts +0 -7
- package/dist/memory/project.d.ts.map +0 -1
- package/dist/memory/project.js +0 -41
- package/dist/memory/project.js.map +0 -1
- package/dist/memory/run-retention.d.ts +0 -12
- package/dist/memory/run-retention.d.ts.map +0 -1
- package/dist/memory/run-retention.js +0 -294
- package/dist/memory/run-retention.js.map +0 -1
- package/dist/memory/run.d.ts +0 -79
- package/dist/memory/run.d.ts.map +0 -1
- package/dist/memory/run.js +0 -417
- package/dist/memory/run.js.map +0 -1
- package/dist/memory/store.d.ts +0 -116
- package/dist/memory/store.d.ts.map +0 -1
- package/dist/memory/store.js +0 -751
- package/dist/memory/store.js.map +0 -1
- package/dist/model-defaults.d.ts.map +0 -1
- package/dist/model-defaults.js.map +0 -1
- package/dist/model-selector.d.ts +0 -5
- package/dist/model-selector.d.ts.map +0 -1
- package/dist/model-selector.js +0 -87
- package/dist/model-selector.js.map +0 -1
- package/dist/output-style-instructions.d.ts +0 -6
- package/dist/output-style-instructions.d.ts.map +0 -1
- package/dist/output-style-instructions.js +0 -53
- package/dist/output-style-instructions.js.map +0 -1
- package/dist/overlay-images.d.ts +0 -9
- package/dist/overlay-images.d.ts.map +0 -1
- package/dist/overlay-images.js +0 -99
- package/dist/overlay-images.js.map +0 -1
- package/dist/pi-extensions.d.ts +0 -28
- package/dist/pi-extensions.d.ts.map +0 -1
- package/dist/pi-extensions.js +0 -141
- package/dist/pi-extensions.js.map +0 -1
- package/dist/pi-llama.d.ts +0 -2
- package/dist/pi-llama.d.ts.map +0 -1
- package/dist/pi-llama.js +0 -15
- package/dist/pi-llama.js.map +0 -1
- package/dist/pi-lock.d.ts.map +0 -1
- package/dist/pi-lock.js.map +0 -1
- package/dist/powerline.d.ts +0 -12
- package/dist/powerline.d.ts.map +0 -1
- package/dist/powerline.js.map +0 -1
- package/dist/project-trust-prompt.d.ts +0 -30
- package/dist/project-trust-prompt.d.ts.map +0 -1
- package/dist/project-trust-prompt.js +0 -122
- package/dist/project-trust-prompt.js.map +0 -1
- package/dist/project-trust.d.ts +0 -8
- package/dist/project-trust.d.ts.map +0 -1
- package/dist/project-trust.js +0 -36
- package/dist/project-trust.js.map +0 -1
- package/dist/prompt-history.d.ts +0 -11
- package/dist/prompt-history.d.ts.map +0 -1
- package/dist/prompt-history.js +0 -96
- package/dist/prompt-history.js.map +0 -1
- package/dist/restart-command.d.ts +0 -9
- package/dist/restart-command.d.ts.map +0 -1
- package/dist/restart-command.js +0 -94
- package/dist/restart-command.js.map +0 -1
- package/dist/resume.d.ts +0 -5
- package/dist/resume.d.ts.map +0 -1
- package/dist/resume.js +0 -46
- package/dist/resume.js.map +0 -1
- package/dist/runtime-factory.d.ts +0 -12
- package/dist/runtime-factory.d.ts.map +0 -1
- package/dist/runtime-factory.js +0 -12
- package/dist/runtime-factory.js.map +0 -1
- package/dist/runtime.d.ts +0 -59
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -534
- package/dist/runtime.js.map +0 -1
- package/dist/savings.d.ts.map +0 -1
- package/dist/savings.js.map +0 -1
- package/dist/settings.d.ts.map +0 -1
- package/dist/settings.js +0 -359
- package/dist/settings.js.map +0 -1
- package/dist/startup-header.d.ts +0 -9
- package/dist/startup-header.d.ts.map +0 -1
- package/dist/startup-header.js +0 -151
- package/dist/startup-header.js.map +0 -1
- package/dist/subagents/catalog.d.ts +0 -8
- package/dist/subagents/catalog.d.ts.map +0 -1
- package/dist/subagents/catalog.js +0 -136
- package/dist/subagents/catalog.js.map +0 -1
- package/dist/subagents/host.d.ts +0 -133
- package/dist/subagents/host.d.ts.map +0 -1
- package/dist/subagents/host.js +0 -1420
- package/dist/subagents/host.js.map +0 -1
- package/dist/subagents/store.d.ts +0 -25
- package/dist/subagents/store.d.ts.map +0 -1
- package/dist/subagents/store.js +0 -35
- package/dist/subagents/store.js.map +0 -1
- package/dist/system-prompt.d.ts.map +0 -1
- package/dist/system-prompt.js.map +0 -1
- package/dist/tui-compatibility.d.ts +0 -4
- package/dist/tui-compatibility.d.ts.map +0 -1
- package/dist/tui-compatibility.js +0 -244
- package/dist/tui-compatibility.js.map +0 -1
- package/dist/update-notification.d.ts +0 -3
- package/dist/update-notification.d.ts.map +0 -1
- package/dist/update-notification.js +0 -50
- package/dist/update-notification.js.map +0 -1
- /package/dist/{browser → providers/browser}/chrome-devtools.d.ts +0 -0
- /package/dist/{browser → providers/browser}/chrome-devtools.js +0 -0
- /package/dist/{browser → providers/browser}/connection-lease.d.ts +0 -0
- /package/dist/{browser → providers/browser}/connection-lease.js +0 -0
- /package/dist/{classifier.d.ts → providers/classifier.d.ts} +0 -0
- /package/dist/{classifier.js → providers/classifier.js} +0 -0
- /package/dist/{codemode.d.ts → providers/codemode.d.ts} +0 -0
- /package/dist/{codemode.js → providers/codemode.js} +0 -0
- /package/dist/{model-defaults.d.ts → providers/model-defaults.d.ts} +0 -0
- /package/dist/{model-defaults.js → providers/model-defaults.js} +0 -0
- /package/dist/{pi-lock.d.ts → providers/pi-lock.d.ts} +0 -0
- /package/dist/{system-prompt.d.ts → providers/system-prompt.d.ts} +0 -0
- /package/dist/{system-prompt.js → providers/system-prompt.js} +0 -0
|
@@ -0,0 +1,806 @@
|
|
|
1
|
+
import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
2
|
+
import { setTimeout as wait } from 'node:timers/promises';
|
|
3
|
+
import { CONTROL_VERSION, LIMITS, OPERATION_CATALOG, PROTOCOL_VERSION, canonicalRequestPayload, encodeFrame, parseClientEnvelope, parseControlRequest, parseControlResponse, parseServerEnvelope, } from '@felan-ai/session-protocol';
|
|
4
|
+
import { spawnDetachedDaemon } from '@felan-ai/daemon/client';
|
|
5
|
+
import { assertTargetIdentity, protocolTarget, resolveDaemonTarget } from '@felan-ai/daemon/client';
|
|
6
|
+
import { waitForDaemonStop } from './daemon-stop.js';
|
|
7
|
+
import { createSessionState, reduceSession } from './reducer.js';
|
|
8
|
+
import { diagnosticText } from './diagnostics.js';
|
|
9
|
+
import { localConnector } from './transport.js';
|
|
10
|
+
export function newRequestId(now = Date.now()) {
|
|
11
|
+
if (!Number.isSafeInteger(now) || now < 0 || now > 0xffffffffffff)
|
|
12
|
+
throw new Error('Invalid request timestamp');
|
|
13
|
+
const bytes = randomBytes(16);
|
|
14
|
+
bytes.writeUIntBE(now, 0, 6);
|
|
15
|
+
bytes[6] = (bytes[6] & 15) | 0x70;
|
|
16
|
+
bytes[8] = (bytes[8] & 63) | 0x80;
|
|
17
|
+
const hex = bytes.toString('hex');
|
|
18
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
19
|
+
}
|
|
20
|
+
const LIVENESS_OPERATIONS = new Set(['hello', 'host.status']);
|
|
21
|
+
const failure = (id, outcome, code, message) => ({ v: 1, re: id, outcome, error: { code, message, retryable: false } });
|
|
22
|
+
export class SessionClient {
|
|
23
|
+
options;
|
|
24
|
+
target;
|
|
25
|
+
connector;
|
|
26
|
+
timeout;
|
|
27
|
+
retries;
|
|
28
|
+
reconnectLimit;
|
|
29
|
+
delay;
|
|
30
|
+
maxDelay;
|
|
31
|
+
transport;
|
|
32
|
+
connecting;
|
|
33
|
+
connectingLaunches = false;
|
|
34
|
+
epoch = 0;
|
|
35
|
+
closed = false;
|
|
36
|
+
lifetime = new AbortController();
|
|
37
|
+
reconnectCount = 0;
|
|
38
|
+
reconnectTimer;
|
|
39
|
+
reconnectAt;
|
|
40
|
+
established = false;
|
|
41
|
+
readyAt = 0;
|
|
42
|
+
records = new Map();
|
|
43
|
+
attachments = new Map();
|
|
44
|
+
interactionNotifications = new Map();
|
|
45
|
+
queuedInteractions = [];
|
|
46
|
+
queuedInteractionBytes = 0;
|
|
47
|
+
recovering = new Set();
|
|
48
|
+
listeners = new Set();
|
|
49
|
+
presentationListeners = new Set();
|
|
50
|
+
presentationSequences = new Map();
|
|
51
|
+
pinned;
|
|
52
|
+
verifying;
|
|
53
|
+
replacing;
|
|
54
|
+
mismatchedWork;
|
|
55
|
+
negotiated;
|
|
56
|
+
connectionState = 'disconnected';
|
|
57
|
+
constructor(options) {
|
|
58
|
+
this.options = options;
|
|
59
|
+
this.options = { ...options, target: structuredClone(options.target),
|
|
60
|
+
...(options.launch ? { launch: structuredClone(options.launch) } : {}),
|
|
61
|
+
interactionKinds: [...(options.interactionKinds ?? [])], capabilities: [...(options.capabilities ?? [])] };
|
|
62
|
+
this.target = resolveDaemonTarget(options.target);
|
|
63
|
+
if (options.expectedDaemonVersion !== undefined && (!options.expectedDaemonVersion || Buffer.byteLength(options.expectedDaemonVersion) > 128))
|
|
64
|
+
throw new Error('Invalid expected daemon version.');
|
|
65
|
+
this.connector = options.connector ?? localConnector(this.target);
|
|
66
|
+
this.pinned = options.expected && structuredClone(options.expected);
|
|
67
|
+
if (this.pinned)
|
|
68
|
+
assertTargetIdentity(this.target, this.pinned, this.pinned);
|
|
69
|
+
this.timeout = bounded(options.requestTimeoutMs ?? 5_000, 1, 60_000);
|
|
70
|
+
this.retries = bounded(options.retries ?? 2, 0, 5);
|
|
71
|
+
this.reconnectLimit = options.reconnectAttempts === undefined ? Infinity : bounded(options.reconnectAttempts, 0, Number.MAX_SAFE_INTEGER);
|
|
72
|
+
this.delay = bounded(options.reconnectDelayMs ?? 250, 0, 10_000);
|
|
73
|
+
this.maxDelay = Math.max(this.delay, bounded(options.reconnectMaxDelayMs ?? 10_000, 0, 300_000));
|
|
74
|
+
}
|
|
75
|
+
get status() { return this.connectionState; }
|
|
76
|
+
/** The scheduled automatic reconnect after an established connection dropped; automatic attempts never launch a daemon. */
|
|
77
|
+
get reconnection() {
|
|
78
|
+
return this.reconnectAt === undefined ? undefined : { attempt: this.reconnectCount + 1, retryAt: this.reconnectAt };
|
|
79
|
+
}
|
|
80
|
+
get identity() { return this.pinned && structuredClone(this.pinned); }
|
|
81
|
+
get capabilities() { return this.negotiated && structuredClone(this.negotiated); }
|
|
82
|
+
/** Active work on an incompatible daemon, when it could report it; restarting it would interrupt that work. */
|
|
83
|
+
get incompatibleActiveWork() { return this.connectionState === 'incompatible' ? this.mismatchedWork : undefined; }
|
|
84
|
+
getInteractions(options = {}) {
|
|
85
|
+
const items = new Map(this.interactionNotifications);
|
|
86
|
+
if (options.includeSessions)
|
|
87
|
+
for (const attachment of this.attachments.values()) {
|
|
88
|
+
if (attachment.state.status !== 'live')
|
|
89
|
+
continue;
|
|
90
|
+
for (const item of attachment.state.snapshot?.interactions ?? []) {
|
|
91
|
+
if (item.state === 'waiting' || item.state === 'deferred')
|
|
92
|
+
items.set(item.id, item);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return structuredClone([...items.values()]);
|
|
96
|
+
}
|
|
97
|
+
/** An independent, mutable copy of the attachment; use {@link readAttachment} for frequent reads. */
|
|
98
|
+
getAttachment(session) { return structuredClone(this.attachments.get(session)); }
|
|
99
|
+
/** The current attachment itself, deeply frozen and shared with every reader; it never changes, later updates replace it. */
|
|
100
|
+
readAttachment(session) {
|
|
101
|
+
const attachment = this.attachments.get(session);
|
|
102
|
+
if (attachment)
|
|
103
|
+
deepFreeze(attachment);
|
|
104
|
+
return attachment;
|
|
105
|
+
}
|
|
106
|
+
getRequest(id) {
|
|
107
|
+
const record = this.records.get(id) ?? this.records.get(id.toLowerCase());
|
|
108
|
+
return record && (record.response ? { status: record.response.outcome, id: record.envelope.id, op: record.envelope.op, attempts: record.attempts, response: structuredClone(record.response) }
|
|
109
|
+
: { status: 'pending', id: record.envelope.id, op: record.envelope.op, attempts: record.attempts });
|
|
110
|
+
}
|
|
111
|
+
subscribe(listener) { this.listeners.add(listener); return () => this.listeners.delete(listener); }
|
|
112
|
+
subscribePresentation(listener) {
|
|
113
|
+
this.presentationListeners.add(listener);
|
|
114
|
+
return () => this.presentationListeners.delete(listener);
|
|
115
|
+
}
|
|
116
|
+
emit() { for (const listener of this.listeners) {
|
|
117
|
+
try {
|
|
118
|
+
listener();
|
|
119
|
+
}
|
|
120
|
+
catch { /* Observers cannot interrupt protocol processing. */ }
|
|
121
|
+
} }
|
|
122
|
+
connectTransport(receiver) {
|
|
123
|
+
if (this.closed)
|
|
124
|
+
return Promise.reject(new Error('Client is closed'));
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
let settled = false;
|
|
127
|
+
const finish = (error, transport) => {
|
|
128
|
+
if (settled) {
|
|
129
|
+
transport?.close();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
settled = true;
|
|
133
|
+
clearTimeout(timer);
|
|
134
|
+
this.lifetime.signal.removeEventListener('abort', onClose);
|
|
135
|
+
if (transport)
|
|
136
|
+
resolve(transport);
|
|
137
|
+
else
|
|
138
|
+
reject(error);
|
|
139
|
+
};
|
|
140
|
+
const onClose = () => finish(new Error('Client is closed'));
|
|
141
|
+
const timer = setTimeout(() => finish(new Error('Connection deadline exceeded')), this.timeout);
|
|
142
|
+
this.lifetime.signal.addEventListener('abort', onClose, { once: true });
|
|
143
|
+
try {
|
|
144
|
+
void this.connector(receiver).then(transport => finish(undefined, transport), error => finish(error));
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
finish(error);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
whileOpen(operation) {
|
|
152
|
+
return new Promise((resolve, reject) => {
|
|
153
|
+
const onClose = () => reject(new Error('Client is closed'));
|
|
154
|
+
if (this.closed)
|
|
155
|
+
onClose();
|
|
156
|
+
else
|
|
157
|
+
this.lifetime.signal.addEventListener('abort', onClose, { once: true });
|
|
158
|
+
void operation.then(resolve, reject).finally(() => this.lifetime.signal.removeEventListener('abort', onClose));
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/** Connects now, resetting automatic backoff; unlike automatic reconnects this starts an absent daemon when `launch` is configured. */
|
|
162
|
+
async connect(options = {}) {
|
|
163
|
+
if (options.replacing) {
|
|
164
|
+
assertTargetIdentity(this.target, options.replacing, options.replacing);
|
|
165
|
+
this.replacing = structuredClone(options.replacing);
|
|
166
|
+
}
|
|
167
|
+
if (this.connecting && !this.connectingLaunches)
|
|
168
|
+
await this.connecting.catch(() => { });
|
|
169
|
+
this.cancelReconnect();
|
|
170
|
+
this.reconnectCount = 0;
|
|
171
|
+
try {
|
|
172
|
+
return await this.connectShared(true);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
this.retryLater();
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
connectShared(launch) {
|
|
180
|
+
if (this.closed)
|
|
181
|
+
return Promise.reject(new Error('Client is closed'));
|
|
182
|
+
if (this.connecting)
|
|
183
|
+
return this.connecting;
|
|
184
|
+
if (this.connectionState === 'ready')
|
|
185
|
+
return Promise.resolve(structuredClone(this.negotiated));
|
|
186
|
+
this.connectingLaunches = launch;
|
|
187
|
+
this.connecting = this.open(launch).finally(() => { this.connecting = undefined; });
|
|
188
|
+
return this.connecting;
|
|
189
|
+
}
|
|
190
|
+
/** An idle daemon from another installation is replaced transparently; one with active work stays incompatible so the caller can ask. */
|
|
191
|
+
async open(launch) {
|
|
192
|
+
try {
|
|
193
|
+
return await this.openOnce(launch);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (!launch || this.closed || this.connectionState !== 'incompatible' || this.mismatchedWork !== 0 || !this.options.launch || this.options.expected)
|
|
197
|
+
throw error;
|
|
198
|
+
const identity = this.pinned;
|
|
199
|
+
const response = await this.control('host.restart', 'drain');
|
|
200
|
+
if (response.outcome !== 'accepted')
|
|
201
|
+
throw new Error('The running daemon did not accept a restart.');
|
|
202
|
+
await waitForDaemonStop(this, this.lifetime.signal);
|
|
203
|
+
this.pinned = undefined;
|
|
204
|
+
this.replacing = identity;
|
|
205
|
+
return this.openOnce(launch);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async openOnce(launch) {
|
|
209
|
+
this.queuedInteractions = [];
|
|
210
|
+
this.queuedInteractionBytes = 0;
|
|
211
|
+
this.mismatchedWork = undefined;
|
|
212
|
+
// Only an explicit expected identity or this attempt's launch receipt pins the instance; an unpinned client follows daemon restarts.
|
|
213
|
+
this.verifying = this.options.expected && structuredClone(this.options.expected);
|
|
214
|
+
this.connectionState = 'connecting';
|
|
215
|
+
this.negotiated = undefined;
|
|
216
|
+
this.emit();
|
|
217
|
+
const epoch = ++this.epoch;
|
|
218
|
+
const receiver = { frame: (value) => { if (epoch === this.epoch)
|
|
219
|
+
this.receive(value); },
|
|
220
|
+
closed: (reason) => { if (epoch === this.epoch)
|
|
221
|
+
this.lost(reason); } };
|
|
222
|
+
try {
|
|
223
|
+
try {
|
|
224
|
+
this.transport = await this.connectTransport(receiver);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (this.closed)
|
|
228
|
+
throw new Error('Client is closed');
|
|
229
|
+
const code = error.code;
|
|
230
|
+
if (!launch || this.options.expected || !this.options.launch || !['ENOENT', 'stale_endpoint', 'unavailable'].includes(code ?? ''))
|
|
231
|
+
throw error;
|
|
232
|
+
try {
|
|
233
|
+
const receipt = await this.whileOpen(spawnDetachedDaemon({ target: this.options.target, ...this.options.launch, ...(this.replacing ? { replacing: this.replacing } : {}) }));
|
|
234
|
+
if (this.closed)
|
|
235
|
+
throw new Error('Client is closed');
|
|
236
|
+
assertTargetIdentity(this.target, receipt.identity, receipt.identity);
|
|
237
|
+
this.pinned = receipt.identity;
|
|
238
|
+
this.verifying = receipt.identity;
|
|
239
|
+
}
|
|
240
|
+
catch (launchError) {
|
|
241
|
+
if (launchError.code !== 'launch_failed')
|
|
242
|
+
throw launchError;
|
|
243
|
+
// A concurrent starter can win ownership while this launch exits.
|
|
244
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
245
|
+
if (attempt)
|
|
246
|
+
await wait(this.delay, undefined, { signal: this.lifetime.signal });
|
|
247
|
+
try {
|
|
248
|
+
this.transport = await this.connectTransport(receiver);
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
catch { /* Retry only discovery, never the launch. */ }
|
|
252
|
+
}
|
|
253
|
+
if (!this.transport)
|
|
254
|
+
throw launchError;
|
|
255
|
+
}
|
|
256
|
+
this.transport ??= await this.connectTransport(receiver);
|
|
257
|
+
}
|
|
258
|
+
if (this.closed || epoch !== this.epoch) {
|
|
259
|
+
this.transport?.close();
|
|
260
|
+
throw new Error('Connection was superseded');
|
|
261
|
+
}
|
|
262
|
+
const hello = await this.exchange('hello', { clientVersion: this.options.clientVersion, protocol: PROTOCOL_VERSION,
|
|
263
|
+
kind: this.options.kind, interactionKinds: this.options.interactionKinds ?? [],
|
|
264
|
+
capabilities: this.options.capabilities ?? [],
|
|
265
|
+
target: protocolTarget(this.target) }, undefined, undefined, true);
|
|
266
|
+
if (this.closed || epoch !== this.epoch)
|
|
267
|
+
throw new Error('Connection was superseded');
|
|
268
|
+
if (hello.outcome !== 'accepted')
|
|
269
|
+
throw new Error('Daemon handshake rejected');
|
|
270
|
+
const result = hello.result;
|
|
271
|
+
assertTargetIdentity(this.target, this.verifying ?? result.identity, result.identity);
|
|
272
|
+
this.pinned = structuredClone(result.identity);
|
|
273
|
+
const versionDiffers = !!this.options.expectedDaemonVersion && result.daemonVersion !== this.options.expectedDaemonVersion;
|
|
274
|
+
if (versionDiffers || this.options.expectedComposition && (this.options.expectedComposition.managerPackage !== result.composition?.managerPackage
|
|
275
|
+
|| this.options.expectedComposition.managerVersion !== result.composition?.managerVersion
|
|
276
|
+
|| this.options.expectedComposition.providerDigest !== result.composition?.providerDigest)) {
|
|
277
|
+
this.mismatchedWork = await this.activeWork(result.operations);
|
|
278
|
+
this.connectionState = 'incompatible';
|
|
279
|
+
throw new Error(versionDiffers ? 'Daemon version differs from the installed package; restart it to continue.'
|
|
280
|
+
: 'Daemon provider configuration differs from the selected configuration; restart it to continue.');
|
|
281
|
+
}
|
|
282
|
+
this.negotiated = structuredClone(result);
|
|
283
|
+
for (const interaction of this.queuedInteractions)
|
|
284
|
+
this.acceptInteraction(interaction);
|
|
285
|
+
this.queuedInteractions = [];
|
|
286
|
+
this.queuedInteractionBytes = 0;
|
|
287
|
+
for (const attachment of this.attachments.values()) {
|
|
288
|
+
if (this.closed || epoch !== this.epoch)
|
|
289
|
+
throw new Error('Connection was superseded');
|
|
290
|
+
await this.restore(attachment.session, 'reconnect');
|
|
291
|
+
}
|
|
292
|
+
if (epoch !== this.epoch || this.closed)
|
|
293
|
+
throw new Error('Connection was superseded');
|
|
294
|
+
this.connectionState = 'ready';
|
|
295
|
+
this.established = true;
|
|
296
|
+
this.readyAt = Date.now();
|
|
297
|
+
this.replacing = undefined;
|
|
298
|
+
this.diagnose({ event: 'connection.ready', daemonVersion: result.daemonVersion, instanceId: result.identity.instanceId });
|
|
299
|
+
for (const record of this.records.values())
|
|
300
|
+
if (!record.internal && !record.response)
|
|
301
|
+
this.transmit(record);
|
|
302
|
+
this.emit();
|
|
303
|
+
return structuredClone(result);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
this.diagnose({ event: 'connection.failed', error: diagnosticText(error) });
|
|
307
|
+
const status = this.connectionState;
|
|
308
|
+
// An established client that will retry stays disconnected so observers do not treat a daemon restart as fatal.
|
|
309
|
+
if (status !== 'incompatible' && !this.closed)
|
|
310
|
+
this.connectionState = this.established && this.reconnectCount < this.reconnectLimit ? 'disconnected' : 'blocked';
|
|
311
|
+
this.interactionNotifications.clear();
|
|
312
|
+
this.queuedInteractions = [];
|
|
313
|
+
this.queuedInteractionBytes = 0;
|
|
314
|
+
++this.epoch;
|
|
315
|
+
this.transport?.close();
|
|
316
|
+
this.transport = undefined;
|
|
317
|
+
this.settleOutstanding('Daemon connection could not be established; execution may still be running');
|
|
318
|
+
this.emit();
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async activeWork(operations) {
|
|
323
|
+
if (!operations.includes('host.status'))
|
|
324
|
+
return undefined;
|
|
325
|
+
const response = await this.exchange('host.status', {}, undefined, undefined, true);
|
|
326
|
+
return response.outcome === 'accepted' ? response.result.active.work : undefined;
|
|
327
|
+
}
|
|
328
|
+
request(op, params, options = {}) {
|
|
329
|
+
if (op === 'hello' || op === 'attach' || op === 'detach')
|
|
330
|
+
throw new Error('Use connect, attach or detach for connection bindings');
|
|
331
|
+
return this.exchange(op, params, options.session, options.id, false);
|
|
332
|
+
}
|
|
333
|
+
exchange(op, params, session, suppliedId, internal = false) {
|
|
334
|
+
const id = OPERATION_CATALOG[op].mutation ? (suppliedId ?? newRequestId()).toLowerCase() : suppliedId ?? randomUUID();
|
|
335
|
+
const previous = this.records.get(id);
|
|
336
|
+
const envelope = parseClientEnvelope({ v: 1, id, op, params, ...(session === undefined ? {} : { session }) });
|
|
337
|
+
const canonical = canonicalRequestPayload(envelope);
|
|
338
|
+
const payload = op === 'host.setup.answer' || envelope.op === 'remote.configure' && envelope.params.action === 'login'
|
|
339
|
+
? createHash('sha256').update(canonical).digest('hex') : canonical;
|
|
340
|
+
if (previous) {
|
|
341
|
+
if (previous.payload !== payload)
|
|
342
|
+
return Promise.resolve(failure(id, 'rejected', 'request_conflict', 'Request ID already names a different command'));
|
|
343
|
+
return previous.promise;
|
|
344
|
+
}
|
|
345
|
+
const bytes = encodeFrame(envelope).byteLength;
|
|
346
|
+
if (!internal && (this.connectionState !== 'ready' || !this.negotiated?.operations.includes(op))) {
|
|
347
|
+
return Promise.resolve(failure(id, 'rejected', this.connectionState === 'ready' ? 'unsupported_operation' : 'unavailable', this.connectionState === 'ready' ? 'Operation is not available on this connection' : 'Daemon is not connected'));
|
|
348
|
+
}
|
|
349
|
+
const pending = [...this.records.values()].filter(record => !record.response);
|
|
350
|
+
if (pending.length >= LIMITS.inflightRequests || pending.reduce((sum, record) => sum + record.bytes, 0) + bytes > LIMITS.unsentBytes) {
|
|
351
|
+
return Promise.resolve(failure(id, 'rejected', 'request_capacity', 'Client in-flight request limit reached'));
|
|
352
|
+
}
|
|
353
|
+
let resolve;
|
|
354
|
+
const promise = new Promise(done => { resolve = done; });
|
|
355
|
+
const record = { envelope, payload, bytes, attempts: 0, resolve, promise, internal,
|
|
356
|
+
localAttachmentId: session === undefined ? undefined : this.attachments.get(session)?.id };
|
|
357
|
+
this.records.set(id, record);
|
|
358
|
+
this.transmit(record);
|
|
359
|
+
this.emit();
|
|
360
|
+
return promise;
|
|
361
|
+
}
|
|
362
|
+
transmit(record) {
|
|
363
|
+
if (record.response || record.timer)
|
|
364
|
+
return;
|
|
365
|
+
if (this.closed) {
|
|
366
|
+
this.finish(record, failure(record.envelope.id, 'indeterminate', 'unavailable', 'Client is closed'));
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (record.attempts && record.envelope.op === 'remote.configure' && record.envelope.params.action === 'login') {
|
|
370
|
+
this.finish(record, failure(record.envelope.id, 'indeterminate', 'unavailable', 'Remote login reply was lost. Check /remote status or run /remote login again.'));
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (record.attempts > this.retries) {
|
|
374
|
+
this.finish(record, failure(record.envelope.id, 'indeterminate', 'indeterminate', 'No authoritative reply before retry limit'));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
if (!this.transport)
|
|
379
|
+
throw new Error('No transport');
|
|
380
|
+
++record.attempts;
|
|
381
|
+
// Interactive operations wait for their authoritative reply; only liveness probes are bounded.
|
|
382
|
+
if (LIVENESS_OPERATIONS.has(record.envelope.op))
|
|
383
|
+
record.timer = setTimeout(() => {
|
|
384
|
+
record.timer = undefined;
|
|
385
|
+
if (this.transport)
|
|
386
|
+
this.transmit(record);
|
|
387
|
+
else
|
|
388
|
+
this.finish(record, failure(record.envelope.id, 'indeterminate', 'indeterminate', 'Connection lost before authoritative reply'));
|
|
389
|
+
}, this.timeout);
|
|
390
|
+
this.transport.send(record.envelope);
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
this.finish(record, failure(record.envelope.id, record.attempts ? 'indeterminate' : 'rejected', 'unavailable', 'Request could not be delivered'));
|
|
394
|
+
}
|
|
395
|
+
finally {
|
|
396
|
+
if (record.envelope.op === 'remote.configure' && record.envelope.params.action === 'login') {
|
|
397
|
+
// A PAT is sent once, never retained for replay after a disconnect.
|
|
398
|
+
record.envelope = { ...record.envelope, params: { ...record.envelope.params, token: '' } };
|
|
399
|
+
record.bytes = encodeFrame(record.envelope).byteLength + (record.response ? encodeFrame(record.response).byteLength : 0);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
finish(record, response) {
|
|
404
|
+
clearTimeout(record.timer);
|
|
405
|
+
record.timer = undefined;
|
|
406
|
+
if (record.response)
|
|
407
|
+
return;
|
|
408
|
+
if (record.envelope.op === 'host.setup.answer') {
|
|
409
|
+
record.envelope = { ...record.envelope, params: { ...record.envelope.params, text: '' } };
|
|
410
|
+
record.bytes = encodeFrame(record.envelope).byteLength;
|
|
411
|
+
}
|
|
412
|
+
else if (record.envelope.op === 'remote.configure' && record.envelope.params.action === 'login') {
|
|
413
|
+
record.envelope = { ...record.envelope, params: { ...record.envelope.params, token: '' } };
|
|
414
|
+
record.bytes = encodeFrame(record.envelope).byteLength;
|
|
415
|
+
response = JSON.parse(JSON.stringify(response, (_key, value) => typeof value === 'string'
|
|
416
|
+
? value.replace(/fln_pat_[A-Za-z0-9_-]+/gu, '[redacted]') : value));
|
|
417
|
+
}
|
|
418
|
+
record.response = structuredClone(response);
|
|
419
|
+
record.resolve(structuredClone(response));
|
|
420
|
+
record.bytes += encodeFrame(response).byteLength;
|
|
421
|
+
const completed = [...this.records].filter(([, item]) => item.response);
|
|
422
|
+
let retainedBytes = [...this.records.values()].reduce((sum, item) => sum + item.bytes, 0);
|
|
423
|
+
for (const [index, [id, item]] of completed.entries()) {
|
|
424
|
+
if (completed.length - index <= 256 && retainedBytes <= LIMITS.unsentBytes)
|
|
425
|
+
break;
|
|
426
|
+
this.records.delete(id);
|
|
427
|
+
retainedBytes -= item.bytes;
|
|
428
|
+
}
|
|
429
|
+
this.emit();
|
|
430
|
+
}
|
|
431
|
+
receive(value) {
|
|
432
|
+
try {
|
|
433
|
+
if (value !== null && typeof value === 'object' && 'control' in value) {
|
|
434
|
+
const reply = parseControlResponse(value);
|
|
435
|
+
const record = this.records.get(reply.re);
|
|
436
|
+
if (!record || record.envelope.op !== 'hello' || reply.outcome !== 'mismatch')
|
|
437
|
+
throw new Error('Unexpected control reply');
|
|
438
|
+
assertTargetIdentity(this.target, this.verifying ?? reply.identity, reply.identity);
|
|
439
|
+
if (record.response)
|
|
440
|
+
return;
|
|
441
|
+
this.pinned = reply.identity;
|
|
442
|
+
this.connectionState = 'incompatible';
|
|
443
|
+
this.finish(record, failure(reply.re, 'rejected', 'protocol_mismatch', 'Daemon uses an incompatible protocol'));
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
const re = value !== null && typeof value === 'object' && 're' in value ? value.re : undefined;
|
|
447
|
+
const record = typeof re === 'string' ? this.records.get(re) : undefined;
|
|
448
|
+
// Replies are decoded against the operation that produced them, never a union of result shapes.
|
|
449
|
+
if (re !== undefined && !record)
|
|
450
|
+
throw new Error('Uncorrelated response');
|
|
451
|
+
const message = parseServerEnvelope(value, record?.envelope.op);
|
|
452
|
+
if ('re' in message) {
|
|
453
|
+
if (!record)
|
|
454
|
+
throw new Error('Uncorrelated response');
|
|
455
|
+
if (message.outcome === 'accepted' && record.envelope.op === 'attach' &&
|
|
456
|
+
message.result.snapshot.session !== record.envelope.session)
|
|
457
|
+
throw new Error('Attachment session mismatch');
|
|
458
|
+
if (record.response)
|
|
459
|
+
return;
|
|
460
|
+
if (message.outcome !== 'accepted' && message.error.code === 'resync_required' && record.envelope.session &&
|
|
461
|
+
record.localAttachmentId === this.attachments.get(record.envelope.session)?.id)
|
|
462
|
+
this.resync(record.envelope.session, record.envelope.op);
|
|
463
|
+
this.finish(record, message);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if ('interaction' in message) {
|
|
467
|
+
const interaction = message.interaction;
|
|
468
|
+
if (!this.negotiated) {
|
|
469
|
+
const bytes = Buffer.byteLength(JSON.stringify(interaction));
|
|
470
|
+
if (this.connectionState !== 'connecting' || this.queuedInteractions.length >= LIMITS.pageEntries
|
|
471
|
+
|| this.queuedInteractionBytes + bytes > LIMITS.unsentBytes)
|
|
472
|
+
throw new Error('Interaction notification before handshake');
|
|
473
|
+
this.queuedInteractions.push(interaction);
|
|
474
|
+
this.queuedInteractionBytes += bytes;
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
this.acceptInteraction(interaction);
|
|
478
|
+
this.emit();
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if ('presentationEvent' in message) {
|
|
482
|
+
if (!this.negotiated || !this.attachments.has(message.session))
|
|
483
|
+
throw new Error('Unbound presentation event.');
|
|
484
|
+
const event = message.presentationEvent;
|
|
485
|
+
if (!this.negotiated.capabilities?.includes('native.events'))
|
|
486
|
+
throw new Error('Unnegotiated native event.');
|
|
487
|
+
if (event.sequence !== (this.presentationSequences.get(message.session) ?? -1) + 1)
|
|
488
|
+
throw new Error('Native event sequence gap.');
|
|
489
|
+
this.presentationSequences.set(message.session, event.sequence);
|
|
490
|
+
for (const listener of [...this.presentationListeners])
|
|
491
|
+
listener(structuredClone(message));
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (!this.negotiated)
|
|
495
|
+
throw new Error('Session update before handshake');
|
|
496
|
+
const attachment = this.attachments.get(message.session);
|
|
497
|
+
if (!attachment)
|
|
498
|
+
return;
|
|
499
|
+
const current = this.renewRecoveryBudget(attachment);
|
|
500
|
+
this.store({ ...current, state: reduceSession(current.state, { type: 'update', update: message }) });
|
|
501
|
+
this.recover(message.session);
|
|
502
|
+
this.emit();
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
this.lost('invalid_frame', error);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
acceptInteraction(interaction) {
|
|
509
|
+
if (!this.negotiated?.interactionKinds.includes(interaction.request.kind))
|
|
510
|
+
throw new Error('Ineligible interaction notification');
|
|
511
|
+
if (interaction.scope.kind === 'session' && !this.attachments.has(interaction.scope.session))
|
|
512
|
+
throw new Error('Unbound interaction notification');
|
|
513
|
+
if (interaction.scope.kind === 'host' && interaction.scope.recipient !== undefined
|
|
514
|
+
&& interaction.scope.recipient !== this.negotiated.attachmentId)
|
|
515
|
+
throw new Error('Host interaction targets another client');
|
|
516
|
+
if (interaction.state === 'waiting' || interaction.state === 'deferred')
|
|
517
|
+
this.interactionNotifications.set(interaction.id, interaction);
|
|
518
|
+
else
|
|
519
|
+
this.interactionNotifications.delete(interaction.id);
|
|
520
|
+
if (this.interactionNotifications.size > LIMITS.pageEntries)
|
|
521
|
+
throw new Error('Interaction notification limit exceeded');
|
|
522
|
+
}
|
|
523
|
+
async attach(session, policy = {}) {
|
|
524
|
+
if (this.connectionState !== 'ready')
|
|
525
|
+
throw new Error('Connect before attaching');
|
|
526
|
+
if (this.attachments.has(session))
|
|
527
|
+
throw new Error('Session already attached');
|
|
528
|
+
const attachment = { id: randomUUID(), session, ...policy, state: createSessionState(session) };
|
|
529
|
+
this.attachments.set(session, attachment);
|
|
530
|
+
const response = await this.restore(session, 'attach');
|
|
531
|
+
if (response.outcome === 'rejected' && this.attachments.get(session)?.id === attachment.id)
|
|
532
|
+
this.attachments.delete(session);
|
|
533
|
+
this.emit();
|
|
534
|
+
return response;
|
|
535
|
+
}
|
|
536
|
+
async retryAttach(session) {
|
|
537
|
+
if (this.connectionState !== 'ready')
|
|
538
|
+
throw new Error('Connect before retrying an attachment');
|
|
539
|
+
const attachment = this.attachments.get(session);
|
|
540
|
+
if (!attachment || attachment.state.status !== 'blocked')
|
|
541
|
+
throw new Error('No blocked attachment to retry');
|
|
542
|
+
if (attachment.state.recoveryAttempts >= 3)
|
|
543
|
+
throw new Error('Attachment recovery limit reached; restart this client to attach again');
|
|
544
|
+
this.store({ ...attachment, state: reduceSession({ ...attachment.state, status: 'awaiting_snapshot' }, { type: 'recovery_started' }) });
|
|
545
|
+
this.emit();
|
|
546
|
+
return this.restore(session, 'retry');
|
|
547
|
+
}
|
|
548
|
+
async restore(session, trigger) {
|
|
549
|
+
this.presentationSequences.delete(session);
|
|
550
|
+
const attachment = this.attachments.get(session);
|
|
551
|
+
const epoch = this.epoch;
|
|
552
|
+
const bufferGeneration = attachment.state.bufferGeneration;
|
|
553
|
+
if (attachment.state.status === 'disconnected')
|
|
554
|
+
this.attachments.set(session, { ...attachment, state: { ...attachment.state, status: 'awaiting_snapshot' } });
|
|
555
|
+
const started = Date.now();
|
|
556
|
+
const response = await this.exchange('attach', { expected: this.pinned,
|
|
557
|
+
...(attachment.requirePolicy ? { requirePolicy: attachment.requirePolicy } : {}) }, session, undefined, true);
|
|
558
|
+
this.diagnoseAttach(session, trigger, response, Date.now() - started);
|
|
559
|
+
if (this.closed || epoch !== this.epoch || this.attachments.get(session)?.id !== attachment.id)
|
|
560
|
+
return response;
|
|
561
|
+
if (response.outcome === 'accepted') {
|
|
562
|
+
const current = this.attachments.get(session);
|
|
563
|
+
if (current) {
|
|
564
|
+
const state = reduceSession(current.state, { type: 'snapshot', snapshot: response.result.snapshot, bufferGeneration });
|
|
565
|
+
this.store({ ...current, binding: response.result.attachmentId, state, ...(state.status === 'live' ? { liveSince: Date.now() } : {}) }, { snapshot: true });
|
|
566
|
+
}
|
|
567
|
+
this.recover(session);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
const current = this.attachments.get(session);
|
|
571
|
+
if (current)
|
|
572
|
+
this.store({ ...current, state: { ...current.state, status: 'blocked' } }, { failure: { kind: 'attach_failed', outcome: response.outcome, code: response.error.code, message: diagnosticText(response.error.message) } });
|
|
573
|
+
}
|
|
574
|
+
return response;
|
|
575
|
+
}
|
|
576
|
+
async detach(session) {
|
|
577
|
+
const attachment = this.attachments.get(session);
|
|
578
|
+
if (!attachment)
|
|
579
|
+
throw new Error('No attachment');
|
|
580
|
+
this.attachments.delete(session);
|
|
581
|
+
this.presentationSequences.delete(session);
|
|
582
|
+
for (const [id, interaction] of this.interactionNotifications) {
|
|
583
|
+
if (interaction.scope.kind === 'session' && interaction.scope.session === session)
|
|
584
|
+
this.interactionNotifications.delete(id);
|
|
585
|
+
}
|
|
586
|
+
if (!attachment.binding || this.connectionState !== 'ready') {
|
|
587
|
+
this.emit();
|
|
588
|
+
return failure(newRequestId(), 'indeterminate', 'indeterminate', 'Local attachment removed; server binding outcome is unknown');
|
|
589
|
+
}
|
|
590
|
+
const response = await this.exchange('detach', { attachmentId: attachment.binding }, session, undefined, true);
|
|
591
|
+
this.emit();
|
|
592
|
+
return response;
|
|
593
|
+
}
|
|
594
|
+
resync(session, op) {
|
|
595
|
+
const attachment = this.attachments.get(session);
|
|
596
|
+
if (attachment) {
|
|
597
|
+
const current = this.renewRecoveryBudget(attachment);
|
|
598
|
+
this.store({ ...current, state: reduceSession(current.state, { type: 'resync', cause: 'daemon_resync' }) }, { op });
|
|
599
|
+
}
|
|
600
|
+
this.recover(session);
|
|
601
|
+
}
|
|
602
|
+
/** Updates an attachment and reports transitions into recovery or a blocked state, keeping why it blocked. A snapshot that cannot go live is a new recovery. */
|
|
603
|
+
store(next, detail = {}) {
|
|
604
|
+
const previous = this.attachments.get(next.session)?.state.status;
|
|
605
|
+
const { state } = next;
|
|
606
|
+
if (state.status === 'recovering' && (previous !== 'recovering' || detail.snapshot) && state.recoveryCause) {
|
|
607
|
+
this.diagnose({ event: 'attachment.recovering', session: next.session, cause: state.recoveryCause, attempts: state.recoveryAttempts, ...(detail.op ? { op: detail.op } : {}) });
|
|
608
|
+
}
|
|
609
|
+
if (state.status === 'blocked' && previous !== 'blocked') {
|
|
610
|
+
const reason = detail.failure ?? { kind: 'recovery_limit', ...(state.recoveryCause ? { cause: state.recoveryCause } : {}) };
|
|
611
|
+
this.diagnose({ event: 'attachment.blocked', session: next.session, attempts: state.recoveryAttempts, reason });
|
|
612
|
+
this.attachments.set(next.session, { ...next, blocked: reason });
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
this.attachments.set(next.session, next);
|
|
616
|
+
}
|
|
617
|
+
diagnoseAttach(session, trigger, response, durationMs) {
|
|
618
|
+
if (!this.options.diagnostics)
|
|
619
|
+
return;
|
|
620
|
+
if (response.outcome !== 'accepted') {
|
|
621
|
+
this.diagnose({ event: 'attachment.attached', session, trigger, outcome: response.outcome, durationMs, code: response.error.code, message: diagnosticText(response.error.message) });
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const { snapshot } = response.result;
|
|
625
|
+
this.diagnose({ event: 'attachment.attached', session, trigger, outcome: 'accepted', durationMs, revision: snapshot.revision,
|
|
626
|
+
snapshotBytes: Buffer.byteLength(JSON.stringify(snapshot)),
|
|
627
|
+
counts: { history: snapshot.history.entries.length, tools: snapshot.tools.length, processes: snapshot.processes.length, children: snapshot.children.length,
|
|
628
|
+
interactions: snapshot.interactions.length, presentation: snapshot.presentation.length, activeStreams: snapshot.activeStreams.length } });
|
|
629
|
+
}
|
|
630
|
+
diagnose(event) {
|
|
631
|
+
try {
|
|
632
|
+
this.options.diagnostics?.(event);
|
|
633
|
+
}
|
|
634
|
+
catch { /* Diagnostics never affect the protocol. */ }
|
|
635
|
+
}
|
|
636
|
+
/** Like connection backoff, the recovery budget renews only after the attachment stayed live longer than the longest reconnect delay, so a flapping session cannot resnapshot forever. */
|
|
637
|
+
renewRecoveryBudget(attachment) {
|
|
638
|
+
const { state, liveSince } = attachment;
|
|
639
|
+
if (state.status !== 'live' || state.recoveryAttempts === 0 || liveSince === undefined || Date.now() - liveSince < this.maxDelay)
|
|
640
|
+
return attachment;
|
|
641
|
+
return { ...attachment, state: { ...state, recoveryAttempts: 0 } };
|
|
642
|
+
}
|
|
643
|
+
recover(session) {
|
|
644
|
+
const attachment = this.attachments.get(session);
|
|
645
|
+
if (!attachment || attachment.state.status !== 'recovering' || this.recovering.has(session) || !this.transport)
|
|
646
|
+
return;
|
|
647
|
+
const state = reduceSession(attachment.state, { type: 'recovery_started' });
|
|
648
|
+
this.store({ ...attachment, state });
|
|
649
|
+
if (state.status === 'blocked')
|
|
650
|
+
return;
|
|
651
|
+
this.recovering.add(session);
|
|
652
|
+
const epoch = this.epoch;
|
|
653
|
+
void this.restore(session, 'recovery').catch(error => {
|
|
654
|
+
const current = this.attachments.get(session);
|
|
655
|
+
if (!this.closed && epoch === this.epoch && current?.id === attachment.id)
|
|
656
|
+
this.store({ ...current, state: { ...current.state, status: 'blocked' } }, { failure: { kind: 'attach_failed', outcome: 'error', message: diagnosticText(error) } });
|
|
657
|
+
}).finally(() => { this.recovering.delete(session); this.recover(session); this.emit(); });
|
|
658
|
+
}
|
|
659
|
+
lost(reason, error) {
|
|
660
|
+
if (this.closed)
|
|
661
|
+
return;
|
|
662
|
+
this.diagnose({ event: 'connection.lost', reason, ...(error === undefined ? {} : { error: diagnosticText(error) }) });
|
|
663
|
+
const wasReady = this.connectionState === 'ready';
|
|
664
|
+
++this.epoch;
|
|
665
|
+
const transport = this.transport;
|
|
666
|
+
this.transport = undefined;
|
|
667
|
+
transport?.close();
|
|
668
|
+
this.connectionState = reason === 'invalid_frame' ? 'blocked' : 'disconnected';
|
|
669
|
+
this.interactionNotifications.clear();
|
|
670
|
+
this.queuedInteractions = [];
|
|
671
|
+
this.queuedInteractionBytes = 0;
|
|
672
|
+
for (const [session, attachment] of this.attachments)
|
|
673
|
+
this.attachments.set(session, { ...attachment, state: reduceSession(attachment.state, { type: 'disconnected' }) });
|
|
674
|
+
for (const record of this.records.values()) {
|
|
675
|
+
clearTimeout(record.timer);
|
|
676
|
+
record.timer = undefined;
|
|
677
|
+
if (!record.response && (record.internal || record.envelope.op === 'remote.configure' && record.envelope.params.action === 'login')) {
|
|
678
|
+
this.finish(record, failure(record.envelope.id, 'indeterminate', 'unavailable', record.internal ? 'Connection lost'
|
|
679
|
+
: 'Remote login reply was lost. Check /remote status or run /remote login again.'));
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
// Backoff restarts only after a connection that stayed up longer than the longest delay, so a flapping daemon is not hammered.
|
|
683
|
+
if (wasReady && Date.now() - this.readyAt >= this.maxDelay)
|
|
684
|
+
this.reconnectCount = 0;
|
|
685
|
+
if (!wasReady || reason === 'invalid_frame' || !this.retryLater())
|
|
686
|
+
this.settleOutstanding('Daemon connection lost; execution may still be running');
|
|
687
|
+
this.emit();
|
|
688
|
+
}
|
|
689
|
+
/** Schedules the next automatic attempt; outstanding requests stay pending only until an attempt fails. */
|
|
690
|
+
retryLater() {
|
|
691
|
+
if (this.closed || !this.established || this.connectionState === 'incompatible' || this.reconnectCount >= this.reconnectLimit)
|
|
692
|
+
return false;
|
|
693
|
+
if (this.reconnectTimer)
|
|
694
|
+
return true;
|
|
695
|
+
this.connectionState = 'disconnected';
|
|
696
|
+
const delay = Math.min(this.maxDelay, this.delay * 2 ** Math.min(this.reconnectCount, 30) * (0.9 + Math.random() * 0.2));
|
|
697
|
+
this.reconnectAt = Date.now() + delay;
|
|
698
|
+
this.reconnectTimer = setTimeout(() => {
|
|
699
|
+
this.reconnectTimer = undefined;
|
|
700
|
+
this.reconnectAt = undefined;
|
|
701
|
+
++this.reconnectCount;
|
|
702
|
+
void this.connectShared(false).catch(() => { this.retryLater(); this.emit(); });
|
|
703
|
+
}, delay);
|
|
704
|
+
this.reconnectTimer.unref?.();
|
|
705
|
+
this.emit();
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
cancelReconnect() { clearTimeout(this.reconnectTimer); this.reconnectTimer = undefined; this.reconnectAt = undefined; }
|
|
709
|
+
settleOutstanding(message) {
|
|
710
|
+
for (const record of this.records.values())
|
|
711
|
+
if (!record.response)
|
|
712
|
+
this.finish(record, failure(record.envelope.id, record.attempts ? 'indeterminate' : 'rejected', 'indeterminate', message));
|
|
713
|
+
}
|
|
714
|
+
async control(op, mode) {
|
|
715
|
+
if (this.closed)
|
|
716
|
+
throw new Error('Client is closed');
|
|
717
|
+
if (!this.pinned)
|
|
718
|
+
throw new Error('Control requires a verified daemon identity');
|
|
719
|
+
const id = op === 'host.status' ? randomUUID() : newRequestId();
|
|
720
|
+
const request = parseControlRequest({ control: CONTROL_VERSION, id, op, params: { expected: this.pinned, ...(mode ? { mode } : {}) } });
|
|
721
|
+
let transport;
|
|
722
|
+
let timer;
|
|
723
|
+
let onClose = () => { };
|
|
724
|
+
try {
|
|
725
|
+
return await new Promise((resolve, reject) => {
|
|
726
|
+
let settled = false;
|
|
727
|
+
const fail = () => {
|
|
728
|
+
if (!settled) {
|
|
729
|
+
settled = true;
|
|
730
|
+
clearTimeout(timer);
|
|
731
|
+
transport?.close();
|
|
732
|
+
reject(new Error('Control outcome is indeterminate'));
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
onClose = fail;
|
|
736
|
+
this.lifetime.signal.addEventListener('abort', onClose, { once: true });
|
|
737
|
+
timer = setTimeout(fail, this.timeout);
|
|
738
|
+
void this.connectTransport({ frame: raw => {
|
|
739
|
+
if (settled)
|
|
740
|
+
return;
|
|
741
|
+
try {
|
|
742
|
+
const response = parseControlResponse(raw);
|
|
743
|
+
assertTargetIdentity(this.target, this.pinned, response.identity);
|
|
744
|
+
if (response.re !== id)
|
|
745
|
+
throw new Error('Control correlation mismatch');
|
|
746
|
+
settled = true;
|
|
747
|
+
clearTimeout(timer);
|
|
748
|
+
resolve(response);
|
|
749
|
+
}
|
|
750
|
+
catch {
|
|
751
|
+
fail();
|
|
752
|
+
}
|
|
753
|
+
}, closed: fail }).then(connection => {
|
|
754
|
+
transport = connection;
|
|
755
|
+
if (settled)
|
|
756
|
+
connection.close();
|
|
757
|
+
else {
|
|
758
|
+
try {
|
|
759
|
+
connection.send(request);
|
|
760
|
+
}
|
|
761
|
+
catch {
|
|
762
|
+
fail();
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}, fail);
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
finally {
|
|
769
|
+
this.lifetime.signal.removeEventListener('abort', onClose);
|
|
770
|
+
clearTimeout(timer);
|
|
771
|
+
transport?.close();
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
close() {
|
|
775
|
+
this.closed = true;
|
|
776
|
+
this.connectionState = 'closed';
|
|
777
|
+
++this.epoch;
|
|
778
|
+
this.lifetime.abort();
|
|
779
|
+
this.interactionNotifications.clear();
|
|
780
|
+
this.presentationSequences.clear();
|
|
781
|
+
this.presentationListeners.clear();
|
|
782
|
+
this.queuedInteractions = [];
|
|
783
|
+
this.queuedInteractionBytes = 0;
|
|
784
|
+
this.cancelReconnect();
|
|
785
|
+
this.transport?.close();
|
|
786
|
+
this.transport = undefined;
|
|
787
|
+
this.settleOutstanding('Client detached; execution may still be running');
|
|
788
|
+
for (const [session, attachment] of this.attachments)
|
|
789
|
+
this.attachments.set(session, { ...attachment, state: reduceSession(attachment.state, { type: 'disconnected' }) });
|
|
790
|
+
this.emit();
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
/** Freezes children before parents, so a frozen object's descendants are frozen and the unchanged parts shared by successive states are skipped. */
|
|
794
|
+
function deepFreeze(value) {
|
|
795
|
+
if (value === null || typeof value !== 'object' || Object.isFrozen(value))
|
|
796
|
+
return;
|
|
797
|
+
for (const child of Object.values(value))
|
|
798
|
+
deepFreeze(child);
|
|
799
|
+
Object.freeze(value);
|
|
800
|
+
}
|
|
801
|
+
function bounded(value, min, max) {
|
|
802
|
+
if (!Number.isInteger(value) || value < min || value > max)
|
|
803
|
+
throw new Error('Invalid client limit');
|
|
804
|
+
return value;
|
|
805
|
+
}
|
|
806
|
+
//# sourceMappingURL=client.js.map
|