@poolzin/pool-bot 2026.2.25 → 2026.2.26
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/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +7 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bedrock-discovery.js +3 -1
- package/dist/agents/byteplus-models.js +97 -0
- package/dist/agents/chutes-oauth.js +1 -0
- package/dist/agents/cli-runner/helpers.js +4 -0
- package/dist/agents/compaction.js +41 -14
- package/dist/agents/doubao-models.js +121 -0
- package/dist/agents/failover-error.js +2 -0
- package/dist/agents/huggingface-models.js +5 -3
- package/dist/agents/live-model-filter.js +5 -0
- package/dist/agents/minimax-vlm.js +10 -8
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-catalog.js +3 -1
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +93 -11
- package/dist/agents/ollama-stream.js +117 -4
- package/dist/agents/opencode-zen-models.js +22 -11
- package/dist/agents/pi-embedded-helpers/errors.js +55 -33
- package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
- package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +29 -7
- package/dist/agents/pi-embedded-runner/extensions.js +28 -26
- package/dist/agents/pi-embedded-runner/google.js +20 -8
- package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
- package/dist/agents/pi-embedded-runner/run.js +71 -12
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
- package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
- package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
- package/dist/agents/pi-embedded-runner/thinking.js +42 -0
- package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
- package/dist/agents/pi-embedded-runner/utils.js +7 -10
- package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
- package/dist/agents/pi-embedded-subscribe.js +9 -4
- package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
- package/dist/agents/pi-embedded-utils.js +3 -0
- package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
- package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
- package/dist/agents/pi-settings.js +40 -0
- package/dist/agents/pi-tools.policy.js +2 -1
- package/dist/agents/provider/config-loader.js +1 -1
- package/dist/agents/sandbox/browser.js +170 -33
- package/dist/agents/sandbox/config-hash.js +14 -27
- package/dist/agents/sandbox/config.js +21 -2
- package/dist/agents/sandbox/constants.js +2 -0
- package/dist/agents/sandbox/docker.js +16 -2
- package/dist/agents/sandbox/novnc-auth.js +62 -0
- package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
- package/dist/agents/sandbox/shared.js +10 -6
- package/dist/agents/sandbox-paths.js +24 -11
- package/dist/agents/schema/clean-for-gemini.js +132 -85
- package/dist/agents/session-slug.js +10 -5
- package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
- package/dist/agents/session-tool-result-guard.js +3 -1
- package/dist/agents/session-transcript-repair.js +40 -6
- package/dist/agents/skills/bundled-dir.js +19 -5
- package/dist/agents/skills/env-overrides.js +124 -43
- package/dist/agents/skills/frontmatter.js +6 -6
- package/dist/agents/skills/plugin-skills.js +14 -7
- package/dist/agents/skills/workspace.js +1 -0
- package/dist/agents/subagent-announce.js +251 -49
- package/dist/agents/subagent-lifecycle-events.js +19 -0
- package/dist/agents/subagent-registry-cleanup.js +31 -0
- package/dist/agents/subagent-registry-completion.js +68 -0
- package/dist/agents/subagent-registry-queries.js +117 -0
- package/dist/agents/subagent-registry-state.js +46 -0
- package/dist/agents/subagent-registry.js +252 -221
- package/dist/agents/subagent-registry.store.js +1 -0
- package/dist/agents/subagent-registry.types.js +1 -0
- package/dist/agents/subagent-spawn.js +195 -7
- package/dist/agents/system-prompt.js +22 -6
- package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
- package/dist/agents/test-helpers/fast-core-tools.js +1 -17
- package/dist/agents/timeout.js +18 -6
- package/dist/agents/tool-call-id.js +1 -1
- package/dist/agents/tool-display-common.js +162 -29
- package/dist/agents/tool-images.js +82 -9
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +2 -2
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-send-helpers.js +12 -6
- package/dist/agents/tools/sessions-spawn-tool.js +8 -2
- package/dist/agents/tools/subagents-tool.js +2 -1
- package/dist/agents/tools/whatsapp-actions.js +10 -2
- package/dist/agents/tools/whatsapp-target-auth.js +18 -0
- package/dist/agents/transcript-policy.js +22 -8
- package/dist/agents/venice-models.js +11 -3
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +4 -3
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
- package/dist/auto-reply/reply/bash-command.js +41 -39
- package/dist/auto-reply/reply/command-gates.js +25 -0
- package/dist/auto-reply/reply/commands-allowlist.js +111 -72
- package/dist/auto-reply/reply/commands-bash.js +6 -5
- package/dist/auto-reply/reply/commands-config.js +30 -28
- package/dist/auto-reply/reply/commands-core.js +2 -1
- package/dist/auto-reply/reply/commands-info.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +65 -14
- package/dist/auto-reply/reply/commands-session.js +237 -82
- package/dist/auto-reply/reply/commands-setunset.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
- package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
- package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
- package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
- package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
- package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
- package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
- package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
- package/dist/auto-reply/reply/commands-subagents.js +51 -587
- package/dist/auto-reply/reply/commands-tts.js +10 -5
- package/dist/auto-reply/reply/config-value.js +10 -5
- package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
- package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
- package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
- package/dist/auto-reply/reply/followup-runner.js +1 -0
- package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
- package/dist/auto-reply/reply/get-reply-directives.js +17 -28
- package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
- package/dist/auto-reply/reply/get-reply.js +71 -12
- package/dist/auto-reply/reply/model-selection.js +80 -39
- package/dist/auto-reply/reply/queue/enqueue.js +10 -5
- package/dist/auto-reply/reply/queue/state.js +13 -12
- package/dist/auto-reply/reply/reply-payloads.js +67 -36
- package/dist/auto-reply/reply/reply-reference.js +9 -8
- package/dist/auto-reply/reply/route-reply.js +15 -8
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
- package/dist/auto-reply/reply/session.js +22 -6
- package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
- package/dist/auto-reply/reply/subagents-utils.js +56 -30
- package/dist/auto-reply/reply/typing.js +46 -21
- package/dist/auto-reply/send-policy.js +14 -7
- package/dist/auto-reply/status.js +140 -16
- package/dist/auto-reply/templating.js +10 -5
- package/dist/auto-reply/thinking.js +7 -16
- package/dist/auto-reply/tokens.js +21 -5
- package/dist/browser/bridge-server.js +36 -20
- package/dist/browser/cdp.helpers.js +7 -14
- package/dist/browser/cdp.js +35 -15
- package/dist/browser/chrome.profile-decoration.js +7 -4
- package/dist/browser/config.js +4 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +9 -1
- package/dist/browser/paths.js +77 -0
- package/dist/browser/profiles.js +13 -8
- package/dist/browser/pw-ai-module.js +10 -5
- package/dist/browser/pw-session.js +76 -39
- package/dist/browser/pw-tools-core.interactions.js +14 -7
- package/dist/browser/pw-tools-core.state.js +12 -6
- package/dist/browser/routes/agent.act.js +2 -2
- package/dist/browser/server-context.js +7 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +2 -1
- package/dist/channels/allowlists/resolve-utils.js +43 -19
- package/dist/channels/channel-config.js +14 -7
- package/dist/channels/draft-stream-loop.js +7 -0
- package/dist/channels/model-overrides.js +82 -0
- package/dist/channels/plugins/normalize/imessage.js +14 -7
- package/dist/channels/plugins/normalize/slack.js +10 -5
- package/dist/channels/plugins/normalize/telegram.js +14 -7
- package/dist/channels/plugins/outbound/discord.js +80 -8
- package/dist/channels/plugins/outbound/signal.js +11 -11
- package/dist/channels/plugins/setup-helpers.js +10 -5
- package/dist/channels/sender-label.js +14 -7
- package/dist/channels/session.js +4 -2
- package/dist/channels/status-reactions.js +297 -0
- package/dist/cli/banner.js +1 -1
- package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
- package/dist/cli/cli-name.js +11 -11
- package/dist/cli/cli-utils.js +13 -3
- package/dist/cli/command-format.js +1 -1
- package/dist/cli/config-cli.js +1 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
- package/dist/cli/daemon-cli/lifecycle.js +64 -2
- package/dist/cli/daemon-cli/restart-health.js +126 -0
- package/dist/cli/daemon-cli/status.gather.js +9 -13
- package/dist/cli/daemon-cli/status.print.js +2 -10
- package/dist/cli/deps.js +27 -22
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-media-utils.js +7 -2
- package/dist/cli/outbound-send-deps.js +2 -9
- package/dist/cli/outbound-send-mapping.js +11 -0
- package/dist/cli/pairing-cli.js +40 -14
- package/dist/cli/plugins-cli.js +34 -41
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/command-registry.js +2 -11
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/preaction.js +13 -9
- package/dist/cli/program/register.configure.js +3 -18
- package/dist/cli/program/register.maintenance.js +2 -2
- package/dist/cli/program/register.onboard.js +2 -0
- package/dist/cli/program/register.status-health-sessions.js +16 -17
- package/dist/cli/program/register.subclis.js +93 -52
- package/dist/cli/route.js +11 -7
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/update-cli/shared.js +22 -9
- package/dist/cli/update-cli/update-command.js +89 -14
- package/dist/cli/update-cli/wizard.js +6 -12
- package/dist/commands/agent/run-context.js +18 -5
- package/dist/commands/agent/session-store.js +17 -4
- package/dist/commands/agent.js +22 -2
- package/dist/commands/agents.bindings.js +14 -7
- package/dist/commands/agents.commands.add.js +13 -9
- package/dist/commands/agents.commands.identity.js +12 -6
- package/dist/commands/agents.commands.list.js +11 -6
- package/dist/commands/agents.config.js +8 -10
- package/dist/commands/agents.providers.js +12 -6
- package/dist/commands/auth-choice-options.js +103 -75
- package/dist/commands/auth-choice.apply.byteplus.js +55 -0
- package/dist/commands/auth-choice.apply.js +4 -0
- package/dist/commands/auth-choice.apply.minimax.js +61 -13
- package/dist/commands/auth-choice.apply.openai.js +3 -1
- package/dist/commands/auth-choice.apply.volcengine.js +55 -0
- package/dist/commands/auth-choice.preferred-provider.js +2 -0
- package/dist/commands/channels/remove.js +13 -6
- package/dist/commands/channels/shared.js +4 -14
- package/dist/commands/configure.commands.js +14 -0
- package/dist/commands/configure.gateway.js +2 -4
- package/dist/commands/configure.js +1 -1
- package/dist/commands/configure.shared.js +11 -0
- package/dist/commands/daemon-install-helpers.js +2 -2
- package/dist/commands/dashboard.js +12 -10
- package/dist/commands/docs.js +14 -8
- package/dist/commands/doctor-config-flow.js +11 -9
- package/dist/commands/doctor-legacy-config.js +281 -0
- package/dist/commands/doctor-state-integrity.js +99 -23
- package/dist/commands/doctor-update.js +12 -9
- package/dist/commands/models/list.list-command.js +7 -5
- package/dist/commands/models/set-image.js +2 -21
- package/dist/commands/node-daemon-install-helpers.js +10 -8
- package/dist/commands/onboard-auth.config-minimax.js +54 -80
- package/dist/commands/onboard-auth.config-opencode.js +2 -18
- package/dist/commands/onboard-auth.credentials.js +90 -13
- package/dist/commands/onboard-auth.js +1 -1
- package/dist/commands/onboard-auth.models.js +6 -5
- package/dist/commands/onboard-hooks.js +1 -1
- package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
- package/dist/commands/onboard-provider-auth-flags.js +14 -0
- package/dist/commands/onboard-remote.js +14 -7
- package/dist/commands/onboard.js +11 -13
- package/dist/commands/sandbox-display.js +6 -5
- package/dist/commands/status-all/diagnosis.js +14 -10
- package/dist/commands/status-all/format.js +1 -0
- package/dist/commands/status.gateway-probe.js +1 -16
- package/dist/commands/systemd-linger.js +12 -6
- package/dist/config/agent-limits.js +2 -0
- package/dist/config/commands.js +30 -16
- package/dist/config/config-paths.js +9 -11
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-vars.js +37 -8
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +97 -12
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +4 -0
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.labels.js +38 -6
- package/dist/config/sessions/delivery-info.js +10 -3
- package/dist/config/sessions/main-session.js +10 -5
- package/dist/config/sessions/session-file.js +33 -0
- package/dist/config/sessions/session-key.js +10 -5
- package/dist/config/sessions/store.js +1 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.js +148 -13
- package/dist/config/zod-schema.providers-core.js +78 -4
- package/dist/config/zod-schema.providers.js +6 -1
- package/dist/config/zod-schema.session.js +41 -2
- package/dist/cron/run-log.js +3 -0
- package/dist/cron/schedule.js +21 -10
- package/dist/cron/service/ops.js +35 -21
- package/dist/cron/service/timer.js +116 -16
- package/dist/cron/stagger.js +3 -1
- package/dist/discord/api.js +12 -6
- package/dist/discord/draft-chunking.js +22 -0
- package/dist/discord/draft-stream.js +124 -0
- package/dist/discord/monitor/agent-components.js +1 -1
- package/dist/discord/monitor/commands.js +5 -0
- package/dist/discord/monitor/gateway-plugin.js +2 -1
- package/dist/discord/monitor/listeners.js +37 -27
- package/dist/discord/monitor/message-handler.js +4 -1
- package/dist/discord/monitor/message-handler.preflight.js +65 -8
- package/dist/discord/monitor/message-handler.process.js +246 -217
- package/dist/discord/monitor/message-utils.js +143 -6
- package/dist/discord/monitor/model-picker-preferences.js +143 -0
- package/dist/discord/monitor/model-picker.js +651 -0
- package/dist/discord/monitor/native-command.js +573 -16
- package/dist/discord/monitor/provider.allowlist.js +223 -0
- package/dist/discord/monitor/provider.js +275 -347
- package/dist/discord/monitor/provider.lifecycle.js +100 -0
- package/dist/discord/monitor/reply-delivery.js +123 -16
- package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
- package/dist/discord/monitor/thread-bindings.js +4 -0
- package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
- package/dist/discord/monitor/thread-bindings.manager.js +423 -0
- package/dist/discord/monitor/thread-bindings.messages.js +55 -0
- package/dist/discord/monitor/thread-bindings.state.js +358 -0
- package/dist/discord/monitor/thread-bindings.types.js +6 -0
- package/dist/discord/resolve-users.js +33 -21
- package/dist/discord/send.channels.js +15 -0
- package/dist/discord/send.js +3 -2
- package/dist/discord/send.outbound.js +82 -26
- package/dist/discord/send.permissions.js +83 -30
- package/dist/discord/send.reactions.js +8 -4
- package/dist/discord/token.js +10 -5
- package/dist/discord/voice/command.js +263 -0
- package/dist/discord/voice/manager.js +531 -0
- package/dist/gateway/auth.js +34 -10
- package/dist/gateway/call.js +4 -16
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/net.js +54 -12
- package/dist/gateway/node-invoke-system-run-approval.js +14 -35
- package/dist/gateway/node-registry.js +10 -5
- package/dist/gateway/openai-http.js +1 -0
- package/dist/gateway/openresponses-http.js +1 -0
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/protocol/index.js +4 -3
- package/dist/gateway/protocol/schema/cron.js +1 -0
- package/dist/gateway/protocol/schema/devices.js +1 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/role-policy.js +17 -0
- package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
- package/dist/gateway/server/ws-connection/message-handler.js +175 -148
- package/dist/gateway/server-chat.js +83 -25
- package/dist/gateway/server-constants.js +10 -9
- package/dist/gateway/server-cron.js +1 -0
- package/dist/gateway/server-http.js +16 -7
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/chat.js +10 -6
- package/dist/gateway/server-methods/config.js +12 -14
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- package/dist/gateway/server-methods/sessions.js +64 -8
- package/dist/gateway/server-methods/usage.js +162 -75
- package/dist/gateway/server-node-events.js +29 -0
- package/dist/gateway/server-runtime-config.js +34 -13
- package/dist/gateway/server-startup-memory.js +17 -11
- package/dist/gateway/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- package/dist/gateway/test-helpers.openai-mock.js +14 -7
- package/dist/gateway/tools-invoke-http.js +21 -10
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
- package/dist/hooks/bundled/command-logger/handler.js +7 -2
- package/dist/hooks/bundled/session-memory/handler.js +6 -5
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher.js +11 -6
- package/dist/hooks/internal-hooks.js +11 -1
- package/dist/hooks/llm-slug-generator.js +4 -1
- package/dist/hooks/workspace.js +47 -17
- package/dist/imessage/accounts.js +9 -20
- package/dist/imessage/monitor/inbound-processing.js +2 -1
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +108 -29
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +122 -0
- package/dist/infra/exec-approvals-analysis.js +34 -3
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +53 -45
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- package/dist/infra/heartbeat-wake.js +6 -12
- package/dist/infra/host-env-security-policy.json +19 -0
- package/dist/infra/host-env-security.js +66 -0
- package/dist/infra/net/ssrf.js +131 -38
- package/dist/infra/outbound/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-selection.js +12 -6
- package/dist/infra/outbound/envelope.js +1 -1
- package/dist/infra/outbound/format.js +12 -6
- package/dist/infra/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/provider-usage.fetch.codex.js +7 -15
- package/dist/infra/provider-usage.fetch.gemini.js +14 -11
- package/dist/infra/provider-usage.fetch.shared.js +30 -1
- package/dist/infra/provider-usage.fetch.zai.js +10 -9
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/session-cost-usage.js +107 -59
- package/dist/infra/session-maintenance-warning.js +3 -1
- package/dist/infra/shell-env.js +98 -34
- package/dist/infra/ssh-config.js +12 -6
- package/dist/infra/system-run-command.js +49 -4
- package/dist/infra/update-channels.js +10 -5
- package/dist/line/accounts.js +5 -7
- package/dist/line/bot-access.js +8 -20
- package/dist/line/bot-handlers.js +3 -1
- package/dist/link-understanding/detect.js +15 -7
- package/dist/media/constants.js +15 -6
- package/dist/media/image-ops.js +7 -0
- package/dist/media/local-roots.js +3 -2
- package/dist/media-understanding/apply.js +4 -1
- package/dist/media-understanding/concurrency.js +8 -20
- package/dist/memory/backend-config.js +45 -6
- package/dist/memory/embeddings.js +10 -4
- package/dist/memory/fs-utils.js +23 -0
- package/dist/memory/manager-search.js +12 -6
- package/dist/memory/manager-sync-ops.js +12 -2
- package/dist/memory/qmd-manager.js +466 -53
- package/dist/memory/query-expansion.js +167 -3
- package/dist/memory/status-format.js +10 -5
- package/dist/memory/sync-memory-files.js +1 -1
- package/dist/node-host/invoke-system-run.js +281 -0
- package/dist/node-host/invoke.js +55 -337
- package/dist/pairing/pairing-store.js +22 -0
- package/dist/plugin-sdk/allow-from.js +1 -1
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/index.js +6 -3
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- package/dist/plugins/runtime.js +3 -17
- package/dist/plugins/update.js +78 -12
- package/dist/process/spawn-utils.js +14 -7
- package/dist/providers/github-copilot-token.js +11 -6
- package/dist/providers/qwen-portal-oauth.js +14 -6
- package/dist/routing/account-id.js +30 -0
- package/dist/routing/resolve-route.js +3 -7
- package/dist/routing/session-key.js +2 -16
- package/dist/security/audit-channel.js +93 -2
- package/dist/security/audit-extra.async.js +159 -5
- package/dist/security/audit-extra.js +1 -1
- package/dist/security/audit-extra.sync.js +85 -6
- package/dist/security/audit.js +40 -4
- package/dist/security/dm-policy-shared.js +44 -0
- package/dist/security/external-content.js +26 -6
- package/dist/shared/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +8 -3
- package/dist/signal/accounts.js +7 -20
- package/dist/signal/monitor/event-handler.js +3 -1
- package/dist/slack/accounts.js +6 -19
- package/dist/slack/actions.js +11 -3
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/replies.js +15 -7
- package/dist/slack/monitor/slash.js +22 -13
- package/dist/slack/resolve-channels.js +10 -5
- package/dist/slack/send.js +102 -12
- package/dist/slack/stream-mode.js +10 -0
- package/dist/slack/streaming.js +4 -2
- package/dist/telegram/accounts.js +19 -14
- package/dist/telegram/bot/helpers.js +3 -5
- package/dist/telegram/bot-access.js +35 -36
- package/dist/telegram/bot-handlers.js +120 -148
- package/dist/telegram/bot-message-context.js +68 -9
- package/dist/telegram/bot-message-dispatch.js +155 -90
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +14 -1
- package/dist/telegram/inline-buttons.js +5 -15
- package/dist/telegram/monitor.js +11 -7
- package/dist/telegram/network-config.js +19 -7
- package/dist/telegram/send.js +3 -2
- package/dist/telegram/sent-message-cache.js +5 -6
- package/dist/telegram/status-reaction-variants.js +208 -0
- package/dist/telegram/sticker-cache.js +11 -9
- package/dist/terminal/theme.js +12 -12
- package/dist/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +41 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +58 -6
- package/dist/utils/account-id.js +2 -4
- package/dist/utils/boolean.js +10 -5
- package/dist/utils/directive-tags.js +11 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/web/auto-reply/deliver-reply.js +8 -4
- package/dist/web/auto-reply/mentions.js +10 -5
- package/dist/web/auto-reply/monitor/group-members.js +14 -7
- package/dist/web/auto-reply/monitor/process-message.js +45 -24
- package/dist/web/inbound/access-control.js +5 -2
- package/dist/web/login-qr.js +12 -6
- package/dist/web/media.js +123 -16
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/package.json +1 -1
package/dist/gateway/client.js
CHANGED
|
@@ -2,11 +2,13 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { WebSocket } from "ws";
|
|
3
3
|
import { clearDeviceAuthToken, loadDeviceAuthToken, storeDeviceAuthToken, } from "../infra/device-auth-store.js";
|
|
4
4
|
import { loadOrCreateDeviceIdentity, publicKeyRawBase64UrlFromPem, signDevicePayload, } from "../infra/device-identity.js";
|
|
5
|
+
import { clearDevicePairing } from "../infra/device-pairing.js";
|
|
5
6
|
import { normalizeFingerprint } from "../infra/tls/fingerprint.js";
|
|
6
7
|
import { rawDataToString } from "../infra/ws.js";
|
|
7
8
|
import { logDebug, logError } from "../logger.js";
|
|
8
9
|
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES, } from "../utils/message-channel.js";
|
|
9
10
|
import { buildDeviceAuthPayload } from "./device-auth.js";
|
|
11
|
+
import { isSecureWebSocketUrl } from "./net.js";
|
|
10
12
|
import { PROTOCOL_VERSION, validateEventFrame, validateRequestFrame, validateResponseFrame, } from "./protocol/index.js";
|
|
11
13
|
export const GATEWAY_CLOSE_CODE_HINTS = {
|
|
12
14
|
1000: "normal closure",
|
|
@@ -46,6 +48,24 @@ export class GatewayClient {
|
|
|
46
48
|
this.opts.onConnectError?.(new Error("gateway tls fingerprint requires wss:// gateway url"));
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
51
|
+
// Security check: block ALL plaintext ws:// to non-loopback addresses (CWE-319, CVSS 9.8)
|
|
52
|
+
// This protects both credentials AND chat/conversation data from MITM attacks.
|
|
53
|
+
// Device tokens may be loaded later in sendConnect(), so we block regardless of hasCredentials.
|
|
54
|
+
if (!isSecureWebSocketUrl(url)) {
|
|
55
|
+
// Safe hostname extraction - avoid throwing on malformed URLs in error path
|
|
56
|
+
let displayHost = url;
|
|
57
|
+
try {
|
|
58
|
+
displayHost = new URL(url).hostname || url;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Use raw URL if parsing fails
|
|
62
|
+
}
|
|
63
|
+
const error = new Error(`SECURITY ERROR: Cannot connect to "${displayHost}" over plaintext ws://. ` +
|
|
64
|
+
"Both credentials and chat data would be exposed to network interception. " +
|
|
65
|
+
"Use wss:// for the gateway URL, or connect via SSH tunnel to localhost.");
|
|
66
|
+
this.opts.onConnectError?.(error);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
49
69
|
// Allow node screen snapshots and other large responses.
|
|
50
70
|
const wsOptions = {
|
|
51
71
|
maxPayload: 25 * 1024 * 1024,
|
|
@@ -87,17 +107,21 @@ export class GatewayClient {
|
|
|
87
107
|
this.ws.on("close", (code, reason) => {
|
|
88
108
|
const reasonText = rawDataToString(reason);
|
|
89
109
|
this.ws = null;
|
|
90
|
-
// If closed due to device token mismatch, clear the stored token so next attempt can get a fresh one
|
|
110
|
+
// If closed due to device token mismatch, clear the stored token and pairing so next attempt can get a fresh one
|
|
91
111
|
if (code === 1008 &&
|
|
92
112
|
reasonText.toLowerCase().includes("device token mismatch") &&
|
|
93
113
|
this.opts.deviceIdentity) {
|
|
114
|
+
const deviceId = this.opts.deviceIdentity.deviceId;
|
|
94
115
|
const role = this.opts.role ?? "operator";
|
|
95
116
|
try {
|
|
96
|
-
clearDeviceAuthToken({ deviceId
|
|
97
|
-
|
|
117
|
+
clearDeviceAuthToken({ deviceId, role });
|
|
118
|
+
void clearDevicePairing(deviceId).catch((err) => {
|
|
119
|
+
logDebug(`failed clearing stale device pairing for device ${deviceId}: ${String(err)}`);
|
|
120
|
+
});
|
|
121
|
+
logDebug(`cleared stale device-auth token for device ${deviceId}`);
|
|
98
122
|
}
|
|
99
123
|
catch (err) {
|
|
100
|
-
logDebug(`failed clearing stale device-auth token for device ${
|
|
124
|
+
logDebug(`failed clearing stale device-auth token for device ${deviceId}: ${String(err)}`);
|
|
101
125
|
}
|
|
102
126
|
}
|
|
103
127
|
this.flushPendingErrors(new Error(`gateway closed (${code}): ${reasonText}`));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
1
2
|
import chokidar from "chokidar";
|
|
2
3
|
import { listChannelPlugins } from "../channels/plugins/index.js";
|
|
3
4
|
import { getActivePluginRegistry } from "../plugins/runtime.js";
|
|
@@ -102,10 +103,8 @@ export function diffConfigPaths(prev, next, prefix = "") {
|
|
|
102
103
|
}
|
|
103
104
|
return paths;
|
|
104
105
|
}
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
106
|
+
if (isDeepStrictEqual(prev, next)) {
|
|
107
|
+
return [];
|
|
109
108
|
}
|
|
110
109
|
return [prefix || "<root>"];
|
|
111
110
|
}
|
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveControlUiRootSync } from "../infra/control-ui-assets.js";
|
|
4
|
+
import { isWithinDir } from "../infra/path-safety.js";
|
|
4
5
|
import { DEFAULT_ASSISTANT_IDENTITY, resolveAssistantIdentity } from "./assistant-identity.js";
|
|
6
|
+
import { CONTROL_UI_BOOTSTRAP_CONFIG_PATH, } from "./control-ui-contract.js";
|
|
7
|
+
import { buildControlUiCspHeader } from "./control-ui-csp.js";
|
|
5
8
|
import { buildControlUiAvatarUrl, CONTROL_UI_AVATAR_PREFIX, normalizeControlUiBasePath, resolveAssistantAvatarUrl, } from "./control-ui-shared.js";
|
|
6
9
|
const ROOT_PREFIX = "/";
|
|
7
|
-
function resolveControlUiRoot() {
|
|
8
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const execDir = (() => {
|
|
10
|
-
try {
|
|
11
|
-
return path.dirname(fs.realpathSync(process.execPath));
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
})();
|
|
17
|
-
const candidates = [
|
|
18
|
-
// Packaged app: control-ui lives alongside the executable.
|
|
19
|
-
execDir ? path.resolve(execDir, "control-ui") : null,
|
|
20
|
-
// Running from dist: dist/gateway/control-ui.js -> dist/control-ui
|
|
21
|
-
path.resolve(here, "../control-ui"),
|
|
22
|
-
// Running from source: src/gateway/control-ui.ts -> dist/control-ui
|
|
23
|
-
path.resolve(here, "../../dist/control-ui"),
|
|
24
|
-
// Fallback to cwd (dev)
|
|
25
|
-
path.resolve(process.cwd(), "dist", "control-ui"),
|
|
26
|
-
].filter((dir) => Boolean(dir));
|
|
27
|
-
for (const dir of candidates) {
|
|
28
|
-
if (fs.existsSync(path.join(dir, "index.html")))
|
|
29
|
-
return dir;
|
|
30
|
-
}
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
10
|
function contentTypeForExt(ext) {
|
|
34
11
|
switch (ext) {
|
|
35
12
|
case ".html":
|
|
@@ -60,6 +37,33 @@ function contentTypeForExt(ext) {
|
|
|
60
37
|
return "application/octet-stream";
|
|
61
38
|
}
|
|
62
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Extensions recognised as static assets. Missing files with these extensions
|
|
42
|
+
* return 404 instead of the SPA index.html fallback. `.html` is intentionally
|
|
43
|
+
* excluded — actual HTML files on disk are served earlier, and missing `.html`
|
|
44
|
+
* paths should fall through to the SPA router (client-side routers may use
|
|
45
|
+
* `.html`-suffixed routes).
|
|
46
|
+
*/
|
|
47
|
+
const STATIC_ASSET_EXTENSIONS = new Set([
|
|
48
|
+
".js",
|
|
49
|
+
".css",
|
|
50
|
+
".json",
|
|
51
|
+
".map",
|
|
52
|
+
".svg",
|
|
53
|
+
".png",
|
|
54
|
+
".jpg",
|
|
55
|
+
".jpeg",
|
|
56
|
+
".gif",
|
|
57
|
+
".webp",
|
|
58
|
+
".ico",
|
|
59
|
+
".txt",
|
|
60
|
+
]);
|
|
61
|
+
function applyControlUiSecurityHeaders(res) {
|
|
62
|
+
res.setHeader("X-Frame-Options", "DENY");
|
|
63
|
+
res.setHeader("Content-Security-Policy", buildControlUiCspHeader());
|
|
64
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
65
|
+
res.setHeader("Referrer-Policy", "no-referrer");
|
|
66
|
+
}
|
|
63
67
|
function sendJson(res, status, body) {
|
|
64
68
|
res.statusCode = status;
|
|
65
69
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
@@ -71,18 +75,22 @@ function isValidAgentId(agentId) {
|
|
|
71
75
|
}
|
|
72
76
|
export function handleControlUiAvatarRequest(req, res, opts) {
|
|
73
77
|
const urlRaw = req.url;
|
|
74
|
-
if (!urlRaw)
|
|
78
|
+
if (!urlRaw) {
|
|
75
79
|
return false;
|
|
76
|
-
|
|
80
|
+
}
|
|
81
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
77
82
|
return false;
|
|
83
|
+
}
|
|
78
84
|
const url = new URL(urlRaw, "http://localhost");
|
|
79
85
|
const basePath = normalizeControlUiBasePath(opts.basePath);
|
|
80
86
|
const pathname = url.pathname;
|
|
81
87
|
const pathWithBase = basePath
|
|
82
88
|
? `${basePath}${CONTROL_UI_AVATAR_PREFIX}/`
|
|
83
89
|
: `${CONTROL_UI_AVATAR_PREFIX}/`;
|
|
84
|
-
if (!pathname.startsWith(pathWithBase))
|
|
90
|
+
if (!pathname.startsWith(pathWithBase)) {
|
|
85
91
|
return false;
|
|
92
|
+
}
|
|
93
|
+
applyControlUiSecurityHeaders(res);
|
|
86
94
|
const agentIdParts = pathname.slice(pathWithBase.length).split("/").filter(Boolean);
|
|
87
95
|
const agentId = agentIdParts[0] ?? "";
|
|
88
96
|
if (agentIdParts.length !== 1 || !agentId || !isValidAgentId(agentId)) {
|
|
@@ -119,66 +127,93 @@ function respondNotFound(res) {
|
|
|
119
127
|
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
120
128
|
res.end("Not Found");
|
|
121
129
|
}
|
|
122
|
-
function
|
|
130
|
+
function setStaticFileHeaders(res, filePath) {
|
|
123
131
|
const ext = path.extname(filePath).toLowerCase();
|
|
124
132
|
res.setHeader("Content-Type", contentTypeForExt(ext));
|
|
125
133
|
// Static UI should never be cached aggressively while iterating; allow the
|
|
126
134
|
// browser to revalidate.
|
|
127
135
|
res.setHeader("Cache-Control", "no-cache");
|
|
136
|
+
}
|
|
137
|
+
function serveFile(res, filePath) {
|
|
138
|
+
setStaticFileHeaders(res, filePath);
|
|
128
139
|
res.end(fs.readFileSync(filePath));
|
|
129
140
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
`window.__CLAWDBOT_CONTROL_UI_BASE_PATH__=${JSON.stringify(basePath)};` +
|
|
134
|
-
`window.__CLAWDBOT_ASSISTANT_NAME__=${JSON.stringify(assistantName ?? DEFAULT_ASSISTANT_IDENTITY.name)};` +
|
|
135
|
-
`window.__CLAWDBOT_ASSISTANT_AVATAR__=${JSON.stringify(assistantAvatar ?? DEFAULT_ASSISTANT_IDENTITY.avatar)};` +
|
|
136
|
-
`</script>`;
|
|
137
|
-
// Check if already injected
|
|
138
|
-
if (html.includes("__CLAWDBOT_ASSISTANT_NAME__"))
|
|
139
|
-
return html;
|
|
140
|
-
const headClose = html.indexOf("</head>");
|
|
141
|
-
if (headClose !== -1) {
|
|
142
|
-
return `${html.slice(0, headClose)}${script}${html.slice(headClose)}`;
|
|
143
|
-
}
|
|
144
|
-
return `${script}${html}`;
|
|
141
|
+
function serveResolvedFile(res, filePath, body) {
|
|
142
|
+
setStaticFileHeaders(res, filePath);
|
|
143
|
+
res.end(body);
|
|
145
144
|
}
|
|
146
|
-
function
|
|
147
|
-
const { basePath, config, agentId } = opts;
|
|
148
|
-
const identity = config
|
|
149
|
-
? resolveAssistantIdentity({ cfg: config, agentId })
|
|
150
|
-
: DEFAULT_ASSISTANT_IDENTITY;
|
|
151
|
-
const resolvedAgentId = typeof identity.agentId === "string"
|
|
152
|
-
? identity.agentId
|
|
153
|
-
: agentId;
|
|
154
|
-
const avatarValue = resolveAssistantAvatarUrl({
|
|
155
|
-
avatar: identity.avatar,
|
|
156
|
-
agentId: resolvedAgentId,
|
|
157
|
-
basePath,
|
|
158
|
-
}) ?? identity.avatar;
|
|
145
|
+
function serveResolvedIndexHtml(res, body) {
|
|
159
146
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
160
147
|
res.setHeader("Cache-Control", "no-cache");
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
148
|
+
res.end(body);
|
|
149
|
+
}
|
|
150
|
+
function isContainedPath(baseDir, targetPath) {
|
|
151
|
+
const relative = path.relative(baseDir, targetPath);
|
|
152
|
+
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
153
|
+
}
|
|
154
|
+
function isExpectedSafePathError(error) {
|
|
155
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
156
|
+
return code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP";
|
|
157
|
+
}
|
|
158
|
+
function areSameFileIdentity(preOpen, opened) {
|
|
159
|
+
return preOpen.dev === opened.dev && preOpen.ino === opened.ino;
|
|
160
|
+
}
|
|
161
|
+
function resolveSafeControlUiFile(rootReal, filePath) {
|
|
162
|
+
let fd = null;
|
|
163
|
+
try {
|
|
164
|
+
const fileReal = fs.realpathSync(filePath);
|
|
165
|
+
if (!isContainedPath(rootReal, fileReal)) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const preOpenStat = fs.lstatSync(fileReal);
|
|
169
|
+
if (!preOpenStat.isFile()) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
const openFlags = fs.constants.O_RDONLY |
|
|
173
|
+
(typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0);
|
|
174
|
+
fd = fs.openSync(fileReal, openFlags);
|
|
175
|
+
const openedStat = fs.fstatSync(fd);
|
|
176
|
+
// Compare inode identity so swaps between validation and open are rejected.
|
|
177
|
+
if (!openedStat.isFile() || !areSameFileIdentity(preOpenStat, openedStat)) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const resolved = { path: fileReal, fd };
|
|
181
|
+
fd = null;
|
|
182
|
+
return resolved;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
if (isExpectedSafePathError(error)) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
if (fd !== null) {
|
|
192
|
+
fs.closeSync(fd);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
167
195
|
}
|
|
168
196
|
function isSafeRelativePath(relPath) {
|
|
169
|
-
if (!relPath)
|
|
197
|
+
if (!relPath) {
|
|
170
198
|
return false;
|
|
199
|
+
}
|
|
171
200
|
const normalized = path.posix.normalize(relPath);
|
|
172
|
-
if (
|
|
201
|
+
if (path.posix.isAbsolute(normalized) || path.win32.isAbsolute(normalized)) {
|
|
173
202
|
return false;
|
|
174
|
-
|
|
203
|
+
}
|
|
204
|
+
if (normalized.startsWith("../") || normalized === "..") {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (normalized.includes("\0")) {
|
|
175
208
|
return false;
|
|
209
|
+
}
|
|
176
210
|
return true;
|
|
177
211
|
}
|
|
178
212
|
export function handleControlUiHttpRequest(req, res, opts) {
|
|
179
213
|
const urlRaw = req.url;
|
|
180
|
-
if (!urlRaw)
|
|
214
|
+
if (!urlRaw) {
|
|
181
215
|
return false;
|
|
216
|
+
}
|
|
182
217
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
183
218
|
res.statusCode = 405;
|
|
184
219
|
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
@@ -190,41 +225,104 @@ export function handleControlUiHttpRequest(req, res, opts) {
|
|
|
190
225
|
const pathname = url.pathname;
|
|
191
226
|
if (!basePath) {
|
|
192
227
|
if (pathname === "/ui" || pathname.startsWith("/ui/")) {
|
|
228
|
+
applyControlUiSecurityHeaders(res);
|
|
193
229
|
respondNotFound(res);
|
|
194
230
|
return true;
|
|
195
231
|
}
|
|
196
232
|
}
|
|
197
233
|
if (basePath) {
|
|
198
234
|
if (pathname === basePath) {
|
|
235
|
+
applyControlUiSecurityHeaders(res);
|
|
199
236
|
res.statusCode = 302;
|
|
200
237
|
res.setHeader("Location", `${basePath}/${url.search}`);
|
|
201
238
|
res.end();
|
|
202
239
|
return true;
|
|
203
240
|
}
|
|
204
|
-
if (!pathname.startsWith(`${basePath}/`))
|
|
241
|
+
if (!pathname.startsWith(`${basePath}/`)) {
|
|
205
242
|
return false;
|
|
243
|
+
}
|
|
206
244
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
245
|
+
applyControlUiSecurityHeaders(res);
|
|
246
|
+
const bootstrapConfigPath = basePath
|
|
247
|
+
? `${basePath}${CONTROL_UI_BOOTSTRAP_CONFIG_PATH}`
|
|
248
|
+
: CONTROL_UI_BOOTSTRAP_CONFIG_PATH;
|
|
249
|
+
if (pathname === bootstrapConfigPath) {
|
|
250
|
+
const config = opts?.config;
|
|
251
|
+
const identity = config
|
|
252
|
+
? resolveAssistantIdentity({ cfg: config, agentId: opts?.agentId })
|
|
253
|
+
: DEFAULT_ASSISTANT_IDENTITY;
|
|
254
|
+
const avatarValue = resolveAssistantAvatarUrl({
|
|
255
|
+
avatar: identity.avatar,
|
|
256
|
+
agentId: identity.agentId,
|
|
257
|
+
basePath,
|
|
258
|
+
});
|
|
259
|
+
if (req.method === "HEAD") {
|
|
260
|
+
res.statusCode = 200;
|
|
261
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
262
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
263
|
+
res.end();
|
|
264
|
+
return true;
|
|
212
265
|
}
|
|
213
|
-
|
|
214
|
-
|
|
266
|
+
sendJson(res, 200, {
|
|
267
|
+
basePath,
|
|
268
|
+
assistantName: identity.name,
|
|
269
|
+
assistantAvatar: avatarValue ?? identity.avatar,
|
|
270
|
+
assistantAgentId: identity.agentId,
|
|
271
|
+
});
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
const rootState = opts?.root;
|
|
275
|
+
if (rootState?.kind === "invalid") {
|
|
276
|
+
res.statusCode = 503;
|
|
277
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
278
|
+
res.end(`Control UI assets not found at ${rootState.path}. Build them with \`pnpm ui:build\` (auto-installs UI deps), or update gateway.controlUi.root.`);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
if (rootState?.kind === "missing") {
|
|
282
|
+
res.statusCode = 503;
|
|
283
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
284
|
+
res.end("Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.");
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
const root = rootState?.kind === "resolved"
|
|
288
|
+
? rootState.path
|
|
289
|
+
: resolveControlUiRootSync({
|
|
290
|
+
moduleUrl: import.meta.url,
|
|
291
|
+
argv1: process.argv[1],
|
|
292
|
+
cwd: process.cwd(),
|
|
293
|
+
});
|
|
215
294
|
if (!root) {
|
|
216
295
|
res.statusCode = 503;
|
|
217
296
|
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
218
297
|
res.end("Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.");
|
|
219
298
|
return true;
|
|
220
299
|
}
|
|
300
|
+
const rootReal = (() => {
|
|
301
|
+
try {
|
|
302
|
+
return fs.realpathSync(root);
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
if (isExpectedSafePathError(error)) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
})();
|
|
311
|
+
if (!rootReal) {
|
|
312
|
+
res.statusCode = 503;
|
|
313
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
314
|
+
res.end("Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.");
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
221
317
|
const uiPath = basePath && pathname.startsWith(`${basePath}/`) ? pathname.slice(basePath.length) : pathname;
|
|
222
318
|
const rel = (() => {
|
|
223
|
-
if (uiPath === ROOT_PREFIX)
|
|
319
|
+
if (uiPath === ROOT_PREFIX) {
|
|
224
320
|
return "";
|
|
321
|
+
}
|
|
225
322
|
const assetsIndex = uiPath.indexOf("/assets/");
|
|
226
|
-
if (assetsIndex >= 0)
|
|
323
|
+
if (assetsIndex >= 0) {
|
|
227
324
|
return uiPath.slice(assetsIndex + 1);
|
|
325
|
+
}
|
|
228
326
|
return uiPath.slice(1);
|
|
229
327
|
})();
|
|
230
328
|
const requested = rel && !rel.endsWith("/") ? rel : `${rel}index.html`;
|
|
@@ -233,32 +331,57 @@ export function handleControlUiHttpRequest(req, res, opts) {
|
|
|
233
331
|
respondNotFound(res);
|
|
234
332
|
return true;
|
|
235
333
|
}
|
|
236
|
-
const filePath = path.
|
|
237
|
-
if (!
|
|
334
|
+
const filePath = path.resolve(root, fileRel);
|
|
335
|
+
if (!isWithinDir(root, filePath)) {
|
|
238
336
|
respondNotFound(res);
|
|
239
337
|
return true;
|
|
240
338
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
339
|
+
const safeFile = resolveSafeControlUiFile(rootReal, filePath);
|
|
340
|
+
if (safeFile) {
|
|
341
|
+
try {
|
|
342
|
+
if (req.method === "HEAD") {
|
|
343
|
+
res.statusCode = 200;
|
|
344
|
+
setStaticFileHeaders(res, safeFile.path);
|
|
345
|
+
res.end();
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
if (path.basename(safeFile.path) === "index.html") {
|
|
349
|
+
serveResolvedIndexHtml(res, fs.readFileSync(safeFile.fd, "utf8"));
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
serveResolvedFile(res, safeFile.path, fs.readFileSync(safeFile.fd));
|
|
248
353
|
return true;
|
|
249
354
|
}
|
|
250
|
-
|
|
355
|
+
finally {
|
|
356
|
+
fs.closeSync(safeFile.fd);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// If the requested path looks like a static asset (known extension), return
|
|
360
|
+
// 404 rather than falling through to the SPA index.html fallback. We check
|
|
361
|
+
// against the same set of extensions that contentTypeForExt() recognises so
|
|
362
|
+
// that dotted SPA routes (e.g. /user/jane.doe, /v2.0) still get the
|
|
363
|
+
// client-side router fallback.
|
|
364
|
+
if (STATIC_ASSET_EXTENSIONS.has(path.extname(fileRel).toLowerCase())) {
|
|
365
|
+
respondNotFound(res);
|
|
251
366
|
return true;
|
|
252
367
|
}
|
|
253
368
|
// SPA fallback (client-side router): serve index.html for unknown paths.
|
|
254
369
|
const indexPath = path.join(root, "index.html");
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
370
|
+
const safeIndex = resolveSafeControlUiFile(rootReal, indexPath);
|
|
371
|
+
if (safeIndex) {
|
|
372
|
+
try {
|
|
373
|
+
if (req.method === "HEAD") {
|
|
374
|
+
res.statusCode = 200;
|
|
375
|
+
setStaticFileHeaders(res, safeIndex.path);
|
|
376
|
+
res.end();
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
serveResolvedIndexHtml(res, fs.readFileSync(safeIndex.fd, "utf8"));
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
finally {
|
|
383
|
+
fs.closeSync(safeIndex.fd);
|
|
384
|
+
}
|
|
262
385
|
}
|
|
263
386
|
respondNotFound(res);
|
|
264
387
|
return true;
|