@poolzin/pool-bot 2026.2.24 → 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/CHANGELOG.md +21 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +17 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- package/dist/agents/bash-process-registry.test-helpers.js +29 -0
- package/dist/agents/bash-tools.exec-approval-request.js +20 -0
- package/dist/agents/bash-tools.exec-host-gateway.js +240 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- 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/content-blocks.js +16 -0
- 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-fallback.js +96 -101
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +364 -165
- 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-payloads.js +1 -0
- 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.fixture.js +34 -0
- 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/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -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.mocks.shared.js +12 -0
- 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/assistant-message-fixtures.js +29 -0
- 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/test-helpers/pi-tools-sandbox-context.js +27 -0
- 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-shared.js +108 -0
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- 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/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +19 -21
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- 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-standard.js +13 -0
- 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 +30 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +39 -0
- 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 +431 -424
- package/dist/browser/routes/agent.shared.js +47 -3
- package/dist/browser/routes/agent.snapshot.js +122 -116
- package/dist/browser/routes/agent.storage.js +303 -297
- package/dist/browser/routes/tabs.js +154 -100
- package/dist/browser/server-context.js +7 -0
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +26 -0
- 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/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -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/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +3 -2
- 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/exec-approvals-cli.js +92 -124
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +26 -0
- 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 +250 -73
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +214 -136
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/help.js +43 -12
- 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 +12 -8
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/test-runtime-capture.js +24 -0
- 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 +185 -89
- 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/channels.mock-harness.js +23 -0
- 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/daemon-install-runtime-warning.js +11 -0
- 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/sessions.test-helpers.js +61 -0
- 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 +32 -15
- package/dist/config/config-paths.js +9 -11
- package/dist/config/config.js +1 -1
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +45 -7
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +656 -171
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +54 -4
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.js +58 -570
- 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/validation.js +140 -85
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +156 -20
- 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/daemon/cmd-argv.js +21 -0
- package/dist/daemon/cmd-set.js +58 -0
- package/dist/daemon/service-types.js +1 -0
- 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/exec-approvals.js +357 -162
- 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 +72 -13
- package/dist/gateway/call.js +152 -83
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +74 -9
- 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 +121 -110
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +4 -2
- 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 +4 -1
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/protocol/schema.js +1 -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 +247 -54
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +465 -130
- package/dist/gateway/server-methods/config.js +193 -152
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- package/dist/gateway/server-methods/nodes.helpers.js +12 -0
- package/dist/gateway/server-methods/nodes.js +251 -69
- package/dist/gateway/server-methods/push.js +53 -0
- 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-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +39 -13
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-startup-memory.js +17 -11
- package/dist/gateway/server-ws-runtime.js +1 -0
- package/dist/gateway/server.impl.js +296 -139
- package/dist/gateway/session-preview.test-helpers.js +11 -0
- package/dist/gateway/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- package/dist/gateway/startup-auth.js +126 -0
- package/dist/gateway/test-helpers.agent-results.js +15 -0
- package/dist/gateway/test-helpers.mocks.js +37 -14
- package/dist/gateway/test-helpers.openai-mock.js +14 -7
- package/dist/gateway/test-helpers.server.js +161 -77
- 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 +170 -38
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- 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-path.js +49 -0
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +204 -144
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +141 -70
- package/dist/infra/exec-approvals-analysis.js +78 -20
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +277 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- package/dist/infra/git-root.js +61 -0
- package/dist/infra/heartbeat-active-hours.js +2 -2
- package/dist/infra/heartbeat-reason.js +40 -0
- package/dist/infra/heartbeat-runner.js +72 -32
- 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/install-source-utils.js +91 -7
- package/dist/infra/net/ssrf.js +131 -38
- package/dist/infra/node-pairing.js +50 -105
- package/dist/infra/npm-integrity.js +45 -0
- package/dist/infra/npm-pack-install.js +40 -0
- package/dist/infra/outbound/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- 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/message-action-runner.js +107 -327
- package/dist/infra/outbound/message.js +59 -36
- package/dist/infra/outbound/outbound-policy.js +52 -25
- package/dist/infra/outbound/outbound-send-service.js +58 -71
- package/dist/infra/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/plain-object.js +9 -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/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/scp-host.js +54 -0
- 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/infra/update-startup.js +86 -9
- 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/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -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/memory/test-manager.js +8 -0
- 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/temp-path.js +47 -0
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- package/dist/plugins/loader.js +192 -26
- package/dist/plugins/logger.js +8 -0
- package/dist/plugins/manifest-registry.js +3 -0
- package/dist/plugins/path-safety.js +34 -0
- package/dist/plugins/registry.js +5 -2
- package/dist/plugins/runtime/index.js +271 -206
- 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-models.js +4 -1
- 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 +100 -20
- package/dist/security/audit-extra.async.js +505 -179
- package/dist/security/audit-extra.js +12 -2
- package/dist/security/audit-extra.sync.js +421 -35
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +180 -370
- package/dist/security/dm-policy-shared.js +68 -0
- package/dist/security/external-content.js +46 -14
- package/dist/security/fix.js +49 -85
- package/dist/security/scan-paths.js +20 -0
- package/dist/security/secret-equal.js +3 -7
- package/dist/security/windows-acl.js +30 -15
- package/dist/shared/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +42 -0
- package/dist/shared/text-chunking.js +29 -0
- 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/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/mrkdwn.js +8 -0
- 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 +477 -210
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +44 -8
- 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/reasoning-lane-coordinator.js +128 -0
- 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/prompt-select-styled.js +9 -0
- package/dist/terminal/theme.js +12 -12
- package/dist/test-utils/command-runner.js +6 -0
- package/dist/test-utils/internal-hook-event-payload.js +10 -0
- package/dist/test-utils/model-auth-mock.js +12 -0
- package/dist/test-utils/provider-usage-fetch.js +14 -0
- package/dist/test-utils/temp-home.js +33 -0
- package/dist/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +50 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +236 -48
- 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/mask-api-key.js +10 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/utils/run-with-concurrency.js +39 -0
- 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 +126 -15
- package/docs/tools/slash-commands.md +5 -1
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/extensions/feishu/src/external-keys.ts +19 -0
- package/extensions/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- package/package.json +1 -1
package/dist/gateway/hooks.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { listAgentIds, resolveDefaultAgentId } from "../agents/agent-scope.js";
|
|
3
3
|
import { listChannelPlugins } from "../channels/plugins/index.js";
|
|
4
|
+
import { readJsonBodyWithLimit, requestBodyErrorToText } from "../infra/http-body.js";
|
|
4
5
|
import { normalizeAgentId } from "../routing/session-key.js";
|
|
5
6
|
import { normalizeMessageChannel } from "../utils/message-channel.js";
|
|
6
7
|
import { resolveHookMappings } from "./hooks-mapping.js";
|
|
7
8
|
const DEFAULT_HOOKS_PATH = "/hooks";
|
|
8
9
|
const DEFAULT_HOOKS_MAX_BODY_BYTES = 256 * 1024;
|
|
9
10
|
export function resolveHooksConfig(cfg) {
|
|
10
|
-
if (cfg.hooks?.enabled !== true)
|
|
11
|
+
if (cfg.hooks?.enabled !== true) {
|
|
11
12
|
return null;
|
|
13
|
+
}
|
|
12
14
|
const token = cfg.hooks?.token?.trim();
|
|
13
15
|
if (!token) {
|
|
14
16
|
throw new Error("hooks.enabled requires hooks.token");
|
|
@@ -26,6 +28,18 @@ export function resolveHooksConfig(cfg) {
|
|
|
26
28
|
const defaultAgentId = resolveDefaultAgentId(cfg);
|
|
27
29
|
const knownAgentIds = resolveKnownAgentIds(cfg, defaultAgentId);
|
|
28
30
|
const allowedAgentIds = resolveAllowedAgentIds(cfg.hooks?.allowedAgentIds);
|
|
31
|
+
const defaultSessionKey = resolveSessionKey(cfg.hooks?.defaultSessionKey);
|
|
32
|
+
const allowedSessionKeyPrefixes = resolveAllowedSessionKeyPrefixes(cfg.hooks?.allowedSessionKeyPrefixes);
|
|
33
|
+
if (defaultSessionKey &&
|
|
34
|
+
allowedSessionKeyPrefixes &&
|
|
35
|
+
!isSessionKeyAllowedByPrefix(defaultSessionKey, allowedSessionKeyPrefixes)) {
|
|
36
|
+
throw new Error("hooks.defaultSessionKey must match hooks.allowedSessionKeyPrefixes");
|
|
37
|
+
}
|
|
38
|
+
if (!defaultSessionKey &&
|
|
39
|
+
allowedSessionKeyPrefixes &&
|
|
40
|
+
!isSessionKeyAllowedByPrefix("hook:example", allowedSessionKeyPrefixes)) {
|
|
41
|
+
throw new Error("hooks.allowedSessionKeyPrefixes must include 'hook:' when hooks.defaultSessionKey is unset");
|
|
42
|
+
}
|
|
29
43
|
return {
|
|
30
44
|
basePath: trimmed,
|
|
31
45
|
token,
|
|
@@ -36,6 +50,11 @@ export function resolveHooksConfig(cfg) {
|
|
|
36
50
|
knownAgentIds,
|
|
37
51
|
allowedAgentIds,
|
|
38
52
|
},
|
|
53
|
+
sessionPolicy: {
|
|
54
|
+
defaultSessionKey,
|
|
55
|
+
allowRequestSessionKey: cfg.hooks?.allowRequestSessionKey === true,
|
|
56
|
+
allowedSessionKeyPrefixes,
|
|
57
|
+
},
|
|
39
58
|
};
|
|
40
59
|
}
|
|
41
60
|
function resolveKnownAgentIds(cfg, defaultAgentId) {
|
|
@@ -65,62 +84,68 @@ function resolveAllowedAgentIds(raw) {
|
|
|
65
84
|
}
|
|
66
85
|
return allowed;
|
|
67
86
|
}
|
|
87
|
+
function resolveSessionKey(raw) {
|
|
88
|
+
const value = raw?.trim();
|
|
89
|
+
return value ? value : undefined;
|
|
90
|
+
}
|
|
91
|
+
function normalizeSessionKeyPrefix(raw) {
|
|
92
|
+
const value = raw.trim().toLowerCase();
|
|
93
|
+
return value ? value : undefined;
|
|
94
|
+
}
|
|
95
|
+
function resolveAllowedSessionKeyPrefixes(raw) {
|
|
96
|
+
if (!Array.isArray(raw)) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const set = new Set();
|
|
100
|
+
for (const prefix of raw) {
|
|
101
|
+
const normalized = normalizeSessionKeyPrefix(prefix);
|
|
102
|
+
if (!normalized) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
set.add(normalized);
|
|
106
|
+
}
|
|
107
|
+
return set.size > 0 ? Array.from(set) : undefined;
|
|
108
|
+
}
|
|
109
|
+
function isSessionKeyAllowedByPrefix(sessionKey, prefixes) {
|
|
110
|
+
const normalized = sessionKey.trim().toLowerCase();
|
|
111
|
+
if (!normalized) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return prefixes.some((prefix) => normalized.startsWith(prefix));
|
|
115
|
+
}
|
|
68
116
|
export function extractHookToken(req, url) {
|
|
69
117
|
const auth = typeof req.headers.authorization === "string" ? req.headers.authorization.trim() : "";
|
|
70
118
|
if (auth.toLowerCase().startsWith("bearer ")) {
|
|
71
119
|
const token = auth.slice(7).trim();
|
|
72
|
-
if (token)
|
|
120
|
+
if (token) {
|
|
73
121
|
return { token, fromQuery: false };
|
|
122
|
+
}
|
|
74
123
|
}
|
|
75
124
|
const headerToken = typeof req.headers["x-poolbot-token"] === "string" ? req.headers["x-poolbot-token"].trim() : "";
|
|
76
|
-
if (headerToken)
|
|
125
|
+
if (headerToken) {
|
|
77
126
|
return { token: headerToken, fromQuery: false };
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
127
|
+
}
|
|
128
|
+
const queryToken = url?.searchParams.get("token")?.trim();
|
|
129
|
+
if (queryToken) {
|
|
130
|
+
return { token: queryToken, fromQuery: true };
|
|
131
|
+
}
|
|
81
132
|
return { token: undefined, fromQuery: false };
|
|
82
133
|
}
|
|
83
134
|
export async function readJsonBody(req, maxBytes) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
chunks.push(chunk);
|
|
99
|
-
});
|
|
100
|
-
req.on("end", () => {
|
|
101
|
-
if (done)
|
|
102
|
-
return;
|
|
103
|
-
done = true;
|
|
104
|
-
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
105
|
-
if (!raw) {
|
|
106
|
-
resolve({ ok: true, value: {} });
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
try {
|
|
110
|
-
const parsed = JSON.parse(raw);
|
|
111
|
-
resolve({ ok: true, value: parsed });
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
resolve({ ok: false, error: String(err) });
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
req.on("error", (err) => {
|
|
118
|
-
if (done)
|
|
119
|
-
return;
|
|
120
|
-
done = true;
|
|
121
|
-
resolve({ ok: false, error: String(err) });
|
|
122
|
-
});
|
|
123
|
-
});
|
|
135
|
+
const result = await readJsonBodyWithLimit(req, { maxBytes, emptyObjectOnEmpty: true });
|
|
136
|
+
if (result.ok) {
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
if (result.code === "PAYLOAD_TOO_LARGE") {
|
|
140
|
+
return { ok: false, error: "payload too large" };
|
|
141
|
+
}
|
|
142
|
+
if (result.code === "REQUEST_BODY_TIMEOUT") {
|
|
143
|
+
return { ok: false, error: "request body timeout" };
|
|
144
|
+
}
|
|
145
|
+
if (result.code === "CONNECTION_CLOSED") {
|
|
146
|
+
return { ok: false, error: requestBodyErrorToText("CONNECTION_CLOSED") };
|
|
147
|
+
}
|
|
148
|
+
return { ok: false, error: result.error };
|
|
124
149
|
}
|
|
125
150
|
export function normalizeHookHeaders(req) {
|
|
126
151
|
const headers = {};
|
|
@@ -136,8 +161,9 @@ export function normalizeHookHeaders(req) {
|
|
|
136
161
|
}
|
|
137
162
|
export function normalizeWakePayload(payload) {
|
|
138
163
|
const text = typeof payload.text === "string" ? payload.text.trim() : "";
|
|
139
|
-
if (!text)
|
|
164
|
+
if (!text) {
|
|
140
165
|
return { ok: false, error: "text required" };
|
|
166
|
+
}
|
|
141
167
|
const mode = payload.mode === "next-heartbeat" ? "next-heartbeat" : "now";
|
|
142
168
|
return { ok: true, value: { text, mode } };
|
|
143
169
|
}
|
|
@@ -145,13 +171,16 @@ const listHookChannelValues = () => ["last", ...listChannelPlugins().map((plugin
|
|
|
145
171
|
const getHookChannelSet = () => new Set(listHookChannelValues());
|
|
146
172
|
export const getHookChannelError = () => `channel must be ${listHookChannelValues().join("|")}`;
|
|
147
173
|
export function resolveHookChannel(raw) {
|
|
148
|
-
if (raw === undefined)
|
|
174
|
+
if (raw === undefined) {
|
|
149
175
|
return "last";
|
|
150
|
-
|
|
176
|
+
}
|
|
177
|
+
if (typeof raw !== "string") {
|
|
151
178
|
return null;
|
|
179
|
+
}
|
|
152
180
|
const normalized = normalizeMessageChannel(raw);
|
|
153
|
-
if (!normalized || !getHookChannelSet().has(normalized))
|
|
181
|
+
if (!normalized || !getHookChannelSet().has(normalized)) {
|
|
154
182
|
return null;
|
|
183
|
+
}
|
|
155
184
|
return normalized;
|
|
156
185
|
}
|
|
157
186
|
export function resolveHookDeliver(raw) {
|
|
@@ -182,23 +211,49 @@ export function isHookAgentAllowed(hooksConfig, agentId) {
|
|
|
182
211
|
return resolved ? allowed.has(resolved) : false;
|
|
183
212
|
}
|
|
184
213
|
export const getHookAgentPolicyError = () => "agentId is not allowed by hooks.allowedAgentIds";
|
|
214
|
+
export const getHookSessionKeyRequestPolicyError = () => "sessionKey is disabled for external /hooks/agent payloads; set hooks.allowRequestSessionKey=true to enable";
|
|
215
|
+
export const getHookSessionKeyPrefixError = (prefixes) => `sessionKey must start with one of: ${prefixes.join(", ")}`;
|
|
216
|
+
export function resolveHookSessionKey(params) {
|
|
217
|
+
const requested = resolveSessionKey(params.sessionKey);
|
|
218
|
+
if (requested) {
|
|
219
|
+
if (params.source === "request" && !params.hooksConfig.sessionPolicy.allowRequestSessionKey) {
|
|
220
|
+
return { ok: false, error: getHookSessionKeyRequestPolicyError() };
|
|
221
|
+
}
|
|
222
|
+
const allowedPrefixes = params.hooksConfig.sessionPolicy.allowedSessionKeyPrefixes;
|
|
223
|
+
if (allowedPrefixes && !isSessionKeyAllowedByPrefix(requested, allowedPrefixes)) {
|
|
224
|
+
return { ok: false, error: getHookSessionKeyPrefixError(allowedPrefixes) };
|
|
225
|
+
}
|
|
226
|
+
return { ok: true, value: requested };
|
|
227
|
+
}
|
|
228
|
+
const defaultSessionKey = params.hooksConfig.sessionPolicy.defaultSessionKey;
|
|
229
|
+
if (defaultSessionKey) {
|
|
230
|
+
return { ok: true, value: defaultSessionKey };
|
|
231
|
+
}
|
|
232
|
+
const generated = `hook:${(params.idFactory ?? randomUUID)()}`;
|
|
233
|
+
const allowedPrefixes = params.hooksConfig.sessionPolicy.allowedSessionKeyPrefixes;
|
|
234
|
+
if (allowedPrefixes && !isSessionKeyAllowedByPrefix(generated, allowedPrefixes)) {
|
|
235
|
+
return { ok: false, error: getHookSessionKeyPrefixError(allowedPrefixes) };
|
|
236
|
+
}
|
|
237
|
+
return { ok: true, value: generated };
|
|
238
|
+
}
|
|
185
239
|
export function normalizeAgentPayload(payload, opts) {
|
|
186
240
|
const message = typeof payload.message === "string" ? payload.message.trim() : "";
|
|
187
|
-
if (!message)
|
|
241
|
+
if (!message) {
|
|
188
242
|
return { ok: false, error: "message required" };
|
|
243
|
+
}
|
|
189
244
|
const nameRaw = payload.name;
|
|
190
245
|
const name = typeof nameRaw === "string" && nameRaw.trim() ? nameRaw.trim() : "Hook";
|
|
191
246
|
const agentIdRaw = payload.agentId;
|
|
192
247
|
const agentId = typeof agentIdRaw === "string" && agentIdRaw.trim() ? agentIdRaw.trim() : undefined;
|
|
193
248
|
const wakeMode = payload.wakeMode === "next-heartbeat" ? "next-heartbeat" : "now";
|
|
194
249
|
const sessionKeyRaw = payload.sessionKey;
|
|
195
|
-
const idFactory = opts?.idFactory ?? randomUUID;
|
|
196
250
|
const sessionKey = typeof sessionKeyRaw === "string" && sessionKeyRaw.trim()
|
|
197
251
|
? sessionKeyRaw.trim()
|
|
198
|
-
: `hook:${idFactory()}`;
|
|
252
|
+
: `hook:${(opts?.idFactory ?? randomUUID)()}`;
|
|
199
253
|
const channel = resolveHookChannel(payload.channel);
|
|
200
|
-
if (!channel)
|
|
254
|
+
if (!channel) {
|
|
201
255
|
return { ok: false, error: getHookChannelError() };
|
|
256
|
+
}
|
|
202
257
|
const toRaw = payload.to;
|
|
203
258
|
const to = typeof toRaw === "string" && toRaw.trim() ? toRaw.trim() : undefined;
|
|
204
259
|
const modelRaw = payload.model;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { authorizeHttpGatewayConnect } from "./auth.js";
|
|
2
2
|
import { sendGatewayAuthFailure } from "./http-common.js";
|
|
3
3
|
import { getBearerToken } from "./http-utils.js";
|
|
4
4
|
export async function authorizeGatewayBearerRequestOrReply(params) {
|
|
5
5
|
const token = getBearerToken(params.req);
|
|
6
|
-
const authResult = await
|
|
6
|
+
const authResult = await authorizeHttpGatewayConnect({
|
|
7
7
|
auth: params.auth,
|
|
8
8
|
connectAuth: token ? { token, password: token } : null,
|
|
9
9
|
req: params.req,
|
|
10
10
|
trustedProxies: params.trustedProxies,
|
|
11
|
+
allowRealIpFallback: params.allowRealIpFallback,
|
|
11
12
|
rateLimiter: params.rateLimiter,
|
|
12
13
|
});
|
|
13
14
|
if (!authResult.ok) {
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { readJsonBody } from "./hooks.js";
|
|
2
|
+
/**
|
|
3
|
+
* Apply baseline security headers that are safe for all response types (API JSON,
|
|
4
|
+
* HTML pages, static assets, SSE streams). Headers that restrict framing or set a
|
|
5
|
+
* Content-Security-Policy are intentionally omitted here because some handlers
|
|
6
|
+
* (canvas host, A2UI) serve content that may be loaded inside frames.
|
|
7
|
+
*/
|
|
8
|
+
export function setDefaultSecurityHeaders(res) {
|
|
9
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
10
|
+
res.setHeader("Referrer-Policy", "no-referrer");
|
|
11
|
+
}
|
|
2
12
|
export function sendJson(res, status, body) {
|
|
3
13
|
res.statusCode = status;
|
|
4
14
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
@@ -44,6 +54,18 @@ export function sendInvalidRequest(res, message) {
|
|
|
44
54
|
export async function readJsonBodyOrError(req, res, maxBytes) {
|
|
45
55
|
const body = await readJsonBody(req, maxBytes);
|
|
46
56
|
if (!body.ok) {
|
|
57
|
+
if (body.error === "payload too large") {
|
|
58
|
+
sendJson(res, 413, {
|
|
59
|
+
error: { message: "Payload too large", type: "invalid_request_error" },
|
|
60
|
+
});
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
if (body.error === "request body timeout") {
|
|
64
|
+
sendJson(res, 408, {
|
|
65
|
+
error: { message: "Request body timeout", type: "invalid_request_error" },
|
|
66
|
+
});
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
47
69
|
sendInvalidRequest(res, body.error);
|
|
48
70
|
return undefined;
|
|
49
71
|
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
export const ADMIN_SCOPE = "operator.admin";
|
|
2
|
+
export const READ_SCOPE = "operator.read";
|
|
3
|
+
export const WRITE_SCOPE = "operator.write";
|
|
4
|
+
export const APPROVALS_SCOPE = "operator.approvals";
|
|
5
|
+
export const PAIRING_SCOPE = "operator.pairing";
|
|
6
|
+
export const CLI_DEFAULT_OPERATOR_SCOPES = [
|
|
7
|
+
ADMIN_SCOPE,
|
|
8
|
+
APPROVALS_SCOPE,
|
|
9
|
+
PAIRING_SCOPE,
|
|
10
|
+
];
|
|
11
|
+
const NODE_ROLE_METHODS = new Set(["node.invoke.result", "node.event", "skills.bins"]);
|
|
12
|
+
const METHOD_SCOPE_GROUPS = {
|
|
13
|
+
[APPROVALS_SCOPE]: [
|
|
14
|
+
"exec.approval.request",
|
|
15
|
+
"exec.approval.waitDecision",
|
|
16
|
+
"exec.approval.resolve",
|
|
17
|
+
],
|
|
18
|
+
[PAIRING_SCOPE]: [
|
|
19
|
+
"node.pair.request",
|
|
20
|
+
"node.pair.list",
|
|
21
|
+
"node.pair.approve",
|
|
22
|
+
"node.pair.reject",
|
|
23
|
+
"node.pair.verify",
|
|
24
|
+
"device.pair.list",
|
|
25
|
+
"device.pair.approve",
|
|
26
|
+
"device.pair.reject",
|
|
27
|
+
"device.pair.remove",
|
|
28
|
+
"device.token.rotate",
|
|
29
|
+
"device.token.revoke",
|
|
30
|
+
"node.rename",
|
|
31
|
+
],
|
|
32
|
+
[READ_SCOPE]: [
|
|
33
|
+
"health",
|
|
34
|
+
"logs.tail",
|
|
35
|
+
"channels.status",
|
|
36
|
+
"status",
|
|
37
|
+
"usage.status",
|
|
38
|
+
"usage.cost",
|
|
39
|
+
"tts.status",
|
|
40
|
+
"tts.providers",
|
|
41
|
+
"models.list",
|
|
42
|
+
"agents.list",
|
|
43
|
+
"agent.identity.get",
|
|
44
|
+
"skills.status",
|
|
45
|
+
"voicewake.get",
|
|
46
|
+
"sessions.list",
|
|
47
|
+
"sessions.preview",
|
|
48
|
+
"sessions.resolve",
|
|
49
|
+
"sessions.usage",
|
|
50
|
+
"sessions.usage.timeseries",
|
|
51
|
+
"sessions.usage.logs",
|
|
52
|
+
"cron.list",
|
|
53
|
+
"cron.status",
|
|
54
|
+
"cron.runs",
|
|
55
|
+
"system-presence",
|
|
56
|
+
"last-heartbeat",
|
|
57
|
+
"node.list",
|
|
58
|
+
"node.describe",
|
|
59
|
+
"chat.history",
|
|
60
|
+
"config.get",
|
|
61
|
+
"talk.config",
|
|
62
|
+
"agents.files.list",
|
|
63
|
+
"agents.files.get",
|
|
64
|
+
],
|
|
65
|
+
[WRITE_SCOPE]: [
|
|
66
|
+
"send",
|
|
67
|
+
"poll",
|
|
68
|
+
"agent",
|
|
69
|
+
"agent.wait",
|
|
70
|
+
"wake",
|
|
71
|
+
"talk.mode",
|
|
72
|
+
"tts.enable",
|
|
73
|
+
"tts.disable",
|
|
74
|
+
"tts.convert",
|
|
75
|
+
"tts.setProvider",
|
|
76
|
+
"voicewake.set",
|
|
77
|
+
"node.invoke",
|
|
78
|
+
"chat.send",
|
|
79
|
+
"chat.abort",
|
|
80
|
+
"browser.request",
|
|
81
|
+
"push.test",
|
|
82
|
+
],
|
|
83
|
+
[ADMIN_SCOPE]: [
|
|
84
|
+
"channels.logout",
|
|
85
|
+
"agents.create",
|
|
86
|
+
"agents.update",
|
|
87
|
+
"agents.delete",
|
|
88
|
+
"skills.install",
|
|
89
|
+
"skills.update",
|
|
90
|
+
"cron.add",
|
|
91
|
+
"cron.update",
|
|
92
|
+
"cron.remove",
|
|
93
|
+
"cron.run",
|
|
94
|
+
"sessions.patch",
|
|
95
|
+
"sessions.reset",
|
|
96
|
+
"sessions.delete",
|
|
97
|
+
"sessions.compact",
|
|
98
|
+
"connect",
|
|
99
|
+
"chat.inject",
|
|
100
|
+
"web.login.start",
|
|
101
|
+
"web.login.wait",
|
|
102
|
+
"set-heartbeats",
|
|
103
|
+
"system-event",
|
|
104
|
+
"agents.files.set",
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
const ADMIN_METHOD_PREFIXES = ["exec.approvals.", "config.", "wizard.", "update."];
|
|
108
|
+
const METHOD_SCOPE_BY_NAME = new Map(Object.entries(METHOD_SCOPE_GROUPS).flatMap(([scope, methods]) => methods.map((method) => [method, scope])));
|
|
109
|
+
function resolveScopedMethod(method) {
|
|
110
|
+
const explicitScope = METHOD_SCOPE_BY_NAME.get(method);
|
|
111
|
+
if (explicitScope) {
|
|
112
|
+
return explicitScope;
|
|
113
|
+
}
|
|
114
|
+
if (ADMIN_METHOD_PREFIXES.some((prefix) => method.startsWith(prefix))) {
|
|
115
|
+
return ADMIN_SCOPE;
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
export function isApprovalMethod(method) {
|
|
120
|
+
return resolveScopedMethod(method) === APPROVALS_SCOPE;
|
|
121
|
+
}
|
|
122
|
+
export function isPairingMethod(method) {
|
|
123
|
+
return resolveScopedMethod(method) === PAIRING_SCOPE;
|
|
124
|
+
}
|
|
125
|
+
export function isReadMethod(method) {
|
|
126
|
+
return resolveScopedMethod(method) === READ_SCOPE;
|
|
127
|
+
}
|
|
128
|
+
export function isWriteMethod(method) {
|
|
129
|
+
return resolveScopedMethod(method) === WRITE_SCOPE;
|
|
130
|
+
}
|
|
131
|
+
export function isNodeRoleMethod(method) {
|
|
132
|
+
return NODE_ROLE_METHODS.has(method);
|
|
133
|
+
}
|
|
134
|
+
export function isAdminOnlyMethod(method) {
|
|
135
|
+
return resolveScopedMethod(method) === ADMIN_SCOPE;
|
|
136
|
+
}
|
|
137
|
+
export function resolveRequiredOperatorScopeForMethod(method) {
|
|
138
|
+
return resolveScopedMethod(method);
|
|
139
|
+
}
|
|
140
|
+
export function resolveLeastPrivilegeOperatorScopesForMethod(method) {
|
|
141
|
+
const requiredScope = resolveRequiredOperatorScopeForMethod(method);
|
|
142
|
+
if (requiredScope) {
|
|
143
|
+
return [requiredScope];
|
|
144
|
+
}
|
|
145
|
+
// Default-deny for unclassified methods.
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
export function authorizeOperatorScopesForMethod(method, scopes) {
|
|
149
|
+
if (scopes.includes(ADMIN_SCOPE)) {
|
|
150
|
+
return { allowed: true };
|
|
151
|
+
}
|
|
152
|
+
const requiredScope = resolveRequiredOperatorScopeForMethod(method) ?? ADMIN_SCOPE;
|
|
153
|
+
if (requiredScope === READ_SCOPE) {
|
|
154
|
+
if (scopes.includes(READ_SCOPE) || scopes.includes(WRITE_SCOPE)) {
|
|
155
|
+
return { allowed: true };
|
|
156
|
+
}
|
|
157
|
+
return { allowed: false, missingScope: READ_SCOPE };
|
|
158
|
+
}
|
|
159
|
+
if (scopes.includes(requiredScope)) {
|
|
160
|
+
return { allowed: true };
|
|
161
|
+
}
|
|
162
|
+
return { allowed: false, missingScope: requiredScope };
|
|
163
|
+
}
|
|
164
|
+
export function isGatewayMethodClassified(method) {
|
|
165
|
+
if (isNodeRoleMethod(method)) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
return resolveRequiredOperatorScopeForMethod(method) !== undefined;
|
|
169
|
+
}
|
package/dist/gateway/net.js
CHANGED
|
@@ -135,19 +135,44 @@ function stripOptionalPort(ip) {
|
|
|
135
135
|
}
|
|
136
136
|
return ip;
|
|
137
137
|
}
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
if (!
|
|
138
|
+
function parseIpLiteral(raw) {
|
|
139
|
+
const trimmed = raw?.trim();
|
|
140
|
+
if (!trimmed) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const stripped = stripOptionalPort(trimmed);
|
|
144
|
+
const normalized = normalizeIp(stripped);
|
|
145
|
+
if (!normalized || net.isIP(normalized) === 0) {
|
|
141
146
|
return undefined;
|
|
142
147
|
}
|
|
143
|
-
return
|
|
148
|
+
return normalized;
|
|
144
149
|
}
|
|
145
150
|
function parseRealIp(realIp) {
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
return parseIpLiteral(realIp);
|
|
152
|
+
}
|
|
153
|
+
function resolveForwardedClientIp(params) {
|
|
154
|
+
const { forwardedFor, trustedProxies } = params;
|
|
155
|
+
if (!trustedProxies?.length) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
const forwardedChain = [];
|
|
159
|
+
for (const entry of forwardedFor?.split(",") ?? []) {
|
|
160
|
+
const normalized = parseIpLiteral(entry);
|
|
161
|
+
if (normalized) {
|
|
162
|
+
forwardedChain.push(normalized);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (forwardedChain.length === 0) {
|
|
148
166
|
return undefined;
|
|
149
167
|
}
|
|
150
|
-
return
|
|
168
|
+
// Walk right-to-left and return the first untrusted hop.
|
|
169
|
+
for (let index = forwardedChain.length - 1; index >= 0; index -= 1) {
|
|
170
|
+
const hop = forwardedChain[index];
|
|
171
|
+
if (!isTrustedProxyAddress(hop, trustedProxies)) {
|
|
172
|
+
return hop;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
151
176
|
}
|
|
152
177
|
/**
|
|
153
178
|
* Check if an IP address matches a CIDR block.
|
|
@@ -202,7 +227,7 @@ export function isTrustedProxyAddress(ip, trustedProxies) {
|
|
|
202
227
|
return normalizeIp(candidate) === normalized;
|
|
203
228
|
});
|
|
204
229
|
}
|
|
205
|
-
export function
|
|
230
|
+
export function resolveClientIp(params) {
|
|
206
231
|
const remote = normalizeIp(params.remoteAddr);
|
|
207
232
|
if (!remote) {
|
|
208
233
|
return undefined;
|
|
@@ -210,7 +235,20 @@ export function resolveGatewayClientIp(params) {
|
|
|
210
235
|
if (!isTrustedProxyAddress(remote, params.trustedProxies)) {
|
|
211
236
|
return remote;
|
|
212
237
|
}
|
|
213
|
-
|
|
238
|
+
// Fail closed when traffic comes from a trusted proxy but client-origin headers
|
|
239
|
+
// are missing or invalid. Falling back to the proxy's own IP can accidentally
|
|
240
|
+
// treat unrelated requests as local/trusted.
|
|
241
|
+
const forwardedIp = resolveForwardedClientIp({
|
|
242
|
+
forwardedFor: params.forwardedFor,
|
|
243
|
+
trustedProxies: params.trustedProxies,
|
|
244
|
+
});
|
|
245
|
+
if (forwardedIp) {
|
|
246
|
+
return forwardedIp;
|
|
247
|
+
}
|
|
248
|
+
if (params.allowRealIpFallback) {
|
|
249
|
+
return parseRealIp(params.realIp);
|
|
250
|
+
}
|
|
251
|
+
return undefined;
|
|
214
252
|
}
|
|
215
253
|
export function isLocalGatewayAddress(ip) {
|
|
216
254
|
if (isLoopbackAddress(ip)) {
|
|
@@ -347,3 +385,30 @@ export function isLoopbackHost(host) {
|
|
|
347
385
|
const unbracket = h.startsWith("[") && h.endsWith("]") ? h.slice(1, -1) : h;
|
|
348
386
|
return isLoopbackAddress(unbracket);
|
|
349
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Security check for WebSocket URLs (CWE-319: Cleartext Transmission of Sensitive Information).
|
|
390
|
+
*
|
|
391
|
+
* Returns true if the URL is secure for transmitting data:
|
|
392
|
+
* - wss:// (TLS) is always secure
|
|
393
|
+
* - ws:// is only secure for loopback addresses (localhost, 127.x.x.x, ::1)
|
|
394
|
+
*
|
|
395
|
+
* All other ws:// URLs are considered insecure because both credentials
|
|
396
|
+
* AND chat/conversation data would be exposed to network interception.
|
|
397
|
+
*/
|
|
398
|
+
export function isSecureWebSocketUrl(url) {
|
|
399
|
+
let parsed;
|
|
400
|
+
try {
|
|
401
|
+
parsed = new URL(url);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
if (parsed.protocol === "wss:") {
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
if (parsed.protocol !== "ws:") {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
// ws:// is only secure for loopback addresses
|
|
413
|
+
return isLoopbackHost(parsed.hostname);
|
|
414
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveSystemRunCommand } from "../infra/system-run-command.js";
|
|
2
2
|
function asRecord(value) {
|
|
3
3
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4
4
|
return null;
|
|
@@ -20,24 +20,10 @@ function clientHasApprovals(client) {
|
|
|
20
20
|
const scopes = Array.isArray(client?.connect?.scopes) ? client?.connect?.scopes : [];
|
|
21
21
|
return scopes.includes("operator.admin") || scopes.includes("operator.approvals");
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
const raw = normalizeString(params.rawCommand);
|
|
25
|
-
if (raw) {
|
|
26
|
-
return raw;
|
|
27
|
-
}
|
|
28
|
-
if (Array.isArray(params.command)) {
|
|
29
|
-
const parts = params.command.map((v) => String(v));
|
|
30
|
-
if (parts.length > 0) {
|
|
31
|
-
return formatExecCommand(parts);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return "";
|
|
35
|
-
}
|
|
36
|
-
function approvalMatchesRequest(params, record) {
|
|
23
|
+
function approvalMatchesRequest(cmdText, params, record) {
|
|
37
24
|
if (record.request.host !== "node") {
|
|
38
25
|
return false;
|
|
39
26
|
}
|
|
40
|
-
const cmdText = getCmdText(params);
|
|
41
27
|
if (!cmdText || record.request.command !== cmdText) {
|
|
42
28
|
return false;
|
|
43
29
|
}
|
|
@@ -90,25 +76,18 @@ export function sanitizeSystemRunParamsForForwarding(opts) {
|
|
|
90
76
|
return { ok: true, params: opts.rawParams };
|
|
91
77
|
}
|
|
92
78
|
const p = obj;
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
const validation = validateSystemRunCommandConsistency({ argv, rawCommand: raw });
|
|
104
|
-
if (!validation.ok) {
|
|
105
|
-
return {
|
|
106
|
-
ok: false,
|
|
107
|
-
message: validation.message,
|
|
108
|
-
details: validation.details ?? { code: "RAW_COMMAND_MISMATCH" },
|
|
109
|
-
};
|
|
110
|
-
}
|
|
79
|
+
const cmdTextResolution = resolveSystemRunCommand({
|
|
80
|
+
command: p.command,
|
|
81
|
+
rawCommand: p.rawCommand,
|
|
82
|
+
});
|
|
83
|
+
if (!cmdTextResolution.ok) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
message: cmdTextResolution.message,
|
|
87
|
+
details: cmdTextResolution.details,
|
|
88
|
+
};
|
|
111
89
|
}
|
|
90
|
+
const cmdText = cmdTextResolution.cmdText;
|
|
112
91
|
const approved = p.approved === true;
|
|
113
92
|
const requestedDecision = normalizeApprovalDecision(p.approvalDecision);
|
|
114
93
|
const wantsApprovalOverride = approved || requestedDecision !== null;
|
|
@@ -171,7 +150,7 @@ export function sanitizeSystemRunParamsForForwarding(opts) {
|
|
|
171
150
|
details: { code: "APPROVAL_CLIENT_MISMATCH", runId },
|
|
172
151
|
};
|
|
173
152
|
}
|
|
174
|
-
if (!approvalMatchesRequest(p, snapshot)) {
|
|
153
|
+
if (!approvalMatchesRequest(cmdText, p, snapshot)) {
|
|
175
154
|
return {
|
|
176
155
|
ok: false,
|
|
177
156
|
message: "approval id does not match request",
|