@openclaw/discord 2026.7.2-beta.2 → 2026.7.2-beta.3

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.
Files changed (85) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{activities-api-D0D_87n3.js → activities-api-DS1L7KRY.js} +15 -42
  3. package/dist/activities-api.js +1 -1
  4. package/dist/{allow-list-B7qOH5xu.js → allow-list-DzKrtfah.js} +18 -7
  5. package/dist/{api-B88T4rFN.js → api-C43z8vUm.js} +3 -1
  6. package/dist/api.js +25 -16
  7. package/dist/{approval-handler.runtime-B7E1-x5q.js → approval-handler.runtime-BbkfPoGc.js} +5 -6
  8. package/dist/{conversation-identity-BPcbhCAH.js → approval-message-safety-DrLlgIPz.js} +48 -2
  9. package/dist/{audit-CjpnY1yb.js → audit-BC6bgPMX.js} +3 -3
  10. package/dist/{channel-BDfKr14H.js → channel-5MfaC2IE.js} +18 -18
  11. package/dist/{channel-actions-BQct-o4T.js → channel-actions-DicWTbYH.js} +2 -2
  12. package/dist/{channel-actions.runtime-CC4QwYVO.js → channel-actions.runtime-D9Qadn-l.js} +8 -8
  13. package/dist/channel-config-api.js +1 -1
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/{channel.setup-BS4gd8sc.js → channel.setup-CJXfFclP.js} +3 -3
  16. package/dist/{chunk-CHpY_lsO.js → chunk-CWzmeWf_.js} +9 -49
  17. package/dist/{config-schema-CoDck1GW.js → config-schema-BxrgfSMD.js} +4 -0
  18. package/dist/{directory-config-G1QwBIdi.js → directory-config-CmukHSms.js} +1 -1
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-nfvekMil.js → directory-live-BYlCRO__.js} +3 -3
  21. package/dist/{doctor-Bq4pJAQk.js → doctor-Ci7USQAW.js} +1 -1
  22. package/dist/{handle-action.guild-admin-LYY75_Oa.js → handle-action.guild-admin-Bsk2YBPs.js} +2 -2
  23. package/dist/index.js +2 -2
  24. package/dist/{manager.runtime-w6VVYQMl.js → manager.runtime-Cc8vS-M7.js} +98 -145
  25. package/dist/message-handler-CWJ-mQvH.js +590 -0
  26. package/dist/{message-handler.preflight-DnAH04Ss.js → message-handler.preflight-DK46_qbS.js} +16 -15
  27. package/dist/{message-handler.process-ClgKz8I5.js → message-handler.process-BK0mjFJH.js} +37 -61
  28. package/dist/{message-utils-BU3gc01v.js → message-utils-Cfe6CZ6N.js} +1 -1
  29. package/dist/{outbound-adapter-ByoXsR-V.js → outbound-adapter-B2_oa-zV.js} +36 -5
  30. package/dist/{outbound-components-7wAolLuS.js → outbound-components-BGhk6HI3.js} +3 -3
  31. package/dist/{outbound-session-route-D4QqePZN.js → outbound-session-route-M2bEY9tI.js} +36 -6
  32. package/dist/{pluralkit-r4wiI2yy.js → pluralkit-CT0VRsZd.js} +1 -1
  33. package/dist/{probe-WKeTYyJX.js → probe-C3SCKyYU.js} +1 -1
  34. package/dist/{probe.runtime-CRY-qUke.js → probe.runtime-D55QqC9u.js} +1 -1
  35. package/dist/{provider-PRlF_lZm.js → provider-HW0G-2l6.js} +868 -794
  36. package/dist/{provider-session.runtime-BZPUZRjn.js → provider-session.runtime-cCfGMsF_.js} +3 -3
  37. package/dist/provider.runtime-BWCRsVoT.js +2 -0
  38. package/dist/{resolve-allowlist-common-QN7VMZaC.js → resolve-allowlist-common-CJlqw_nC.js} +2 -2
  39. package/dist/{resolve-channels-BO9NUPlS.js → resolve-channels-9KcG3mLg.js} +4 -4
  40. package/dist/{resolve-users-CU3oG5-m.js → resolve-users-GCGf3oV0.js} +3 -3
  41. package/dist/{runtime-CCf5nkV3.js → runtime-CD5MRZkD.js} +1 -2
  42. package/dist/{runtime-BsefAQ9q.js → runtime-Z2qkKakn.js} +9 -8
  43. package/dist/runtime-api.actions.js +2 -2
  44. package/dist/runtime-api.js +23 -22
  45. package/dist/runtime-api.lookup.js +5 -5
  46. package/dist/runtime-api.monitor-C3EDYJqk.js +6 -0
  47. package/dist/runtime-api.monitor.js +8 -8
  48. package/dist/runtime-api.send.js +6 -5
  49. package/dist/runtime-api.threads.js +3 -3
  50. package/dist/{secret-config-contract-BDNrRWvd.js → secret-config-contract-B1akrlyY.js} +1 -0
  51. package/dist/secret-contract-api.js +1 -1
  52. package/dist/security-audit-contract-api.js +1 -1
  53. package/dist/{security-audit.runtime-K0nkzjzJ.js → security-audit.runtime-DEEywczv.js} +1 -1
  54. package/dist/{send-JJzVo_sK.js → send-CSRxNNgq.js} +7 -86
  55. package/dist/{send.components-CCRW54gK.js → send.components-DLqzOEPJ.js} +5 -4
  56. package/dist/{send.outbound-Cvulb-k_.js → send.outbound-C1SfX20w.js} +4 -3
  57. package/dist/send.reactions-Cj4ugX3F.js +85 -0
  58. package/dist/send.receipt-CuwRrpFz.js +48 -0
  59. package/dist/{send.shared-XuOTO1dW.js → send.shared-Dber6X57.js} +2 -2
  60. package/dist/{sender-identity-C62lBe18.js → sender-identity-mG_zsdox.js} +1 -1
  61. package/dist/session-binding-contract-api.js +1 -1
  62. package/dist/setup-plugin-api.js +1 -1
  63. package/dist/{shared-Bngr0I-v.js → shared-BEhmAdMY.js} +5 -5
  64. package/dist/{subagent-hooks-mSxRv4AE.js → subagent-hooks-Wrk61DwY.js} +2 -2
  65. package/dist/subagent-hooks-api.js +10 -1
  66. package/dist/subagent-progress-B2fpHe3m.js +662 -0
  67. package/dist/{system-events-BANBRAe3.js → system-events-AhfcKRRb.js} +2 -2
  68. package/dist/{target-resolver-BaEmTxeK.js → target-resolver-vqLA450R.js} +2 -2
  69. package/dist/targets-BjEMIe8t.js +3 -0
  70. package/dist/{thread-bindings-4MV-u8vU.js → thread-bindings-CJQoXuWY.js} +4 -4
  71. package/dist/{thread-bindings.discord-api-DXfXsHGZ.js → thread-bindings.discord-api-mNCWlgvM.js} +4 -4
  72. package/dist/{thread-bindings.manager-DJ4cO5Eu.js → thread-bindings.manager-D1z8mK4b.js} +3 -3
  73. package/dist/{timeouts-D5lWili0.js → timeouts-B9cy6RvQ.js} +1 -6
  74. package/dist/{transcripts-source-TDZcMriu.js → transcripts-source-DjDbt14x.js} +1 -1
  75. package/dist/transcripts-source-api.js +1 -1
  76. package/dist/{typing-CKd2NMWG.js → typing-wxtm1NlF.js} +2 -2
  77. package/npm-shrinkwrap.json +3 -3
  78. package/openclaw.plugin.json +10 -0
  79. package/package.json +4 -4
  80. package/dist/approval-message-safety-C-8BL6Kv.js +0 -47
  81. package/dist/message-handler-DExaghWK.js +0 -331
  82. package/dist/provider.runtime-BX8GcCYx.js +0 -2
  83. package/dist/runtime-api.monitor-DCS_ETft.js +0 -6
  84. package/dist/targets-fjJt3PYG.js +0 -3
  85. package/dist/{security-audit-aLbWmUjl.js → security-audit-DtT0SIns.js} +1 -1
@@ -1,24 +1,23 @@
1
- import { C as ThreadUpdateListener, E as Plugin, F as CommandWithSubcommands, I as Guild, J as Container, K as Button, L as Message, P as Command, R as User, St as getChannelMessage, T as Client, U as Modal, Zt as __exportAll, _ as MessageCreateListener, b as PresenceUpdateListener, et as Row, g as InteractionCreateListener, gt as createThread, h as GuildDeleteListener, it as TextDisplay, k as RateLimitError, m as GuildCreateListener, nt as Separator, p as discord_exports, rt as StringSelectMenu, st as BaseMessageInteractiveComponent, t as chunkDiscordTextWithMode, v as MessageReactionAddListener, x as ReadyListener, y as MessageReactionRemoveListener, yt as editChannel } from "./chunk-CHpY_lsO.js";
1
+ import { C as Client, D as RateLimitError, F as Message, I as User, K as Container, M as Command, N as CommandWithSubcommands, P as Guild, Q as Row, V as Modal, W as Button, Yt as __exportAll, _ as MessageReactionRemoveListener, _t as editChannel, at as BaseMessageInteractiveComponent, bt as getChannelMessage, d as discord_exports, et as Separator, f as GuildCreateListener, g as MessageReactionAddListener, h as MessageCreateListener, m as InteractionCreateListener, mt as createThread, nt as TextDisplay, p as GuildDeleteListener, t as chunkDiscordTextWithMode, tt as StringSelectMenu, v as PresenceUpdateListener, w as Plugin, x as ThreadUpdateListener, y as ReadyListener } from "./chunk-CWzmeWf_.js";
2
2
  import { c as resolveDiscordAccountAllowFrom, d as resolveDiscordAccountDmPolicy, f as resolveDiscordMaxLinesPerMessage, p as normalizeDiscordToken, s as resolveDiscordAccount } from "./accounts-CMd4nzLB.js";
3
- import { n as getDiscordActivitiesRuntime } from "./runtime-CCf5nkV3.js";
4
- import { C as parseDiscordComponentCustomId, D as decodeCustomIdComponent, E as parseDiscordModalCustomIdForInteraction, O as encodeCustomIdComponent, S as parseDiscordActivityCustomIdForInteraction, T as parseDiscordModalCustomId, c as parseExecApprovalData, v as buildDiscordActivityCustomId, w as parseDiscordComponentCustomIdForInteraction } from "./outbound-session-route-D4QqePZN.js";
5
- import { C as resolveTimestampMs, a as normalizeDiscordSlug, b as formatDiscordReactionEmoji, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordCommandOwnerAllowFrom, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAllowFrom, h as resolveDiscordOwnerAccess, i as normalizeDiscordDisplaySlug, l as resolveDiscordChannelPolicyCommandAuthorizer, m as resolveDiscordMemberAllowed, n as isDiscordGroupAllowedByPolicy, o as resolveDiscordAllowListMatch, p as resolveDiscordMemberAccessState, r as normalizeDiscordAllowList, t as allowListMatches, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./allow-list-B7qOH5xu.js";
6
- import { D as canViewDiscordGuildChannel, F as createDiscordRestClient, H as registerGateway, K as validateDiscordProxyUrl, U as unregisterGateway, q as withValidatedDiscordProxy, z as DISCORD_REST_TIMEOUT_MS } from "./send.shared-XuOTO1dW.js";
7
- import { _ as resolveDiscordModalEntryWithPersistence, g as resolveDiscordComponentEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-CCRW54gK.js";
3
+ import { n as getDiscordActivitiesRuntime } from "./runtime-CD5MRZkD.js";
4
+ import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, k as encodeCustomIdComponent, l as parseExecApprovalData, s as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./outbound-session-route-M2bEY9tI.js";
5
+ import { D as canViewDiscordGuildChannel, F as createDiscordRestClient, H as registerGateway, K as validateDiscordProxyUrl, U as unregisterGateway, q as withValidatedDiscordProxy, z as DISCORD_REST_TIMEOUT_MS } from "./send.shared-Dber6X57.js";
6
+ import { _ as resolveDiscordModalEntryWithPersistence, g as resolveDiscordComponentEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-DLqzOEPJ.js";
8
7
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
9
- import { a as isDiscordRateLimitResponseBody, o as summarizeDiscordResponseBody } from "./api-B88T4rFN.js";
10
- import { a as formatMention, t as sendMessageDiscord } from "./send.outbound-Cvulb-k_.js";
8
+ import { a as isDiscordRateLimitResponseBody, o as summarizeDiscordResponseBody } from "./api-C43z8vUm.js";
9
+ import { C as resolveTimestampMs, a as normalizeDiscordSlug, b as formatDiscordReactionEmoji, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordCommandOwnerAllowFrom, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAllowFrom, h as resolveDiscordOwnerAccess, i as normalizeDiscordDisplaySlug, l as resolveDiscordChannelPolicyCommandAuthorizer, m as resolveDiscordMemberAllowed, n as isDiscordGroupAllowedByPolicy, o as resolveDiscordAllowListMatch, p as resolveDiscordMemberAccessState, r as normalizeDiscordAllowList, t as allowListMatches, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./allow-list-DzKrtfah.js";
10
+ import { a as formatMention, t as sendMessageDiscord } from "./send.outbound-C1SfX20w.js";
11
11
  import { i as setPresence, t as clearPresences } from "./presence-cache-z1N8MbJ3.js";
12
- import { s as sendVoiceMessageDiscord } from "./send-JJzVo_sK.js";
13
- import { d as withAbortTimeout, l as raceWithTimeout } from "./timeouts-D5lWili0.js";
14
- import { a as isDiscordExecApprovalClientEnabled, r as getDiscordExecApprovalApprovers, t as resolveDiscordConversationIdentity } from "./conversation-identity-BPcbhCAH.js";
15
- import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BO9NUPlS.js";
16
- import { t as resolveDiscordUserAllowlist } from "./resolve-users-CU3oG5-m.js";
17
- import { _ as formatThreadBindingDurationLabel, a as isThreadArchived, d as resolveDiscordChannelNameSafe, f as resolveDiscordChannelParentIdSafe, l as resolveDiscordChannelIdSafe, m as resolveDiscordChannelTopicSafe, p as resolveDiscordChannelParentSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-DXfXsHGZ.js";
18
- import { r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-WKeTYyJX.js";
19
- import { d as resolveDiscordMessageChannelId, n as resolveDiscordForwardedMessagesTextFromSnapshots, t as resolveDiscordEmbedText, u as resolveDiscordChannelInfo } from "./message-utils-BU3gc01v.js";
20
- import { t as resolveDiscordSenderIdentity } from "./sender-identity-C62lBe18.js";
21
- import { n as formatDiscordApprovalDisplayValue, t as DISCORD_APPROVAL_ALLOWED_MENTIONS } from "./approval-message-safety-C-8BL6Kv.js";
12
+ import { n as sendVoiceMessageDiscord } from "./send-CSRxNNgq.js";
13
+ import { c as raceWithTimeout, u as withAbortTimeout } from "./timeouts-B9cy6RvQ.js";
14
+ import { a as getDiscordExecApprovalApprovers, n as formatDiscordApprovalDisplayValue, r as resolveDiscordConversationIdentity, s as isDiscordExecApprovalClientEnabled, t as DISCORD_APPROVAL_ALLOWED_MENTIONS } from "./approval-message-safety-DrLlgIPz.js";
15
+ import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-9KcG3mLg.js";
16
+ import { t as resolveDiscordUserAllowlist } from "./resolve-users-GCGf3oV0.js";
17
+ import { _ as formatThreadBindingDurationLabel, a as isThreadArchived, d as resolveDiscordChannelNameSafe, f as resolveDiscordChannelParentIdSafe, l as resolveDiscordChannelIdSafe, m as resolveDiscordChannelTopicSafe, p as resolveDiscordChannelParentSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-mNCWlgvM.js";
18
+ import { r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-C3SCKyYU.js";
19
+ import { d as resolveDiscordMessageChannelId, n as resolveDiscordForwardedMessagesTextFromSnapshots, t as resolveDiscordEmbedText, u as resolveDiscordChannelInfo } from "./message-utils-Cfe6CZ6N.js";
20
+ import { t as resolveDiscordSenderIdentity } from "./sender-identity-mG_zsdox.js";
22
21
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
23
22
  import { buildAgentSessionKey, deriveLastRoutePolicy, isAcpSessionKey, isSubagentSessionKey, parseAgentSessionKey, resolveAgentIdFromSessionKey, resolveAgentRoute } from "openclaw/plugin-sdk/routing";
24
23
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId, normalizeStringEntries, normalizeStringEntriesLower, summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -33,11 +32,11 @@ import { Check, Errors } from "typebox/value";
33
32
  import { inspect } from "node:util";
34
33
  import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
35
34
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
36
- import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
37
35
  import { fetchWithSsrFGuard, formatErrorMessage as formatErrorMessage$1 } from "openclaw/plugin-sdk/ssrf-runtime";
38
36
  import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent, resolveEnvHttpProxyAgentOptions, wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
39
37
  import { createNonExitingRuntime, createSubsystemLogger, danger, formatDurationSeconds, isVerbose, logVerbose, shouldLogVerbose, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
40
38
  import { sliceUtf16Safe, truncateUtf16Safe, withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
39
+ import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, canonicalizeAllowlistWithResolvedIds, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
41
40
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
42
41
  import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
43
42
  import { chunkItems, sanitizeAssistantVisibleText, sanitizeAssistantVisibleTextWithProfile } from "openclaw/plugin-sdk/text-chunking";
@@ -51,9 +50,10 @@ import { resolvePinnedMainDmOwnerFromAllowlist as resolvePinnedMainDmOwnerFromAl
51
50
  import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
52
51
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
53
52
  import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
54
- import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, canonicalizeAllowlistWithResolvedIds, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
53
+ import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
55
54
  import { buildPairingReply, upsertChannelPairingRequest, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
56
55
  import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, isProfileInCooldown, loadModelCatalog, resolveAgentAvatar, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
56
+ import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
57
57
  import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
58
58
  import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
59
59
  import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
@@ -62,7 +62,7 @@ import { createChannelIngressResolver, defineStableChannelIngressIdentity, readC
62
62
  import { ModelSelectionLockedError, applyModelOverrideToSessionEntry, resolveChannelModelOverride } from "openclaw/plugin-sdk/model-session-runtime";
63
63
  import { completeWithPreparedSimpleCompletionModel, extractAssistantText, prepareSimpleCompletionModelForAgent } from "openclaw/plugin-sdk/simple-completion-runtime";
64
64
  import { getSessionEntry, listSessionEntries, patchSessionEntry, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1 } from "openclaw/plugin-sdk/session-store-runtime";
65
- import { formatInboundEnvelope, resolveEnvelopeFormatOptions, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
65
+ import { formatInboundEnvelope, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
66
66
  import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
67
67
  import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
68
68
  import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-status-runtime";
@@ -1439,9 +1439,11 @@ var DiscordMessageListener = class extends MessageCreateListener {
1439
1439
  }
1440
1440
  async handle(data, client) {
1441
1441
  this.onEvent?.();
1442
- Promise.resolve().then(() => this.handler(data, client)).catch((err) => {
1442
+ try {
1443
+ await this.handler(data, client);
1444
+ } catch (err) {
1443
1445
  (this.logger ?? discordEventQueueLog).error(danger(`discord handler failed: ${String(err)}`));
1444
- });
1446
+ }
1445
1447
  }
1446
1448
  };
1447
1449
  var DiscordInteractionListener = class extends InteractionCreateListener {
@@ -1719,6 +1721,62 @@ var DiscordThreadUpdateListener = class extends ThreadUpdateListener {
1719
1721
  }
1720
1722
  };
1721
1723
  //#endregion
1724
+ //#region extensions/discord/src/internal/gateway-dispatch.ts
1725
+ function dispatchVoiceGatewayEvent(client, type, data) {
1726
+ const guildId = readGuildId(data);
1727
+ if (!guildId) return;
1728
+ const adapter = (client.getPlugin("voice")?.adapters)?.get(guildId);
1729
+ const voiceServerUpdate = GatewayDispatchEvents.VoiceServerUpdate;
1730
+ const voiceStateUpdate = GatewayDispatchEvents.VoiceStateUpdate;
1731
+ if (type === voiceServerUpdate) adapter?.onVoiceServerUpdate?.(data);
1732
+ if (type === voiceStateUpdate) adapter?.onVoiceStateUpdate?.(data);
1733
+ }
1734
+ function mapGatewayDispatchData(client, type, data) {
1735
+ const messageCreate = GatewayDispatchEvents.MessageCreate;
1736
+ const reactionAdd = GatewayDispatchEvents.MessageReactionAdd;
1737
+ const reactionRemove = GatewayDispatchEvents.MessageReactionRemove;
1738
+ if (type === messageCreate) return createMessageDispatchData(client, data);
1739
+ if (type === reactionAdd || type === reactionRemove) return createReactionDispatchData(client, data);
1740
+ return data;
1741
+ }
1742
+ function createMessageDispatchData(client, data) {
1743
+ const message = new Message(client, data);
1744
+ return {
1745
+ ...data,
1746
+ id: data.id,
1747
+ channel_id: data.channel_id,
1748
+ channelId: data.channel_id,
1749
+ message,
1750
+ author: message.author ?? (data.author ? new User(client, data.author) : null),
1751
+ member: data.member,
1752
+ rawMember: data.member,
1753
+ guild: data.guild_id ? new Guild(client, data.guild_id) : null
1754
+ };
1755
+ }
1756
+ function createReactionDispatchData(client, data) {
1757
+ const userRaw = data.member?.user && typeof data.member.user === "object" ? {
1758
+ id: data.user_id,
1759
+ username: "",
1760
+ ...data.member.user
1761
+ } : {
1762
+ id: data.user_id,
1763
+ username: ""
1764
+ };
1765
+ return {
1766
+ ...data,
1767
+ user: new User(client, userRaw),
1768
+ rawMember: data.member,
1769
+ guild: data.guild_id ? new Guild(client, data.guild_id) : null,
1770
+ message: new Message(client, {
1771
+ id: data.message_id,
1772
+ channelId: data.channel_id
1773
+ })
1774
+ };
1775
+ }
1776
+ function readGuildId(data) {
1777
+ return data && typeof data === "object" && typeof data.guild_id === "string" ? data.guild_id : void 0;
1778
+ }
1779
+ //#endregion
1722
1780
  //#region extensions/discord/src/monitor/dm-command-decision.ts
1723
1781
  async function handleDiscordDmCommandDecision(params) {
1724
1782
  if (params.senderAccess.decision === "allow") return true;
@@ -2326,16 +2384,23 @@ function shouldBypassConfiguredAcpGuildGuards(commandName) {
2326
2384
  //#endregion
2327
2385
  //#region extensions/discord/src/monitor/inbound-context.ts
2328
2386
  function createDiscordSupplementalContextAccessChecker(params) {
2387
+ const userAllowList = params.channelConfig?.users ?? params.guildInfo?.users ?? [];
2388
+ const roleAllowList = params.channelConfig?.roles ?? params.guildInfo?.roles ?? [];
2389
+ const allowFrom = [...userAllowList, ...roleAllowList];
2329
2390
  return (sender) => {
2330
- if (!params.isGuild) return true;
2331
- return resolveDiscordMemberAllowed({
2332
- userAllowList: params.channelConfig?.users ?? params.guildInfo?.users,
2333
- roleAllowList: params.channelConfig?.roles ?? params.guildInfo?.roles,
2334
- memberRoleIds: sender.memberRoleIds ?? [],
2335
- userId: sender.id ?? "",
2336
- userName: sender.name,
2337
- userTag: sender.tag,
2338
- allowNameMatching: params.allowNameMatching
2391
+ return resolveInboundSupplementalSenderAllowed({
2392
+ isGroup: params.isGuild,
2393
+ groupPolicy: allowFrom.length === 0 ? "open" : "allowlist",
2394
+ allowFrom,
2395
+ isSenderAllowed: () => resolveDiscordMemberAllowed({
2396
+ userAllowList,
2397
+ roleAllowList,
2398
+ memberRoleIds: sender.memberRoleIds ?? [],
2399
+ userId: sender.id ?? "",
2400
+ userName: sender.name,
2401
+ userTag: sender.tag,
2402
+ allowNameMatching: params.allowNameMatching
2403
+ })
2339
2404
  });
2340
2405
  };
2341
2406
  }
@@ -5240,62 +5305,6 @@ function canResumeAfterGatewayClose(code) {
5240
5305
  return !nonResumableGatewayCloseCodes.has(code);
5241
5306
  }
5242
5307
  //#endregion
5243
- //#region extensions/discord/src/internal/gateway-dispatch.ts
5244
- function dispatchVoiceGatewayEvent(client, type, data) {
5245
- const guildId = readGuildId(data);
5246
- if (!guildId) return;
5247
- const adapter = (client.getPlugin("voice")?.adapters)?.get(guildId);
5248
- const voiceServerUpdate = GatewayDispatchEvents.VoiceServerUpdate;
5249
- const voiceStateUpdate = GatewayDispatchEvents.VoiceStateUpdate;
5250
- if (type === voiceServerUpdate) adapter?.onVoiceServerUpdate?.(data);
5251
- if (type === voiceStateUpdate) adapter?.onVoiceStateUpdate?.(data);
5252
- }
5253
- function mapGatewayDispatchData(client, type, data) {
5254
- const messageCreate = GatewayDispatchEvents.MessageCreate;
5255
- const reactionAdd = GatewayDispatchEvents.MessageReactionAdd;
5256
- const reactionRemove = GatewayDispatchEvents.MessageReactionRemove;
5257
- if (type === messageCreate) return createMessageDispatchData(client, data);
5258
- if (type === reactionAdd || type === reactionRemove) return createReactionDispatchData(client, data);
5259
- return data;
5260
- }
5261
- function createMessageDispatchData(client, data) {
5262
- const message = new Message(client, data);
5263
- return {
5264
- ...data,
5265
- id: data.id,
5266
- channel_id: data.channel_id,
5267
- channelId: data.channel_id,
5268
- message,
5269
- author: message.author ?? (data.author ? new User(client, data.author) : null),
5270
- member: data.member,
5271
- rawMember: data.member,
5272
- guild: data.guild_id ? new Guild(client, data.guild_id) : null
5273
- };
5274
- }
5275
- function createReactionDispatchData(client, data) {
5276
- const userRaw = data.member?.user && typeof data.member.user === "object" ? {
5277
- id: data.user_id,
5278
- username: "",
5279
- ...data.member.user
5280
- } : {
5281
- id: data.user_id,
5282
- username: ""
5283
- };
5284
- return {
5285
- ...data,
5286
- user: new User(client, userRaw),
5287
- rawMember: data.member,
5288
- guild: data.guild_id ? new Guild(client, data.guild_id) : null,
5289
- message: new Message(client, {
5290
- id: data.message_id,
5291
- channelId: data.channel_id
5292
- })
5293
- };
5294
- }
5295
- function readGuildId(data) {
5296
- return data && typeof data === "object" && typeof data.guild_id === "string" ? data.guild_id : void 0;
5297
- }
5298
- //#endregion
5299
5308
  //#region extensions/discord/src/internal/gateway-identify-limiter.ts
5300
5309
  const IDENTIFY_WINDOW_MS = 5e3;
5301
5310
  function normalizeMaxConcurrency(value) {
@@ -5825,7 +5834,7 @@ var GatewayPlugin = class extends Plugin {
5825
5834
  }
5826
5835
  this.voiceStateCache.apply(payload);
5827
5836
  dispatchVoiceGatewayEvent(this.client, payload.t, payload.d);
5828
- const data = mapGatewayDispatchData(this.client, payload.t, payload.d);
5837
+ const data = payload.t === GatewayDispatchEvents.MessageCreate ? payload.d : mapGatewayDispatchData(this.client, payload.t, payload.d);
5829
5838
  await this.client.dispatchGatewayEvent(payload.t, data);
5830
5839
  if (payload.t === GatewayDispatchEvents.InteractionCreate && this.options.autoInteractions) await this.client.handleInteraction(payload.d);
5831
5840
  }
@@ -7239,7 +7248,7 @@ async function runDiscordGatewayLifecycle(params) {
7239
7248
  gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
7240
7249
  if (params.voiceManager) {
7241
7250
  await params.voiceManager.destroy();
7242
- const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-TDZcMriu.js").then((n) => n.n);
7251
+ const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-DjDbt14x.js").then((n) => n.n);
7243
7252
  setDiscordTranscriptsVoiceManager({
7244
7253
  accountId: params.accountId,
7245
7254
  manager: null
@@ -7254,7 +7263,7 @@ async function runDiscordGatewayLifecycle(params) {
7254
7263
  let discordVoiceRuntimePromise;
7255
7264
  let discordProviderSessionRuntimePromise;
7256
7265
  async function loadDiscordVoiceRuntime() {
7257
- const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-w6VVYQMl.js");
7266
+ const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-Cc8vS-M7.js");
7258
7267
  discordVoiceRuntimePromise = promise;
7259
7268
  try {
7260
7269
  return await promise;
@@ -7264,7 +7273,7 @@ async function loadDiscordVoiceRuntime() {
7264
7273
  }
7265
7274
  }
7266
7275
  async function loadDiscordProviderSessionRuntime() {
7267
- const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BZPUZRjn.js");
7276
+ const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-cCfGMsF_.js");
7268
7277
  discordProviderSessionRuntimePromise = promise;
7269
7278
  try {
7270
7279
  return await promise;
@@ -7612,8 +7621,8 @@ async function resolveDiscordAllowlistConfig(params) {
7612
7621
  }
7613
7622
  //#endregion
7614
7623
  //#region extensions/discord/src/monitor/provider.cleanup.ts
7615
- function cleanupDiscordProviderStartup(params) {
7616
- params.deactivateMessageHandler?.();
7624
+ async function cleanupDiscordProviderStartup(params) {
7625
+ await params.deactivateMessageHandler?.();
7617
7626
  params.autoPresenceController?.stop();
7618
7627
  params.setStatus?.({ connected: false });
7619
7628
  if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
@@ -8019,107 +8028,6 @@ function runDiscordCommandDeployInBackground(params) {
8019
8028
  });
8020
8029
  }
8021
8030
  //#endregion
8022
- //#region extensions/discord/src/monitor/agent-components-context.ts
8023
- function formatUsername(user) {
8024
- if (user.discriminator && user.discriminator !== "0") return `${user.username}#${user.discriminator}`;
8025
- return user.username;
8026
- }
8027
- function isThreadChannelType(channelType) {
8028
- return channelType === ChannelType.PublicThread || channelType === ChannelType.PrivateThread || channelType === ChannelType.AnnouncementThread;
8029
- }
8030
- function resolveAgentComponentRoute(params) {
8031
- return resolveAgentRoute({
8032
- cfg: params.ctx.cfg,
8033
- channel: "discord",
8034
- accountId: params.ctx.accountId,
8035
- guildId: params.rawGuildId,
8036
- memberRoleIds: params.memberRoleIds,
8037
- peer: {
8038
- kind: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
8039
- id: params.isDirectMessage ? params.userId : params.channelId
8040
- },
8041
- parentPeer: params.parentId ? {
8042
- kind: "channel",
8043
- id: params.parentId
8044
- } : void 0
8045
- });
8046
- }
8047
- async function ackComponentInteraction(params) {
8048
- try {
8049
- await params.interaction.reply({
8050
- content: "✓",
8051
- ...params.replyOpts
8052
- });
8053
- } catch (err) {
8054
- logError(`${params.label}: failed to acknowledge interaction: ${String(err)}`);
8055
- }
8056
- }
8057
- function resolveDiscordChannelContext(interaction) {
8058
- const channel = interaction.channel;
8059
- const channelInfo = resolveDiscordChannelInfoSafe(channel);
8060
- const channelName = channelInfo.name;
8061
- const channelSlug = channelName ? normalizeDiscordSlug(channelName) : "";
8062
- const displayChannelSlug = channelName ? normalizeDiscordDisplaySlug(channelName) : "";
8063
- const channelType = channelInfo.type;
8064
- const isThread = isThreadChannelType(channelType);
8065
- let parentId;
8066
- let parentName;
8067
- let parentSlug = "";
8068
- if (isThread) {
8069
- parentId = channelInfo.parentId;
8070
- parentName = channelInfo.parentName;
8071
- if (parentName) parentSlug = normalizeDiscordSlug(parentName);
8072
- }
8073
- return {
8074
- channelName,
8075
- channelSlug,
8076
- displayChannelSlug,
8077
- channelType,
8078
- isThread,
8079
- parentId,
8080
- parentName,
8081
- parentSlug
8082
- };
8083
- }
8084
- async function resolveComponentInteractionContext(params) {
8085
- const { interaction, label } = params;
8086
- const channelId = interaction.rawData.channel_id;
8087
- if (!channelId) {
8088
- logError(`${label}: missing channel_id in interaction`);
8089
- return null;
8090
- }
8091
- const user = interaction.user;
8092
- if (!user) {
8093
- logError(`${label}: missing user in interaction`);
8094
- return null;
8095
- }
8096
- const shouldDefer = params.defer !== false && "defer" in interaction;
8097
- let didDefer = false;
8098
- if (shouldDefer) try {
8099
- await interaction.defer({ ephemeral: true });
8100
- didDefer = true;
8101
- } catch (err) {
8102
- logError(`${label}: failed to defer interaction: ${String(err)}`);
8103
- }
8104
- const replyOpts = didDefer ? {} : { ephemeral: true };
8105
- const username = formatUsername(user);
8106
- const userId = user.id;
8107
- const rawGuildId = interaction.rawData.guild_id;
8108
- const channelType = resolveDiscordChannelContext(interaction).channelType;
8109
- const isGroupDm = channelType === ChannelType.GroupDM;
8110
- return {
8111
- channelId,
8112
- user,
8113
- username,
8114
- userId,
8115
- replyOpts,
8116
- rawGuildId,
8117
- isDirectMessage: channelType === ChannelType.DM || !rawGuildId && !isGroupDm && channelType == null,
8118
- isGroupDm,
8119
- memberRoleIds: Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : []
8120
- };
8121
- }
8122
- //#endregion
8123
8031
  //#region extensions/discord/src/monitor/agent-components-reply.ts
8124
8032
  async function replySilently(interaction, params) {
8125
8033
  try {
@@ -8127,463 +8035,118 @@ async function replySilently(interaction, params) {
8127
8035
  } catch {}
8128
8036
  }
8129
8037
  //#endregion
8130
- //#region extensions/discord/src/monitor/agent-components-dm-auth.ts
8131
- async function ensureDmComponentAuthorized(params) {
8132
- const { ctx, interaction, user, componentLabel, replyOpts } = params;
8133
- const dmPolicy = ctx.dmPolicy ?? "pairing";
8134
- if (dmPolicy === "disabled") {
8135
- logVerbose(`agent ${componentLabel}: blocked (DM policy disabled)`);
8136
- await replySilently(interaction, {
8137
- content: "DM interactions are disabled.",
8138
- ...replyOpts
8139
- });
8140
- return false;
8038
+ //#region extensions/discord/src/activities/interaction.ts
8039
+ const REGISTRATION_WIDGET_ID = "AAAAAAAAAAAAAAAAAAAAAA";
8040
+ const PENDING_LAUNCH_WRITE_BUDGET_MS = 250;
8041
+ var DiscordActivityButton = class extends Button {
8042
+ constructor(ctx, deps) {
8043
+ super();
8044
+ this.ctx = ctx;
8045
+ this.deps = deps;
8046
+ this.label = "Open widget";
8047
+ this.customId = buildDiscordActivityCustomId(REGISTRATION_WIDGET_ID);
8048
+ this.customIdParser = parseDiscordActivityCustomIdForInteraction;
8049
+ this.pendingLaunchFailureLogged = false;
8141
8050
  }
8142
- const access = await resolveDiscordDmCommandAccess({
8143
- accountId: ctx.accountId,
8144
- dmPolicy,
8145
- configuredAllowFrom: ctx.allowFrom ?? [],
8146
- sender: {
8147
- id: user.id,
8148
- name: user.username,
8149
- tag: formatDiscordUserTag(user)
8150
- },
8151
- allowNameMatching: isDangerousNameMatchingEnabled(ctx.discordConfig),
8152
- cfg: ctx.cfg,
8153
- token: ctx.token,
8154
- readStoreAllowFrom: async ({ accountId, dmPolicy: dmPolicyLocal }) => await readChannelIngressStoreAllowFromForDmPolicy({
8155
- provider: "discord",
8156
- accountId,
8157
- dmPolicy: dmPolicyLocal
8158
- }),
8159
- eventKind: "button"
8160
- });
8161
- if (access.senderAccess.decision === "allow") return true;
8162
- if (access.senderAccess.decision !== "pairing") {
8163
- logVerbose(`agent ${componentLabel}: blocked DM user ${user.id} (not in allowFrom)`);
8164
- await replySilently(interaction, {
8165
- content: `You are not authorized to use this ${componentLabel}.`,
8166
- ...replyOpts
8167
- });
8168
- return false;
8051
+ logPendingLaunchFailure(error) {
8052
+ if (this.pendingLaunchFailureLogged) return;
8053
+ this.pendingLaunchFailureLogged = true;
8054
+ this.deps.logError(`discord activity: failed to record pending launch: ${String(error)}`);
8169
8055
  }
8170
- if (!(await createChannelPairingChallengeIssuer({
8171
- channel: "discord",
8172
- accountId: ctx.accountId,
8173
- upsertPairingRequest: async ({ id, meta }) => {
8174
- return await upsertChannelPairingRequest$1({
8175
- channel: "discord",
8176
- id,
8177
- accountId: ctx.accountId,
8178
- meta
8056
+ async run(interaction, data) {
8057
+ if (typeof data.widgetId !== "string") {
8058
+ await this.deps.reply(interaction, {
8059
+ content: "This widget is no longer valid.",
8060
+ ephemeral: true
8179
8061
  });
8062
+ return;
8180
8063
  }
8181
- })({
8182
- senderId: user.id,
8183
- senderIdLine: `Your Discord user id: ${user.id}`,
8184
- meta: {
8185
- tag: formatDiscordUserTag(user),
8186
- name: user.username
8187
- },
8188
- sendPairingReply: async (text) => {
8189
- await interaction.reply({
8190
- content: text,
8191
- ...replyOpts
8064
+ const runtime = getDiscordActivitiesRuntime();
8065
+ const channelId = interaction.rawData.channel_id;
8066
+ const discordUserId = interaction.userId;
8067
+ if (!runtime || !channelId || !discordUserId) this.logPendingLaunchFailure(/* @__PURE__ */ new Error("missing activity runtime or interaction identity"));
8068
+ else {
8069
+ const write = runtime.store.recordPendingLaunch({
8070
+ accountId: this.ctx.accountId,
8071
+ channelId,
8072
+ discordUserId,
8073
+ widgetId: data.widgetId,
8074
+ createdAt: Date.now()
8075
+ }).then(() => "written").catch((error) => {
8076
+ this.logPendingLaunchFailure(error);
8077
+ return "failed";
8078
+ });
8079
+ const timeout = new Promise((resolve) => {
8080
+ setTimeout(() => resolve("timeout"), PENDING_LAUNCH_WRITE_BUDGET_MS).unref?.();
8192
8081
  });
8082
+ if (await Promise.race([write, timeout]) === "timeout") this.logPendingLaunchFailure(/* @__PURE__ */ new Error(`pending launch write exceeded ${PENDING_LAUNCH_WRITE_BUDGET_MS}ms`));
8193
8083
  }
8194
- })).created) await replySilently(interaction, {
8195
- content: "Pairing already requested. Ask the bot owner to approve your code.",
8196
- ...replyOpts
8197
- });
8198
- return false;
8199
- }
8200
- async function ensureGroupDmComponentAuthorized(params) {
8201
- const { ctx, interaction, channelId, componentLabel, replyOpts } = params;
8202
- if (!(ctx.discordConfig?.dm?.groupEnabled ?? false)) {
8203
- logVerbose(`agent ${componentLabel}: blocked group dm ${channelId} (group DMs disabled)`);
8204
- await replySilently(interaction, {
8205
- content: "Group DM interactions are disabled.",
8206
- ...replyOpts
8207
- });
8208
- return false;
8084
+ await interaction.launchActivity();
8209
8085
  }
8210
- const channelCtx = resolveDiscordChannelContext(interaction);
8211
- if (resolveGroupDmAllow({
8212
- channels: ctx.discordConfig?.dm?.groupChannels,
8213
- channelId,
8214
- channelName: channelCtx.channelName,
8215
- channelSlug: channelCtx.channelSlug
8216
- })) return true;
8217
- logVerbose(`agent ${componentLabel}: blocked group dm ${channelId} (not allowlisted)`);
8218
- await replySilently(interaction, {
8219
- content: `You are not authorized to use this ${componentLabel}.`,
8220
- ...replyOpts
8221
- });
8222
- return false;
8223
- }
8224
- async function resolveInteractionContextWithDmAuth(params) {
8225
- const interactionCtx = await resolveComponentInteractionContext({
8226
- interaction: params.interaction,
8227
- label: params.label,
8228
- defer: params.defer
8086
+ };
8087
+ function createDiscordActivityButton(ctx, applicationId, deps = {}) {
8088
+ const runtime = getDiscordActivitiesRuntime();
8089
+ if (!runtime || !runtime.isAccountEnabled(ctx.accountId, ctx.cfg)) return null;
8090
+ if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
8091
+ if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
8092
+ return new DiscordActivityButton(ctx, {
8093
+ reply: deps.reply ?? replySilently,
8094
+ logError: deps.logError ?? logError
8229
8095
  });
8230
- if (!interactionCtx) return null;
8231
- if (interactionCtx.isDirectMessage) {
8232
- if (!await ensureDmComponentAuthorized({
8233
- ctx: params.ctx,
8234
- interaction: params.interaction,
8235
- user: interactionCtx.user,
8236
- componentLabel: params.componentLabel,
8237
- replyOpts: interactionCtx.replyOpts
8238
- })) return null;
8239
- }
8240
- if (interactionCtx.isGroupDm) {
8241
- if (!await ensureGroupDmComponentAuthorized({
8242
- ctx: params.ctx,
8243
- interaction: params.interaction,
8244
- channelId: interactionCtx.channelId,
8245
- componentLabel: params.componentLabel,
8246
- replyOpts: interactionCtx.replyOpts
8247
- })) return null;
8248
- }
8249
- return interactionCtx;
8250
8096
  }
8251
8097
  //#endregion
8252
- //#region extensions/discord/src/monitor/agent-components-guild-auth.ts
8253
- function resolveComponentRuntimeGroupPolicy(ctx) {
8254
- return resolveOpenProviderRuntimeGroupPolicy({
8255
- providerConfigPresent: ctx.cfg.channels?.discord !== void 0,
8256
- groupPolicy: ctx.discordConfig?.groupPolicy,
8257
- defaultGroupPolicy: ctx.cfg.channels?.defaults?.groupPolicy
8098
+ //#region extensions/discord/src/voice/access.ts
8099
+ async function authorizeDiscordVoiceIngress(params) {
8100
+ const groupPolicy = params.groupPolicy ?? resolveOpenProviderRuntimeGroupPolicy({
8101
+ providerConfigPresent: params.cfg.channels?.discord !== void 0,
8102
+ groupPolicy: params.discordConfig.groupPolicy,
8103
+ defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
8258
8104
  }).groupPolicy;
8259
- }
8260
- async function ensureGuildComponentMemberAllowed(params) {
8261
- const { interaction, guildInfo, channelId, rawGuildId, channelCtx, memberRoleIds, user, replyOpts, componentLabel, unauthorizedReply } = params;
8262
- if (!rawGuildId) return true;
8263
- const replyUnauthorized = async () => {
8264
- await replySilently(interaction, {
8265
- content: unauthorizedReply,
8266
- ...replyOpts
8267
- });
8268
- };
8269
- const channelConfig = resolveDiscordChannelConfigWithFallback({
8270
- guildInfo,
8271
- channelId,
8272
- channelName: channelCtx.channelName,
8273
- channelSlug: channelCtx.channelSlug,
8274
- parentId: channelCtx.parentId,
8275
- parentName: channelCtx.parentName,
8276
- parentSlug: channelCtx.parentSlug,
8277
- scope: channelCtx.isThread ? "thread" : "channel"
8105
+ const guildInfo = resolveDiscordGuildEntry({
8106
+ guild: params.guild ?? {
8107
+ id: params.guildId,
8108
+ ...params.guildName ? { name: params.guildName } : {}
8109
+ },
8110
+ guildId: params.guildId,
8111
+ guildEntries: params.discordConfig.guilds
8278
8112
  });
8279
- if (channelConfig?.enabled === false) {
8280
- await replyUnauthorized();
8281
- return false;
8282
- }
8113
+ const channelConfig = params.channelId ? resolveDiscordChannelConfigWithFallback({
8114
+ guildInfo,
8115
+ channelId: params.channelId,
8116
+ channelName: params.channelName,
8117
+ channelSlug: params.channelSlug,
8118
+ parentId: params.parentId,
8119
+ parentName: params.parentName,
8120
+ parentSlug: params.parentSlug,
8121
+ scope: params.scope
8122
+ }) : null;
8123
+ if (channelConfig?.enabled === false) return {
8124
+ ok: false,
8125
+ message: "This channel is disabled."
8126
+ };
8283
8127
  const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
8284
- const channelAllowed = channelConfig?.allowed !== false;
8128
+ if (!params.channelId && groupPolicy === "allowlist" && channelAllowlistConfigured) return {
8129
+ ok: false,
8130
+ message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
8131
+ };
8132
+ const channelAllowed = channelConfig ? channelConfig.allowed : !channelAllowlistConfigured;
8285
8133
  if (!isDiscordGroupAllowedByPolicy({
8286
- groupPolicy: params.groupPolicy,
8134
+ groupPolicy,
8287
8135
  guildAllowlisted: Boolean(guildInfo),
8288
8136
  channelAllowlistConfigured,
8289
8137
  channelAllowed
8290
- })) {
8291
- await replyUnauthorized();
8292
- return false;
8293
- }
8294
- if (channelConfig?.allowed === false) {
8295
- await replyUnauthorized();
8296
- return false;
8297
- }
8298
- const { memberAllowed } = resolveDiscordMemberAccessState({
8138
+ }) || channelConfig?.allowed === false) return {
8139
+ ok: false,
8140
+ message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
8141
+ };
8142
+ const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
8299
8143
  channelConfig,
8300
8144
  guildInfo,
8301
- memberRoleIds,
8302
- sender: {
8303
- id: user.id,
8304
- name: user.username,
8305
- tag: user.discriminator ? `${user.username}#${user.discriminator}` : void 0
8306
- },
8307
- allowNameMatching: params.allowNameMatching
8145
+ memberRoleIds: params.memberRoleIds,
8146
+ sender: params.sender,
8147
+ allowNameMatching: false
8308
8148
  });
8309
- if (memberAllowed) return true;
8310
- logVerbose(`agent ${componentLabel}: blocked user ${user.id} (not in users/roles allowlist)`);
8311
- await replyUnauthorized();
8312
- return false;
8313
- }
8314
- async function ensureComponentUserAllowed(params) {
8315
- const allowList = normalizeDiscordAllowList(params.entry.allowedUsers, [
8316
- "discord:",
8317
- "user:",
8318
- "pk:"
8319
- ]);
8320
- if (!allowList) return true;
8321
- if (resolveDiscordAllowListMatch({
8322
- allowList,
8323
- candidate: {
8324
- id: params.user.id,
8325
- name: params.user.username,
8326
- tag: formatDiscordUserTag(params.user)
8327
- },
8328
- allowNameMatching: params.allowNameMatching
8329
- }).allowed) return true;
8330
- logVerbose(`discord component ${params.componentLabel}: blocked user ${params.user.id} (not in allowedUsers)`);
8331
- await replySilently(params.interaction, {
8332
- content: params.unauthorizedReply,
8333
- ...params.replyOpts
8334
- });
8335
- return false;
8336
- }
8337
- async function ensureAgentComponentInteractionAllowed(params) {
8338
- const guildInfo = resolveDiscordGuildEntry({
8339
- guild: params.interaction.guild ?? void 0,
8340
- guildId: params.rawGuildId,
8341
- guildEntries: params.ctx.guildEntries
8342
- });
8343
- const channelCtx = resolveDiscordChannelContext(params.interaction);
8344
- if (!await ensureGuildComponentMemberAllowed({
8345
- interaction: params.interaction,
8346
- guildInfo,
8347
- channelId: params.channelId,
8348
- rawGuildId: params.rawGuildId,
8349
- channelCtx,
8350
- memberRoleIds: params.memberRoleIds,
8351
- user: params.user,
8352
- replyOpts: params.replyOpts,
8353
- componentLabel: params.componentLabel,
8354
- unauthorizedReply: params.unauthorizedReply,
8355
- allowNameMatching: isDangerousNameMatchingEnabled(params.ctx.discordConfig),
8356
- groupPolicy: resolveComponentRuntimeGroupPolicy(params.ctx)
8357
- })) return null;
8358
- return { parentId: channelCtx.parentId };
8359
- }
8360
- async function resolveAuthorizedComponentInteraction(params) {
8361
- const interactionCtx = await resolveInteractionContextWithDmAuth({
8362
- ctx: params.ctx,
8363
- interaction: params.interaction,
8364
- label: params.label,
8365
- componentLabel: params.componentLabel,
8366
- defer: params.defer
8367
- });
8368
- if (!interactionCtx) return null;
8369
- const { channelId, user, replyOpts, rawGuildId, memberRoleIds } = interactionCtx;
8370
- const guildInfo = resolveDiscordGuildEntry({
8371
- guild: params.interaction.guild ?? void 0,
8372
- guildId: rawGuildId,
8373
- guildEntries: params.ctx.guildEntries
8374
- });
8375
- const channelCtx = resolveDiscordChannelContext(params.interaction);
8376
- const allowNameMatching = isDangerousNameMatchingEnabled(params.ctx.discordConfig);
8377
- const channelConfig = resolveDiscordChannelConfigWithFallback({
8378
- guildInfo,
8379
- channelId,
8380
- channelName: channelCtx.channelName,
8381
- channelSlug: channelCtx.channelSlug,
8382
- parentId: channelCtx.parentId,
8383
- parentName: channelCtx.parentName,
8384
- parentSlug: channelCtx.parentSlug,
8385
- scope: channelCtx.isThread ? "thread" : "channel"
8386
- });
8387
- if (!await ensureGuildComponentMemberAllowed({
8388
- interaction: params.interaction,
8389
- guildInfo,
8390
- channelId,
8391
- rawGuildId,
8392
- channelCtx,
8393
- memberRoleIds,
8394
- user,
8395
- replyOpts,
8396
- componentLabel: params.componentLabel,
8397
- unauthorizedReply: params.unauthorizedReply,
8398
- allowNameMatching,
8399
- groupPolicy: resolveComponentRuntimeGroupPolicy(params.ctx)
8400
- })) return null;
8401
- return {
8402
- interactionCtx,
8403
- channelCtx,
8404
- guildInfo,
8405
- channelConfig,
8406
- allowNameMatching,
8407
- commandAuthorized: await resolveComponentCommandAuthorized({
8408
- ctx: params.ctx,
8409
- interactionCtx,
8410
- channelConfig,
8411
- guildInfo,
8412
- allowNameMatching
8413
- }),
8414
- user,
8415
- replyOpts
8416
- };
8417
- }
8418
- async function resolveComponentCommandAuthorized(params) {
8419
- const { ctx, interactionCtx, channelConfig, guildInfo } = params;
8420
- if (interactionCtx.isDirectMessage) return true;
8421
- const { ownerAllowList, ownerAllowed: ownerOk } = resolveDiscordOwnerAccess({
8422
- allowFrom: ctx.allowFrom,
8423
- sender: {
8424
- id: interactionCtx.user.id,
8425
- name: interactionCtx.user.username,
8426
- tag: formatDiscordUserTag(interactionCtx.user)
8427
- },
8428
- allowNameMatching: params.allowNameMatching
8429
- });
8430
- const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
8431
- channelConfig,
8432
- guildInfo,
8433
- memberRoleIds: interactionCtx.memberRoleIds,
8434
- sender: {
8435
- id: interactionCtx.user.id,
8436
- name: interactionCtx.user.username,
8437
- tag: formatDiscordUserTag(interactionCtx.user)
8438
- },
8439
- allowNameMatching: params.allowNameMatching
8440
- });
8441
- const useAccessGroups = ctx.cfg.commands?.useAccessGroups !== false;
8442
- return resolveCommandAuthorizedFromAuthorizers({
8443
- useAccessGroups,
8444
- authorizers: useAccessGroups ? [{
8445
- configured: ownerAllowList != null,
8446
- allowed: ownerOk
8447
- }, {
8448
- configured: hasAccessRestrictions,
8449
- allowed: memberAllowed
8450
- }] : [{
8451
- configured: hasAccessRestrictions,
8452
- allowed: memberAllowed
8453
- }],
8454
- modeWhenAccessGroupsOff: "configured"
8455
- });
8456
- }
8457
- //#endregion
8458
- //#region extensions/discord/src/activities/interaction.ts
8459
- const REGISTRATION_WIDGET_ID = "AAAAAAAAAAAAAAAAAAAAAA";
8460
- const PENDING_LAUNCH_WRITE_BUDGET_MS = 250;
8461
- var DiscordActivityButton = class extends Button {
8462
- constructor(ctx, deps) {
8463
- super();
8464
- this.ctx = ctx;
8465
- this.deps = deps;
8466
- this.label = "Open widget";
8467
- this.customId = buildDiscordActivityCustomId(REGISTRATION_WIDGET_ID);
8468
- this.customIdParser = parseDiscordActivityCustomIdForInteraction;
8469
- this.pendingLaunchFailureLogged = false;
8470
- }
8471
- logPendingLaunchFailure(error) {
8472
- if (this.pendingLaunchFailureLogged) return;
8473
- this.pendingLaunchFailureLogged = true;
8474
- this.deps.logError(`discord activity: failed to record pending launch: ${String(error)}`);
8475
- }
8476
- async run(interaction, data) {
8477
- if (typeof data.widgetId !== "string") {
8478
- await this.deps.reply(interaction, {
8479
- content: "This widget is no longer valid.",
8480
- ephemeral: true
8481
- });
8482
- return;
8483
- }
8484
- const authorized = await this.deps.authorize({
8485
- ctx: this.ctx,
8486
- interaction,
8487
- label: "discord activity",
8488
- componentLabel: "widget button",
8489
- unauthorizedReply: "not allowed",
8490
- defer: false
8491
- });
8492
- if (!authorized) return;
8493
- if (!authorized.commandAuthorized) {
8494
- await this.deps.reply(interaction, {
8495
- content: "not allowed",
8496
- ephemeral: true
8497
- });
8498
- return;
8499
- }
8500
- const runtime = getDiscordActivitiesRuntime();
8501
- const channelId = interaction.rawData.channel_id;
8502
- const discordUserId = interaction.userId;
8503
- if (!runtime || !channelId || !discordUserId) this.logPendingLaunchFailure(/* @__PURE__ */ new Error("missing activity runtime or interaction identity"));
8504
- else {
8505
- const write = runtime.store.recordPendingLaunch({
8506
- accountId: this.ctx.accountId,
8507
- channelId,
8508
- discordUserId,
8509
- widgetId: data.widgetId,
8510
- createdAt: Date.now()
8511
- }).then(() => "written").catch((error) => {
8512
- this.logPendingLaunchFailure(error);
8513
- return "failed";
8514
- });
8515
- const timeout = new Promise((resolve) => {
8516
- setTimeout(() => resolve("timeout"), PENDING_LAUNCH_WRITE_BUDGET_MS).unref?.();
8517
- });
8518
- if (await Promise.race([write, timeout]) === "timeout") this.logPendingLaunchFailure(/* @__PURE__ */ new Error(`pending launch write exceeded ${PENDING_LAUNCH_WRITE_BUDGET_MS}ms`));
8519
- }
8520
- await interaction.launchActivity();
8521
- }
8522
- };
8523
- function createDiscordActivityButton(ctx, applicationId, deps = {}) {
8524
- const runtime = getDiscordActivitiesRuntime();
8525
- if (!runtime || !runtime.isAccountEnabled(ctx.accountId, ctx.cfg)) return null;
8526
- if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
8527
- if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
8528
- return new DiscordActivityButton(ctx, {
8529
- authorize: deps.authorize ?? resolveAuthorizedComponentInteraction,
8530
- reply: deps.reply ?? replySilently,
8531
- logError: deps.logError ?? logError
8532
- });
8533
- }
8534
- //#endregion
8535
- //#region extensions/discord/src/voice/access.ts
8536
- async function authorizeDiscordVoiceIngress(params) {
8537
- const groupPolicy = params.groupPolicy ?? resolveOpenProviderRuntimeGroupPolicy({
8538
- providerConfigPresent: params.cfg.channels?.discord !== void 0,
8539
- groupPolicy: params.discordConfig.groupPolicy,
8540
- defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
8541
- }).groupPolicy;
8542
- const guildInfo = resolveDiscordGuildEntry({
8543
- guild: params.guild ?? {
8544
- id: params.guildId,
8545
- ...params.guildName ? { name: params.guildName } : {}
8546
- },
8547
- guildId: params.guildId,
8548
- guildEntries: params.discordConfig.guilds
8549
- });
8550
- const channelConfig = params.channelId ? resolveDiscordChannelConfigWithFallback({
8551
- guildInfo,
8552
- channelId: params.channelId,
8553
- channelName: params.channelName,
8554
- channelSlug: params.channelSlug,
8555
- parentId: params.parentId,
8556
- parentName: params.parentName,
8557
- parentSlug: params.parentSlug,
8558
- scope: params.scope
8559
- }) : null;
8560
- if (channelConfig?.enabled === false) return {
8561
- ok: false,
8562
- message: "This channel is disabled."
8563
- };
8564
- const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
8565
- if (!params.channelId && groupPolicy === "allowlist" && channelAllowlistConfigured) return {
8566
- ok: false,
8567
- message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
8568
- };
8569
- const channelAllowed = channelConfig ? channelConfig.allowed : !channelAllowlistConfigured;
8570
- if (!isDiscordGroupAllowedByPolicy({
8571
- groupPolicy,
8572
- guildAllowlisted: Boolean(guildInfo),
8573
- channelAllowlistConfigured,
8574
- channelAllowed
8575
- }) || channelConfig?.allowed === false) return {
8576
- ok: false,
8577
- message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
8578
- };
8579
- const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
8580
- channelConfig,
8581
- guildInfo,
8582
- memberRoleIds: params.memberRoleIds,
8583
- sender: params.sender,
8584
- allowNameMatching: false
8585
- });
8586
- const admissionAllowList = normalizeDiscordAllowList(params.admissionAllowFrom ?? params.discordConfig.allowFrom ?? params.discordConfig.dm?.allowFrom, [
8149
+ const admissionAllowList = normalizeDiscordAllowList(params.admissionAllowFrom ?? params.discordConfig.allowFrom ?? params.discordConfig.dm?.allowFrom, [
8587
8150
  "discord:",
8588
8151
  "user:",
8589
8152
  "pk:"
@@ -8708,160 +8271,589 @@ async function resolveVoiceCommandRuntimeContext(interaction, params) {
8708
8271
  return null;
8709
8272
  }
8710
8273
  return {
8711
- guildId,
8712
- manager
8274
+ guildId,
8275
+ manager
8276
+ };
8277
+ }
8278
+ async function ensureVoiceCommandAccess(params) {
8279
+ const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
8280
+ if (access.ok) return true;
8281
+ await params.interaction.reply({
8282
+ content: access.message ?? "Not authorized.",
8283
+ ephemeral: true
8284
+ });
8285
+ return false;
8286
+ }
8287
+ function createDiscordVoiceCommand(params) {
8288
+ const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
8289
+ class JoinCommand extends Command {
8290
+ constructor(..._args) {
8291
+ super(..._args);
8292
+ this.name = "join";
8293
+ this.description = "Join a voice channel";
8294
+ this.defer = true;
8295
+ this.ephemeral = params.ephemeralDefault;
8296
+ this.options = [{
8297
+ name: "channel",
8298
+ description: "Voice channel to join",
8299
+ type: ApplicationCommandOptionType.Channel,
8300
+ required: true,
8301
+ channel_types: VOICE_CHANNEL_TYPES
8302
+ }];
8303
+ }
8304
+ async run(interaction) {
8305
+ const channel = await interaction.options.getChannel("channel", true);
8306
+ if (!channel || !("id" in channel)) {
8307
+ await interaction.reply({
8308
+ content: "Voice channel not found.",
8309
+ ephemeral: true
8310
+ });
8311
+ return;
8312
+ }
8313
+ const access = await authorizeVoiceCommand(interaction, params, { channelOverride: {
8314
+ id: channel.id,
8315
+ name: resolveDiscordChannelNameSafe(channel)
8316
+ } });
8317
+ if (!access.ok) {
8318
+ await interaction.reply({
8319
+ content: access.message ?? "Not authorized.",
8320
+ ephemeral: true
8321
+ });
8322
+ return;
8323
+ }
8324
+ if (!isVoiceChannelType(channel.type)) {
8325
+ await interaction.reply({
8326
+ content: "That is not a voice channel.",
8327
+ ephemeral: true
8328
+ });
8329
+ return;
8330
+ }
8331
+ const guildId = access.guildId ?? ("guildId" in channel ? channel.guildId : void 0);
8332
+ if (!guildId) {
8333
+ await interaction.reply({
8334
+ content: "Unable to resolve guild for this voice channel.",
8335
+ ephemeral: true
8336
+ });
8337
+ return;
8338
+ }
8339
+ const manager = params.getManager();
8340
+ if (!manager) {
8341
+ await interaction.reply({
8342
+ content: "Voice manager is not available yet.",
8343
+ ephemeral: true
8344
+ });
8345
+ return;
8346
+ }
8347
+ const result = await manager.join({
8348
+ guildId,
8349
+ channelId: channel.id
8350
+ });
8351
+ await interaction.reply({
8352
+ content: result.message,
8353
+ ephemeral: true
8354
+ });
8355
+ }
8356
+ }
8357
+ class LeaveCommand extends Command {
8358
+ constructor(..._args2) {
8359
+ super(..._args2);
8360
+ this.name = "leave";
8361
+ this.description = "Leave the current voice channel";
8362
+ this.defer = true;
8363
+ this.ephemeral = params.ephemeralDefault;
8364
+ }
8365
+ async run(interaction) {
8366
+ const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
8367
+ if (!runtimeContext) return;
8368
+ const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
8369
+ if (!await ensureVoiceCommandAccess({
8370
+ interaction,
8371
+ context: params,
8372
+ channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
8373
+ })) return;
8374
+ const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
8375
+ await interaction.reply({
8376
+ content: result.message,
8377
+ ephemeral: true
8378
+ });
8379
+ }
8380
+ }
8381
+ class StatusCommand extends Command {
8382
+ constructor(..._args3) {
8383
+ super(..._args3);
8384
+ this.name = "status";
8385
+ this.description = "Show active voice sessions";
8386
+ this.defer = true;
8387
+ this.ephemeral = params.ephemeralDefault;
8388
+ }
8389
+ async run(interaction) {
8390
+ const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
8391
+ if (!runtimeContext) return;
8392
+ const sessions = runtimeContext.manager.status().filter((entry) => entry.guildId === runtimeContext.guildId);
8393
+ const sessionChannelId = sessions[0]?.channelId;
8394
+ if (!await ensureVoiceCommandAccess({
8395
+ interaction,
8396
+ context: params,
8397
+ channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
8398
+ })) return;
8399
+ if (sessions.length === 0) {
8400
+ await interaction.reply({
8401
+ content: "No active voice sessions.",
8402
+ ephemeral: true
8403
+ });
8404
+ return;
8405
+ }
8406
+ const lines = sessions.map((entry) => `• ${formatMention({ channelId: entry.channelId })} (guild ${entry.guildId})`);
8407
+ await interaction.reply({
8408
+ content: lines.join("\n"),
8409
+ ephemeral: true
8410
+ });
8411
+ }
8412
+ }
8413
+ return new class extends CommandWithSubcommands {
8414
+ constructor(..._args4) {
8415
+ super(..._args4);
8416
+ this.name = "vc";
8417
+ this.description = "Voice channel controls";
8418
+ this.subcommands = [
8419
+ new JoinCommand(),
8420
+ new LeaveCommand(),
8421
+ new StatusCommand()
8422
+ ];
8423
+ }
8424
+ }();
8425
+ }
8426
+ function isVoiceChannelType(type) {
8427
+ return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
8428
+ }
8429
+ //#endregion
8430
+ //#region extensions/discord/src/monitor/agent-components-context.ts
8431
+ function formatUsername(user) {
8432
+ if (user.discriminator && user.discriminator !== "0") return `${user.username}#${user.discriminator}`;
8433
+ return user.username;
8434
+ }
8435
+ function isThreadChannelType(channelType) {
8436
+ return channelType === ChannelType.PublicThread || channelType === ChannelType.PrivateThread || channelType === ChannelType.AnnouncementThread;
8437
+ }
8438
+ function resolveAgentComponentRoute(params) {
8439
+ return resolveAgentRoute({
8440
+ cfg: params.ctx.cfg,
8441
+ channel: "discord",
8442
+ accountId: params.ctx.accountId,
8443
+ guildId: params.rawGuildId,
8444
+ memberRoleIds: params.memberRoleIds,
8445
+ peer: {
8446
+ kind: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
8447
+ id: params.isDirectMessage ? params.userId : params.channelId
8448
+ },
8449
+ parentPeer: params.parentId ? {
8450
+ kind: "channel",
8451
+ id: params.parentId
8452
+ } : void 0
8453
+ });
8454
+ }
8455
+ async function ackComponentInteraction(params) {
8456
+ try {
8457
+ await params.interaction.reply({
8458
+ content: "✓",
8459
+ ...params.replyOpts
8460
+ });
8461
+ } catch (err) {
8462
+ logError(`${params.label}: failed to acknowledge interaction: ${String(err)}`);
8463
+ }
8464
+ }
8465
+ function resolveDiscordChannelContext(interaction) {
8466
+ const channel = interaction.channel;
8467
+ const channelInfo = resolveDiscordChannelInfoSafe(channel);
8468
+ const channelName = channelInfo.name;
8469
+ const channelSlug = channelName ? normalizeDiscordSlug(channelName) : "";
8470
+ const displayChannelSlug = channelName ? normalizeDiscordDisplaySlug(channelName) : "";
8471
+ const channelType = channelInfo.type;
8472
+ const isThread = isThreadChannelType(channelType);
8473
+ let parentId;
8474
+ let parentName;
8475
+ let parentSlug = "";
8476
+ if (isThread) {
8477
+ parentId = channelInfo.parentId;
8478
+ parentName = channelInfo.parentName;
8479
+ if (parentName) parentSlug = normalizeDiscordSlug(parentName);
8480
+ }
8481
+ return {
8482
+ channelName,
8483
+ channelSlug,
8484
+ displayChannelSlug,
8485
+ channelType,
8486
+ isThread,
8487
+ parentId,
8488
+ parentName,
8489
+ parentSlug
8490
+ };
8491
+ }
8492
+ async function resolveComponentInteractionContext(params) {
8493
+ const { interaction, label } = params;
8494
+ const channelId = interaction.rawData.channel_id;
8495
+ if (!channelId) {
8496
+ logError(`${label}: missing channel_id in interaction`);
8497
+ return null;
8498
+ }
8499
+ const user = interaction.user;
8500
+ if (!user) {
8501
+ logError(`${label}: missing user in interaction`);
8502
+ return null;
8503
+ }
8504
+ const shouldDefer = params.defer !== false && "defer" in interaction;
8505
+ let didDefer = false;
8506
+ if (shouldDefer) try {
8507
+ await interaction.defer({ ephemeral: true });
8508
+ didDefer = true;
8509
+ } catch (err) {
8510
+ logError(`${label}: failed to defer interaction: ${String(err)}`);
8511
+ }
8512
+ const replyOpts = didDefer ? {} : { ephemeral: true };
8513
+ const username = formatUsername(user);
8514
+ const userId = user.id;
8515
+ const rawGuildId = interaction.rawData.guild_id;
8516
+ const channelType = resolveDiscordChannelContext(interaction).channelType;
8517
+ const isGroupDm = channelType === ChannelType.GroupDM;
8518
+ return {
8519
+ channelId,
8520
+ user,
8521
+ username,
8522
+ userId,
8523
+ replyOpts,
8524
+ rawGuildId,
8525
+ isDirectMessage: channelType === ChannelType.DM || !rawGuildId && !isGroupDm && channelType == null,
8526
+ isGroupDm,
8527
+ memberRoleIds: Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : []
8528
+ };
8529
+ }
8530
+ //#endregion
8531
+ //#region extensions/discord/src/monitor/agent-components-dm-auth.ts
8532
+ async function ensureDmComponentAuthorized(params) {
8533
+ const { ctx, interaction, user, componentLabel, replyOpts } = params;
8534
+ const dmPolicy = ctx.dmPolicy ?? "pairing";
8535
+ if (dmPolicy === "disabled") {
8536
+ logVerbose(`agent ${componentLabel}: blocked (DM policy disabled)`);
8537
+ await replySilently(interaction, {
8538
+ content: "DM interactions are disabled.",
8539
+ ...replyOpts
8540
+ });
8541
+ return false;
8542
+ }
8543
+ const access = await resolveDiscordDmCommandAccess({
8544
+ accountId: ctx.accountId,
8545
+ dmPolicy,
8546
+ configuredAllowFrom: ctx.allowFrom ?? [],
8547
+ sender: {
8548
+ id: user.id,
8549
+ name: user.username,
8550
+ tag: formatDiscordUserTag(user)
8551
+ },
8552
+ allowNameMatching: isDangerousNameMatchingEnabled(ctx.discordConfig),
8553
+ cfg: ctx.cfg,
8554
+ token: ctx.token,
8555
+ readStoreAllowFrom: async ({ accountId, dmPolicy: dmPolicyLocal }) => await readChannelIngressStoreAllowFromForDmPolicy({
8556
+ provider: "discord",
8557
+ accountId,
8558
+ dmPolicy: dmPolicyLocal
8559
+ }),
8560
+ eventKind: "button"
8561
+ });
8562
+ if (access.senderAccess.decision === "allow") return true;
8563
+ if (access.senderAccess.decision !== "pairing") {
8564
+ logVerbose(`agent ${componentLabel}: blocked DM user ${user.id} (not in allowFrom)`);
8565
+ await replySilently(interaction, {
8566
+ content: `You are not authorized to use this ${componentLabel}.`,
8567
+ ...replyOpts
8568
+ });
8569
+ return false;
8570
+ }
8571
+ if (!(await createChannelPairingChallengeIssuer({
8572
+ channel: "discord",
8573
+ accountId: ctx.accountId,
8574
+ upsertPairingRequest: async ({ id, meta }) => {
8575
+ return await upsertChannelPairingRequest$1({
8576
+ channel: "discord",
8577
+ id,
8578
+ accountId: ctx.accountId,
8579
+ meta
8580
+ });
8581
+ }
8582
+ })({
8583
+ senderId: user.id,
8584
+ senderIdLine: `Your Discord user id: ${user.id}`,
8585
+ meta: {
8586
+ tag: formatDiscordUserTag(user),
8587
+ name: user.username
8588
+ },
8589
+ sendPairingReply: async (text) => {
8590
+ await interaction.reply({
8591
+ content: text,
8592
+ ...replyOpts
8593
+ });
8594
+ }
8595
+ })).created) await replySilently(interaction, {
8596
+ content: "Pairing already requested. Ask the bot owner to approve your code.",
8597
+ ...replyOpts
8598
+ });
8599
+ return false;
8600
+ }
8601
+ async function ensureGroupDmComponentAuthorized(params) {
8602
+ const { ctx, interaction, channelId, componentLabel, replyOpts } = params;
8603
+ if (!(ctx.discordConfig?.dm?.groupEnabled ?? false)) {
8604
+ logVerbose(`agent ${componentLabel}: blocked group dm ${channelId} (group DMs disabled)`);
8605
+ await replySilently(interaction, {
8606
+ content: "Group DM interactions are disabled.",
8607
+ ...replyOpts
8608
+ });
8609
+ return false;
8610
+ }
8611
+ const channelCtx = resolveDiscordChannelContext(interaction);
8612
+ if (resolveGroupDmAllow({
8613
+ channels: ctx.discordConfig?.dm?.groupChannels,
8614
+ channelId,
8615
+ channelName: channelCtx.channelName,
8616
+ channelSlug: channelCtx.channelSlug
8617
+ })) return true;
8618
+ logVerbose(`agent ${componentLabel}: blocked group dm ${channelId} (not allowlisted)`);
8619
+ await replySilently(interaction, {
8620
+ content: `You are not authorized to use this ${componentLabel}.`,
8621
+ ...replyOpts
8622
+ });
8623
+ return false;
8624
+ }
8625
+ async function resolveInteractionContextWithDmAuth(params) {
8626
+ const interactionCtx = await resolveComponentInteractionContext({
8627
+ interaction: params.interaction,
8628
+ label: params.label,
8629
+ defer: params.defer
8630
+ });
8631
+ if (!interactionCtx) return null;
8632
+ if (interactionCtx.isDirectMessage) {
8633
+ if (!await ensureDmComponentAuthorized({
8634
+ ctx: params.ctx,
8635
+ interaction: params.interaction,
8636
+ user: interactionCtx.user,
8637
+ componentLabel: params.componentLabel,
8638
+ replyOpts: interactionCtx.replyOpts
8639
+ })) return null;
8640
+ }
8641
+ if (interactionCtx.isGroupDm) {
8642
+ if (!await ensureGroupDmComponentAuthorized({
8643
+ ctx: params.ctx,
8644
+ interaction: params.interaction,
8645
+ channelId: interactionCtx.channelId,
8646
+ componentLabel: params.componentLabel,
8647
+ replyOpts: interactionCtx.replyOpts
8648
+ })) return null;
8649
+ }
8650
+ return interactionCtx;
8651
+ }
8652
+ //#endregion
8653
+ //#region extensions/discord/src/monitor/agent-components-guild-auth.ts
8654
+ function resolveComponentRuntimeGroupPolicy(ctx) {
8655
+ return resolveOpenProviderRuntimeGroupPolicy({
8656
+ providerConfigPresent: ctx.cfg.channels?.discord !== void 0,
8657
+ groupPolicy: ctx.discordConfig?.groupPolicy,
8658
+ defaultGroupPolicy: ctx.cfg.channels?.defaults?.groupPolicy
8659
+ }).groupPolicy;
8660
+ }
8661
+ async function ensureGuildComponentMemberAllowed(params) {
8662
+ const { interaction, guildInfo, channelId, rawGuildId, channelCtx, memberRoleIds, user, replyOpts, componentLabel, unauthorizedReply } = params;
8663
+ if (!rawGuildId) return true;
8664
+ const replyUnauthorized = async () => {
8665
+ await replySilently(interaction, {
8666
+ content: unauthorizedReply,
8667
+ ...replyOpts
8668
+ });
8669
+ };
8670
+ const channelConfig = resolveDiscordChannelConfigWithFallback({
8671
+ guildInfo,
8672
+ channelId,
8673
+ channelName: channelCtx.channelName,
8674
+ channelSlug: channelCtx.channelSlug,
8675
+ parentId: channelCtx.parentId,
8676
+ parentName: channelCtx.parentName,
8677
+ parentSlug: channelCtx.parentSlug,
8678
+ scope: channelCtx.isThread ? "thread" : "channel"
8679
+ });
8680
+ if (channelConfig?.enabled === false) {
8681
+ await replyUnauthorized();
8682
+ return false;
8683
+ }
8684
+ const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
8685
+ const channelAllowed = channelConfig?.allowed !== false;
8686
+ if (!isDiscordGroupAllowedByPolicy({
8687
+ groupPolicy: params.groupPolicy,
8688
+ guildAllowlisted: Boolean(guildInfo),
8689
+ channelAllowlistConfigured,
8690
+ channelAllowed
8691
+ })) {
8692
+ await replyUnauthorized();
8693
+ return false;
8694
+ }
8695
+ if (channelConfig?.allowed === false) {
8696
+ await replyUnauthorized();
8697
+ return false;
8698
+ }
8699
+ const { memberAllowed } = resolveDiscordMemberAccessState({
8700
+ channelConfig,
8701
+ guildInfo,
8702
+ memberRoleIds,
8703
+ sender: {
8704
+ id: user.id,
8705
+ name: user.username,
8706
+ tag: user.discriminator ? `${user.username}#${user.discriminator}` : void 0
8707
+ },
8708
+ allowNameMatching: params.allowNameMatching
8709
+ });
8710
+ if (memberAllowed) return true;
8711
+ logVerbose(`agent ${componentLabel}: blocked user ${user.id} (not in users/roles allowlist)`);
8712
+ await replyUnauthorized();
8713
+ return false;
8714
+ }
8715
+ async function ensureComponentUserAllowed(params) {
8716
+ const allowList = normalizeDiscordAllowList(params.entry.allowedUsers, [
8717
+ "discord:",
8718
+ "user:",
8719
+ "pk:"
8720
+ ]);
8721
+ if (!allowList) return true;
8722
+ if (resolveDiscordAllowListMatch({
8723
+ allowList,
8724
+ candidate: {
8725
+ id: params.user.id,
8726
+ name: params.user.username,
8727
+ tag: formatDiscordUserTag(params.user)
8728
+ },
8729
+ allowNameMatching: params.allowNameMatching
8730
+ }).allowed) return true;
8731
+ logVerbose(`discord component ${params.componentLabel}: blocked user ${params.user.id} (not in allowedUsers)`);
8732
+ await replySilently(params.interaction, {
8733
+ content: params.unauthorizedReply,
8734
+ ...params.replyOpts
8735
+ });
8736
+ return false;
8737
+ }
8738
+ async function ensureAgentComponentInteractionAllowed(params) {
8739
+ const guildInfo = resolveDiscordGuildEntry({
8740
+ guild: params.interaction.guild ?? void 0,
8741
+ guildId: params.rawGuildId,
8742
+ guildEntries: params.ctx.guildEntries
8743
+ });
8744
+ const channelCtx = resolveDiscordChannelContext(params.interaction);
8745
+ if (!await ensureGuildComponentMemberAllowed({
8746
+ interaction: params.interaction,
8747
+ guildInfo,
8748
+ channelId: params.channelId,
8749
+ rawGuildId: params.rawGuildId,
8750
+ channelCtx,
8751
+ memberRoleIds: params.memberRoleIds,
8752
+ user: params.user,
8753
+ replyOpts: params.replyOpts,
8754
+ componentLabel: params.componentLabel,
8755
+ unauthorizedReply: params.unauthorizedReply,
8756
+ allowNameMatching: isDangerousNameMatchingEnabled(params.ctx.discordConfig),
8757
+ groupPolicy: resolveComponentRuntimeGroupPolicy(params.ctx)
8758
+ })) return null;
8759
+ return { parentId: channelCtx.parentId };
8760
+ }
8761
+ async function resolveAuthorizedComponentInteraction(params) {
8762
+ const interactionCtx = await resolveInteractionContextWithDmAuth({
8763
+ ctx: params.ctx,
8764
+ interaction: params.interaction,
8765
+ label: params.label,
8766
+ componentLabel: params.componentLabel,
8767
+ defer: params.defer
8768
+ });
8769
+ if (!interactionCtx) return null;
8770
+ const { channelId, user, replyOpts, rawGuildId, memberRoleIds } = interactionCtx;
8771
+ const guildInfo = resolveDiscordGuildEntry({
8772
+ guild: params.interaction.guild ?? void 0,
8773
+ guildId: rawGuildId,
8774
+ guildEntries: params.ctx.guildEntries
8775
+ });
8776
+ const channelCtx = resolveDiscordChannelContext(params.interaction);
8777
+ const allowNameMatching = isDangerousNameMatchingEnabled(params.ctx.discordConfig);
8778
+ const channelConfig = resolveDiscordChannelConfigWithFallback({
8779
+ guildInfo,
8780
+ channelId,
8781
+ channelName: channelCtx.channelName,
8782
+ channelSlug: channelCtx.channelSlug,
8783
+ parentId: channelCtx.parentId,
8784
+ parentName: channelCtx.parentName,
8785
+ parentSlug: channelCtx.parentSlug,
8786
+ scope: channelCtx.isThread ? "thread" : "channel"
8787
+ });
8788
+ if (!await ensureGuildComponentMemberAllowed({
8789
+ interaction: params.interaction,
8790
+ guildInfo,
8791
+ channelId,
8792
+ rawGuildId,
8793
+ channelCtx,
8794
+ memberRoleIds,
8795
+ user,
8796
+ replyOpts,
8797
+ componentLabel: params.componentLabel,
8798
+ unauthorizedReply: params.unauthorizedReply,
8799
+ allowNameMatching,
8800
+ groupPolicy: resolveComponentRuntimeGroupPolicy(params.ctx)
8801
+ })) return null;
8802
+ return {
8803
+ interactionCtx,
8804
+ channelCtx,
8805
+ guildInfo,
8806
+ channelConfig,
8807
+ allowNameMatching,
8808
+ commandAuthorized: await resolveComponentCommandAuthorized({
8809
+ ctx: params.ctx,
8810
+ interactionCtx,
8811
+ channelConfig,
8812
+ guildInfo,
8813
+ allowNameMatching
8814
+ }),
8815
+ user,
8816
+ replyOpts
8713
8817
  };
8714
8818
  }
8715
- async function ensureVoiceCommandAccess(params) {
8716
- const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
8717
- if (access.ok) return true;
8718
- await params.interaction.reply({
8719
- content: access.message ?? "Not authorized.",
8720
- ephemeral: true
8819
+ async function resolveComponentCommandAuthorized(params) {
8820
+ const { ctx, interactionCtx, channelConfig, guildInfo } = params;
8821
+ if (interactionCtx.isDirectMessage) return true;
8822
+ const { ownerAllowList, ownerAllowed: ownerOk } = resolveDiscordOwnerAccess({
8823
+ allowFrom: ctx.allowFrom,
8824
+ sender: {
8825
+ id: interactionCtx.user.id,
8826
+ name: interactionCtx.user.username,
8827
+ tag: formatDiscordUserTag(interactionCtx.user)
8828
+ },
8829
+ allowNameMatching: params.allowNameMatching
8830
+ });
8831
+ const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
8832
+ channelConfig,
8833
+ guildInfo,
8834
+ memberRoleIds: interactionCtx.memberRoleIds,
8835
+ sender: {
8836
+ id: interactionCtx.user.id,
8837
+ name: interactionCtx.user.username,
8838
+ tag: formatDiscordUserTag(interactionCtx.user)
8839
+ },
8840
+ allowNameMatching: params.allowNameMatching
8841
+ });
8842
+ const useAccessGroups = ctx.cfg.commands?.useAccessGroups !== false;
8843
+ return resolveCommandAuthorizedFromAuthorizers({
8844
+ useAccessGroups,
8845
+ authorizers: useAccessGroups ? [{
8846
+ configured: ownerAllowList != null,
8847
+ allowed: ownerOk
8848
+ }, {
8849
+ configured: hasAccessRestrictions,
8850
+ allowed: memberAllowed
8851
+ }] : [{
8852
+ configured: hasAccessRestrictions,
8853
+ allowed: memberAllowed
8854
+ }],
8855
+ modeWhenAccessGroupsOff: "configured"
8721
8856
  });
8722
- return false;
8723
- }
8724
- function createDiscordVoiceCommand(params) {
8725
- const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
8726
- class JoinCommand extends Command {
8727
- constructor(..._args) {
8728
- super(..._args);
8729
- this.name = "join";
8730
- this.description = "Join a voice channel";
8731
- this.defer = true;
8732
- this.ephemeral = params.ephemeralDefault;
8733
- this.options = [{
8734
- name: "channel",
8735
- description: "Voice channel to join",
8736
- type: ApplicationCommandOptionType.Channel,
8737
- required: true,
8738
- channel_types: VOICE_CHANNEL_TYPES
8739
- }];
8740
- }
8741
- async run(interaction) {
8742
- const channel = await interaction.options.getChannel("channel", true);
8743
- if (!channel || !("id" in channel)) {
8744
- await interaction.reply({
8745
- content: "Voice channel not found.",
8746
- ephemeral: true
8747
- });
8748
- return;
8749
- }
8750
- const access = await authorizeVoiceCommand(interaction, params, { channelOverride: {
8751
- id: channel.id,
8752
- name: resolveDiscordChannelNameSafe(channel)
8753
- } });
8754
- if (!access.ok) {
8755
- await interaction.reply({
8756
- content: access.message ?? "Not authorized.",
8757
- ephemeral: true
8758
- });
8759
- return;
8760
- }
8761
- if (!isVoiceChannelType(channel.type)) {
8762
- await interaction.reply({
8763
- content: "That is not a voice channel.",
8764
- ephemeral: true
8765
- });
8766
- return;
8767
- }
8768
- const guildId = access.guildId ?? ("guildId" in channel ? channel.guildId : void 0);
8769
- if (!guildId) {
8770
- await interaction.reply({
8771
- content: "Unable to resolve guild for this voice channel.",
8772
- ephemeral: true
8773
- });
8774
- return;
8775
- }
8776
- const manager = params.getManager();
8777
- if (!manager) {
8778
- await interaction.reply({
8779
- content: "Voice manager is not available yet.",
8780
- ephemeral: true
8781
- });
8782
- return;
8783
- }
8784
- const result = await manager.join({
8785
- guildId,
8786
- channelId: channel.id
8787
- });
8788
- await interaction.reply({
8789
- content: result.message,
8790
- ephemeral: true
8791
- });
8792
- }
8793
- }
8794
- class LeaveCommand extends Command {
8795
- constructor(..._args2) {
8796
- super(..._args2);
8797
- this.name = "leave";
8798
- this.description = "Leave the current voice channel";
8799
- this.defer = true;
8800
- this.ephemeral = params.ephemeralDefault;
8801
- }
8802
- async run(interaction) {
8803
- const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
8804
- if (!runtimeContext) return;
8805
- const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
8806
- if (!await ensureVoiceCommandAccess({
8807
- interaction,
8808
- context: params,
8809
- channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
8810
- })) return;
8811
- const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
8812
- await interaction.reply({
8813
- content: result.message,
8814
- ephemeral: true
8815
- });
8816
- }
8817
- }
8818
- class StatusCommand extends Command {
8819
- constructor(..._args3) {
8820
- super(..._args3);
8821
- this.name = "status";
8822
- this.description = "Show active voice sessions";
8823
- this.defer = true;
8824
- this.ephemeral = params.ephemeralDefault;
8825
- }
8826
- async run(interaction) {
8827
- const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
8828
- if (!runtimeContext) return;
8829
- const sessions = runtimeContext.manager.status().filter((entry) => entry.guildId === runtimeContext.guildId);
8830
- const sessionChannelId = sessions[0]?.channelId;
8831
- if (!await ensureVoiceCommandAccess({
8832
- interaction,
8833
- context: params,
8834
- channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
8835
- })) return;
8836
- if (sessions.length === 0) {
8837
- await interaction.reply({
8838
- content: "No active voice sessions.",
8839
- ephemeral: true
8840
- });
8841
- return;
8842
- }
8843
- const lines = sessions.map((entry) => `• ${formatMention({ channelId: entry.channelId })} (guild ${entry.guildId})`);
8844
- await interaction.reply({
8845
- content: lines.join("\n"),
8846
- ephemeral: true
8847
- });
8848
- }
8849
- }
8850
- return new class extends CommandWithSubcommands {
8851
- constructor(..._args4) {
8852
- super(..._args4);
8853
- this.name = "vc";
8854
- this.description = "Voice channel controls";
8855
- this.subcommands = [
8856
- new JoinCommand(),
8857
- new LeaveCommand(),
8858
- new StatusCommand()
8859
- ];
8860
- }
8861
- }();
8862
- }
8863
- function isVoiceChannelType(type) {
8864
- return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
8865
8857
  }
8866
8858
  //#endregion
8867
8859
  //#region extensions/discord/src/monitor/agent-components-data.ts
@@ -9174,7 +9166,7 @@ async function deliverDiscordReply(params) {
9174
9166
  //#endregion
9175
9167
  //#region extensions/discord/src/monitor/agent-components.dispatch.ts
9176
9168
  const loadConversationRuntime$1 = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.js"));
9177
- const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-CKd2NMWG.js").then((n) => n.n));
9169
+ const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-wxtm1NlF.js").then((n) => n.n));
9178
9170
  function buildDiscordComponentConversationLabel(params) {
9179
9171
  if (params.interactionCtx.isDirectMessage) return buildDirectLabel(params.interactionCtx.user);
9180
9172
  if (params.interactionCtx.isGroupDm) return `Group DM #${params.channelCtx.channelName ?? params.interactionCtx.channelId} channel id:${params.interactionCtx.channelId}`;
@@ -9283,7 +9275,7 @@ async function dispatchDiscordComponentEvent(params) {
9283
9275
  previousTimestamp,
9284
9276
  envelope: envelopeOptions
9285
9277
  });
9286
- const { createReplyReferencePlanner, dispatchReplyWithBufferedBlockDispatcher, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit, recordInboundSession } = await (async () => {
9278
+ const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await (async () => {
9287
9279
  return { ...await loadConversationRuntime$1() };
9288
9280
  })();
9289
9281
  const ctxPayload = finalizeInboundContext({
@@ -9359,12 +9351,11 @@ async function dispatchDiscordComponentEvent(params) {
9359
9351
  cfg: ctx.cfg,
9360
9352
  channel: "discord",
9361
9353
  accountId,
9362
- agentId,
9363
- routeSessionKey: sessionKey,
9364
- storePath,
9354
+ route: {
9355
+ agentId,
9356
+ sessionKey
9357
+ },
9365
9358
  ctxPayload,
9366
- recordInboundSession,
9367
- dispatchReplyWithBufferedBlockDispatcher,
9368
9359
  record: {
9369
9360
  updateLastRoute: interactionCtx.isDirectMessage ? {
9370
9361
  sessionKey: inboundLastRouteSessionKey,
@@ -9587,7 +9578,7 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
9587
9578
  }
9588
9579
  //#endregion
9589
9580
  //#region extensions/discord/src/monitor/agent-components.handlers.ts
9590
- const loadComponentsRuntime = createLazyRuntimeModule(() => import("./outbound-session-route-D4QqePZN.js").then((n) => n.n));
9581
+ const loadComponentsRuntime = createLazyRuntimeModule(() => import("./outbound-session-route-M2bEY9tI.js").then((n) => n.n));
9591
9582
  async function handleDiscordComponentEvent(params) {
9592
9583
  const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
9593
9584
  if (!parsed) {
@@ -10276,6 +10267,74 @@ function createDiscordExecApprovalButtonContext(params) {
10276
10267
  };
10277
10268
  }
10278
10269
  //#endregion
10270
+ //#region extensions/discord/src/monitor/questions.ts
10271
+ var QuestionButton = class extends Button {
10272
+ constructor(ctx) {
10273
+ super();
10274
+ this.ctx = ctx;
10275
+ this.label = "question";
10276
+ this.customId = "ocq:id=seed;i=0";
10277
+ this.style = ButtonStyle.Primary;
10278
+ }
10279
+ async run(interaction, data) {
10280
+ const callback = parseDiscordQuestionData(data);
10281
+ if (!callback) {
10282
+ await interaction.reply({
10283
+ content: "This question is no longer valid.",
10284
+ ephemeral: true
10285
+ });
10286
+ return;
10287
+ }
10288
+ if (!await this.ctx.authorizeQuestion(interaction)) return;
10289
+ try {
10290
+ await interaction.acknowledge();
10291
+ } catch {}
10292
+ let result;
10293
+ try {
10294
+ result = await this.ctx.resolveQuestion({
10295
+ cfg: this.ctx.cfg,
10296
+ questionId: callback.questionId,
10297
+ optionIndex: callback.optionIndex,
10298
+ senderId: interaction.userId,
10299
+ clientDisplayName: `Discord question (${this.ctx.accountId})`
10300
+ });
10301
+ } catch {
10302
+ try {
10303
+ await interaction.followUp({
10304
+ content: "Could not submit this answer.",
10305
+ ephemeral: true
10306
+ });
10307
+ } catch {}
10308
+ return;
10309
+ }
10310
+ try {
10311
+ await interaction.followUp({
10312
+ content: result.status === "answered" ? "Answer submitted." : "This question was already answered.",
10313
+ ephemeral: true
10314
+ });
10315
+ } catch {}
10316
+ }
10317
+ };
10318
+ function createDiscordQuestionButton(params) {
10319
+ const authContext = params.authContext ?? {
10320
+ cfg: params.cfg,
10321
+ accountId: params.accountId
10322
+ };
10323
+ return new QuestionButton({
10324
+ cfg: params.cfg,
10325
+ accountId: params.accountId,
10326
+ resolveQuestion: params.resolveQuestion ?? questionGatewayRuntime.resolveOption,
10327
+ authorizeQuestion: params.authorizeQuestion ?? (async (interaction) => Boolean(await resolveAuthorizedComponentInteraction({
10328
+ ctx: authContext,
10329
+ interaction,
10330
+ label: "discord question",
10331
+ componentLabel: "button",
10332
+ unauthorizedReply: "You are not authorized to answer this question.",
10333
+ defer: false
10334
+ })))
10335
+ });
10336
+ }
10337
+ //#endregion
10279
10338
  //#region extensions/discord/src/monitor/provider.interactions.ts
10280
10339
  function createDiscordProviderInteractionSurface(params) {
10281
10340
  const createNativeCommand = params.createNativeCommand ?? createDiscordNativeCommand;
@@ -10320,6 +10379,20 @@ function createDiscordProviderInteractionSurface(params) {
10320
10379
  abortSignal: params.abortSignal
10321
10380
  });
10322
10381
  const components = [
10382
+ createDiscordQuestionButton({
10383
+ cfg: params.cfg,
10384
+ accountId: params.accountId,
10385
+ authContext: {
10386
+ cfg: params.cfg,
10387
+ accountId: params.accountId,
10388
+ discordConfig: params.discordConfig,
10389
+ runtime: params.runtime,
10390
+ token: params.token,
10391
+ guildEntries: params.guildEntries,
10392
+ allowFrom: params.allowFrom,
10393
+ dmPolicy: params.dmPolicy
10394
+ }
10395
+ }),
10323
10396
  createDiscordCommandArgFallbackButton({
10324
10397
  cfg: params.cfg,
10325
10398
  discordConfig: params.discordConfig,
@@ -10915,7 +10988,7 @@ async function monitorDiscordProvider(opts = {}) {
10915
10988
  runtime,
10916
10989
  botUserId
10917
10990
  });
10918
- const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-TDZcMriu.js").then((n) => n.n);
10991
+ const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-DjDbt14x.js").then((n) => n.n);
10919
10992
  setDiscordTranscriptsVoiceManager({
10920
10993
  accountId: account.accountId,
10921
10994
  manager: voiceManager
@@ -10927,6 +11000,7 @@ async function monitorDiscordProvider(opts = {}) {
10927
11000
  registerDiscordListener(client.listeners, new DiscordVoiceStateUpdateListener(voiceManager));
10928
11001
  }
10929
11002
  const messageHandler = discordProviderSessionRuntime.createDiscordMessageHandler({
11003
+ client,
10930
11004
  cfg,
10931
11005
  discordConfig: discordCfg,
10932
11006
  accountId: account.accountId,
@@ -11006,7 +11080,7 @@ async function monitorDiscordProvider(opts = {}) {
11006
11080
  gatewayRuntimeReadyTimeoutMs: account.config.gatewayRuntimeReadyTimeoutMs
11007
11081
  });
11008
11082
  } finally {
11009
- cleanupDiscordProviderStartup({
11083
+ await cleanupDiscordProviderStartup({
11010
11084
  deactivateMessageHandler,
11011
11085
  autoPresenceController,
11012
11086
  setStatus: opts.setStatus,
@@ -11021,4 +11095,4 @@ async function monitorDiscordProvider(opts = {}) {
11021
11095
  }
11022
11096
  }
11023
11097
  //#endregion
11024
- export { resolveDiscordTextCommandAccess as A, registerDiscordListener as C, resolveDiscordThreadStarter as D, resolveDiscordReplyTarget as E, sanitizeDiscordThreadName as O, handleDiscordDmCommandDecision as S, resolveDiscordAutoThreadReplyPlan as T, createDiscordSupplementalContextAccessChecker as _, buildDirectLabel as a, resolveDiscordEffectiveRoute as b, resolveDiscordVoiceAccess as c, resolveDiscordGatewayIntents as d, waitForDiscordGatewayPluginRegistration as f, buildDiscordInboundAccessContext as g, buildDiscordGroupSystemPrompt as h, sanitizeDiscordFrontChannelReplyPayloads as i, resolveDiscordDmCommandAccess as k, authorizeDiscordVoiceIngress as l, createDiscordNativeCommand as m, deliverDiscordReply as n, buildGuildLabel as o, resolveDiscordVoiceEnabled as p, formatDiscordReplyDeliveryFailure as r, resolveReplyContext as s, monitorDiscordProvider as t, createDiscordGatewayPlugin as u, buildDiscordRoutePeer as v, threading_exports as w, shouldIgnoreStaleDiscordRouteBinding as x, resolveDiscordConversationRoute as y };
11098
+ export { resolveDiscordDmCommandAccess as A, mapGatewayDispatchData as C, resolveDiscordReplyTarget as D, resolveDiscordAutoThreadReplyPlan as E, resolveDiscordThreadStarter as O, handleDiscordDmCommandDecision as S, threading_exports as T, createDiscordSupplementalContextAccessChecker as _, buildDirectLabel as a, resolveDiscordEffectiveRoute as b, resolveDiscordVoiceAccess as c, resolveDiscordGatewayIntents as d, waitForDiscordGatewayPluginRegistration as f, buildDiscordInboundAccessContext as g, buildDiscordGroupSystemPrompt as h, sanitizeDiscordFrontChannelReplyPayloads as i, resolveDiscordTextCommandAccess as j, sanitizeDiscordThreadName as k, authorizeDiscordVoiceIngress as l, createDiscordNativeCommand as m, deliverDiscordReply as n, buildGuildLabel as o, resolveDiscordVoiceEnabled as p, formatDiscordReplyDeliveryFailure as r, resolveReplyContext as s, monitorDiscordProvider as t, createDiscordGatewayPlugin as u, buildDiscordRoutePeer as v, registerDiscordListener as w, shouldIgnoreStaleDiscordRouteBinding as x, resolveDiscordConversationRoute as y };