@openclaw/discord 2026.9.6 → 2026.9.8

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 (150) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{account-inspect-BwQj24ht.mjs → account-inspect-De8hOUxG.mjs} +1 -1
  3. package/dist/.setup/{accounts-CwJQoLjM.mjs → accounts-ChaMcixG.mjs} +1 -4
  4. package/dist/.setup/{activities-api-COU4-0nR.mjs → activities-api-tvbsU2e3.mjs} +38 -66
  5. package/dist/.setup/{api-CBK9zcq5.mjs → api-DVbJwZVt.mjs} +10 -2
  6. package/dist/.setup/{approval-handler.runtime-CbBktBb4.mjs → approval-handler.runtime-DxCK2Rux.mjs} +49 -125
  7. package/dist/.setup/{approval-message-updates-jf9zMaIC.mjs → approval-message-updates-BKFqavHZ.mjs} +2 -2
  8. package/dist/.setup/{audit-vKbh-LFR.mjs → audit-CLg9I71N.mjs} +5 -5
  9. package/dist/.setup/{channel-Dv4e3Jpc.mjs → channel-DxlUVU9t.mjs} +121 -227
  10. package/dist/.setup/{channel-type-DKnjV1XW.mjs → channel-type-DRCrEMss.mjs} +22 -22
  11. package/dist/.setup/{channel.setup-0NX6FFwi.mjs → channel.setup-CRo1GjV7.mjs} +6 -9
  12. package/dist/.setup/{components-yBEb75bB.mjs → components-Cq1PvIpN.mjs} +41 -69
  13. package/dist/.setup/{config-schema-CiZz-mtA.mjs → config-schema-oxELUSDx.mjs} +19 -44
  14. package/dist/.setup/{conversation-binding-route-B7qImK_b.mjs → conversation-binding-route-Caz_XuFH.mjs} +10 -5
  15. package/dist/.setup/{directory-config-BytTftz-.mjs → directory-config-esqNn0Eo.mjs} +6 -9
  16. package/dist/.setup/{directory-live--EGTH0DC.mjs → directory-live-DtKRHuGV.mjs} +6 -12
  17. package/dist/.setup/{discord-BXpHW-cu.mjs → discord-0xJYfdDD.mjs} +82 -386
  18. package/dist/.setup/{doctor-D1R-uFIu.mjs → doctor-BCl1H5tl.mjs} +21 -36
  19. package/dist/.setup/{doctor-contract-Co5vRCZ6.mjs → doctor-contract-CvvgwrrG.mjs} +41 -50
  20. package/dist/.setup/{channel-actions.runtime-leZuw01r.mjs → handle-action-CUvQWnE7.mjs} +67 -104
  21. package/dist/.setup/{handle-action.guild-admin-DcFa8NwA.mjs → handle-action.guild-admin-Df-8gVle.mjs} +62 -120
  22. package/dist/.setup/{live-policy-config-eKQ-PLdy.mjs → live-policy-config-8Pv20CHc.mjs} +2 -3
  23. package/dist/.setup/{message-handler-X6ejmbtY.mjs → message-handler-B-Jk4oDk.mjs} +18 -94
  24. package/dist/.setup/{message-handler.preflight-pluralkit-8Xji34AF.mjs → message-handler.preflight-pluralkit-CWLUBVcx.mjs} +8 -10
  25. package/dist/.setup/{message-handler.preflight-DE_POxFc.mjs → message-handler.preflight-v-__NSDq.mjs} +69 -180
  26. package/dist/.setup/{message-handler.process-CCmIVnxy.mjs → message-handler.process-BNFFuChn.mjs} +65 -86
  27. package/dist/.setup/{outbound-adapter-ClIgmu4F.mjs → outbound-adapter-BobT-kse.mjs} +105 -19
  28. package/dist/.setup/{outbound-session-route-VulUE0yV.mjs → outbound-session-route-zVGxxceg.mjs} +140 -108
  29. package/dist/.setup/{pluralkit-CdAt1G0P.mjs → pluralkit-a6_NLfH9.mjs} +1 -1
  30. package/dist/.setup/{presence-cache-dYSHPWMx.mjs → presence-cache-Di3H3DIU.mjs} +0 -4
  31. package/dist/.setup/{probe-CupW4we4.mjs → probe-LYrIHlBF.mjs} +13 -4
  32. package/dist/.setup/{provider-iOf73HW-.mjs → provider-B_G5hASF.mjs} +721 -1416
  33. package/dist/.setup/provider-session.runtime-BYlTBFD2.mjs +6 -0
  34. package/dist/.setup/provider.runtime-CUE3UxER.mjs +2 -0
  35. package/dist/.setup/{realtime-session.runtime-Dz8uVutq.mjs → realtime-session.runtime-oUd9DOcz.mjs} +41 -55
  36. package/dist/.setup/{receive-recovery-DHst8WRx.mjs → receive-recovery-CHPOsnLc.mjs} +1 -4
  37. package/dist/.setup/{resolve-allowlist-common-CwMBzbx9.mjs → resolve-allowlist-common-DPdRggu5.mjs} +4 -7
  38. package/dist/.setup/{resolve-channels-BbvsLQOZ.mjs → resolve-channels-BFPNRmVv.mjs} +21 -40
  39. package/dist/.setup/{resolve-users-ByFlR7LQ.mjs → resolve-users-0-aBuCy3.mjs} +4 -4
  40. package/dist/.setup/{retry-BEYkDy0P.mjs → retry-pz_cSha2.mjs} +3 -3
  41. package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
  42. package/dist/.setup/{runtime-B8lJfyrA.mjs → runtime-FN000lxA.mjs} +60 -162
  43. package/dist/.setup/runtime-doctor-migrations-CshUGl36.mjs +159 -0
  44. package/dist/.setup/{runtime-DisDbixd.mjs → runtime-sUksZ--Q.mjs} +2 -5
  45. package/dist/.setup/{secret-config-contract-DFu9hfU8.mjs → secret-config-contract-uOE2J7yM.mjs} +15 -85
  46. package/dist/.setup/{security-audit-s5w50-Ly.mjs → security-audit-Cdaegq7C.mjs} +3 -1
  47. package/dist/.setup/{send-CIBzvXjS.mjs → send-CrfEI6Bs.mjs} +53 -108
  48. package/dist/.setup/{send.components-ChY21qr-.mjs → send.components-DxQAMfES.mjs} +62 -107
  49. package/dist/.setup/{send.outbound-QTyuFupn.mjs → send.outbound-BISKnb-a.mjs} +66 -140
  50. package/dist/.setup/{send.shared-VNvWfX2T.mjs → send.shared-DGFkbkQR.mjs} +10 -25
  51. package/dist/.setup/{sender-identity-0Ymgvmaj.mjs → sender-identity-B9X5Vb9R.mjs} +2 -3
  52. package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +3 -0
  53. package/dist/.setup/{shared-DHPDaMSx.mjs → shared-B3wZ4hN-.mjs} +25 -32
  54. package/dist/.setup/{subagent-hooks-CjW7r8Pe.mjs → subagent-hooks-nlUE9ow7.mjs} +5 -6
  55. package/dist/.setup/system-events-CdeZnvPV.mjs +33 -0
  56. package/dist/.setup/{target-resolver-BXpy6VT8.mjs → target-resolver-BuLapkhy.mjs} +9 -12
  57. package/dist/.setup/targets-0KUcEIYx.mjs +3 -0
  58. package/dist/.setup/{thread-bindings-CEh2dhqP.mjs → thread-bindings-D7TfgjR_.mjs} +33 -35
  59. package/dist/.setup/{thread-bindings.manager-ve-i6oqt.mjs → thread-bindings.manager-DN-NissX.mjs} +325 -233
  60. package/dist/.setup/thread-bindings.session-updates-CshfKghV.mjs +359 -0
  61. package/dist/.setup/{thread-bindings.state-BThFQEga.mjs → thread-bindings.state-g6v9zAym.mjs} +21 -62
  62. package/dist/.setup/{transcripts-source-DVegW0WI.mjs → transcripts-source-p8EV179h.mjs} +76 -235
  63. package/dist/.setup/{typing-BKZL5fGj.mjs → typing-BiHCzBRu.mjs} +2 -1
  64. package/dist/.setup/{voice-runtime-elTtjEIG.mjs → voice-runtime-B46rcwrG.mjs} +140 -244
  65. package/dist/account-inspect-api.js +1 -1
  66. package/dist/action-runtime-api.js +1 -1
  67. package/dist/activities-api.js +1 -1
  68. package/dist/api.js +18 -18
  69. package/dist/channel-config-api.js +1 -1
  70. package/dist/channel-plugin-api.js +1 -1
  71. package/dist/directory-contract-api.js +1 -1
  72. package/dist/doctor-contract-api.js +4 -4
  73. package/dist/index.js +1 -1
  74. package/dist/runtime-api.js +20 -20
  75. package/dist/secret-contract-api.js +1 -1
  76. package/dist/security-audit-contract-api.js +1 -1
  77. package/dist/setup-entry.js +1 -1
  78. package/dist/setup-plugin-api.js +1 -1
  79. package/dist/src/voice/audio-worker.runtime.js +15 -24
  80. package/dist/subagent-hooks-api.js +3 -4
  81. package/dist/transcripts-source-api.js +1 -1
  82. package/node_modules/@types/node/README.md +2 -2
  83. package/node_modules/@types/node/child_process.d.ts +1 -1
  84. package/node_modules/@types/node/crypto.d.ts +20 -8
  85. package/node_modules/@types/node/ffi.d.ts +14 -0
  86. package/node_modules/@types/node/http2.d.ts +3 -2
  87. package/node_modules/@types/node/net.d.ts +16 -4
  88. package/node_modules/@types/node/package.json +2 -17
  89. package/node_modules/@types/node/process.d.ts +1 -0
  90. package/node_modules/@types/node/quic.d.ts +39 -1
  91. package/node_modules/@types/node/stream/iter.d.ts +9 -12
  92. package/node_modules/@types/node/test/reporters.d.ts +1 -0
  93. package/node_modules/@types/node/test.d.ts +72 -0
  94. package/node_modules/@types/node/tls.d.ts +14 -10
  95. package/node_modules/@types/node/vm.d.ts +2 -1
  96. package/node_modules/@types/node/worker_threads.d.ts +4 -1
  97. package/node_modules/typebox/build/compile/code.mjs +1 -2
  98. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  99. package/node_modules/typebox/build/format/iri.mjs +16 -9
  100. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  101. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  102. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  103. package/node_modules/typebox/build/guard/index.mjs +6 -0
  104. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  105. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  106. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  107. package/node_modules/typebox/build/schema/build.mjs +2 -3
  108. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  109. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  110. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  111. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  112. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  113. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  114. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  115. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  116. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  117. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  118. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  119. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  120. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  121. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  122. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  123. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  124. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  125. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  126. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  127. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  128. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  129. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  130. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  131. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  132. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  133. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  134. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  135. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  136. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  137. package/node_modules/typebox/package.json +1 -1
  138. package/node_modules/typebox/readme.md +3 -1
  139. package/openclaw.plugin.json +21 -1
  140. package/package.json +5 -5
  141. package/dist/.setup/agent-components.runtime-CEPrf2SY.mjs +0 -4
  142. package/dist/.setup/probe.runtime-DBQ_AGPe.mjs +0 -2
  143. package/dist/.setup/provider-session.runtime-DrGAYnZv.mjs +0 -6
  144. package/dist/.setup/provider.runtime-BmjW_pIw.mjs +0 -2
  145. package/dist/.setup/security-audit.runtime-DHtYenx9.mjs +0 -2
  146. package/dist/.setup/setup-plugin-api-Dvr41dyx.mjs +0 -3
  147. package/dist/.setup/system-events-B2YEEMbS.mjs +0 -34
  148. package/dist/.setup/targets-CvemhN3i.mjs +0 -3
  149. package/dist/.setup/thread-bindings.session-updates-DCQq1WZ5.mjs +0 -55
  150. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,38 +1,39 @@
1
- import { D as Message, E as Guild, G as Row, J as StringSelectMenu, L as Button, O as User, P as Modal, Q as BaseMessageInteractiveComponent, T as CommandWithSubcommands, Y as TextDisplay, a as MessageCreateListener, c as PresenceUpdateListener, d as ThreadDeleteListener, f as ThreadUpdateListener, h as Plugin, i as InteractionCreateListener, k as hasDiscordV2Components, l as ReadyListener, m as Client, n as GuildCreateListener, o as MessageReactionAddListener, q as Separator, r as GuildDeleteListener, s as MessageReactionRemoveListener, t as discord_exports, v as RateLimitError, w as Command, z as Container } from "./discord-BXpHW-cu.mjs";
2
- import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, c as parseExecApprovalData, d as buildDiscordComponentMessage, k as encodeCustomIdComponent, o as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./components-yBEb75bB.mjs";
3
- import { C as resolveTimestampMs, E as getDiscordEndpointRuntime, T as assertDiscordEndpointGatewayUrl, a as normalizeDiscordDisplaySlug, b as formatDiscordReactionEmoji, c as resolveDiscordChannelConfig, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAllowFrom, h as resolveDiscordOwnerAccess, i as normalizeDiscordAllowList, l as resolveDiscordChannelConfigWithFallback, m as resolveDiscordMemberAllowed, o as normalizeDiscordSlug, p as resolveDiscordMemberAccessState, r as isDiscordGroupAllowedByPolicy, s as resolveDiscordAllowListMatch, t as isDiscordThreadChannelType, u as resolveDiscordChannelPolicyCommandAuthorizer, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./channel-type-DKnjV1XW.mjs";
4
- import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, h as resolveDiscordToken, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, o as mergeDiscordAccountConfig, p as resolveDiscordMaxLinesPerMessage } from "./accounts-CwJQoLjM.mjs";
5
- import { a as registerDiscordComponentEntries, o as resolveDiscordComponentEntryWithPersistence, s as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-ChY21qr-.mjs";
1
+ import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, c as parseExecApprovalData, d as buildDiscordComponentMessage, k as encodeCustomIdComponent, o as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./components-Cq1PvIpN.mjs";
2
+ import { $ as BaseMessageInteractiveComponent, B as Container, D as Message, E as Guild, J as Separator, K as Row, O as User, P as Modal, R as Button, T as CommandWithSubcommands, X as TextDisplay, Y as StringSelectMenu, a as MessageCreateListener, c as PresenceUpdateListener, d as ThreadDeleteListener, f as ThreadUpdateListener, h as Plugin, i as InteractionCreateListener, k as hasDiscordV2Components, l as ReadyListener, m as Client, n as GuildCreateListener, o as MessageReactionAddListener, r as GuildDeleteListener, s as MessageReactionRemoveListener, t as discord_exports, v as RateLimitError, w as Command } from "./discord-0xJYfdDD.mjs";
3
+ import { D as getDiscordEndpointRuntime, E as assertDiscordEndpointGatewayUrl, S as formatDiscordUserTag, _ as resolveDiscordOwnerAllowFrom, a as normalizeDiscordDisplaySlug, b as shouldEmitDiscordReactionNotification, c as resolveDiscordChannelConfig, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAccess, i as normalizeDiscordAllowList, l as resolveDiscordChannelConfigWithFallback, m as resolveDiscordMemberAllowed, o as normalizeDiscordSlug, p as resolveDiscordMemberAccessState, r as isDiscordGroupAllowedByPolicy, s as resolveDiscordAllowListMatch, t as isDiscordThreadChannelType, u as resolveDiscordChannelPolicyCommandAuthorizer, w as resolveTimestampMs, x as formatDiscordReactionEmoji, y as resolveGroupDmAllow } from "./channel-type-DRCrEMss.mjs";
4
+ import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, h as resolveDiscordToken, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, o as mergeDiscordAccountConfig, p as resolveDiscordMaxLinesPerMessage } from "./accounts-ChaMcixG.mjs";
5
+ import { a as registerDiscordComponentEntries, o as resolveDiscordComponentEntryWithPersistence, s as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-DxQAMfES.mjs";
6
6
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.mjs";
7
- import { a as isDiscordRateLimitResponseBody, o as summarizeDiscordResponseBody } from "./api-CBK9zcq5.mjs";
8
- import { o as chunkDiscordTextWithMode } from "./retry-BEYkDy0P.mjs";
9
- import { B as validateDiscordProxyUrl, G as unregisterGateway, P as createDiscordRestClient, R as DISCORD_REST_TIMEOUT_MS, V as withValidatedDiscordProxy, W as registerGateway, b as canViewDiscordGuildChannel, w as hasAnyChannelPermissionDiscord } from "./send.shared-VNvWfX2T.mjs";
10
- import { o as formatMention, t as sendMessageDiscord } from "./send.outbound-QTyuFupn.mjs";
11
- import { n as getDiscordActivitiesRuntime } from "./runtime-DisDbixd.mjs";
7
+ import { a as isDiscordRateLimitResponseBody, s as summarizeDiscordResponseBody } from "./api-DVbJwZVt.mjs";
8
+ import { o as chunkDiscordTextWithMode } from "./retry-pz_cSha2.mjs";
9
+ import { B as withValidatedDiscordProxy, C as hasAnyChannelPermissionDiscord, L as DISCORD_REST_TIMEOUT_MS, N as createDiscordRestClient, U as registerGateway, W as unregisterGateway, y as canViewDiscordGuildChannel, z as validateDiscordProxyUrl } from "./send.shared-DGFkbkQR.mjs";
10
+ import { o as formatMention, t as sendMessageDiscord } from "./send.outbound-BISKnb-a.mjs";
11
+ import { n as getDiscordActivitiesRuntime } from "./runtime-sUksZ--Q.mjs";
12
12
  import { t as resolveDiscordCommandOwnerAllowFrom } from "./command-owners-D78sAoOz.mjs";
13
13
  import { n as resolveDiscordChannelInfoSafe, o as resolveDiscordChannelTopicSafe, r as resolveDiscordChannelNameSafe } from "./channel-access-C12aDZ0p.mjs";
14
- import { O as resolveDiscordMessageStickers, c as authorizeDiscordVoiceIngress, d as resolveDiscordThreadLikeChannelContext, f as resolveFetchedDiscordThreadLikeChannelContext, i as setDiscordTranscriptsVoiceManager, l as resolveDiscordVoiceAccess, s as resolveDiscordVoiceEnabled } from "./transcripts-source-DVegW0WI.mjs";
15
- import { i as setPresence, t as clearPresences } from "./presence-cache-dYSHPWMx.mjs";
16
- import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-CIBzvXjS.mjs";
14
+ import { D as resolveDiscordReferencedReplyMessage, O as resolveDiscordReferencedReplyMessageId, a as resolveDiscordVoiceEnabled, i as setDiscordTranscriptsVoiceManager, l as resolveDiscordThreadLikeChannelContext, o as authorizeDiscordVoiceIngress, s as resolveDiscordVoiceAccess, u as resolveFetchedDiscordThreadLikeChannelContext } from "./transcripts-source-p8EV179h.mjs";
15
+ import { i as setPresence, t as clearPresences } from "./presence-cache-Di3H3DIU.mjs";
16
+ import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-CrfEI6Bs.mjs";
17
17
  import { c as raceWithTimeout, u as withAbortTimeout } from "./timeouts-D86uWLt_.mjs";
18
- import { D as isDiscordExecApprovalClientEnabled, T as getDiscordExecApprovalApprovers, a as resolveDiscordComponentSpec, c as formatDiscordApprovalDisplayValue, d as resolveDiscordBoundConversationRoute, h as resolveDiscordConversationIdentity, l as buildDiscordConversationRouteContext, n as DISCORD_PRESENTATION_CAPABILITIES, p as resolveDiscordEffectiveRoute, r as buildDiscordPresentationPayload, s as DISCORD_APPROVAL_ALLOWED_MENTIONS, u as buildDiscordRoutePeer } from "./outbound-session-route-VulUE0yV.mjs";
19
- import { n as discordIngressIdentity, t as selectDiscordLivePolicyConfig } from "./live-policy-config-eKQ-PLdy.mjs";
20
- import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BbvsLQOZ.mjs";
21
- import { t as resolveDiscordUserAllowlist } from "./resolve-users-ByFlR7LQ.mjs";
22
- import { o as isThreadArchived, r as getThreadBindingManager, u as formatThreadBindingDurationLabel } from "./thread-bindings.manager-ve-i6oqt.mjs";
23
- import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-CupW4we4.mjs";
18
+ import { D as isDiscordExecApprovalClientEnabled, T as getDiscordExecApprovalApprovers, a as resolveDiscordComponentSpec, c as formatDiscordApprovalDisplayValue, d as resolveDiscordBoundConversationRoute, h as resolveDiscordConversationIdentity, l as buildDiscordConversationRouteContext, n as DISCORD_PRESENTATION_CAPABILITIES, p as resolveDiscordEffectiveRoute, r as buildDiscordPresentationPayload, s as DISCORD_APPROVAL_ALLOWED_MENTIONS, u as buildDiscordRoutePeer } from "./outbound-session-route-zVGxxceg.mjs";
19
+ import { n as discordIngressIdentity, t as selectDiscordLivePolicyConfig } from "./live-policy-config-8Pv20CHc.mjs";
20
+ import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BFPNRmVv.mjs";
21
+ import { t as resolveDiscordUserAllowlist } from "./resolve-users-0-aBuCy3.mjs";
22
+ import { a as isThreadArchived, n as getThreadBindingManager } from "./thread-bindings.manager-DN-NissX.mjs";
23
+ import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-LYrIHlBF.mjs";
24
24
  import { i as sanitizeRecentModels, n as normalizeModelRef, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.mjs";
25
- import { t as resolveDiscordSenderIdentity } from "./sender-identity-0Ymgvmaj.mjs";
26
- import { n as hasDiscordApprovalControl, t as discordApprovalMessageUpdates } from "./approval-message-updates-jf9zMaIC.mjs";
25
+ import { t as resolveDiscordSenderIdentity } from "./sender-identity-B9X5Vb9R.mjs";
26
+ import { n as hasDiscordApprovalControl, t as discordApprovalMessageUpdates } from "./approval-message-updates-BKFqavHZ.mjs";
27
27
  import { createRequire } from "node:module";
28
28
  import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
29
29
  import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes, PermissionFlagsBits } from "discord-api-types/v10";
30
30
  import { Type } from "typebox";
31
31
  import { Check, Errors } from "typebox/value";
32
32
  import { createHash, randomUUID } from "node:crypto";
33
- import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolvePromptHistoryLimit, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
34
33
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
34
+ import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolvePromptHistoryLimit, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
35
35
  import { inspect } from "node:util";
36
+ import * as fetchRuntimeSdk from "openclaw/plugin-sdk/fetch-runtime";
36
37
  import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent, resolveEnvHttpProxyAgentOptions, wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
37
38
  import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
38
39
  import { fetchWithSsrFGuard, formatErrorMessage, resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -58,23 +59,23 @@ import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProvi
58
59
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
59
60
  import { buildChannelInboundEventContext, createChannelPartialDeliveryError, createCommandTurnContext, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
60
61
  import path from "node:path";
61
- import { resolvePinnedMainDmOwnerFromAllowlist as resolvePinnedMainDmOwnerFromAllowlist$1 } from "openclaw/plugin-sdk/security-runtime";
62
+ import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
62
63
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
63
64
  import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
64
- import { buildPairingReply, upsertChannelPairingRequest, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
65
+ import { buildPairingReply, formatThreadBindingDurationLabel, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
65
66
  import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute } from "openclaw/plugin-sdk/conversation-binding-runtime";
66
67
  import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
67
68
  import { readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
68
69
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
69
70
  import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
70
71
  import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
71
- import { enqueueRoutedSystemEvent, enqueueRoutedSystemEvent as enqueueRoutedSystemEvent$1 } from "openclaw/plugin-sdk/system-event-runtime";
72
+ import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
72
73
  import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, listAgentIds, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
73
- import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1 } from "openclaw/plugin-sdk/session-store-runtime";
74
- import { captureHttpExchange, captureWsEvent, resolveDebugProxySettings, resolveEffectiveDebugProxyUrl } from "openclaw/plugin-sdk/proxy-capture";
74
+ import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
75
+ import * as proxyCaptureSdk from "openclaw/plugin-sdk/proxy-capture";
76
+ import { resolveDebugProxySettings, resolveEffectiveDebugProxyUrl } from "openclaw/plugin-sdk/proxy-capture";
75
77
  import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
76
78
  import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch";
77
- import { Agent } from "undici";
78
79
  import * as dns from "node:dns";
79
80
  import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, mergeNativeCommandSpecs, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
80
81
  import { PLUGIN_COMMAND_DISPATCH } from "openclaw/plugin-sdk/plugin-command-runtime";
@@ -82,7 +83,7 @@ import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-
82
83
  import * as modelsProviderRuntime from "openclaw/plugin-sdk/models-provider-runtime";
83
84
  import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
84
85
  import { EventEmitter } from "node:events";
85
- import { Agent as Agent$1 } from "node:https";
86
+ import { Agent } from "node:https";
86
87
  import { channelReadyPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
87
88
  import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
88
89
  import { stripPlainTextToolCallBlocks } from "openclaw/plugin-sdk/tool-payload";
@@ -528,22 +529,10 @@ async function runDiscordReactionHandler(initialParams) {
528
529
  listener: params.listener,
529
530
  event: params.event,
530
531
  run: async () => handleDiscordReactionEvent({
532
+ ...params.handlerParams,
531
533
  data: params.data,
532
534
  client: params.client,
533
- action: params.action,
534
- cfg: params.handlerParams.cfg,
535
- isPolicyCurrent: params.handlerParams.isPolicyCurrent,
536
- accountId: params.handlerParams.accountId,
537
- botUserId: params.handlerParams.botUserId,
538
- dmEnabled: params.handlerParams.dmEnabled,
539
- groupDmEnabled: params.handlerParams.groupDmEnabled,
540
- groupDmChannels: params.handlerParams.groupDmChannels,
541
- dmPolicy: params.handlerParams.dmPolicy,
542
- allowFrom: params.handlerParams.allowFrom,
543
- groupPolicy: params.handlerParams.groupPolicy,
544
- allowNameMatching: params.handlerParams.allowNameMatching,
545
- guildEntries: params.handlerParams.guildEntries,
546
- logger: params.handlerParams.logger
535
+ action: params.action
547
536
  })
548
537
  });
549
538
  }
@@ -625,51 +614,6 @@ async function authorizeDiscordReactionIngress(params) {
625
614
  };
626
615
  return { allowed: true };
627
616
  }
628
- async function handleDiscordThreadReactionNotification(params) {
629
- if (params.reactionMode === "off") return;
630
- if (params.reactionMode === "all" || params.reactionMode === "allowlist") {
631
- const { access, channelConfig } = await params.resolveThreadChannelAccess();
632
- if (!access.allowed || !params.shouldNotifyReaction({
633
- mode: params.reactionMode,
634
- channelConfig
635
- })) return;
636
- const { baseText } = params.resolveReactionBase();
637
- params.emitReaction(baseText, params.parentId);
638
- return;
639
- }
640
- const message = await params.message.fetch().catch(() => null);
641
- const { access, channelConfig } = await params.resolveThreadChannelAccess();
642
- const messageAuthorId = message?.author?.id ?? void 0;
643
- if (!access.allowed || !params.shouldNotifyReaction({
644
- mode: params.reactionMode,
645
- messageAuthorId,
646
- channelConfig
647
- })) return;
648
- params.emitReactionWithAuthor(message);
649
- }
650
- async function handleDiscordChannelReactionNotification(params) {
651
- if (params.isGuildMessage) {
652
- if (!(await params.authorizeReactionIngressForChannel(params.channelConfig)).allowed) return;
653
- }
654
- if (params.reactionMode === "off") return;
655
- if (params.reactionMode === "all" || params.reactionMode === "allowlist") {
656
- if (!params.shouldNotifyReaction({
657
- mode: params.reactionMode,
658
- channelConfig: params.channelConfig
659
- })) return;
660
- const { baseText } = params.resolveReactionBase();
661
- params.emitReaction(baseText, params.parentId);
662
- return;
663
- }
664
- const message = await params.message.fetch().catch(() => null);
665
- const messageAuthorId = message?.author?.id ?? void 0;
666
- if (!params.shouldNotifyReaction({
667
- mode: params.reactionMode,
668
- messageAuthorId,
669
- channelConfig: params.channelConfig
670
- })) return;
671
- params.emitReactionWithAuthor(message);
672
- }
673
617
  function hasDiscordGuildChannelOverrides(guildInfo) {
674
618
  return Boolean(guildInfo?.channels && Object.keys(guildInfo.channels).length > 0);
675
619
  }
@@ -757,57 +701,10 @@ async function handleDiscordReactionEvent(params) {
757
701
  const parentId = isThreadChannel ? channelContext.threadParentId : channelContext.parentId;
758
702
  const parentName = isThreadChannel ? channelContext.threadParentName : void 0;
759
703
  const parentSlug = isThreadChannel ? channelContext.threadParentSlug : "";
760
- let reactionBase = null;
761
- const resolveReactionBase = () => {
762
- if (reactionBase) return reactionBase;
763
- const emojiLabel = formatDiscordReactionEmoji(data.emoji);
764
- const actorLabel = formatDiscordUserTag(user) || user.id;
765
- const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
766
- const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
767
- reactionBase = {
768
- baseText: `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`,
769
- contextKey: `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`
770
- };
771
- return reactionBase;
772
- };
773
- const emitReaction = (text, parentPeerId) => {
774
- const { contextKey } = resolveReactionBase();
775
- const route = resolveAgentRoute({
776
- cfg: params.cfg,
777
- channel: "discord",
778
- accountId: params.accountId,
779
- guildId: data.guild_id ?? void 0,
780
- memberRoleIds,
781
- peer: {
782
- kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
783
- id: isDirectMessage ? user.id : data.channel_id
784
- },
785
- parentPeer: parentPeerId ? {
786
- kind: "channel",
787
- id: parentPeerId
788
- } : void 0
789
- });
790
- enqueueRoutedSystemEvent(text, route, { contextKey });
791
- };
792
- const shouldNotifyReaction = (options) => shouldEmitDiscordReactionNotification({
793
- mode: options.mode,
794
- botId: botUserId,
795
- messageAuthorId: options.messageAuthorId,
796
- userId: user.id,
797
- userName: user.username,
798
- userTag: formatDiscordUserTag(user),
799
- channelConfig: options.channelConfig,
800
- guildInfo,
801
- memberRoleIds,
802
- allowNameMatching: params.allowNameMatching
803
- });
804
- const emitReactionWithAuthor = (message) => {
805
- const { baseText } = resolveReactionBase();
806
- const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
807
- const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
808
- emitReaction(text, parentId);
809
- };
810
- const resolveThreadChannelConfig = () => resolveDiscordChannelConfigWithFallback({
704
+ if (isThreadChannel && reactionMode === "off") return;
705
+ let message = null;
706
+ if (isThreadChannel && reactionMode === "own") message = await data.message.fetch().catch(() => null);
707
+ const channelConfig = resolveDiscordChannelConfigWithFallback({
811
708
  guildInfo,
812
709
  channelId: data.channel_id,
813
710
  channelName,
@@ -815,54 +712,51 @@ async function handleDiscordReactionEvent(params) {
815
712
  parentId,
816
713
  parentName,
817
714
  parentSlug,
818
- scope: "thread"
819
- });
820
- const authorizeReactionIngressForChannel = async (channelConfig) => await authorizeDiscordReactionIngress({
821
- ...reactionIngressBase,
822
- channelConfig
715
+ scope: isThreadChannel ? "thread" : "channel"
823
716
  });
824
- const resolveThreadChannelAccess = async () => {
825
- const channelConfig = resolveThreadChannelConfig();
826
- return {
827
- access: await authorizeReactionIngressForChannel(channelConfig),
717
+ if (isGuildMessage || isThreadChannel) {
718
+ if (!(await authorizeDiscordReactionIngress({
719
+ ...reactionIngressBase,
828
720
  channelConfig
829
- };
830
- };
831
- if (isThreadChannel) {
832
- await handleDiscordThreadReactionNotification({
833
- reactionMode,
834
- message: data.message,
835
- parentId,
836
- resolveThreadChannelAccess,
837
- shouldNotifyReaction,
838
- resolveReactionBase,
839
- emitReaction,
840
- emitReactionWithAuthor
841
- });
842
- return;
721
+ })).allowed) return;
843
722
  }
844
- const channelConfig = resolveDiscordChannelConfigWithFallback({
845
- guildInfo,
846
- channelId: data.channel_id,
847
- channelName,
848
- channelSlug,
849
- parentId,
850
- parentName,
851
- parentSlug,
852
- scope: "channel"
853
- });
854
- await handleDiscordChannelReactionNotification({
855
- isGuildMessage,
856
- reactionMode,
857
- message: data.message,
723
+ if (!isThreadChannel && reactionMode === "own") message = await data.message.fetch().catch(() => null);
724
+ if (!shouldEmitDiscordReactionNotification({
725
+ mode: reactionMode,
726
+ botId: botUserId,
727
+ messageAuthorId: message?.author?.id,
728
+ userId: user.id,
729
+ userName: user.username,
730
+ userTag: formatDiscordUserTag(user),
858
731
  channelConfig,
859
- parentId,
860
- authorizeReactionIngressForChannel,
861
- shouldNotifyReaction,
862
- resolveReactionBase,
863
- emitReaction,
864
- emitReactionWithAuthor
732
+ guildInfo,
733
+ memberRoleIds,
734
+ allowNameMatching: params.allowNameMatching
735
+ })) return;
736
+ const emojiLabel = formatDiscordReactionEmoji(data.emoji);
737
+ const actorLabel = formatDiscordUserTag(user) || user.id;
738
+ const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
739
+ const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
740
+ const baseText = `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`;
741
+ const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
742
+ const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
743
+ const contextKey = `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`;
744
+ const route = resolveAgentRoute({
745
+ cfg: params.cfg,
746
+ channel: "discord",
747
+ accountId: params.accountId,
748
+ guildId: data.guild_id ?? void 0,
749
+ memberRoleIds,
750
+ peer: {
751
+ kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
752
+ id: isDirectMessage ? user.id : data.channel_id
753
+ },
754
+ parentPeer: parentId ? {
755
+ kind: "channel",
756
+ id: parentId
757
+ } : void 0
865
758
  });
759
+ enqueueRoutedSystemEvent(text, route, { contextKey });
866
760
  } catch (err) {
867
761
  params.logger.error(danger(`discord reaction handler failed: ${String(err)}`));
868
762
  }
@@ -898,7 +792,7 @@ var DiscordInteractionListener = class extends InteractionCreateListener {
898
792
  }
899
793
  async handle(data, client) {
900
794
  this.onEvent?.();
901
- Promise.resolve().then(() => client.handleInteraction(data, {})).catch((err) => {
795
+ Promise.resolve().then(() => client.handleInteraction(data)).catch((err) => {
902
796
  (this.logger ?? discordEventQueueLog).error(danger(`discord interaction handler failed: ${String(err)}`));
903
797
  });
904
798
  }
@@ -1253,7 +1147,7 @@ var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
1253
1147
  event: this.type,
1254
1148
  run: async () => {
1255
1149
  const threadId = data.id;
1256
- getThreadBindingManager(this.accountId)?.unbindThread({
1150
+ await getThreadBindingManager(this.accountId)?.unbindThread({
1257
1151
  threadId,
1258
1152
  reason: "thread-delete",
1259
1153
  sendFarewell: false
@@ -1275,14 +1169,12 @@ var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
1275
1169
  };
1276
1170
  //#endregion
1277
1171
  //#region extensions/discord/src/internal/gateway-dispatch.ts
1278
- function dispatchVoiceGatewayEvent(client, type, data) {
1279
- const guildId = readGuildId(data);
1172
+ function dispatchVoiceGatewayEvent(client, payload) {
1173
+ const guildId = readGuildId(payload.d);
1280
1174
  if (!guildId) return;
1281
1175
  const adapter = (client.getPlugin("voice")?.adapters)?.get(guildId);
1282
- const voiceServerUpdate = GatewayDispatchEvents.VoiceServerUpdate;
1283
- const voiceStateUpdate = GatewayDispatchEvents.VoiceStateUpdate;
1284
- if (type === voiceServerUpdate) adapter?.onVoiceServerUpdate?.(data);
1285
- if (type === voiceStateUpdate) adapter?.onVoiceStateUpdate?.(data);
1176
+ if (payload.t === GatewayDispatchEvents.VoiceServerUpdate) adapter?.onVoiceServerUpdate?.(payload.d);
1177
+ if (payload.t === GatewayDispatchEvents.VoiceStateUpdate) adapter?.onVoiceStateUpdate?.(payload.d);
1286
1178
  }
1287
1179
  function mapGatewayDispatchData(client, type, data) {
1288
1180
  const messageCreate = GatewayDispatchEvents.MessageCreate;
@@ -1513,10 +1405,8 @@ async function resolveAllowFromByUserAllowlist(params) {
1513
1405
  function collectGuildUserEntries(guildEntries) {
1514
1406
  const userEntries = /* @__PURE__ */ new Set();
1515
1407
  for (const guild of Object.values(guildEntries)) {
1516
- if (!guild || typeof guild !== "object") continue;
1517
1408
  addAllowlistUserEntriesFromConfigEntry(userEntries, guild);
1518
- const channels = guild.channels ?? {};
1519
- for (const channel of Object.values(channels)) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
1409
+ for (const channel of Object.values(guild.channels ?? {})) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
1520
1410
  }
1521
1411
  return userEntries;
1522
1412
  }
@@ -1533,15 +1423,13 @@ async function resolveGuildEntriesByUserAllowlist(params) {
1533
1423
  formatResolved: formatDiscordUserResolved,
1534
1424
  formatUnresolved: formatDiscordUserUnresolved
1535
1425
  });
1536
- const nextGuilds = { ...params.guildEntries };
1537
- for (const [guildKey, guildConfig] of Object.entries(params.guildEntries)) {
1538
- if (!guildConfig || typeof guildConfig !== "object") continue;
1426
+ const nextGuilds = patchAllowlistUsersInConfigEntries({
1427
+ entries: params.guildEntries,
1428
+ resolvedMap,
1429
+ strategy: "canonicalize"
1430
+ });
1431
+ for (const [guildKey, guildConfig] of Object.entries(nextGuilds)) {
1539
1432
  const nextGuild = { ...guildConfig };
1540
- const users = guildConfig.users;
1541
- if (Array.isArray(users) && users.length > 0) nextGuild.users = canonicalizeAllowlistWithResolvedIds({
1542
- existing: users,
1543
- resolvedMap
1544
- });
1545
1433
  const channels = guildConfig.channels ?? {};
1546
1434
  if (channels && typeof channels === "object") nextGuild.channels = patchAllowlistUsersInConfigEntries({
1547
1435
  entries: channels,
@@ -1601,7 +1489,7 @@ function isDiscordTransportHostname(hostname) {
1601
1489
  return DISCORD_DNS_HOSTS.some((target) => normalized === target || normalized.endsWith(`.${target}`));
1602
1490
  }
1603
1491
  function reorderLookupAddresses(addresses) {
1604
- if (!Array.isArray(addresses) || addresses.length < 2) return addresses;
1492
+ if (addresses.length < 2) return addresses;
1605
1493
  const ipv4 = addresses.filter((entry) => entry.family === 4);
1606
1494
  const ipv6 = addresses.filter((entry) => entry.family === 6);
1607
1495
  if (ipv4.length === 0) return ipv6;
@@ -1654,13 +1542,9 @@ function createDiscordEndpointDnsLookup(endpointHostname) {
1654
1542
  }
1655
1543
  //#endregion
1656
1544
  //#region extensions/discord/src/monitor/rest-fetch.ts
1545
+ const captureSdk$2 = proxyCaptureSdk;
1546
+ const fetchSdk = fetchRuntimeSdk;
1657
1547
  const discordDnsLookup$1 = createDiscordDnsLookup();
1658
- function createDirectDiscordRestDispatcher() {
1659
- return new Agent({
1660
- allowH2: false,
1661
- connect: { lookup: discordDnsLookup$1 }
1662
- });
1663
- }
1664
1548
  function createEnvProxyDiscordRestDispatcher(runtime) {
1665
1549
  const envProxyOptions = resolveEnvHttpProxyAgentOptions();
1666
1550
  if (!envProxyOptions) return;
@@ -1679,7 +1563,7 @@ function createDiscordRestFetchWithDispatcher(dispatcher) {
1679
1563
  ...init,
1680
1564
  dispatcher
1681
1565
  }).then((response) => {
1682
- captureHttpExchange({
1566
+ captureSdk$2.captureHttpExchangeAsync?.({
1683
1567
  url: resolveRequestUrl(input),
1684
1568
  method: init?.method ?? "GET",
1685
1569
  requestHeaders: init?.headers,
@@ -1687,7 +1571,7 @@ function createDiscordRestFetchWithDispatcher(dispatcher) {
1687
1571
  response,
1688
1572
  flowId: randomUUID(),
1689
1573
  meta: { subsystem: "discord-rest" }
1690
- });
1574
+ }).catch(() => {});
1691
1575
  return response;
1692
1576
  })));
1693
1577
  }
@@ -1699,7 +1583,12 @@ function resolveDiscordRestFetch(proxyUrl, runtime) {
1699
1583
  runtime.log?.("discord: rest proxy enabled");
1700
1584
  return fetcher;
1701
1585
  }
1702
- return createDiscordRestFetchWithDispatcher(createEnvProxyDiscordRestDispatcher(runtime) ?? createDirectDiscordRestDispatcher());
1586
+ return createDiscordRestFetchWithDispatcher(createEnvProxyDiscordRestDispatcher(runtime) ?? fetchSdk.createHttp1Agent?.({ connect: { lookup: discordDnsLookup$1 } }) ?? createHttp1EnvHttpProxyAgent({
1587
+ httpProxy: "",
1588
+ httpsProxy: "",
1589
+ noProxy: "*",
1590
+ connect: { lookup: discordDnsLookup$1 }
1591
+ }));
1703
1592
  }
1704
1593
  //#endregion
1705
1594
  //#region extensions/discord/src/monitor/live-policy.ts
@@ -1847,6 +1736,13 @@ async function readDiscordInteractionPolicy(readPolicy) {
1847
1736
  //#endregion
1848
1737
  //#region extensions/discord/src/monitor/native-command-reply.ts
1849
1738
  const DISCORD_EMPTY_VISIBLE_REPLY_WARNING = "⚠️ Command produced no visible reply.";
1739
+ function resolveDiscordInteractionReplyOptions(params) {
1740
+ return {
1741
+ textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
1742
+ maxLinesPerMessage: resolveDiscordMaxLinesPerMessage(params),
1743
+ chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
1744
+ };
1745
+ }
1850
1746
  function isDiscordUnknownInteraction(error) {
1851
1747
  if (!error || typeof error !== "object") return false;
1852
1748
  const err = error;
@@ -1936,54 +1832,32 @@ async function deliverDiscordInteractionReply(params) {
1936
1832
  if (!payloadDelivered) throw expiry;
1937
1833
  throw createChannelPartialDeliveryError(expiry, { visibleReplySent: true });
1938
1834
  };
1939
- if (reply.hasMedia) {
1940
- const media = await Promise.all(reply.mediaUrls.map(async (url) => {
1941
- const loaded = await loadWebMedia(url, { localRoots: params.mediaLocalRoots });
1942
- return {
1943
- name: loaded.fileName ?? "upload",
1944
- data: loaded.buffer,
1945
- contentType: loaded.contentType
1946
- };
1947
- }));
1948
- const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
1949
- maxChars: textLimit,
1950
- maxLines: maxLinesPerMessage,
1951
- chunkMode
1952
- }));
1953
- await sendMessage(chunks[0] ?? "", media, firstMessageComponents, firstMessageEmbeds);
1954
- for (const chunk of chunks.slice(1)) {
1955
- if (!chunk.trim()) continue;
1956
- await sendMessage(chunk);
1957
- }
1958
- return payloadDelivered;
1959
- }
1960
- if (!reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
1835
+ const files = reply.hasMedia ? await Promise.all(reply.mediaUrls.map(async (url) => {
1836
+ const loaded = await loadWebMedia(url, { localRoots: params.mediaLocalRoots });
1837
+ return {
1838
+ name: loaded.fileName ?? "upload",
1839
+ data: loaded.buffer,
1840
+ contentType: loaded.contentType
1841
+ };
1842
+ })) : void 0;
1843
+ if (!files && !reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
1961
1844
  const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
1962
1845
  maxChars: textLimit,
1963
1846
  maxLines: maxLinesPerMessage,
1964
1847
  chunkMode
1965
1848
  }));
1966
1849
  if (chunks.length === 0) chunks.push("");
1967
- for (const chunk of chunks) {
1968
- if (!chunk.trim() && !firstMessageComponents && !firstMessageEmbeds) continue;
1969
- await sendMessage(chunk, void 0, firstMessageComponents, firstMessageEmbeds);
1850
+ for (const [index, chunk] of chunks.entries()) {
1851
+ const chunkFiles = index === 0 ? files : void 0;
1852
+ if (!chunk.trim() && !chunkFiles && !firstMessageComponents && !firstMessageEmbeds) continue;
1853
+ await sendMessage(chunk, chunkFiles, firstMessageComponents, firstMessageEmbeds);
1970
1854
  }
1971
1855
  return payloadDelivered;
1972
1856
  }
1973
1857
  //#endregion
1974
1858
  //#region extensions/discord/src/monitor/native-command-route.ts
1975
1859
  function resolveDiscordNativeInteractionRouteState(params) {
1976
- const route = resolveDiscordBoundConversationRoute({
1977
- cfg: params.cfg,
1978
- accountId: params.accountId,
1979
- guildId: params.guildId,
1980
- memberRoleIds: params.memberRoleIds,
1981
- isDirectMessage: params.isDirectMessage,
1982
- isGroupDm: params.isGroupDm,
1983
- directUserId: params.directUserId,
1984
- conversationId: params.conversationId,
1985
- parentConversationId: params.parentConversationId
1986
- });
1860
+ const route = resolveDiscordBoundConversationRoute(params);
1987
1861
  const configuredRoute = params.threadBinding == null ? resolveConfiguredBindingRoute({
1988
1862
  cfg: params.cfg,
1989
1863
  route,
@@ -2051,15 +1925,9 @@ async function dispatchDiscordNativeAgentReply(params) {
2051
1925
  sessionKey: params.ctxPayload.CommandTargetSessionKey ?? params.effectiveRoute.sessionKey
2052
1926
  },
2053
1927
  mediaLocalRoots: params.mediaLocalRoots,
2054
- textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
2055
- maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
2056
- cfg: params.cfg,
2057
- discordConfig: params.discordConfig,
2058
- accountId: params.accountId
2059
- }),
1928
+ ...resolveDiscordInteractionReplyOptions(params),
2060
1929
  preferFollowUp: params.preferFollowUp || didReply,
2061
- responseEphemeral: params.responseEphemeral,
2062
- chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
1930
+ responseEphemeral: params.responseEphemeral
2063
1931
  });
2064
1932
  didReply ||= payloadDelivered;
2065
1933
  return payloadDelivered ? { visibleReplySent: true } : {
@@ -2105,11 +1973,7 @@ async function dispatchDiscordNativeAgentReply(params) {
2105
1973
  content: DISCORD_EMPTY_VISIBLE_REPLY_WARNING,
2106
1974
  ephemeral: true
2107
1975
  };
2108
- if (params.preferFollowUp) {
2109
- await params.interaction.followUp(payload);
2110
- return;
2111
- }
2112
- await params.interaction.reply(payload);
1976
+ await params.interaction[params.preferFollowUp ? "followUp" : "reply"](payload);
2113
1977
  });
2114
1978
  return dispatchResult;
2115
1979
  }
@@ -2121,9 +1985,6 @@ function resolveDiscordSlashCommandConfig(raw) {
2121
1985
  //#endregion
2122
1986
  //#region extensions/discord/src/monitor/native-command-arg-ui.ts
2123
1987
  const DISCORD_COMMAND_ARG_CUSTOM_ID_KEY = "cmdarg";
2124
- function createCommandArgsWithValue(params) {
2125
- return { values: { [params.argName]: params.value } };
2126
- }
2127
1988
  function buildDiscordCommandArgCustomId(params) {
2128
1989
  return [
2129
1990
  `${DISCORD_COMMAND_ARG_CUSTOM_ID_KEY}:command=${encodeCustomIdComponent(params.command)}`,
@@ -2168,46 +2029,33 @@ async function handleDiscordCommandArgInteraction(params) {
2168
2029
  return;
2169
2030
  }
2170
2031
  if (await clearWithMessage(`⏳ Applying ${parsed.value}...`) === null) return;
2171
- const commandArgs = createCommandArgsWithValue({
2172
- argName: parsed.arg,
2173
- value: parsed.value
2174
- });
2032
+ const commandArgs = { values: { [parsed.arg]: parsed.value } };
2175
2033
  const commandArgsWithRaw = {
2176
2034
  ...commandArgs,
2177
2035
  raw: serializeCommandArgs(commandDefinition, commandArgs)
2178
2036
  };
2179
2037
  const prompt = buildCommandTextFromArgs(commandDefinition, commandArgsWithRaw);
2180
2038
  await params.dispatchCommandInteraction({
2181
- readPolicy: ctx.readPolicy,
2039
+ ...ctx,
2182
2040
  interaction,
2183
2041
  prompt,
2184
2042
  command: commandDefinition,
2185
2043
  commandArgs: commandArgsWithRaw,
2186
- cfg: ctx.cfg,
2187
- discordConfig: ctx.discordConfig,
2188
- accountId: ctx.accountId,
2189
- sessionPrefix: ctx.sessionPrefix,
2190
2044
  preferFollowUp: true,
2191
- threadBindings: ctx.threadBindings,
2192
2045
  responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
2193
- buildContext: ctx.buildContext,
2194
- dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
2195
2046
  pluginCommandDispatch: { kind: "non-plugin" }
2196
2047
  });
2197
2048
  }
2198
- async function runDiscordCommandArgButton(params) {
2199
- await handleDiscordCommandArgInteraction(params);
2200
- }
2201
2049
  var DiscordCommandArgButton = class extends Button {
2202
2050
  constructor(params) {
2203
2051
  super();
2204
- this.style = ButtonStyle.Secondary;
2052
+ this.params = params;
2205
2053
  this.label = params.label;
2206
2054
  this.customId = params.customId;
2207
- this.params = params;
2055
+ this.style = params.style ?? ButtonStyle.Secondary;
2208
2056
  }
2209
2057
  async run(interaction, data) {
2210
- await runDiscordCommandArgButton({
2058
+ await handleDiscordCommandArgInteraction({
2211
2059
  ...this.params,
2212
2060
  interaction,
2213
2061
  data
@@ -2241,23 +2089,13 @@ function buildDiscordCommandArgMenu(params) {
2241
2089
  components: rows
2242
2090
  };
2243
2091
  }
2244
- var DiscordCommandArgFallbackButton = class extends Button {
2245
- constructor(params) {
2246
- super();
2247
- this.params = params;
2248
- this.label = "cmdarg";
2249
- this.customId = "cmdarg:seed=1";
2250
- }
2251
- async run(interaction, data) {
2252
- await runDiscordCommandArgButton({
2253
- ...this.params,
2254
- interaction,
2255
- data
2256
- });
2257
- }
2258
- };
2259
2092
  function createDiscordCommandArgFallbackButton$1(params) {
2260
- return new DiscordCommandArgFallbackButton(params);
2093
+ return new DiscordCommandArgButton({
2094
+ ...params,
2095
+ label: "cmdarg",
2096
+ customId: "cmdarg:seed=1",
2097
+ style: ButtonStyle.Primary
2098
+ });
2261
2099
  }
2262
2100
  //#endregion
2263
2101
  //#region extensions/discord/src/monitor/inbound-context.ts
@@ -2286,15 +2124,13 @@ function buildDiscordGroupSystemPrompt(channelConfig) {
2286
2124
  return channelConfig?.systemPrompt?.trim() || void 0;
2287
2125
  }
2288
2126
  function buildDiscordChannelStructuredContext(params) {
2289
- if (!params.isGuild) return;
2290
- const entries = [];
2291
- if (typeof params.channelTopic === "string" && params.channelTopic.trim().length > 0) entries.push({
2127
+ if (!params.isGuild || typeof params.channelTopic !== "string" || !params.channelTopic.trim()) return;
2128
+ return [{
2292
2129
  label: "Discord channel metadata",
2293
2130
  source: "discord",
2294
2131
  type: "channel_metadata",
2295
2132
  payload: { topic: params.channelTopic.trim() }
2296
- });
2297
- return entries.length > 0 ? entries : void 0;
2133
+ }];
2298
2134
  }
2299
2135
  function buildDiscordInboundAccessContext(params) {
2300
2136
  return {
@@ -2502,9 +2338,7 @@ function createDiscordNativeCommandAuthority(params) {
2502
2338
  }).senderIsOwner);
2503
2339
  const commands = resolveDiscordNativeCommandAllowlistAccess({
2504
2340
  cfg,
2505
- accountId: params.accountId,
2506
2341
  sender: params.sender,
2507
- chatType: params.ctx.ChatType === "direct" ? "direct" : "channel",
2508
2342
  guildId: params.guildId
2509
2343
  });
2510
2344
  return {
@@ -2574,10 +2408,7 @@ function resolveDiscordNativeCommandChannelAccessContext(params) {
2574
2408
  const guild = params.guild ?? null;
2575
2409
  const commandsAllowFromAccess = resolveDiscordNativeCommandAllowlistAccess({
2576
2410
  cfg: params.cfg,
2577
- accountId: params.accountId,
2578
2411
  sender: params.sender,
2579
- chatType: params.isDirectMessage ? "direct" : params.isThreadChannel ? "thread" : guild ? "channel" : "group",
2580
- conversationId: params.rawChannelId || void 0,
2581
2412
  guildId: guild?.id
2582
2413
  });
2583
2414
  const guildInfo = resolveDiscordGuildEntry({
@@ -2619,10 +2450,6 @@ async function resolveDiscordGuildNativeCommandAuthorized(params) {
2619
2450
  sender: params.sender,
2620
2451
  allowNameMatching: params.allowNameMatching
2621
2452
  });
2622
- const commandAllowlistAuthorizer = {
2623
- configured: params.commandsAllowFromAccess.configured,
2624
- allowed: params.commandsAllowFromAccess.allowed
2625
- };
2626
2453
  const ownerAuthorizer = {
2627
2454
  configured: params.ownerAllowListConfigured,
2628
2455
  allowed: params.ownerAllowed
@@ -2640,9 +2467,9 @@ async function resolveDiscordGuildNativeCommandAuthorized(params) {
2640
2467
  ownerAuthorizer,
2641
2468
  memberAuthorizer
2642
2469
  ];
2643
- const authorizers = params.commandsAllowFromAccess.configured ? [commandAllowlistAuthorizer] : fallbackAuthorizers;
2470
+ const authorizers = params.commandsAllowFromAccess.configured ? [params.commandsAllowFromAccess] : fallbackAuthorizers;
2644
2471
  return resolveCommandAuthorizedFromAuthorizers({
2645
- useAccessGroups: params.useAccessGroups,
2472
+ useAccessGroups: true,
2646
2473
  authorizers,
2647
2474
  modeWhenAccessGroupsOff: "configured"
2648
2475
  });
@@ -2678,38 +2505,25 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
2678
2505
  hasGuild: Boolean(interaction.guild),
2679
2506
  channelIdFallback: interaction.rawData.channel_id ?? ""
2680
2507
  });
2681
- const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId, threadParentName, threadParentSlug } = channelContext;
2508
+ const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId } = channelContext;
2682
2509
  if (params.isPolicyCurrent?.() === false) return false;
2683
2510
  const memberRoleIds = Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : [];
2684
2511
  const allowNameMatching = isDangerousNameMatchingEnabled(discordConfig);
2685
- const useAccessGroups = true;
2686
2512
  const configuredDmAllowFrom = resolveDiscordAccountAllowFrom({
2687
2513
  cfg,
2688
2514
  accountId
2689
2515
  }) ?? [];
2690
2516
  const { ownerAllowList, ownerAllowed: ownerOk } = resolveDiscordOwnerAccess({
2691
2517
  allowFrom: configuredDmAllowFrom,
2692
- sender: {
2693
- id: sender.id,
2694
- name: sender.name,
2695
- tag: sender.tag
2696
- },
2518
+ sender,
2697
2519
  allowNameMatching
2698
2520
  });
2699
2521
  const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
2700
2522
  cfg,
2701
2523
  discordConfig,
2702
- accountId,
2703
2524
  sender,
2704
- isDirectMessage,
2705
- isThreadChannel,
2706
- guild: interaction.guild ?? null,
2707
- rawChannelId,
2708
- channelName,
2709
- channelSlug,
2710
- threadParentId,
2711
- threadParentName,
2712
- threadParentSlug
2525
+ ...channelContext,
2526
+ guild: interaction.guild ?? null
2713
2527
  });
2714
2528
  if (channelConfig?.enabled === false) return false;
2715
2529
  if (interaction.guild && channelConfig?.allowed === false) return false;
@@ -2736,11 +2550,7 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
2736
2550
  accountId,
2737
2551
  dmPolicy,
2738
2552
  configuredAllowFrom: configuredDmAllowFrom,
2739
- sender: {
2740
- id: sender.id,
2741
- name: sender.name,
2742
- tag: sender.tag
2743
- },
2553
+ sender,
2744
2554
  allowNameMatching,
2745
2555
  cfg,
2746
2556
  rest: interaction.client.rest
@@ -2758,9 +2568,7 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
2758
2568
  if (!isDirectMessage) {
2759
2569
  if (!await resolveDiscordGuildNativeCommandAuthorized({
2760
2570
  cfg,
2761
- accountId,
2762
2571
  discordConfig,
2763
- useAccessGroups,
2764
2572
  commandsAllowFromAccess,
2765
2573
  guildInfo,
2766
2574
  channelConfig,
@@ -2836,14 +2644,11 @@ function openPreferenceStore(env) {
2836
2644
  ...env ? { env } : {}
2837
2645
  });
2838
2646
  }
2839
- function normalizeId(value) {
2840
- return normalizeOptionalString(value) ?? "";
2841
- }
2842
2647
  function buildDiscordModelPickerPreferenceKey(scope) {
2843
- const userId = normalizeId(scope.userId);
2648
+ const userId = normalizeOptionalString(scope.userId);
2844
2649
  if (!userId) return null;
2845
2650
  const accountId = normalizeAccountId(scope.accountId);
2846
- const guildId = normalizeId(scope.guildId);
2651
+ const guildId = normalizeOptionalString(scope.guildId);
2847
2652
  if (guildId) return `discord:${accountId}:guild:${guildId}:user:${userId}`;
2848
2653
  return `discord:${accountId}:dm:user:${userId}`;
2849
2654
  }
@@ -2863,6 +2668,12 @@ function sanitizeStoredPreferenceEntry(value) {
2863
2668
  function timestampOrder(value) {
2864
2669
  return value !== void 0 && value >= 0 ? value : 0;
2865
2670
  }
2671
+ function scopedPreferenceEntries(entries, scopeKey) {
2672
+ return entries.map((entry) => ({
2673
+ key: entry.key,
2674
+ value: sanitizeStoredPreferenceEntry(entry.value)
2675
+ })).filter((entry) => entry.value?.scopeKey === scopeKey);
2676
+ }
2866
2677
  function comparePreferenceEntries(left, right) {
2867
2678
  return preferenceTimestampMs(right.value.updatedAt) - preferenceTimestampMs(left.value.updatedAt) || timestampOrder(right.value.updatedOrder) - timestampOrder(left.value.updatedOrder) || left.key.localeCompare(right.key);
2868
2679
  }
@@ -2881,10 +2692,7 @@ async function readDiscordModelPickerRecentModels(params) {
2881
2692
  if (!key) return [];
2882
2693
  const limit = Math.max(1, Math.min(params.limit ?? DEFAULT_RECENT_LIMIT, 10));
2883
2694
  try {
2884
- const recent = (await openPreferenceStore(params.env).entries()).map((entry) => ({
2885
- key: entry.key,
2886
- value: sanitizeStoredPreferenceEntry(entry.value)
2887
- })).filter((entry) => entry.value?.scopeKey === key).toSorted(comparePreferenceEntries).map((entry) => entry.value.modelRef);
2695
+ const recent = scopedPreferenceEntries(await openPreferenceStore(params.env).entries(), key).toSorted(comparePreferenceEntries).map((entry) => entry.value.modelRef);
2888
2696
  if (!params.allowedModelRefs || params.allowedModelRefs.size === 0) return sanitizeRecentModels(recent, limit);
2889
2697
  return sanitizeRecentModels(recent.filter((modelRef) => params.allowedModelRefs?.has(modelRef)), limit);
2890
2698
  } catch {
@@ -2897,17 +2705,14 @@ async function recordDiscordModelPickerRecentModel(params) {
2897
2705
  if (!key || !normalizedModelRef) return;
2898
2706
  try {
2899
2707
  const store = openPreferenceStore(params.env);
2900
- const timestamp = nextPreferenceTimestamp((await store.entries()).map((entry) => sanitizeStoredPreferenceEntry(entry.value)).filter((entry) => entry?.scopeKey === key));
2708
+ const timestamp = nextPreferenceTimestamp(scopedPreferenceEntries(await store.entries(), key).map((entry) => entry.value));
2901
2709
  await store.register(buildPreferenceModelKey(key, normalizedModelRef), {
2902
2710
  scopeKey: key,
2903
2711
  modelRef: normalizedModelRef,
2904
2712
  ...timestamp
2905
2713
  });
2906
2714
  const limit = Math.max(1, Math.min(params.limit ?? DEFAULT_RECENT_LIMIT, 10));
2907
- const scopedEntries = (await store.entries()).map((entry) => ({
2908
- key: entry.key,
2909
- value: sanitizeStoredPreferenceEntry(entry.value)
2910
- })).filter((entry) => entry.value?.scopeKey === key).toSorted(comparePreferenceEntries);
2715
+ const scopedEntries = scopedPreferenceEntries(await store.entries(), key).toSorted(comparePreferenceEntries);
2911
2716
  await Promise.all(scopedEntries.slice(limit).map((entry) => store.delete(entry.key)));
2912
2717
  } catch {}
2913
2718
  }
@@ -2950,11 +2755,6 @@ const PICKER_VIEWS = [
2950
2755
  "models",
2951
2756
  "recents"
2952
2757
  ];
2953
- /**
2954
- * Alpha buckets engage only when the sorted item list exceeds the single-page
2955
- * select cap. Below this threshold the user gets the existing flat list +
2956
- * prev/next behavior unchanged.
2957
- */
2958
2758
  const DISCORD_MODEL_PICKER_BUCKET_THRESHOLD = DISCORD_COMPONENT_MAX_SELECT_OPTIONS;
2959
2759
  /** Target items per alpha bucket. Discord caps selects at 25 options. */
2960
2760
  const DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE = 20;
@@ -2976,9 +2776,7 @@ function isValidPickerView(value) {
2976
2776
  return PICKER_VIEWS.includes(value);
2977
2777
  }
2978
2778
  function normalizeModelPickerPage(value) {
2979
- const numeric = typeof value === "number" ? value : NaN;
2980
- if (!Number.isFinite(numeric)) return 1;
2981
- return Math.max(1, Math.floor(numeric));
2779
+ return normalizeOptionalModelPickerIndex(value) ?? 1;
2982
2780
  }
2983
2781
  function parseRawPage(value) {
2984
2782
  if (typeof value === "number") return normalizeModelPickerPage(value);
@@ -3109,17 +2907,6 @@ function parseDiscordModelPickerData(data) {
3109
2907
  ...modelBucketRaw ? { modelBucket: modelBucketRaw } : {}
3110
2908
  };
3111
2909
  }
3112
- /**
3113
- * Split a sorted item list into letter-range buckets when its length exceeds
3114
- * {@link DISCORD_MODEL_PICKER_BUCKET_THRESHOLD}. Items below the threshold
3115
- * return a single "All" bucket so callers can render the same code path.
3116
- *
3117
- * The boundary extender keeps items sharing the same starting letter inside
3118
- * the same bucket — selecting "A–G" never strands a stray "g" item in the
3119
- * next bucket. If every item shares a first letter (e.g. all `qwen3-*`),
3120
- * the function falls back to count-based numeric chunks so the user still
3121
- * gets a finite-cardinality picker.
3122
- */
3123
2910
  function computeAlphaBuckets(sortedItems) {
3124
2911
  if (sortedItems.length === 0) return [];
3125
2912
  if (sortedItems.length <= DISCORD_MODEL_PICKER_BUCKET_THRESHOLD) return [{
@@ -3154,16 +2941,8 @@ function computeAlphaBuckets(sortedItems) {
3154
2941
  }
3155
2942
  return buckets;
3156
2943
  }
3157
- /**
3158
- * Pick the per-bucket target size such that the resulting bucket count never
3159
- * exceeds {@link DISCORD_COMPONENT_MAX_SELECT_OPTIONS} (Discord's hard select
3160
- * cap). Stays at the default {@link DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE}
3161
- * for typical inputs and grows linearly for very large lists.
3162
- */
3163
2944
  function computeBucketTargetSize(totalItems) {
3164
- const minTarget = DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE;
3165
- const capByBucketCount = Math.ceil(totalItems / DISCORD_COMPONENT_MAX_SELECT_OPTIONS);
3166
- return Math.max(minTarget, capByBucketCount);
2945
+ return Math.max(DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE, Math.ceil(totalItems / DISCORD_COMPONENT_MAX_SELECT_OPTIONS));
3167
2946
  }
3168
2947
  function chunkBucketsByCount(sortedItems) {
3169
2948
  const buckets = [];
@@ -3179,37 +2958,15 @@ function chunkBucketsByCount(sortedItems) {
3179
2958
  }
3180
2959
  return buckets;
3181
2960
  }
3182
- /**
3183
- * Resolve a bucket from a list given a (possibly user-supplied) bucket id.
3184
- * Falls back to the first bucket when the id does not match — mirrors the
3185
- * "bad customId → reset to defaults" semantics already used for other
3186
- * state fields.
3187
- */
3188
2961
  function resolveBucket(buckets, id) {
3189
- if (buckets.length === 0) return null;
3190
- if (!id) return expectDefined(buckets.at(0), "non-empty model picker buckets");
3191
- return buckets.find((bucket) => bucket.id === id) ?? expectDefined(buckets.at(0), "non-empty model picker buckets");
2962
+ return buckets.find((bucket) => bucket.id === id) ?? buckets[0] ?? null;
3192
2963
  }
3193
- /**
3194
- * Derive the alpha-bucket id that contains a given provider id. Returns
3195
- * `undefined` when bucketing is inactive (all providers fit in one bucket)
3196
- * or the provider is unknown. Used by the interaction handler to recompute
3197
- * `providerBucket` at re-render time without forcing every customId to
3198
- * carry the bucket field — the bucket is a pure function of the provider
3199
- * list + provider id.
3200
- */
3201
2964
  function findProviderBucketId(data, provider) {
3202
2965
  return findProviderBucketLocation(data, provider)?.bucket;
3203
2966
  }
3204
2967
  function findProviderBucketLocation(data, provider) {
3205
2968
  return findModelPickerBucketLocation([...data.providers].toSorted(), normalizeProviderId(provider));
3206
2969
  }
3207
- /**
3208
- * Derive the alpha-bucket id that contains a given model id within the
3209
- * named provider. Same rationale as {@link findProviderBucketId} — saves
3210
- * customId budget by recomputing the bucket from the durable state
3211
- * (provider + model) rather than carrying it as a parameter.
3212
- */
3213
2970
  function findModelBucketId(data, provider, model) {
3214
2971
  const modelSet = data.byProvider.get(normalizeProviderId(provider));
3215
2972
  return modelSet ? findModelPickerBucketLocation([...modelSet].toSorted(compareBucketItems), model)?.bucket : void 0;
@@ -3317,14 +3074,6 @@ function createModelSelect(params) {
3317
3074
  }
3318
3075
  return new DiscordModelPickerSelect();
3319
3076
  }
3320
- /**
3321
- * Build the alpha-bucket select row that appears above the provider/model
3322
- * surface when the list exceeds {@link DISCORD_MODEL_PICKER_BUCKET_THRESHOLD}.
3323
- *
3324
- * Selecting a bucket emits action=bucket. The chosen bucket travels in the
3325
- * select value, while the custom_id carries only the stable context needed to
3326
- * rebuild the picker under Discord's 100-character custom_id limit.
3327
- */
3328
3077
  function buildBucketSelectRow(params) {
3329
3078
  if (params.buckets.length <= 1) return null;
3330
3079
  const options = params.buckets.map((bucket) => ({
@@ -3358,11 +3107,6 @@ function resolveExplicitRuntimeState(params) {
3358
3107
  const runtime = params.pendingRuntime?.trim() || params.currentRuntime?.trim();
3359
3108
  return runtime && runtime !== "auto" && runtime !== "default" ? runtime : void 0;
3360
3109
  }
3361
- function resolveSelectedRuntime(params) {
3362
- const choices = getRuntimeChoices(params);
3363
- const explicit = resolveExplicitRuntimeState(params);
3364
- return explicit ? choices?.find((choice) => choice.id === explicit)?.id : choices?.[0]?.id;
3365
- }
3366
3110
  function getActiveBucketId(bucket) {
3367
3111
  return bucket && bucket.id !== "all" ? bucket.id : void 0;
3368
3112
  }
@@ -3398,18 +3142,18 @@ function buildRenderedShell(params) {
3398
3142
  return { components: [new Container(containerComponents)] };
3399
3143
  }
3400
3144
  function buildProviderSelectRow(params) {
3401
- if (params.page.items.length === 0) return null;
3402
3145
  const options = params.page.items.map((provider) => ({
3403
3146
  label: provider.id,
3404
3147
  value: provider.id,
3405
3148
  default: provider.id === params.currentProvider,
3406
- description: `${provider.count} ${provider.count === 1 ? "model" : "models"}`
3149
+ ...params.showModelCounts ? { description: `${provider.count} ${provider.count === 1 ? "model" : "models"}` } : {}
3407
3150
  }));
3408
3151
  return new Row([createModelSelect({
3409
3152
  customId: buildDiscordModelPickerCustomId({
3410
3153
  command: params.command,
3411
3154
  action: "provider",
3412
3155
  view: "models",
3156
+ provider: params.provider,
3413
3157
  page: params.page.page,
3414
3158
  providerPage: params.page.page,
3415
3159
  providerBucket: params.providerBucket,
@@ -3453,40 +3197,27 @@ function buildModelRows(params) {
3453
3197
  page: params.providerPage,
3454
3198
  bucket: params.providerBucket
3455
3199
  });
3456
- const providerOptions = providerPage.items.map((provider) => ({
3457
- label: provider.id,
3458
- value: provider.id,
3459
- default: provider.id === params.modelPage.provider
3460
- }));
3461
3200
  const activeProviderBucket = getActiveBucketId(providerPage.bucket);
3462
3201
  const activeModelBucket = getActiveBucketId(params.modelPage.bucket);
3463
- if (!((params.modelPage.buckets?.length ?? 0) > 1)) rows.push(new Row([createModelSelect({
3464
- customId: buildDiscordModelPickerCustomId({
3465
- command: params.command,
3466
- action: "provider",
3467
- view: "models",
3468
- provider: params.modelPage.provider,
3469
- page: providerPage.page,
3470
- providerPage: providerPage.page,
3471
- providerBucket: activeProviderBucket,
3472
- userId: params.userId
3473
- }),
3474
- options: providerOptions,
3475
- placeholder: "Select provider"
3476
- })]));
3202
+ if (!((params.modelPage.buckets?.length ?? 0) > 1)) rows.push(buildProviderSelectRow({
3203
+ command: params.command,
3204
+ userId: params.userId,
3205
+ page: providerPage,
3206
+ provider: params.modelPage.provider,
3207
+ currentProvider: params.modelPage.provider,
3208
+ providerBucket: activeProviderBucket
3209
+ }));
3477
3210
  const runtimeChoices = getRuntimeChoices({
3478
3211
  data: params.data,
3479
3212
  provider: params.modelPage.provider,
3480
3213
  modelRef: params.pendingModel ?? params.currentModel
3481
3214
  });
3482
3215
  const currentRuntime = parsedCurrentModel?.provider === params.modelPage.provider ? params.currentRuntime : void 0;
3483
- const selectedRuntime = resolveSelectedRuntime({
3484
- data: params.data,
3485
- provider: params.modelPage.provider,
3486
- modelRef: params.pendingModel ?? params.currentModel,
3216
+ const explicitRuntime = resolveExplicitRuntimeState({
3487
3217
  currentRuntime,
3488
3218
  pendingRuntime: params.pendingRuntime
3489
3219
  });
3220
+ const selectedRuntime = explicitRuntime ? runtimeChoices?.find((choice) => choice.id === explicitRuntime)?.id : runtimeChoices?.[0]?.id;
3490
3221
  const compactRuntime = resolveCompactRuntimeState({
3491
3222
  currentRuntime,
3492
3223
  pendingRuntime: params.pendingRuntime
@@ -3548,7 +3279,7 @@ function buildModelRows(params) {
3548
3279
  providerPage: providerPage.page,
3549
3280
  modelIndex: params.pendingModelIndex,
3550
3281
  modelToken: pendingModelToken,
3551
- modelBucket: params.modelPage.bucket && params.modelPage.bucket.id !== "all" ? params.modelPage.bucket.id : void 0
3282
+ modelBucket: activeModelBucket
3552
3283
  });
3553
3284
  if (modelNavRow) rows.push(modelNavRow);
3554
3285
  const resolvedDefault = params.data.resolvedDefault;
@@ -3615,7 +3346,9 @@ function buildModelRows(params) {
3615
3346
  }));
3616
3347
  return {
3617
3348
  rows,
3618
- buttonRow: new Row(buttonRowItems)
3349
+ buttonRow: new Row(buttonRowItems),
3350
+ runtimeChoices,
3351
+ selectedRuntime
3619
3352
  };
3620
3353
  }
3621
3354
  function renderDiscordModelPickerProvidersView(params) {
@@ -3634,15 +3367,15 @@ function renderDiscordModelPickerProvidersView(params) {
3634
3367
  currentBucketId: page.bucket?.id
3635
3368
  });
3636
3369
  if (bucketRow) rows.push(bucketRow);
3637
- const activeProviderBucket = page.bucket && page.bucket.id !== "all" ? page.bucket.id : void 0;
3638
- const providerRow = buildProviderSelectRow({
3370
+ const activeProviderBucket = getActiveBucketId(page.bucket);
3371
+ if (page.items.length > 0) rows.push(buildProviderSelectRow({
3639
3372
  command: params.command,
3640
3373
  userId: params.userId,
3641
3374
  page,
3642
3375
  currentProvider: parsedCurrent?.provider,
3643
- providerBucket: activeProviderBucket
3644
- });
3645
- if (providerRow) rows.push(providerRow);
3376
+ providerBucket: activeProviderBucket,
3377
+ showModelCounts: true
3378
+ }));
3646
3379
  const navRow = buildPaginationRow({
3647
3380
  command: params.command,
3648
3381
  userId: params.userId,
@@ -3692,19 +3425,10 @@ function renderDiscordModelPickerModelsView(params) {
3692
3425
  footer: "Choose a different provider."
3693
3426
  });
3694
3427
  }
3695
- const { rows: modelRows, buttonRow } = buildModelRows({
3696
- command: params.command,
3697
- userId: params.userId,
3698
- data: params.data,
3428
+ const { rows: modelRows, buttonRow, runtimeChoices: choices, selectedRuntime } = buildModelRows({
3429
+ ...params,
3699
3430
  providerPage,
3700
- modelPage,
3701
- currentModel: params.currentModel,
3702
- currentRuntime: params.currentRuntime,
3703
- pendingModel: params.pendingModel,
3704
- pendingModelIndex: params.pendingModelIndex,
3705
- pendingRuntime: params.pendingRuntime,
3706
- quickModels: params.quickModels,
3707
- providerBucket: params.providerBucket
3431
+ modelPage
3708
3432
  });
3709
3433
  const pendingRuntime = params.pendingRuntime?.trim();
3710
3434
  const rows = [];
@@ -3716,24 +3440,11 @@ function renderDiscordModelPickerModelsView(params) {
3716
3440
  currentBucketId: modelPage.bucket?.id,
3717
3441
  provider: modelPage.provider,
3718
3442
  runtimeToken: pendingRuntime ? createDiscordModelPickerRuntimeToken(pendingRuntime) : void 0,
3719
- providerPage,
3720
- providerBucket: params.providerBucket
3443
+ providerPage
3721
3444
  });
3722
3445
  if (bucketRow) rows.push(bucketRow);
3723
3446
  rows.push(...modelRows);
3724
3447
  const defaultModel = `${params.data.resolvedDefault.provider}/${params.data.resolvedDefault.model}`;
3725
- const choices = getRuntimeChoices({
3726
- data: params.data,
3727
- provider: modelPage.provider,
3728
- modelRef: params.pendingModel ?? params.currentModel
3729
- });
3730
- const selectedRuntime = resolveSelectedRuntime({
3731
- data: params.data,
3732
- provider: modelPage.provider,
3733
- modelRef: params.pendingModel ?? params.currentModel,
3734
- currentRuntime: parseCurrentModelRef(params.currentModel)?.provider === modelPage.provider ? params.currentRuntime : void 0,
3735
- pendingRuntime: params.pendingRuntime
3736
- });
3737
3448
  const selectedRuntimeLabel = choices?.find((choice) => choice.id === selectedRuntime)?.label;
3738
3449
  const pendingLine = !params.pendingModel ? "Select a model, then press Submit." : !supportsDiscordModelPickerRuntimeChoices() ? `Selected: ${params.pendingModel} (press Submit)` : choices === void 0 ? "Could not confirm how to run this model. Open /models to try again." : choices.length === 0 ? "This model cannot run with your current connections. Choose another model." : selectedRuntimeLabel ? `Selected: ${params.pendingModel} · ${selectedRuntimeLabel} (press Submit)` : "Choose how to run this model, then press Submit.";
3739
3450
  const detailLines = [formatCurrentModelLine(params.currentModel), `Default: ${defaultModel}`];
@@ -3872,21 +3583,11 @@ async function applyDiscordModelPickerSelection(params) {
3872
3583
  }
3873
3584
  //#endregion
3874
3585
  //#region extensions/discord/src/monitor/native-command-model-picker-ui.ts
3875
- function resolveDiscordModelPickerCommandContext(command) {
3876
- const normalized = normalizeLowercaseStringOrEmpty(command.nativeName ?? command.key);
3877
- if (normalized === "model" || normalized === "models") return normalized;
3878
- return null;
3879
- }
3880
- function resolveCommandArgStringValue(args, key) {
3881
- const value = args?.values?.[key];
3882
- if (typeof value !== "string") return "";
3883
- return value.trim();
3884
- }
3885
3586
  function shouldOpenDiscordModelPickerFromCommand(params) {
3886
- const context = resolveDiscordModelPickerCommandContext(params.command);
3887
- if (!context) return null;
3587
+ const context = normalizeLowercaseStringOrEmpty(params.command.nativeName ?? params.command.key);
3588
+ if (context !== "model" && context !== "models") return null;
3888
3589
  const serializedArgs = normalizeOptionalString(serializeCommandArgs(params.command, params.commandArgs)) ?? "";
3889
- if (context === "model") return !resolveCommandArgStringValue(params.commandArgs, "model") && !serializedArgs ? context : null;
3590
+ if (context === "model") return !normalizeOptionalString(params.commandArgs?.values?.model) && !serializedArgs ? context : null;
3890
3591
  return serializedArgs ? null : context;
3891
3592
  }
3892
3593
  function buildDiscordModelPickerAllowedModelRefs(data) {
@@ -3908,7 +3609,7 @@ function resolveDiscordModelPickerPreferenceScope(params) {
3908
3609
  function buildDiscordModelPickerNoticePayload(message) {
3909
3610
  return { components: [new Container([new TextDisplay(message)])] };
3910
3611
  }
3911
- async function resolveDiscordModelPickerRouteState(params) {
3612
+ async function resolveDiscordModelPickerRoute(params) {
3912
3613
  const { interaction, cfg, accountId } = params;
3913
3614
  const { isDirectMessage, isGroupDm, isThreadChannel, rawChannelId, threadParentId } = await resolveDiscordNativeInteractionChannelContext({
3914
3615
  channel: interaction.channel,
@@ -3929,10 +3630,7 @@ async function resolveDiscordModelPickerRouteState(params) {
3929
3630
  conversationId: rawChannelId,
3930
3631
  parentConversationId: threadParentId,
3931
3632
  threadBinding
3932
- });
3933
- }
3934
- async function resolveDiscordModelPickerRoute(params) {
3935
- return (await resolveDiscordModelPickerRouteState(params)).effectiveRoute;
3633
+ }).effectiveRoute;
3936
3634
  }
3937
3635
  async function resolveDiscordNativeChoiceContext(params) {
3938
3636
  try {
@@ -4051,8 +3749,6 @@ async function replyWithDiscordModelPickerProviders(params) {
4051
3749
  provider: initialProvider,
4052
3750
  model: parsedCurrentRef.model
4053
3751
  }) : { page: 1 };
4054
- const initialPage = initialResolved.page;
4055
- const initialModelBucket = initialResolved.bucket;
4056
3752
  const initialProviderLocation = findProviderBucketLocation(data, initialProvider);
4057
3753
  const payload = {
4058
3754
  ...renderDiscordModelPickerModelsView({
@@ -4060,10 +3756,10 @@ async function replyWithDiscordModelPickerProviders(params) {
4060
3756
  userId: params.userId,
4061
3757
  data,
4062
3758
  provider: initialProvider,
4063
- page: initialPage,
3759
+ page: initialResolved.page,
4064
3760
  providerPage: initialProviderLocation?.page ?? 1,
4065
3761
  providerBucket: initialProviderLocation?.bucket,
4066
- modelBucket: initialModelBucket,
3762
+ modelBucket: initialResolved.bucket,
4067
3763
  currentModel,
4068
3764
  currentRuntime,
4069
3765
  quickModels
@@ -4071,11 +3767,7 @@ async function replyWithDiscordModelPickerProviders(params) {
4071
3767
  ephemeral: true
4072
3768
  };
4073
3769
  await params.safeInteractionCall("model picker reply", async () => {
4074
- if (params.preferFollowUp) {
4075
- await params.interaction.followUp(payload);
4076
- return;
4077
- }
4078
- await params.interaction.reply(payload);
3770
+ await params.interaction[params.preferFollowUp ? "followUp" : "reply"](payload);
4079
3771
  });
4080
3772
  }
4081
3773
  function splitDiscordModelRef(modelRef) {
@@ -4093,11 +3785,7 @@ function splitDiscordModelRef(modelRef) {
4093
3785
  //#endregion
4094
3786
  //#region extensions/discord/src/monitor/native-command-model-picker-interaction.ts
4095
3787
  function resolveModelPickerSelectionValue(interaction) {
4096
- const rawValues = interaction.values;
4097
- if (!Array.isArray(rawValues) || rawValues.length === 0) return null;
4098
- const first = rawValues[0];
4099
- if (typeof first !== "string") return null;
4100
- return first.trim() || null;
3788
+ return normalizeOptionalString(interaction.values?.[0]) ?? null;
4101
3789
  }
4102
3790
  function resolveRuntimeToken(choices, token) {
4103
3791
  if (!token) return;
@@ -4164,15 +3852,11 @@ function resolveDiscordModelPickerModelRefByToken(data, modelToken) {
4164
3852
  return matchingRefs.length === 1 ? matchingRefs[0] ?? null : null;
4165
3853
  }
4166
3854
  function resolveDiscordModelPickerModelIndex(params) {
4167
- const models = listDiscordModelPickerProviderModels(params.data, params.provider);
4168
- if (!models.length) return null;
4169
- const index = models.indexOf(params.model);
4170
- if (index < 0) return null;
4171
- return index + 1;
3855
+ const index = listDiscordModelPickerProviderModels(params.data, params.provider).indexOf(params.model);
3856
+ return index < 0 ? null : index + 1;
4172
3857
  }
4173
3858
  function resolveDiscordModelPickerModelSelection(params) {
4174
3859
  const models = listDiscordModelPickerProviderModels(params.data, params.provider);
4175
- if (!models.length) return null;
4176
3860
  if (params.modelToken) {
4177
3861
  const matchingModels = models.filter((model) => createDiscordModelPickerModelToken(params.provider, model) === params.modelToken);
4178
3862
  return matchingModels.length === 1 ? matchingModels[0] ?? null : null;
@@ -4191,10 +3875,8 @@ async function handleDiscordModelPickerInteraction(params) {
4191
3875
  await params.safeInteractionCall("model picker ack", () => interaction.acknowledge());
4192
3876
  return;
4193
3877
  }
4194
- let deferredUpdate = interaction.acknowledged;
4195
- if (!deferredUpdate) {
3878
+ if (!interaction.acknowledged) {
4196
3879
  if (await params.safeInteractionCall("model picker defer", () => interaction.acknowledge()) === null) return;
4197
- deferredUpdate = true;
4198
3880
  }
4199
3881
  const cfg = getRuntimeConfigSnapshot() ?? ctx.cfg;
4200
3882
  const requireModelToken = cfg !== ctx.cfg;
@@ -4232,7 +3914,7 @@ async function handleDiscordModelPickerInteraction(params) {
4232
3914
  allowedModelRefs,
4233
3915
  limit: 5
4234
3916
  });
4235
- const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () => deferredUpdate ? interaction.editReply(payload) : interaction.update(payload));
3917
+ const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () => interaction.editReply(payload));
4236
3918
  const showNotice = async (message) => await updatePicker(buildDiscordModelPickerNoticePayload(message));
4237
3919
  const updateModelsView = async (provider, state = {}) => {
4238
3920
  const rendered = renderDiscordModelPickerModelsView({
@@ -4299,15 +3981,16 @@ async function handleDiscordModelPickerInteraction(params) {
4299
3981
  }));
4300
3982
  return;
4301
3983
  }
4302
- if (parsed.action === "bucket" && parsed.view === "models") {
3984
+ if (parsed.view === "models" && (parsed.action === "bucket" || parsed.action === "back")) {
4303
3985
  const provider = resolveModelPickerProvider({
4304
3986
  parsedProvider,
4305
3987
  currentModelRef,
4306
3988
  data: pickerData
4307
3989
  });
3990
+ const selectingBucket = parsed.action === "bucket";
4308
3991
  await updateModelsView(provider, {
4309
- page: 1,
4310
- modelBucket: resolveSelectedBucket(interaction),
3992
+ page: selectingBucket ? 1 : parsed.page,
3993
+ modelBucket: selectingBucket ? resolveSelectedBucket(interaction) : parsed.modelBucket,
4311
3994
  pendingRuntime: resolvePendingRuntime({
4312
3995
  data: pickerData,
4313
3996
  provider,
@@ -4350,22 +4033,6 @@ async function handleDiscordModelPickerInteraction(params) {
4350
4033
  });
4351
4034
  return;
4352
4035
  }
4353
- if (parsed.action === "back" && parsed.view === "models") {
4354
- const provider = resolveModelPickerProvider({
4355
- parsedProvider,
4356
- currentModelRef,
4357
- data: pickerData
4358
- });
4359
- await updateModelsView(provider, {
4360
- modelBucket: parsed.modelBucket,
4361
- pendingRuntime: resolvePendingRuntime({
4362
- data: pickerData,
4363
- provider,
4364
- parsed
4365
- })
4366
- });
4367
- return;
4368
- }
4369
4036
  if (parsed.action === "provider") {
4370
4037
  const selectedProvider = resolveModelPickerSelectionValue(interaction) ?? parsed.provider;
4371
4038
  if (!selectedProvider || !pickerData.byProvider.has(selectedProvider)) {
@@ -4437,9 +4104,8 @@ async function handleDiscordModelPickerInteraction(params) {
4437
4104
  provider,
4438
4105
  model: selectedModel
4439
4106
  }) : void 0;
4440
- const currentModelOnly = splitDiscordModelRef(currentModelRef ?? "");
4441
4107
  await updateModelsView(provider, {
4442
- modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) : currentModelOnly && currentModelOnly.provider === provider ? findModelBucketId(pickerData, provider, currentModelOnly.model) : void 0),
4108
+ modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) : currentModel && currentModel.provider === provider ? findModelBucketId(pickerData, provider, currentModel.model) : void 0),
4443
4109
  ...pendingModel ? { pendingModel } : {},
4444
4110
  pendingModelIndex: pendingModelIndex ?? void 0,
4445
4111
  pendingRuntime: selectedRuntime
@@ -4545,45 +4211,38 @@ async function handleDiscordModelPickerInteraction(params) {
4545
4211
  }
4546
4212
  if (parsed.action === "cancel") await showNotice(`ℹ️ Model kept as ${currentModelRef ?? "default"}.`);
4547
4213
  }
4548
- async function runDiscordModelPickerFallback(params) {
4549
- await handleDiscordModelPickerInteraction(params);
4550
- }
4551
- var DiscordModelPickerFallbackButton = class extends Button {
4552
- constructor(params) {
4553
- super();
4554
- this.params = params;
4555
- this.label = "modelpick";
4556
- this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=btn`;
4557
- }
4558
- async run(interaction, data) {
4559
- await runDiscordModelPickerFallback({
4560
- ...this.params,
4561
- interaction,
4562
- data
4563
- });
4564
- }
4565
- };
4566
- var DiscordModelPickerFallbackSelect = class extends StringSelectMenu {
4567
- constructor(params) {
4568
- super();
4569
- this.params = params;
4570
- this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=sel`;
4571
- this.options = [];
4572
- }
4573
- async run(interaction, data) {
4574
- await runDiscordModelPickerFallback({
4575
- ...this.params,
4576
- interaction,
4577
- data
4578
- });
4579
- }
4580
- };
4581
4214
  function createDiscordModelPickerFallbackButton$1(params) {
4582
- return new DiscordModelPickerFallbackButton(params);
4215
+ return new class extends Button {
4216
+ constructor(..._args) {
4217
+ super(..._args);
4218
+ this.label = "modelpick";
4219
+ this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=btn`;
4220
+ }
4221
+ async run(interaction, data) {
4222
+ await handleDiscordModelPickerInteraction({
4223
+ ...params,
4224
+ interaction,
4225
+ data
4226
+ });
4227
+ }
4228
+ }();
4583
4229
  }
4584
4230
  function createDiscordModelPickerFallbackSelect$1(params) {
4585
- return new DiscordModelPickerFallbackSelect(params);
4586
- }
4231
+ return new class extends StringSelectMenu {
4232
+ constructor(..._args2) {
4233
+ super(..._args2);
4234
+ this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=sel`;
4235
+ this.options = [];
4236
+ }
4237
+ async run(interaction, data) {
4238
+ await handleDiscordModelPickerInteraction({
4239
+ ...params,
4240
+ interaction,
4241
+ data
4242
+ });
4243
+ }
4244
+ }();
4245
+ }
4587
4246
  //#endregion
4588
4247
  //#region extensions/discord/src/monitor/native-command-status.ts
4589
4248
  async function maybeDeliverDiscordDirectStatus(params) {
@@ -4603,15 +4262,9 @@ async function maybeDeliverDiscordDirectStatus(params) {
4603
4262
  interaction: params.interaction,
4604
4263
  payload: statusReply,
4605
4264
  mediaLocalRoots: params.mediaLocalRoots,
4606
- textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
4607
- maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
4608
- cfg: params.cfg,
4609
- discordConfig: params.discordConfig,
4610
- accountId: params.accountId
4611
- }),
4265
+ ...resolveDiscordInteractionReplyOptions(params),
4612
4266
  preferFollowUp: params.preferFollowUp,
4613
- responseEphemeral: params.responseEphemeral,
4614
- chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
4267
+ responseEphemeral: params.responseEphemeral
4615
4268
  });
4616
4269
  return {
4617
4270
  accepted: true,
@@ -4631,9 +4284,9 @@ function readDiscordCommandArgs(interaction, definitions) {
4631
4284
  const values = {};
4632
4285
  for (const definition of definitions) {
4633
4286
  let value;
4634
- if (definition.type === "number") value = interaction.options.getNumber(definition.name) ?? null;
4635
- else if (definition.type === "boolean") value = interaction.options.getBoolean(definition.name) ?? null;
4636
- else value = interaction.options.getString(definition.name) ?? null;
4287
+ if (definition.type === "number") value = interaction.options.getNumber(definition.name);
4288
+ else if (definition.type === "boolean") value = interaction.options.getBoolean(definition.name);
4289
+ else value = interaction.options.getString(definition.name);
4637
4290
  if (value != null) values[definition.name] = value;
4638
4291
  }
4639
4292
  return Object.keys(values).length > 0 ? { values } : void 0;
@@ -4668,26 +4321,21 @@ function truncateDiscordCommandDescriptionLocalizations(params) {
4668
4321
  label: `${params.label} locale:${locale}`
4669
4322
  })]));
4670
4323
  }
4671
- function resolveDiscordCommandLogLabel(command) {
4672
- if (typeof command.nativeName === "string" && command.nativeName.trim().length > 0) return command.nativeName;
4673
- return command.key;
4674
- }
4675
4324
  function buildDiscordCommandOptions(params) {
4676
4325
  const { command, cfg, resolveConfig, authorizeChoiceContext, resolveChoiceContext } = params;
4677
- const commandLabel = resolveDiscordCommandLogLabel(command);
4326
+ const commandLabel = command.nativeName?.trim() ? command.nativeName : command.key;
4678
4327
  const args = command.args;
4679
4328
  if (!args || args.length === 0) return;
4680
4329
  return args.map((arg) => {
4681
- const required = arg.required ?? false;
4682
- if (arg.type === "number" || arg.type === "boolean") return {
4330
+ const base = {
4683
4331
  name: arg.name,
4684
4332
  description: truncateDiscordCommandDescription({
4685
4333
  value: arg.description,
4686
4334
  label: `command:${commandLabel} arg:${arg.name}`
4687
4335
  }),
4688
- type: arg.type === "number" ? ApplicationCommandOptionType.Number : ApplicationCommandOptionType.Boolean,
4689
- required
4336
+ required: arg.required ?? false
4690
4337
  };
4338
+ if (arg.type === "number" || arg.type === "boolean") return Object.assign(base, { type: arg.type === "number" ? ApplicationCommandOptionType.Number : ApplicationCommandOptionType.Boolean });
4691
4339
  const resolvedChoices = resolveCommandArgChoices({
4692
4340
  command,
4693
4341
  arg,
@@ -4728,17 +4376,11 @@ function buildDiscordCommandOptions(params) {
4728
4376
  name: choice.label,
4729
4377
  value: choice.value
4730
4378
  })) : void 0;
4731
- return {
4732
- name: arg.name,
4733
- description: truncateDiscordCommandDescription({
4734
- value: arg.description,
4735
- label: `command:${commandLabel} arg:${arg.name}`
4736
- }),
4379
+ return Object.assign(base, {
4737
4380
  type: ApplicationCommandOptionType.String,
4738
- required,
4739
4381
  choices,
4740
4382
  autocomplete
4741
- };
4383
+ });
4742
4384
  });
4743
4385
  }
4744
4386
  //#endregion
@@ -4842,14 +4484,9 @@ async function dispatchDiscordCommandInteraction(params) {
4842
4484
  ...ephemeral !== void 0 ? { ephemeral } : {}
4843
4485
  };
4844
4486
  await safeDiscordInteractionCall("interaction reply", async () => {
4845
- if (preferFollowUp) {
4846
- await interaction.followUp(payload);
4847
- return;
4848
- }
4849
- await interaction.reply(payload);
4487
+ await interaction[preferFollowUp ? "followUp" : "reply"](payload);
4850
4488
  });
4851
4489
  };
4852
- const useAccessGroups = true;
4853
4490
  const user = interaction.user;
4854
4491
  if (!user) return { accepted: false };
4855
4492
  const sender = resolveDiscordSenderIdentity({
@@ -4863,7 +4500,7 @@ async function dispatchDiscordCommandInteraction(params) {
4863
4500
  hasGuild: Boolean(interaction.guild),
4864
4501
  channelIdFallback: interaction.rawData.channel_id ?? ""
4865
4502
  });
4866
- const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId, threadParentName, threadParentSlug } = channelContext;
4503
+ const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId } = channelContext;
4867
4504
  if (policy?.isCurrent() === false) {
4868
4505
  await respond("Access policy changed. Try this interaction again.", { ephemeral: true });
4869
4506
  return { accepted: false };
@@ -4874,31 +4511,17 @@ async function dispatchDiscordCommandInteraction(params) {
4874
4511
  cfg,
4875
4512
  accountId
4876
4513
  }) ?? [];
4877
- const { ownerAllowList: discordOwnerAllowList, ownerAllowed: discordOwnerOk } = resolveDiscordOwnerAccess({
4514
+ const { ownerAllowList, ownerAllowed } = resolveDiscordOwnerAccess({
4878
4515
  allowFrom: configuredDmAllowFrom,
4879
- sender: {
4880
- id: sender.id,
4881
- name: sender.name,
4882
- tag: sender.tag
4883
- },
4516
+ sender,
4884
4517
  allowNameMatching
4885
4518
  });
4886
- const ownerAllowListConfigured = discordOwnerAllowList != null;
4887
- const ownerOk = discordOwnerOk;
4888
4519
  const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
4889
4520
  cfg,
4890
4521
  discordConfig,
4891
- accountId,
4892
4522
  sender,
4893
- isDirectMessage,
4894
- isThreadChannel,
4895
- guild: interaction.guild ?? null,
4896
- rawChannelId,
4897
- channelName,
4898
- channelSlug,
4899
- threadParentId,
4900
- threadParentName,
4901
- threadParentSlug
4523
+ ...channelContext,
4524
+ guild: interaction.guild ?? null
4902
4525
  });
4903
4526
  let nativeRouteState;
4904
4527
  const getNativeRouteState = () => nativeRouteState ??= nativeCommandRuntime.resolveDiscordNativeInteractionRouteState({
@@ -4960,11 +4583,7 @@ async function dispatchDiscordCommandInteraction(params) {
4960
4583
  accountId,
4961
4584
  dmPolicy,
4962
4585
  configuredAllowFrom: configuredDmAllowFrom,
4963
- sender: {
4964
- id: sender.id,
4965
- name: sender.name,
4966
- tag: sender.tag
4967
- },
4586
+ sender,
4968
4587
  allowNameMatching,
4969
4588
  cfg,
4970
4589
  rest: interaction.client.rest
@@ -5012,17 +4631,15 @@ async function dispatchDiscordCommandInteraction(params) {
5012
4631
  if (!isDirectMessage) {
5013
4632
  commandAuthorized = await resolveDiscordGuildNativeCommandAuthorized({
5014
4633
  cfg,
5015
- accountId,
5016
4634
  discordConfig,
5017
- useAccessGroups,
5018
4635
  commandsAllowFromAccess,
5019
4636
  guildInfo,
5020
4637
  channelConfig,
5021
4638
  memberRoleIds,
5022
4639
  sender,
5023
4640
  allowNameMatching,
5024
- ownerAllowListConfigured,
5025
- ownerAllowed: ownerOk
4641
+ ownerAllowListConfigured: ownerAllowList != null,
4642
+ ownerAllowed
5026
4643
  });
5027
4644
  if (!commandAuthorized && !canBypassConfiguredAcpGuildGuards()) {
5028
4645
  await respond("You are not authorized to use this command.", { ephemeral: true });
@@ -5130,15 +4747,7 @@ async function dispatchDiscordCommandInteraction(params) {
5130
4747
  safeInteractionCall: safeDiscordInteractionCall,
5131
4748
  dispatchCommandInteraction: dispatchDiscordCommandInteraction
5132
4749
  });
5133
- if (preferFollowUp) {
5134
- await safeDiscordInteractionCall("interaction follow-up", () => interaction.followUp({
5135
- content: menuPayload.content,
5136
- components: menuPayload.components,
5137
- ephemeral: true
5138
- }));
5139
- return { accepted: true };
5140
- }
5141
- await safeDiscordInteractionCall("interaction reply", () => interaction.reply({
4750
+ await safeDiscordInteractionCall(preferFollowUp ? "interaction follow-up" : "interaction reply", () => interaction[preferFollowUp ? "followUp" : "reply"]({
5142
4751
  content: menuPayload.content,
5143
4752
  components: menuPayload.components,
5144
4753
  ephemeral: true
@@ -5194,15 +4803,13 @@ async function dispatchDiscordCommandInteraction(params) {
5194
4803
  await deliverDiscordInteractionReply({
5195
4804
  interaction,
5196
4805
  payload: pluginReply,
5197
- textLimit: resolveTextChunkLimit(cfg, "discord", accountId, { fallbackLimit: 2e3 }),
5198
- maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
4806
+ ...resolveDiscordInteractionReplyOptions({
5199
4807
  cfg,
5200
4808
  discordConfig,
5201
4809
  accountId
5202
4810
  }),
5203
4811
  preferFollowUp,
5204
- responseEphemeral,
5205
- chunkMode: resolveChunkMode(cfg, "discord", accountId)
4812
+ responseEphemeral
5206
4813
  });
5207
4814
  return {
5208
4815
  accepted: true,
@@ -5460,7 +5067,7 @@ var GatewaySendLimiter = class {
5460
5067
  shouldEmitOverflowWarning = true;
5461
5068
  }
5462
5069
  }
5463
- this.outboundQueue.push({ payload: serialized });
5070
+ this.outboundQueue.push(serialized);
5464
5071
  if (shouldEmitOverflowWarning) this.emitOverflowWarning({
5465
5072
  droppedEvents: this.droppedEvents,
5466
5073
  maxQueuedEvents: GATEWAY_SEND_QUEUE_LIMIT,
@@ -5517,9 +5124,9 @@ var GatewaySendLimiter = class {
5517
5124
  flush() {
5518
5125
  while (this.outboundQueue.length > 0 && this.canSend(Date.now())) {
5519
5126
  const queued = this.outboundQueue.shift();
5520
- if (!queued) continue;
5127
+ if (queued === void 0) continue;
5521
5128
  try {
5522
- this.sendSerialized(queued.payload);
5129
+ this.sendSerialized(queued);
5523
5130
  } catch (error) {
5524
5131
  this.emitError(error instanceof Error ? error : new Error(String(error), { cause: error }));
5525
5132
  this.clear();
@@ -5654,9 +5261,6 @@ var GatewayPlugin = class extends Plugin {
5654
5261
  };
5655
5262
  this.gatewayInfo = gatewayInfo;
5656
5263
  }
5657
- get ping() {
5658
- return null;
5659
- }
5660
5264
  listVoiceChannelStates(guildId, channelId) {
5661
5265
  return this.voiceStateCache.listVoiceChannelStates(guildId, channelId);
5662
5266
  }
@@ -5690,8 +5294,8 @@ var GatewayPlugin = class extends Plugin {
5690
5294
  this.connect(false);
5691
5295
  }
5692
5296
  connect(resume = false) {
5693
- this.stopReconnectTimer();
5694
- this.stopHeartbeat();
5297
+ this.reconnectTimer.stop();
5298
+ this.heartbeatTimers.stop();
5695
5299
  if (this.isConnecting) return;
5696
5300
  this.shouldReconnect = true;
5697
5301
  this.lastHeartbeatAck = true;
@@ -5704,8 +5308,8 @@ var GatewayPlugin = class extends Plugin {
5704
5308
  }
5705
5309
  disconnect() {
5706
5310
  this.shouldReconnect = false;
5707
- this.stopReconnectTimer();
5708
- this.stopHeartbeat();
5311
+ this.reconnectTimer.stop();
5312
+ this.heartbeatTimers.stop();
5709
5313
  this.outboundLimiter.clear();
5710
5314
  this.ws?.close(1e3, "Client disconnect");
5711
5315
  this.ws = null;
@@ -5738,7 +5342,7 @@ var GatewayPlugin = class extends Plugin {
5738
5342
  socket.on("close", (code) => {
5739
5343
  if (socket !== this.ws) return;
5740
5344
  const closeCode = code;
5741
- this.stopHeartbeat();
5345
+ this.heartbeatTimers.stop();
5742
5346
  this.outboundLimiter.clear();
5743
5347
  this.isConnecting = false;
5744
5348
  this.isConnected = false;
@@ -5823,12 +5427,6 @@ var GatewayPlugin = class extends Plugin {
5823
5427
  }
5824
5428
  });
5825
5429
  }
5826
- stopHeartbeat() {
5827
- this.heartbeatTimers.stop();
5828
- }
5829
- stopReconnectTimer() {
5830
- this.reconnectTimer.stop();
5831
- }
5832
5430
  sendHeartbeat() {
5833
5431
  if (!this.ws || this.ws.readyState !== READY_STATE_OPEN) return;
5834
5432
  this.lastHeartbeatAck = false;
@@ -5894,7 +5492,7 @@ var GatewayPlugin = class extends Plugin {
5894
5492
  this.isConnected = true;
5895
5493
  }
5896
5494
  this.voiceStateCache.apply(payload);
5897
- dispatchVoiceGatewayEvent(this.client, payload.t, payload.d);
5495
+ dispatchVoiceGatewayEvent(this.client, payload);
5898
5496
  const data = payload.t === GatewayDispatchEvents.MessageCreate ? payload.d : mapGatewayDispatchData(this.client, payload.t, payload.d);
5899
5497
  await this.client.dispatchGatewayEvent(payload.t, data);
5900
5498
  if (payload.t === GatewayDispatchEvents.InteractionCreate && this.options.autoInteractions) await this.client.handleInteraction(payload.d);
@@ -5914,8 +5512,8 @@ var GatewayPlugin = class extends Plugin {
5914
5512
  }
5915
5513
  scheduleReconnect(options) {
5916
5514
  if (!this.shouldReconnect) return;
5917
- this.stopHeartbeat();
5918
- this.stopReconnectTimer();
5515
+ this.heartbeatTimers.stop();
5516
+ this.reconnectTimer.stop();
5919
5517
  this.ws?.close();
5920
5518
  this.ws = null;
5921
5519
  this.isConnecting = false;
@@ -5953,43 +5551,24 @@ var GatewayPlugin = class extends Plugin {
5953
5551
  d: data
5954
5552
  }, true);
5955
5553
  }
5956
- requestGuildMembers(data) {
5957
- if (!this.hasIntent(GatewayIntentBits.GuildMembers)) throw new Error("GUILD_MEMBERS intent is required for requestGuildMembers");
5958
- if (data.presences && !this.hasIntent(GatewayIntentBits.GuildPresences)) throw new Error("GUILD_PRESENCES intent is required when requesting presences");
5959
- if (!data.query && data.query !== "" && !data.user_ids) throw new Error("Either query or user_ids is required for requestGuildMembers");
5960
- this.send({
5961
- op: GatewayOpcodes.RequestGuildMembers,
5962
- d: data
5963
- });
5964
- }
5965
5554
  getRateLimitStatus() {
5966
5555
  return this.outboundLimiter.getStatus();
5967
5556
  }
5968
- hasIntent(intent) {
5969
- return Boolean((this.options.intents ?? 0) & intent);
5970
- }
5971
5557
  };
5972
5558
  //#endregion
5973
5559
  //#region extensions/discord/src/monitor/presence.ts
5974
- const DEFAULT_CUSTOM_ACTIVITY_TYPE$1 = 4;
5975
- const CUSTOM_STATUS_NAME$1 = "Custom Status";
5560
+ const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
5561
+ const CUSTOM_STATUS_NAME = "Custom Status";
5976
5562
  function resolveDiscordPresenceUpdate(config) {
5977
5563
  const activityText = normalizeOptionalString(config.activity) ?? "";
5978
5564
  const status = normalizeOptionalString(config.status) ?? "";
5979
5565
  const activityType = config.activityType;
5980
5566
  const activityUrl = normalizeOptionalString(config.activityUrl) ?? "";
5981
- const hasActivity = Boolean(activityText);
5982
- if (!hasActivity && !Boolean(status)) return {
5983
- since: null,
5984
- activities: [],
5985
- status: "online",
5986
- afk: false
5987
- };
5988
5567
  const activities = [];
5989
- if (hasActivity) {
5990
- const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE$1;
5991
- const activity = resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE$1 ? {
5992
- name: CUSTOM_STATUS_NAME$1,
5568
+ if (activityText) {
5569
+ const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE;
5570
+ const activity = resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE ? {
5571
+ name: CUSTOM_STATUS_NAME,
5993
5572
  type: resolvedType,
5994
5573
  state: activityText
5995
5574
  } : {
@@ -6008,8 +5587,6 @@ function resolveDiscordPresenceUpdate(config) {
6008
5587
  }
6009
5588
  //#endregion
6010
5589
  //#region extensions/discord/src/monitor/auto-presence.ts
6011
- const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
6012
- const CUSTOM_STATUS_NAME = "Custom Status";
6013
5590
  const DEFAULT_INTERVAL_MS = 3e4;
6014
5591
  const DEFAULT_MIN_UPDATE_INTERVAL_MS = 15e3;
6015
5592
  const MIN_INTERVAL_MS = 5e3;
@@ -6029,13 +5606,6 @@ function resolveAutoPresenceConfig(config) {
6029
5606
  minUpdateIntervalMs
6030
5607
  };
6031
5608
  }
6032
- function buildCustomStatusActivity(text) {
6033
- return {
6034
- name: CUSTOM_STATUS_NAME,
6035
- type: DEFAULT_CUSTOM_ACTIVITY_TYPE,
6036
- state: text
6037
- };
6038
- }
6039
5609
  function isExhaustedUnavailableReason(reason) {
6040
5610
  if (!reason) return false;
6041
5611
  return reason === "rate_limit" || reason === "overloaded" || reason === "billing" || reason === "auth" || reason === "auth_permanent";
@@ -6051,15 +5621,6 @@ function resolveAuthAvailability(params) {
6051
5621
  now: params.now
6052
5622
  })) ? "exhausted" : "degraded";
6053
5623
  }
6054
- function resolvePresenceActivities(params) {
6055
- if (params.state === "healthy") return params.basePresence?.activities ?? [];
6056
- return [buildCustomStatusActivity(params.state === "degraded" ? "runtime degraded" : "token exhausted")];
6057
- }
6058
- function resolvePresenceStatus(state) {
6059
- if (state === "healthy") return "online";
6060
- if (state === "exhausted") return "dnd";
6061
- return "idle";
6062
- }
6063
5624
  function resolveDiscordAutoPresenceUpdate(params) {
6064
5625
  if (!resolveAutoPresenceConfig(params.discordConfig.autoPresence).enabled) return null;
6065
5626
  const now = params.now ?? Date.now();
@@ -6069,15 +5630,15 @@ function resolveDiscordAutoPresenceUpdate(params) {
6069
5630
  now
6070
5631
  });
6071
5632
  const state = params.gatewayConnected ? availability : "degraded";
6072
- return {
5633
+ return state === "healthy" ? {
6073
5634
  since: null,
6074
- activities: resolvePresenceActivities({
6075
- state,
6076
- basePresence
6077
- }),
6078
- status: resolvePresenceStatus(state),
5635
+ activities: basePresence.activities,
5636
+ status: "online",
6079
5637
  afk: false
6080
- };
5638
+ } : resolveDiscordPresenceUpdate({
5639
+ activity: state === "degraded" ? "runtime degraded" : "token exhausted",
5640
+ status: state === "degraded" ? "idle" : "dnd"
5641
+ });
6081
5642
  }
6082
5643
  function stablePresenceSignature(payload) {
6083
5644
  return JSON.stringify({
@@ -6150,6 +5711,7 @@ function createDiscordAutoPresenceController(params) {
6150
5711
  const DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT = "openclaw:discord-gateway-transport-activity";
6151
5712
  //#endregion
6152
5713
  //#region extensions/discord/src/monitor/gateway-metadata.ts
5714
+ const captureSdk$1 = proxyCaptureSdk;
6153
5715
  const DISCORD_GATEWAY_BOT_URL = "https://discord.com/api/v10/gateway/bot";
6154
5716
  const DISCORD_API_HOST = "discord.com";
6155
5717
  const DEFAULT_DISCORD_GATEWAY_URL = "wss://gateway.discord.gg/";
@@ -6169,11 +5731,6 @@ const discordGatewayBotInfoSchema = Type.Object({
6169
5731
  })
6170
5732
  });
6171
5733
  const gatewayMetadataFallbackLogLastAt = /* @__PURE__ */ new WeakMap();
6172
- function resolveFetchInputUrl(input) {
6173
- if (typeof input === "string") return input;
6174
- if (input instanceof URL) return input.toString();
6175
- return input.url;
6176
- }
6177
5734
  async function materializeGuardedResponse(response) {
6178
5735
  const body = new Uint8Array(await readResponseWithLimit(response, DISCORD_GATEWAY_METADATA_MAX_BYTES, { onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`Discord gateway metadata response body too large: ${size} bytes (limit: ${maxBytes} bytes)`) }));
6179
5736
  return new Response(body, {
@@ -6237,6 +5794,7 @@ function parseDiscordGatewayInfoBody(body) {
6237
5794
  }
6238
5795
  async function fetchDiscordGatewayInfo(params) {
6239
5796
  let response;
5797
+ let body;
6240
5798
  try {
6241
5799
  response = await params.fetchImpl(params.gatewayBotUrl ?? DISCORD_GATEWAY_BOT_URL, {
6242
5800
  ...params.fetchInit,
@@ -6245,15 +5803,6 @@ async function fetchDiscordGatewayInfo(params) {
6245
5803
  Authorization: `Bot ${params.token}`
6246
5804
  }
6247
5805
  });
6248
- } catch (error) {
6249
- throw createGatewayMetadataError({
6250
- detail: formatErrorMessage$1(error),
6251
- transient: true,
6252
- cause: error
6253
- });
6254
- }
6255
- let body;
6256
- try {
6257
5806
  body = await response.text();
6258
5807
  } catch (error) {
6259
5808
  throw createGatewayMetadataError({
@@ -6318,7 +5867,7 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
6318
5867
  const requestInit = init;
6319
5868
  const signal = requestInit?.signal ?? void 0;
6320
5869
  const guarded = await fetchWithSsrFGuard({
6321
- url: resolveFetchInputUrl(input),
5870
+ url: input,
6322
5871
  init: requestInit,
6323
5872
  ...signal ? { signal } : {},
6324
5873
  policy: { allowedHostnames: [DISCORD_API_HOST] },
@@ -6339,7 +5888,7 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
6339
5888
  } finally {
6340
5889
  await guarded.release();
6341
5890
  }
6342
- if (options?.capture) captureHttpExchange({
5891
+ if (options?.capture) captureSdk$1.captureHttpExchangeAsync?.({
6343
5892
  url: input,
6344
5893
  method: init?.method ?? "GET",
6345
5894
  requestHeaders: init?.headers,
@@ -6347,23 +5896,17 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
6347
5896
  response,
6348
5897
  flowId: options.capture.flowId,
6349
5898
  meta: options.capture.meta
6350
- });
5899
+ }).catch(() => {});
6351
5900
  return response;
6352
5901
  }
6353
5902
  //#endregion
6354
5903
  //#region extensions/discord/src/monitor/gateway-plugin.ts
5904
+ const captureSdk = proxyCaptureSdk;
6355
5905
  const DISCORD_GATEWAY_POLICY_VIOLATION_CLOSE_CODE = 1008;
6356
5906
  const DISCORD_GATEWAY_WS_RECEIVER_LIMIT_CODE = "WS_ERR_TOO_MANY_BUFFERED_PARTS";
6357
5907
  const DISCORD_GATEWAY_CLOSE_REASON_LOG_MAX_CHARS = 240;
6358
5908
  const discordDnsLookup = createDiscordDnsLookup();
6359
5909
  const registrationPromises = /* @__PURE__ */ new WeakMap();
6360
- function assignGatewayClient(plugin, client) {
6361
- plugin.client = client;
6362
- }
6363
- function hasGatewaySocketStarted(plugin) {
6364
- const state = plugin;
6365
- return state.ws != null || state.isConnecting === true;
6366
- }
6367
5910
  function readStringProperty(value, key) {
6368
5911
  const property = value[key];
6369
5912
  return typeof property === "string" && property ? property : void 0;
@@ -6439,7 +5982,7 @@ function createGatewayPlugin(params) {
6439
5982
  return registration;
6440
5983
  }
6441
5984
  async registerClientInternal(client) {
6442
- assignGatewayClient(this, client);
5985
+ this.client = client;
6443
5986
  if (!this.gatewayInfo || this.gatewayInfoUsedFallback) {
6444
5987
  const resolved = await fetchDiscordGatewayInfoWithTimeout({
6445
5988
  token: client.options.token,
@@ -6464,7 +6007,7 @@ function createGatewayPlugin(params) {
6464
6007
  await params.testing.registerClient(this, client);
6465
6008
  return;
6466
6009
  }
6467
- if (hasGatewaySocketStarted(this)) return;
6010
+ if (this.ws != null || this.isConnecting) return;
6468
6011
  return super.registerClient(client);
6469
6012
  }
6470
6013
  createWebSocket(url) {
@@ -6480,35 +6023,34 @@ function createGatewayPlugin(params) {
6480
6023
  if (this.ws !== socket) return;
6481
6024
  this.emitter.emit(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, { at: Date.now() });
6482
6025
  };
6483
- captureWsEvent({
6484
- url,
6026
+ const captureEvent = (event) => {
6027
+ captureSdk.captureWsEventAsync?.({
6028
+ url,
6029
+ ...event(),
6030
+ flowId: wsFlowId,
6031
+ meta: { subsystem: "discord-gateway" }
6032
+ }).catch(() => {});
6033
+ };
6034
+ captureEvent(() => ({
6485
6035
  direction: "local",
6486
- kind: "ws-open",
6487
- flowId: wsFlowId,
6488
- meta: { subsystem: "discord-gateway" }
6489
- });
6036
+ kind: "ws-open"
6037
+ }));
6490
6038
  socket.on?.("message", (data) => {
6491
6039
  emitTransportActivity();
6492
- captureWsEvent({
6493
- url,
6040
+ captureEvent(() => ({
6494
6041
  direction: "inbound",
6495
6042
  kind: "ws-frame",
6496
- flowId: wsFlowId,
6497
- payload: Buffer.isBuffer(data) ? data : Buffer.from(String(data)),
6498
- meta: { subsystem: "discord-gateway" }
6499
- });
6043
+ payload: Buffer.isBuffer(data) ? data : Buffer.from(String(data))
6044
+ }));
6500
6045
  });
6501
6046
  socket.on?.("close", (code, reason) => {
6502
6047
  const closeReason = Buffer.isBuffer(reason) ? reason : Buffer.from(String(reason ?? ""));
6503
- captureWsEvent({
6504
- url,
6048
+ captureEvent(() => ({
6505
6049
  direction: "local",
6506
6050
  kind: "ws-close",
6507
- flowId: wsFlowId,
6508
6051
  closeCode: code,
6509
- payload: closeReason,
6510
- meta: { subsystem: "discord-gateway" }
6511
- });
6052
+ payload: closeReason
6053
+ }));
6512
6054
  if (shouldLogDiscordGatewayTransportClose({
6513
6055
  code,
6514
6056
  reason: closeReason,
@@ -6522,14 +6064,11 @@ function createGatewayPlugin(params) {
6522
6064
  });
6523
6065
  socket.on?.("error", (error) => {
6524
6066
  lastTransportError = describeDiscordGatewayTransportError(error);
6525
- captureWsEvent({
6526
- url,
6067
+ captureEvent(() => ({
6527
6068
  direction: "local",
6528
6069
  kind: "error",
6529
- flowId: wsFlowId,
6530
- errorText: error.message,
6531
- meta: { subsystem: "discord-gateway" }
6532
- });
6070
+ errorText: error.message
6071
+ }));
6533
6072
  params.runtime?.log?.(warn(formatDiscordGatewayTransportErrorLog({
6534
6073
  flowId: wsFlowId,
6535
6074
  error: lastTransportError
@@ -6580,7 +6119,7 @@ function createDiscordGatewayPlugin(params) {
6580
6119
  } : void 0;
6581
6120
  const endpointGatewayUrl = endpoint ? new URL(endpoint.gatewayOrigin) : void 0;
6582
6121
  let fetchImpl = createDiscordGatewayMetadataFetch(debugProxySettings.enabled, endpoint ? { endpoint } : void 0);
6583
- let wsAgent = endpointGatewayUrl?.protocol === "ws:" ? void 0 : new Agent$1({ lookup: endpointGatewayUrl ? createDiscordEndpointDnsLookup(endpointGatewayUrl.hostname) : discordDnsLookup });
6122
+ let wsAgent = endpointGatewayUrl?.protocol === "ws:" ? void 0 : new Agent({ lookup: endpointGatewayUrl ? createDiscordEndpointDnsLookup(endpointGatewayUrl.hostname) : discordDnsLookup });
6584
6123
  if (proxy && !endpoint) try {
6585
6124
  validateDiscordProxyUrl(proxy);
6586
6125
  wsAgent = params.testing?.createProxyAgent?.(proxy) ?? createNodeProxyAgent({
@@ -6659,29 +6198,16 @@ function formatDiscordGatewayErrorMessage(err) {
6659
6198
  }
6660
6199
  function classifyDiscordGatewayEvent(params) {
6661
6200
  const message = formatDiscordGatewayErrorMessage(params.err);
6662
- if (params.isDisallowedIntentsError(params.err)) return {
6663
- type: "disallowed-intents",
6664
- err: params.err,
6665
- message,
6666
- shouldStopLifecycle: true
6667
- };
6668
- if (message.includes("Max reconnect attempts")) return {
6669
- type: "reconnect-exhausted",
6670
- err: params.err,
6671
- message,
6672
- shouldStopLifecycle: true
6673
- };
6674
- if (params.err instanceof TypeError || message.includes("Fatal Gateway error") || message.includes("Fatal gateway close code") || message.includes("Gateway HELLO missing heartbeat") || message.includes("Invalid gateway payload") || message.includes("Gateway socket emitted an unknown error")) return {
6675
- type: "fatal",
6676
- err: params.err,
6677
- message,
6678
- shouldStopLifecycle: true
6679
- };
6201
+ let type;
6202
+ if (params.isDisallowedIntentsError(params.err)) type = "disallowed-intents";
6203
+ else if (message.includes("Max reconnect attempts")) type = "reconnect-exhausted";
6204
+ else if (params.err instanceof TypeError || message.includes("Fatal Gateway error") || message.includes("Fatal gateway close code") || message.includes("Gateway HELLO missing heartbeat") || message.includes("Invalid gateway payload") || message.includes("Gateway socket emitted an unknown error")) type = "fatal";
6205
+ else type = "other";
6680
6206
  return {
6681
- type: "other",
6207
+ type,
6682
6208
  err: params.err,
6683
6209
  message,
6684
- shouldStopLifecycle: false
6210
+ shouldStopLifecycle: type !== "other"
6685
6211
  };
6686
6212
  }
6687
6213
  function createDiscordGatewaySupervisor(params) {
@@ -6697,7 +6223,7 @@ function createDiscordGatewaySupervisor(params) {
6697
6223
  let lifecycleHandler;
6698
6224
  let phase = "buffering";
6699
6225
  const seenLateEventKeys = /* @__PURE__ */ new Set();
6700
- const logLateEvent = (state) => (event) => {
6226
+ const logLateEvent = (state, event) => {
6701
6227
  const key = `${state}:${event.type}:${event.message}`;
6702
6228
  if (seenLateEventKeys.has(key)) return;
6703
6229
  seenLateEventKeys.add(key);
@@ -6710,13 +6236,13 @@ function createDiscordGatewaySupervisor(params) {
6710
6236
  });
6711
6237
  switch (phase) {
6712
6238
  case "disposed":
6713
- logLateEvent("disposed")(event);
6239
+ logLateEvent("disposed", event);
6714
6240
  return;
6715
6241
  case "active":
6716
6242
  lifecycleHandler?.(event);
6717
6243
  return;
6718
6244
  case "teardown":
6719
- logLateEvent("teardown")(event);
6245
+ logLateEvent("teardown", event);
6720
6246
  return;
6721
6247
  case "buffering": pending.push(event);
6722
6248
  }
@@ -6868,12 +6394,6 @@ function normalizeGatewayReadyTimeoutMs(value) {
6868
6394
  if (numeric === void 0) return;
6869
6395
  return Math.min(numeric, MAX_DISCORD_GATEWAY_READY_TIMEOUT_MS);
6870
6396
  }
6871
- function resolveDiscordGatewayReadyTimeoutMs(params) {
6872
- return normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS;
6873
- }
6874
- function resolveDiscordGatewayRuntimeReadyTimeoutMs(params) {
6875
- return normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS;
6876
- }
6877
6397
  async function restartGatewayAfterReadyTimeout(params) {
6878
6398
  if (!params.gateway || params.abortSignal?.aborted) return;
6879
6399
  const socket = params.gateway.ws;
@@ -6902,44 +6422,32 @@ async function restartGatewayAfterReadyTimeout(params) {
6902
6422
  socket.removeListener("close", onClose);
6903
6423
  socket.removeListener("error", ignoreSocketError);
6904
6424
  };
6905
- const finishResolve = () => {
6906
- if (settled) return;
6907
- settled = true;
6908
- cleanup();
6909
- resolve();
6910
- };
6911
- const finishReject = (error) => {
6912
- if (params.abortSignal?.aborted) {
6913
- finishResolve();
6914
- return;
6915
- }
6425
+ const finish = (error) => {
6916
6426
  if (settled) return;
6917
6427
  settled = true;
6918
6428
  cleanup();
6919
- reject(error);
6920
- };
6921
- const onClose = () => {
6922
- finishResolve();
6429
+ if (error && !params.abortSignal?.aborted) reject(error);
6430
+ else resolve();
6923
6431
  };
6432
+ const onClose = () => finish();
6433
+ const failClose = () => finish(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6924
6434
  socket.on("error", ignoreSocketError);
6925
6435
  socket.on("close", onClose);
6926
6436
  params.gateway?.disconnect();
6927
6437
  drainTimeout = setTimeout(() => {
6928
6438
  if (settled) return;
6929
6439
  if (typeof socket.terminate !== "function") {
6930
- finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6440
+ failClose();
6931
6441
  return;
6932
6442
  }
6933
6443
  params.runtime.error?.(danger(`discord: startup restart waiting on a stale gateway socket for ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms; forcing terminate before reconnect`));
6934
6444
  try {
6935
6445
  socket.terminate();
6936
6446
  } catch {
6937
- finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6447
+ failClose();
6938
6448
  return;
6939
6449
  }
6940
- terminateCloseTimeout = setTimeout(() => {
6941
- finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6942
- }, DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS);
6450
+ terminateCloseTimeout = setTimeout(failClose, DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS);
6943
6451
  terminateCloseTimeout.unref?.();
6944
6452
  }, DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS);
6945
6453
  drainTimeout.unref?.();
@@ -6980,9 +6488,6 @@ function createGatewayStatusObserver(params) {
6980
6488
  }
6981
6489
  queuedForceStopError = err;
6982
6490
  };
6983
- const pushConnectedStatus = (at) => {
6984
- params.pushStatus(createDiscordReadyStatusPatch(at));
6985
- };
6986
6491
  const startReadyWatch = () => {
6987
6492
  clearReadyWatch();
6988
6493
  const pollConnected = () => {
@@ -6992,7 +6497,7 @@ function createGatewayStatusObserver(params) {
6992
6497
  }
6993
6498
  if (!params.gateway?.isConnected) return;
6994
6499
  clearReadyWatch();
6995
- pushConnectedStatus(Date.now());
6500
+ params.pushStatus(createDiscordReadyStatusPatch(Date.now()));
6996
6501
  };
6997
6502
  pollConnected();
6998
6503
  if (!readyTimeoutId) {
@@ -7142,8 +6647,8 @@ async function runDiscordGatewayLifecycle(params) {
7142
6647
  const pushStatus = (patch) => {
7143
6648
  params.statusSink?.(patch);
7144
6649
  };
7145
- const gatewayReadyTimeoutMs = resolveDiscordGatewayReadyTimeoutMs({ env: process.env });
7146
- const gatewayRuntimeReadyTimeoutMs = resolveDiscordGatewayRuntimeReadyTimeoutMs({ env: process.env });
6650
+ const gatewayReadyTimeoutMs = normalizeGatewayReadyTimeoutMs(process.env[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS;
6651
+ const gatewayRuntimeReadyTimeoutMs = normalizeGatewayReadyTimeoutMs(process.env[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS;
7147
6652
  const statusObserver = createGatewayStatusObserver({
7148
6653
  gateway,
7149
6654
  abortSignal: params.abortSignal,
@@ -7207,23 +6712,26 @@ async function runDiscordGatewayLifecycle(params) {
7207
6712
  } catch (err) {
7208
6713
  if (!sawDisallowedIntents && !params.isDisallowedIntentsError(err)) throw err;
7209
6714
  } finally {
7210
- lifecycleStopping = true;
7211
- params.gatewaySupervisor.detachLifecycle();
7212
- unregisterGateway(params.accountId);
7213
- stopGatewayLogging();
7214
- statusObserver.dispose();
7215
- gatewayEmitter?.removeListener("debug", statusObserver.onGatewayDebug);
7216
- gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
7217
- if (params.voiceManager) {
7218
- await params.voiceManager.destroy();
7219
- setDiscordTranscriptsVoiceManager({
7220
- accountId: params.accountId,
7221
- manager: null,
7222
- expectedManager: params.voiceManager
7223
- });
7224
- params.voiceManagerRef.current = null;
6715
+ try {
6716
+ lifecycleStopping = true;
6717
+ params.gatewaySupervisor.detachLifecycle();
6718
+ unregisterGateway(params.accountId);
6719
+ stopGatewayLogging();
6720
+ statusObserver.dispose();
6721
+ gatewayEmitter?.removeListener("debug", statusObserver.onGatewayDebug);
6722
+ gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
6723
+ if (params.voiceManager) {
6724
+ await params.voiceManager.destroy();
6725
+ setDiscordTranscriptsVoiceManager({
6726
+ accountId: params.accountId,
6727
+ manager: null,
6728
+ expectedManager: params.voiceManager
6729
+ });
6730
+ params.voiceManagerRef.current = null;
6731
+ }
6732
+ } finally {
6733
+ await params.threadBindings.stop();
7225
6734
  }
7226
- params.threadBindings.stop();
7227
6735
  }
7228
6736
  }
7229
6737
  //#endregion
@@ -7231,7 +6739,7 @@ async function runDiscordGatewayLifecycle(params) {
7231
6739
  let discordVoiceRuntimePromise;
7232
6740
  let discordProviderSessionRuntimePromise;
7233
6741
  async function loadDiscordVoiceRuntime() {
7234
- const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-elTtjEIG.mjs").then((n) => n.t);
6742
+ const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-B46rcwrG.mjs").then((n) => n.t);
7235
6743
  discordVoiceRuntimePromise = promise;
7236
6744
  try {
7237
6745
  return await promise;
@@ -7241,7 +6749,7 @@ async function loadDiscordVoiceRuntime() {
7241
6749
  }
7242
6750
  }
7243
6751
  async function loadDiscordProviderSessionRuntime() {
7244
- const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-DrGAYnZv.mjs");
6752
+ const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BYlTBFD2.mjs");
7245
6753
  discordProviderSessionRuntimePromise = promise;
7246
6754
  try {
7247
6755
  return await promise;
@@ -7345,22 +6853,49 @@ async function probeDiscordAcpBindingHealth(params) {
7345
6853
  //#endregion
7346
6854
  //#region extensions/discord/src/monitor/provider.cleanup.ts
7347
6855
  async function cleanupDiscordProviderStartup(params) {
7348
- const listenersStopped = params.stopMonitorListeners?.();
7349
6856
  try {
7350
- await params.deactivateMessageHandler?.();
6857
+ const listenersStopped = params.stopMonitorListeners?.();
6858
+ try {
6859
+ await params.deactivateMessageHandler?.();
6860
+ } finally {
6861
+ await listenersStopped;
6862
+ }
6863
+ params.autoPresenceController?.stop();
6864
+ params.setStatus?.({ connected: false });
6865
+ if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
6866
+ if (!params.lifecycleStarted) try {
6867
+ params.lifecycleGateway?.disconnect();
6868
+ } catch (err) {
6869
+ params.runtime.error?.(danger(`discord: failed to disconnect gateway during startup cleanup: ${String(err)}`));
6870
+ }
6871
+ params.gatewaySupervisor?.dispose();
7351
6872
  } finally {
7352
- await listenersStopped;
7353
- }
7354
- params.autoPresenceController?.stop();
7355
- params.setStatus?.({ connected: false });
7356
- if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
7357
- if (!params.lifecycleStarted) try {
7358
- params.lifecycleGateway?.disconnect();
7359
- } catch (err) {
7360
- params.runtime.error?.(danger(`discord: failed to disconnect gateway during startup cleanup: ${String(err)}`));
6873
+ if (!params.lifecycleStarted) await params.threadBindings.stop();
7361
6874
  }
7362
- params.gatewaySupervisor?.dispose();
7363
- if (!params.lifecycleStarted) params.threadBindings.stop();
6875
+ }
6876
+ //#endregion
6877
+ //#region extensions/discord/src/voice/session.ts
6878
+ const MIN_SEGMENT_SECONDS = .35;
6879
+ const CAPTURE_FINALIZE_GRACE_MS = 2e3;
6880
+ const VOICE_CONNECT_READY_TIMEOUT_MS = 3e4;
6881
+ const VOICE_RECONNECT_GRACE_MS = 15e3;
6882
+ function resolveVoiceTimeoutMs(value, fallbackMs) {
6883
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallbackMs;
6884
+ return Math.floor(value);
6885
+ }
6886
+ function resolveDiscordVoiceMode(voice) {
6887
+ const mode = voice?.mode;
6888
+ if (mode === "stt-tts" || mode === "bidi") return mode;
6889
+ return "agent-proxy";
6890
+ }
6891
+ function isDiscordRealtimeVoiceMode(mode) {
6892
+ return mode === "agent-proxy" || mode === "bidi";
6893
+ }
6894
+ function logVoiceVerbose(message) {
6895
+ logVerbose(`discord voice: ${message}`);
6896
+ }
6897
+ function isVoiceChannel(type) {
6898
+ return type === discord_exports.ChannelType.GuildVoice || type === discord_exports.ChannelType.GuildStageVoice;
7364
6899
  }
7365
6900
  //#endregion
7366
6901
  //#region extensions/discord/src/voice/command.ts
@@ -7437,37 +6972,6 @@ async function authorizeVoiceCommand(interaction, params, options) {
7437
6972
  guildId: interaction.guild.id
7438
6973
  };
7439
6974
  }
7440
- async function resolveVoiceCommandRuntimeContext(interaction, params) {
7441
- const guildId = interaction.guild?.id;
7442
- if (!guildId) {
7443
- await interaction.reply({
7444
- content: "Unable to resolve guild for this command.",
7445
- ephemeral: true
7446
- });
7447
- return null;
7448
- }
7449
- const manager = params.getManager();
7450
- if (!manager) {
7451
- await interaction.reply({
7452
- content: "Voice manager is not available yet.",
7453
- ephemeral: true
7454
- });
7455
- return null;
7456
- }
7457
- return {
7458
- guildId,
7459
- manager
7460
- };
7461
- }
7462
- async function ensureVoiceCommandAccess(params) {
7463
- const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
7464
- if (access.ok) return true;
7465
- await params.interaction.reply({
7466
- content: access.message ?? "Not authorized.",
7467
- ephemeral: true
7468
- });
7469
- return false;
7470
- }
7471
6975
  function createDiscordVoiceCommand(startupParams) {
7472
6976
  const params = {
7473
6977
  ...startupParams,
@@ -7483,7 +6987,6 @@ function createDiscordVoiceCommand(startupParams) {
7483
6987
  }
7484
6988
  })
7485
6989
  };
7486
- const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
7487
6990
  class JoinCommand extends Command {
7488
6991
  constructor(..._args) {
7489
6992
  super(..._args);
@@ -7519,7 +7022,7 @@ function createDiscordVoiceCommand(startupParams) {
7519
7022
  });
7520
7023
  return;
7521
7024
  }
7522
- if (!isVoiceChannelType(channel.type)) {
7025
+ if (!isVoiceChannel(channel.type)) {
7523
7026
  await interaction.reply({
7524
7027
  content: "That is not a voice channel.",
7525
7028
  ephemeral: true
@@ -7552,48 +7055,49 @@ function createDiscordVoiceCommand(startupParams) {
7552
7055
  });
7553
7056
  }
7554
7057
  }
7555
- class LeaveCommand extends Command {
7556
- constructor(..._args2) {
7557
- super(..._args2);
7558
- this.name = "leave";
7559
- this.description = "Leave the current voice channel";
7560
- this.defer = true;
7561
- this.ephemeral = params.ephemeralDefault;
7562
- }
7563
- async run(interaction) {
7564
- const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
7565
- if (!runtimeContext) return;
7566
- const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
7567
- if (!await ensureVoiceCommandAccess({
7568
- interaction,
7569
- context: params,
7570
- channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
7571
- })) return;
7572
- const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
7573
- await interaction.reply({
7574
- content: result.message,
7575
- ephemeral: true
7576
- });
7577
- }
7578
- }
7579
- class StatusCommand extends Command {
7580
- constructor(..._args3) {
7581
- super(..._args3);
7582
- this.name = "status";
7583
- this.description = "Show active voice sessions";
7058
+ class SessionCommand extends Command {
7059
+ constructor(name) {
7060
+ super();
7061
+ this.name = name;
7584
7062
  this.defer = true;
7585
7063
  this.ephemeral = params.ephemeralDefault;
7064
+ this.description = name === "leave" ? "Leave the current voice channel" : "Show active voice sessions";
7586
7065
  }
7587
7066
  async run(interaction) {
7588
- const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
7589
- if (!runtimeContext) return;
7590
- const sessions = runtimeContext.manager.status().filter((entry) => entry.guildId === runtimeContext.guildId);
7067
+ const guildId = interaction.guild?.id;
7068
+ if (!guildId) {
7069
+ await interaction.reply({
7070
+ content: "Unable to resolve guild for this command.",
7071
+ ephemeral: true
7072
+ });
7073
+ return;
7074
+ }
7075
+ const manager = params.getManager();
7076
+ if (!manager) {
7077
+ await interaction.reply({
7078
+ content: "Voice manager is not available yet.",
7079
+ ephemeral: true
7080
+ });
7081
+ return;
7082
+ }
7083
+ const sessions = manager.status().filter((entry) => entry.guildId === guildId);
7591
7084
  const sessionChannelId = sessions[0]?.channelId;
7592
- if (!await ensureVoiceCommandAccess({
7593
- interaction,
7594
- context: params,
7595
- channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
7596
- })) return;
7085
+ const access = await authorizeVoiceCommand(interaction, params, { channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0 });
7086
+ if (!access.ok) {
7087
+ await interaction.reply({
7088
+ content: access.message ?? "Not authorized.",
7089
+ ephemeral: true
7090
+ });
7091
+ return;
7092
+ }
7093
+ if (this.name === "leave") {
7094
+ const result = await manager.leave({ guildId });
7095
+ await interaction.reply({
7096
+ content: result.message,
7097
+ ephemeral: true
7098
+ });
7099
+ return;
7100
+ }
7597
7101
  if (sessions.length === 0) {
7598
7102
  await interaction.reply({
7599
7103
  content: "No active voice sessions.",
@@ -7609,21 +7113,18 @@ function createDiscordVoiceCommand(startupParams) {
7609
7113
  }
7610
7114
  }
7611
7115
  return new class extends CommandWithSubcommands {
7612
- constructor(..._args4) {
7613
- super(..._args4);
7116
+ constructor(..._args2) {
7117
+ super(..._args2);
7614
7118
  this.name = DISCORD_VOICE_COMMAND_SPEC.name;
7615
7119
  this.description = DISCORD_VOICE_COMMAND_SPEC.description;
7616
7120
  this.subcommands = [
7617
7121
  new JoinCommand(),
7618
- new LeaveCommand(),
7619
- new StatusCommand()
7122
+ new SessionCommand("leave"),
7123
+ new SessionCommand("status")
7620
7124
  ];
7621
7125
  }
7622
7126
  }();
7623
7127
  }
7624
- function isVoiceChannelType(type) {
7625
- return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
7626
- }
7627
7128
  //#endregion
7628
7129
  //#region extensions/discord/src/monitor/provider.commands.ts
7629
7130
  const loadPluginCommandRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/plugin-command-runtime"));
@@ -7705,7 +7206,6 @@ function attachDiscordDeployRestContext(err, context) {
7705
7206
  if (typeof context.timeoutMs === "number" && Number.isFinite(context.timeoutMs)) deployErr.deployTimeoutMs = context.timeoutMs;
7706
7207
  }
7707
7208
  function stringifyDiscordDeployField(value) {
7708
- if (typeof value === "string") return JSON.stringify(value);
7709
7209
  try {
7710
7210
  return JSON.stringify(value);
7711
7211
  } catch {
@@ -7723,8 +7223,7 @@ function readDiscordDeployRejectedFields(value) {
7723
7223
  function resolveDiscordRejectedDeployEntriesSource(rawBody) {
7724
7224
  if (!rawBody || typeof rawBody !== "object") return null;
7725
7225
  const payload = rawBody;
7726
- const source = (payload.errors && typeof payload.errors === "object" ? payload.errors : void 0) ?? rawBody;
7727
- return source && typeof source === "object" ? source : null;
7226
+ return (payload.errors && typeof payload.errors === "object" ? payload.errors : void 0) ?? rawBody;
7728
7227
  }
7729
7228
  function readDiscordDeployObjectField(value, field) {
7730
7229
  return value && typeof value === "object" && field in value ? value[field] : void 0;
@@ -7739,9 +7238,7 @@ function formatDiscordDeployRestOperation(err) {
7739
7238
  const method = typeof err.deployRestMethod === "string" && err.deployRestMethod.trim().length > 0 ? err.deployRestMethod.toUpperCase() : void 0;
7740
7239
  const path = typeof err.deployRestPath === "string" && err.deployRestPath.trim().length > 0 ? err.deployRestPath : void 0;
7741
7240
  if (method && path) return `${method} ${path}`;
7742
- if (method) return method;
7743
- if (path) return path;
7744
- return "request";
7241
+ return method ?? path ?? "request";
7745
7242
  }
7746
7243
  function formatDiscordDeployErrorMessage(err) {
7747
7244
  if (!isAbortLikeError(err)) return formatErrorMessage(err);
@@ -7777,19 +7274,19 @@ function formatDiscordDeployRateLimitDetails(err) {
7777
7274
  const rateLimit = resolveDiscordDeployRateLimitDetails(err);
7778
7275
  if (!rateLimit) return "";
7779
7276
  const details = [];
7780
- if (typeof rateLimit.status === "number") details.push(`status=${rateLimit.status}`);
7781
- if (typeof rateLimit.retryAfterMs === "number") details.push(`retryAfter=${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7277
+ if (rateLimit.status !== void 0) details.push(`status=${rateLimit.status}`);
7278
+ if (rateLimit.retryAfterMs !== void 0) details.push(`retryAfter=${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7782
7279
  if (rateLimit.scope) details.push(`scope=${rateLimit.scope}`);
7783
- if (typeof rateLimit.discordCode === "number" || typeof rateLimit.discordCode === "string") details.push(`code=${rateLimit.discordCode}`);
7280
+ if (rateLimit.discordCode !== void 0) details.push(`code=${rateLimit.discordCode}`);
7784
7281
  return details.length > 0 ? ` (${details.join(", ")})` : "";
7785
7282
  }
7786
7283
  function formatDiscordDeployRateLimitWarning(err, accountId) {
7787
7284
  const rateLimit = resolveDiscordDeployRateLimitDetails(err);
7788
7285
  if (!rateLimit) return;
7789
7286
  const parts = [`[${accountId}] slash command deploy rate limited`];
7790
- if (typeof rateLimit.retryAfterMs === "number") parts.push(`retry after ${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7287
+ if (rateLimit.retryAfterMs !== void 0) parts.push(`retry after ${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7791
7288
  if (rateLimit.scope) parts.push(`scope=${rateLimit.scope}`);
7792
- if (typeof rateLimit.discordCode === "number" || typeof rateLimit.discordCode === "string") parts.push(`code=${rateLimit.discordCode}`);
7289
+ if (rateLimit.discordCode !== void 0) parts.push(`code=${rateLimit.discordCode}`);
7793
7290
  return `${parts.join("; ")}. Existing slash commands stay active. Message send/receive is unaffected.`;
7794
7291
  }
7795
7292
  function formatDiscordRejectedDeployEntries(params) {
@@ -7818,10 +7315,7 @@ function formatDiscordDeployErrorDetails(err) {
7818
7315
  if (!err || typeof err !== "object") return "";
7819
7316
  const rateLimitDetails = formatDiscordDeployRateLimitDetails(err);
7820
7317
  if (rateLimitDetails) return rateLimitDetails;
7821
- const status = err.status;
7822
- const discordCode = err.discordCode;
7823
- const rawBody = err.rawBody;
7824
- const requestBody = err.deployRequestBody;
7318
+ const { status, discordCode, rawBody, deployRequestBody: requestBody } = err;
7825
7319
  const details = [];
7826
7320
  if (typeof status === "number") details.push(`status=${status}`);
7827
7321
  if (typeof discordCode === "number" || typeof discordCode === "string") details.push(`code=${discordCode}`);
@@ -7862,7 +7356,7 @@ function formatDiscordStartupGatewayState(gateway) {
7862
7356
  const reconnectAttempts = gateway.reconnectAttempts;
7863
7357
  return `gatewayConnected=${gateway.isConnected ? "true" : "false"} reconnectAttempts=${typeof reconnectAttempts === "number" ? reconnectAttempts : "na"}`;
7864
7358
  }
7865
- function logDiscordStartupPhase$1(params) {
7359
+ function logDiscordStartupPhase(params) {
7866
7360
  if (!(params.isVerbose ?? isVerbose)()) return;
7867
7361
  const elapsedMs = Math.max(0, Date.now() - params.startAt);
7868
7362
  const suffix = [params.details, formatDiscordStartupGatewayState(params.gateway)].filter((value) => Boolean(value)).join(" ");
@@ -7970,7 +7464,7 @@ async function deployDiscordCommands(params) {
7970
7464
  }
7971
7465
  function runDiscordCommandDeployInBackground(params) {
7972
7466
  if (!params.enabled) return;
7973
- logDiscordStartupPhase$1({
7467
+ logDiscordStartupPhase({
7974
7468
  runtime: params.runtime,
7975
7469
  accountId: params.accountId,
7976
7470
  phase: "deploy-commands:scheduled",
@@ -7979,7 +7473,7 @@ function runDiscordCommandDeployInBackground(params) {
7979
7473
  isVerbose: params.isVerbose
7980
7474
  });
7981
7475
  deployDiscordCommands(params).then(() => {
7982
- logDiscordStartupPhase$1({
7476
+ logDiscordStartupPhase({
7983
7477
  runtime: params.runtime,
7984
7478
  accountId: params.accountId,
7985
7479
  phase: "deploy-commands:done",
@@ -8056,7 +7550,7 @@ var DiscordActivityButton = class extends Button {
8056
7550
  };
8057
7551
  function createDiscordActivityButton(ctx, applicationId, deps = {}) {
8058
7552
  const runtime = getDiscordActivitiesRuntime();
8059
- if (!runtime || !runtime.isAccountEnabled(ctx.accountId, ctx.cfg)) return null;
7553
+ if (!runtime) return null;
8060
7554
  if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
8061
7555
  if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
8062
7556
  return new DiscordActivityButton(ctx, {
@@ -8171,36 +7665,134 @@ async function resolveComponentInteractionContext(params) {
8171
7665
  };
8172
7666
  }
8173
7667
  //#endregion
8174
- //#region extensions/discord/src/monitor/agent-components-live-policy.ts
8175
- async function resolveAgentComponentPolicyContext(params) {
8176
- if (!params.ctx.readPolicy) return params.ctx;
8177
- try {
8178
- const policy = await readDiscordInteractionPolicy(params.ctx.readPolicy);
8179
- if (!policy) {
8180
- await replyUnavailableComponentInteraction(params.interaction, "Access policy is still updating. Try this interaction again.");
8181
- return null;
8182
- }
8183
- return {
8184
- ...params.ctx,
8185
- ...policy,
8186
- isPolicyCurrent: policy.isCurrent,
8187
- readPolicy: void 0
8188
- };
8189
- } catch (error) {
8190
- await replyUnavailableComponentInteraction(params.interaction, "Could not verify the current access policy. Try this interaction again.");
8191
- throw error;
8192
- }
7668
+ //#region extensions/discord/src/monitor/agent-components-data.ts
7669
+ function readParsedComponentId(data) {
7670
+ if (!data || typeof data !== "object") return;
7671
+ return "cid" in data ? data.cid : data.componentId;
8193
7672
  }
8194
- //#endregion
8195
- //#region extensions/discord/src/monitor/agent-components-dm-auth.ts
8196
- async function ensureDmComponentAuthorized(params) {
8197
- const { ctx, interaction, user, componentLabel, replyOpts } = params;
8198
- const dmPolicy = ctx.dmPolicy ?? "pairing";
8199
- if (ctx.discordConfig?.dm?.enabled === false || dmPolicy === "disabled") {
8200
- logVerbose(`agent ${componentLabel}: blocked (DM policy disabled)`);
8201
- await replySilently(interaction, {
8202
- content: "DM interactions are disabled.",
8203
- ...replyOpts
7673
+ function normalizeComponentId(value) {
7674
+ if (typeof value === "string") return normalizeOptionalString(value);
7675
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
7676
+ }
7677
+ function mapOptionLabels(options, values) {
7678
+ if (!options || options.length === 0) return values;
7679
+ const map = new Map(options.map((option) => [option.value, option.label]));
7680
+ return values.map((value) => map.get(value) ?? value);
7681
+ }
7682
+ function parseAgentComponentData(data) {
7683
+ const raw = readParsedComponentId(data);
7684
+ const componentId = typeof raw === "string" ? decodeCustomIdComponent(raw) : typeof raw === "number" ? String(raw) : null;
7685
+ if (!componentId) return null;
7686
+ return { componentId };
7687
+ }
7688
+ function parseDiscordComponentData(data, customId) {
7689
+ if (!data || typeof data !== "object") return null;
7690
+ const rawComponentId = readParsedComponentId(data);
7691
+ const rawModalId = "mid" in data ? data.mid : data.modalId;
7692
+ let componentId = normalizeComponentId(rawComponentId);
7693
+ let modalId = normalizeComponentId(rawModalId);
7694
+ if (!componentId && customId) {
7695
+ const parsed = parseDiscordComponentCustomId(customId);
7696
+ if (parsed) {
7697
+ componentId = parsed.componentId;
7698
+ modalId = parsed.modalId;
7699
+ }
7700
+ }
7701
+ if (!componentId) return null;
7702
+ return {
7703
+ componentId,
7704
+ modalId
7705
+ };
7706
+ }
7707
+ function parseDiscordModalId(data, customId) {
7708
+ if (data && typeof data === "object") {
7709
+ const modalId = normalizeComponentId("mid" in data ? data.mid : data.modalId);
7710
+ if (modalId) return modalId;
7711
+ }
7712
+ if (customId) return parseDiscordModalCustomId(customId);
7713
+ return null;
7714
+ }
7715
+ function resolveInteractionCustomId(interaction) {
7716
+ if (!interaction?.rawData || typeof interaction.rawData !== "object") return;
7717
+ if (!("data" in interaction.rawData)) return;
7718
+ return normalizeOptionalString(interaction.rawData.data?.custom_id);
7719
+ }
7720
+ function mapSelectValues(entry, values) {
7721
+ switch (entry.selectType) {
7722
+ case "string": return mapOptionLabels(entry.options, values);
7723
+ case "user":
7724
+ case "role":
7725
+ case "mentionable":
7726
+ case "channel": return values.map((value) => `${entry.selectType}:${value}`);
7727
+ default: return values;
7728
+ }
7729
+ }
7730
+ function resolveModalFieldValues(field, interaction) {
7731
+ const fields = interaction.fields;
7732
+ const required = field.required === true;
7733
+ try {
7734
+ switch (field.type) {
7735
+ case "text": {
7736
+ const value = fields.getText(field.id, required);
7737
+ return value ? [value] : [];
7738
+ }
7739
+ case "select":
7740
+ case "checkbox":
7741
+ case "radio": return mapOptionLabels(field.options, fields.getStringSelect(field.id, required));
7742
+ case "role-select": try {
7743
+ return fields.getRoleSelect(field.id, required).map((role) => role.name ?? role.id);
7744
+ } catch {
7745
+ return fields.getStringSelect(field.id, required);
7746
+ }
7747
+ case "user-select": return fields.getUserSelect(field.id, required).map((user) => formatDiscordUserTag(user));
7748
+ default: return [];
7749
+ }
7750
+ } catch (err) {
7751
+ logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
7752
+ return [];
7753
+ }
7754
+ }
7755
+ function formatModalSubmissionText(entry, interaction) {
7756
+ const lines = [`Form "${entry.title}" submitted.`];
7757
+ for (const field of entry.fields) {
7758
+ const values = resolveModalFieldValues(field, interaction);
7759
+ if (values.length === 0) continue;
7760
+ lines.push(`- ${field.label}: ${values.join(", ")}`);
7761
+ }
7762
+ if (lines.length === 1) lines.push("- (no values)");
7763
+ return lines.join("\n");
7764
+ }
7765
+ //#endregion
7766
+ //#region extensions/discord/src/monitor/agent-components-live-policy.ts
7767
+ async function resolveAgentComponentPolicyContext(params) {
7768
+ if (!params.ctx.readPolicy) return params.ctx;
7769
+ try {
7770
+ const policy = await readDiscordInteractionPolicy(params.ctx.readPolicy);
7771
+ if (!policy) {
7772
+ await replyUnavailableComponentInteraction(params.interaction, "Access policy is still updating. Try this interaction again.");
7773
+ return null;
7774
+ }
7775
+ return {
7776
+ ...params.ctx,
7777
+ ...policy,
7778
+ isPolicyCurrent: policy.isCurrent,
7779
+ readPolicy: void 0
7780
+ };
7781
+ } catch (error) {
7782
+ await replyUnavailableComponentInteraction(params.interaction, "Could not verify the current access policy. Try this interaction again.");
7783
+ throw error;
7784
+ }
7785
+ }
7786
+ //#endregion
7787
+ //#region extensions/discord/src/monitor/agent-components-dm-auth.ts
7788
+ async function ensureDmComponentAuthorized(params) {
7789
+ const { ctx, interaction, user, componentLabel, replyOpts } = params;
7790
+ const dmPolicy = ctx.dmPolicy ?? "pairing";
7791
+ if (ctx.discordConfig?.dm?.enabled === false || dmPolicy === "disabled") {
7792
+ logVerbose(`agent ${componentLabel}: blocked (DM policy disabled)`);
7793
+ await replySilently(interaction, {
7794
+ content: "DM interactions are disabled.",
7795
+ ...replyOpts
8204
7796
  });
8205
7797
  return false;
8206
7798
  }
@@ -8243,7 +7835,7 @@ async function ensureDmComponentAuthorized(params) {
8243
7835
  channel: "discord",
8244
7836
  accountId: ctx.accountId,
8245
7837
  upsertPairingRequest: async ({ id, meta }) => {
8246
- return await upsertChannelPairingRequest$1({
7838
+ return await upsertChannelPairingRequest({
8247
7839
  channel: "discord",
8248
7840
  id,
8249
7841
  accountId: ctx.accountId,
@@ -8393,7 +7985,7 @@ async function ensureGuildComponentMemberAllowed(params) {
8393
7985
  return false;
8394
7986
  }
8395
7987
  async function ensureComponentUserAllowed(params) {
8396
- const allowList = normalizeDiscordAllowList(params.entry.allowedUsers, [
7988
+ const allowList = normalizeDiscordAllowList(params.allowedUsers, [
8397
7989
  "discord:",
8398
7990
  "user:",
8399
7991
  "pk:"
@@ -8504,6 +8096,13 @@ async function resolveAuthorizedComponentInteraction(params) {
8504
8096
  });
8505
8097
  return null;
8506
8098
  }
8099
+ if (params.allowedUsers !== void 0 && !await ensureComponentUserAllowed({
8100
+ ...params,
8101
+ allowedUsers: params.allowedUsers,
8102
+ user,
8103
+ replyOpts,
8104
+ allowNameMatching
8105
+ })) return null;
8507
8106
  return {
8508
8107
  ctx,
8509
8108
  interactionCtx,
@@ -8552,130 +8151,21 @@ async function resolveComponentCommandAuthorized(params) {
8552
8151
  });
8553
8152
  }
8554
8153
  //#endregion
8555
- //#region extensions/discord/src/monitor/agent-components-data.ts
8556
- function readParsedComponentId(data) {
8557
- if (!data || typeof data !== "object") return;
8558
- return "cid" in data ? data.cid : data.componentId;
8559
- }
8560
- function normalizeComponentId(value) {
8561
- if (typeof value === "string") {
8562
- const trimmed = value.trim();
8563
- return trimmed ? trimmed : void 0;
8564
- }
8565
- if (typeof value === "number" && Number.isFinite(value)) return String(value);
8566
- }
8567
- function mapOptionLabels(options, values) {
8568
- if (!options || options.length === 0) return values;
8569
- const map = new Map(options.map((option) => [option.value, option.label]));
8570
- return values.map((value) => map.get(value) ?? value);
8571
- }
8572
- function parseAgentComponentData(data) {
8573
- const raw = readParsedComponentId(data);
8574
- const componentId = typeof raw === "string" ? decodeCustomIdComponent(raw) : typeof raw === "number" ? String(raw) : null;
8575
- if (!componentId) return null;
8576
- return { componentId };
8577
- }
8578
- function parseDiscordComponentData(data, customId) {
8579
- if (!data || typeof data !== "object") return null;
8580
- const rawComponentId = readParsedComponentId(data);
8581
- const rawModalId = "mid" in data ? data.mid : data.modalId;
8582
- let componentId = normalizeComponentId(rawComponentId);
8583
- let modalId = normalizeComponentId(rawModalId);
8584
- if (!componentId && customId) {
8585
- const parsed = parseDiscordComponentCustomId(customId);
8586
- if (parsed) {
8587
- componentId = parsed.componentId;
8588
- modalId = parsed.modalId;
8589
- }
8590
- }
8591
- if (!componentId) return null;
8592
- return {
8593
- componentId,
8594
- modalId
8595
- };
8596
- }
8597
- function parseDiscordModalId(data, customId) {
8598
- if (data && typeof data === "object") {
8599
- const modalId = normalizeComponentId("mid" in data ? data.mid : data.modalId);
8600
- if (modalId) return modalId;
8601
- }
8602
- if (customId) return parseDiscordModalCustomId(customId);
8603
- return null;
8604
- }
8605
- function resolveInteractionCustomId(interaction) {
8606
- if (!interaction?.rawData || typeof interaction.rawData !== "object") return;
8607
- if (!("data" in interaction.rawData)) return;
8608
- const customId = interaction.rawData.data?.custom_id;
8609
- if (typeof customId !== "string") return;
8610
- const trimmed = customId.trim();
8611
- return trimmed ? trimmed : void 0;
8612
- }
8613
- function mapSelectValues(entry, values) {
8614
- if (entry.selectType === "string") return mapOptionLabels(entry.options, values);
8615
- if (entry.selectType === "user") return values.map((value) => `user:${value}`);
8616
- if (entry.selectType === "role") return values.map((value) => `role:${value}`);
8617
- if (entry.selectType === "mentionable") return values.map((value) => `mentionable:${value}`);
8618
- if (entry.selectType === "channel") return values.map((value) => `channel:${value}`);
8619
- return values;
8620
- }
8621
- function resolveModalFieldValues(field, interaction) {
8622
- const fields = interaction.fields;
8623
- const optionLabels = field.options?.map((option) => ({
8624
- value: option.value,
8625
- label: option.label
8626
- }));
8627
- const required = field.required === true;
8628
- try {
8629
- switch (field.type) {
8630
- case "text": {
8631
- const value = required ? fields.getText(field.id, true) : fields.getText(field.id);
8632
- return value ? [value] : [];
8633
- }
8634
- case "select":
8635
- case "checkbox":
8636
- case "radio": return mapOptionLabels(optionLabels, required ? fields.getStringSelect(field.id, true) : fields.getStringSelect(field.id) ?? []);
8637
- case "role-select": try {
8638
- return (required ? fields.getRoleSelect(field.id, true) : fields.getRoleSelect(field.id) ?? []).map((role) => role.name ?? role.id);
8639
- } catch {
8640
- return required ? fields.getStringSelect(field.id, true) : fields.getStringSelect(field.id) ?? [];
8641
- }
8642
- case "user-select": return (required ? fields.getUserSelect(field.id, true) : fields.getUserSelect(field.id) ?? []).map((user) => formatDiscordUserTag(user));
8643
- default: return [];
8644
- }
8645
- } catch (err) {
8646
- logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
8647
- return [];
8648
- }
8649
- }
8650
- function formatModalSubmissionText(entry, interaction) {
8651
- const lines = [`Form "${entry.title}" submitted.`];
8652
- for (const field of entry.fields) {
8653
- const values = resolveModalFieldValues(field, interaction);
8654
- if (values.length === 0) continue;
8655
- lines.push(`- ${field.label}: ${values.join(", ")}`);
8656
- }
8657
- if (lines.length === 1) lines.push("- (no values)");
8658
- return lines.join("\n");
8659
- }
8660
- //#endregion
8661
- //#region extensions/discord/src/monitor/agent-components-helpers.ts
8662
- const AGENT_BUTTON_KEY = "agent";
8663
- const AGENT_SELECT_KEY = "agentsel";
8664
- //#endregion
8665
8154
  //#region extensions/discord/src/monitor/reply-context.ts
8666
8155
  function resolveReplyContext(message, resolveDiscordMessageText) {
8667
- const referenced = message.referencedMessage;
8668
- if (!referenced?.author) return null;
8156
+ const id = resolveDiscordReferencedReplyMessageId(message);
8157
+ if (!id) return null;
8158
+ const referenced = resolveDiscordReferencedReplyMessage(message);
8159
+ const channelId = message.messageReference?.channel_id ?? message.channelId;
8160
+ if (!referenced?.author || referenced.id !== id) return null;
8669
8161
  const referencedText = resolveDiscordMessageText(referenced, { includeForwarded: true });
8670
- const hasVisibleMedia = referenced.attachments.length > 0 || !referencedText && resolveDiscordMessageStickers(referenced).length > 0;
8671
- if (!referencedText && !hasVisibleMedia) return null;
8672
8162
  const sender = resolveDiscordSenderIdentity({
8673
8163
  author: referenced.author,
8674
8164
  pluralkitInfo: null
8675
8165
  });
8676
8166
  return {
8677
- id: referenced.id,
8678
- channelId: referenced.channelId,
8167
+ id,
8168
+ channelId,
8679
8169
  sender: sender.tag ?? sender.label ?? "unknown",
8680
8170
  senderId: referenced.author.id,
8681
8171
  senderName: referenced.author.username ?? void 0,
@@ -8759,14 +8249,10 @@ function formatDiscordReplySkip(params) {
8759
8249
  const context = [`target=${params.target}`, params.sessionKey ? `session=${params.sessionKey}` : void 0].filter(Boolean).join(" ");
8760
8250
  return `discord ${params.kind} reply skipped (${params.reason}): ${context}`;
8761
8251
  }
8762
- function resolveTargetChannelId(target) {
8763
- if (!target.startsWith("channel:")) return;
8764
- return target.slice(8).trim() || void 0;
8765
- }
8766
8252
  function resolveBoundThreadBinding(params) {
8767
8253
  const sessionKey = params.sessionKey?.trim();
8768
8254
  if (!params.threadBindings || !sessionKey) return;
8769
- const targetChannelId = resolveTargetChannelId(params.target);
8255
+ const targetChannelId = params.target.startsWith("channel:") ? params.target.slice(8).trim() : void 0;
8770
8256
  if (!targetChannelId) return;
8771
8257
  return params.threadBindings.listBySessionKey(sessionKey).find((entry) => entry.threadId === targetChannelId);
8772
8258
  }
@@ -8797,27 +8283,6 @@ function createDiscordDeliveryDeps(params) {
8797
8283
  })
8798
8284
  };
8799
8285
  }
8800
- function resolveDiscordDeliveryOptions(params) {
8801
- const binding = resolveBoundThreadBinding({
8802
- threadBindings: params.threadBindings,
8803
- sessionKey: params.sessionKey,
8804
- target: params.target
8805
- });
8806
- return {
8807
- to: binding ? `channel:${binding.channelId}` : params.target,
8808
- threadId: binding?.threadId,
8809
- agentId: binding?.agentId,
8810
- identity: resolveBindingIdentity(params.cfg, binding),
8811
- mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
8812
- replyToMode: params.replyToMode ?? "all",
8813
- formatting: {
8814
- textLimit: params.textLimit,
8815
- maxLinesPerMessage: params.maxLinesPerMessage,
8816
- tableMode: params.tableMode,
8817
- chunkMode: params.chunkMode
8818
- }
8819
- };
8820
- }
8821
8286
  function formatDiscordReasoningPayload(payload) {
8822
8287
  if (payload.isReasoning !== true) return payload;
8823
8288
  const text = typeof payload.text === "string" ? payload.text.trim() : "";
@@ -8829,8 +8294,8 @@ function formatDiscordReasoningPayload(payload) {
8829
8294
  return nextPayload;
8830
8295
  }
8831
8296
  async function deliverDiscordReply(params) {
8832
- params.runtime;
8833
- const delivery = resolveDiscordDeliveryOptions(params);
8297
+ const binding = resolveBoundThreadBinding(params);
8298
+ const to = binding ? `channel:${binding.channelId}` : params.target;
8834
8299
  const payloads = sanitizeDiscordFrontChannelReplyPayloads(params.replies, { kind: params.kind }).map(formatDiscordReasoningPayload).map((payload) => params.bindPendingFinalDelivery?.(payload) ?? payload);
8835
8300
  if (payloads.length === 0) return {
8836
8301
  visibleReplySent: false,
@@ -8839,14 +8304,19 @@ async function deliverDiscordReply(params) {
8839
8304
  const send = await sendDurableMessageBatch({
8840
8305
  cfg: params.cfg,
8841
8306
  channel: "discord",
8842
- to: delivery.to,
8307
+ to,
8843
8308
  accountId: params.accountId,
8844
8309
  payloads,
8845
8310
  replyToId: normalizeOptionalString(params.replyToId),
8846
- replyToMode: delivery.replyToMode,
8847
- formatting: delivery.formatting,
8848
- threadId: delivery.threadId,
8849
- identity: delivery.identity,
8311
+ replyToMode: params.replyToMode ?? "all",
8312
+ formatting: {
8313
+ textLimit: params.textLimit,
8314
+ maxLinesPerMessage: params.maxLinesPerMessage,
8315
+ tableMode: params.tableMode,
8316
+ chunkMode: params.chunkMode
8317
+ },
8318
+ threadId: binding?.threadId,
8319
+ identity: resolveBindingIdentity(params.cfg, binding),
8850
8320
  onPlatformSendDispatch: params.onPlatformSendDispatch,
8851
8321
  assertDirectAdapterHandoff: params.assertPlatformSendAuthorized,
8852
8322
  deps: createDiscordDeliveryDeps({
@@ -8855,11 +8325,11 @@ async function deliverDiscordReply(params) {
8855
8325
  rest: params.rest,
8856
8326
  allowedMentions: params.allowedMentions
8857
8327
  }),
8858
- mediaAccess: delivery.mediaAccess,
8328
+ mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
8859
8329
  session: buildOutboundSessionContext({
8860
8330
  cfg: params.cfg,
8861
8331
  sessionKey: params.sessionKey,
8862
- agentId: delivery.agentId,
8332
+ agentId: binding?.agentId,
8863
8333
  requesterAccountId: params.accountId
8864
8334
  })
8865
8335
  });
@@ -8875,7 +8345,7 @@ async function deliverDiscordReply(params) {
8875
8345
  }
8876
8346
  };
8877
8347
  }
8878
- if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${delivery.to}`);
8348
+ if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${to}`);
8879
8349
  const deliveryResult = {
8880
8350
  messageIds: listMessageReceiptPlatformIds(send.receipt),
8881
8351
  receipt: send.receipt,
@@ -8886,8 +8356,8 @@ async function deliverDiscordReply(params) {
8886
8356
  }
8887
8357
  //#endregion
8888
8358
  //#region extensions/discord/src/monitor/agent-components.dispatch.ts
8889
- const loadConversationRuntime$1 = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.mjs"));
8890
- const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-BKZL5fGj.mjs").then((n) => n.n));
8359
+ const loadReplyRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/reply-runtime"));
8360
+ const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-BiHCzBRu.mjs").then((n) => n.n));
8891
8361
  function buildDiscordComponentConversationLabel(params) {
8892
8362
  if (params.interactionCtx.isDirectMessage) return buildDirectLabel(params.interactionCtx.user);
8893
8363
  if (params.interactionCtx.isGroupDm) return `Group DM #${params.channelCtx.channelName ?? params.interactionCtx.channelId} channel id:${params.interactionCtx.channelId}`;
@@ -8902,16 +8372,8 @@ function resolveDiscordComponentChatType(interactionCtx) {
8902
8372
  if (interactionCtx.isGroupDm) return "group";
8903
8373
  return "channel";
8904
8374
  }
8905
- function resolveDiscordComponentOriginatingTo(interactionCtx) {
8906
- return resolveDiscordConversationIdentity({
8907
- isDirectMessage: interactionCtx.isDirectMessage,
8908
- userId: interactionCtx.userId,
8909
- channelId: interactionCtx.channelId
8910
- });
8911
- }
8912
8375
  async function dispatchDiscordComponentEvent(params) {
8913
8376
  const { ctx, interaction, interactionCtx, channelCtx, guildInfo, eventText } = params;
8914
- const runtime = ctx.runtime ?? createNonExitingRuntime();
8915
8377
  const route = resolveAgentComponentRoute({
8916
8378
  ctx,
8917
8379
  rawGuildId: interactionCtx.rawGuildId,
@@ -8925,7 +8387,6 @@ async function dispatchDiscordComponentEvent(params) {
8925
8387
  const sessionKey = params.routeOverrides?.sessionKey ?? route.sessionKey;
8926
8388
  const agentId = params.routeOverrides?.agentId ?? route.agentId;
8927
8389
  const accountId = params.routeOverrides?.accountId ?? route.accountId;
8928
- const inboundLastRouteSessionKey = sessionKey;
8929
8390
  const fromLabel = buildDiscordComponentConversationLabel({
8930
8391
  interactionCtx,
8931
8392
  interaction,
@@ -8960,7 +8421,7 @@ async function dispatchDiscordComponentEvent(params) {
8960
8421
  isGuild: !interactionCtx.isDirectMessage
8961
8422
  });
8962
8423
  const groupSystemPrompt = buildDiscordGroupSystemPrompt(channelConfig);
8963
- const pinnedMainDmOwner = interactionCtx.isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist$1({
8424
+ const pinnedMainDmOwner = interactionCtx.isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
8964
8425
  dmScope: ctx.cfg.session?.dmScope,
8965
8426
  allowFrom: channelConfig?.users ?? guildInfo?.users,
8966
8427
  normalizeEntry: (entry) => {
@@ -8979,12 +8440,17 @@ async function dispatchDiscordComponentEvent(params) {
8979
8440
  guildInfo,
8980
8441
  allowNameMatching
8981
8442
  });
8982
- const storePath = resolveStorePath$1(ctx.cfg.session?.store, { agentId });
8443
+ const storePath = resolveStorePath(ctx.cfg.session?.store, { agentId });
8983
8444
  const envelopeOptions = resolveEnvelopeFormatOptions(ctx.cfg);
8984
- const previousTimestamp = readSessionUpdatedAt$1({
8445
+ const previousTimestamp = readSessionUpdatedAt({
8985
8446
  storePath,
8986
8447
  sessionKey
8987
8448
  });
8449
+ const originatingTo = resolveDiscordConversationIdentity({
8450
+ isDirectMessage: interactionCtx.isDirectMessage,
8451
+ userId: interactionCtx.userId,
8452
+ channelId: interactionCtx.channelId
8453
+ });
8988
8454
  const timestamp = Date.now();
8989
8455
  const combinedBody = formatInboundEnvelope({
8990
8456
  channel: "Discord",
@@ -8996,9 +8462,7 @@ async function dispatchDiscordComponentEvent(params) {
8996
8462
  previousTimestamp,
8997
8463
  envelope: envelopeOptions
8998
8464
  });
8999
- const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await (async () => {
9000
- return { ...await loadConversationRuntime$1() };
9001
- })();
8465
+ const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await loadReplyRuntime();
9002
8466
  const ctxPayload = finalizeInboundContext({
9003
8467
  Body: combinedBody,
9004
8468
  BodyForAgent: eventText,
@@ -9040,7 +8504,7 @@ async function dispatchDiscordComponentEvent(params) {
9040
8504
  MessageSid: interaction.rawData.id,
9041
8505
  Timestamp: timestamp,
9042
8506
  OriginatingChannel: "discord",
9043
- OriginatingTo: resolveDiscordComponentOriginatingTo(interactionCtx) ?? `channel:${interactionCtx.channelId}`
8507
+ OriginatingTo: originatingTo ?? `channel:${interactionCtx.channelId}`
9044
8508
  });
9045
8509
  const deliverTarget = `channel:${interactionCtx.channelId}`;
9046
8510
  const typingChannelId = interactionCtx.channelId;
@@ -9086,11 +8550,11 @@ async function dispatchDiscordComponentEvent(params) {
9086
8550
  dispatchReplyFromConfig: ctx.channelRuntime?.reply?.dispatchReplyFromConfig,
9087
8551
  record: {
9088
8552
  updateLastRoute: interactionCtx.isDirectMessage ? {
9089
- sessionKey: inboundLastRouteSessionKey,
8553
+ sessionKey,
9090
8554
  channel: "discord",
9091
- to: resolveDiscordComponentOriginatingTo(interactionCtx) ?? `user:${interactionCtx.userId}`,
8555
+ to: originatingTo ?? `user:${interactionCtx.userId}`,
9092
8556
  accountId,
9093
- mainDmOwnerPin: inboundLastRouteSessionKey === route.mainSessionKey && pinnedMainDmOwner ? {
8557
+ mainDmOwnerPin: sessionKey === route.mainSessionKey && pinnedMainDmOwner ? {
9094
8558
  ownerRecipient: pinnedMainDmOwner,
9095
8559
  senderRecipient: interactionCtx.userId,
9096
8560
  onSkip: ({ ownerRecipient, senderRecipient }) => {
@@ -9112,7 +8576,6 @@ async function dispatchDiscordComponentEvent(params) {
9112
8576
  token,
9113
8577
  accountId,
9114
8578
  rest: interaction.client.rest,
9115
- runtime,
9116
8579
  replyToId,
9117
8580
  replyToMode,
9118
8581
  textLimit,
@@ -9169,7 +8632,7 @@ async function dispatchDiscordPluginInteractiveHandler(params) {
9169
8632
  }
9170
8633
  //#endregion
9171
8634
  //#region extensions/discord/src/monitor/agent-components.plugin-interactive.ts
9172
- const loadConversationRuntime = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.mjs"));
8635
+ const loadConversationRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/conversation-runtime"));
9173
8636
  async function dispatchPluginDiscordInteractiveEvent(params) {
9174
8637
  const normalizedConversationId = params.interactionCtx.rawGuildId || params.channelCtx.channelType === ChannelType.GroupDM ? `channel:${params.interactionCtx.channelId}` : `user:${params.interactionCtx.userId}`;
9175
8638
  let responded = false;
@@ -9224,13 +8687,16 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
9224
8687
  });
9225
8688
  }
9226
8689
  };
8690
+ const acknowledgeSilently = async () => {
8691
+ try {
8692
+ await respond.acknowledge();
8693
+ } catch {}
8694
+ };
9227
8695
  const conversationRuntime = await loadConversationRuntime();
9228
8696
  const pluginBindingApproval = conversationRuntime.parsePluginBindingApprovalCustomId(params.data);
9229
8697
  if (pluginBindingApproval) {
9230
8698
  const { buildPluginBindingResolvedText, resolvePluginConversationBindingApproval } = conversationRuntime;
9231
- try {
9232
- await respond.acknowledge();
9233
- } catch {}
8699
+ await acknowledgeSilently();
9234
8700
  const resolved = await resolvePluginConversationBindingApproval({
9235
8701
  approvalId: pluginBindingApproval.approvalId,
9236
8702
  decision: pluginBindingApproval.decision,
@@ -9275,24 +8741,18 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
9275
8741
  }
9276
8742
  },
9277
8743
  respond,
9278
- onMatched: async () => {
9279
- try {
9280
- await respond.acknowledge();
9281
- } catch {}
9282
- }
8744
+ onMatched: acknowledgeSilently
9283
8745
  });
9284
8746
  if (!dispatched.matched) return "unmatched";
9285
8747
  if (dispatched.handled) {
9286
- if (!responded) try {
9287
- await respond.acknowledge();
9288
- } catch {}
8748
+ if (!responded) await acknowledgeSilently();
9289
8749
  return "handled";
9290
8750
  }
9291
8751
  return "unmatched";
9292
8752
  }
9293
8753
  //#endregion
9294
8754
  //#region extensions/discord/src/monitor/agent-components.handlers.ts
9295
- const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-yBEb75bB.mjs").then((n) => n.t));
8755
+ const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-Cq1PvIpN.mjs").then((n) => n.t));
9296
8756
  async function handleDiscordComponentEvent(params) {
9297
8757
  const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
9298
8758
  if (!parsed) {
@@ -9315,19 +8775,11 @@ async function handleDiscordComponentEvent(params) {
9315
8775
  label: params.label,
9316
8776
  componentLabel: params.componentLabel,
9317
8777
  unauthorizedReply,
8778
+ allowedUsers: entry.allowedUsers,
9318
8779
  defer: false
9319
8780
  });
9320
8781
  if (!authorized) return;
9321
- const { ctx, interactionCtx, channelCtx, guildInfo, allowNameMatching, commandAuthorized, user, replyOpts } = authorized;
9322
- if (!await ensureComponentUserAllowed({
9323
- entry,
9324
- interaction: params.interaction,
9325
- user,
9326
- replyOpts,
9327
- componentLabel: params.componentLabel,
9328
- unauthorizedReply,
9329
- allowNameMatching
9330
- })) return;
8782
+ const { ctx, interactionCtx, channelCtx, guildInfo, commandAuthorized, replyOpts } = authorized;
9331
8783
  const consumed = await resolveDiscordComponentEntryWithPersistence({
9332
8784
  id: parsed.componentId,
9333
8785
  consume: !entry.reusable
@@ -9363,14 +8815,11 @@ async function handleDiscordComponentEvent(params) {
9363
8815
  label: consumed.label,
9364
8816
  values
9365
8817
  });
9366
- try {
9367
- await params.interaction.reply({
9368
- content: "✓",
9369
- ...replyOpts
9370
- });
9371
- } catch (err) {
9372
- logError(`${params.label}: failed to acknowledge interaction: ${String(err)}`);
9373
- }
8818
+ await ackComponentInteraction({
8819
+ interaction: params.interaction,
8820
+ replyOpts,
8821
+ label: params.label
8822
+ });
9374
8823
  await dispatchDiscordComponentEvent({
9375
8824
  ctx,
9376
8825
  interaction: params.interaction,
@@ -9407,25 +8856,14 @@ async function handleDiscordModalTrigger(params) {
9407
8856
  await replyUnavailableComponentInteraction(params.interaction, "This form is no longer available.");
9408
8857
  return;
9409
8858
  }
9410
- const unauthorizedReply = "You are not authorized to use this form.";
9411
- const authorized = await resolveAuthorizedComponentInteraction({
8859
+ if (!await resolveAuthorizedComponentInteraction({
9412
8860
  ctx: params.ctx,
9413
8861
  interaction: params.interaction,
9414
8862
  label: params.label,
9415
8863
  componentLabel: "form",
9416
- unauthorizedReply,
8864
+ unauthorizedReply: "You are not authorized to use this form.",
8865
+ allowedUsers: entry.allowedUsers,
9417
8866
  defer: false
9418
- });
9419
- if (!authorized) return;
9420
- const { user, replyOpts, allowNameMatching } = authorized;
9421
- if (!await ensureComponentUserAllowed({
9422
- entry,
9423
- interaction: params.interaction,
9424
- user,
9425
- replyOpts,
9426
- componentLabel: "form",
9427
- unauthorizedReply,
9428
- allowNameMatching
9429
8867
  })) return;
9430
8868
  const consumed = await resolveDiscordComponentEntryWithPersistence({
9431
8869
  id: parsed.componentId,
@@ -9460,11 +8898,11 @@ const discordComponentControlHandlers = {
9460
8898
  var DiscordComponentModal = class extends Modal {
9461
8899
  constructor(ctx) {
9462
8900
  super();
8901
+ this.ctx = ctx;
9463
8902
  this.title = "OpenClaw form";
9464
8903
  this.customId = "__openclaw_discord_component_modal_wildcard__";
9465
8904
  this.components = [];
9466
8905
  this.customIdParser = parseDiscordModalCustomIdForInteraction;
9467
- this.ctx = ctx;
9468
8906
  }
9469
8907
  async run(interaction, data) {
9470
8908
  const modalId = parseDiscordModalId(data, resolveInteractionCustomId(interaction));
@@ -9481,32 +8919,18 @@ var DiscordComponentModal = class extends Modal {
9481
8919
  await replyUnavailableComponentInteraction(interaction, "This form has expired.");
9482
8920
  return;
9483
8921
  }
9484
- const unauthorizedReply = "You are not authorized to use this form.";
9485
8922
  const authorized = await resolveAuthorizedComponentInteraction({
9486
8923
  ctx: this.ctx,
9487
8924
  interaction,
9488
8925
  label: "discord component modal",
9489
8926
  componentLabel: "form",
9490
- unauthorizedReply,
8927
+ unauthorizedReply: "You are not authorized to use this form.",
8928
+ allowedUsers: modalEntry.allowedUsers,
9491
8929
  defer: false
9492
8930
  });
9493
8931
  if (!authorized) return;
9494
8932
  const ctx = authorized.ctx;
9495
- const { interactionCtx, channelCtx, guildInfo, allowNameMatching, commandAuthorized, user, replyOpts } = authorized;
9496
- if (!await ensureComponentUserAllowed({
9497
- entry: {
9498
- id: modalEntry.id,
9499
- kind: "button",
9500
- label: modalEntry.title,
9501
- allowedUsers: modalEntry.allowedUsers
9502
- },
9503
- interaction,
9504
- user,
9505
- replyOpts,
9506
- componentLabel: "form",
9507
- unauthorizedReply,
9508
- allowNameMatching
9509
- })) return;
8933
+ const { interactionCtx, channelCtx, guildInfo, commandAuthorized } = authorized;
9510
8934
  const consumed = await resolveDiscordModalEntryWithPersistence({
9511
8935
  id: modalId,
9512
8936
  consume: !modalEntry.reusable
@@ -9556,6 +8980,8 @@ var DiscordComponentModal = class extends Modal {
9556
8980
  };
9557
8981
  //#endregion
9558
8982
  //#region extensions/discord/src/monitor/agent-components.system-controls.ts
8983
+ const AGENT_BUTTON_KEY = "agent";
8984
+ const AGENT_SELECT_KEY = "agentsel";
9559
8985
  async function runAgentSystemControlInteraction(params) {
9560
8986
  const parsed = parseAgentComponentData(params.data);
9561
8987
  if (!parsed) {
@@ -9603,7 +9029,7 @@ async function runAgentSystemControlInteraction(params) {
9603
9029
  userId
9604
9030
  });
9605
9031
  logDebug(`${params.label}: enqueuing event for channel ${channelId}: ${eventText}`);
9606
- enqueueRoutedSystemEvent$1(eventText, route, { contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}:${params.interaction.id}` });
9032
+ enqueueRoutedSystemEvent(eventText, route, { contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}:${params.interaction.id}` });
9607
9033
  await ackComponentInteraction({
9608
9034
  interaction: params.interaction,
9609
9035
  replyOpts,
@@ -9613,10 +9039,10 @@ async function runAgentSystemControlInteraction(params) {
9613
9039
  var AgentComponentButton = class extends Button {
9614
9040
  constructor(ctx) {
9615
9041
  super();
9042
+ this.ctx = ctx;
9616
9043
  this.label = AGENT_BUTTON_KEY;
9617
9044
  this.customId = `${AGENT_BUTTON_KEY}:seed=1`;
9618
9045
  this.style = ButtonStyle.Primary;
9619
- this.ctx = ctx;
9620
9046
  }
9621
9047
  async run(interaction, data) {
9622
9048
  await runAgentSystemControlInteraction({
@@ -9636,9 +9062,9 @@ var AgentComponentButton = class extends Button {
9636
9062
  var AgentSelectMenu = class extends StringSelectMenu {
9637
9063
  constructor(ctx) {
9638
9064
  super();
9065
+ this.ctx = ctx;
9639
9066
  this.customId = `${AGENT_SELECT_KEY}:seed=1`;
9640
9067
  this.options = [];
9641
- this.ctx = ctx;
9642
9068
  }
9643
9069
  async run(interaction, data) {
9644
9070
  const values = interaction.values ?? [];
@@ -9757,11 +9183,8 @@ var DiscordComponentButton = class extends Button {
9757
9183
  });
9758
9184
  }
9759
9185
  };
9760
- function createSelectControl(spec, ctx, handlers) {
9761
- return new DiscordComponentSelectControl(spec, ctx, handlers);
9762
- }
9763
9186
  function bindSelectControl(spec) {
9764
- return (ctx, handlers) => createSelectControl(spec, ctx, handlers);
9187
+ return (ctx, handlers) => new DiscordComponentSelectControl(spec, ctx, handlers);
9765
9188
  }
9766
9189
  function createDiscordComponentButtonControl(ctx, handlers) {
9767
9190
  return new DiscordComponentButton(ctx, handlers);
@@ -9773,24 +9196,15 @@ const createDiscordComponentMentionableSelectControl = bindSelectControl(SELECT_
9773
9196
  const createDiscordComponentChannelSelectControl = bindSelectControl(SELECT_CONTROLS.channel);
9774
9197
  //#endregion
9775
9198
  //#region extensions/discord/src/monitor/agent-components.ts
9776
- function bindDiscordComponentControl(createControl) {
9777
- return (ctx) => createControl(ctx, discordComponentControlHandlers);
9778
- }
9779
- const createDiscordComponentButton = bindDiscordComponentControl(createDiscordComponentButtonControl);
9780
- const createDiscordComponentStringSelect = bindDiscordComponentControl(createDiscordComponentStringSelectControl);
9781
- const createDiscordComponentUserSelect = bindDiscordComponentControl(createDiscordComponentUserSelectControl);
9782
- const createDiscordComponentRoleSelect = bindDiscordComponentControl(createDiscordComponentRoleSelectControl);
9783
- const createDiscordComponentMentionableSelect = bindDiscordComponentControl(createDiscordComponentMentionableSelectControl);
9784
- const createDiscordComponentChannelSelect = bindDiscordComponentControl(createDiscordComponentChannelSelectControl);
9785
9199
  const createAgentComponentControls = [createAgentComponentButton, createAgentSelectMenu];
9786
9200
  const createDiscordComponentControls = [
9787
- createDiscordComponentButton,
9788
- createDiscordComponentStringSelect,
9789
- createDiscordComponentUserSelect,
9790
- createDiscordComponentRoleSelect,
9791
- createDiscordComponentMentionableSelect,
9792
- createDiscordComponentChannelSelect
9793
- ];
9201
+ createDiscordComponentButtonControl,
9202
+ createDiscordComponentStringSelectControl,
9203
+ createDiscordComponentUserSelectControl,
9204
+ createDiscordComponentRoleSelectControl,
9205
+ createDiscordComponentMentionableSelectControl,
9206
+ createDiscordComponentChannelSelectControl
9207
+ ].map((createControl) => (ctx) => createControl(ctx, discordComponentControlHandlers));
9794
9208
  function createDiscordComponentModal(ctx) {
9795
9209
  return new DiscordComponentModal(ctx);
9796
9210
  }
@@ -9835,23 +9249,19 @@ var ExecApprovalButton = class extends Button {
9835
9249
  async run(interaction, data) {
9836
9250
  const parsed = parseExecApprovalData(data);
9837
9251
  if (!parsed) {
9838
- try {
9839
- await interaction.reply({
9840
- content: "This approval is no longer valid.",
9841
- ephemeral: true
9842
- });
9843
- } catch {}
9252
+ await replySilently(interaction, {
9253
+ content: "This approval is no longer valid.",
9254
+ ephemeral: true
9255
+ });
9844
9256
  return;
9845
9257
  }
9846
9258
  const approvers = this.ctx.getApprovers();
9847
9259
  const userId = interaction.userId;
9848
9260
  if (!approvers.some((id) => id === userId)) {
9849
- try {
9850
- await interaction.reply({
9851
- content: "⛔ You are not authorized to approve requests.",
9852
- ephemeral: true
9853
- });
9854
- } catch {}
9261
+ await replySilently(interaction, {
9262
+ content: "⛔ You are not authorized to approve requests.",
9263
+ ephemeral: true
9264
+ });
9855
9265
  return;
9856
9266
  }
9857
9267
  const decisionLabel = parsed.action === "allow-once" ? "Allowed (once)" : parsed.action === "allow-always" ? "Allowed (always)" : "Denied";
@@ -9989,6 +9399,16 @@ function createDiscordQuestionButton(params) {
9989
9399
  //#region extensions/discord/src/monitor/provider.interactions.ts
9990
9400
  function createDiscordProviderInteractionSurface(params) {
9991
9401
  const createNativeCommand = params.createNativeCommand ?? createDiscordNativeCommand;
9402
+ const commandContext = {
9403
+ readPolicy: params.readPolicy,
9404
+ cfg: params.cfg,
9405
+ discordConfig: params.discordConfig,
9406
+ accountId: params.accountId,
9407
+ sessionPrefix: params.sessionPrefix,
9408
+ threadBindings: params.threadBindings,
9409
+ buildContext: params.channelRuntime?.inbound.buildContext,
9410
+ dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9411
+ };
9992
9412
  const commands = params.commandSpecs.map((spec) => {
9993
9413
  if (params.nativeEnabled && params.voiceEnabled && spec.name === DISCORD_VOICE_COMMAND_SPEC.name) return createDiscordVoiceCommand({
9994
9414
  readPolicy: params.readPolicy,
@@ -10001,16 +9421,9 @@ function createDiscordProviderInteractionSurface(params) {
10001
9421
  ephemeralDefault: params.ephemeralDefault
10002
9422
  });
10003
9423
  return createNativeCommand({
10004
- readPolicy: params.readPolicy,
9424
+ ...commandContext,
10005
9425
  command: spec,
10006
- cfg: params.cfg,
10007
- discordConfig: params.discordConfig,
10008
- accountId: params.accountId,
10009
- sessionPrefix: params.sessionPrefix,
10010
- ephemeralDefault: params.ephemeralDefault,
10011
- threadBindings: params.threadBindings,
10012
- buildContext: params.channelRuntime?.inbound.buildContext,
10013
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9426
+ ephemeralDefault: params.ephemeralDefault
10014
9427
  });
10015
9428
  });
10016
9429
  const execApprovalsConfig = params.discordConfig.execApprovals ?? {};
@@ -10035,64 +9448,29 @@ function createDiscordProviderInteractionSurface(params) {
10035
9448
  },
10036
9449
  abortSignal: params.abortSignal
10037
9450
  });
10038
- const components = [
10039
- createDiscordQuestionButton({
10040
- cfg: params.cfg,
10041
- accountId: params.accountId,
10042
- authContext: {
10043
- readPolicy: params.readPolicy,
10044
- cfg: params.cfg,
10045
- accountId: params.accountId,
10046
- discordConfig: params.discordConfig,
10047
- runtime: params.runtime,
10048
- token: params.token,
10049
- guildEntries: params.guildEntries,
10050
- allowFrom: params.allowFrom,
10051
- dmPolicy: params.dmPolicy
10052
- }
10053
- }),
10054
- createDiscordCommandArgFallbackButton({
10055
- readPolicy: params.readPolicy,
10056
- cfg: params.cfg,
10057
- discordConfig: params.discordConfig,
10058
- accountId: params.accountId,
10059
- sessionPrefix: params.sessionPrefix,
10060
- threadBindings: params.threadBindings,
10061
- buildContext: params.channelRuntime?.inbound.buildContext,
10062
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
10063
- }),
10064
- createDiscordModelPickerFallbackButton({
10065
- readPolicy: params.readPolicy,
10066
- cfg: params.cfg,
10067
- discordConfig: params.discordConfig,
10068
- accountId: params.accountId,
10069
- sessionPrefix: params.sessionPrefix,
10070
- threadBindings: params.threadBindings,
10071
- buildContext: params.channelRuntime?.inbound.buildContext,
10072
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
10073
- }),
10074
- createDiscordModelPickerFallbackSelect({
10075
- readPolicy: params.readPolicy,
10076
- cfg: params.cfg,
10077
- discordConfig: params.discordConfig,
10078
- accountId: params.accountId,
10079
- sessionPrefix: params.sessionPrefix,
10080
- threadBindings: params.threadBindings,
10081
- buildContext: params.channelRuntime?.inbound.buildContext,
10082
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
10083
- })
10084
- ];
10085
- const activityButton = createDiscordActivityButton({
9451
+ const componentContext = {
10086
9452
  readPolicy: params.readPolicy,
10087
9453
  cfg: params.cfg,
10088
- discordConfig: params.discordConfig,
10089
9454
  accountId: params.accountId,
9455
+ discordConfig: params.discordConfig,
9456
+ runtime: params.runtime,
9457
+ token: params.token,
10090
9458
  guildEntries: params.guildEntries,
10091
9459
  allowFrom: params.allowFrom,
10092
- dmPolicy: params.dmPolicy,
10093
- runtime: params.runtime,
10094
- channelRuntime: params.channelRuntime,
10095
- token: params.token
9460
+ dmPolicy: params.dmPolicy
9461
+ };
9462
+ const components = [createDiscordQuestionButton({
9463
+ cfg: params.cfg,
9464
+ accountId: params.accountId,
9465
+ authContext: componentContext
9466
+ }), ...[
9467
+ createDiscordCommandArgFallbackButton,
9468
+ createDiscordModelPickerFallbackButton,
9469
+ createDiscordModelPickerFallbackSelect
9470
+ ].map((create) => create(commandContext))];
9471
+ const activityButton = createDiscordActivityButton({
9472
+ ...componentContext,
9473
+ channelRuntime: params.channelRuntime
10096
9474
  }, params.applicationId);
10097
9475
  if (activityButton) components.push(activityButton);
10098
9476
  const modals = [];
@@ -10102,17 +9480,6 @@ function createDiscordProviderInteractionSurface(params) {
10102
9480
  config: execApprovalsConfig
10103
9481
  })));
10104
9482
  if ((params.discordConfig.agentComponents ?? {}).enabled ?? true) {
10105
- const componentContext = {
10106
- readPolicy: params.readPolicy,
10107
- cfg: params.cfg,
10108
- discordConfig: params.discordConfig,
10109
- accountId: params.accountId,
10110
- guildEntries: params.guildEntries,
10111
- allowFrom: params.allowFrom,
10112
- dmPolicy: params.dmPolicy,
10113
- runtime: params.runtime,
10114
- token: params.token
10115
- };
10116
9483
  components.push(...createAgentComponentControls.map((create) => create(componentContext)));
10117
9484
  components.push(...createDiscordComponentControls.map((create) => create(componentContext)));
10118
9485
  modals.push(createDiscordComponentModal(componentContext));
@@ -10166,11 +9533,7 @@ function resolveDiscordPreflightChannelAccess(params) {
10166
9533
  if (params.isGuildMessage && params.channelConfig?.enabled === false) {
10167
9534
  logDebug(`[discord-preflight] drop: channel disabled`);
10168
9535
  logVerbose(`Blocked discord channel ${params.messageChannelId} (channel disabled, ${params.channelMatchMeta})`);
10169
- return {
10170
- allowed: false,
10171
- channelAllowlistConfigured: false,
10172
- channelAllowed: false
10173
- };
9536
+ return false;
10174
9537
  }
10175
9538
  const groupDmAllowed = params.isGroupDm && resolveGroupDmAllow({
10176
9539
  channels: params.groupDmChannels,
@@ -10178,11 +9541,7 @@ function resolveDiscordPreflightChannelAccess(params) {
10178
9541
  channelName: params.displayChannelName,
10179
9542
  channelSlug: params.displayChannelSlug
10180
9543
  });
10181
- if (params.isGroupDm && !groupDmAllowed) return {
10182
- allowed: false,
10183
- channelAllowlistConfigured: false,
10184
- channelAllowed: false
10185
- };
9544
+ if (params.isGroupDm && !groupDmAllowed) return false;
10186
9545
  const channelAllowlistConfigured = Boolean(params.guildInfo?.channels) && Object.keys(params.guildInfo?.channels ?? {}).length > 0;
10187
9546
  const channelAllowed = params.channelConfig?.allowed !== false;
10188
9547
  if (params.isGuildMessage && !isDiscordGroupAllowedByPolicy({
@@ -10201,30 +9560,18 @@ function resolveDiscordPreflightChannelAccess(params) {
10201
9560
  logDebug(`[discord] Ignored message from channel ${params.messageChannelId} (not in guild allowlist). Add to guilds.<guildId>.channels to enable.`);
10202
9561
  logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${params.channelMatchMeta})`);
10203
9562
  }
10204
- return {
10205
- allowed: false,
10206
- channelAllowlistConfigured,
10207
- channelAllowed
10208
- };
9563
+ return false;
10209
9564
  }
10210
9565
  if (params.isGuildMessage && params.channelConfig?.allowed === false) {
10211
9566
  logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
10212
9567
  logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (${params.channelMatchMeta})`);
10213
- return {
10214
- allowed: false,
10215
- channelAllowlistConfigured,
10216
- channelAllowed
10217
- };
9568
+ return false;
10218
9569
  }
10219
9570
  if (params.isGuildMessage) {
10220
9571
  logDebug(`[discord-preflight] pass: channel allowed`);
10221
9572
  logVerbose(`discord: allow channel ${params.messageChannelId} (${params.channelMatchMeta})`);
10222
9573
  }
10223
- return {
10224
- allowed: true,
10225
- channelAllowlistConfigured,
10226
- channelAllowed
10227
- };
9574
+ return true;
10228
9575
  }
10229
9576
  //#endregion
10230
9577
  //#region extensions/discord/src/monitor/listeners.guild-join.ts
@@ -10281,7 +9628,7 @@ var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
10281
9628
  guildInfo,
10282
9629
  channelConfig,
10283
9630
  channelMatchMeta: `guild=${data.id} channel=${channel.id}`
10284
- }).allowed;
9631
+ });
10285
9632
  if (roomAllowed) {
10286
9633
  targetChannel = channel;
10287
9634
  break;
@@ -10355,11 +9702,7 @@ var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
10355
9702
  //#region extensions/discord/src/monitor/provider.startup.ts
10356
9703
  function registerLatePlugin(client, plugin) {
10357
9704
  plugin.registerClient?.(client);
10358
- plugin.registerRoutes?.(client);
10359
- if (!client.plugins.some((entry) => entry.id === plugin.id)) client.plugins.push({
10360
- id: plugin.id,
10361
- plugin
10362
- });
9705
+ if (!client.plugins.some((entry) => entry.id === plugin.id)) client.plugins.push(plugin);
10363
9706
  }
10364
9707
  function createDiscordStatusReadyListener(params) {
10365
9708
  return new class DiscordStatusReadyListener extends ReadyListener {
@@ -10371,21 +9714,17 @@ function createDiscordStatusReadyListener(params) {
10371
9714
  }
10372
9715
  const gateway = client.getPlugin("gateway");
10373
9716
  if (!gateway) return;
10374
- const presence = resolveDiscordPresenceUpdate(params.discordConfig);
10375
- if (!presence) return;
10376
- gateway.updatePresence(presence);
9717
+ gateway.updatePresence(resolveDiscordPresenceUpdate(params.discordConfig));
10377
9718
  }
10378
9719
  }();
10379
9720
  }
10380
9721
  async function createDiscordMonitorClient(params) {
10381
9722
  let autoPresenceController = null;
10382
- const clientPlugins = [params.createGatewayPlugin({
9723
+ const constructorPlugins = [params.createGatewayPlugin({
10383
9724
  discordConfig: params.discordConfig,
10384
9725
  runtime: params.runtime
10385
9726
  })];
10386
- if (params.voiceEnabled) clientPlugins.push(new VoicePlugin());
10387
- const voicePlugin = clientPlugins.find((plugin) => plugin.id === "voice");
10388
- const constructorPlugins = voicePlugin ? clientPlugins.filter((plugin) => plugin !== voicePlugin) : clientPlugins;
9727
+ const voicePlugin = params.voiceEnabled ? new VoicePlugin() : void 0;
10389
9728
  const eventQueueOpts = {
10390
9729
  listenerTimeout: 12e4,
10391
9730
  slowListenerThreshold: 3e4
@@ -10395,16 +9734,11 @@ async function createDiscordMonitorClient(params) {
10395
9734
  getAutoPresenceController: () => autoPresenceController
10396
9735
  });
10397
9736
  const client = params.createClient({
10398
- baseUrl: "http://localhost",
10399
- deploySecret: "a",
10400
9737
  clientId: params.applicationId,
10401
- publicKey: "a",
10402
9738
  token: params.token,
10403
- autoDeploy: false,
10404
9739
  commandDeployHashStore: params.commandDeployHashStore,
10405
9740
  requestOptions: {
10406
9741
  timeout: DISCORD_REST_TIMEOUT_MS,
10407
- runtimeProfile: "persistent",
10408
9742
  maxQueueSize: 1e3,
10409
9743
  ...params.restFetch ? { fetch: params.restFetch } : {}
10410
9744
  },
@@ -10458,9 +9792,8 @@ async function fetchDiscordBotIdentity(params) {
10458
9792
  params.logStartupPhase("fetch-bot-identity:error", String(err));
10459
9793
  throw new Error("Failed to resolve Discord bot identity", { cause: err });
10460
9794
  }
10461
- const botUserRecord = botUser;
10462
- const botUserId = normalizeOptionalString(botUserRecord?.id);
10463
- const botUserName = normalizeOptionalString(botUserRecord?.username) ?? normalizeOptionalString(botUserRecord?.globalName);
9795
+ const botUserId = normalizeOptionalString(botUser?.id);
9796
+ const botUserName = normalizeOptionalString(botUser?.username) ?? normalizeOptionalString(botUser?.globalName);
10464
9797
  if (!botUserId) {
10465
9798
  const details = "fetchUser(\"@me\") returned no usable id";
10466
9799
  params.runtime.error?.(danger(`discord: failed to fetch bot identity: ${details}`));
@@ -10544,12 +9877,6 @@ function formatDiscordStartupStatusMessage(params) {
10544
9877
  //#endregion
10545
9878
  //#region extensions/discord/src/monitor/provider.ts
10546
9879
  const DEFAULT_DISCORD_MEDIA_MAX_MB = 100;
10547
- function logDiscordStartupPhase(params) {
10548
- logDiscordStartupPhase$1({
10549
- ...params,
10550
- isVerbose: discordProviderRuntime.isVerbose
10551
- });
10552
- }
10553
9880
  const DISCORD_DISALLOWED_INTENTS_CODE = GatewayCloseCodes$1.DisallowedIntents;
10554
9881
  function isDiscordDisallowedIntentsError(err) {
10555
9882
  if (!err) return false;
@@ -10566,6 +9893,16 @@ async function monitorDiscordProvider(opts = {}) {
10566
9893
  const token = normalizeDiscordToken(opts.token ?? void 0, "channels.discord.token") ?? account.token;
10567
9894
  if (!token) throw new Error(`Discord bot token missing for account "${account.accountId}" (set discord.accounts.${account.accountId}.token or DISCORD_BOT_TOKEN for default).`);
10568
9895
  const runtime = opts.runtime ?? createNonExitingRuntime();
9896
+ let lifecycleGateway;
9897
+ const logStartupPhase = (phase, details) => logDiscordStartupPhase({
9898
+ runtime,
9899
+ accountId: account.accountId,
9900
+ phase,
9901
+ startAt: startupStartedAt,
9902
+ gateway: lifecycleGateway,
9903
+ details,
9904
+ isVerbose: discordProviderRuntime.isVerbose
9905
+ });
10569
9906
  const rawDiscordCfg = account.config;
10570
9907
  const discordRestFetch = resolveDiscordRestFetch(rawDiscordCfg.proxy, runtime);
10571
9908
  const dmConfig = rawDiscordCfg.dm;
@@ -10671,12 +10008,7 @@ async function monitorDiscordProvider(opts = {}) {
10671
10008
  threadBindingIdleTimeoutMs,
10672
10009
  threadBindingMaxAgeMs
10673
10010
  });
10674
- logDiscordStartupPhase({
10675
- runtime,
10676
- accountId: account.accountId,
10677
- phase: "fetch-application-id:start",
10678
- startAt: startupStartedAt
10679
- });
10011
+ logStartupPhase("fetch-application-id:start");
10680
10012
  const parsedApplicationId = (typeof discordCfg.applicationId === "string" && discordCfg.applicationId.trim() ? discordCfg.applicationId.trim() : void 0) ?? parseApplicationIdFromToken(token);
10681
10013
  const applicationIdProbe = parsedApplicationId ? {
10682
10014
  kind: "resolved",
@@ -10702,13 +10034,7 @@ async function monitorDiscordProvider(opts = {}) {
10702
10034
  throw new Error(message, { cause: applicationIdProbe.error });
10703
10035
  }
10704
10036
  const applicationId = applicationIdProbe.applicationId;
10705
- logDiscordStartupPhase({
10706
- runtime,
10707
- accountId: account.accountId,
10708
- phase: "fetch-application-id:done",
10709
- startAt: startupStartedAt,
10710
- details: `applicationId=${applicationId}`
10711
- });
10037
+ logStartupPhase("fetch-application-id:done", `applicationId=${applicationId}`);
10712
10038
  const { commandSpecs } = await resolveDiscordProviderCommandSpecs({
10713
10039
  cfg,
10714
10040
  runtime,
@@ -10731,7 +10057,6 @@ async function monitorDiscordProvider(opts = {}) {
10731
10057
  let deactivateMessageHandler;
10732
10058
  let stopMonitorListeners;
10733
10059
  let autoPresenceController = null;
10734
- let lifecycleGateway;
10735
10060
  let earlyGatewayEmitter = gatewaySupervisor?.emitter;
10736
10061
  let onEarlyGatewayDebug;
10737
10062
  try {
@@ -10811,14 +10136,7 @@ async function monitorDiscordProvider(opts = {}) {
10811
10136
  runtime.log?.(`discord startup [${account.accountId}] gateway-debug ${Math.max(0, Date.now() - startupStartedAt)}ms ${String(msg)}`);
10812
10137
  };
10813
10138
  earlyGatewayEmitter?.on("debug", onEarlyGatewayDebug);
10814
- logDiscordStartupPhase({
10815
- runtime,
10816
- accountId: account.accountId,
10817
- phase: "deploy-commands:schedule",
10818
- startAt: startupStartedAt,
10819
- gateway: lifecycleGateway,
10820
- details: `native=${nativeEnabled ? "on" : "off"} reconcile=on commandCount=${commands.length}`
10821
- });
10139
+ logStartupPhase("deploy-commands:schedule", `native=${nativeEnabled ? "on" : "off"} reconcile=on commandCount=${commands.length}`);
10822
10140
  runDiscordCommandDeployInBackground({
10823
10141
  client,
10824
10142
  runtime,
@@ -10834,14 +10152,7 @@ async function monitorDiscordProvider(opts = {}) {
10834
10152
  client,
10835
10153
  token,
10836
10154
  runtime,
10837
- logStartupPhase: (phase, details) => logDiscordStartupPhase({
10838
- runtime,
10839
- accountId: account.accountId,
10840
- phase,
10841
- startAt: startupStartedAt,
10842
- gateway: lifecycleGateway,
10843
- details
10844
- })
10155
+ logStartupPhase
10845
10156
  });
10846
10157
  let voiceManager = null;
10847
10158
  if (voiceEnabled) {
@@ -10918,13 +10229,7 @@ async function monitorDiscordProvider(opts = {}) {
10918
10229
  messageHandler,
10919
10230
  trackInboundEvent
10920
10231
  });
10921
- logDiscordStartupPhase({
10922
- runtime,
10923
- accountId: account.accountId,
10924
- phase: "client-start",
10925
- startAt: startupStartedAt,
10926
- gateway: lifecycleGateway
10927
- });
10232
+ logStartupPhase("client-start");
10928
10233
  const botIdentity = botUserId && botUserName ? `${botUserId} (${botUserName})` : botUserId ?? botUserName ?? "";
10929
10234
  runtime.log?.(formatDiscordStartupStatusMessage({
10930
10235
  gatewayReady: lifecycleGateway?.isConnected === true,
@@ -10963,4 +10268,4 @@ async function monitorDiscordProvider(opts = {}) {
10963
10268
  }
10964
10269
  }
10965
10270
  //#endregion
10966
- export { resolveDiscordTextCommandAccess as S, handleDiscordDmCommandDecision as _, formatDiscordReplySkip as a, registerDiscordListener as b, buildGuildLabel as c, resolveDiscordGatewayIntents as d, waitForDiscordGatewayPluginRegistration as f, createDiscordSupplementalContextAccessChecker as g, buildDiscordInboundAccessContext as h, formatDiscordReplyDeliveryFailure as i, resolveReplyContext as l, buildDiscordGroupSystemPrompt as m, resolveDiscordPreflightChannelAccess as n, sanitizeDiscordFrontChannelReplyPayloads as o, createDiscordNativeCommand as p, deliverDiscordReply as r, buildDirectLabel as s, monitorDiscordProvider as t, createDiscordGatewayPlugin as u, createDiscordLivePolicyReader as v, resolveDiscordDmCommandAccess as x, mapGatewayDispatchData as y };
10271
+ export { resolveDiscordDmCommandAccess as A, buildDiscordGroupSystemPrompt as C, createDiscordLivePolicyReader as D, handleDiscordDmCommandDecision as E, mapGatewayDispatchData as O, createDiscordNativeCommand as S, createDiscordSupplementalContextAccessChecker as T, resolveDiscordVoiceMode as _, formatDiscordReplySkip as a, resolveDiscordGatewayIntents as b, buildGuildLabel as c, MIN_SEGMENT_SECONDS as d, VOICE_CONNECT_READY_TIMEOUT_MS as f, logVoiceVerbose as g, isVoiceChannel as h, formatDiscordReplyDeliveryFailure as i, resolveDiscordTextCommandAccess as j, registerDiscordListener as k, resolveReplyContext as l, isDiscordRealtimeVoiceMode as m, resolveDiscordPreflightChannelAccess as n, sanitizeDiscordFrontChannelReplyPayloads as o, VOICE_RECONNECT_GRACE_MS as p, deliverDiscordReply as r, buildDirectLabel as s, monitorDiscordProvider as t, CAPTURE_FINALIZE_GRACE_MS as u, resolveVoiceTimeoutMs as v, buildDiscordInboundAccessContext as w, waitForDiscordGatewayPluginRegistration as x, createDiscordGatewayPlugin as y };