@openclaw/discord 2026.7.2-beta.7 → 2026.8.1-beta.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 (95) hide show
  1. package/dist/{account-inspect-SXiCBCgP.js → account-inspect-CqzrH14k.js} +48 -42
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/action-runtime-api.js +1 -1
  4. package/dist/{active-turn-thread-route-MlKWp8RD.js → active-turn-thread-route-fmHl1HNd.js} +9 -11
  5. package/dist/{activities-api-DTKsuDxf.js → activities-api-DS7vpdtp.js} +4 -4
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-DzKrtfah.js → allow-list-DnxIlPP2.js} +2 -3
  8. package/dist/{api-DnrK9gML.js → api-DNVbJyEy.js} +7 -2
  9. package/dist/api.js +15 -15
  10. package/dist/{approval-handler.runtime-HymvFTYn.js → approval-handler.runtime-B6yEV79q.js} +5 -5
  11. package/dist/{approval-message-safety-DEyKVsAw.js → approval-message-safety-AcIxvrf3.js} +1 -1
  12. package/dist/{audit-CjsrabP8.js → audit-Db-rlntl.js} +4 -4
  13. package/dist/{channel-vKa-76xY.js → channel-CnnbJSt5.js} +46 -72
  14. package/dist/{channel-actions-uXFTJX3o.js → channel-actions-5s_hjYKd.js} +4 -4
  15. package/dist/{channel-actions.runtime-CIYU90sl.js → channel-actions.runtime-CLKrx6tr.js} +53 -36
  16. package/dist/channel-config-api.js +1 -1
  17. package/dist/channel-plugin-api.js +1 -1
  18. package/dist/{channel.setup-CmcwZ_qd.js → channel.setup-BFAO-V1P.js} +15 -53
  19. package/dist/{config-schema-WHRQcY19.js → config-schema-BgEskFAs.js} +9 -4
  20. package/dist/{directory-config-D_LojtCe.js → directory-config-BVX7Cflc.js} +1 -1
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-Bw5Ephzv.js → directory-live-DGIGxpIo.js} +6 -3
  23. package/dist/{doctor-Bc4S1qyd.js → doctor-BzC-TLnB.js} +4 -4
  24. package/dist/{doctor-contract-CCFMIDk9.js → doctor-contract-DLa-BTiU.js} +2 -3
  25. package/dist/doctor-contract-api.js +147 -2
  26. package/dist/{handle-action.guild-admin-D6VRRW-C.js → handle-action.guild-admin-BNVTUISF.js} +4 -7
  27. package/dist/{inbound-event-delivery-CEPlt2uz.js → inbound-event-delivery-De2qxTrP.js} +4 -25
  28. package/dist/index.js +4 -2
  29. package/dist/{message-handler-CeiSulIw.js → message-handler-Unk_f10F.js} +41 -32
  30. package/dist/{message-handler.preflight-DibgQFf2.js → message-handler.preflight-C9zecxR9.js} +50 -26
  31. package/dist/{message-handler.process-Dnc_oz9y.js → message-handler.process-DWQ6UHHu.js} +130 -166
  32. package/dist/{message-utils-BgTwT_q7.js → message-utils-BSCPVgy0.js} +4 -4
  33. package/dist/{model-picker-preference-primitives-D25pnCOu.js → model-picker-preference-primitives-BHT1LkR_.js} +3 -3
  34. package/dist/{outbound-adapter-DtE-i2OJ.js → outbound-adapter-D9nRivT1.js} +91 -32
  35. package/dist/{outbound-components-C7GVyfPh.js → outbound-components-cTzwBJ60.js} +3 -3
  36. package/dist/{outbound-session-route-H-HoyH5U.js → outbound-session-route-DxLkrgKQ.js} +68 -95
  37. package/dist/{pluralkit-CD4B11JB.js → pluralkit-DdiJ9KMK.js} +1 -1
  38. package/dist/{preflight-audio-BjnQZ5yS.js → preflight-audio-DrnqFA8U.js} +22 -28
  39. package/dist/{probe-BeWKhjqX.js → probe-Bl-k5_Ku.js} +36 -12
  40. package/dist/probe.runtime-M9fREKvp.js +2 -0
  41. package/dist/{provider-DfQJX3z5.js → provider-DvSNb-2v.js} +969 -1248
  42. package/dist/{provider-session.runtime-Bo88k0pV.js → provider-session.runtime-BUEqD0rA.js} +3 -3
  43. package/dist/provider.runtime-C9PnJZbZ.js +2 -0
  44. package/dist/realtime-session.runtime-C7wen-aF.js +1340 -0
  45. package/dist/{resolve-allowlist-common-DHERApxi.js → resolve-allowlist-common-D04lpEzb.js} +2 -2
  46. package/dist/{resolve-channels-BjepAj8b.js → resolve-channels-Dm7jEeg6.js} +4 -4
  47. package/dist/{resolve-users-Bc28htgt.js → resolve-users-bktrCUUU.js} +3 -3
  48. package/dist/{chunk-DX4jpFQP.js → retry-CLpJcXXf.js} +291 -68
  49. package/dist/{runtime-_aRC6V2s.js → runtime-DGsSyDTS.js} +30 -25
  50. package/dist/{runtime-BmW_j_hl.js → runtime-DoHjckYm.js} +4 -6
  51. package/dist/runtime-api.actions.js +2 -2
  52. package/dist/runtime-api.js +22 -23
  53. package/dist/runtime-api.lookup.js +5 -5
  54. package/dist/runtime-api.monitor-CHxrFPnW.js +5 -0
  55. package/dist/runtime-api.monitor.js +5 -5
  56. package/dist/runtime-api.send.js +6 -6
  57. package/dist/runtime-api.threads.js +5 -6
  58. package/dist/sdk-runtime-QpY8PvCh.js +370 -0
  59. package/dist/{send-CdkZ6zeW.js → send-B7Q6Oc1I.js} +175 -86
  60. package/dist/{send.components-5uqwkjgE.js → send.components-iJyFXw9L.js} +24 -28
  61. package/dist/{send.outbound-D-80Ej-t.js → send.outbound-DS5tHwfR.js} +37 -24
  62. package/dist/{send.reactions-CtlmGd_o.js → send.reactions-BAn0iiVQ.js} +14 -21
  63. package/dist/{send.receipt-CuwRrpFz.js → send.receipt-IPI1p-SP.js} +19 -1
  64. package/dist/{send.shared-jpvAG_u6.js → send.shared-BmwFjW6T.js} +16 -85
  65. package/dist/{sender-identity-mG_zsdox.js → sender-identity-QtalnCYv.js} +1 -1
  66. package/dist/setup-entry.js +0 -5
  67. package/dist/setup-plugin-api.js +1 -1
  68. package/dist/{shared-CXF1tup1.js → shared-BIXIX6uJ.js} +16 -17
  69. package/dist/{subagent-hooks-Dxy7Fmnq.js → subagent-hooks-CTt5KCJr.js} +2 -2
  70. package/dist/subagent-hooks-api.js +2 -6
  71. package/dist/subagent-progress-DhaE_h8a.js +109 -0
  72. package/dist/{system-events-DdUqf91B.js → system-events-CTqDf6_s.js} +2 -2
  73. package/dist/{target-resolver-C3s_2m0t.js → target-resolver-maOKSqO0.js} +2 -2
  74. package/dist/targets-yUFTHoAx.js +3 -0
  75. package/dist/{thread-bindings-C-M-ly7P.js → thread-bindings-3L8p82GV.js} +5 -7
  76. package/dist/{thread-bindings.manager-DYvSlrva.js → thread-bindings.manager-DCIH6WDC.js} +257 -29
  77. package/dist/{thread-bindings.session-updates-DAIlp7Px.js → thread-bindings.session-updates-bJ2KQFY6.js} +1 -1
  78. package/dist/{thread-bindings.state-Cgi5uRn-.js → thread-bindings.state-aeV8HNgV.js} +2 -15
  79. package/dist/{transcripts-source-DIKGsTGT.js → transcripts-source-CfFMexGt.js} +1 -1
  80. package/dist/transcripts-source-api.js +1 -1
  81. package/dist/{typing--Mzo2kM7.js → typing-CS-nNVoe.js} +1 -1
  82. package/dist/voice-runtime-BEdqNcST.js +2459 -0
  83. package/openclaw.plugin.json +203 -19
  84. package/package.json +15 -9
  85. package/skills/discord/SKILL.md +22 -115
  86. package/dist/legacy-state-migrations-api.js +0 -138
  87. package/dist/manager.runtime-Bjav3pfC.js +0 -3655
  88. package/dist/preflight-audio.runtime-CoCXMM8r.js +0 -7
  89. package/dist/probe.runtime-DqFGFMbZ.js +0 -2
  90. package/dist/provider.runtime-Cy7XZmyh.js +0 -2
  91. package/dist/runtime-api.monitor-CCRubd3-.js +0 -5
  92. package/dist/session-binding-contract-api.js +0 -2
  93. package/dist/subagent-progress-DI3sYLLo.js +0 -664
  94. package/dist/targets-Dv_RN7vT.js +0 -3
  95. package/dist/thread-bindings.discord-api-BoDNqamb.js +0 -246
@@ -1,12 +1,12 @@
1
- import { u as resolveDiscordChannelId } from "./chunk-DX4jpFQP.js";
2
- import { a as buildDiscordPresentationComponents, i as buildDiscordInteractiveComponents } from "./outbound-session-route-H-HoyH5U.js";
3
- import { a as readDiscordAutoArchiveDurationParam, t as handleDiscordAction } from "./runtime-_aRC6V2s.js";
4
- import "./targets-Dv_RN7vT.js";
1
+ import { m as resolveDiscordChannelId, p as parseDiscordTarget } from "./retry-CLpJcXXf.js";
2
+ import { a as buildDiscordPresentationComponents, i as buildDiscordInteractiveComponents } from "./outbound-session-route-DxLkrgKQ.js";
3
+ import { a as readDiscordAutoArchiveDurationParam, t as handleDiscordAction } from "./runtime-DGsSyDTS.js";
4
+ import "./targets-yUFTHoAx.js";
5
5
  import "./action-runtime-api.js";
6
- import { r as notifyDiscordInboundEventOutboundSuccess } from "./inbound-event-delivery-CEPlt2uz.js";
7
- import { r as isDiscordComponentSpecWithinMessageLimit, t as DISCORD_PRESENTATION_CAPABILITIES } from "./outbound-components-C7GVyfPh.js";
8
- import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-D6VRRW-C.js";
9
- import { n as notifyDiscordActiveTurnThreadCreated, r as notifyDiscordActiveTurnThreadReplyDelivered } from "./active-turn-thread-route-MlKWp8RD.js";
6
+ import { t as discordInboundEventDelivery } from "./inbound-event-delivery-De2qxTrP.js";
7
+ import { r as isDiscordComponentSpecWithinMessageLimit, t as DISCORD_PRESENTATION_CAPABILITIES } from "./outbound-components-cTzwBJ60.js";
8
+ import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-BNVTUISF.js";
9
+ import { n as notifyDiscordActiveTurnThreadCreated, r as notifyDiscordActiveTurnThreadReplyDelivered } from "./active-turn-thread-route-fmHl1HNd.js";
10
10
  import { normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
11
11
  import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
12
12
  import { adaptMessagePresentationForChannel, normalizeLegacyInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
@@ -47,12 +47,30 @@ async function handleDiscordMessageAction(ctx) {
47
47
  mediaReadFile: ctx.mediaReadFile,
48
48
  ...readPolicyOptions
49
49
  };
50
- const notifyVisibleOutbound = (to, fallbackSessionKey) => notifyDiscordInboundEventOutboundSuccess({
51
- sessionKey: ctx.sessionKey ?? fallbackSessionKey ?? void 0,
52
- to,
53
- accountId,
54
- inboundEventKind: ctx.inboundEventKind
55
- });
50
+ const notifyVisibleOutbound = (result, to, fallbackSessionKey) => {
51
+ if ((result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : void 0)?.ok !== true) return;
52
+ discordInboundEventDelivery.notify({
53
+ sessionKey: ctx.sessionKey ?? fallbackSessionKey ?? void 0,
54
+ to,
55
+ accountId,
56
+ inboundEventKind: ctx.inboundEventKind
57
+ });
58
+ };
59
+ const withAdoptedThreadReplyRoute = (result, to, fallbackSessionKey) => {
60
+ if ((result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : void 0)?.ok !== true) return result;
61
+ let target;
62
+ try {
63
+ target = parseDiscordTarget(to, { defaultKind: "channel" });
64
+ } catch {
65
+ return result;
66
+ }
67
+ if (target?.kind === "channel" && notifyDiscordActiveTurnThreadReplyDelivered({
68
+ sessionKey: ctx.sessionKey ?? fallbackSessionKey,
69
+ accountId,
70
+ threadId: target.id
71
+ })) return withCurrentSourceReplyRoute(result);
72
+ return result;
73
+ };
56
74
  const readTarget = () => {
57
75
  const target = readStringParam$1(params, "channelId") ?? readStringParam$1(params, "to") ?? readCurrentDiscordTarget(ctx.toolContext);
58
76
  if (!target) throw new Error("Discord channel target is required (use channel:<id>).");
@@ -118,8 +136,8 @@ async function handleDiscordMessageAction(ctx) {
118
136
  __sessionKey: sessionKey ?? void 0,
119
137
  __agentId: agentId ?? void 0
120
138
  }, cfg, actionOptions);
121
- notifyVisibleOutbound(to, sessionKey);
122
- return result;
139
+ notifyVisibleOutbound(result, to, sessionKey);
140
+ return withAdoptedThreadReplyRoute(result, to, sessionKey);
123
141
  }
124
142
  if (action === "upload-file") {
125
143
  const to = readSendTarget();
@@ -145,8 +163,8 @@ async function handleDiscordMessageAction(ctx) {
145
163
  __sessionKey: sessionKey ?? void 0,
146
164
  __agentId: agentId ?? void 0
147
165
  }, cfg, actionOptions);
148
- notifyVisibleOutbound(to, sessionKey);
149
- return result;
166
+ notifyVisibleOutbound(result, to, sessionKey);
167
+ return withAdoptedThreadReplyRoute(result, to, sessionKey);
150
168
  }
151
169
  if (action === "poll") {
152
170
  const to = readStringParam$1(params, "to", { required: true });
@@ -164,7 +182,7 @@ async function handleDiscordMessageAction(ctx) {
164
182
  durationHours: durationHours ?? void 0,
165
183
  content: readStringParam$1(params, "message")
166
184
  }, cfg, actionOptions);
167
- notifyVisibleOutbound(to);
185
+ notifyVisibleOutbound(result, to);
168
186
  return result;
169
187
  }
170
188
  if (action === "react") {
@@ -258,15 +276,17 @@ async function handleDiscordMessageAction(ctx) {
258
276
  appliedTags: appliedTags ?? void 0
259
277
  }, cfg, actionOptions);
260
278
  const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : void 0;
261
- const threadId = typeof details?.thread?.id === "string" ? details.thread.id : void 0;
262
- await notifyDiscordActiveTurnThreadCreated({
263
- sessionKey: ctx.sessionKey,
264
- accountId,
265
- sourceChannelId: resolveChannelId(),
266
- sourceMessageId: messageId,
267
- threadId
268
- });
269
- notifyVisibleOutbound(resolveChannelId());
279
+ if (details?.ok === true) {
280
+ const threadId = typeof details.thread?.id === "string" ? details.thread.id : void 0;
281
+ await notifyDiscordActiveTurnThreadCreated({
282
+ sessionKey: ctx.sessionKey,
283
+ accountId,
284
+ sourceChannelId: resolveChannelId(),
285
+ sourceMessageId: messageId,
286
+ threadId
287
+ });
288
+ }
289
+ notifyVisibleOutbound(result, resolveChannelId());
270
290
  return result;
271
291
  }
272
292
  if (action === "sticker") {
@@ -282,7 +302,7 @@ async function handleDiscordMessageAction(ctx) {
282
302
  stickerIds,
283
303
  content: readStringParam$1(params, "message")
284
304
  }, cfg, actionOptions);
285
- notifyVisibleOutbound(to);
305
+ notifyVisibleOutbound(result, to);
286
306
  return result;
287
307
  }
288
308
  if (action === "set-presence") return await handleDiscordAction({
@@ -297,17 +317,14 @@ async function handleDiscordMessageAction(ctx) {
297
317
  const adminResult = await tryHandleDiscordMessageActionGuildAdmin({
298
318
  ctx,
299
319
  resolveChannelId,
300
- readPolicyOptions
320
+ readPolicyOptions,
321
+ actionOptions
301
322
  });
302
323
  if (adminResult !== void 0) {
303
324
  if (action === "thread-reply") {
304
325
  const threadId = readStringParam$1(params, "threadId") ?? readTarget();
305
- notifyVisibleOutbound(threadId);
306
- if (notifyDiscordActiveTurnThreadReplyDelivered({
307
- sessionKey: ctx.sessionKey,
308
- accountId,
309
- threadId
310
- })) return withCurrentSourceReplyRoute(adminResult);
326
+ notifyVisibleOutbound(adminResult, threadId);
327
+ return withAdoptedThreadReplyRoute(adminResult, threadId);
311
328
  }
312
329
  return adminResult;
313
330
  }
@@ -1,2 +1,2 @@
1
- import { t as DiscordChannelConfigSchema } from "./config-schema-WHRQcY19.js";
1
+ import { t as DiscordChannelConfigSchema } from "./config-schema-BgEskFAs.js";
2
2
  export { DiscordChannelConfigSchema };
@@ -1,2 +1,2 @@
1
- import { t as discordPlugin } from "./channel-vKa-76xY.js";
1
+ import { t as discordPlugin } from "./channel-CnnbJSt5.js";
2
2
  export { discordPlugin };
@@ -1,8 +1,8 @@
1
1
  import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, l as resolveDiscordAccountConfig, m as resolveDiscordToken, o as resolveDefaultDiscordAccountId } from "./accounts-DJTf1LtA.js";
2
- import { n as inspectDiscordConfiguredToken } from "./account-inspect-SXiCBCgP.js";
3
- import { a as discordSetupContract, i as discordSetupAdapter, t as createDiscordPluginBase } from "./shared-CXF1tup1.js";
4
- import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BjepAj8b.js";
5
- import { t as resolveDiscordUserAllowlist } from "./resolve-users-Bc28htgt.js";
2
+ import { n as inspectDiscordAccountTokenState } from "./account-inspect-CqzrH14k.js";
3
+ import { i as discordSetupContract, t as createDiscordPluginBase } from "./shared-BIXIX6uJ.js";
4
+ import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-Dm7jEeg6.js";
5
+ import { t as resolveDiscordUserAllowlist } from "./resolve-users-bktrCUUU.js";
6
6
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
7
7
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { resolveBasicAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
@@ -25,54 +25,17 @@ function inspectDiscordSetupAccount(params) {
25
25
  const enabled = params.cfg.channels?.discord?.enabled !== false && config.enabled !== false;
26
26
  const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
27
27
  const hasAccountToken = Boolean(accountConfig && Object.hasOwn(accountConfig, "token"));
28
- const accountToken = inspectDiscordConfiguredToken(accountConfig?.token);
29
- if (accountToken) return {
30
- accountId,
31
- enabled,
32
- token: accountToken.token,
33
- tokenSource: accountToken.tokenSource,
34
- tokenStatus: accountToken.tokenStatus,
35
- configured: true,
36
- config
37
- };
38
- if (hasAccountToken) return {
39
- accountId,
40
- enabled,
41
- token: "",
42
- tokenSource: "none",
43
- tokenStatus: "missing",
44
- configured: false,
45
- config
46
- };
47
- const channelToken = inspectDiscordConfiguredToken(params.cfg.channels?.discord?.token);
48
- if (channelToken) return {
49
- accountId,
50
- enabled,
51
- token: channelToken.token,
52
- tokenSource: channelToken.tokenSource,
53
- tokenStatus: channelToken.tokenStatus,
54
- configured: true,
55
- config
56
- };
57
- const tokenResolution = resolveDiscordToken(params.cfg, { accountId });
58
- if (tokenResolution.token) return {
59
- accountId,
60
- enabled,
61
- token: tokenResolution.token,
62
- tokenSource: tokenResolution.source,
63
- tokenStatus: "available",
64
- configured: true,
65
- config
66
- };
67
- return {
68
- accountId,
69
- enabled,
70
- token: "",
71
- tokenSource: "none",
72
- tokenStatus: "missing",
73
- configured: false,
74
- config
75
- };
28
+ return inspectDiscordAccountTokenState({
29
+ base: {
30
+ accountId,
31
+ enabled
32
+ },
33
+ config,
34
+ accountToken: accountConfig?.token,
35
+ hasAccountToken,
36
+ channelToken: params.cfg.channels?.discord?.token,
37
+ resolveFallbackToken: () => resolveDiscordToken(params.cfg, { accountId })
38
+ });
76
39
  }
77
40
  //#endregion
78
41
  //#region extensions/discord/src/setup-core.ts
@@ -332,7 +295,6 @@ const discordSetupPlugin = { ...createDiscordPluginBase({
332
295
  entries
333
296
  })
334
297
  }),
335
- setup: discordSetupAdapter,
336
298
  setupContract: discordSetupContract
337
299
  }) };
338
300
  //#endregion
@@ -20,16 +20,16 @@ const discordChannelConfigUiHints = {
20
20
  },
21
21
  nativeCommands: true,
22
22
  streaming: {
23
- "": "Unified Discord stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". \"progress\" keeps a single editable progress draft until final delivery. Legacy boolean/streamMode keys are auto-mapped.",
24
- mode: "Canonical Discord preview mode: \"off\" | \"partial\" | \"block\" | \"progress\".",
23
+ "": "Discord preview streaming is off by default. Set mode to \"partial\", \"block\", or \"progress\" to opt in. Run openclaw doctor --fix to migrate legacy keys.",
24
+ mode: "Discord preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". Default: \"off\".",
25
25
  chunkMode: "Chunking mode for outbound Discord text delivery: \"length\" (default) or \"newline\".",
26
- "block.enabled": "Enable chunked block-style Discord preview delivery when channels.discord.streaming.mode=\"block\".",
26
+ "block.enabled": "Enable normal Discord block replies. This takes precedence over editable preview delivery.",
27
27
  "block.coalesce": "Merge streamed Discord block replies before final delivery.",
28
28
  "preview.chunk.minChars": "Minimum chars before emitting a Discord stream preview update when channels.discord.streaming.mode=\"block\" (default: 200).",
29
29
  "preview.chunk.maxChars": "Target max size for a Discord stream preview chunk when channels.discord.streaming.mode=\"block\" (default: 800; clamped to channels.discord.textChunkLimit).",
30
30
  "preview.chunk.breakPreference": "Preferred breakpoints for Discord draft chunks (paragraph | newline | sentence). Default: paragraph.",
31
31
  "preview.toolProgress": "Show tool/progress activity in the live draft preview message (default: true). Set false to hide interim tool updates while the draft preview stays active.",
32
- "preview.commandText": "Command/exec detail in preview tool-progress lines: \"raw\" preserves released behavior; \"status\" shows only the tool label."
32
+ "preview.commandText": "Command/exec detail in preview tool-progress lines: \"status\" is the safe default; \"raw\" opts into command text."
33
33
  },
34
34
  progress: { includeCommentary: true }
35
35
  }),
@@ -73,6 +73,10 @@ const discordChannelConfigUiHints = {
73
73
  label: "Discord Component TTL (ms)",
74
74
  help: "How long sent Discord component callbacks remain registered. Default is 1800000 (30 minutes); maximum is 86400000 (24 hours)."
75
75
  },
76
+ "intents.messageContent": {
77
+ label: "Discord Message Content Intent",
78
+ help: "Request the privileged Message Content intent (default: true). Set false only for mention-only guild operation when Discord cannot grant the intent; DMs and explicit mentions still include message content."
79
+ },
76
80
  "intents.presence": {
77
81
  label: "Discord Presence Intent",
78
82
  help: "Enable the Guild Presences privileged intent. Must also be enabled in the Discord Developer Portal. Allows tracking user activities (e.g. Spotify). Default: false."
@@ -509,6 +513,7 @@ const DiscordAccountSchema = z.object({
509
513
  defaultSpawnContext: z.enum(["isolated", "fork"]).optional()
510
514
  }).strict().optional(),
511
515
  intents: z.object({
516
+ messageContent: z.boolean().optional(),
512
517
  presence: z.boolean().optional(),
513
518
  guildMembers: z.boolean().optional(),
514
519
  voiceStates: z.boolean().optional()
@@ -1,4 +1,4 @@
1
- import { Yt as __exportAll } from "./chunk-DX4jpFQP.js";
1
+ import { tn as __exportAll } from "./retry-CLpJcXXf.js";
2
2
  import { a as mergeDiscordAccountConfig, c as resolveDiscordAccountAllowFrom, o as resolveDefaultDiscordAccountId } from "./accounts-DJTf1LtA.js";
3
3
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
4
4
  import { createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-config-runtime";
@@ -1,4 +1,4 @@
1
- import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-D_LojtCe.js";
1
+ import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BVX7Cflc.js";
2
2
  //#region extensions/discord/directory-contract-api.ts
3
3
  const discordDirectoryContractPlugin = {
4
4
  id: "discord",
@@ -1,7 +1,7 @@
1
- import { Yt as __exportAll } from "./chunk-DX4jpFQP.js";
1
+ import { tn as __exportAll } from "./retry-CLpJcXXf.js";
2
2
  import { p as normalizeDiscordToken, s as resolveDiscordAccount } from "./accounts-DJTf1LtA.js";
3
- import { r as fetchDiscord, t as DISCORD_DIRECTORY_LOOKUP_TIMEOUT_MS } from "./api-DnrK9gML.js";
4
- import { a as normalizeDiscordSlug } from "./allow-list-DzKrtfah.js";
3
+ import { r as fetchDiscord, t as DISCORD_DIRECTORY_LOOKUP_TIMEOUT_MS } from "./api-DNVbJyEy.js";
4
+ import { a as normalizeDiscordSlug } from "./allow-list-DnxIlPP2.js";
5
5
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing";
6
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  //#region extensions/discord/src/directory-cache-state.ts
@@ -123,6 +123,7 @@ async function listDiscordDirectoryPeersLive(params) {
123
123
  if (!query) return [];
124
124
  const guilds = await listDiscordGuilds(token);
125
125
  const rows = [];
126
+ const seenUserIds = /* @__PURE__ */ new Set();
126
127
  const limit = typeof params.limit === "number" && params.limit > 0 ? params.limit : 25;
127
128
  for (const guild of guilds) {
128
129
  const paramsObj = new URLSearchParams({
@@ -143,6 +144,8 @@ async function listDiscordDirectoryPeersLive(params) {
143
144
  user.username ? `@${user.username}` : null
144
145
  ]
145
146
  });
147
+ if (seenUserIds.has(user.id)) continue;
148
+ seenUserIds.add(user.id);
146
149
  const name = member.nick?.trim() || user.global_name?.trim() || user.username?.trim();
147
150
  rows.push({
148
151
  kind: "user",
@@ -1,11 +1,11 @@
1
1
  import { o as resolveDefaultDiscordAccountId } from "./accounts-DJTf1LtA.js";
2
- import { t as inspectDiscordAccount } from "./account-inspect-SXiCBCgP.js";
3
- import { r as DISCORD_LEGACY_CONFIG_RULES } from "./shared-CXF1tup1.js";
4
- import { n as normalizeCompatibilityConfig } from "./doctor-contract-CCFMIDk9.js";
2
+ import { t as inspectDiscordAccount } from "./account-inspect-CqzrH14k.js";
3
+ import { r as DISCORD_LEGACY_CONFIG_RULES } from "./shared-BIXIX6uJ.js";
4
+ import { n as normalizeCompatibilityConfig } from "./doctor-contract-DLa-BTiU.js";
5
5
  import { t as isDiscordMutableAllowEntry } from "./security-doctor-nGgPm65L.js";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
8
- import { asObjectRecord, collectChannelAccountScopes, collectProviderDangerousNameMatchingScopes } from "openclaw/plugin-sdk/runtime-doctor";
8
+ import { asObjectRecord, collectChannelAccountScopes, collectProviderDangerousNameMatchingScopes } from "openclaw/plugin-sdk/runtime-doctor-migrations";
9
9
  //#region extensions/discord/src/doctor.ts
10
10
  function sanitizeForLog(value) {
11
11
  return value.replace(/\p{Cc}+/gu, " ").trim();
@@ -1,5 +1,5 @@
1
- import { isSupportedRealtimeVoiceActivationName, normalizeRealtimeVoiceActivationNamePrefix } from "openclaw/plugin-sdk/realtime-voice";
2
- import { asObjectRecord, defineChannelAliasMigration, defineKeyMoveMigration, hasLegacyAccountStreamingAliases, normalizeChannelAccounts, stripRetiredChannelKeys } from "openclaw/plugin-sdk/runtime-doctor";
1
+ import { isSupportedRealtimeVoiceActivationName, normalizeRealtimeVoiceActivationNamePrefix } from "openclaw/plugin-sdk/realtime-voice-activation";
2
+ import { asObjectRecord, defineChannelAliasMigration, defineKeyMoveMigration, hasLegacyAccountStreamingAliases, normalizeChannelAccounts, stripRetiredChannelKeys } from "openclaw/plugin-sdk/runtime-doctor-migrations";
3
3
  //#region extensions/discord/src/doctor-contract.ts
4
4
  const LEGACY_TTS_PROVIDER_KEYS = [
5
5
  "openai",
@@ -18,7 +18,6 @@ const streamingAliasMigration = defineChannelAliasMigration({
18
18
  channelId: "discord",
19
19
  streaming: {
20
20
  defaultMode: "off",
21
- absentObjectDefault: "progress",
22
21
  includePreviewChunk: true
23
22
  },
24
23
  accountStreamingReplacesRoot: true,
@@ -1,2 +1,147 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-CCFMIDk9.js";
2
- export { legacyConfigRules, normalizeCompatibilityConfig };
1
+ import { n as DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE, t as DISCORD_COMMAND_DEPLOY_HASH_MAX_ENTRIES } from "./command-deploy-store-DFkBTViB.js";
2
+ import { a as THREAD_BINDINGS_MAX_ENTRIES, d as normalizePersistedBinding, k as toBindingRecordKey, o as THREAD_BINDINGS_NAMESPACE } from "./thread-bindings.state-aeV8HNgV.js";
3
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-DLa-BTiU.js";
4
+ import { i as sanitizeRecentModels, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.js";
5
+ import { MAX_DATE_TIMESTAMP_MS, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
6
+ import path from "node:path";
7
+ import { definePluginDoctorMigrationFromPlans } from "openclaw/plugin-sdk/runtime-doctor-migrations";
8
+ import fs from "node:fs";
9
+ //#region extensions/discord/src/monitor/model-picker-preferences-migrations.ts
10
+ const PREFERENCE_MAX_ENTRIES = 2e3;
11
+ const MAX_PLUGIN_STATE_KEY_BYTES = 512;
12
+ const textEncoder = new TextEncoder();
13
+ function fileExists(filePath) {
14
+ try {
15
+ return fs.statSync(filePath).isFile();
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+ function readLegacyStore(filePath) {
21
+ try {
22
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
23
+ return parsed && typeof parsed === "object" ? parsed : null;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+ function readLegacyThreadBindingsStore(filePath) {
29
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
30
+ if (!parsed || typeof parsed !== "object") throw new Error("legacy Discord thread bindings store must be an object");
31
+ return parsed;
32
+ }
33
+ function normalizeLegacyPreferenceKey(key) {
34
+ const trimmed = key.trim();
35
+ if (!trimmed || textEncoder.encode(trimmed).length > MAX_PLUGIN_STATE_KEY_BYTES) return;
36
+ return trimmed;
37
+ }
38
+ function legacyUpdatedAtForIndex(updatedAt, index, total) {
39
+ const baseMs = preferenceTimestampMs(updatedAt);
40
+ return timestampMsToIsoString(Math.min(baseMs + Math.max(0, total), MAX_DATE_TIMESTAMP_MS) - Math.max(0, index)) ?? timestampMsToIsoString(baseMs) ?? timestampMsToIsoString(Math.max(0, total - index)) ?? "1970-01-01T00:00:00.000Z";
41
+ }
42
+ function readFiniteNumberField(entry, key) {
43
+ const value = entry[key];
44
+ return typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : void 0;
45
+ }
46
+ function upgradeLegacyThreadBindingShape(rawEntry) {
47
+ if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) return rawEntry;
48
+ const entry = { ...rawEntry };
49
+ if (entry.targetSessionKey === void 0 && typeof entry.sessionKey === "string") entry.targetSessionKey = entry.sessionKey;
50
+ delete entry.sessionKey;
51
+ const expiresAt = readFiniteNumberField(entry, "expiresAt");
52
+ delete entry.expiresAt;
53
+ if (entry.idleTimeoutMs === void 0 && entry.maxAgeMs === void 0 && expiresAt !== void 0) {
54
+ entry.idleTimeoutMs = 0;
55
+ if (expiresAt <= 0) entry.maxAgeMs = 0;
56
+ else {
57
+ const boundAt = readFiniteNumberField(entry, "boundAt") ?? 0;
58
+ const lastActivityAt = readFiniteNumberField(entry, "lastActivityAt") ?? 0;
59
+ entry.maxAgeMs = Math.max(1, expiresAt - Math.max(0, boundAt > 0 ? boundAt : lastActivityAt));
60
+ }
61
+ }
62
+ return entry;
63
+ }
64
+ const detectDiscordLegacyStateMigrations = ({ stateDir }) => {
65
+ const plans = [];
66
+ const commandDeployCacheSourcePath = path.join(stateDir, "discord", "command-deploy-cache.json");
67
+ if (fileExists(commandDeployCacheSourcePath)) plans.push({
68
+ kind: "plugin-state-import",
69
+ label: "Discord command deployment cache",
70
+ sourcePath: commandDeployCacheSourcePath,
71
+ targetPath: `plugin state:${DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE}`,
72
+ pluginId: "discord",
73
+ namespace: DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE,
74
+ maxEntries: DISCORD_COMMAND_DEPLOY_HASH_MAX_ENTRIES,
75
+ scopeKey: "",
76
+ cleanupSource: "remove",
77
+ cleanupWhenEmpty: true,
78
+ readEntries: () => []
79
+ });
80
+ const modelPickerSourcePath = path.join(stateDir, "discord", "model-picker-preferences.json");
81
+ if (fileExists(modelPickerSourcePath)) plans.push({
82
+ kind: "plugin-state-import",
83
+ label: "Discord model picker preferences",
84
+ sourcePath: modelPickerSourcePath,
85
+ targetPath: "plugin state:model-picker-preferences",
86
+ pluginId: "discord",
87
+ namespace: "model-picker-preferences",
88
+ maxEntries: PREFERENCE_MAX_ENTRIES,
89
+ scopeKey: "",
90
+ cleanupSource: "rename",
91
+ readEntries: () => {
92
+ const store = readLegacyStore(modelPickerSourcePath);
93
+ if (!store || !store.entries || typeof store.entries !== "object") return [];
94
+ const out = [];
95
+ for (const [rawKey, rawEntry] of Object.entries(store.entries)) {
96
+ const scopeKey = normalizeLegacyPreferenceKey(rawKey);
97
+ if (!scopeKey || !rawEntry || typeof rawEntry !== "object") continue;
98
+ const recent = sanitizeRecentModels(rawEntry.recent, 10);
99
+ for (const [index, modelRef] of recent.entries()) out.push({
100
+ key: buildPreferenceModelKey(scopeKey, modelRef),
101
+ value: {
102
+ scopeKey,
103
+ modelRef,
104
+ updatedAt: legacyUpdatedAtForIndex(rawEntry.updatedAt, index, recent.length)
105
+ }
106
+ });
107
+ }
108
+ return out;
109
+ }
110
+ });
111
+ const threadBindingsSourcePath = path.join(stateDir, "discord", "thread-bindings.json");
112
+ if (fileExists(threadBindingsSourcePath)) plans.push({
113
+ kind: "plugin-state-import",
114
+ label: "Discord thread bindings",
115
+ sourcePath: threadBindingsSourcePath,
116
+ targetPath: `plugin state:${THREAD_BINDINGS_NAMESPACE}`,
117
+ pluginId: "discord",
118
+ namespace: THREAD_BINDINGS_NAMESPACE,
119
+ maxEntries: THREAD_BINDINGS_MAX_ENTRIES,
120
+ scopeKey: "",
121
+ cleanupSource: "rename",
122
+ cleanupWhenEmpty: true,
123
+ readEntries: () => {
124
+ const store = readLegacyThreadBindingsStore(threadBindingsSourcePath);
125
+ if (store?.version !== 1 || !store.bindings || typeof store.bindings !== "object") throw new Error("legacy Discord thread bindings store must have version 1 bindings");
126
+ const out = [];
127
+ for (const [rawKey, rawEntry] of Object.entries(store.bindings)) {
128
+ const normalized = normalizePersistedBinding(rawKey, upgradeLegacyThreadBindingShape(rawEntry));
129
+ if (normalized) out.push({
130
+ key: toBindingRecordKey(normalized),
131
+ value: normalized
132
+ });
133
+ }
134
+ return out;
135
+ }
136
+ });
137
+ return plans;
138
+ };
139
+ //#endregion
140
+ //#region extensions/discord/doctor-contract-api.ts
141
+ const stateMigrations = [definePluginDoctorMigrationFromPlans({
142
+ id: "discord-legacy-state",
143
+ label: "Discord legacy state",
144
+ resolvePlans: detectDiscordLegacyStateMigrations
145
+ })];
146
+ //#endregion
147
+ export { legacyConfigRules, normalizeCompatibilityConfig, stateMigrations };
@@ -1,6 +1,6 @@
1
- import { c as readDiscordChannelMoveParams, n as isDiscordModerationAction, o as readDiscordChannelCreateParams, r as readDiscordModerationCommand, s as readDiscordChannelEditParams, t as handleDiscordAction } from "./runtime-_aRC6V2s.js";
1
+ import { c as readDiscordChannelMoveParams, n as isDiscordModerationAction, o as readDiscordChannelCreateParams, r as readDiscordModerationCommand, s as readDiscordChannelEditParams, t as handleDiscordAction } from "./runtime-DGsSyDTS.js";
2
2
  import "./action-runtime-api.js";
3
- import { n as isTrustedRequesterGuildAdminAction } from "./channel-actions-uXFTJX3o.js";
3
+ import { n as isTrustedRequesterGuildAdminAction } from "./channel-actions-5s_hjYKd.js";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { readNonNegativeIntegerParam, readPositiveIntegerParam, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
6
6
  //#region extensions/discord/src/actions/handle-action.guild-admin.ts
@@ -13,7 +13,7 @@ function senderParam(senderUserId) {
13
13
  return senderUserId ? { senderUserId } : {};
14
14
  }
15
15
  async function tryHandleDiscordMessageActionGuildAdmin(params) {
16
- const { ctx, resolveChannelId, readPolicyOptions } = params;
16
+ const { ctx, resolveChannelId, readPolicyOptions, actionOptions } = params;
17
17
  const { action, params: actionParams, cfg } = ctx;
18
18
  const accountId = ctx.accountId ?? readStringParam(actionParams, "accountId");
19
19
  const senderUserId = readDiscordRequesterSenderId(ctx);
@@ -284,10 +284,7 @@ async function tryHandleDiscordMessageActionGuildAdmin(params) {
284
284
  content,
285
285
  mediaUrl: mediaUrl ?? void 0,
286
286
  replyTo: replyTo ?? void 0
287
- }, cfg, {
288
- mediaLocalRoots: ctx.mediaLocalRoots,
289
- mediaReadFile: ctx.mediaReadFile
290
- });
287
+ }, cfg, actionOptions);
291
288
  }
292
289
  if (action === "search") {
293
290
  const guildId = readStringParam(actionParams, "guildId");
@@ -1,32 +1,11 @@
1
1
  import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
+ import { createInboundEventDeliveryCorrelation } from "openclaw/plugin-sdk/inbound-event-delivery";
2
3
  //#region extensions/discord/src/inbound-event-delivery.ts
3
4
  const DISCORD_INBOUND_EVENT_DELIVERY_KEY = "__openclawInboundEventDelivery";
4
- const registry = /* @__PURE__ */ new Map();
5
5
  function normalizeDiscordDeliveryTarget(value) {
6
6
  return value.trim().replace(/^discord:/iu, "").replace(/^channel:/iu, "").toLowerCase();
7
7
  }
8
- function resolveDiscordInboundEventDeliveryCorrelationKey(sessionKey, inboundEventKind) {
9
- const key = sessionKey?.trim();
10
- if (!key) return;
11
- return inboundEventKind === "room_event" ? `${key}:room_event` : key;
12
- }
13
- function beginDiscordInboundEventDeliveryCorrelation(sessionKey, event, options) {
14
- const key = resolveDiscordInboundEventDeliveryCorrelationKey(sessionKey, options?.inboundEventKind);
15
- if (!key) return () => {};
16
- registry.set(key, event);
17
- return () => {
18
- if (registry.get(key) === event) registry.delete(key);
19
- };
20
- }
21
- function notifyDiscordInboundEventOutboundSuccess(params) {
22
- const key = resolveDiscordInboundEventDeliveryCorrelationKey(params.sessionKey, params.inboundEventKind);
23
- if (!key) return;
24
- const event = registry.get(key);
25
- if (!event || normalizeDiscordDeliveryTarget(event.outboundTo) !== normalizeDiscordDeliveryTarget(params.to)) return;
26
- if (event.outboundAccountId && params.accountId && params.accountId !== event.outboundAccountId) return;
27
- registry.delete(key);
28
- event.markInboundEventDelivered();
29
- }
8
+ const discordInboundEventDelivery = createInboundEventDeliveryCorrelation({ targetsMatch: (expected, actual) => normalizeDiscordDeliveryTarget(expected) === normalizeDiscordDeliveryTarget(actual) });
30
9
  function withDiscordInboundEventDeliveryMetadata(payload, params) {
31
10
  const sessionKey = params.sessionKey?.trim();
32
11
  if (!sessionKey || params.inboundEventKind !== "room_event") return payload;
@@ -49,7 +28,7 @@ function withDiscordInboundEventDeliveryMetadata(payload, params) {
49
28
  function notifyDiscordInboundEventOutboundPayloadSuccess(params) {
50
29
  const metadata = asOptionalRecord(asOptionalRecord(asOptionalRecord(params.payload.channelData)?.discord)?.[DISCORD_INBOUND_EVENT_DELIVERY_KEY]);
51
30
  if (!metadata) return;
52
- notifyDiscordInboundEventOutboundSuccess({
31
+ discordInboundEventDelivery.notify({
53
32
  sessionKey: normalizeOptionalString(metadata.sessionKey),
54
33
  inboundEventKind: normalizeOptionalString(metadata.inboundEventKind),
55
34
  to: params.to,
@@ -57,4 +36,4 @@ function notifyDiscordInboundEventOutboundPayloadSuccess(params) {
57
36
  });
58
37
  }
59
38
  //#endregion
60
- export { withDiscordInboundEventDeliveryMetadata as i, notifyDiscordInboundEventOutboundPayloadSuccess as n, notifyDiscordInboundEventOutboundSuccess as r, beginDiscordInboundEventDeliveryCorrelation as t };
39
+ export { notifyDiscordInboundEventOutboundPayloadSuccess as n, withDiscordInboundEventDeliveryMetadata as r, discordInboundEventDelivery as t };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { t as registerDiscordActivities } from "./activities-api-DTKsuDxf.js";
1
+ import { t as registerDiscordActivities } from "./activities-api-DS7vpdtp.js";
2
2
  import { registerDiscordSubagentHooks } from "./subagent-hooks-api.js";
3
- import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-DIKGsTGT.js";
3
+ import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-CfFMexGt.js";
4
4
  import "./transcripts-source-api.js";
5
5
  import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
6
6
  //#region extensions/discord/index.ts
@@ -24,6 +24,8 @@ var discord_default = defineBundledChannelEntry({
24
24
  registerFull(api) {
25
25
  registerDiscordActivities(api);
26
26
  registerDiscordSubagentHooks(api);
27
+ },
28
+ registerCapabilities(api) {
27
29
  api.registerTranscriptSourceProvider(discordVoiceTranscriptsSourceProvider);
28
30
  }
29
31
  });