@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
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
import { Button } from "@buape/carbon";
|
|
1
|
+
import { Button, Row, Separator, TextDisplay, serializePayload, } from "@buape/carbon";
|
|
2
2
|
import { ButtonStyle, Routes } from "discord-api-types/v10";
|
|
3
|
+
import { loadSessionStore, resolveStorePath } from "../../config/sessions.js";
|
|
4
|
+
import { buildGatewayConnectionDetails } from "../../gateway/call.js";
|
|
3
5
|
import { GatewayClient } from "../../gateway/client.js";
|
|
4
|
-
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
|
|
5
|
-
import { createDiscordClient } from "../send.shared.js";
|
|
6
6
|
import { logDebug, logError } from "../../logger.js";
|
|
7
|
+
import { normalizeAccountId, resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
|
|
8
|
+
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES, normalizeMessageChannel, } from "../../utils/message-channel.js";
|
|
9
|
+
import { createDiscordClient, stripUndefinedFields } from "../send.shared.js";
|
|
10
|
+
import { DiscordUiContainer } from "../ui.js";
|
|
7
11
|
const EXEC_APPROVAL_KEY = "execapproval";
|
|
12
|
+
/** Extract Discord channel ID from a session key like "agent:main:discord:channel:123456789" */
|
|
13
|
+
export function extractDiscordChannelId(sessionKey) {
|
|
14
|
+
if (!sessionKey) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
// Session key format: agent:<id>:discord:channel:<channelId> or agent:<id>:discord:group:<channelId>
|
|
18
|
+
const match = sessionKey.match(/discord:(?:channel|group):(\d+)/);
|
|
19
|
+
return match ? match[1] : null;
|
|
20
|
+
}
|
|
8
21
|
function encodeCustomIdValue(value) {
|
|
9
22
|
return encodeURIComponent(value);
|
|
10
23
|
}
|
|
@@ -20,13 +33,15 @@ export function buildExecApprovalCustomId(approvalId, action) {
|
|
|
20
33
|
return [`${EXEC_APPROVAL_KEY}:id=${encodeCustomIdValue(approvalId)}`, `action=${action}`].join(";");
|
|
21
34
|
}
|
|
22
35
|
export function parseExecApprovalData(data) {
|
|
23
|
-
if (!data || typeof data !== "object")
|
|
36
|
+
if (!data || typeof data !== "object") {
|
|
24
37
|
return null;
|
|
38
|
+
}
|
|
25
39
|
const coerce = (value) => typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
26
40
|
const rawId = coerce(data.id);
|
|
27
41
|
const rawAction = coerce(data.action);
|
|
28
|
-
if (!rawId || !rawAction)
|
|
42
|
+
if (!rawId || !rawAction) {
|
|
29
43
|
return null;
|
|
44
|
+
}
|
|
30
45
|
const action = rawAction;
|
|
31
46
|
if (action !== "allow-once" && action !== "allow-always" && action !== "deny") {
|
|
32
47
|
return null;
|
|
@@ -36,88 +51,161 @@ export function parseExecApprovalData(data) {
|
|
|
36
51
|
action,
|
|
37
52
|
};
|
|
38
53
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
class ExecApprovalContainer extends DiscordUiContainer {
|
|
55
|
+
constructor(params) {
|
|
56
|
+
const components = [
|
|
57
|
+
new TextDisplay(`## ${params.title}`),
|
|
58
|
+
];
|
|
59
|
+
if (params.description) {
|
|
60
|
+
components.push(new TextDisplay(params.description));
|
|
61
|
+
}
|
|
62
|
+
components.push(new Separator({ divider: true, spacing: "small" }));
|
|
63
|
+
components.push(new TextDisplay(`### Command\n\`\`\`\n${params.commandPreview}\n\`\`\``));
|
|
64
|
+
if (params.metadataLines?.length) {
|
|
65
|
+
components.push(new TextDisplay(params.metadataLines.join("\n")));
|
|
66
|
+
}
|
|
67
|
+
if (params.actionRow) {
|
|
68
|
+
components.push(params.actionRow);
|
|
69
|
+
}
|
|
70
|
+
if (params.footer) {
|
|
71
|
+
components.push(new Separator({ divider: false, spacing: "small" }));
|
|
72
|
+
components.push(new TextDisplay(`-# ${params.footer}`));
|
|
73
|
+
}
|
|
74
|
+
super({
|
|
75
|
+
cfg: params.cfg,
|
|
76
|
+
accountId: params.accountId,
|
|
77
|
+
components,
|
|
78
|
+
accentColor: params.accentColor,
|
|
55
79
|
});
|
|
56
80
|
}
|
|
81
|
+
}
|
|
82
|
+
class ExecApprovalActionButton extends Button {
|
|
83
|
+
customId;
|
|
84
|
+
label;
|
|
85
|
+
style;
|
|
86
|
+
constructor(params) {
|
|
87
|
+
super();
|
|
88
|
+
this.customId = buildExecApprovalCustomId(params.approvalId, params.action);
|
|
89
|
+
this.label = params.label;
|
|
90
|
+
this.style = params.style;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
class ExecApprovalActionRow extends Row {
|
|
94
|
+
constructor(approvalId) {
|
|
95
|
+
super([
|
|
96
|
+
new ExecApprovalActionButton({
|
|
97
|
+
approvalId,
|
|
98
|
+
action: "allow-once",
|
|
99
|
+
label: "Allow once",
|
|
100
|
+
style: ButtonStyle.Success,
|
|
101
|
+
}),
|
|
102
|
+
new ExecApprovalActionButton({
|
|
103
|
+
approvalId,
|
|
104
|
+
action: "allow-always",
|
|
105
|
+
label: "Always allow",
|
|
106
|
+
style: ButtonStyle.Primary,
|
|
107
|
+
}),
|
|
108
|
+
new ExecApprovalActionButton({
|
|
109
|
+
approvalId,
|
|
110
|
+
action: "deny",
|
|
111
|
+
label: "Deny",
|
|
112
|
+
style: ButtonStyle.Danger,
|
|
113
|
+
}),
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function resolveExecApprovalAccountId(params) {
|
|
118
|
+
const sessionKey = params.request.request.sessionKey?.trim();
|
|
119
|
+
if (!sessionKey) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const agentId = resolveAgentIdFromSessionKey(sessionKey);
|
|
124
|
+
const storePath = resolveStorePath(params.cfg.session?.store, { agentId });
|
|
125
|
+
const store = loadSessionStore(storePath);
|
|
126
|
+
const entry = store[sessionKey];
|
|
127
|
+
const channel = normalizeMessageChannel(entry?.origin?.provider ?? entry?.lastChannel);
|
|
128
|
+
if (channel && channel !== "discord") {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const accountId = entry?.origin?.accountId ?? entry?.lastAccountId;
|
|
132
|
+
return accountId?.trim() || null;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function buildExecApprovalMetadataLines(request) {
|
|
139
|
+
const lines = [];
|
|
140
|
+
if (request.request.cwd) {
|
|
141
|
+
lines.push(`- Working Directory: ${request.request.cwd}`);
|
|
142
|
+
}
|
|
57
143
|
if (request.request.host) {
|
|
58
|
-
|
|
59
|
-
name: "Host",
|
|
60
|
-
value: request.request.host,
|
|
61
|
-
inline: true,
|
|
62
|
-
});
|
|
144
|
+
lines.push(`- Host: ${request.request.host}`);
|
|
63
145
|
}
|
|
64
146
|
if (request.request.agentId) {
|
|
65
|
-
|
|
66
|
-
name: "Agent",
|
|
67
|
-
value: request.request.agentId,
|
|
68
|
-
inline: true,
|
|
69
|
-
});
|
|
147
|
+
lines.push(`- Agent: ${request.request.agentId}`);
|
|
70
148
|
}
|
|
71
|
-
return
|
|
149
|
+
return lines;
|
|
150
|
+
}
|
|
151
|
+
function buildExecApprovalPayload(container) {
|
|
152
|
+
const components = [container];
|
|
153
|
+
return { components };
|
|
154
|
+
}
|
|
155
|
+
function createExecApprovalRequestContainer(params) {
|
|
156
|
+
const commandText = params.request.request.command;
|
|
157
|
+
const commandRaw = commandText.length > 1000 ? `${commandText.slice(0, 1000)}...` : commandText;
|
|
158
|
+
const commandPreview = commandRaw.replace(/`/g, "\u200b`");
|
|
159
|
+
const expiresAtSeconds = Math.max(0, Math.floor(params.request.expiresAtMs / 1000));
|
|
160
|
+
return new ExecApprovalContainer({
|
|
161
|
+
cfg: params.cfg,
|
|
162
|
+
accountId: params.accountId,
|
|
72
163
|
title: "Exec Approval Required",
|
|
73
164
|
description: "A command needs your approval.",
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
165
|
+
commandPreview,
|
|
166
|
+
metadataLines: buildExecApprovalMetadataLines(params.request),
|
|
167
|
+
actionRow: params.actionRow,
|
|
168
|
+
footer: `Expires <t:${expiresAtSeconds}:R> · ID: ${params.request.id}`,
|
|
169
|
+
accentColor: "#FFA500",
|
|
170
|
+
});
|
|
79
171
|
}
|
|
80
|
-
function
|
|
81
|
-
const commandText = request.request.command;
|
|
82
|
-
const
|
|
83
|
-
const
|
|
172
|
+
function createResolvedContainer(params) {
|
|
173
|
+
const commandText = params.request.request.command;
|
|
174
|
+
const commandRaw = commandText.length > 500 ? `${commandText.slice(0, 500)}...` : commandText;
|
|
175
|
+
const commandPreview = commandRaw.replace(/`/g, "\u200b`");
|
|
176
|
+
const decisionLabel = params.decision === "allow-once"
|
|
84
177
|
? "Allowed (once)"
|
|
85
|
-
: decision === "allow-always"
|
|
178
|
+
: params.decision === "allow-always"
|
|
86
179
|
? "Allowed (always)"
|
|
87
180
|
: "Denied";
|
|
88
|
-
const
|
|
89
|
-
|
|
181
|
+
const accentColor = params.decision === "deny"
|
|
182
|
+
? "#ED4245"
|
|
183
|
+
: params.decision === "allow-always"
|
|
184
|
+
? "#5865F2"
|
|
185
|
+
: "#57F287";
|
|
186
|
+
return new ExecApprovalContainer({
|
|
187
|
+
cfg: params.cfg,
|
|
188
|
+
accountId: params.accountId,
|
|
90
189
|
title: `Exec Approval: ${decisionLabel}`,
|
|
91
|
-
description: resolvedBy ? `Resolved by ${resolvedBy}` : "Resolved",
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
value: `\`\`\`\n${commandPreview}\n\`\`\``,
|
|
97
|
-
inline: false,
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
footer: { text: `ID: ${request.id}` },
|
|
101
|
-
timestamp: new Date().toISOString(),
|
|
102
|
-
};
|
|
190
|
+
description: params.resolvedBy ? `Resolved by ${params.resolvedBy}` : "Resolved",
|
|
191
|
+
commandPreview,
|
|
192
|
+
footer: `ID: ${params.request.id}`,
|
|
193
|
+
accentColor,
|
|
194
|
+
});
|
|
103
195
|
}
|
|
104
|
-
function
|
|
105
|
-
const commandText = request.request.command;
|
|
106
|
-
const
|
|
107
|
-
|
|
196
|
+
function createExpiredContainer(params) {
|
|
197
|
+
const commandText = params.request.request.command;
|
|
198
|
+
const commandRaw = commandText.length > 500 ? `${commandText.slice(0, 500)}...` : commandText;
|
|
199
|
+
const commandPreview = commandRaw.replace(/`/g, "\u200b`");
|
|
200
|
+
return new ExecApprovalContainer({
|
|
201
|
+
cfg: params.cfg,
|
|
202
|
+
accountId: params.accountId,
|
|
108
203
|
title: "Exec Approval: Expired",
|
|
109
204
|
description: "This approval request has expired.",
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
value: `\`\`\`\n${commandPreview}\n\`\`\``,
|
|
115
|
-
inline: false,
|
|
116
|
-
},
|
|
117
|
-
],
|
|
118
|
-
footer: { text: `ID: ${request.id}` },
|
|
119
|
-
timestamp: new Date().toISOString(),
|
|
120
|
-
};
|
|
205
|
+
commandPreview,
|
|
206
|
+
footer: `ID: ${params.request.id}`,
|
|
207
|
+
accentColor: "#99AAB5",
|
|
208
|
+
});
|
|
121
209
|
}
|
|
122
210
|
export class DiscordExecApprovalHandler {
|
|
123
211
|
gatewayClient = null;
|
|
@@ -130,22 +218,37 @@ export class DiscordExecApprovalHandler {
|
|
|
130
218
|
}
|
|
131
219
|
shouldHandle(request) {
|
|
132
220
|
const config = this.opts.config;
|
|
133
|
-
if (!config.enabled)
|
|
221
|
+
if (!config.enabled) {
|
|
134
222
|
return false;
|
|
135
|
-
|
|
223
|
+
}
|
|
224
|
+
if (!config.approvers || config.approvers.length === 0) {
|
|
136
225
|
return false;
|
|
226
|
+
}
|
|
227
|
+
const requestAccountId = resolveExecApprovalAccountId({
|
|
228
|
+
cfg: this.opts.cfg,
|
|
229
|
+
request,
|
|
230
|
+
});
|
|
231
|
+
if (requestAccountId) {
|
|
232
|
+
const handlerAccountId = normalizeAccountId(this.opts.accountId);
|
|
233
|
+
if (normalizeAccountId(requestAccountId) !== handlerAccountId) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
137
237
|
// Check agent filter
|
|
138
238
|
if (config.agentFilter?.length) {
|
|
139
|
-
if (!request.request.agentId)
|
|
239
|
+
if (!request.request.agentId) {
|
|
140
240
|
return false;
|
|
141
|
-
|
|
241
|
+
}
|
|
242
|
+
if (!config.agentFilter.includes(request.request.agentId)) {
|
|
142
243
|
return false;
|
|
244
|
+
}
|
|
143
245
|
}
|
|
144
246
|
// Check session filter (substring match)
|
|
145
247
|
if (config.sessionFilter?.length) {
|
|
146
248
|
const session = request.request.sessionKey;
|
|
147
|
-
if (!session)
|
|
249
|
+
if (!session) {
|
|
148
250
|
return false;
|
|
251
|
+
}
|
|
149
252
|
const matches = config.sessionFilter.some((p) => {
|
|
150
253
|
try {
|
|
151
254
|
return session.includes(p) || new RegExp(p).test(session);
|
|
@@ -154,14 +257,16 @@ export class DiscordExecApprovalHandler {
|
|
|
154
257
|
return session.includes(p);
|
|
155
258
|
}
|
|
156
259
|
});
|
|
157
|
-
if (!matches)
|
|
260
|
+
if (!matches) {
|
|
158
261
|
return false;
|
|
262
|
+
}
|
|
159
263
|
}
|
|
160
264
|
return true;
|
|
161
265
|
}
|
|
162
266
|
async start() {
|
|
163
|
-
if (this.started)
|
|
267
|
+
if (this.started) {
|
|
164
268
|
return;
|
|
269
|
+
}
|
|
165
270
|
this.started = true;
|
|
166
271
|
const config = this.opts.config;
|
|
167
272
|
if (!config.enabled) {
|
|
@@ -173,8 +278,12 @@ export class DiscordExecApprovalHandler {
|
|
|
173
278
|
return;
|
|
174
279
|
}
|
|
175
280
|
logDebug("discord exec approvals: starting handler");
|
|
281
|
+
const { url: gatewayUrl } = buildGatewayConnectionDetails({
|
|
282
|
+
config: this.opts.cfg,
|
|
283
|
+
url: this.opts.gatewayUrl,
|
|
284
|
+
});
|
|
176
285
|
this.gatewayClient = new GatewayClient({
|
|
177
|
-
url:
|
|
286
|
+
url: gatewayUrl,
|
|
178
287
|
clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
|
|
179
288
|
clientDisplayName: "Discord Exec Approvals",
|
|
180
289
|
mode: GATEWAY_CLIENT_MODES.BACKEND,
|
|
@@ -193,8 +302,9 @@ export class DiscordExecApprovalHandler {
|
|
|
193
302
|
this.gatewayClient.start();
|
|
194
303
|
}
|
|
195
304
|
async stop() {
|
|
196
|
-
if (!this.started)
|
|
305
|
+
if (!this.started) {
|
|
197
306
|
return;
|
|
307
|
+
}
|
|
198
308
|
this.started = false;
|
|
199
309
|
// Clear all pending timeouts
|
|
200
310
|
for (const pending of this.pending.values()) {
|
|
@@ -217,111 +327,177 @@ export class DiscordExecApprovalHandler {
|
|
|
217
327
|
}
|
|
218
328
|
}
|
|
219
329
|
async handleApprovalRequested(request) {
|
|
220
|
-
if (!this.shouldHandle(request))
|
|
330
|
+
if (!this.shouldHandle(request)) {
|
|
221
331
|
return;
|
|
332
|
+
}
|
|
222
333
|
logDebug(`discord exec approvals: received request ${request.id}`);
|
|
223
334
|
this.requestCache.set(request.id, request);
|
|
224
335
|
const { rest, request: discordRequest } = createDiscordClient({ token: this.opts.token, accountId: this.opts.accountId }, this.opts.cfg);
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
{
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
body: { recipient_id: userId },
|
|
259
|
-
}), "dm-channel"));
|
|
260
|
-
if (!dmChannel?.id) {
|
|
261
|
-
logError(`discord exec approvals: failed to create DM for user ${userId}`);
|
|
262
|
-
continue;
|
|
336
|
+
const actionRow = new ExecApprovalActionRow(request.id);
|
|
337
|
+
const container = createExecApprovalRequestContainer({
|
|
338
|
+
request,
|
|
339
|
+
cfg: this.opts.cfg,
|
|
340
|
+
accountId: this.opts.accountId,
|
|
341
|
+
actionRow,
|
|
342
|
+
});
|
|
343
|
+
const payload = buildExecApprovalPayload(container);
|
|
344
|
+
const body = stripUndefinedFields(serializePayload(payload));
|
|
345
|
+
const target = this.opts.config.target ?? "dm";
|
|
346
|
+
const sendToDm = target === "dm" || target === "both";
|
|
347
|
+
const sendToChannel = target === "channel" || target === "both";
|
|
348
|
+
let fallbackToDm = false;
|
|
349
|
+
// Send to originating channel if configured
|
|
350
|
+
if (sendToChannel) {
|
|
351
|
+
const channelId = extractDiscordChannelId(request.request.sessionKey);
|
|
352
|
+
if (channelId) {
|
|
353
|
+
try {
|
|
354
|
+
const message = (await discordRequest(() => rest.post(Routes.channelMessages(channelId), {
|
|
355
|
+
body,
|
|
356
|
+
}), "send-approval-channel"));
|
|
357
|
+
if (message?.id) {
|
|
358
|
+
const timeoutMs = Math.max(0, request.expiresAtMs - Date.now());
|
|
359
|
+
const timeoutId = setTimeout(() => {
|
|
360
|
+
void this.handleApprovalTimeout(request.id, "channel");
|
|
361
|
+
}, timeoutMs);
|
|
362
|
+
this.pending.set(`${request.id}:channel`, {
|
|
363
|
+
discordMessageId: message.id,
|
|
364
|
+
discordChannelId: channelId,
|
|
365
|
+
timeoutId,
|
|
366
|
+
});
|
|
367
|
+
logDebug(`discord exec approvals: sent approval ${request.id} to channel ${channelId}`);
|
|
368
|
+
}
|
|
263
369
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
370
|
+
catch (err) {
|
|
371
|
+
logError(`discord exec approvals: failed to send to channel: ${String(err)}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
if (!sendToDm) {
|
|
376
|
+
logError(`discord exec approvals: target is "channel" but could not extract channel id from session key "${request.request.sessionKey ?? "(none)"}" — falling back to DM delivery for approval ${request.id}`);
|
|
377
|
+
fallbackToDm = true;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
logDebug("discord exec approvals: could not extract channel id from session key");
|
|
274
381
|
}
|
|
275
|
-
// Set up timeout
|
|
276
|
-
const timeoutMs = Math.max(0, request.expiresAtMs - Date.now());
|
|
277
|
-
const timeoutId = setTimeout(() => {
|
|
278
|
-
void this.handleApprovalTimeout(request.id);
|
|
279
|
-
}, timeoutMs);
|
|
280
|
-
this.pending.set(request.id, {
|
|
281
|
-
discordMessageId: message.id,
|
|
282
|
-
discordChannelId: dmChannel.id,
|
|
283
|
-
timeoutId,
|
|
284
|
-
});
|
|
285
|
-
logDebug(`discord exec approvals: sent approval ${request.id} to user ${userId}`);
|
|
286
382
|
}
|
|
287
|
-
|
|
288
|
-
|
|
383
|
+
}
|
|
384
|
+
// Send to approver DMs if configured (or as fallback when channel extraction fails)
|
|
385
|
+
if (sendToDm || fallbackToDm) {
|
|
386
|
+
const approvers = this.opts.config.approvers ?? [];
|
|
387
|
+
for (const approver of approvers) {
|
|
388
|
+
const userId = String(approver);
|
|
389
|
+
try {
|
|
390
|
+
// Create DM channel
|
|
391
|
+
const dmChannel = (await discordRequest(() => rest.post(Routes.userChannels(), {
|
|
392
|
+
body: { recipient_id: userId },
|
|
393
|
+
}), "dm-channel"));
|
|
394
|
+
if (!dmChannel?.id) {
|
|
395
|
+
logError(`discord exec approvals: failed to create DM for user ${userId}`);
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
// Send message with components v2 + buttons
|
|
399
|
+
const message = (await discordRequest(() => rest.post(Routes.channelMessages(dmChannel.id), {
|
|
400
|
+
body,
|
|
401
|
+
}), "send-approval"));
|
|
402
|
+
if (!message?.id) {
|
|
403
|
+
logError(`discord exec approvals: failed to send message to user ${userId}`);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
// Clear any existing pending DM entry to avoid timeout leaks
|
|
407
|
+
const existingDm = this.pending.get(`${request.id}:dm`);
|
|
408
|
+
if (existingDm) {
|
|
409
|
+
clearTimeout(existingDm.timeoutId);
|
|
410
|
+
}
|
|
411
|
+
// Set up timeout
|
|
412
|
+
const timeoutMs = Math.max(0, request.expiresAtMs - Date.now());
|
|
413
|
+
const timeoutId = setTimeout(() => {
|
|
414
|
+
void this.handleApprovalTimeout(request.id, "dm");
|
|
415
|
+
}, timeoutMs);
|
|
416
|
+
this.pending.set(`${request.id}:dm`, {
|
|
417
|
+
discordMessageId: message.id,
|
|
418
|
+
discordChannelId: dmChannel.id,
|
|
419
|
+
timeoutId,
|
|
420
|
+
});
|
|
421
|
+
logDebug(`discord exec approvals: sent approval ${request.id} to user ${userId}`);
|
|
422
|
+
}
|
|
423
|
+
catch (err) {
|
|
424
|
+
logError(`discord exec approvals: failed to notify user ${userId}: ${String(err)}`);
|
|
425
|
+
}
|
|
289
426
|
}
|
|
290
427
|
}
|
|
291
428
|
}
|
|
292
429
|
async handleApprovalResolved(resolved) {
|
|
293
|
-
|
|
294
|
-
if (!pending)
|
|
295
|
-
return;
|
|
296
|
-
clearTimeout(pending.timeoutId);
|
|
297
|
-
this.pending.delete(resolved.id);
|
|
430
|
+
// Clean up all pending entries for this approval (channel + dm)
|
|
298
431
|
const request = this.requestCache.get(resolved.id);
|
|
299
432
|
this.requestCache.delete(resolved.id);
|
|
300
|
-
if (!request)
|
|
433
|
+
if (!request) {
|
|
301
434
|
return;
|
|
435
|
+
}
|
|
302
436
|
logDebug(`discord exec approvals: resolved ${resolved.id} with ${resolved.decision}`);
|
|
303
|
-
|
|
437
|
+
const container = createResolvedContainer({
|
|
438
|
+
request,
|
|
439
|
+
decision: resolved.decision,
|
|
440
|
+
resolvedBy: resolved.resolvedBy,
|
|
441
|
+
cfg: this.opts.cfg,
|
|
442
|
+
accountId: this.opts.accountId,
|
|
443
|
+
});
|
|
444
|
+
for (const suffix of [":channel", ":dm", ""]) {
|
|
445
|
+
const key = `${resolved.id}${suffix}`;
|
|
446
|
+
const pending = this.pending.get(key);
|
|
447
|
+
if (!pending) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
clearTimeout(pending.timeoutId);
|
|
451
|
+
this.pending.delete(key);
|
|
452
|
+
await this.finalizeMessage(pending.discordChannelId, pending.discordMessageId, container);
|
|
453
|
+
}
|
|
304
454
|
}
|
|
305
|
-
async handleApprovalTimeout(approvalId) {
|
|
306
|
-
const
|
|
307
|
-
|
|
455
|
+
async handleApprovalTimeout(approvalId, source) {
|
|
456
|
+
const key = source ? `${approvalId}:${source}` : approvalId;
|
|
457
|
+
const pending = this.pending.get(key);
|
|
458
|
+
if (!pending) {
|
|
308
459
|
return;
|
|
309
|
-
|
|
460
|
+
}
|
|
461
|
+
this.pending.delete(key);
|
|
310
462
|
const request = this.requestCache.get(approvalId);
|
|
311
|
-
this
|
|
312
|
-
|
|
463
|
+
// Only clean up requestCache if no other pending entries exist for this approval
|
|
464
|
+
const hasOtherPending = this.pending.has(`${approvalId}:channel`) ||
|
|
465
|
+
this.pending.has(`${approvalId}:dm`) ||
|
|
466
|
+
this.pending.has(approvalId);
|
|
467
|
+
if (!hasOtherPending) {
|
|
468
|
+
this.requestCache.delete(approvalId);
|
|
469
|
+
}
|
|
470
|
+
if (!request) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
logDebug(`discord exec approvals: timeout for ${approvalId} (${source ?? "default"})`);
|
|
474
|
+
const container = createExpiredContainer({
|
|
475
|
+
request,
|
|
476
|
+
cfg: this.opts.cfg,
|
|
477
|
+
accountId: this.opts.accountId,
|
|
478
|
+
});
|
|
479
|
+
await this.finalizeMessage(pending.discordChannelId, pending.discordMessageId, container);
|
|
480
|
+
}
|
|
481
|
+
async finalizeMessage(channelId, messageId, container) {
|
|
482
|
+
if (!this.opts.config.cleanupAfterResolve) {
|
|
483
|
+
await this.updateMessage(channelId, messageId, container);
|
|
313
484
|
return;
|
|
314
|
-
|
|
315
|
-
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
const { rest, request: discordRequest } = createDiscordClient({ token: this.opts.token, accountId: this.opts.accountId }, this.opts.cfg);
|
|
488
|
+
await discordRequest(() => rest.delete(Routes.channelMessage(channelId, messageId)), "delete-approval");
|
|
489
|
+
}
|
|
490
|
+
catch (err) {
|
|
491
|
+
logError(`discord exec approvals: failed to delete message: ${String(err)}`);
|
|
492
|
+
await this.updateMessage(channelId, messageId, container);
|
|
493
|
+
}
|
|
316
494
|
}
|
|
317
|
-
async updateMessage(channelId, messageId,
|
|
495
|
+
async updateMessage(channelId, messageId, container) {
|
|
318
496
|
try {
|
|
319
497
|
const { rest, request: discordRequest } = createDiscordClient({ token: this.opts.token, accountId: this.opts.accountId }, this.opts.cfg);
|
|
498
|
+
const payload = buildExecApprovalPayload(container);
|
|
320
499
|
await discordRequest(() => rest.patch(Routes.channelMessage(channelId, messageId), {
|
|
321
|
-
body:
|
|
322
|
-
embeds: [embed],
|
|
323
|
-
components: [], // Remove buttons
|
|
324
|
-
},
|
|
500
|
+
body: stripUndefinedFields(serializePayload(payload)),
|
|
325
501
|
}), "update-approval");
|
|
326
502
|
}
|
|
327
503
|
catch (err) {
|
|
@@ -347,6 +523,10 @@ export class DiscordExecApprovalHandler {
|
|
|
347
523
|
return false;
|
|
348
524
|
}
|
|
349
525
|
}
|
|
526
|
+
/** Return the list of configured approver IDs. */
|
|
527
|
+
getApprovers() {
|
|
528
|
+
return this.opts.config.approvers ?? [];
|
|
529
|
+
}
|
|
350
530
|
}
|
|
351
531
|
export class ExecApprovalButton extends Button {
|
|
352
532
|
label = "execapproval";
|
|
@@ -371,6 +551,21 @@ export class ExecApprovalButton extends Button {
|
|
|
371
551
|
}
|
|
372
552
|
return;
|
|
373
553
|
}
|
|
554
|
+
// Verify the user is an authorized approver
|
|
555
|
+
const approvers = this.ctx.handler.getApprovers();
|
|
556
|
+
const userId = interaction.userId;
|
|
557
|
+
if (!approvers.some((id) => String(id) === userId)) {
|
|
558
|
+
try {
|
|
559
|
+
await interaction.reply({
|
|
560
|
+
content: "⛔ You are not authorized to approve exec requests.",
|
|
561
|
+
ephemeral: true,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
// Interaction may have expired
|
|
566
|
+
}
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
374
569
|
const decisionLabel = parsed.action === "allow-once"
|
|
375
570
|
? "Allowed (once)"
|
|
376
571
|
: parsed.action === "allow-always"
|
|
@@ -8,7 +8,8 @@ export function resolveDiscordGatewayIntents(intentsConfig) {
|
|
|
8
8
|
GatewayIntents.MessageContent |
|
|
9
9
|
GatewayIntents.DirectMessages |
|
|
10
10
|
GatewayIntents.GuildMessageReactions |
|
|
11
|
-
GatewayIntents.DirectMessageReactions
|
|
11
|
+
GatewayIntents.DirectMessageReactions |
|
|
12
|
+
GatewayIntents.GuildVoiceStates;
|
|
12
13
|
if (intentsConfig?.presence) {
|
|
13
14
|
intents |= GatewayIntents.GuildPresences;
|
|
14
15
|
}
|