@openclaw/discord 2026.8.1 → 2026.8.2

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 (89) hide show
  1. package/dist/account-inspect-BY-ve3yH.js +45 -0
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CfQ-vSyf.js → accounts-CwJQoLjM.js} +89 -45
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{activities-api-Dl-TOyOX.js → activities-api-CkKcHUB6.js} +14 -13
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-BDMimASD.js → allow-list-C2JuH-R0.js} +10 -6
  8. package/dist/{api-DNVbJyEy.js → api-BfmEP6wp.js} +6 -5
  9. package/dist/api.js +17 -17
  10. package/dist/{approval-handler.runtime-q4Zqo44V.js → approval-handler.runtime-DZM6Kt1Z.js} +8 -7
  11. package/dist/{audit-DgrvFPGt.js → audit-DIbQA4VT.js} +8 -7
  12. package/dist/{channel-BsQUalPw.js → channel-CarzU3bg.js} +24 -22
  13. package/dist/{channel-actions.runtime-UMGGIfSy.js → channel-actions.runtime-B2wMqeVK.js} +13 -11
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-rPs4dsk_.js → channel.setup-z_ewMVa9.js} +18 -18
  17. package/dist/{components-Dk35LTf_.js → components-gvRA0oaI.js} +1 -1
  18. package/dist/{config-schema-CxPqtVI1.js → config-schema-B797-Spt.js} +5 -4
  19. package/dist/{conversation-binding-route-BjvX4e35.js → conversation-binding-route-DPpBRpYI.js} +1 -1
  20. package/dist/{directory-config-B7DY_pNG.js → directory-config-AA8wQx0D.js} +2 -2
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-DuAXKkan.js → directory-live-D_kFz_Fj.js} +4 -4
  23. package/dist/{doctor-zQTtn6hm.js → doctor-QQTOkBfW.js} +5 -5
  24. package/dist/{doctor-contract-DsWvKIXF.js → doctor-contract-Co5vRCZ6.js} +9 -6
  25. package/dist/doctor-contract-api.js +3 -2
  26. package/dist/{handle-action.guild-admin-DZewwLr1.js → handle-action.guild-admin-Cc88ZGon.js} +2 -2
  27. package/dist/index.js +1 -1
  28. package/dist/{ingress-identity-CzZKcPK8.js → ingress-identity-BCzfPPYM.js} +1 -1
  29. package/dist/{message-handler-C5By3yl5.js → message-handler-CAeEpqWo.js} +14 -10
  30. package/dist/{message-handler.preflight-DrszWuHw.js → message-handler.preflight-CoKoE3dY.js} +24 -19
  31. package/dist/{message-handler.process-DyFPDLCt.js → message-handler.process-cdIJ_fDT.js} +56 -74
  32. package/dist/{message-text-Ca8M6TU8.js → message-text-C0K4-fkg.js} +9 -4
  33. package/dist/{outbound-adapter-Dif8p481.js → outbound-adapter-Ch0At5Ra.js} +34 -24
  34. package/dist/{outbound-components-wjv7yyAj.js → outbound-components-Bnt_7x7r.js} +3 -3
  35. package/dist/{outbound-session-route-Bn4uXaoE.js → outbound-session-route-CzzerX2K.js} +10 -7
  36. package/dist/{owner-access-UlYi9t0M.js → owner-access-yc1sX7Gx.js} +7 -6
  37. package/dist/{pluralkit-9EuEN4UD.js → pluralkit-B3cUVI7i.js} +2 -2
  38. package/dist/{probe-n6ZXxK8V.js → probe-3ovFAp3b.js} +3 -3
  39. package/dist/{probe.runtime-CN4bdPfZ.js → probe.runtime-BckHn3cJ.js} +1 -1
  40. package/dist/{provider-LXiOcJrH.js → provider-CjI8BSzS.js} +97 -76
  41. package/dist/{provider-session.runtime-DSNe7r2W.js → provider-session.runtime-DdKRMcE9.js} +3 -3
  42. package/dist/provider.runtime-Bo1WbLLr.js +2 -0
  43. package/dist/{realtime-session.runtime-DOViOIjY.js → realtime-session.runtime-37IC-p5K.js} +5 -5
  44. package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-BJ5UZNNT.js} +3 -3
  45. package/dist/{resolve-channels-D2yl_2CN.js → resolve-channels-BexR2eUn.js} +4 -4
  46. package/dist/{resolve-users-BLxfqajZ.js → resolve-users-BtXBCH5W.js} +5 -4
  47. package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
  48. package/dist/{retry-DqHCW6PV.js → retry-t5RcEsPk.js} +37 -29
  49. package/dist/{runtime-DrxVBTtp.js → runtime-BNlDfLwS.js} +2 -2
  50. package/dist/{runtime-BYamRVPN.js → runtime-DydyfxST.js} +126 -92
  51. package/dist/runtime-api.js +19 -19
  52. package/dist/{secret-config-contract-B3i6WxV5.js → secret-config-contract-DFu9hfU8.js} +14 -6
  53. package/dist/secret-contract-api.js +1 -1
  54. package/dist/{send-UJHiAm4C.js → send-mTKSBdmZ.js} +76 -48
  55. package/dist/{send.components-CrBJpGT_.js → send.components-nsPnc7kK.js} +20 -14
  56. package/dist/{send.outbound-D7JYmfm9.js → send.outbound-CaOs9Zy1.js} +34 -20
  57. package/dist/{send.shared-DZJ1akvQ.js → send.shared-BJHt0Vyf.js} +24 -17
  58. package/dist/{sender-identity-BJtfyise.js → sender-identity-Dt0imZyY.js} +1 -1
  59. package/dist/setup-plugin-api.js +1 -1
  60. package/dist/{shared-Dii2HTn7.js → shared-BNesVA4P.js} +17 -14
  61. package/dist/{subagent-hooks-JyGrtQIl.js → subagent-hooks-IeZVPLGj.js} +2 -2
  62. package/dist/subagent-hooks-api.js +1 -1
  63. package/dist/{system-events-BEmcj4xJ.js → system-events-Be5EJI3b.js} +2 -2
  64. package/dist/{target-resolver-V-IYae6s.js → target-resolver-C0MnwEki.js} +6 -5
  65. package/dist/targets-DQSye1Rv.js +3 -0
  66. package/dist/{thread-bindings-DvYP79fy.js → thread-bindings-wECUSIIG.js} +6 -5
  67. package/dist/{thread-bindings.manager-Clm77DBM.js → thread-bindings.manager-B-3UHCc1.js} +28 -25
  68. package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-CC7HoQvt.js} +2 -1
  69. package/dist/{threading-CXuu_7o9.js → threading-te5ADPQI.js} +8 -6
  70. package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
  71. package/dist/{transcripts-source-BLEMH_yi.js → transcripts-source-DkUhR7YK.js} +3 -3
  72. package/dist/transcripts-source-api.js +1 -1
  73. package/dist/{typing-B9snnwMe.js → typing-DAwJF5VT.js} +2 -2
  74. package/dist/{voice-runtime-DY6_o73o.js → voice-runtime-COyYYTDD.js} +348 -14
  75. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
  76. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
  77. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
  78. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
  79. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
  80. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
  81. package/node_modules/typebox/build/format/email.mjs +1 -1
  82. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  83. package/node_modules/typebox/package.json +1 -1
  84. package/openclaw.plugin.json +2 -2
  85. package/package.json +5 -5
  86. package/dist/account-inspect-BDfKyuvL.js +0 -89
  87. package/dist/provider.runtime-DiInaDXO.js +0 -2
  88. package/dist/sdk-runtime-6tfgYDjY.js +0 -338
  89. package/dist/targets-CQp53cGj.js +0 -3
@@ -1,6 +1,6 @@
1
- import { Tt as createThread, c as createDiscordSendResult, s as createDiscordSendReceiptFromResults, u as createReusableDiscordReplyReference, wt as createChannelMessage } from "./retry-DqHCW6PV.js";
2
- import { i as normalizeDiscordHandleKey, o as resolveDiscordDirectoryUserId } from "./directory-live-DuAXKkan.js";
3
- import { A as resolveDiscordSendComponents, D as buildDiscordMessageRequest, K as parseAndResolveChannelRecipient, M as resolveDiscordSuppressEmbeds, N as createDiscordClient, O as createDiscordMessageNonce, a as normalizeDiscordPollInput, c as normalizeStickerIds, f as sendDiscordMedia, j as resolveDiscordSendEmbeds, k as resolveDiscordMessageFlags, l as resolveChannelId, n as buildDiscordTextChunks, p as sendDiscordText, t as buildDiscordSendError, u as resolveDiscordChannel } from "./send.shared-DZJ1akvQ.js";
1
+ import { Tt as createThread, c as createDiscordSendResult, s as createDiscordSendReceiptFromResults, u as createReusableDiscordReplyReference, wt as createChannelMessage } from "./retry-t5RcEsPk.js";
2
+ import { i as normalizeDiscordHandleKey, o as resolveDiscordDirectoryUserId } from "./directory-live-D_kFz_Fj.js";
3
+ import { A as resolveDiscordSendComponents, D as buildDiscordMessageRequest, K as parseAndResolveChannelRecipient, M as resolveDiscordSuppressEmbeds, N as createDiscordClient, O as createDiscordMessageNonce, a as normalizeDiscordPollInput, c as normalizeStickerIds, f as sendDiscordMedia, j as resolveDiscordSendEmbeds, k as resolveDiscordMessageFlags, l as resolveChannelId, n as buildDiscordTextChunks, p as sendDiscordText, t as buildDiscordSendError, u as resolveDiscordChannel } from "./send.shared-BJHt0Vyf.js";
4
4
  import { ChannelType } from "discord-api-types/v10";
5
5
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
6
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -247,10 +247,12 @@ function normalizeDiscordBold(markdown) {
247
247
  for (const edit of edits) {
248
248
  while ((protectedRanges[rangeIndex]?.end ?? Number.POSITIVE_INFINITY) <= edit.start) rangeIndex += 1;
249
249
  const range = protectedRanges[rangeIndex];
250
- if (range && (edit.consume === 0 ? edit.start >= range.start && edit.start < range.end : edit.start < range.end && edit.start + edit.consume > range.start)) if (edit.delimiter) protectedSpanIds.add(edit.spanId);
251
- else {
252
- protectedEditKeys.add(`${edit.start}:${edit.consume}:${edit.marker}`);
253
- spansWithProtectedContent.add(edit.spanId);
250
+ if (range && (edit.consume === 0 ? edit.start >= range.start && edit.start < range.end : edit.start < range.end && edit.start + edit.consume > range.start)) {
251
+ if (edit.delimiter) protectedSpanIds.add(edit.spanId);
252
+ else {
253
+ protectedEditKeys.add(`${edit.start}:${edit.consume}:${edit.marker}`);
254
+ spansWithProtectedContent.add(edit.spanId);
255
+ }
254
256
  }
255
257
  }
256
258
  for (const spanId of spansWithProtectedContent) {
@@ -420,14 +422,16 @@ async function sendDiscordThreadTextChunks(params) {
420
422
  allowedMentions: params.allowedMentions,
421
423
  maxChars: params.maxChars,
422
424
  onResult: params.onResult,
423
- onPlatformSendDispatch: params.onPlatformSendDispatch
425
+ onPlatformSendDispatch: params.onPlatformSendDispatch,
426
+ assertPlatformSendAuthorized: params.assertPlatformSendAuthorized
424
427
  });
425
428
  }
426
429
  /** Discord thread names are capped at 100 characters. */
427
430
  const DISCORD_THREAD_NAME_LIMIT = 100;
428
431
  /** Derive a thread title from the first non-empty line of the message text. */
429
432
  function deriveForumThreadName(text) {
430
- return truncateUtf16Safe(normalizeOptionalString(text.split("\n").find((line) => normalizeOptionalString(line))) ?? "", DISCORD_THREAD_NAME_LIMIT) || (/* @__PURE__ */ new Date()).toISOString().slice(0, 16);
433
+ const firstLine = normalizeOptionalString(text.split("\n").find((line) => normalizeOptionalString(line))) ?? "";
434
+ return truncateUtf16Safe(firstLine, DISCORD_THREAD_NAME_LIMIT) || (/* @__PURE__ */ new Date()).toISOString().slice(0, 16);
431
435
  }
432
436
  /** Forum/Media channels cannot receive regular messages; detect them here. */
433
437
  function isForumLikeChannel(channel) {
@@ -449,7 +453,8 @@ async function resolveDiscordSendTarget(to, opts) {
449
453
  ...opts,
450
454
  cfg
451
455
  });
452
- const { channelId } = await resolveChannelId(rest, await parseAndResolveChannelRecipient(to, cfg, account.accountId), request);
456
+ const recipient = await parseAndResolveChannelRecipient(to, cfg, account.accountId);
457
+ const { channelId } = await resolveChannelId(rest, recipient, request);
453
458
  return {
454
459
  rest,
455
460
  request,
@@ -482,7 +487,8 @@ async function sendMessageDiscord(to, text, opts) {
482
487
  accountId: accountInfo.accountId,
483
488
  mentionAliases: accountInfo.config.mentionAliases
484
489
  });
485
- const { channelId } = await resolveChannelId(rest, await parseAndResolveChannelRecipient(to, cfg, accountInfo.accountId), request);
490
+ const recipient = await parseAndResolveChannelRecipient(to, cfg, accountInfo.accountId);
491
+ const { channelId } = await resolveChannelId(rest, recipient, request);
486
492
  const channel = await resolveDiscordChannel(rest, channelId);
487
493
  const deliveredResults = [];
488
494
  let deliveryThreadId;
@@ -513,21 +519,23 @@ async function sendMessageDiscord(to, text, opts) {
513
519
  embeds: opts.embeds,
514
520
  isFirst: true
515
521
  });
522
+ const starterFlags = resolveDiscordMessageFlags({
523
+ silent: opts.silent,
524
+ suppressEmbeds: suppressEmbeds && !starterEmbeds?.length
525
+ });
516
526
  const starterBody = buildDiscordMessageRequest({
517
527
  endpoint: "forum-thread",
518
528
  text: starterContent,
519
529
  components: starterComponents,
520
530
  embeds: starterEmbeds,
521
- flags: resolveDiscordMessageFlags({
522
- silent: opts.silent,
523
- suppressEmbeds: suppressEmbeds && !starterEmbeds?.length
524
- }),
531
+ flags: starterFlags,
525
532
  allowedMentions: opts.allowedMentions
526
533
  });
527
534
  let threadRes;
528
535
  try {
529
536
  threadRes = await request(async () => {
530
537
  await opts.onPlatformSendDispatch?.();
538
+ opts.assertPlatformSendAuthorized?.();
531
539
  return createThread(rest, channelId, { body: {
532
540
  name: threadName,
533
541
  ...channel.default_auto_archive_duration === void 0 ? {} : { auto_archive_duration: channel.default_auto_archive_duration },
@@ -578,7 +586,8 @@ async function sendMessageDiscord(to, text, opts) {
578
586
  allowedMentions: opts.allowedMentions,
579
587
  maxChars: textLimit,
580
588
  onResult: reportResult,
581
- onPlatformSendDispatch: opts.onPlatformSendDispatch
589
+ onPlatformSendDispatch: opts.onPlatformSendDispatch,
590
+ assertPlatformSendAuthorized: opts.assertPlatformSendAuthorized
582
591
  });
583
592
  await sendDiscordThreadTextChunks({
584
593
  rest,
@@ -592,7 +601,8 @@ async function sendMessageDiscord(to, text, opts) {
592
601
  suppressEmbeds,
593
602
  allowedMentions: opts.allowedMentions,
594
603
  onResult: reportResult,
595
- onPlatformSendDispatch: opts.onPlatformSendDispatch
604
+ onPlatformSendDispatch: opts.onPlatformSendDispatch,
605
+ assertPlatformSendAuthorized: opts.assertPlatformSendAuthorized
596
606
  });
597
607
  } else await sendDiscordThreadTextChunks({
598
608
  rest,
@@ -606,7 +616,8 @@ async function sendMessageDiscord(to, text, opts) {
606
616
  suppressEmbeds,
607
617
  allowedMentions: opts.allowedMentions,
608
618
  onResult: reportResult,
609
- onPlatformSendDispatch: opts.onPlatformSendDispatch
619
+ onPlatformSendDispatch: opts.onPlatformSendDispatch,
620
+ assertPlatformSendAuthorized: opts.assertPlatformSendAuthorized
610
621
  });
611
622
  } catch (err) {
612
623
  throw await buildDiscordSendError(err, {
@@ -653,7 +664,8 @@ async function sendMessageDiscord(to, text, opts) {
653
664
  allowedMentions: opts.allowedMentions,
654
665
  maxChars: textLimit,
655
666
  onResult: reportResult,
656
- onPlatformSendDispatch: opts.onPlatformSendDispatch
667
+ onPlatformSendDispatch: opts.onPlatformSendDispatch,
668
+ assertPlatformSendAuthorized: opts.assertPlatformSendAuthorized
657
669
  });
658
670
  else result = await sendDiscordText({
659
671
  rest,
@@ -670,7 +682,8 @@ async function sendMessageDiscord(to, text, opts) {
670
682
  allowedMentions: opts.allowedMentions,
671
683
  maxChars: textLimit,
672
684
  onResult: reportResult,
673
- onPlatformSendDispatch: opts.onPlatformSendDispatch
685
+ onPlatformSendDispatch: opts.onPlatformSendDispatch,
686
+ assertPlatformSendAuthorized: opts.assertPlatformSendAuthorized
674
687
  });
675
688
  } catch (err) {
676
689
  throw await buildDiscordSendError(err, {
@@ -735,6 +748,7 @@ async function resolveDiscordStructuredSendContext(to, opts) {
735
748
  send: async (kind, body) => {
736
749
  const result = await request(async () => {
737
750
  await opts.onPlatformSendDispatch?.();
751
+ opts.assertPlatformSendAuthorized?.();
738
752
  return createChannelMessage(rest, channelId, { body });
739
753
  }, kind, { safety: "nonce-protected-create" });
740
754
  recordChannelActivity({
@@ -1,6 +1,6 @@
1
- import { At as getChannel, J as Embed, Jt as getGuildMember, K as hasDiscordV2Components, Mt as getThreadMember, P as RequestClient, a as chunkDiscordTextWithMode, bt as getCurrentUser, d as resolveDiscordReplyMessageId, n as createDiscordRetryRunner, q as serializePayload, qt as getGuild, wt as createChannelMessage, yt as createUserDmChannel } from "./retry-DqHCW6PV.js";
2
- import { c as resolveDiscordAccount, m as normalizeDiscordToken, o as mergeDiscordAccountConfig } from "./accounts-CfQ-vSyf.js";
3
- import { t as parseAndResolveDiscordTarget } from "./target-resolver-V-IYae6s.js";
1
+ import { At as getChannel, J as Embed, Jt as getGuildMember, K as hasDiscordV2Components, Mt as getThreadMember, P as RequestClient, a as chunkDiscordTextWithMode, bt as getCurrentUser, d as resolveDiscordReplyMessageId, n as createDiscordRetryRunner, q as serializePayload, qt as getGuild, wt as createChannelMessage, yt as createUserDmChannel } from "./retry-t5RcEsPk.js";
2
+ import { c as resolveDiscordAccount, m as normalizeDiscordToken, o as mergeDiscordAccountConfig } from "./accounts-CwJQoLjM.js";
3
+ import { t as parseAndResolveDiscordTarget } from "./target-resolver-C0MnwEki.js";
4
4
  import { t as isDiscordThreadChannelType } from "./channel-type-CVLZyGYS.js";
5
5
  import { ChannelType, MessageFlags, PermissionFlagsBits } from "discord-api-types/v10";
6
6
  import { randomBytes } from "node:crypto";
@@ -18,12 +18,13 @@ import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
18
18
  async function parseAndResolveRecipient(raw, cfg, accountId, parseOptions = {}) {
19
19
  if (!cfg) throw new Error("Discord recipient resolution requires a resolved runtime config. Load and resolve config at the command or gateway boundary, then pass cfg through the runtime path.");
20
20
  const resolvedCfg = requireRuntimeConfig(cfg, "Discord recipient resolution");
21
+ const accountInfo = resolveDiscordAccount({
22
+ cfg: resolvedCfg,
23
+ accountId
24
+ });
21
25
  const resolved = await parseAndResolveDiscordTarget(raw, {
22
26
  cfg: resolvedCfg,
23
- accountId: resolveDiscordAccount({
24
- cfg: resolvedCfg,
25
- accountId
26
- }).accountId
27
+ accountId: accountInfo.accountId
27
28
  }, parseOptions);
28
29
  return {
29
30
  kind: resolved.kind,
@@ -31,8 +32,9 @@ async function parseAndResolveRecipient(raw, cfg, accountId, parseOptions = {})
31
32
  };
32
33
  }
33
34
  async function parseAndResolveChannelRecipient(raw, cfg, accountId) {
35
+ const resolvedCfg = requireRuntimeConfig(cfg, "Discord recipient resolution");
34
36
  const resolved = await parseAndResolveDiscordTarget(raw, {
35
- cfg: requireRuntimeConfig(cfg, "Discord recipient resolution"),
37
+ cfg: resolvedCfg,
36
38
  accountId
37
39
  }, { defaultKind: "channel" });
38
40
  return {
@@ -512,9 +514,9 @@ var DiscordSendError = class extends Error {
512
514
  return this.message;
513
515
  }
514
516
  };
515
- const DISCORD_MAX_EMOJI_BYTES = 256 * 1024;
516
- const DISCORD_MAX_STICKER_BYTES = 512 * 1024;
517
- const DISCORD_MAX_EVENT_COVER_BYTES = 8 * 1024 * 1024;
517
+ const DISCORD_MAX_EMOJI_BYTES = 262144;
518
+ const DISCORD_MAX_STICKER_BYTES = 524288;
519
+ const DISCORD_MAX_EVENT_COVER_BYTES = 8388608;
518
520
  //#endregion
519
521
  //#region extensions/discord/src/send.shared.ts
520
522
  const DISCORD_TEXT_LIMIT = 2e3;
@@ -637,14 +639,15 @@ async function resolveDiscordChannel(rest, channelId) {
637
639
  }
638
640
  function buildDiscordTextChunks(text, opts = {}) {
639
641
  if (!text) return [];
640
- return resolveTextChunksWithFallback(text, chunkDiscordTextWithMode(text, {
642
+ const chunks = chunkDiscordTextWithMode(text, {
641
643
  maxChars: opts.maxChars ?? DISCORD_TEXT_LIMIT,
642
644
  maxLines: opts.maxLinesPerMessage,
643
645
  chunkMode: opts.chunkMode
644
- }));
646
+ });
647
+ return resolveTextChunksWithFallback(text, chunks);
645
648
  }
646
649
  async function sendDiscordText(params) {
647
- const { rest, channelId, text, request, reply, maxLinesPerMessage, components, embeds, allowedMentions, chunkMode, silent, suppressEmbeds, maxChars, onResult, onPlatformSendDispatch } = params;
650
+ const { rest, channelId, text, request, reply, maxLinesPerMessage, components, embeds, allowedMentions, chunkMode, silent, suppressEmbeds, maxChars, onResult, onPlatformSendDispatch, assertPlatformSendAuthorized } = params;
648
651
  const chunks = buildDiscordTextChunks(text, {
649
652
  maxLinesPerMessage,
650
653
  chunkMode,
@@ -680,6 +683,7 @@ async function sendDiscordText(params) {
680
683
  return {
681
684
  result: await request(async () => {
682
685
  await onPlatformSendDispatch?.();
686
+ assertPlatformSendAuthorized?.();
683
687
  return createChannelMessage(rest, channelId, { body });
684
688
  }, "text", { safety: "nonce-protected-create" }),
685
689
  replyToId: chunkReplyTo,
@@ -709,7 +713,7 @@ async function sendDiscordText(params) {
709
713
  };
710
714
  }
711
715
  async function sendDiscordMedia(params) {
712
- const { rest, channelId, text, mediaUrl, filename, mediaAccess, mediaLocalRoots, mediaReadFile, maxBytes, reply, request, maxLinesPerMessage, components, embeds, allowedMentions, chunkMode, silent, suppressEmbeds, maxChars, onResult, onPlatformSendDispatch } = params;
716
+ const { rest, channelId, text, mediaUrl, filename, mediaAccess, mediaLocalRoots, mediaReadFile, maxBytes, reply, request, maxLinesPerMessage, components, embeds, allowedMentions, chunkMode, silent, suppressEmbeds, maxChars, onResult, onPlatformSendDispatch, assertPlatformSendAuthorized } = params;
713
717
  const media = await loadWebMedia(mediaUrl, buildOutboundMediaLoadOptions({
714
718
  maxBytes,
715
719
  mediaAccess,
@@ -753,6 +757,7 @@ async function sendDiscordMedia(params) {
753
757
  try {
754
758
  res = await request(async () => {
755
759
  await onPlatformSendDispatch?.();
760
+ assertPlatformSendAuthorized?.();
756
761
  return createChannelMessage(rest, channelId, { body });
757
762
  }, "media", { safety: "nonce-protected-create" });
758
763
  } catch (err) {
@@ -770,7 +775,8 @@ async function sendDiscordMedia(params) {
770
775
  allowedMentions,
771
776
  maxChars,
772
777
  onResult,
773
- onPlatformSendDispatch
778
+ onPlatformSendDispatch,
779
+ assertPlatformSendAuthorized
774
780
  });
775
781
  }
776
782
  await onResult?.(res, "media", reply?.messageId);
@@ -791,7 +797,8 @@ async function sendDiscordMedia(params) {
791
797
  allowedMentions,
792
798
  maxChars,
793
799
  onResult,
794
- onPlatformSendDispatch
800
+ onPlatformSendDispatch,
801
+ assertPlatformSendAuthorized
795
802
  });
796
803
  for (const id of followup.platformMessageIds) if (id) platformMessageIds.push(id);
797
804
  }
@@ -1,4 +1,4 @@
1
- import { x as formatDiscordUserTag } from "./allow-list-BDMimASD.js";
1
+ import { x as formatDiscordUserTag } from "./allow-list-C2JuH-R0.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-rPs4dsk_.js";
1
+ import { t as discordSetupPlugin } from "./channel.setup-z_ewMVa9.js";
2
2
  export { discordSetupPlugin };
@@ -1,9 +1,9 @@
1
- import { c as resolveDiscordAccount, d as resolveDiscordAccountDisabledReason, f as resolveDiscordAccountDmPolicy, l as resolveDiscordAccountAllowFrom, n as isDiscordAccountEnabledForRuntime, o as mergeDiscordAccountConfig, r as listDiscordAccountIds, s as resolveDefaultDiscordAccountId } from "./accounts-CfQ-vSyf.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-BDfKyuvL.js";
3
- import { t as discordIngressIdentity } from "./ingress-identity-CzZKcPK8.js";
4
- import { t as DiscordChannelConfigSchema } from "./config-schema-CxPqtVI1.js";
5
- import { n as normalizeCompatibilityConfig } from "./doctor-contract-DsWvKIXF.js";
6
- import { r as secretTargetRegistryEntries, t as collectRuntimeConfigAssignments } from "./secret-config-contract-B3i6WxV5.js";
1
+ import { c as resolveDiscordAccount, d as resolveDiscordAccountDisabledReason, f as resolveDiscordAccountDmPolicy, l as resolveDiscordAccountAllowFrom, n as isDiscordAccountEnabledForRuntime, o as mergeDiscordAccountConfig, r as listDiscordAccountIds, s as resolveDefaultDiscordAccountId } from "./accounts-CwJQoLjM.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-BY-ve3yH.js";
3
+ import { t as discordIngressIdentity } from "./ingress-identity-BCzfPPYM.js";
4
+ import { t as DiscordChannelConfigSchema } from "./config-schema-B797-Spt.js";
5
+ import { n as normalizeCompatibilityConfig } from "./doctor-contract-Co5vRCZ6.js";
6
+ import { r as secretTargetRegistryEntries, t as collectRuntimeConfigAssignments } from "./secret-config-contract-DFu9hfU8.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";
9
9
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
@@ -81,6 +81,15 @@ const discordSecurityAdapter = {
81
81
  collectWarnings: collectDiscordSecurityFindings,
82
82
  collectAuditFindings: async (params) => (await loadDiscordSecurityAuditModule()).collectDiscordSecurityAuditFindings(params)
83
83
  };
84
+ //#endregion
85
+ //#region extensions/discord/src/setup-adapter.ts
86
+ const discordSetupAdapter = createEnvPatchedAccountSetupAdapter({
87
+ channelKey: "discord",
88
+ defaultAccountOnlyEnvError: "DISCORD_BOT_TOKEN can only be used for the default account.",
89
+ missingCredentialError: "Discord requires token (or --use-env).",
90
+ hasCredentials: (input) => Boolean(input.token),
91
+ buildPatch: (input) => input.token ? { token: input.token } : {}
92
+ });
84
93
  const discordSetupContract = defineChannelSetupContract({
85
94
  fields: {
86
95
  token: {
@@ -100,13 +109,7 @@ const discordSetupContract = defineChannelSetupContract({
100
109
  envVars: ["DISCORD_BOT_TOKEN"]
101
110
  }
102
111
  },
103
- legacyAdapter: createEnvPatchedAccountSetupAdapter({
104
- channelKey: "discord",
105
- defaultAccountOnlyEnvError: "DISCORD_BOT_TOKEN can only be used for the default account.",
106
- missingCredentialError: "Discord requires token (or --use-env).",
107
- hasCredentials: (input) => Boolean(input.token),
108
- buildPatch: (input) => input.token ? { token: input.token } : {}
109
- })
112
+ legacyAdapter: discordSetupAdapter
110
113
  });
111
114
  //#endregion
112
115
  //#region extensions/discord/src/doctor-shared.ts
@@ -114,7 +117,7 @@ const DISCORD_LEGACY_CONFIG_RULES = [];
114
117
  //#endregion
115
118
  //#region extensions/discord/src/shared.ts
116
119
  const DISCORD_CHANNEL = "discord";
117
- const loadDiscordDoctorModule = createLazyRuntimeModule(() => import("./doctor-zQTtn6hm.js"));
120
+ const loadDiscordDoctorModule = createLazyRuntimeModule(() => import("./doctor-QQTOkBfW.js"));
118
121
  const discordDoctor = {
119
122
  dmAllowFromMode: "topOnly",
120
123
  groupModel: "route",
@@ -1,5 +1,5 @@
1
- import { on as __exportAll } from "./retry-DqHCW6PV.js";
2
- import { o as unbindThreadBindingsBySessionKey, r as listThreadBindingsBySessionKey } from "./thread-bindings-DvYP79fy.js";
1
+ import { on as __exportAll } from "./retry-t5RcEsPk.js";
2
+ import { o as unbindThreadBindingsBySessionKey, r as listThreadBindingsBySessionKey } from "./thread-bindings-wECUSIIG.js";
3
3
  import { normalizeOptionalLowercaseString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  //#region extensions/discord/src/subagent-hooks.ts
5
5
  var subagent_hooks_exports = /* @__PURE__ */ __exportAll({
@@ -1,6 +1,6 @@
1
1
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
2
2
  //#region extensions/discord/subagent-hooks-api.ts
3
- const loadDiscordSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-JyGrtQIl.js").then((n) => n.r));
3
+ const loadDiscordSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-IeZVPLGj.js").then((n) => n.r));
4
4
  function registerDiscordSubagentHooks(api) {
5
5
  api.on("subagent_ended", async (event) => {
6
6
  const { handleDiscordSubagentEnded } = await loadDiscordSubagentHooksModule();
@@ -1,5 +1,5 @@
1
- import { y as discord_exports } from "./retry-DqHCW6PV.js";
2
- import { x as formatDiscordUserTag } from "./allow-list-BDMimASD.js";
1
+ import { y as discord_exports } from "./retry-t5RcEsPk.js";
2
+ import { x as formatDiscordUserTag } from "./allow-list-C2JuH-R0.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 { _ as parseDiscordTarget, on as __exportAll, p as allowFromContainsDiscordUserId } from "./retry-DqHCW6PV.js";
2
- import { c as resolveDiscordAccount, l as resolveDiscordAccountAllowFrom } from "./accounts-CfQ-vSyf.js";
3
- import { a as rememberDiscordDirectoryUser, r as listDiscordDirectoryPeersLive } from "./directory-live-DuAXKkan.js";
1
+ import { _ as parseDiscordTarget, on as __exportAll, p as allowFromContainsDiscordUserId } from "./retry-t5RcEsPk.js";
2
+ import { c as resolveDiscordAccount, l as resolveDiscordAccountAllowFrom } from "./accounts-CwJQoLjM.js";
3
+ import { a as rememberDiscordDirectoryUser, r as listDiscordDirectoryPeersLive } from "./directory-live-D_kFz_Fj.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);
@@ -62,10 +62,11 @@ function safeParseDiscordTarget(input, options) {
62
62
  }
63
63
  }
64
64
  function isConfiguredAllowedDiscordDmUser(input, options) {
65
- return allowFromContainsDiscordUserId(resolveDiscordAccountAllowFrom({
65
+ const allowFrom = resolveDiscordAccountAllowFrom({
66
66
  cfg: options.cfg,
67
67
  accountId: options.accountId
68
- }) ?? [], input);
68
+ }) ?? [];
69
+ return allowFromContainsDiscordUserId(allowFrom, input);
69
70
  }
70
71
  function isExplicitUserLookup(input, options) {
71
72
  if (/^<@!?(\d+)>$/.test(input)) return true;
@@ -0,0 +1,3 @@
1
+ import "./retry-t5RcEsPk.js";
2
+ import "./target-resolver-C0MnwEki.js";
3
+ export {};
@@ -1,8 +1,8 @@
1
- import { _ as parseDiscordTarget, on as __exportAll } from "./retry-DqHCW6PV.js";
2
- import "./targets-CQp53cGj.js";
1
+ import { _ as parseDiscordTarget, on as __exportAll } from "./retry-t5RcEsPk.js";
2
+ import "./targets-DQSye1Rv.js";
3
3
  import { C as resolveThreadBindingMaxAgeExpiresAt, O as shouldPersistBindingMutations, S as resolveThreadBindingInactivityExpiresAt, T as saveBindingsToDisk, h as refreshUnboundThreadWebhookIdentity, m as normalizeThreadId, n as MANAGERS_BY_ACCOUNT_ID, t as BINDINGS_BY_THREAD_ID, u as getThreadBindingToken, v as removeBindingRecord, w as resolveThreadBindingMaxAgeMs$1, x as resolveThreadBindingIdleTimeoutMs$1 } from "./thread-bindings.state-D8OMdk4O.js";
4
- import { n as setThreadBindingMaxAgeBySessionKey, r as resolveBindingIdsForTargetSession, t as setThreadBindingIdleTimeoutBySessionKey } from "./thread-bindings.session-updates-CJb-BpPL.js";
5
- import { _ as resolveThreadBindingThreadName, g as resolveThreadBindingIntroText, h as formatThreadBindingDurationLabel, m as resolveThreadBindingPersonaFromRecord, n as createThreadBindingManager, o as resolveChannelIdForBinding, p as resolveThreadBindingPersona, r as getThreadBindingManager, t as createNoopThreadBindingManager } from "./thread-bindings.manager-Clm77DBM.js";
4
+ import { n as setThreadBindingMaxAgeBySessionKey, r as resolveBindingIdsForTargetSession, t as setThreadBindingIdleTimeoutBySessionKey } from "./thread-bindings.session-updates-CC7HoQvt.js";
5
+ import { _ as resolveThreadBindingThreadName, g as resolveThreadBindingIntroText, h as formatThreadBindingDurationLabel, m as resolveThreadBindingPersonaFromRecord, n as createThreadBindingManager, o as resolveChannelIdForBinding, p as resolveThreadBindingPersona, r as getThreadBindingManager, t as createNoopThreadBindingManager } from "./thread-bindings.manager-B-3UHCc1.js";
6
6
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
7
7
  import { normalizeOptionalLowercaseString, normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { resolveThreadBindingIdleTimeoutMs, resolveThreadBindingMaxAgeMs, resolveThreadBindingsEnabled } from "openclaw/plugin-sdk/conversation-runtime";
@@ -141,7 +141,8 @@ async function reconcileAcpThreadBindingsOnStartup(params) {
141
141
  }
142
142
  const session = readAcpSessionEntry({
143
143
  cfg: params.cfg,
144
- sessionKey
144
+ sessionKey,
145
+ agentId: binding.agentId
145
146
  });
146
147
  if (!session) {
147
148
  staleBindings.push(binding);
@@ -1,8 +1,8 @@
1
- import { At as getChannel, on as __exportAll, v as resolveDiscordChannelId, vt as createChannelWebhook } from "./retry-DqHCW6PV.js";
2
- import { P as createDiscordRestClient } from "./send.shared-DZJ1akvQ.js";
3
- import { t as sendMessageDiscord } from "./send.outbound-D7JYmfm9.js";
1
+ import { At as getChannel, on as __exportAll, v as resolveDiscordChannelId, vt as createChannelWebhook } from "./retry-t5RcEsPk.js";
2
+ import { P as createDiscordRestClient } from "./send.shared-BJHt0Vyf.js";
3
+ import { t as sendMessageDiscord } from "./send.outbound-CaOs9Zy1.js";
4
4
  import { t as isDiscordThreadChannelType } from "./channel-type-CVLZyGYS.js";
5
- import { c as sendWebhookMessageDiscord, u as createThreadDiscord } from "./send-UJHiAm4C.js";
5
+ import { c as sendWebhookMessageDiscord, u as createThreadDiscord } from "./send-mTKSBdmZ.js";
6
6
  import { A as toReusableWebhookKey, C as resolveThreadBindingMaxAgeExpiresAt, D as shouldDefaultPersist, E as setBindingRecord, S as resolveThreadBindingInactivityExpiresAt, T as saveBindingsToDisk, _ as rememberThreadBindingToken, b as resolveBindingRecordKey, c as ensureBindingsLoaded, f as normalizeTargetKind, g as rememberReusableWebhook, h as refreshUnboundThreadWebhookIdentity, i as REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL, l as forgetThreadBindingToken, m as normalizeThreadId, n as MANAGERS_BY_ACCOUNT_ID, p as normalizeThreadBindingDurationMs, 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 removeBindingRecord, w as resolveThreadBindingMaxAgeMs$1, x as resolveThreadBindingIdleTimeoutMs$1, y as resolveBindingIdsForSession } from "./thread-bindings.state-D8OMdk4O.js";
7
7
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
8
8
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
@@ -20,7 +20,8 @@ function normalizePersonaLabel(value) {
20
20
  return value.replace(/\s+/g, " ").trim() || void 0;
21
21
  }
22
22
  function resolveThreadBindingPersona(params) {
23
- return truncateUtf16Safe(`${SYSTEM_MARK} ${normalizePersonaLabel(params.label) || normalizePersonaLabel(params.agentId) || "agent"}`, THREAD_BINDING_PERSONA_MAX_CHARS);
23
+ const base = normalizePersonaLabel(params.label) || normalizePersonaLabel(params.agentId) || "agent";
24
+ return truncateUtf16Safe(`${SYSTEM_MARK} ${base}`, THREAD_BINDING_PERSONA_MAX_CHARS);
24
25
  }
25
26
  function resolveThreadBindingPersonaFromRecord(record) {
26
27
  return resolveThreadBindingPersona({
@@ -92,7 +93,7 @@ function resolveDiscordChannelInfoSafe(channel) {
92
93
  //#endregion
93
94
  //#region extensions/discord/src/monitor/thread-bindings.types.ts
94
95
  const THREAD_BINDINGS_SWEEP_INTERVAL_MS = 12e4;
95
- const DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS = 1440 * 60 * 1e3;
96
+ const DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS = 864e5;
96
97
  //#endregion
97
98
  //#region extensions/discord/src/monitor/thread-bindings.discord-api.ts
98
99
  function buildThreadTarget(threadId) {
@@ -232,11 +233,12 @@ async function resolveChannelIdForBinding(params) {
232
233
  }
233
234
  async function createThreadForBinding(params) {
234
235
  try {
235
- return (normalizeOptionalString((await createThreadDiscord(params.channelId, { name: params.threadName }, {
236
+ const created = await createThreadDiscord(params.channelId, { name: params.threadName }, {
236
237
  cfg: params.cfg,
237
238
  accountId: params.accountId,
238
239
  token: params.token
239
- }))?.id) ?? "") || null;
240
+ });
241
+ return (normalizeOptionalString(created?.id) ?? "") || null;
240
242
  } catch (err) {
241
243
  logVerbose(`discord thread binding auto-thread create failed for ${params.channelId}: ${summarizeDiscordError(err)}`);
242
244
  return null;
@@ -400,12 +402,6 @@ var thread_bindings_manager_exports = /* @__PURE__ */ __exportAll({
400
402
  createThreadBindingManager: () => createThreadBindingManager,
401
403
  getThreadBindingManager: () => getThreadBindingManager
402
404
  });
403
- function registerManager(manager) {
404
- MANAGERS_BY_ACCOUNT_ID.set(manager.accountId, manager);
405
- }
406
- function unregisterManager(accountId, manager) {
407
- if (MANAGERS_BY_ACCOUNT_ID.get(accountId) === manager) MANAGERS_BY_ACCOUNT_ID.delete(accountId);
408
- }
409
405
  function createNoopManager(accountIdRaw) {
410
406
  return {
411
407
  accountId: normalizeAccountId(accountIdRaw),
@@ -447,13 +443,14 @@ function createThreadBindingManager(params) {
447
443
  const maxAgeMs = normalizeThreadBindingDurationMs(params.maxAgeMs, 0);
448
444
  const resolveCurrentCfg = () => getRuntimeConfigSnapshot() ?? params.cfg;
449
445
  const resolveCurrentToken = () => getThreadBindingToken(accountId) ?? params.token;
446
+ const getCurrentBinding = (threadId) => MANAGERS_BY_ACCOUNT_ID.get(accountId) === manager ? manager.getByThreadId(threadId) : void 0;
450
447
  let sweepTimer = null;
451
448
  const runSweepOnce = async () => {
452
449
  const bindings = manager.listBindings();
453
450
  if (bindings.length === 0) return;
454
451
  let rest = null;
455
452
  for (const snapshotBinding of bindings) {
456
- const binding = manager.getByThreadId(snapshotBinding.threadId);
453
+ const binding = getCurrentBinding(snapshotBinding.threadId);
457
454
  if (!binding) continue;
458
455
  const now = Date.now();
459
456
  const inactivityExpiresAt = resolveThreadBindingInactivityExpiresAt({
@@ -496,8 +493,9 @@ function createThreadBindingManager(params) {
496
493
  }
497
494
  if (isDirectConversationBindingId(binding.threadId)) continue;
498
495
  if (!rest) try {
496
+ const cfg = resolveCurrentCfg();
499
497
  rest = createDiscordRestClient({
500
- cfg: resolveCurrentCfg(),
498
+ cfg,
501
499
  accountId,
502
500
  token: resolveCurrentToken()
503
501
  }).rest;
@@ -506,6 +504,7 @@ function createThreadBindingManager(params) {
506
504
  }
507
505
  try {
508
506
  const channel = await getChannel(rest, binding.threadId);
507
+ if (getCurrentBinding(binding.threadId) !== binding) continue;
509
508
  if (!channel || typeof channel !== "object") {
510
509
  logVerbose(`discord thread binding sweep probe returned invalid payload for ${binding.threadId}`);
511
510
  continue;
@@ -516,6 +515,7 @@ function createThreadBindingManager(params) {
516
515
  sendFarewell: true
517
516
  });
518
517
  } catch (err) {
518
+ if (getCurrentBinding(binding.threadId) !== binding) continue;
519
519
  if (isDiscordThreadGoneError(err)) {
520
520
  logVerbose(`discord thread binding sweep removing stale binding ${binding.threadId}: ${summarizeDiscordError(err)}`);
521
521
  manager.unbindThread({
@@ -604,6 +604,7 @@ function createThreadBindingManager(params) {
604
604
  const targetSessionKey = normalizeOptionalString(bindParams.targetSessionKey) ?? "";
605
605
  if (!targetSessionKey) return null;
606
606
  const targetKind = normalizeTargetKind(bindParams.targetKind, targetSessionKey);
607
+ const previous = existingValue?.targetSessionKey === targetSessionKey && existingValue.targetKind === targetKind ? existingValue : void 0;
607
608
  let webhookId = normalizeOptionalString(bindParams.webhookId) ?? normalizeOptionalString(existingValue?.webhookId) ?? "";
608
609
  let webhookToken = normalizeOptionalString(bindParams.webhookToken) ?? normalizeOptionalString(existingValue?.webhookToken) ?? "";
609
610
  if (!directConversationBinding && (!webhookId || !webhookToken)) {
@@ -631,22 +632,22 @@ function createThreadBindingManager(params) {
631
632
  threadId,
632
633
  targetKind,
633
634
  targetSessionKey,
634
- agentId: normalizeOptionalString(bindParams.agentId) ?? normalizeOptionalString(existingValue?.agentId) ?? resolveSessionAgentIdStrict({
635
+ agentId: normalizeOptionalString(bindParams.agentId) ?? normalizeOptionalString(previous?.agentId) ?? resolveSessionAgentIdStrict({
635
636
  config: cfg,
636
637
  sessionKey: targetSessionKey
637
638
  }),
638
- label: normalizeOptionalString(bindParams.label) ?? normalizeOptionalString(existingValue?.label),
639
+ label: normalizeOptionalString(bindParams.label) ?? normalizeOptionalString(previous?.label),
639
640
  webhookId: webhookId || void 0,
640
641
  webhookToken: webhookToken || void 0,
641
- boundBy: normalizeOptionalString(bindParams.boundBy) ?? normalizeOptionalString(existingValue?.boundBy) ?? "system",
642
+ boundBy: normalizeOptionalString(bindParams.boundBy) ?? normalizeOptionalString(previous?.boundBy) ?? "system",
642
643
  boundAt: now,
643
644
  lastActivityAt: now,
644
645
  idleTimeoutMs: typeof existingValue?.idleTimeoutMs === "number" ? existingValue.idleTimeoutMs : idleTimeoutMs,
645
646
  maxAgeMs: typeof existingValue?.maxAgeMs === "number" ? existingValue.maxAgeMs : maxAgeMs,
646
- metadata: bindParams.metadata && typeof bindParams.metadata === "object" ? {
647
- ...existingValue?.metadata,
647
+ metadata: {
648
+ ...previous?.metadata,
648
649
  ...bindParams.metadata
649
- } : existingValue?.metadata ? { ...existingValue.metadata } : void 0
650
+ }
650
651
  };
651
652
  setBindingRecord(record);
652
653
  if (persist) saveBindingsToDisk();
@@ -719,13 +720,15 @@ function createThreadBindingManager(params) {
719
720
  clearInterval(sweepTimer);
720
721
  sweepTimer = null;
721
722
  }
722
- unregisterManager(accountId, manager);
723
+ if (MANAGERS_BY_ACCOUNT_ID.get(accountId) === manager) {
724
+ MANAGERS_BY_ACCOUNT_ID.delete(accountId);
725
+ forgetThreadBindingToken(accountId);
726
+ }
723
727
  unregisterSessionBindingAdapter({
724
728
  channel: "discord",
725
729
  accountId,
726
730
  adapter: sessionBindingAdapter
727
731
  });
728
- forgetThreadBindingToken(accountId);
729
732
  }
730
733
  };
731
734
  if (params.enableSweeper !== false) {
@@ -745,7 +748,7 @@ function createThreadBindingManager(params) {
745
748
  resolveCurrentToken
746
749
  });
747
750
  registerSessionBindingAdapter(sessionBindingAdapter);
748
- registerManager(manager);
751
+ MANAGERS_BY_ACCOUNT_ID.set(accountId, manager);
749
752
  return manager;
750
753
  }
751
754
  function createNoopThreadBindingManager(accountId) {
@@ -9,9 +9,10 @@ function resolveBindingIdsForTargetSession(params) {
9
9
  ensureBindingsLoaded();
10
10
  const targetSessionKey = params.targetSessionKey.trim();
11
11
  if (!targetSessionKey) return [];
12
+ const accountId = params.accountId ? normalizeAccountId(params.accountId) : void 0;
12
13
  return resolveBindingIdsForSession({
13
14
  targetSessionKey,
14
- accountId: params.accountId ? normalizeAccountId(params.accountId) : void 0,
15
+ accountId,
15
16
  targetKind: params.targetKind
16
17
  });
17
18
  }
@@ -1,7 +1,7 @@
1
- import { F as DiscordError, Ot as editChannel, Tt as createThread, jt as getChannelMessage, on as __exportAll, y as discord_exports } from "./retry-DqHCW6PV.js";
1
+ import { F as DiscordError, Ot as editChannel, Tt as createThread, jt as getChannelMessage, on as __exportAll, y as discord_exports } from "./retry-t5RcEsPk.js";
2
2
  import { t as isDiscordThreadChannelType } from "./channel-type-CVLZyGYS.js";
3
- import { d as resolveDiscordChannelParentSafe, l as resolveDiscordChannelNameSafe, s as resolveDiscordChannelIdSafe, u as resolveDiscordChannelParentIdSafe } from "./thread-bindings.manager-Clm77DBM.js";
4
- import { a as formatDiscordMediaText, f as resolveDiscordChannelInfo, n as resolveDiscordForwardedMessagesTextFromSnapshots, p as resolveDiscordMessageChannelId, t as resolveDiscordEmbedText } from "./message-text-Ca8M6TU8.js";
3
+ import { d as resolveDiscordChannelParentSafe, l as resolveDiscordChannelNameSafe, s as resolveDiscordChannelIdSafe, u as resolveDiscordChannelParentIdSafe } from "./thread-bindings.manager-B-3UHCc1.js";
4
+ import { a as formatDiscordMediaText, h as resolveDiscordMessageChannelId, m as resolveDiscordChannelInfo, n as resolveDiscordForwardedMessagesTextFromSnapshots, t as resolveDiscordEmbedText } from "./message-text-C0K4-fkg.js";
5
5
  import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing";
6
6
  import { normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
@@ -100,8 +100,8 @@ function normalizeTitleContextField(raw, maxChars) {
100
100
  }
101
101
  //#endregion
102
102
  //#region extensions/discord/src/monitor/threading.cache.ts
103
- const DISCORD_THREAD_STARTER_CACHE_TTL_MS = 300 * 1e3;
104
- const DISCORD_THREAD_STARTER_NEGATIVE_CACHE_TTL_MS = 30 * 1e3;
103
+ const DISCORD_THREAD_STARTER_CACHE_TTL_MS = 3e5;
104
+ const DISCORD_THREAD_STARTER_NEGATIVE_CACHE_TTL_MS = 3e4;
105
105
  const DISCORD_THREAD_STARTER_CACHE_MAX = 500;
106
106
  const DISCORD_THREAD_STARTER_CACHE = /* @__PURE__ */ new Map();
107
107
  function getCachedThreadStarter(key, now) {
@@ -266,7 +266,9 @@ function resolveDiscordReplyTarget(opts) {
266
266
  return opts.hasReplied ? void 0 : replyToId;
267
267
  }
268
268
  function sanitizeDiscordThreadName(rawName, fallbackId) {
269
- return truncateUtf16Safe(truncateUtf16Safe(rawName.replace(/<@!?\d+>/g, "").replace(/<@&\d+>/g, "").replace(/<#\d+>/g, "").replace(/\s+/g, " ").trim() || `Thread ${fallbackId}`, 80), 100) || `Thread ${fallbackId}`;
269
+ const baseSource = rawName.replace(/<@!?\d+>/g, "").replace(/<@&\d+>/g, "").replace(/<#\d+>/g, "").replace(/\s+/g, " ").trim() || `Thread ${fallbackId}`;
270
+ const base = truncateUtf16Safe(baseSource, 80);
271
+ return truncateUtf16Safe(base, 100) || `Thread ${fallbackId}`;
270
272
  }
271
273
  function resolveDiscordReplyDeliveryPlan(params) {
272
274
  const originalReplyTarget = params.replyTarget;
@@ -1,7 +1,7 @@
1
1
  import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
2
2
  //#region extensions/discord/src/monitor/timeouts.ts
3
3
  const DISCORD_DEFAULT_LISTENER_TIMEOUT_MS = 12e4;
4
- const DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS = 30 * 6e4;
4
+ const DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS = 18e5;
5
5
  const DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS = 6e4;
6
6
  const DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS = 12e4;
7
7
  /** @deprecated Discord listener timeouts are compatibility-only. */