@poolzin/pool-bot 2026.2.21 → 2026.2.23
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 +25 -0
- package/dist/agents/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/device-pair/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/irc/src/accounts.ts +1 -1
- package/extensions/irc/src/onboarding.ts +4 -4
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +10 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +10 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +10 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +10 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +10 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +10 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +10 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
- package/dist/agents/openclaw-tools.js +0 -151
- package/dist/agents/tool-security.js +0 -96
- package/dist/gateway/url-validation.js +0 -94
- package/dist/infra/openclaw-root.js +0 -109
- package/dist/infra/tmp-openclaw-dir.js +0 -81
- package/dist/media/path-sanitization.js +0 -78
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { inspect } from "node:util";
|
|
2
|
-
import { Client } from "@buape/carbon";
|
|
3
|
-
import { GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway";
|
|
2
|
+
import { Client, ReadyListener, } from "@buape/carbon";
|
|
4
3
|
import { Routes } from "discord-api-types/v10";
|
|
5
4
|
import { resolveTextChunkLimit } from "../../auto-reply/chunk.js";
|
|
6
5
|
import { listNativeCommandSpecsForConfig } from "../../auto-reply/commands-registry.js";
|
|
7
6
|
import { listSkillCommandsForAgents } from "../../auto-reply/skill-commands.js";
|
|
8
|
-
import { mergeAllowlist, summarizeMapping } from "../../channels/allowlists/resolve-utils.js";
|
|
7
|
+
import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, mergeAllowlist, resolveAllowlistIdAdditions, patchAllowlistUsersInConfigEntries, summarizeMapping, } from "../../channels/allowlists/resolve-utils.js";
|
|
9
8
|
import { isNativeCommandsExplicitlyDisabled, resolveNativeCommandsEnabled, resolveNativeSkillsEnabled, } from "../../config/commands.js";
|
|
10
9
|
import { loadConfig } from "../../config/config.js";
|
|
11
10
|
import { danger, logVerbose, shouldLogVerbose, warn } from "../../globals.js";
|
|
12
11
|
import { formatErrorMessage } from "../../infra/errors.js";
|
|
13
12
|
import { createDiscordRetryRunner } from "../../infra/retry-policy.js";
|
|
14
13
|
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
14
|
+
import { createNonExitingRuntime } from "../../runtime.js";
|
|
15
15
|
import { resolveDiscordAccount } from "../accounts.js";
|
|
16
16
|
import { attachDiscordGatewayLogging } from "../gateway-logging.js";
|
|
17
17
|
import { getDiscordGatewayEmitter, waitForDiscordGatewayStop } from "../monitor.gateway.js";
|
|
@@ -19,28 +19,53 @@ import { fetchDiscordApplicationId } from "../probe.js";
|
|
|
19
19
|
import { resolveDiscordChannelAllowlist } from "../resolve-channels.js";
|
|
20
20
|
import { resolveDiscordUserAllowlist } from "../resolve-users.js";
|
|
21
21
|
import { normalizeDiscordToken } from "../token.js";
|
|
22
|
+
import { createAgentComponentButton, createAgentSelectMenu, createDiscordComponentButton, createDiscordComponentChannelSelect, createDiscordComponentMentionableSelect, createDiscordComponentModal, createDiscordComponentRoleSelect, createDiscordComponentStringSelect, createDiscordComponentUserSelect, } from "./agent-components.js";
|
|
23
|
+
import { createExecApprovalButton, DiscordExecApprovalHandler } from "./exec-approvals.js";
|
|
24
|
+
import { createDiscordGatewayPlugin } from "./gateway-plugin.js";
|
|
25
|
+
import { registerGateway, unregisterGateway } from "./gateway-registry.js";
|
|
22
26
|
import { DiscordMessageListener, DiscordPresenceListener, DiscordReactionListener, DiscordReactionRemoveListener, registerDiscordListener, } from "./listeners.js";
|
|
23
27
|
import { createDiscordMessageHandler } from "./message-handler.js";
|
|
24
28
|
import { createDiscordCommandArgFallbackButton, createDiscordNativeCommand, } from "./native-command.js";
|
|
25
|
-
import {
|
|
29
|
+
import { resolveDiscordPresenceUpdate } from "./presence.js";
|
|
30
|
+
import { resolveDiscordRestFetch } from "./rest-fetch.js";
|
|
26
31
|
function summarizeAllowList(list) {
|
|
27
|
-
if (!list || list.length === 0)
|
|
32
|
+
if (!list || list.length === 0) {
|
|
28
33
|
return "any";
|
|
34
|
+
}
|
|
29
35
|
const sample = list.slice(0, 4).map((entry) => String(entry));
|
|
30
36
|
const suffix = list.length > sample.length ? ` (+${list.length - sample.length})` : "";
|
|
31
37
|
return `${sample.join(", ")}${suffix}`;
|
|
32
38
|
}
|
|
33
39
|
function summarizeGuilds(entries) {
|
|
34
|
-
if (!entries || Object.keys(entries).length === 0)
|
|
40
|
+
if (!entries || Object.keys(entries).length === 0) {
|
|
35
41
|
return "any";
|
|
42
|
+
}
|
|
36
43
|
const keys = Object.keys(entries);
|
|
37
44
|
const sample = keys.slice(0, 4);
|
|
38
45
|
const suffix = keys.length > sample.length ? ` (+${keys.length - sample.length})` : "";
|
|
39
46
|
return `${sample.join(", ")}${suffix}`;
|
|
40
47
|
}
|
|
48
|
+
function dedupeSkillCommandsForDiscord(skillCommands) {
|
|
49
|
+
const seen = new Set();
|
|
50
|
+
const deduped = [];
|
|
51
|
+
for (const command of skillCommands) {
|
|
52
|
+
const key = command.skillName.trim().toLowerCase();
|
|
53
|
+
if (!key) {
|
|
54
|
+
deduped.push(command);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (seen.has(key)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
seen.add(key);
|
|
61
|
+
deduped.push(command);
|
|
62
|
+
}
|
|
63
|
+
return deduped;
|
|
64
|
+
}
|
|
41
65
|
async function deployDiscordCommands(params) {
|
|
42
|
-
if (!params.enabled)
|
|
66
|
+
if (!params.enabled) {
|
|
43
67
|
return;
|
|
68
|
+
}
|
|
44
69
|
const runWithRetry = createDiscordRetryRunner({ verbose: shouldLogVerbose() });
|
|
45
70
|
try {
|
|
46
71
|
await runWithRetry(() => params.client.handleDeployRequest(), "command deploy");
|
|
@@ -51,14 +76,16 @@ async function deployDiscordCommands(params) {
|
|
|
51
76
|
}
|
|
52
77
|
}
|
|
53
78
|
function formatDiscordDeployErrorDetails(err) {
|
|
54
|
-
if (!err || typeof err !== "object")
|
|
79
|
+
if (!err || typeof err !== "object") {
|
|
55
80
|
return "";
|
|
81
|
+
}
|
|
56
82
|
const status = err.status;
|
|
57
83
|
const discordCode = err.discordCode;
|
|
58
84
|
const rawBody = err.rawBody;
|
|
59
85
|
const details = [];
|
|
60
|
-
if (typeof status === "number")
|
|
86
|
+
if (typeof status === "number") {
|
|
61
87
|
details.push(`status=${status}`);
|
|
88
|
+
}
|
|
62
89
|
if (typeof discordCode === "number" || typeof discordCode === "string") {
|
|
63
90
|
details.push(`code=${discordCode}`);
|
|
64
91
|
}
|
|
@@ -79,21 +106,6 @@ function formatDiscordDeployErrorDetails(err) {
|
|
|
79
106
|
}
|
|
80
107
|
return details.length > 0 ? ` (${details.join(", ")})` : "";
|
|
81
108
|
}
|
|
82
|
-
function resolveDiscordGatewayIntents(intentsConfig) {
|
|
83
|
-
let intents = GatewayIntents.Guilds |
|
|
84
|
-
GatewayIntents.GuildMessages |
|
|
85
|
-
GatewayIntents.MessageContent |
|
|
86
|
-
GatewayIntents.DirectMessages |
|
|
87
|
-
GatewayIntents.GuildMessageReactions |
|
|
88
|
-
GatewayIntents.DirectMessageReactions;
|
|
89
|
-
if (intentsConfig?.presence) {
|
|
90
|
-
intents |= GatewayIntents.GuildPresences;
|
|
91
|
-
}
|
|
92
|
-
if (intentsConfig?.guildMembers) {
|
|
93
|
-
intents |= GatewayIntents.GuildMembers;
|
|
94
|
-
}
|
|
95
|
-
return intents;
|
|
96
|
-
}
|
|
97
109
|
export async function monitorDiscordProvider(opts = {}) {
|
|
98
110
|
const cfg = opts.config ?? loadConfig();
|
|
99
111
|
const account = resolveDiscordAccount({
|
|
@@ -104,14 +116,9 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
104
116
|
if (!token) {
|
|
105
117
|
throw new Error(`Discord bot token missing for account "${account.accountId}" (set discord.accounts.${account.accountId}.token or DISCORD_BOT_TOKEN for default).`);
|
|
106
118
|
}
|
|
107
|
-
const runtime = opts.runtime ??
|
|
108
|
-
log: console.log,
|
|
109
|
-
error: console.error,
|
|
110
|
-
exit: (code) => {
|
|
111
|
-
throw new Error(`exit ${code}`);
|
|
112
|
-
},
|
|
113
|
-
};
|
|
119
|
+
const runtime = opts.runtime ?? createNonExitingRuntime();
|
|
114
120
|
const discordCfg = account.config;
|
|
121
|
+
const discordRestFetch = resolveDiscordRestFetch(discordCfg.proxy, runtime);
|
|
115
122
|
const dmConfig = discordCfg.dm;
|
|
116
123
|
let guildEntries = discordCfg.guilds;
|
|
117
124
|
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
|
@@ -122,7 +129,7 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
122
129
|
groupPolicy === "open") {
|
|
123
130
|
runtime.log?.(warn('discord: groupPolicy defaults to "open" when channels.discord is missing; set channels.discord.groupPolicy (or channels.defaults.groupPolicy) or add channels.discord.guilds to restrict access.'));
|
|
124
131
|
}
|
|
125
|
-
let allowFrom = dmConfig?.allowFrom;
|
|
132
|
+
let allowFrom = discordCfg.allowFrom ?? dmConfig?.allowFrom;
|
|
126
133
|
const mediaMaxBytes = (opts.mediaMaxMb ?? discordCfg.mediaMaxMb ?? 8) * 1024 * 1024;
|
|
127
134
|
const textLimit = resolveTextChunkLimit(cfg, "discord", account.accountId, {
|
|
128
135
|
fallbackLimit: 2000,
|
|
@@ -130,7 +137,7 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
130
137
|
const historyLimit = Math.max(0, opts.historyLimit ?? discordCfg.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? 20);
|
|
131
138
|
const replyToMode = opts.replyToMode ?? discordCfg.replyToMode ?? "off";
|
|
132
139
|
const dmEnabled = dmConfig?.enabled ?? true;
|
|
133
|
-
const dmPolicy = dmConfig?.policy ?? "pairing";
|
|
140
|
+
const dmPolicy = discordCfg.dmPolicy ?? dmConfig?.policy ?? "pairing";
|
|
134
141
|
const groupDmEnabled = dmConfig?.groupEnabled ?? false;
|
|
135
142
|
const groupDmChannels = dmConfig?.groupChannels;
|
|
136
143
|
const nativeEnabled = resolveNativeCommandsEnabled({
|
|
@@ -155,12 +162,14 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
155
162
|
try {
|
|
156
163
|
const entries = [];
|
|
157
164
|
for (const [guildKey, guildCfg] of Object.entries(guildEntries)) {
|
|
158
|
-
if (guildKey === "*")
|
|
165
|
+
if (guildKey === "*") {
|
|
159
166
|
continue;
|
|
167
|
+
}
|
|
160
168
|
const channels = guildCfg?.channels ?? {};
|
|
161
169
|
const channelKeys = Object.keys(channels).filter((key) => key !== "*");
|
|
162
170
|
if (channelKeys.length === 0) {
|
|
163
|
-
|
|
171
|
+
const input = /^\d+$/.test(guildKey) ? `guild:${guildKey}` : guildKey;
|
|
172
|
+
entries.push({ input, guildKey });
|
|
164
173
|
continue;
|
|
165
174
|
}
|
|
166
175
|
for (const channelKey of channelKeys) {
|
|
@@ -175,14 +184,16 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
175
184
|
const resolved = await resolveDiscordChannelAllowlist({
|
|
176
185
|
token,
|
|
177
186
|
entries: entries.map((entry) => entry.input),
|
|
187
|
+
fetcher: discordRestFetch,
|
|
178
188
|
});
|
|
179
189
|
const nextGuilds = { ...guildEntries };
|
|
180
190
|
const mapping = [];
|
|
181
191
|
const unresolved = [];
|
|
182
192
|
for (const entry of resolved) {
|
|
183
193
|
const source = entries.find((item) => item.input === entry.input);
|
|
184
|
-
if (!source)
|
|
194
|
+
if (!source) {
|
|
185
195
|
continue;
|
|
196
|
+
}
|
|
186
197
|
const sourceGuild = guildEntries?.[source.guildKey] ?? {};
|
|
187
198
|
if (!entry.resolved || !entry.guildId) {
|
|
188
199
|
unresolved.push(entry.input);
|
|
@@ -225,19 +236,9 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
225
236
|
const resolvedUsers = await resolveDiscordUserAllowlist({
|
|
226
237
|
token,
|
|
227
238
|
entries: allowEntries.map((entry) => String(entry)),
|
|
239
|
+
fetcher: discordRestFetch,
|
|
228
240
|
});
|
|
229
|
-
const mapping =
|
|
230
|
-
const unresolved = [];
|
|
231
|
-
const additions = [];
|
|
232
|
-
for (const entry of resolvedUsers) {
|
|
233
|
-
if (entry.resolved && entry.id) {
|
|
234
|
-
mapping.push(`${entry.input}→${entry.id}`);
|
|
235
|
-
additions.push(entry.id);
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
unresolved.push(entry.input);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
+
const { mapping, unresolved, additions } = buildAllowlistResolutionSummary(resolvedUsers);
|
|
241
242
|
allowFrom = mergeAllowlist({ existing: allowFrom, additions });
|
|
242
243
|
summarizeMapping("discord users", mapping, unresolved, runtime);
|
|
243
244
|
}
|
|
@@ -248,28 +249,13 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
248
249
|
if (guildEntries && Object.keys(guildEntries).length > 0) {
|
|
249
250
|
const userEntries = new Set();
|
|
250
251
|
for (const guild of Object.values(guildEntries)) {
|
|
251
|
-
if (!guild || typeof guild !== "object")
|
|
252
|
+
if (!guild || typeof guild !== "object") {
|
|
252
253
|
continue;
|
|
253
|
-
const users = guild.users;
|
|
254
|
-
if (Array.isArray(users)) {
|
|
255
|
-
for (const entry of users) {
|
|
256
|
-
const trimmed = String(entry).trim();
|
|
257
|
-
if (trimmed && trimmed !== "*")
|
|
258
|
-
userEntries.add(trimmed);
|
|
259
|
-
}
|
|
260
254
|
}
|
|
255
|
+
addAllowlistUserEntriesFromConfigEntry(userEntries, guild);
|
|
261
256
|
const channels = guild.channels ?? {};
|
|
262
257
|
for (const channel of Object.values(channels)) {
|
|
263
|
-
|
|
264
|
-
continue;
|
|
265
|
-
const channelUsers = channel.users;
|
|
266
|
-
if (!Array.isArray(channelUsers))
|
|
267
|
-
continue;
|
|
268
|
-
for (const entry of channelUsers) {
|
|
269
|
-
const trimmed = String(entry).trim();
|
|
270
|
-
if (trimmed && trimmed !== "*")
|
|
271
|
-
userEntries.add(trimmed);
|
|
272
|
-
}
|
|
258
|
+
addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
|
|
273
259
|
}
|
|
274
260
|
}
|
|
275
261
|
if (userEntries.size > 0) {
|
|
@@ -277,52 +263,26 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
277
263
|
const resolvedUsers = await resolveDiscordUserAllowlist({
|
|
278
264
|
token,
|
|
279
265
|
entries: Array.from(userEntries),
|
|
266
|
+
fetcher: discordRestFetch,
|
|
280
267
|
});
|
|
281
|
-
const resolvedMap =
|
|
282
|
-
const mapping = resolvedUsers
|
|
283
|
-
.filter((entry) => entry.resolved && entry.id)
|
|
284
|
-
.map((entry) => `${entry.input}→${entry.id}`);
|
|
285
|
-
const unresolved = resolvedUsers
|
|
286
|
-
.filter((entry) => !entry.resolved)
|
|
287
|
-
.map((entry) => entry.input);
|
|
268
|
+
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
|
288
269
|
const nextGuilds = { ...guildEntries };
|
|
289
270
|
for (const [guildKey, guildConfig] of Object.entries(guildEntries ?? {})) {
|
|
290
|
-
if (!guildConfig || typeof guildConfig !== "object")
|
|
271
|
+
if (!guildConfig || typeof guildConfig !== "object") {
|
|
291
272
|
continue;
|
|
273
|
+
}
|
|
292
274
|
const nextGuild = { ...guildConfig };
|
|
293
275
|
const users = guildConfig.users;
|
|
294
276
|
if (Array.isArray(users) && users.length > 0) {
|
|
295
|
-
const additions =
|
|
296
|
-
for (const entry of users) {
|
|
297
|
-
const trimmed = String(entry).trim();
|
|
298
|
-
const resolved = resolvedMap.get(trimmed);
|
|
299
|
-
if (resolved?.resolved && resolved.id)
|
|
300
|
-
additions.push(resolved.id);
|
|
301
|
-
}
|
|
277
|
+
const additions = resolveAllowlistIdAdditions({ existing: users, resolvedMap });
|
|
302
278
|
nextGuild.users = mergeAllowlist({ existing: users, additions });
|
|
303
279
|
}
|
|
304
280
|
const channels = guildConfig.channels ?? {};
|
|
305
281
|
if (channels && typeof channels === "object") {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const channelUsers = channelConfig.users;
|
|
311
|
-
if (!Array.isArray(channelUsers) || channelUsers.length === 0)
|
|
312
|
-
continue;
|
|
313
|
-
const additions = [];
|
|
314
|
-
for (const entry of channelUsers) {
|
|
315
|
-
const trimmed = String(entry).trim();
|
|
316
|
-
const resolved = resolvedMap.get(trimmed);
|
|
317
|
-
if (resolved?.resolved && resolved.id)
|
|
318
|
-
additions.push(resolved.id);
|
|
319
|
-
}
|
|
320
|
-
nextChannels[channelKey] = {
|
|
321
|
-
...channelConfig,
|
|
322
|
-
users: mergeAllowlist({ existing: channelUsers, additions }),
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
nextGuild.channels = nextChannels;
|
|
282
|
+
nextGuild.channels = patchAllowlistUsersInConfigEntries({
|
|
283
|
+
entries: channels,
|
|
284
|
+
resolvedMap,
|
|
285
|
+
});
|
|
326
286
|
}
|
|
327
287
|
nextGuilds[guildKey] = nextGuild;
|
|
328
288
|
}
|
|
@@ -338,12 +298,14 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
338
298
|
if (shouldLogVerbose()) {
|
|
339
299
|
logVerbose(`discord: config dm=${dmEnabled ? "on" : "off"} dmPolicy=${dmPolicy} allowFrom=${summarizeAllowList(allowFrom)} groupDm=${groupDmEnabled ? "on" : "off"} groupDmChannels=${summarizeAllowList(groupDmChannels)} groupPolicy=${groupPolicy} guilds=${summarizeGuilds(guildEntries)} historyLimit=${historyLimit} mediaMaxMb=${Math.round(mediaMaxBytes / (1024 * 1024))} native=${nativeEnabled ? "on" : "off"} nativeSkills=${nativeSkillsEnabled ? "on" : "off"} accessGroups=${useAccessGroups ? "on" : "off"}`);
|
|
340
300
|
}
|
|
341
|
-
const applicationId = await fetchDiscordApplicationId(token, 4000);
|
|
301
|
+
const applicationId = await fetchDiscordApplicationId(token, 4000, discordRestFetch);
|
|
342
302
|
if (!applicationId) {
|
|
343
303
|
throw new Error("Failed to resolve Discord application id");
|
|
344
304
|
}
|
|
345
305
|
const maxDiscordCommands = 100;
|
|
346
|
-
let skillCommands = nativeEnabled && nativeSkillsEnabled
|
|
306
|
+
let skillCommands = nativeEnabled && nativeSkillsEnabled
|
|
307
|
+
? dedupeSkillCommandsForDiscord(listSkillCommandsForAgents({ cfg }))
|
|
308
|
+
: [];
|
|
347
309
|
let commandSpecs = nativeEnabled
|
|
348
310
|
? listNativeCommandSpecsForConfig(cfg, { skillCommands, provider: "discord" })
|
|
349
311
|
: [];
|
|
@@ -375,6 +337,8 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
375
337
|
runtime,
|
|
376
338
|
})
|
|
377
339
|
: null;
|
|
340
|
+
const agentComponentsConfig = discordCfg.agentComponents ?? {};
|
|
341
|
+
const agentComponentsEnabled = agentComponentsConfig.enabled ?? true;
|
|
378
342
|
const components = [
|
|
379
343
|
createDiscordCommandArgFallbackButton({
|
|
380
344
|
cfg,
|
|
@@ -383,9 +347,44 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
383
347
|
sessionPrefix,
|
|
384
348
|
}),
|
|
385
349
|
];
|
|
350
|
+
const modals = [];
|
|
386
351
|
if (execApprovalsHandler) {
|
|
387
352
|
components.push(createExecApprovalButton({ handler: execApprovalsHandler }));
|
|
388
353
|
}
|
|
354
|
+
if (agentComponentsEnabled) {
|
|
355
|
+
const componentContext = {
|
|
356
|
+
cfg,
|
|
357
|
+
discordConfig: discordCfg,
|
|
358
|
+
accountId: account.accountId,
|
|
359
|
+
guildEntries,
|
|
360
|
+
allowFrom,
|
|
361
|
+
dmPolicy,
|
|
362
|
+
runtime,
|
|
363
|
+
token,
|
|
364
|
+
};
|
|
365
|
+
components.push(createAgentComponentButton(componentContext));
|
|
366
|
+
components.push(createAgentSelectMenu(componentContext));
|
|
367
|
+
components.push(createDiscordComponentButton(componentContext));
|
|
368
|
+
components.push(createDiscordComponentStringSelect(componentContext));
|
|
369
|
+
components.push(createDiscordComponentUserSelect(componentContext));
|
|
370
|
+
components.push(createDiscordComponentRoleSelect(componentContext));
|
|
371
|
+
components.push(createDiscordComponentMentionableSelect(componentContext));
|
|
372
|
+
components.push(createDiscordComponentChannelSelect(componentContext));
|
|
373
|
+
modals.push(createDiscordComponentModal(componentContext));
|
|
374
|
+
}
|
|
375
|
+
class DiscordStatusReadyListener extends ReadyListener {
|
|
376
|
+
async handle(_data, client) {
|
|
377
|
+
const gateway = client.getPlugin("gateway");
|
|
378
|
+
if (!gateway) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const presence = resolveDiscordPresenceUpdate(discordCfg);
|
|
382
|
+
if (!presence) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
gateway.updatePresence(presence);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
389
388
|
const client = new Client({
|
|
390
389
|
baseUrl: "http://localhost",
|
|
391
390
|
deploySecret: "a",
|
|
@@ -395,17 +394,10 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
395
394
|
autoDeploy: false,
|
|
396
395
|
}, {
|
|
397
396
|
commands,
|
|
398
|
-
listeners: [],
|
|
397
|
+
listeners: [new DiscordStatusReadyListener()],
|
|
399
398
|
components,
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
reconnect: {
|
|
403
|
-
maxAttempts: Number.POSITIVE_INFINITY,
|
|
404
|
-
},
|
|
405
|
-
intents: resolveDiscordGatewayIntents(discordCfg.intents),
|
|
406
|
-
autoInteractions: true,
|
|
407
|
-
}),
|
|
408
|
-
]);
|
|
399
|
+
modals,
|
|
400
|
+
}, [createDiscordGatewayPlugin({ discordConfig: discordCfg, runtime })]);
|
|
409
401
|
await deployDiscordCommands({ client, runtime, enabled: nativeEnabled });
|
|
410
402
|
const logger = createSubsystemLogger("discord/monitor");
|
|
411
403
|
const guildHistories = new Map();
|
|
@@ -469,6 +461,9 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
469
461
|
await execApprovalsHandler.start();
|
|
470
462
|
}
|
|
471
463
|
const gateway = client.getPlugin("gateway");
|
|
464
|
+
if (gateway) {
|
|
465
|
+
registerGateway(account.accountId, gateway);
|
|
466
|
+
}
|
|
472
467
|
const gatewayEmitter = getDiscordGatewayEmitter(gateway);
|
|
473
468
|
const stopGatewayLogging = attachDiscordGatewayLogging({
|
|
474
469
|
emitter: gatewayEmitter,
|
|
@@ -476,8 +471,9 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
476
471
|
});
|
|
477
472
|
const abortSignal = opts.abortSignal;
|
|
478
473
|
const onAbort = () => {
|
|
479
|
-
if (!gateway)
|
|
474
|
+
if (!gateway) {
|
|
480
475
|
return;
|
|
476
|
+
}
|
|
481
477
|
// Carbon emits an error when maxAttempts is 0; keep a one-shot listener to avoid
|
|
482
478
|
// an unhandled error after we tear down listeners during abort.
|
|
483
479
|
gatewayEmitter?.once("error", () => { });
|
|
@@ -495,10 +491,12 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
495
491
|
let helloTimeoutId;
|
|
496
492
|
const onGatewayDebug = (msg) => {
|
|
497
493
|
const message = String(msg);
|
|
498
|
-
if (!message.includes("WebSocket connection opened"))
|
|
494
|
+
if (!message.includes("WebSocket connection opened")) {
|
|
499
495
|
return;
|
|
500
|
-
|
|
496
|
+
}
|
|
497
|
+
if (helloTimeoutId) {
|
|
501
498
|
clearTimeout(helloTimeoutId);
|
|
499
|
+
}
|
|
502
500
|
helloTimeoutId = setTimeout(() => {
|
|
503
501
|
if (!gateway?.isConnected) {
|
|
504
502
|
runtime.log?.(danger(`connection stalled: no HELLO received within ${HELLO_TIMEOUT_MS}ms, forcing reconnect`));
|
|
@@ -528,9 +526,11 @@ export async function monitorDiscordProvider(opts = {}) {
|
|
|
528
526
|
});
|
|
529
527
|
}
|
|
530
528
|
finally {
|
|
529
|
+
unregisterGateway(account.accountId);
|
|
531
530
|
stopGatewayLogging();
|
|
532
|
-
if (helloTimeoutId)
|
|
531
|
+
if (helloTimeoutId) {
|
|
533
532
|
clearTimeout(helloTimeoutId);
|
|
533
|
+
}
|
|
534
534
|
gatewayEmitter?.removeListener("debug", onGatewayDebug);
|
|
535
535
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
536
536
|
if (execApprovalsHandler) {
|
|
@@ -549,3 +549,8 @@ async function clearDiscordNativeCommands(params) {
|
|
|
549
549
|
params.runtime.error?.(danger(`discord: failed to clear native commands: ${String(err)}`));
|
|
550
550
|
}
|
|
551
551
|
}
|
|
552
|
+
export const __testing = {
|
|
553
|
+
createDiscordGatewayPlugin,
|
|
554
|
+
dedupeSkillCommandsForDiscord,
|
|
555
|
+
resolveDiscordRestFetch,
|
|
556
|
+
};
|
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export function resolveReplyContext(message, resolveDiscordMessageText
|
|
1
|
+
import { resolveTimestampMs } from "./format.js";
|
|
2
|
+
import { resolveDiscordSenderIdentity } from "./sender-identity.js";
|
|
3
|
+
export function resolveReplyContext(message, resolveDiscordMessageText) {
|
|
4
4
|
const referenced = message.referencedMessage;
|
|
5
|
-
if (!referenced?.author)
|
|
5
|
+
if (!referenced?.author) {
|
|
6
6
|
return null;
|
|
7
|
+
}
|
|
7
8
|
const referencedText = resolveDiscordMessageText(referenced, {
|
|
8
9
|
includeForwarded: true,
|
|
9
10
|
});
|
|
10
|
-
if (!referencedText)
|
|
11
|
+
if (!referencedText) {
|
|
11
12
|
return null;
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from: fromLabel,
|
|
17
|
-
timestamp: resolveTimestampMs(referenced.timestamp),
|
|
18
|
-
body,
|
|
19
|
-
envelope: options?.envelope,
|
|
13
|
+
}
|
|
14
|
+
const sender = resolveDiscordSenderIdentity({
|
|
15
|
+
author: referenced.author,
|
|
16
|
+
pluralkitInfo: null,
|
|
20
17
|
});
|
|
18
|
+
return {
|
|
19
|
+
id: referenced.id,
|
|
20
|
+
channelId: referenced.channelId,
|
|
21
|
+
sender: sender.tag ?? sender.label ?? "unknown",
|
|
22
|
+
body: referencedText,
|
|
23
|
+
timestamp: resolveTimestampMs(referenced.timestamp),
|
|
24
|
+
};
|
|
21
25
|
}
|
|
22
|
-
export function buildDirectLabel(author) {
|
|
23
|
-
const username =
|
|
24
|
-
return `${username} user id:${author.id}`;
|
|
26
|
+
export function buildDirectLabel(author, tagOverride) {
|
|
27
|
+
const username = tagOverride?.trim() || resolveDiscordSenderIdentity({ author, pluralkitInfo: null }).tag;
|
|
28
|
+
return `${username ?? "unknown"} user id:${author.id}`;
|
|
25
29
|
}
|
|
26
30
|
export function buildGuildLabel(params) {
|
|
27
31
|
const { guild, channelName, channelId } = params;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { convertMarkdownTables } from "../../markdown/tables.js";
|
|
2
2
|
import { chunkDiscordTextWithMode } from "../chunk.js";
|
|
3
|
-
import { sendMessageDiscord } from "../send.js";
|
|
3
|
+
import { sendMessageDiscord, sendVoiceMessageDiscord } from "../send.js";
|
|
4
4
|
export async function deliverDiscordReply(params) {
|
|
5
5
|
const chunkLimit = Math.min(params.textLimit, 2000);
|
|
6
6
|
for (const payload of params.replies) {
|
|
@@ -8,36 +8,67 @@ export async function deliverDiscordReply(params) {
|
|
|
8
8
|
const rawText = payload.text ?? "";
|
|
9
9
|
const tableMode = params.tableMode ?? "code";
|
|
10
10
|
const text = convertMarkdownTables(rawText, tableMode);
|
|
11
|
-
if (!text && mediaList.length === 0)
|
|
11
|
+
if (!text && mediaList.length === 0) {
|
|
12
12
|
continue;
|
|
13
|
+
}
|
|
13
14
|
const replyTo = params.replyToId?.trim() || undefined;
|
|
14
15
|
if (mediaList.length === 0) {
|
|
15
|
-
let isFirstChunk = true;
|
|
16
16
|
const mode = params.chunkMode ?? "length";
|
|
17
17
|
const chunks = chunkDiscordTextWithMode(text, {
|
|
18
18
|
maxChars: chunkLimit,
|
|
19
19
|
maxLines: params.maxLinesPerMessage,
|
|
20
20
|
chunkMode: mode,
|
|
21
21
|
});
|
|
22
|
-
if (!chunks.length && text)
|
|
22
|
+
if (!chunks.length && text) {
|
|
23
23
|
chunks.push(text);
|
|
24
|
+
}
|
|
24
25
|
for (const chunk of chunks) {
|
|
25
26
|
const trimmed = chunk.trim();
|
|
26
|
-
if (!trimmed)
|
|
27
|
+
if (!trimmed) {
|
|
27
28
|
continue;
|
|
29
|
+
}
|
|
28
30
|
await sendMessageDiscord(params.target, trimmed, {
|
|
29
31
|
token: params.token,
|
|
30
32
|
rest: params.rest,
|
|
31
33
|
accountId: params.accountId,
|
|
32
|
-
replyTo
|
|
34
|
+
replyTo,
|
|
33
35
|
});
|
|
34
|
-
isFirstChunk = false;
|
|
35
36
|
}
|
|
36
37
|
continue;
|
|
37
38
|
}
|
|
38
39
|
const firstMedia = mediaList[0];
|
|
39
|
-
if (!firstMedia)
|
|
40
|
+
if (!firstMedia) {
|
|
40
41
|
continue;
|
|
42
|
+
}
|
|
43
|
+
// Voice message path: audioAsVoice flag routes through sendVoiceMessageDiscord
|
|
44
|
+
if (payload.audioAsVoice) {
|
|
45
|
+
await sendVoiceMessageDiscord(params.target, firstMedia, {
|
|
46
|
+
token: params.token,
|
|
47
|
+
rest: params.rest,
|
|
48
|
+
accountId: params.accountId,
|
|
49
|
+
replyTo,
|
|
50
|
+
});
|
|
51
|
+
// Voice messages cannot include text; send remaining text separately if present
|
|
52
|
+
if (text.trim()) {
|
|
53
|
+
await sendMessageDiscord(params.target, text, {
|
|
54
|
+
token: params.token,
|
|
55
|
+
rest: params.rest,
|
|
56
|
+
accountId: params.accountId,
|
|
57
|
+
replyTo,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// Additional media items are sent as regular attachments (voice is single-file only)
|
|
61
|
+
for (const extra of mediaList.slice(1)) {
|
|
62
|
+
await sendMessageDiscord(params.target, "", {
|
|
63
|
+
token: params.token,
|
|
64
|
+
rest: params.rest,
|
|
65
|
+
mediaUrl: extra,
|
|
66
|
+
accountId: params.accountId,
|
|
67
|
+
replyTo,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
41
72
|
await sendMessageDiscord(params.target, text, {
|
|
42
73
|
token: params.token,
|
|
43
74
|
rest: params.rest,
|
|
@@ -51,6 +82,7 @@ export async function deliverDiscordReply(params) {
|
|
|
51
82
|
rest: params.rest,
|
|
52
83
|
mediaUrl: extra,
|
|
53
84
|
accountId: params.accountId,
|
|
85
|
+
replyTo,
|
|
54
86
|
});
|
|
55
87
|
}
|
|
56
88
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ProxyAgent, fetch as undiciFetch } from "undici";
|
|
2
|
+
import { danger } from "../../globals.js";
|
|
3
|
+
import { wrapFetchWithAbortSignal } from "../../infra/fetch.js";
|
|
4
|
+
export function resolveDiscordRestFetch(proxyUrl, runtime) {
|
|
5
|
+
const proxy = proxyUrl?.trim();
|
|
6
|
+
if (!proxy) {
|
|
7
|
+
return fetch;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const agent = new ProxyAgent(proxy);
|
|
11
|
+
const fetcher = ((input, init) => undiciFetch(input, {
|
|
12
|
+
...init,
|
|
13
|
+
dispatcher: agent,
|
|
14
|
+
}));
|
|
15
|
+
runtime.log?.("discord: rest proxy enabled");
|
|
16
|
+
return wrapFetchWithAbortSignal(fetcher);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
runtime.error?.(danger(`discord: invalid rest proxy: ${String(err)}`));
|
|
20
|
+
return fetch;
|
|
21
|
+
}
|
|
22
|
+
}
|