@openclaw/discord 2026.5.31-beta.2 → 2026.5.31-beta.4

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 (69) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{allow-list-BnkWtVpA.js → allow-list-C-MqM-B_.js} +1 -1
  3. package/dist/api.js +12 -12
  4. package/dist/{approval-handler.runtime-DSFfzXpo.js → approval-handler.runtime-DQiJ1Z0k.js} +3 -3
  5. package/dist/{audit-kgIklCyI.js → audit-eI8e8RpG.js} +3 -3
  6. package/dist/{channel-D0gX0yj6.js → channel-W1HBHzdw.js} +20 -20
  7. package/dist/{channel-actions-DDoc4V7x.js → channel-actions-BaPDAWN_.js} +2 -2
  8. package/dist/{channel-actions.runtime-CqZfnMaA.js → channel-actions.runtime-BEMDJjP1.js} +5 -5
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/{channel.setup-BNZm3eed.js → channel.setup-BX7g7pL-.js} +3 -3
  11. package/dist/{components-DcLQ2JkV.js → components-CCbYVuVr.js} +66 -27
  12. package/dist/contract-api.js +3 -3
  13. package/dist/{conversation-identity-BURFgcfI.js → conversation-identity-CEP1KbK0.js} +2 -2
  14. package/dist/{directory-config-B9Jw1Q2R.js → directory-config-j1bfTue_.js} +1 -1
  15. package/dist/directory-contract-api.js +1 -1
  16. package/dist/{directory-live-CDWUg-nA.js → directory-live-BjBs64RV.js} +2 -2
  17. package/dist/{doctor-BUhqxLb9.js → doctor-D3ngpo-Y.js} +2 -2
  18. package/dist/{doctor-contract-BAu3WLvd.js → doctor-contract-CU7lnZTF.js} +2 -2
  19. package/dist/doctor-contract-api.js +1 -1
  20. package/dist/{handle-action.guild-admin-Dpa-kUzu.js → handle-action.guild-admin-CqUsOA2L.js} +3 -3
  21. package/dist/index.js +1 -1
  22. package/dist/legacy-state-migrations-api.js +39 -6
  23. package/dist/{manager.runtime-BWBENHRA.js → manager.runtime-CVB9_dwq.js} +51 -45
  24. package/dist/{message-handler-HO8BbZmQ.js → message-handler-CQGpWQ0f.js} +6 -6
  25. package/dist/{message-handler.preflight-DxHBPQvD.js → message-handler.preflight-B9aZ9jQD.js} +14 -14
  26. package/dist/{message-handler.process-Cq3j7A9k.js → message-handler.process-DrLZOgzG.js} +18 -17
  27. package/dist/{message-utils-D_3KTxh_.js → message-utils-ZTGvA2L8.js} +1 -3
  28. package/dist/{outbound-adapter-BkPkILpq.js → outbound-adapter-Bt6-9M13.js} +6 -6
  29. package/dist/{pluralkit-Ds9aZAM4.js → pluralkit-BEEldePl.js} +1 -1
  30. package/dist/{provider-BK8hjk_y.js → provider-BTp6enEl.js} +53 -96
  31. package/dist/{provider-session.runtime-CYMFlLg9.js → provider-session.runtime-CC2f_W1j.js} +3 -3
  32. package/dist/provider.runtime-DUQJvWin.js +2 -0
  33. package/dist/{resolve-allowlist-common-BIf3417N.js → resolve-allowlist-common-B3p7cT8F.js} +1 -1
  34. package/dist/{resolve-channels-DK-3f_aA.js → resolve-channels-DLNfxFQP.js} +3 -3
  35. package/dist/{resolve-users-DUDPsfWt.js → resolve-users-QTyD8qgI.js} +2 -2
  36. package/dist/{runtime-Blf_d9E7.js → runtime-Dds0Ww1n.js} +8 -8
  37. package/dist/runtime-api.actions.js +2 -2
  38. package/dist/runtime-api.js +21 -21
  39. package/dist/runtime-api.lookup.js +4 -4
  40. package/dist/runtime-api.monitor-BkA-vJZA.js +6 -0
  41. package/dist/runtime-api.monitor.js +5 -5
  42. package/dist/runtime-api.send.js +5 -5
  43. package/dist/runtime-api.threads.js +5 -5
  44. package/dist/{send-BHkA8a-k.js → send-CyyRF1yd.js} +3 -3
  45. package/dist/{send.components-CUHzDapa.js → send.components-a9JQeeH5.js} +4 -4
  46. package/dist/{send.outbound-DSKZbjML.js → send.outbound-DhMLobqR.js} +3 -3
  47. package/dist/{send.receipt-CjsWpitW.js → send.receipt-Z8V6yMOY.js} +38 -11
  48. package/dist/{send.shared-Cluujl6W.js → send.shared-B3QxPnR3.js} +5 -5
  49. package/dist/{sender-identity-BFp5w0F8.js → sender-identity-CEsfDF0L.js} +1 -1
  50. package/dist/setup-plugin-api.js +1 -1
  51. package/dist/{shared-BMGLQw74.js → shared-D11J9bXI.js} +2 -2
  52. package/dist/subagent-hooks-api.js +1 -1
  53. package/dist/{subagent-hooks-7jAn9HT5.js → subagent-hooks-nBcp0iGm.js} +2 -2
  54. package/dist/{system-events-BjuNA9Zs.js → system-events-NnSID6Q5.js} +2 -2
  55. package/dist/{target-resolver-BYuWNVQp.js → target-resolver-BKGK0ftO.js} +2 -2
  56. package/dist/targets-Cv797U29.js +3 -0
  57. package/dist/{thread-bindings-CKruJE91.js → thread-bindings-Tfr_vFxk.js} +6 -6
  58. package/dist/{thread-bindings.discord-api-BjLUwwSP.js → thread-bindings.discord-api-CfDs1lWu.js} +5 -5
  59. package/dist/{thread-bindings.manager-Dji7SZHG.js → thread-bindings.manager-CRc4hYr1.js} +20 -21
  60. package/dist/{thread-bindings.session-updates-DoDFvU_h.js → thread-bindings.session-updates-DeMxmcXB.js} +1 -1
  61. package/dist/{thread-bindings.state-DYp4FVEB.js → thread-bindings.state-CVLF7gJH.js} +48 -22
  62. package/dist/{transcripts-source-O73_YIDs.js → transcripts-source-Cegx0wdw.js} +1 -1
  63. package/dist/transcripts-source-api.js +1 -1
  64. package/dist/{typing-CKW0i8du.js → typing-C7RXECnL.js} +1 -1
  65. package/npm-shrinkwrap.json +3 -3
  66. package/package.json +4 -4
  67. package/dist/provider.runtime-RfQSSM_v.js +0 -2
  68. package/dist/runtime-api.monitor-LVbgPRHA.js +0 -6
  69. package/dist/targets-BNDUOdvI.js +0 -3
@@ -1,7 +1,7 @@
1
- import { At as getGuildMember, Bt as removeGuildMemberRole, C as readDiscordCode, Ct as createGuildBan, Dt as createGuildSticker, Et as createGuildScheduledEvent, Ft as listGuildRoles, It as listGuildScheduledEvents, Lt as moveGuildChannels, Mt as listGuildActiveThreads, Nt as listGuildChannels, Ot as deleteChannelPermission, Pt as listGuildEmojis, Rt as putChannelPermission, S as RateLimitError, St as addGuildMemberRole, T as readRetryAfter, Tt as createGuildEmoji, Vt as timeoutGuildMember, Wt as __exportAll, _t as listChannelPins, at as deleteOwnMessageReaction, bt as sendChannelTyping, ct as createThread, dt as editChannel, ft as editChannelMessage, gt as listChannelMessages, ht as listChannelArchivedThreads, it as createOwnMessageReaction, jt as getGuildVoiceState, kt as getGuild, lt as deleteChannel, mt as getChannelMessage, n as createDiscordSendResult, ot as listMessageReactionUsers, pt as getChannel, st as createChannelMessage, ut as deleteChannelMessage, vt as pinChannelMessage, w as readDiscordMessage, wt as createGuildChannel, x as DiscordError, xt as unpinChannelMessage, yt as searchGuildMessages, zt as removeGuildMember } from "./send.receipt-CjsWpitW.js";
1
+ import { At as getGuildMember, Bt as removeGuildMemberRole, C as readDiscordCode, Ct as createGuildBan, Dt as createGuildSticker, Et as createGuildScheduledEvent, Ft as listGuildRoles, It as listGuildScheduledEvents, Lt as moveGuildChannels, Mt as listGuildActiveThreads, Nt as listGuildChannels, Ot as deleteChannelPermission, Pt as listGuildEmojis, Rt as putChannelPermission, S as RateLimitError, St as addGuildMemberRole, T as readRetryAfter, Tt as createGuildEmoji, Vt as timeoutGuildMember, Wt as __exportAll, _t as listChannelPins, at as deleteOwnMessageReaction, bt as sendChannelTyping, ct as createThread, dt as editChannel, ft as editChannelMessage, gt as listChannelMessages, ht as listChannelArchivedThreads, it as createOwnMessageReaction, jt as getGuildVoiceState, kt as getGuild, lt as deleteChannel, mt as getChannelMessage, n as createDiscordSendResult, ot as listMessageReactionUsers, pt as getChannel, st as createChannelMessage, ut as deleteChannelMessage, vt as pinChannelMessage, w as readDiscordMessage, wt as createGuildChannel, x as DiscordError, xt as unpinChannelMessage, yt as searchGuildMessages, zt as removeGuildMember } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { s as resolveDiscordAccount } from "./accounts-P19jm1lf.js";
3
- import { A as hasAllGuildPermissionsDiscord, C as DISCORD_MAX_STICKER_BYTES, D as canViewDiscordGuildChannel, E as canManageGuildRoleDiscord, F as createDiscordClient, M as hasAnyGuildPermissionDiscord, O as fetchChannelPermissionsDiscord, P as parseAndResolveChannelRecipient, R as resolveDiscordClientAccountContext, S as DISCORD_MAX_EVENT_COVER_BYTES, T as canManageGuildMemberRoleDiscord, i as formatReactionEmoji, j as hasAnyChannelPermissionDiscord, k as fetchMemberGuildPermissionsDiscord, l as resolveChannelId, o as normalizeEmojiName, r as buildReactionIdentifier, s as normalizeReactionEmoji, t as buildDiscordSendError, w as DiscordSendError, x as DISCORD_MAX_EMOJI_BYTES, z as resolveDiscordRest } from "./send.shared-Cluujl6W.js";
4
- import { n as sendPollDiscord, r as sendStickerDiscord, s as rewriteDiscordKnownMentions, t as sendMessageDiscord } from "./send.outbound-DSKZbjML.js";
3
+ import { A as hasAllGuildPermissionsDiscord, C as DISCORD_MAX_STICKER_BYTES, D as canViewDiscordGuildChannel, E as canManageGuildRoleDiscord, F as createDiscordClient, M as hasAnyGuildPermissionDiscord, O as fetchChannelPermissionsDiscord, P as parseAndResolveChannelRecipient, R as resolveDiscordClientAccountContext, S as DISCORD_MAX_EVENT_COVER_BYTES, T as canManageGuildMemberRoleDiscord, i as formatReactionEmoji, j as hasAnyChannelPermissionDiscord, k as fetchMemberGuildPermissionsDiscord, l as resolveChannelId, o as normalizeEmojiName, r as buildReactionIdentifier, s as normalizeReactionEmoji, t as buildDiscordSendError, w as DiscordSendError, x as DISCORD_MAX_EMOJI_BYTES, z as resolveDiscordRest } from "./send.shared-B3QxPnR3.js";
4
+ import { n as sendPollDiscord, r as sendStickerDiscord, s as rewriteDiscordKnownMentions, t as sendMessageDiscord } from "./send.outbound-DhMLobqR.js";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { ChannelType } from "discord-api-types/v10";
7
7
  import { parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
@@ -1,10 +1,10 @@
1
- import { Wt as __exportAll, ft as editChannelMessage, j as serializePayload, n as createDiscordSendResult, st as createChannelMessage } from "./send.receipt-CjsWpitW.js";
1
+ import { Wt as __exportAll, ft as editChannelMessage, j as serializePayload, n as createDiscordSendResult, st as createChannelMessage } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { s as resolveDiscordAccount } from "./accounts-P19jm1lf.js";
3
3
  import "./config-api-JiPdJeb0.js";
4
4
  import "./channel-api-CAJ0wMoV.js";
5
- import { c as buildDiscordComponentMessage, f as resolveDiscordComponentAttachmentName, l as buildDiscordComponentMessageFlags } from "./components-DcLQ2JkV.js";
6
- import { F as createDiscordClient, P as parseAndResolveChannelRecipient, b as stripUndefinedFields, h as SUPPRESS_NOTIFICATIONS_FLAG, l as resolveChannelId, m as toDiscordFileBlob, t as buildDiscordSendError, u as resolveDiscordChannelType } from "./send.shared-Cluujl6W.js";
7
- import { t as sendMessageDiscord } from "./send.outbound-DSKZbjML.js";
5
+ import { c as buildDiscordComponentMessage, f as resolveDiscordComponentAttachmentName, l as buildDiscordComponentMessageFlags } from "./components-CCbYVuVr.js";
6
+ import { F as createDiscordClient, P as parseAndResolveChannelRecipient, b as stripUndefinedFields, h as SUPPRESS_NOTIFICATIONS_FLAG, l as resolveChannelId, m as toDiscordFileBlob, t as buildDiscordSendError, u as resolveDiscordChannelType } from "./send.shared-B3QxPnR3.js";
7
+ import { t as sendMessageDiscord } from "./send.outbound-DhMLobqR.js";
8
8
  import { n as getOptionalDiscordRuntime } from "./runtime-DgnVQ7zW.js";
9
9
  import "openclaw/plugin-sdk/account-id";
10
10
  import "openclaw/plugin-sdk/secret-input";
@@ -1,7 +1,7 @@
1
- import { ct as createThread, n as createDiscordSendResult, st as createChannelMessage } from "./send.receipt-CjsWpitW.js";
1
+ import { ct as createThread, n as createDiscordSendResult, st as createChannelMessage } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { s as resolveDiscordAccount } from "./accounts-P19jm1lf.js";
3
- import { F as createDiscordClient, P as parseAndResolveChannelRecipient, _ as resolveDiscordMessageFlags, a as normalizeDiscordPollInput, c as normalizeStickerIds, f as sendDiscordMedia, g as buildDiscordMessageRequest, l as resolveChannelId, n as buildDiscordTextChunks, p as sendDiscordText, t as buildDiscordSendError, u as resolveDiscordChannelType, v as resolveDiscordSendComponents, y as resolveDiscordSendEmbeds } from "./send.shared-Cluujl6W.js";
4
- import { a as resolveDiscordDirectoryUserId } from "./directory-live-CDWUg-nA.js";
3
+ import { F as createDiscordClient, P as parseAndResolveChannelRecipient, _ as resolveDiscordMessageFlags, a as normalizeDiscordPollInput, c as normalizeStickerIds, f as sendDiscordMedia, g as buildDiscordMessageRequest, l as resolveChannelId, n as buildDiscordTextChunks, p as sendDiscordText, t as buildDiscordSendError, u as resolveDiscordChannelType, v as resolveDiscordSendComponents, y as resolveDiscordSendEmbeds } from "./send.shared-B3QxPnR3.js";
4
+ import { a as resolveDiscordDirectoryUserId } from "./directory-live-BjBs64RV.js";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { ChannelType } from "discord-api-types/v10";
7
7
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -395,10 +395,10 @@ const optionComparisonOmittedFields = new Set([
395
395
  "name_localized"
396
396
  ]);
397
397
  const nullableLocalizationFields = new Set(["description_localizations", "name_localizations"]);
398
- function stableComparableObject(value, path = []) {
398
+ function stableComparableObject(value, pathValue = []) {
399
399
  if (Array.isArray(value)) {
400
- const normalized = value.map((entry) => stableComparableObject(entry, path));
401
- const key = path.at(-1);
400
+ const normalized = value.map((entry) => stableComparableObject(entry, pathValue));
401
+ const key = pathValue.at(-1);
402
402
  if (key && unorderedCommandArrayFields.has(key) && normalized.every((entry) => typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean")) return normalized.toSorted((left, right) => String(left).localeCompare(String(right)));
403
403
  return normalized;
404
404
  }
@@ -406,13 +406,13 @@ function stableComparableObject(value, path = []) {
406
406
  return Object.fromEntries(Object.entries(value).filter(([key, entry]) => {
407
407
  if (entry === void 0) return false;
408
408
  if (entry === null && nullableLocalizationFields.has(key)) return false;
409
- if (path.includes("options") && optionComparisonOmittedFields.has(key)) return false;
409
+ if (pathValue.includes("options") && optionComparisonOmittedFields.has(key)) return false;
410
410
  if ((key === "required" || key === "autocomplete") && entry === false) return false;
411
411
  return true;
412
- }).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => [key, shouldNormalizeDescriptionValue(path, key, entry) ? normalizeDescriptionForComparison(entry) : stableComparableObject(entry, [...path, key])]));
412
+ }).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => [key, shouldNormalizeDescriptionValue(pathValue, key, entry) ? normalizeDescriptionForComparison(entry) : stableComparableObject(entry, [...pathValue, key])]));
413
413
  }
414
- function shouldNormalizeDescriptionValue(path, key, entry) {
415
- return typeof entry === "string" && (key === "description" || path.at(-1) === "description_localizations");
414
+ function shouldNormalizeDescriptionValue(pathLocal, key, entry) {
415
+ return typeof entry === "string" && (key === "description" || pathLocal.at(-1) === "description_localizations");
416
416
  }
417
417
  /**
418
418
  * Normalize a Discord command description for equality comparison.
@@ -1096,10 +1096,16 @@ function channelFactory(clientForTest, channelData, _partial) {
1096
1096
  //#endregion
1097
1097
  //#region extensions/discord/src/internal/entity-cache.ts
1098
1098
  const DEFAULT_REST_CACHE_TTL_MS = 3e4;
1099
+ const DEFAULT_MAX_ENTRIES = 5e3;
1100
+ const DEFAULT_SWEEP_INTERVAL_MS = 3e4;
1099
1101
  var DiscordEntityCache = class {
1100
1102
  constructor(params) {
1101
1103
  this.params = params;
1102
1104
  this.entries = /* @__PURE__ */ new Map();
1105
+ this.lastSweepAt = 0;
1106
+ }
1107
+ get size() {
1108
+ return this.entries.size;
1103
1109
  }
1104
1110
  async fetchUser(id) {
1105
1111
  return await this.fetchCached(`user:${id}`, async () => {
@@ -1157,13 +1163,34 @@ var DiscordEntityCache = class {
1157
1163
  const value = await fetcher();
1158
1164
  if (ttl > 0) {
1159
1165
  const expiresAt = resolveExpiresAtMsFromDurationMs(ttl, { nowMs: rawNow });
1160
- if (expiresAt !== void 0) this.entries.set(key, {
1161
- expiresAt,
1162
- value
1163
- });
1166
+ if (expiresAt !== void 0) {
1167
+ if (now !== void 0) this.maybeSweepExpired(now);
1168
+ this.entries.set(key, {
1169
+ expiresAt,
1170
+ value
1171
+ });
1172
+ this.enforceMaxEntries();
1173
+ }
1164
1174
  }
1165
1175
  return value;
1166
1176
  }
1177
+ maybeSweepExpired(now) {
1178
+ const interval = this.params.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS;
1179
+ if (now - this.lastSweepAt < interval) return;
1180
+ this.lastSweepAt = now;
1181
+ for (const [key, entry] of this.entries) if (entry.expiresAt <= now) this.entries.delete(key);
1182
+ }
1183
+ enforceMaxEntries() {
1184
+ const max = this.params.maxEntries ?? DEFAULT_MAX_ENTRIES;
1185
+ if (this.entries.size <= max) return;
1186
+ const toRemove = this.entries.size - max;
1187
+ let removed = 0;
1188
+ for (const key of this.entries.keys()) {
1189
+ if (removed >= toRemove) break;
1190
+ this.entries.delete(key);
1191
+ removed += 1;
1192
+ }
1193
+ }
1167
1194
  get rest() {
1168
1195
  return typeof this.params.rest === "function" ? this.params.rest() : this.params.rest;
1169
1196
  }
@@ -1,6 +1,6 @@
1
- import { At as getGuildMember, M as Embed, S as RateLimitError, b as RequestClient, j as serializePayload, kt as getGuild, nt as createUserDmChannel, pt as getChannel, rt as getCurrentUser, s as chunkDiscordTextWithMode, st as createChannelMessage } from "./send.receipt-CjsWpitW.js";
1
+ import { At as getGuildMember, M as Embed, S as RateLimitError, b as RequestClient, j as serializePayload, kt as getGuild, nt as createUserDmChannel, pt as getChannel, rt as getCurrentUser, s as chunkDiscordTextWithMode, st as createChannelMessage } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { a as mergeDiscordAccountConfig, p as normalizeDiscordToken, s as resolveDiscordAccount } from "./accounts-P19jm1lf.js";
3
- import { t as parseAndResolveDiscordTarget } from "./target-resolver-BYuWNVQp.js";
3
+ import { t as parseAndResolveDiscordTarget } from "./target-resolver-BKGK0ftO.js";
4
4
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
6
6
  import { ChannelType, MessageFlags, PermissionFlagsBits } from "discord-api-types/v10";
@@ -255,12 +255,12 @@ async function fetchBotUserId(rest) {
255
255
  return me.id;
256
256
  }
257
257
  function resolveMemberGuildPermissionBits(params) {
258
- const rolesById = new Map((params.guild.roles ?? []).map((role) => [role.id, role]));
259
- const everyoneRole = rolesById.get(params.guild.id);
258
+ const rolesByIdLocal = new Map((params.guild.roles ?? []).map((role) => [role.id, role]));
259
+ const everyoneRole = rolesByIdLocal.get(params.guild.id);
260
260
  let permissions = 0n;
261
261
  if (everyoneRole?.permissions) permissions = addPermissionBits(permissions, everyoneRole.permissions);
262
262
  for (const roleId of params.member.roles ?? []) {
263
- const role = rolesById.get(roleId);
263
+ const role = rolesByIdLocal.get(roleId);
264
264
  if (role?.permissions) permissions = addPermissionBits(permissions, role.permissions);
265
265
  }
266
266
  return permissions;
@@ -1,4 +1,4 @@
1
- import { b as formatDiscordUserTag } from "./allow-list-BnkWtVpA.js";
1
+ import { b as formatDiscordUserTag } from "./allow-list-C-MqM-B_.js";
2
2
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  //#region extensions/discord/src/monitor/sender-identity.ts
4
4
  function resolveDiscordWebhookId(message) {
@@ -1,2 +1,2 @@
1
- import { t as discordSetupPlugin } from "./channel.setup-BNZm3eed.js";
1
+ import { t as discordSetupPlugin } from "./channel.setup-BX7g7pL-.js";
2
2
  export { discordSetupPlugin };
@@ -2,7 +2,7 @@ import { t as inspectDiscordAccount } from "./account-inspect-DDZtT5C8.js";
2
2
  import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, d as resolveDiscordAccountDmPolicy, n as isDiscordAccountEnabledForRuntime, o as resolveDefaultDiscordAccountId, r as listDiscordAccountIds, s as resolveDiscordAccount, u as resolveDiscordAccountDisabledReason } from "./accounts-P19jm1lf.js";
3
3
  import { i as getChatChannelMeta, o as resolveConfiguredFromCredentialStatuses } from "./channel-api-CAJ0wMoV.js";
4
4
  import { t as DiscordChannelConfigSchema } from "./config-schema-spuxW477.js";
5
- import { n as normalizeCompatibilityConfig } from "./doctor-contract-BAu3WLvd.js";
5
+ import { n as normalizeCompatibilityConfig } from "./doctor-contract-CU7lnZTF.js";
6
6
  import { n as secretTargetRegistryEntries, t as collectRuntimeConfigAssignments } from "./secret-config-contract-BjM-1hr9.js";
7
7
  import { n as unsupportedSecretRefSurfacePatterns, t as collectUnsupportedSecretRefConfigCandidates } from "./security-contract-DSHk7I2w.js";
8
8
  import { t as deriveLegacySessionChatType } from "./session-contract-BO5tlIdl.js";
@@ -71,7 +71,7 @@ const DISCORD_LEGACY_CONFIG_RULES = [];
71
71
  const DISCORD_CHANNEL = "discord";
72
72
  let discordDoctorModulePromise;
73
73
  async function loadDiscordDoctorModule() {
74
- discordDoctorModulePromise ??= import("./doctor-BUhqxLb9.js");
74
+ discordDoctorModulePromise ??= import("./doctor-D3ngpo-Y.js");
75
75
  return await discordDoctorModulePromise;
76
76
  }
77
77
  const discordDoctor = {
@@ -1,7 +1,7 @@
1
1
  //#region extensions/discord/subagent-hooks-api.ts
2
2
  let discordSubagentHooksPromise = null;
3
3
  function loadDiscordSubagentHooksModule() {
4
- discordSubagentHooksPromise ??= import("./subagent-hooks-7jAn9HT5.js").then((n) => n.i);
4
+ discordSubagentHooksPromise ??= import("./subagent-hooks-nBcp0iGm.js").then((n) => n.i);
5
5
  return discordSubagentHooksPromise;
6
6
  }
7
7
  function registerDiscordSubagentHooks(api) {
@@ -1,6 +1,6 @@
1
- import { Wt as __exportAll } from "./send.receipt-CjsWpitW.js";
1
+ import { Wt as __exportAll } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { s as resolveDiscordAccount } from "./accounts-P19jm1lf.js";
3
- import { n as autoBindSpawnedDiscordSubagent, o as unbindThreadBindingsBySessionKey, r as listThreadBindingsBySessionKey } from "./thread-bindings-CKruJE91.js";
3
+ import { n as autoBindSpawnedDiscordSubagent, o as unbindThreadBindingsBySessionKey, r as listThreadBindingsBySessionKey } from "./thread-bindings-Tfr_vFxk.js";
4
4
  import { normalizeOptionalLowercaseString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { formatThreadBindingDisabledError, formatThreadBindingSpawnDisabledError, resolveThreadBindingSpawnPolicy } from "openclaw/plugin-sdk/conversation-runtime";
6
6
  //#region extensions/discord/src/subagent-hooks.ts
@@ -1,5 +1,5 @@
1
- import { c as discord_exports } from "./send.receipt-CjsWpitW.js";
2
- import { b as formatDiscordUserTag } from "./allow-list-BnkWtVpA.js";
1
+ import { c as discord_exports } from "./send.receipt-Z8V6yMOY.js";
2
+ import { b as formatDiscordUserTag } from "./allow-list-C-MqM-B_.js";
3
3
  //#region extensions/discord/src/monitor/system-events.ts
4
4
  function resolveDiscordSystemEvent(message, location) {
5
5
  switch (message.type) {
@@ -1,6 +1,6 @@
1
- import { Ht as parseDiscordTarget, Wt as __exportAll, r as allowFromContainsDiscordUserId } from "./send.receipt-CjsWpitW.js";
1
+ import { Ht as parseDiscordTarget, Wt as __exportAll, r as allowFromContainsDiscordUserId } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { c as resolveDiscordAccountAllowFrom, s as resolveDiscordAccount } from "./accounts-P19jm1lf.js";
3
- import { i as rememberDiscordDirectoryUser, r as listDiscordDirectoryPeersLive } from "./directory-live-CDWUg-nA.js";
3
+ import { i as rememberDiscordDirectoryUser, r as listDiscordDirectoryPeersLive } from "./directory-live-BjBs64RV.js";
4
4
  import { buildMessagingTarget } from "openclaw/plugin-sdk/channel-targets";
5
5
  //#region extensions/discord/src/send-target-parsing.ts
6
6
  const parseDiscordSendTarget = (raw, options = {}) => parseDiscordTarget(raw, options);
@@ -0,0 +1,3 @@
1
+ import "./send.receipt-Z8V6yMOY.js";
2
+ import "./target-resolver-BKGK0ftO.js";
3
+ export {};
@@ -1,9 +1,9 @@
1
- import { Ht as parseDiscordTarget, Wt as __exportAll } from "./send.receipt-CjsWpitW.js";
2
- import "./targets-BNDUOdvI.js";
3
- import { C as resolveThreadBindingMaxAgeMs$1, O as shouldPersistBindingMutations, S as resolveThreadBindingMaxAgeExpiresAt, T as saveBindingsToDisk, b as resolveThreadBindingIdleTimeoutMs$1, c as getThreadBindingToken, f as normalizeThreadId, g as removeBindingRecord, l as isRecentlyUnboundThreadWebhookMessage, n as MANAGERS_BY_ACCOUNT_ID, p as rememberRecentUnboundWebhookEcho, t as BINDINGS_BY_THREAD_ID, x as resolveThreadBindingInactivityExpiresAt } from "./thread-bindings.state-DYp4FVEB.js";
4
- import { n as setThreadBindingMaxAgeBySessionKey, r as resolveBindingIdsForTargetSession, t as setThreadBindingIdleTimeoutBySessionKey } from "./thread-bindings.session-updates-DoDFvU_h.js";
5
- import { _ as formatThreadBindingDurationLabel, b as resolveThreadBindingThreadName, g as resolveThreadBindingPersonaFromRecord, h as resolveThreadBindingPersona, s as resolveChannelIdForBinding, y as resolveThreadBindingIntroText } from "./thread-bindings.discord-api-BjLUwwSP.js";
6
- import { i as testing, n as createThreadBindingManager, r as getThreadBindingManager, t as createNoopThreadBindingManager } from "./thread-bindings.manager-Dji7SZHG.js";
1
+ import { Ht as parseDiscordTarget, Wt as __exportAll } from "./send.receipt-Z8V6yMOY.js";
2
+ import "./targets-Cv797U29.js";
3
+ import { A as shouldPersistBindingMutations, C as resolveThreadBindingIdleTimeoutMs$1, D as saveBindingsToDisk, E as resolveThreadBindingMaxAgeMs$1, T as resolveThreadBindingMaxAgeExpiresAt, d as isRecentlyUnboundThreadWebhookMessage, g as rememberRecentUnboundWebhookEcho, h as normalizeThreadId, n as MANAGERS_BY_ACCOUNT_ID, t as BINDINGS_BY_THREAD_ID, u as getThreadBindingToken, w as resolveThreadBindingInactivityExpiresAt, y as removeBindingRecord } from "./thread-bindings.state-CVLF7gJH.js";
4
+ import { n as setThreadBindingMaxAgeBySessionKey, r as resolveBindingIdsForTargetSession, t as setThreadBindingIdleTimeoutBySessionKey } from "./thread-bindings.session-updates-DeMxmcXB.js";
5
+ import { _ as formatThreadBindingDurationLabel, b as resolveThreadBindingThreadName, g as resolveThreadBindingPersonaFromRecord, h as resolveThreadBindingPersona, s as resolveChannelIdForBinding, y as resolveThreadBindingIntroText } from "./thread-bindings.discord-api-CfDs1lWu.js";
6
+ import { i as testing, n as createThreadBindingManager, r as getThreadBindingManager, t as createNoopThreadBindingManager } from "./thread-bindings.manager-CRc4hYr1.js";
7
7
  import { normalizeOptionalLowercaseString, normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
9
9
  import { resolveThreadBindingIdleTimeoutMs, resolveThreadBindingMaxAgeMs, resolveThreadBindingsEnabled } from "openclaw/plugin-sdk/conversation-runtime";
@@ -1,8 +1,8 @@
1
- import { Ut as resolveDiscordChannelId, pt as getChannel, tt as createChannelWebhook } from "./send.receipt-CjsWpitW.js";
2
- import { I as createDiscordRestClient } from "./send.shared-Cluujl6W.js";
3
- import { c as sendWebhookMessageDiscord, u as createThreadDiscord } from "./send-BHkA8a-k.js";
4
- import { t as sendMessageDiscord } from "./send.outbound-DSKZbjML.js";
5
- import { i as REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL, k as toReusableWebhookKey, m as rememberReusableWebhook, t as BINDINGS_BY_THREAD_ID } from "./thread-bindings.state-DYp4FVEB.js";
1
+ import { Ut as resolveDiscordChannelId, pt as getChannel, tt as createChannelWebhook } from "./send.receipt-Z8V6yMOY.js";
2
+ import { I as createDiscordRestClient } from "./send.shared-B3QxPnR3.js";
3
+ import { c as sendWebhookMessageDiscord, u as createThreadDiscord } from "./send-CyyRF1yd.js";
4
+ import { t as sendMessageDiscord } from "./send.outbound-DhMLobqR.js";
5
+ import { M as toReusableWebhookKey, _ as rememberReusableWebhook, i as REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL, t as BINDINGS_BY_THREAD_ID } from "./thread-bindings.state-CVLF7gJH.js";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { ChannelType } from "discord-api-types/v10";
8
8
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
@@ -1,7 +1,7 @@
1
- import { Ut as resolveDiscordChannelId, Wt as __exportAll, pt as getChannel } from "./send.receipt-CjsWpitW.js";
2
- import { I as createDiscordRestClient } from "./send.shared-Cluujl6W.js";
3
- import { A as DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS, C as resolveThreadBindingMaxAgeMs$1, D as shouldDefaultPersist, E as setBindingRecord, M as THREAD_BINDINGS_SWEEP_INTERVAL_MS, S as resolveThreadBindingMaxAgeExpiresAt, T as saveBindingsToDisk, _ as resetThreadBindingsForTests, a as THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS, b as resolveThreadBindingIdleTimeoutMs$1, c as getThreadBindingToken, d as normalizeThreadBindingDurationMs, f as normalizeThreadId, g as removeBindingRecord, h as rememberThreadBindingToken, n as MANAGERS_BY_ACCOUNT_ID, o as ensureBindingsLoaded, p as rememberRecentUnboundWebhookEcho, r as PERSIST_BY_ACCOUNT_ID, s as forgetThreadBindingToken, t as BINDINGS_BY_THREAD_ID, u as normalizeTargetKind, v as resolveBindingIdsForSession, w as resolveThreadBindingsPath, x as resolveThreadBindingInactivityExpiresAt, y as resolveBindingRecordKey } from "./thread-bindings.state-DYp4FVEB.js";
4
- import { a as isThreadArchived, b as resolveThreadBindingThreadName, c as summarizeDiscordError, i as isDiscordThreadGoneError, n as createWebhookForChannel, o as maybeSendBindingMessage, r as findReusableWebhook, s as resolveChannelIdForBinding, t as createThreadForBinding, v as resolveThreadBindingFarewellText } from "./thread-bindings.discord-api-BjLUwwSP.js";
1
+ import { Ut as resolveDiscordChannelId, Wt as __exportAll, pt as getChannel } from "./send.receipt-Z8V6yMOY.js";
2
+ import { I as createDiscordRestClient } from "./send.shared-B3QxPnR3.js";
3
+ import { C as resolveThreadBindingIdleTimeoutMs$1, D as saveBindingsToDisk, E as resolveThreadBindingMaxAgeMs$1, F as THREAD_BINDINGS_SWEEP_INTERVAL_MS, N as DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS, O as setBindingRecord, S as resolveBindingRecordKey, T as resolveThreadBindingMaxAgeExpiresAt, b as resetThreadBindingsForTests, c as ensureBindingsLoaded, g as rememberRecentUnboundWebhookEcho, h as normalizeThreadId, k as shouldDefaultPersist, l as forgetThreadBindingToken, m as normalizeThreadBindingDurationMs, n as MANAGERS_BY_ACCOUNT_ID, p as normalizeTargetKind, r as PERSIST_BY_ACCOUNT_ID, s as THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS, t as BINDINGS_BY_THREAD_ID, u as getThreadBindingToken, v as rememberThreadBindingToken, w as resolveThreadBindingInactivityExpiresAt, x as resolveBindingIdsForSession, y as removeBindingRecord } from "./thread-bindings.state-CVLF7gJH.js";
4
+ import { a as isThreadArchived, b as resolveThreadBindingThreadName, c as summarizeDiscordError, i as isDiscordThreadGoneError, n as createWebhookForChannel, o as maybeSendBindingMessage, r as findReusableWebhook, s as resolveChannelIdForBinding, t as createThreadForBinding, v as resolveThreadBindingFarewellText } from "./thread-bindings.discord-api-CfDs1lWu.js";
5
5
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing";
7
7
  import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
@@ -327,13 +327,13 @@ function createThreadBindingManager(params) {
327
327
  threadId: touchParams.threadId
328
328
  });
329
329
  if (!key) return null;
330
- const existing = BINDINGS_BY_THREAD_ID.get(key);
331
- if (!existing || existing.accountId !== accountId) return null;
330
+ const existingResult = BINDINGS_BY_THREAD_ID.get(key);
331
+ if (!existingResult || existingResult.accountId !== accountId) return null;
332
332
  const now = Date.now();
333
333
  const at = typeof touchParams.at === "number" && Number.isFinite(touchParams.at) ? Math.max(0, Math.floor(touchParams.at)) : now;
334
334
  const nextRecord = {
335
- ...existing,
336
- lastActivityAt: Math.max(existing.lastActivityAt || 0, at)
335
+ ...existingResult,
336
+ lastActivityAt: Math.max(existingResult.lastActivityAt || 0, at)
337
337
  };
338
338
  setBindingRecord(nextRecord);
339
339
  if (touchParams.persist ?? persist) saveBindingsToDisk({ minIntervalMs: THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS });
@@ -368,12 +368,12 @@ function createThreadBindingManager(params) {
368
368
  channelId: bindParams.channelId
369
369
  }) ?? "";
370
370
  if (!channelId) return null;
371
- const existing = manager.getByThreadId(threadId);
371
+ const existingValue = manager.getByThreadId(threadId);
372
372
  const targetSessionKey = normalizeOptionalString(bindParams.targetSessionKey) ?? "";
373
373
  if (!targetSessionKey) return null;
374
374
  const targetKind = normalizeTargetKind(bindParams.targetKind, targetSessionKey);
375
- let webhookId = normalizeOptionalString(bindParams.webhookId) ?? normalizeOptionalString(existing?.webhookId) ?? "";
376
- let webhookToken = normalizeOptionalString(bindParams.webhookToken) ?? normalizeOptionalString(existing?.webhookToken) ?? "";
375
+ let webhookId = normalizeOptionalString(bindParams.webhookId) ?? normalizeOptionalString(existingValue?.webhookId) ?? "";
376
+ let webhookToken = normalizeOptionalString(bindParams.webhookToken) ?? normalizeOptionalString(existingValue?.webhookToken) ?? "";
377
377
  if (!directConversationBinding && (!webhookId || !webhookToken)) {
378
378
  const cachedWebhook = findReusableWebhook({
379
379
  accountId,
@@ -399,19 +399,19 @@ function createThreadBindingManager(params) {
399
399
  threadId,
400
400
  targetKind,
401
401
  targetSessionKey,
402
- agentId: normalizeOptionalString(bindParams.agentId) ?? normalizeOptionalString(existing?.agentId) ?? resolveAgentIdFromSessionKey(targetSessionKey),
403
- label: normalizeOptionalString(bindParams.label) ?? normalizeOptionalString(existing?.label),
402
+ agentId: normalizeOptionalString(bindParams.agentId) ?? normalizeOptionalString(existingValue?.agentId) ?? resolveAgentIdFromSessionKey(targetSessionKey),
403
+ label: normalizeOptionalString(bindParams.label) ?? normalizeOptionalString(existingValue?.label),
404
404
  webhookId: webhookId || void 0,
405
405
  webhookToken: webhookToken || void 0,
406
- boundBy: normalizeOptionalString(bindParams.boundBy) ?? normalizeOptionalString(existing?.boundBy) ?? "system",
406
+ boundBy: normalizeOptionalString(bindParams.boundBy) ?? normalizeOptionalString(existingValue?.boundBy) ?? "system",
407
407
  boundAt: now,
408
408
  lastActivityAt: now,
409
- idleTimeoutMs: typeof existing?.idleTimeoutMs === "number" ? existing.idleTimeoutMs : idleTimeoutMs,
410
- maxAgeMs: typeof existing?.maxAgeMs === "number" ? existing.maxAgeMs : maxAgeMs,
409
+ idleTimeoutMs: typeof existingValue?.idleTimeoutMs === "number" ? existingValue.idleTimeoutMs : idleTimeoutMs,
410
+ maxAgeMs: typeof existingValue?.maxAgeMs === "number" ? existingValue.maxAgeMs : maxAgeMs,
411
411
  metadata: bindParams.metadata && typeof bindParams.metadata === "object" ? {
412
- ...existing?.metadata,
412
+ ...existingValue?.metadata,
413
413
  ...bindParams.metadata
414
- } : existing?.metadata ? { ...existing.metadata } : void 0
414
+ } : existingValue?.metadata ? { ...existingValue.metadata } : void 0
415
415
  };
416
416
  setBindingRecord(record);
417
417
  if (persist) saveBindingsToDisk();
@@ -429,8 +429,8 @@ function createThreadBindingManager(params) {
429
429
  threadId: unbindParams.threadId
430
430
  });
431
431
  if (!bindingKey) return null;
432
- const existing = BINDINGS_BY_THREAD_ID.get(bindingKey);
433
- if (!existing || existing.accountId !== accountId) return null;
432
+ const existingLocal = BINDINGS_BY_THREAD_ID.get(bindingKey);
433
+ if (!existingLocal || existingLocal.accountId !== accountId) return null;
434
434
  const removed = removeBindingRecord(bindingKey);
435
435
  if (!removed) return null;
436
436
  rememberRecentUnboundWebhookEcho(removed);
@@ -522,7 +522,6 @@ function getThreadBindingManager(accountId) {
522
522
  return MANAGERS_BY_ACCOUNT_ID.get(normalized) ?? null;
523
523
  }
524
524
  const testing = {
525
- resolveThreadBindingsPath,
526
525
  resolveThreadBindingThreadName,
527
526
  resetThreadBindingsForTests,
528
527
  runThreadBindingSweepForAccount: async (accountId) => {
@@ -1,4 +1,4 @@
1
- import { E as setBindingRecord, O as shouldPersistBindingMutations, T as saveBindingsToDisk, o as ensureBindingsLoaded, t as BINDINGS_BY_THREAD_ID, v as resolveBindingIdsForSession } from "./thread-bindings.state-DYp4FVEB.js";
1
+ import { A as shouldPersistBindingMutations, D as saveBindingsToDisk, O as setBindingRecord, c as ensureBindingsLoaded, t as BINDINGS_BY_THREAD_ID, x as resolveBindingIdsForSession } from "./thread-bindings.state-CVLF7gJH.js";
2
2
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
3
3
  //#region extensions/discord/src/monitor/thread-bindings.session-shared.ts
4
4
  function normalizeNonNegativeMs(raw) {
@@ -1,10 +1,7 @@
1
+ import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
1
2
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
2
3
  import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing";
3
4
  import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
4
- import path from "node:path";
5
- import fs from "node:fs";
6
- import { loadJsonFile, saveJsonFile } from "openclaw/plugin-sdk/json-store";
7
- import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
8
5
  //#region extensions/discord/src/monitor/thread-bindings.types.ts
9
6
  const THREAD_BINDINGS_SWEEP_INTERVAL_MS = 12e4;
10
7
  const DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS = 1440 * 60 * 1e3;
@@ -24,6 +21,8 @@ function createThreadBindingsGlobalState() {
24
21
  reusableWebhooksByAccountChannel: /* @__PURE__ */ new Map(),
25
22
  persistByAccountId: /* @__PURE__ */ new Map(),
26
23
  loadedBindings: false,
24
+ loadedPersistentBindings: false,
25
+ persistenceAvailable: true,
27
26
  lastPersistedAtMs: 0
28
27
  };
29
28
  }
@@ -44,6 +43,8 @@ const RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY = THREAD_BINDINGS_STATE.recen
44
43
  const REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL = THREAD_BINDINGS_STATE.reusableWebhooksByAccountChannel;
45
44
  const PERSIST_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.persistByAccountId;
46
45
  const THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS = 15e3;
46
+ const THREAD_BINDINGS_NAMESPACE = "thread-bindings";
47
+ const THREAD_BINDINGS_MAX_ENTRIES = 1e4;
47
48
  function rememberThreadBindingToken(params) {
48
49
  const normalizedAccountId = normalizeAccountId(params.accountId);
49
50
  const token = params.token?.trim();
@@ -59,8 +60,11 @@ function getThreadBindingToken(accountId) {
59
60
  function shouldDefaultPersist() {
60
61
  return !(process.env.VITEST || false);
61
62
  }
62
- function resolveThreadBindingsPath() {
63
- return path.join(resolveStateDir(process.env), "discord", "thread-bindings.json");
63
+ function openThreadBindingsStore() {
64
+ return getDiscordRuntime().state.openSyncKeyedStore({
65
+ namespace: THREAD_BINDINGS_NAMESPACE,
66
+ maxEntries: THREAD_BINDINGS_MAX_ENTRIES
67
+ });
64
68
  }
65
69
  function normalizeTargetKind(raw, targetSessionKey) {
66
70
  if (raw === "subagent" || raw === "acp") return raw;
@@ -260,22 +264,34 @@ function shouldPersistAnyBindingState() {
260
264
  return false;
261
265
  }
262
266
  function shouldPersistBindingMutations() {
267
+ if (!THREAD_BINDINGS_STATE.persistenceAvailable) return false;
263
268
  if (shouldPersistAnyBindingState()) return true;
264
- return fs.existsSync(resolveThreadBindingsPath());
269
+ return THREAD_BINDINGS_STATE.loadedPersistentBindings;
270
+ }
271
+ function toPersistedBindingRecord(record) {
272
+ const serialized = JSON.stringify(record);
273
+ if (!serialized) return { ...record };
274
+ return JSON.parse(serialized);
265
275
  }
266
276
  function saveBindingsToDisk(params = {}) {
267
277
  if (!params.force && !shouldPersistAnyBindingState()) return;
278
+ if (!THREAD_BINDINGS_STATE.persistenceAvailable) return;
268
279
  const minIntervalMs = typeof params.minIntervalMs === "number" && Number.isFinite(params.minIntervalMs) ? Math.max(0, Math.floor(params.minIntervalMs)) : 0;
269
280
  const now = Date.now();
270
281
  if (!params.force && minIntervalMs > 0 && THREAD_BINDINGS_STATE.lastPersistedAtMs > 0 && now - THREAD_BINDINGS_STATE.lastPersistedAtMs < minIntervalMs) return;
271
- const bindings = {};
272
- for (const [bindingKey, record] of BINDINGS_BY_THREAD_ID.entries()) bindings[bindingKey] = { ...record };
273
- const payload = {
274
- version: 1,
275
- bindings
276
- };
277
- saveJsonFile(resolveThreadBindingsPath(), payload);
278
- THREAD_BINDINGS_STATE.lastPersistedAtMs = now;
282
+ try {
283
+ const store = openThreadBindingsStore();
284
+ const persistedKeys = /* @__PURE__ */ new Set();
285
+ for (const [bindingKey, record] of BINDINGS_BY_THREAD_ID.entries()) {
286
+ store.register(bindingKey, toPersistedBindingRecord(record));
287
+ persistedKeys.add(bindingKey);
288
+ }
289
+ for (const entry of store.entries()) if (!persistedKeys.has(entry.key)) store.delete(entry.key);
290
+ THREAD_BINDINGS_STATE.loadedPersistentBindings = persistedKeys.size > 0;
291
+ THREAD_BINDINGS_STATE.lastPersistedAtMs = now;
292
+ } catch {
293
+ THREAD_BINDINGS_STATE.persistenceAvailable = false;
294
+ }
279
295
  }
280
296
  function ensureBindingsLoaded() {
281
297
  if (THREAD_BINDINGS_STATE.loadedBindings) return;
@@ -283,12 +299,20 @@ function ensureBindingsLoaded() {
283
299
  BINDINGS_BY_THREAD_ID.clear();
284
300
  BINDINGS_BY_SESSION_KEY.clear();
285
301
  REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.clear();
286
- const raw = loadJsonFile(resolveThreadBindingsPath());
287
- if (!raw || typeof raw !== "object") return;
288
- const payload = raw;
289
- if (payload.version !== 1 || !payload.bindings || typeof payload.bindings !== "object") return;
290
- for (const [threadId, entry] of Object.entries(payload.bindings)) {
291
- const normalized = normalizePersistedBinding(threadId, entry);
302
+ THREAD_BINDINGS_STATE.loadedPersistentBindings = false;
303
+ const entries = (() => {
304
+ try {
305
+ return openThreadBindingsStore().entries();
306
+ } catch {
307
+ THREAD_BINDINGS_STATE.persistenceAvailable = false;
308
+ return null;
309
+ }
310
+ })();
311
+ if (!entries) return;
312
+ THREAD_BINDINGS_STATE.persistenceAvailable = true;
313
+ THREAD_BINDINGS_STATE.loadedPersistentBindings = entries.length > 0;
314
+ for (const entry of entries) {
315
+ const normalized = normalizePersistedBinding(entry.key, entry.value);
292
316
  if (!normalized) continue;
293
317
  setBindingRecord(normalized);
294
318
  }
@@ -318,7 +342,9 @@ function resetThreadBindingsForTests() {
318
342
  TOKENS_BY_ACCOUNT_ID.clear();
319
343
  PERSIST_BY_ACCOUNT_ID.clear();
320
344
  THREAD_BINDINGS_STATE.loadedBindings = false;
345
+ THREAD_BINDINGS_STATE.loadedPersistentBindings = false;
346
+ THREAD_BINDINGS_STATE.persistenceAvailable = true;
321
347
  THREAD_BINDINGS_STATE.lastPersistedAtMs = 0;
322
348
  }
323
349
  //#endregion
324
- export { DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS as A, resolveThreadBindingMaxAgeMs as C, shouldDefaultPersist as D, setBindingRecord as E, THREAD_BINDINGS_SWEEP_INTERVAL_MS as M, shouldPersistBindingMutations as O, resolveThreadBindingMaxAgeExpiresAt as S, saveBindingsToDisk as T, resetThreadBindingsForTests as _, THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS as a, resolveThreadBindingIdleTimeoutMs as b, getThreadBindingToken as c, normalizeThreadBindingDurationMs as d, normalizeThreadId as f, removeBindingRecord as g, rememberThreadBindingToken as h, REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL as i, DISCORD_UNKNOWN_CHANNEL_ERROR_CODE as j, toReusableWebhookKey as k, isRecentlyUnboundThreadWebhookMessage as l, rememberReusableWebhook as m, MANAGERS_BY_ACCOUNT_ID as n, ensureBindingsLoaded as o, rememberRecentUnboundWebhookEcho as p, PERSIST_BY_ACCOUNT_ID as r, forgetThreadBindingToken as s, BINDINGS_BY_THREAD_ID as t, normalizeTargetKind as u, resolveBindingIdsForSession as v, resolveThreadBindingsPath as w, resolveThreadBindingInactivityExpiresAt as x, resolveBindingRecordKey as y };
350
+ export { shouldPersistBindingMutations as A, resolveThreadBindingIdleTimeoutMs as C, saveBindingsToDisk as D, resolveThreadBindingMaxAgeMs as E, THREAD_BINDINGS_SWEEP_INTERVAL_MS as F, toReusableWebhookKey as M, DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS as N, setBindingRecord as O, DISCORD_UNKNOWN_CHANNEL_ERROR_CODE as P, resolveBindingRecordKey as S, resolveThreadBindingMaxAgeExpiresAt as T, rememberReusableWebhook as _, THREAD_BINDINGS_MAX_ENTRIES as a, resetThreadBindingsForTests as b, ensureBindingsLoaded as c, isRecentlyUnboundThreadWebhookMessage as d, normalizePersistedBinding as f, rememberRecentUnboundWebhookEcho as g, normalizeThreadId as h, REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL as i, toBindingRecordKey as j, shouldDefaultPersist as k, forgetThreadBindingToken as l, normalizeThreadBindingDurationMs as m, MANAGERS_BY_ACCOUNT_ID as n, THREAD_BINDINGS_NAMESPACE as o, normalizeTargetKind as p, PERSIST_BY_ACCOUNT_ID as r, THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS as s, BINDINGS_BY_THREAD_ID as t, getThreadBindingToken as u, rememberThreadBindingToken as v, resolveThreadBindingInactivityExpiresAt as w, resolveBindingIdsForSession as x, removeBindingRecord as y };
@@ -1,4 +1,4 @@
1
- import { Wt as __exportAll } from "./send.receipt-CjsWpitW.js";
1
+ import { Wt as __exportAll } from "./send.receipt-Z8V6yMOY.js";
2
2
  //#region extensions/discord/src/voice/transcripts-source.ts
3
3
  var transcripts_source_exports = /* @__PURE__ */ __exportAll({
4
4
  discordVoiceTranscriptsSourceProvider: () => discordVoiceTranscriptsSourceProvider,
@@ -1,2 +1,2 @@
1
- import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-O73_YIDs.js";
1
+ import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-Cegx0wdw.js";
2
2
  export { discordVoiceTranscriptsSourceProvider };
@@ -1,4 +1,4 @@
1
- import { Wt as __exportAll, bt as sendChannelTyping } from "./send.receipt-CjsWpitW.js";
1
+ import { Wt as __exportAll, bt as sendChannelTyping } from "./send.receipt-Z8V6yMOY.js";
2
2
  import { o as raceWithTimeout } from "./timeouts-CEJ3--Uw.js";
3
3
  //#region extensions/discord/src/monitor/typing.ts
4
4
  var typing_exports = /* @__PURE__ */ __exportAll({ sendTyping: () => sendTyping });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/discord",
3
- "version": "2026.5.31-beta.2",
3
+ "version": "2026.5.31-beta.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/discord",
9
- "version": "2026.5.31-beta.2",
9
+ "version": "2026.5.31-beta.4",
10
10
  "dependencies": {
11
11
  "@discordjs/voice": "0.19.2",
12
12
  "discord-api-types": "0.38.48",
@@ -16,7 +16,7 @@
16
16
  "ws": "8.21.0"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.5.31-beta.2"
19
+ "openclaw": ">=2026.5.31-beta.4"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/discord",
3
- "version": "2026.5.31-beta.2",
3
+ "version": "2026.5.31-beta.4",
4
4
  "description": "OpenClaw Discord channel plugin for channels, DMs, commands, and app events.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  "ws": "8.21.0"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.5.31-beta.2"
19
+ "openclaw": ">=2026.5.31-beta.4"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
@@ -63,10 +63,10 @@
63
63
  "allowInvalidConfigRecovery": true
64
64
  },
65
65
  "compat": {
66
- "pluginApi": ">=2026.5.31-beta.2"
66
+ "pluginApi": ">=2026.5.31-beta.4"
67
67
  },
68
68
  "build": {
69
- "openclawVersion": "2026.5.31-beta.2"
69
+ "openclawVersion": "2026.5.31-beta.4"
70
70
  },
71
71
  "release": {
72
72
  "publishToClawHub": true,
@@ -1,2 +0,0 @@
1
- import { t as monitorDiscordProvider } from "./provider-BK8hjk_y.js";
2
- export { monitorDiscordProvider };
@@ -1,6 +0,0 @@
1
- import "./allow-list-BnkWtVpA.js";
2
- import "./timeouts-CEJ3--Uw.js";
3
- import "./provider-BK8hjk_y.js";
4
- import "./message-utils-D_3KTxh_.js";
5
- import "./message-handler-HO8BbZmQ.js";
6
- export {};
@@ -1,3 +0,0 @@
1
- import "./send.receipt-CjsWpitW.js";
2
- import "./target-resolver-BYuWNVQp.js";
3
- export {};