@openclaw/discord 2026.5.12 → 2026.5.14-beta.1

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 (60) hide show
  1. package/dist/{account-inspect-D7jL5YDH.js → account-inspect-BhtPexBW.js} +1 -1
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-BcwyaFd-.js → accounts-BbRDLOSB.js} +2 -1
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/api.js +11 -11
  6. package/dist/{approval-handler.runtime-S-ircYcz.js → approval-handler.runtime-CWW7pvnT.js} +3 -3
  7. package/dist/{approval-native-Gtqpyfdj.js → approval-native-DBBOuPzt.js} +3 -3
  8. package/dist/{approval-shared-BFnWKSQD.js → approval-shared-DxKO7gfl.js} +1 -1
  9. package/dist/{audit-BliEqCEc.js → audit-CifMTQ4S.js} +3 -3
  10. package/dist/{channel-Bliqi-Qi.js → channel-Di2t5Ef3.js} +13 -13
  11. package/dist/{channel-actions-Cn_K00Vy.js → channel-actions-BfavEEmD.js} +3 -3
  12. package/dist/{channel-actions.runtime-DcsRvPnx.js → channel-actions.runtime-CwAAxp-T.js} +3 -3
  13. package/dist/channel-config-api.js +1 -1
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/{channel.setup-DR-xVYso.js → channel.setup-7et6c1aZ.js} +2 -2
  16. package/dist/{config-schema-D2KGskAp.js → config-schema-DnD91yKG.js} +20 -0
  17. package/dist/contract-api.js +2 -2
  18. package/dist/{directory-config-CDl4JTCA.js → directory-config-BFIM4K7-.js} +1 -1
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-ApUXOSj0.js → directory-live-CdCwhQYI.js} +1 -1
  21. package/dist/{doctor-jcX_qXsS.js → doctor-CpgTyCTh.js} +2 -2
  22. package/dist/{handle-action.guild-admin-C4phin-a.js → handle-action.guild-admin-SEB7Ohbw.js} +1 -1
  23. package/dist/{manager.runtime-DqMGETqp.js → manager.runtime-DWYmpG8O.js} +101 -17
  24. package/dist/{message-handler-DIsnboy2.js → message-handler-Cg5wp_2Y.js} +4 -4
  25. package/dist/{message-handler.preflight-BRH-dv1o.js → message-handler.preflight-B4lZOc7E.js} +18 -7
  26. package/dist/{message-handler.process-Bs5wropA.js → message-handler.process-BuDy-YnE.js} +24 -20
  27. package/dist/{message-utils-ByofKwPe.js → message-utils-m_Trzh54.js} +14 -10
  28. package/dist/{outbound-adapter-lWjkSeyP.js → outbound-adapter-DXtiQgPB.js} +4 -4
  29. package/dist/{provider-DABvNRT0.js → provider-B28t_1YH.js} +13 -13
  30. package/dist/{provider-session.runtime-BZyP90-i.js → provider-session.runtime-DaeQ5NLC.js} +3 -3
  31. package/dist/provider.runtime-6_eQZwab.js +2 -0
  32. package/dist/{reply-delivery-CUSK6SA_.js → reply-delivery-DU6Dm1P4.js} +2 -2
  33. package/dist/{route-resolution-BFfF9xmG.js → route-resolution-DxF6Qn7V.js} +1 -1
  34. package/dist/{runtime-CdnAT8R5.js → runtime-C6dFeIPS.js} +6 -6
  35. package/dist/runtime-api.actions.js +2 -2
  36. package/dist/runtime-api.js +16 -16
  37. package/dist/runtime-api.lookup.js +2 -2
  38. package/dist/runtime-api.monitor-Ba1r1iSI.js +6 -0
  39. package/dist/runtime-api.monitor.js +5 -5
  40. package/dist/runtime-api.send.js +4 -4
  41. package/dist/runtime-api.threads.js +3 -3
  42. package/dist/{send-DCFuSiBi.js → send-DDM8s4P5.js} +3 -3
  43. package/dist/{send.components-DxDqPJZQ.js → send.components-Cidmc-7C.js} +3 -3
  44. package/dist/{send.outbound-PM0J0F60.js → send.outbound-DsgxtI_N.js} +2 -2
  45. package/dist/{send.shared-Dza0jdso.js → send.shared-CnvqNVpX.js} +2 -2
  46. package/dist/setup-plugin-api.js +1 -1
  47. package/dist/{shared-Yp_M6Cfp.js → shared-ljKQIIu9.js} +4 -4
  48. package/dist/{subagent-hooks-CtN-hfXy.js → subagent-hooks-DFS9GrHB.js} +2 -2
  49. package/dist/subagent-hooks-api.js +1 -1
  50. package/dist/{target-resolver-CgJei-kD.js → target-resolver-DklxEM4N.js} +2 -2
  51. package/dist/{targets-DToZUkgV.js → targets-DkUzREzb.js} +1 -1
  52. package/dist/test-api.js +3 -3
  53. package/dist/{thread-bindings-B4of4OmR.js → thread-bindings-qSEjvnb4.js} +3 -3
  54. package/dist/{thread-bindings.discord-api-BAw15EQb.js → thread-bindings.discord-api-BvPFybEu.js} +3 -3
  55. package/dist/{thread-bindings.manager-DNFl10CA.js → thread-bindings.manager-C-LpcekY.js} +2 -2
  56. package/dist/{threading-CLZ3v7-y.js → threading-D9rX0JRU.js} +1 -1
  57. package/openclaw.plugin.json +68 -0
  58. package/package.json +4 -4
  59. package/dist/provider.runtime-Cmv1SFtb.js +0 -2
  60. package/dist/runtime-api.monitor-W_dJ5EQu.js +0 -6
@@ -1,4 +1,4 @@
1
- import { a as mergeDiscordAccountConfig, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId } from "./accounts-BcwyaFd-.js";
1
+ import { a as mergeDiscordAccountConfig, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId } from "./accounts-BbRDLOSB.js";
2
2
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
3
3
  import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -1,4 +1,4 @@
1
- import { t as inspectDiscordAccount } from "./account-inspect-D7jL5YDH.js";
1
+ import { t as inspectDiscordAccount } from "./account-inspect-BhtPexBW.js";
2
2
  //#region extensions/discord/account-inspect-api.ts
3
3
  function inspectDiscordReadOnlyAccount(cfg, accountId) {
4
4
  return inspectDiscordAccount({
@@ -15,7 +15,8 @@ function mergeDiscordAccountConfig(cfg, accountId) {
15
15
  return resolveMergedAccountConfig({
16
16
  channelConfig: cfg.channels?.discord,
17
17
  accounts: cfg.channels?.discord?.accounts,
18
- accountId
18
+ accountId,
19
+ nestedObjectKeys: ["botLoopProtection"]
19
20
  });
20
21
  }
21
22
  function resolveDiscordAccountAllowFrom(params) {
@@ -1,2 +1,2 @@
1
- import { t as handleDiscordAction } from "./runtime-CdnAT8R5.js";
1
+ import { t as handleDiscordAction } from "./runtime-C6dFeIPS.js";
2
2
  export { handleDiscordAction };
package/dist/api.js CHANGED
@@ -1,25 +1,25 @@
1
- import { a as mergeDiscordAccountConfig, f as resolveDiscordMaxLinesPerMessage, i as listEnabledDiscordAccounts, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId, r as listDiscordAccountIds, s as resolveDiscordAccount, t as createDiscordActionGate } from "./accounts-BcwyaFd-.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-D7jL5YDH.js";
1
+ import { a as mergeDiscordAccountConfig, f as resolveDiscordMaxLinesPerMessage, i as listEnabledDiscordAccounts, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId, r as listDiscordAccountIds, s as resolveDiscordAccount, t as createDiscordActionGate } from "./accounts-BbRDLOSB.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-BhtPexBW.js";
3
3
  import { n as resolveDiscordChannelId, t as parseDiscordTarget } from "./target-parsing-D-H7nnh2.js";
4
4
  import { n as fetchDiscord, r as requestDiscord, t as DiscordApiError } from "./api-DzNBVTto.js";
5
5
  import { i as normalizeDiscordOutboundTarget, n as looksLikeDiscordTargetId, r as normalizeDiscordMessagingTarget } from "./normalize-Cu94FOqy.js";
6
- import { i as parseDiscordSendTarget, n as resolveDiscordTarget } from "./target-resolver-CgJei-kD.js";
6
+ import { i as parseDiscordSendTarget, n as resolveDiscordTarget } from "./target-resolver-DklxEM4N.js";
7
7
  import { _ as parseDiscordModalCustomIdForInteraction, a as buildDiscordComponentMessage, c as readDiscordComponentSpec, d as DISCORD_MODAL_CUSTOM_ID_KEY, f as buildDiscordComponentCustomId, g as parseDiscordModalCustomId, h as parseDiscordComponentCustomIdForInteraction, i as createDiscordFormModal, l as resolveDiscordComponentAttachmentName, m as parseDiscordComponentCustomId, n as formatDiscordComponentEventText, o as buildDiscordComponentMessageFlags, p as buildDiscordModalCustomId, r as DiscordFormModal, s as DISCORD_COMPONENT_ATTACHMENT_PREFIX, u as DISCORD_COMPONENT_CUSTOM_ID_KEY } from "./components-Dxq2mU57.js";
8
8
  import { t as buildDiscordInteractiveComponents } from "./shared-interactive-DavY6jYt.js";
9
- import "./targets-DToZUkgV.js";
10
- import { a as shouldSuppressLocalDiscordExecApprovalPrompt, i as isDiscordExecApprovalClientEnabled, n as getDiscordExecApprovalApprovers, r as isDiscordExecApprovalApprover } from "./approval-shared-BFnWKSQD.js";
11
- import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-Bliqi-Qi.js";
9
+ import "./targets-DkUzREzb.js";
10
+ import { a as shouldSuppressLocalDiscordExecApprovalPrompt, i as isDiscordExecApprovalClientEnabled, n as getDiscordExecApprovalApprovers, r as isDiscordExecApprovalApprover } from "./approval-shared-DxKO7gfl.js";
11
+ import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-Di2t5Ef3.js";
12
12
  import { t as normalizeExplicitDiscordSessionKey } from "./session-key-normalization-BV82IME9.js";
13
- import { t as discordSetupPlugin } from "./channel.setup-DR-xVYso.js";
14
- import { n as handleDiscordSubagentEnded, r as handleDiscordSubagentSpawning, t as handleDiscordSubagentDeliveryTarget } from "./subagent-hooks-CtN-hfXy.js";
15
- import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-C4phin-a.js";
16
- import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-CDl4JTCA.js";
13
+ import { t as discordSetupPlugin } from "./channel.setup-7et6c1aZ.js";
14
+ import { n as handleDiscordSubagentEnded, r as handleDiscordSubagentSpawning, t as handleDiscordSubagentDeliveryTarget } from "./subagent-hooks-DFS9GrHB.js";
15
+ import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-SEB7Ohbw.js";
16
+ import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BFIM4K7-.js";
17
17
  import { t as fetchPluralKitMessageInfo } from "./pluralkit-B1HTaBc9.js";
18
18
  import { a as resolveDiscordPrivilegedIntentsFromFlags, i as probeDiscord, n as fetchDiscordApplicationSummary, r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-BZtr8qle.js";
19
19
  import { t as collectDiscordSecurityAuditFindings } from "./security-audit-BQ_sGK3J.js";
20
20
  import { a as mergeAbortSignals, i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C3FYXWJX.js";
21
21
  import { resolveOpenProviderRuntimeGroupPolicy as resolveDiscordRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
22
22
  //#region extensions/discord/api.ts
23
- const handleDiscordMessageAction = async (...args) => (await import("./channel-actions.runtime-DcsRvPnx.js")).handleDiscordMessageAction(...args);
23
+ const handleDiscordMessageAction = async (...args) => (await import("./channel-actions.runtime-CwAAxp-T.js")).handleDiscordMessageAction(...args);
24
24
  //#endregion
25
25
  export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_COMPONENT_ATTACHMENT_PREFIX, DISCORD_COMPONENT_CUSTOM_ID_KEY, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, DISCORD_MODAL_CUSTOM_ID_KEY, DiscordApiError, DiscordFormModal, buildDiscordComponentCustomId, buildDiscordComponentMessage, buildDiscordComponentMessageFlags, buildDiscordInteractiveComponents, buildDiscordModalCustomId, collectDiscordSecurityAuditFindings, collectDiscordStatusIssues, createDiscordActionGate, createDiscordFormModal, discordPlugin, discordSetupPlugin, fetchDiscord, fetchDiscordApplicationId, fetchDiscordApplicationSummary, fetchPluralKitMessageInfo, formatDiscordComponentEventText, getDiscordExecApprovalApprovers, handleDiscordMessageAction, handleDiscordSubagentDeliveryTarget, handleDiscordSubagentEnded, handleDiscordSubagentSpawning, inspectDiscordAccount, isDiscordExecApprovalApprover, isDiscordExecApprovalClientEnabled, listDiscordAccountIds, listDiscordDirectoryGroupsFromConfig, listDiscordDirectoryPeersFromConfig, listEnabledDiscordAccounts, looksLikeDiscordTargetId, mergeAbortSignals, mergeDiscordAccountConfig, normalizeDiscordMessagingTarget, normalizeDiscordOutboundTarget, normalizeExplicitDiscordSessionKey, parseApplicationIdFromToken, parseDiscordComponentCustomId, parseDiscordComponentCustomIdForInteraction as parseDiscordComponentCustomIdForCarbon, parseDiscordComponentCustomIdForInteraction, parseDiscordModalCustomId, parseDiscordModalCustomIdForInteraction as parseDiscordModalCustomIdForCarbon, parseDiscordModalCustomIdForInteraction, parseDiscordSendTarget, parseDiscordTarget, probeDiscord, readDiscordComponentSpec, requestDiscord, resolveDefaultDiscordAccountId, resolveDiscordAccount, resolveDiscordAccountConfig, resolveDiscordChannelId, resolveDiscordComponentAttachmentName, resolveDiscordGroupRequireMention, resolveDiscordGroupToolPolicy, resolveDiscordMaxLinesPerMessage, resolveDiscordPrivilegedIntentsFromFlags, resolveDiscordRuntimeGroupPolicy, resolveDiscordTarget, shouldSuppressLocalDiscordExecApprovalPrompt, tryHandleDiscordMessageActionGuildAdmin };
@@ -1,7 +1,7 @@
1
1
  import { Ft as __exportAll, N as Container, T as serializePayload, U as TextDisplay, V as Separator, Y as createUserDmChannel, at as editChannelMessage, et as createChannelMessage, j as Button, rt as deleteChannelMessage, z as Row } from "./discord-BqYcwxvG.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-D7jL5YDH.js";
3
- import { A as createDiscordClient, y as stripUndefinedFields } from "./send.shared-Dza0jdso.js";
4
- import { i as isDiscordExecApprovalClientEnabled, t as shouldHandleDiscordApprovalRequest } from "./approval-shared-BFnWKSQD.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-BhtPexBW.js";
3
+ import { A as createDiscordClient, y as stripUndefinedFields } from "./send.shared-CnvqNVpX.js";
4
+ import { i as isDiscordExecApprovalClientEnabled, t as shouldHandleDiscordApprovalRequest } from "./approval-shared-DxKO7gfl.js";
5
5
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { ButtonStyle } from "discord-api-types/v10";
7
7
  import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
@@ -1,5 +1,5 @@
1
- import { r as listDiscordAccountIds, s as resolveDiscordAccount } from "./accounts-BcwyaFd-.js";
2
- import { c as createChannelNativeOriginTargetResolver, i as isDiscordExecApprovalClientEnabled, n as getDiscordExecApprovalApprovers, o as createApproverRestrictedNativeApprovalCapability, r as isDiscordExecApprovalApprover, s as createChannelApproverDmTargetResolver, t as shouldHandleDiscordApprovalRequest } from "./approval-shared-BFnWKSQD.js";
1
+ import { r as listDiscordAccountIds, s as resolveDiscordAccount } from "./accounts-BbRDLOSB.js";
2
+ import { c as createChannelNativeOriginTargetResolver, i as isDiscordExecApprovalClientEnabled, n as getDiscordExecApprovalApprovers, o as createApproverRestrictedNativeApprovalCapability, r as isDiscordExecApprovalApprover, s as createChannelApproverDmTargetResolver, t as shouldHandleDiscordApprovalRequest } from "./approval-shared-DxKO7gfl.js";
3
3
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
5
5
  import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
@@ -140,7 +140,7 @@ function createDiscordApprovalCapability(configOverride) {
140
140
  request,
141
141
  configOverride
142
142
  }),
143
- load: async () => (await import("./approval-handler.runtime-S-ircYcz.js").then((n) => n.t)).discordApprovalNativeRuntime
143
+ load: async () => (await import("./approval-handler.runtime-CWW7pvnT.js").then((n) => n.t)).discordApprovalNativeRuntime
144
144
  })
145
145
  });
146
146
  }
@@ -1,4 +1,4 @@
1
- import { s as resolveDiscordAccount } from "./accounts-BcwyaFd-.js";
1
+ import { s as resolveDiscordAccount } from "./accounts-BbRDLOSB.js";
2
2
  import { t as parseDiscordTarget } from "./target-parsing-D-H7nnh2.js";
3
3
  import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, doesApprovalRequestMatchChannelAccount } from "openclaw/plugin-sdk/approval-native-runtime";
4
4
  import { getExecApprovalReplyMetadata, isChannelExecApprovalClientEnabledFromConfig, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
@@ -1,7 +1,7 @@
1
1
  import { Ft as __exportAll } from "./discord-BqYcwxvG.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-D7jL5YDH.js";
3
- import { T as fetchChannelPermissionsDiscord } from "./send.shared-Dza0jdso.js";
4
- import "./send-DCFuSiBi.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-BhtPexBW.js";
3
+ import { T as fetchChannelPermissionsDiscord } from "./send.shared-CnvqNVpX.js";
4
+ import "./send-DDM8s4P5.js";
5
5
  import { n as collectDiscordAuditChannelIdsForAccount, t as auditDiscordChannelPermissionsWithFetcher } from "./audit-core-BgDZSkIR.js";
6
6
  //#region extensions/discord/src/audit.ts
7
7
  var audit_exports = /* @__PURE__ */ __exportAll({
@@ -1,17 +1,17 @@
1
- import { c as resolveDiscordAccountAllowFrom, r as listDiscordAccountIds, s as resolveDiscordAccount } from "./accounts-BcwyaFd-.js";
1
+ import { c as resolveDiscordAccountAllowFrom, r as listDiscordAccountIds, s as resolveDiscordAccount } from "./accounts-BbRDLOSB.js";
2
2
  import { a as projectCredentialSnapshotFields, n as PAIRING_APPROVED_MESSAGE, o as resolveConfiguredFromCredentialStatuses, r as buildTokenChannelStatusSummary, t as DEFAULT_ACCOUNT_ID } from "./channel-api-CTSWMrnD.js";
3
3
  import { t as parseDiscordTarget } from "./target-parsing-D-H7nnh2.js";
4
4
  import { t as resolveDiscordOutboundSessionRoute } from "./outbound-session-route-BaJRt05p.js";
5
5
  import { n as looksLikeDiscordTargetId, r as normalizeDiscordMessagingTarget } from "./normalize-Cu94FOqy.js";
6
6
  import { t as getDiscordRuntime } from "./runtime-BqCoo-zp.js";
7
- import { a as shouldSuppressLocalDiscordExecApprovalPrompt } from "./approval-shared-BFnWKSQD.js";
8
- import { t as getDiscordApprovalCapability } from "./approval-native-Gtqpyfdj.js";
7
+ import { a as shouldSuppressLocalDiscordExecApprovalPrompt } from "./approval-shared-DxKO7gfl.js";
8
+ import { t as getDiscordApprovalCapability } from "./approval-native-DBBOuPzt.js";
9
9
  import { r as resolveRequiredDiscordChannelPermissions } from "./audit-core-BgDZSkIR.js";
10
- import { t as discordMessageActions$1 } from "./channel-actions-Cn_K00Vy.js";
10
+ import { t as discordMessageActions$1 } from "./channel-actions-BfavEEmD.js";
11
11
  import { n as resolveDiscordCurrentConversationIdentity } from "./conversation-identity-CvIx6J7M.js";
12
12
  import { n as setThreadBindingMaxAgeBySessionKey, t as setThreadBindingIdleTimeoutBySessionKey } from "./thread-bindings.session-updates-D18cCLmN.js";
13
- import { n as discordOutbound } from "./outbound-adapter-lWjkSeyP.js";
14
- import { i as discordSecurityAdapter, n as discordConfigAdapter, r as discordSetupAdapter, t as createDiscordPluginBase } from "./shared-Yp_M6Cfp.js";
13
+ import { n as discordOutbound } from "./outbound-adapter-DXtiQgPB.js";
14
+ import { i as discordSecurityAdapter, n as discordConfigAdapter, r as discordSetupAdapter, t as createDiscordPluginBase } from "./shared-ljKQIIu9.js";
15
15
  import { t as normalizeExplicitDiscordSessionKey } from "./session-key-normalization-BV82IME9.js";
16
16
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
17
17
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
@@ -129,13 +129,13 @@ let discordProbeRuntimePromise;
129
129
  let discordAuditModulePromise;
130
130
  let discordSendModulePromise;
131
131
  let discordDirectoryLiveModulePromise;
132
- const loadDiscordDirectoryConfigModule = createLazyRuntimeModule(() => import("./directory-config-CDl4JTCA.js").then((n) => n.t));
132
+ const loadDiscordDirectoryConfigModule = createLazyRuntimeModule(() => import("./directory-config-BFIM4K7-.js").then((n) => n.t));
133
133
  const loadDiscordResolveChannelsModule = createLazyRuntimeModule(() => import("./resolve-channels-JNt3Ak6P.js").then((n) => n.n));
134
134
  const loadDiscordResolveUsersModule = createLazyRuntimeModule(() => import("./resolve-users-CrjbUxrL.js").then((n) => n.n));
135
- const loadDiscordThreadBindingsManagerModule = createLazyRuntimeModule(() => import("./thread-bindings.manager-DNFl10CA.js").then((n) => n.a));
136
- const loadDiscordTargetResolverModule = createLazyRuntimeModule(() => import("./target-resolver-CgJei-kD.js").then((n) => n.r));
135
+ const loadDiscordThreadBindingsManagerModule = createLazyRuntimeModule(() => import("./thread-bindings.manager-C-LpcekY.js").then((n) => n.a));
136
+ const loadDiscordTargetResolverModule = createLazyRuntimeModule(() => import("./target-resolver-DklxEM4N.js").then((n) => n.r));
137
137
  async function loadDiscordProviderRuntime() {
138
- discordProviderRuntimePromise ??= import("./provider.runtime-Cmv1SFtb.js");
138
+ discordProviderRuntimePromise ??= import("./provider.runtime-6_eQZwab.js");
139
139
  return await discordProviderRuntimePromise;
140
140
  }
141
141
  async function loadDiscordProbeRuntime() {
@@ -143,15 +143,15 @@ async function loadDiscordProbeRuntime() {
143
143
  return await discordProbeRuntimePromise;
144
144
  }
145
145
  async function loadDiscordAuditModule() {
146
- discordAuditModulePromise ??= import("./audit-BliEqCEc.js").then((n) => n.n);
146
+ discordAuditModulePromise ??= import("./audit-CifMTQ4S.js").then((n) => n.n);
147
147
  return await discordAuditModulePromise;
148
148
  }
149
149
  async function loadDiscordSendModule() {
150
- discordSendModulePromise ??= import("./send-DCFuSiBi.js").then((n) => n.t);
150
+ discordSendModulePromise ??= import("./send-DDM8s4P5.js").then((n) => n.t);
151
151
  return await discordSendModulePromise;
152
152
  }
153
153
  async function loadDiscordDirectoryLiveModule() {
154
- discordDirectoryLiveModulePromise ??= import("./directory-live-ApUXOSj0.js").then((n) => n.t);
154
+ discordDirectoryLiveModulePromise ??= import("./directory-live-CdCwhQYI.js").then((n) => n.t);
155
155
  return await discordDirectoryLiveModulePromise;
156
156
  }
157
157
  //#endregion
@@ -1,5 +1,5 @@
1
- import { r as listDiscordAccountIds, t as createDiscordActionGate } from "./accounts-BcwyaFd-.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-D7jL5YDH.js";
1
+ import { r as listDiscordAccountIds, t as createDiscordActionGate } from "./accounts-BbRDLOSB.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-BhtPexBW.js";
3
3
  import { c as readDiscordComponentSpec } from "./components-Dxq2mU57.js";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { createUnionActionGate } from "openclaw/plugin-sdk/channel-actions";
@@ -7,7 +7,7 @@ import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
7
7
  //#region extensions/discord/src/channel-actions.ts
8
8
  let discordChannelActionsRuntimePromise;
9
9
  async function loadDiscordChannelActionsRuntime() {
10
- discordChannelActionsRuntimePromise ??= import("./channel-actions.runtime-DcsRvPnx.js");
10
+ discordChannelActionsRuntimePromise ??= import("./channel-actions.runtime-CwAAxp-T.js");
11
11
  return await discordChannelActionsRuntimePromise;
12
12
  }
13
13
  function listDiscoverableDiscordAccounts(cfg) {
@@ -1,9 +1,9 @@
1
1
  import { n as resolveDiscordChannelId } from "./target-parsing-D-H7nnh2.js";
2
- import { t as handleDiscordAction } from "./runtime-CdnAT8R5.js";
2
+ import { t as handleDiscordAction } from "./runtime-C6dFeIPS.js";
3
3
  import { n as buildDiscordPresentationComponents, t as buildDiscordInteractiveComponents } from "./shared-interactive-DavY6jYt.js";
4
- import "./targets-DToZUkgV.js";
4
+ import "./targets-DkUzREzb.js";
5
5
  import "./action-runtime-api.js";
6
- import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-C4phin-a.js";
6
+ import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-SEB7Ohbw.js";
7
7
  import { normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
9
9
  import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
@@ -1,2 +1,2 @@
1
- import { t as DiscordChannelConfigSchema } from "./config-schema-D2KGskAp.js";
1
+ import { t as DiscordChannelConfigSchema } from "./config-schema-DnD91yKG.js";
2
2
  export { DiscordChannelConfigSchema };
@@ -1,2 +1,2 @@
1
- import { t as discordPlugin } from "./channel-Bliqi-Qi.js";
1
+ import { t as discordPlugin } from "./channel-Di2t5Ef3.js";
2
2
  export { discordPlugin };
@@ -1,6 +1,6 @@
1
1
  import { n as resolveDiscordToken } from "./token-BZtonk7d.js";
2
- import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId } from "./accounts-BcwyaFd-.js";
3
- import { r as discordSetupAdapter, t as createDiscordPluginBase } from "./shared-Yp_M6Cfp.js";
2
+ import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId } from "./accounts-BbRDLOSB.js";
3
+ import { r as discordSetupAdapter, t as createDiscordPluginBase } from "./shared-ljKQIIu9.js";
4
4
  import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-JNt3Ak6P.js";
5
5
  import { t as resolveDiscordUserAllowlist } from "./resolve-users-CrjbUxrL.js";
6
6
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
@@ -311,6 +311,26 @@ const DiscordChannelConfigSchema = buildChannelConfigSchema(DiscordConfigSchema,
311
311
  label: "Discord Allow Bot Messages",
312
312
  help: "Allow bot-authored messages to trigger Discord replies (default: false). Set \"mentions\" to only accept bot messages that mention the bot."
313
313
  },
314
+ botLoopProtection: {
315
+ label: "Discord Bot Loop Protection",
316
+ help: "Sliding-window guard for bot-to-bot Discord loops. Default is enabled whenever allowBots lets bot-authored messages reach dispatch."
317
+ },
318
+ "botLoopProtection.enabled": {
319
+ label: "Discord Bot Loop Protection Enabled",
320
+ help: "Enable the bot-pair loop guard. Defaults to true when allowBots is true or \"mentions\", and false when bot messages are ignored."
321
+ },
322
+ "botLoopProtection.maxEventsPerWindow": {
323
+ label: "Discord Bot Pair Events Per Window",
324
+ help: "Maximum messages a single Discord bot pair may exchange in the configured window before suppression starts. Default: 20."
325
+ },
326
+ "botLoopProtection.windowSeconds": {
327
+ label: "Discord Bot Loop Window Seconds",
328
+ help: "Sliding window length in seconds for Discord bot-pair loop budgets. Default: 60."
329
+ },
330
+ "botLoopProtection.cooldownSeconds": {
331
+ label: "Discord Bot Loop Cooldown Seconds",
332
+ help: "Seconds to suppress a Discord bot pair after it exceeds the loop budget. Default: 60."
333
+ },
314
334
  mentionAliases: {
315
335
  label: "Discord Mention Aliases",
316
336
  help: "Map outbound @handle text to stable Discord user IDs before sending. Set per account via channels.discord.accounts.<id>.mentionAliases."
@@ -2,7 +2,7 @@ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doc
2
2
  import { n as secretTargetRegistryEntries, t as collectRuntimeConfigAssignments } from "./secret-config-contract-BCQNNS7N.js";
3
3
  import { n as unsupportedSecretRefSurfacePatterns, t as collectUnsupportedSecretRefConfigCandidates } from "./security-contract-DkCMKSvb.js";
4
4
  import { t as deriveLegacySessionChatType } from "./session-contract-D871HDFG.js";
5
- import { r as createThreadBindingManager, t as __testing } from "./thread-bindings.manager-DNFl10CA.js";
6
- import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-CDl4JTCA.js";
5
+ import { r as createThreadBindingManager, t as __testing } from "./thread-bindings.manager-C-LpcekY.js";
6
+ import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BFIM4K7-.js";
7
7
  import { t as collectDiscordSecurityAuditFindings } from "./security-audit-BQ_sGK3J.js";
8
8
  export { collectDiscordSecurityAuditFindings, collectRuntimeConfigAssignments, collectUnsupportedSecretRefConfigCandidates, createThreadBindingManager, deriveLegacySessionChatType, __testing as discordThreadBindingTesting, legacyConfigRules, listDiscordDirectoryGroupsFromConfig, listDiscordDirectoryPeersFromConfig, normalizeCompatibilityConfig, secretTargetRegistryEntries, unsupportedSecretRefSurfacePatterns };
@@ -1,5 +1,5 @@
1
1
  import { Ft as __exportAll } from "./discord-BqYcwxvG.js";
2
- import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, o as resolveDefaultDiscordAccountId } from "./accounts-BcwyaFd-.js";
2
+ import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, o as resolveDefaultDiscordAccountId } from "./accounts-BbRDLOSB.js";
3
3
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
4
4
  import { createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-config-runtime";
5
5
  //#region extensions/discord/src/directory-config.ts
@@ -1,2 +1,2 @@
1
- import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-CDl4JTCA.js";
1
+ import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BFIM4K7-.js";
2
2
  export { listDiscordDirectoryGroupsFromConfig, listDiscordDirectoryPeersFromConfig };
@@ -1,6 +1,6 @@
1
1
  import { Ft as __exportAll } from "./discord-BqYcwxvG.js";
2
2
  import { t as normalizeDiscordToken } from "./token-BZtonk7d.js";
3
- import { s as resolveDiscordAccount } from "./accounts-BcwyaFd-.js";
3
+ import { s as resolveDiscordAccount } from "./accounts-BbRDLOSB.js";
4
4
  import { t as rememberDiscordDirectoryUser } from "./directory-cache-Ddl-Oxue.js";
5
5
  import { n as fetchDiscord } from "./api-DzNBVTto.js";
6
6
  import { a as normalizeDiscordSlug } from "./allow-list-n8Ki-Rt3.js";
@@ -1,5 +1,5 @@
1
- import { o as resolveDefaultDiscordAccountId } from "./accounts-BcwyaFd-.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-D7jL5YDH.js";
1
+ import { o as resolveDefaultDiscordAccountId } from "./accounts-BbRDLOSB.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-BhtPexBW.js";
3
3
  import { n as normalizeCompatibilityConfig } from "./doctor-contract-BGjjFBdq.js";
4
4
  import { t as DISCORD_LEGACY_CONFIG_RULES } from "./doctor-shared-D_QLzu30.js";
5
5
  import { t as isDiscordMutableAllowEntry } from "./security-doctor-BJH5YIGL.js";
@@ -1,4 +1,4 @@
1
- import { a as readDiscordChannelCreateParams, n as isDiscordModerationAction, o as readDiscordChannelEditParams, r as readDiscordModerationCommand, s as readDiscordChannelMoveParams, t as handleDiscordAction } from "./runtime-CdnAT8R5.js";
1
+ import { a as readDiscordChannelCreateParams, n as isDiscordModerationAction, o as readDiscordChannelEditParams, r as readDiscordModerationCommand, s as readDiscordChannelMoveParams, t as handleDiscordAction } from "./runtime-C6dFeIPS.js";
2
2
  import "./action-runtime-api.js";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { readNumberParam, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
@@ -1,5 +1,5 @@
1
1
  import { c as ResumedListener, s as ReadyListener, t as discord_exports, u as VoiceStateUpdateListener } from "./discord-BqYcwxvG.js";
2
- import { c as resolveDiscordAccountAllowFrom } from "./accounts-BcwyaFd-.js";
2
+ import { c as resolveDiscordAccountAllowFrom } from "./accounts-BbRDLOSB.js";
3
3
  import { t as parseDiscordTarget } from "./target-parsing-D-H7nnh2.js";
4
4
  import { n as formatDiscordUserTag } from "./format-D8TsaXxW.js";
5
5
  import { a as normalizeDiscordSlug, m as resolveDiscordOwnerAccess } from "./allow-list-n8Ki-Rt3.js";
@@ -245,6 +245,27 @@ function scheduleVoiceCaptureFinalize(params) {
245
245
  });
246
246
  return true;
247
247
  }
248
+ const logger$3 = createSubsystemLogger("discord/voice");
249
+ function summarizeAgentTurnPayloads(payloads) {
250
+ let textPayloads = 0;
251
+ let nonEmptyTextPayloads = 0;
252
+ let reasoningPayloads = 0;
253
+ let errorPayloads = 0;
254
+ let mediaPayloads = 0;
255
+ for (const payload of payloads) {
256
+ if (!payload || typeof payload !== "object") continue;
257
+ const record = payload;
258
+ const text = record.text;
259
+ if (typeof text === "string") {
260
+ textPayloads += 1;
261
+ if (text.trim()) nonEmptyTextPayloads += 1;
262
+ }
263
+ if (record.isReasoning === true) reasoningPayloads += 1;
264
+ if (record.isError === true) errorPayloads += 1;
265
+ if (typeof record.mediaUrl === "string" || Array.isArray(record.mediaUrls) && record.mediaUrls.length > 0) mediaPayloads += 1;
266
+ }
267
+ return `payloadCount=${payloads.length} textPayloads=${textPayloads} nonEmptyTextPayloads=${nonEmptyTextPayloads} reasoningPayloads=${reasoningPayloads} errorPayloads=${errorPayloads} mediaPayloads=${mediaPayloads}`;
268
+ }
248
269
  async function resolveDiscordVoiceIngressContext(params) {
249
270
  const { entry, userId } = params;
250
271
  if (!entry.guildName) entry.guildName = await params.fetchGuildName(entry.guildId);
@@ -286,21 +307,24 @@ async function runDiscordVoiceAgentTurn(params) {
286
307
  });
287
308
  if (!context) return null;
288
309
  const voiceModel = normalizeOptionalString(params.discordConfig.voice?.model);
310
+ const payloads = (await agentCommandFromIngress({
311
+ message: params.message,
312
+ sessionKey: params.entry.route.sessionKey,
313
+ agentId: params.entry.route.agentId,
314
+ messageChannel: "discord",
315
+ messageProvider: "discord-voice",
316
+ extraSystemPrompt: context.extraSystemPrompt,
317
+ senderIsOwner: context.senderIsOwner,
318
+ allowModelOverride: Boolean(voiceModel),
319
+ model: voiceModel,
320
+ toolsAllow: params.toolsAllow,
321
+ deliver: false
322
+ }, params.runtime)).payloads ?? [];
323
+ const text = payloads.map((payload) => payload.text).filter((entry) => typeof entry === "string" && entry.trim()).join("\n").trim();
324
+ if (!text) logger$3.info(`discord voice: agent turn produced no speakable payloads guild=${params.entry.guildId} channel=${params.entry.channelId} voiceSession=${params.entry.voiceSessionKey} supervisorSession=${params.entry.route.sessionKey} agent=${params.entry.route.agentId} user=${params.userId} ${summarizeAgentTurnPayloads(payloads)}`);
289
325
  return {
290
326
  context,
291
- text: ((await agentCommandFromIngress({
292
- message: params.message,
293
- sessionKey: params.entry.route.sessionKey,
294
- agentId: params.entry.route.agentId,
295
- messageChannel: "discord",
296
- messageProvider: "discord-voice",
297
- extraSystemPrompt: context.extraSystemPrompt,
298
- senderIsOwner: context.senderIsOwner,
299
- allowModelOverride: Boolean(voiceModel),
300
- model: voiceModel,
301
- toolsAllow: params.toolsAllow,
302
- deliver: false
303
- }, params.runtime)).payloads ?? []).map((payload) => payload.text).filter((text) => typeof text === "string" && text.trim()).join("\n").trim()
327
+ text
304
328
  };
305
329
  }
306
330
  //#endregion
@@ -356,6 +380,7 @@ const DISCORD_REALTIME_RECENT_AGENT_PROXY_CONSULT_TTL_MS = 15e3;
356
380
  const DISCORD_REALTIME_LOG_PREVIEW_CHARS = 500;
357
381
  const DISCORD_REALTIME_DEFAULT_MIN_BARGE_IN_AUDIO_END_MS = 250;
358
382
  const DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS = 200;
383
+ const DISCORD_REALTIME_DUPLICATE_ERROR_SUPPRESS_MS = 6e4;
359
384
  const REALTIME_PCM16_BYTES_PER_SAMPLE = 2;
360
385
  const DISCORD_REALTIME_FORCED_CONSULT_TRAILING_FRAGMENT_WORDS = new Set([
361
386
  "a",
@@ -603,8 +628,11 @@ var DiscordRealtimeVoiceSession = class {
603
628
  const interruptionLog = formatRealtimeInterruptionLog(event);
604
629
  if (interruptionLog) logger$2.info(interruptionLog);
605
630
  },
606
- onError: (error) => logger$2.warn(`discord voice: realtime error: ${formatErrorMessage(error)}`),
607
- onClose: (reason) => logVoiceVerbose(`realtime closed: ${reason}`)
631
+ onError: (error) => this.logRealtimeError(formatErrorMessage(error)),
632
+ onClose: (reason) => {
633
+ this.flushSuppressedRealtimeErrors();
634
+ logVoiceVerbose(`realtime closed: ${reason}`);
635
+ }
608
636
  });
609
637
  const resolvedModel = readProviderConfigString(resolved.providerConfig, "model") ?? resolved.provider.defaultModel;
610
638
  const resolvedVoice = readProviderConfigString(resolved.providerConfig, "voice");
@@ -619,6 +647,7 @@ var DiscordRealtimeVoiceSession = class {
619
647
  }
620
648
  close() {
621
649
  this.stopped = true;
650
+ this.flushSuppressedRealtimeErrors();
622
651
  this.talkback.close();
623
652
  this.clearForcedConsultTimers();
624
653
  this.pendingAgentProxyConsultContexts = [];
@@ -633,6 +662,25 @@ var DiscordRealtimeVoiceSession = class {
633
662
  const voiceSdk = loadDiscordVoiceSdk();
634
663
  this.params.entry.player.off(voiceSdk.AudioPlayerStatus.Idle, this.playerIdleHandler);
635
664
  }
665
+ logRealtimeError(message) {
666
+ const now = Date.now();
667
+ if (this.lastRealtimeError?.message === message && now - this.lastRealtimeError.lastLoggedAt < DISCORD_REALTIME_DUPLICATE_ERROR_SUPPRESS_MS) {
668
+ this.lastRealtimeError.suppressed += 1;
669
+ return;
670
+ }
671
+ this.flushSuppressedRealtimeErrors();
672
+ this.lastRealtimeError = {
673
+ message,
674
+ suppressed: 0,
675
+ lastLoggedAt: now
676
+ };
677
+ logger$2.warn(`discord voice: realtime error: ${message}`);
678
+ }
679
+ flushSuppressedRealtimeErrors() {
680
+ if (!this.lastRealtimeError || this.lastRealtimeError.suppressed === 0) return;
681
+ logger$2.warn(`discord voice: suppressed ${this.lastRealtimeError.suppressed} duplicate realtime errors: ${this.lastRealtimeError.message}`);
682
+ this.lastRealtimeError.suppressed = 0;
683
+ }
636
684
  beginSpeakerTurn(context, userId) {
637
685
  const turn = {
638
686
  context: {
@@ -1485,6 +1533,15 @@ var DiscordVoiceSpeakerContextResolver = class {
1485
1533
  //#region extensions/discord/src/voice/manager.ts
1486
1534
  const logger = createSubsystemLogger("discord/voice");
1487
1535
  const VOICE_LOG_PREVIEW_CHARS = 500;
1536
+ const DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS = [
1537
+ "api key missing",
1538
+ "incorrect api key",
1539
+ "invalid api key",
1540
+ "unauthorized",
1541
+ "authentication",
1542
+ "permission denied",
1543
+ "forbidden"
1544
+ ];
1488
1545
  function formatVoiceLogPreview(text) {
1489
1546
  const oneLine = text.replace(/\s+/g, " ").trim();
1490
1547
  if (oneLine.length <= VOICE_LOG_PREVIEW_CHARS) return oneLine;
@@ -1524,6 +1581,13 @@ function normalizeVoiceChannelResidencies(entries) {
1524
1581
  function isVoiceChannelAllowed(params) {
1525
1582
  return params.allowedChannels === null || params.allowedChannels.some((entry) => entry.guildId === params.guildId && entry.channelId === params.channelId);
1526
1583
  }
1584
+ function formatAutoJoinFailureKey(entry) {
1585
+ return `${entry.guildId}:${entry.channelId}`;
1586
+ }
1587
+ function isFatalAutoJoinFailure(message) {
1588
+ const normalized = message.toLowerCase();
1589
+ return DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS.some((pattern) => normalized.includes(pattern));
1590
+ }
1527
1591
  function startAutoJoin(manager) {
1528
1592
  manager.autoJoin().catch((err) => logger.warn(`discord voice: autoJoin failed: ${formatErrorMessage(err)}`));
1529
1593
  }
@@ -1570,6 +1634,7 @@ var DiscordVoiceManager$1 = class {
1570
1634
  this.params = params;
1571
1635
  this.sessions = /* @__PURE__ */ new Map();
1572
1636
  this.autoJoinTask = null;
1637
+ this.fatalAutoJoinFailures = /* @__PURE__ */ new Map();
1573
1638
  this.botUserId = params.botUserId;
1574
1639
  this.voiceEnabled = resolveDiscordVoiceEnabled(params.discordConfig.voice);
1575
1640
  this.ownerAllowFrom = resolveDiscordAccountAllowFrom({
@@ -1611,12 +1676,27 @@ var DiscordVoiceManager$1 = class {
1611
1676
  if (selected) logger.warn(`discord voice: autoJoin has multiple entries for guild ${guildId}; using channel ${selected.channelId}`);
1612
1677
  }
1613
1678
  for (const entry of entriesByGuild.values()) {
1679
+ const failureKey = formatAutoJoinFailureKey(entry);
1680
+ const fatalFailure = this.fatalAutoJoinFailures.get(failureKey);
1681
+ if (fatalFailure) {
1682
+ if (!fatalFailure.skipLogged) {
1683
+ logger.warn(`discord voice: autoJoin suppressed guild=${entry.guildId} channel=${entry.channelId} after fatal startup failure; retry with /vc join or reload config after fixing credentials: ${fatalFailure.message}`);
1684
+ fatalFailure.skipLogged = true;
1685
+ }
1686
+ continue;
1687
+ }
1614
1688
  logVoiceVerbose(`autoJoin: joining guild ${entry.guildId} channel ${entry.channelId}`);
1615
1689
  const result = await this.join({
1616
1690
  guildId: entry.guildId,
1617
1691
  channelId: entry.channelId
1618
1692
  });
1619
- if (!result.ok) logger.warn(`discord voice: autoJoin skipped guild=${entry.guildId} channel=${entry.channelId}: ${result.message}`);
1693
+ if (!result.ok) {
1694
+ logger.warn(`discord voice: autoJoin skipped guild=${entry.guildId} channel=${entry.channelId}: ${result.message}`);
1695
+ if (isFatalAutoJoinFailure(result.message)) this.fatalAutoJoinFailures.set(failureKey, {
1696
+ message: result.message,
1697
+ skipLogged: false
1698
+ });
1699
+ }
1620
1700
  }
1621
1701
  })().finally(() => {
1622
1702
  this.autoJoinTask = null;
@@ -1881,6 +1961,10 @@ var DiscordVoiceManager$1 = class {
1881
1961
  connection.on(voiceSdk.VoiceConnectionStatus.Destroyed, destroyedHandler);
1882
1962
  player.on("error", playerErrorHandler);
1883
1963
  this.sessions.set(guildId, entry);
1964
+ this.fatalAutoJoinFailures.delete(formatAutoJoinFailureKey({
1965
+ guildId,
1966
+ channelId
1967
+ }));
1884
1968
  logger.info(`discord voice: joined guild=${guildId} channel=${channelId} mode=${voiceMode} agent=${route.agentId} voiceSession=${voiceRoute.sessionKey} supervisorSession=${route.sessionKey} voiceModel=${voiceConfig?.model ?? "route-default"}`);
1885
1969
  return {
1886
1970
  ok: true,
@@ -1,7 +1,7 @@
1
- import { j as createDiscordRestClient } from "./send.shared-Dza0jdso.js";
1
+ import { j as createDiscordRestClient } from "./send.shared-CnvqNVpX.js";
2
2
  import { a as resolveDiscordChannelParentSafe, n as resolveDiscordChannelInfoSafe, r as resolveDiscordChannelNameSafe, t as resolveDiscordChannelIdSafe } from "./channel-access-BL-wemES.js";
3
3
  import { a as mergeAbortSignals } from "./timeouts-C3FYXWJX.js";
4
- import { l as resolveDiscordMessageChannelId, r as resolveDiscordMessageText, s as hasDiscordMessageStickers } from "./message-utils-ByofKwPe.js";
4
+ import { l as resolveDiscordMessageChannelId, r as resolveDiscordMessageText, s as hasDiscordMessageStickers } from "./message-utils-m_Trzh54.js";
5
5
  import { t as sendTyping } from "./typing-_jePdFIw.js";
6
6
  import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
7
7
  import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
@@ -121,7 +121,7 @@ function applyImplicitReplyBatchGate(ctx, replyToMode, isBatched) {
121
121
  //#region extensions/discord/src/monitor/message-run-queue.ts
122
122
  let messageProcessRuntimePromise;
123
123
  async function loadMessageProcessRuntime() {
124
- messageProcessRuntimePromise ??= import("./message-handler.process-Bs5wropA.js");
124
+ messageProcessRuntimePromise ??= import("./message-handler.process-BuDy-YnE.js");
125
125
  return await messageProcessRuntimePromise;
126
126
  }
127
127
  async function processDiscordQueuedMessage(params) {
@@ -173,7 +173,7 @@ function createDiscordMessageRunQueue(params) {
173
173
  //#region extensions/discord/src/monitor/message-handler.ts
174
174
  let messagePreflightRuntimePromise;
175
175
  async function loadMessagePreflightRuntime() {
176
- messagePreflightRuntimePromise ??= import("./message-handler.preflight-BRH-dv1o.js");
176
+ messagePreflightRuntimePromise ??= import("./message-handler.preflight-B4lZOc7E.js");
177
177
  return await messagePreflightRuntimePromise;
178
178
  }
179
179
  function isNonEmptyString(value) {
@@ -1,13 +1,13 @@
1
1
  import { C as Message, st as getChannelMessage, t as discord_exports } from "./discord-BqYcwxvG.js";
2
- import { o as resolveDefaultDiscordAccountId } from "./accounts-BcwyaFd-.js";
2
+ import { o as resolveDefaultDiscordAccountId } from "./accounts-BbRDLOSB.js";
3
3
  import { i as resolveTimestampMs, n as formatDiscordUserTag, r as resolveDiscordSystemLocation } from "./format-D8TsaXxW.js";
4
4
  import { _ as resolveGroupDmAllow, a as normalizeDiscordSlug, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordGuildEntry, f as resolveDiscordMemberAccessState, g as resolveDiscordShouldRequireMention, i as normalizeDiscordDisplaySlug, n as isDiscordGroupAllowedByPolicy } from "./allow-list-n8Ki-Rt3.js";
5
5
  import { t as resolveDiscordConversationIdentity } from "./conversation-identity-CvIx6J7M.js";
6
6
  import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-SPlv6mh7.js";
7
- import "./thread-bindings-B4of4OmR.js";
7
+ import "./thread-bindings-qSEjvnb4.js";
8
8
  import { n as resolveDiscordChannelInfoSafe, r as resolveDiscordChannelNameSafe } from "./channel-access-BL-wemES.js";
9
- import { a as shouldIgnoreStaleDiscordRouteBinding, c as resolveDiscordTextCommandAccess, i as resolveDiscordEffectiveRoute, o as handleDiscordDmCommandDecision, r as resolveDiscordConversationRoute, s as resolveDiscordDmCommandAccess, t as buildDiscordRoutePeer } from "./route-resolution-BFfF9xmG.js";
10
- import { c as resolveDiscordChannelInfo, l as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-ByofKwPe.js";
9
+ import { a as shouldIgnoreStaleDiscordRouteBinding, c as resolveDiscordTextCommandAccess, i as resolveDiscordEffectiveRoute, o as handleDiscordDmCommandDecision, r as resolveDiscordConversationRoute, s as resolveDiscordDmCommandAccess, t as buildDiscordRoutePeer } from "./route-resolution-DxF6Qn7V.js";
10
+ import { c as resolveDiscordChannelInfo, l as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-m_Trzh54.js";
11
11
  import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-w9rSI-nD.js";
12
12
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
13
  import { getChildLogger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
@@ -28,7 +28,7 @@ async function loadConversationRuntime$1() {
28
28
  return await conversationRuntimePromise$1;
29
29
  }
30
30
  async function loadDiscordSendRuntime() {
31
- discordSendRuntimePromise ??= import("./send-DCFuSiBi.js").then((n) => n.t);
31
+ discordSendRuntimePromise ??= import("./send-DDM8s4P5.js").then((n) => n.t);
32
32
  return await discordSendRuntimePromise;
33
33
  }
34
34
  async function resolveDiscordDmPreflightAccess(params) {
@@ -438,7 +438,7 @@ async function loadSystemEventsRuntime() {
438
438
  return await systemEventsRuntimePromise;
439
439
  }
440
440
  async function loadDiscordThreadingRuntime() {
441
- discordThreadingRuntimePromise ??= import("./threading-CLZ3v7-y.js").then((n) => n.t);
441
+ discordThreadingRuntimePromise ??= import("./threading-D9rX0JRU.js").then((n) => n.t);
442
442
  return await discordThreadingRuntimePromise;
443
443
  }
444
444
  function isPreflightAborted(abortSignal) {
@@ -955,6 +955,16 @@ async function preflightDiscordMessage(params) {
955
955
  return null;
956
956
  }
957
957
  }
958
+ const botLoopProtection = author.bot && !sender.isPluralKit && allowBotsMode !== "off" && params.botUserId && author.id !== params.botUserId ? {
959
+ scopeId: params.accountId,
960
+ conversationId: messageChannelId,
961
+ senderId: author.id,
962
+ receiverId: params.botUserId,
963
+ config: params.discordConfig?.botLoopProtection,
964
+ defaultsConfig: params.cfg.channels?.defaults?.botLoopProtection,
965
+ defaultEnabled: true,
966
+ nowMs: resolveTimestampMs(message.timestamp)
967
+ } : void 0;
958
968
  logDebug(`[discord-preflight] success: route=${effectiveRoute.agentId} sessionKey=${effectiveRoute.sessionKey}`);
959
969
  return buildDiscordMessagePreflightContext({
960
970
  preflightParams: params,
@@ -1001,7 +1011,8 @@ async function preflightDiscordMessage(params) {
1001
1011
  shouldBypassMention: mentionDecision.shouldBypassMention,
1002
1012
  effectiveWasMentioned,
1003
1013
  canDetectMention,
1004
- historyEntry
1014
+ historyEntry,
1015
+ botLoopProtection
1005
1016
  });
1006
1017
  }
1007
1018
  //#endregion