@openclaw/discord 2026.7.1 → 2026.7.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{allow-list-C-MqM-B_.js → allow-list-B7qOH5xu.js} +22 -1
  3. package/dist/{api-DPRqYi4Z.js → api--f62GFaS.js} +38 -23
  4. package/dist/api.js +15 -15
  5. package/dist/approval-custom-id-NYPYj9Po.js +58 -0
  6. package/dist/{approval-handler.runtime-Bw2pZNk1.js → approval-handler.runtime-DeyIiw5I.js} +28 -23
  7. package/dist/approval-message-safety-C-8BL6Kv.js +47 -0
  8. package/dist/{audit-MLpDpN3Z.js → audit-Df2w046a.js} +3 -3
  9. package/dist/{channel-actions-D_fjVUZ_.js → channel-actions-ChpBSRcu.js} +6 -4
  10. package/dist/{channel-actions.runtime-CVHlFqQg.js → channel-actions.runtime-D8V8tyCq.js} +41 -12
  11. package/dist/channel-config-api.js +1 -1
  12. package/dist/{channel-DGWPH5u3.js → channel-nYmJ7FKQ.js} +275 -62
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel.setup-tZcpIn4e.js → channel.setup-DyihrqHH.js} +3 -3
  15. package/dist/{components-BIBizbtZ.js → components-BVrfRS-F.js} +78 -52
  16. package/dist/config-api-B18fR8M5.js +3 -0
  17. package/dist/{config-schema-BgIhO3ko.js → config-schema-_bUKcWRm.js} +42 -82
  18. package/dist/conversation-identity-BpkAzklg.js +94 -0
  19. package/dist/{directory-config-ByaUKL1f.js → directory-config-BUe-qq_C.js} +1 -1
  20. package/dist/directory-contract-api.js +1 -1
  21. package/dist/{directory-live-BX79ImQA.js → directory-live-DZByMdPO.js} +6 -6
  22. package/dist/{doctor-Bgoxm5AN.js → doctor-bMaWXFKu.js} +5 -4
  23. package/dist/doctor-contract-api.js +1 -1
  24. package/dist/{doctor-contract-CU7lnZTF.js → doctor-contract-wId6pV41.js} +41 -37
  25. package/dist/{handle-action.guild-admin-CgJSNVui.js → handle-action.guild-admin-C_PQcBEV.js} +12 -12
  26. package/dist/index.js +1 -1
  27. package/dist/legacy-state-migrations-api.js +24 -2
  28. package/dist/{manager.runtime-DaB-CTrt.js → manager.runtime-3RVMVkyx.js} +546 -154
  29. package/dist/{message-handler-DcgvugZt.js → message-handler-CIxWq5Yh.js} +8 -9
  30. package/dist/{message-handler.preflight-DvLXiYVH.js → message-handler.preflight-BI86IbHz.js} +46 -22
  31. package/dist/{message-handler.process-Cjf30P_B.js → message-handler.process-bPS_9_tb.js} +241 -107
  32. package/dist/{message-utils-B_3yA5bN.js → message-utils-D4j07taS.js} +2 -3
  33. package/dist/{outbound-adapter-82RWi_SR.js → outbound-adapter-Czny0Fae.js} +16 -68
  34. package/dist/outbound-components-oJKLj62G.js +99 -0
  35. package/dist/pluralkit-UXq1OyUI.js +40 -0
  36. package/dist/{probe-D1ImJEo2.js → probe-DxjMBeVG.js} +1 -1
  37. package/dist/{probe.runtime-B1dsEeBD.js → probe.runtime-Bc8Oo6e8.js} +1 -1
  38. package/dist/{provider-BkfbC9FQ.js → provider-DWvDNb4J.js} +702 -236
  39. package/dist/{provider-session.runtime-BDjyFw6Y.js → provider-session.runtime-D5pCGibh.js} +3 -3
  40. package/dist/provider.runtime-C2iIfbTs.js +2 -0
  41. package/dist/{resolve-allowlist-common-CWbE8XlH.js → resolve-allowlist-common-B9S8LLBd.js} +5 -5
  42. package/dist/{resolve-channels-CcpvWoRa.js → resolve-channels-BrkWOKdG.js} +7 -7
  43. package/dist/{resolve-users-DJamun9s.js → resolve-users-OjrXXvJP.js} +5 -5
  44. package/dist/{runtime-C6rRmQ6l.js → runtime-C618lis9.js} +223 -33
  45. package/dist/runtime-api.actions.js +2 -2
  46. package/dist/runtime-api.js +23 -23
  47. package/dist/runtime-api.lookup.js +5 -5
  48. package/dist/runtime-api.monitor-DSbfGnzS.js +6 -0
  49. package/dist/runtime-api.monitor.js +7 -7
  50. package/dist/runtime-api.send.js +5 -5
  51. package/dist/runtime-api.threads.js +5 -5
  52. package/dist/{send-iJ0B4bAX.js → send-BFpa_DHn.js} +21 -12
  53. package/dist/{send.components-D0I39utR.js → send.components-BaXQJKWT.js} +15 -10
  54. package/dist/{send.outbound-Bj61Q3a0.js → send.outbound-BlA6VzSE.js} +22 -12
  55. package/dist/{send.receipt-BpBQED_5.js → send.receipt-aegk69an.js} +59 -75
  56. package/dist/{send.shared-wAwMhHDN.js → send.shared-Xz7IMVpu.js} +44 -20
  57. package/dist/{sender-identity-CEsfDF0L.js → sender-identity-C62lBe18.js} +1 -1
  58. package/dist/session-binding-contract-api.js +1 -1
  59. package/dist/setup-plugin-api.js +1 -1
  60. package/dist/{shared-BQVKfnev.js → shared-BLYBt5SA.js} +3 -3
  61. package/dist/{subagent-hooks-B-bJxxGg.js → subagent-hooks-DKJ4p-Oy.js} +2 -2
  62. package/dist/subagent-hooks-api.js +1 -1
  63. package/dist/{system-events-DVnqSyTt.js → system-events-DKwfE-2z.js} +2 -2
  64. package/dist/{target-resolver-CwHaSLt3.js → target-resolver-BQyEHyeS.js} +2 -2
  65. package/dist/targets-DvItNIvP.js +3 -0
  66. package/dist/thread-binding-api-BDZJD4na.js +4 -0
  67. package/dist/thread-binding-api.js +1 -3
  68. package/dist/{thread-bindings-DsTxqu3E.js → thread-bindings-BbzjUuNB.js} +26 -43
  69. package/dist/{thread-bindings.discord-api-BjIf9lGs.js → thread-bindings.discord-api-DJD3qwIN.js} +8 -10
  70. package/dist/{thread-bindings.manager-Bwmtqc3E.js → thread-bindings.manager-BIBm6bQd.js} +4 -4
  71. package/dist/{thread-bindings.session-updates-Chs3HgGa.js → thread-bindings.session-updates-eRcJlzIU.js} +1 -1
  72. package/dist/{thread-bindings.state-iSWjCYjB.js → thread-bindings.state-9VAxhVf6.js} +3 -14
  73. package/dist/{timeouts-C5TBc_9x.js → timeouts-ZRc9Lw4y.js} +3 -15
  74. package/dist/timeouts.js +1 -1
  75. package/dist/{transcripts-source-BvvM5Ns9.js → transcripts-source-CLZ5X8fh.js} +1 -1
  76. package/dist/transcripts-source-api.js +1 -1
  77. package/dist/{typing-BVcJgILg.js → typing-BnYT7Szq.js} +2 -2
  78. package/node_modules/p-map/index.d.ts +155 -0
  79. package/node_modules/p-map/index.js +284 -0
  80. package/node_modules/p-map/license +9 -0
  81. package/node_modules/p-map/package.json +57 -0
  82. package/node_modules/p-map/readme.md +190 -0
  83. package/npm-shrinkwrap.json +16 -3
  84. package/openclaw.plugin.json +70 -2
  85. package/package.json +6 -4
  86. package/dist/config-api-JiPdJeb0.js +0 -2
  87. package/dist/conversation-identity-DWC5d8Sy.js +0 -272
  88. package/dist/pluralkit-DcD-3EcL.js +0 -24
  89. package/dist/preview-streaming-DXT8oJdo.js +0 -8
  90. package/dist/provider.runtime-WrJXikSv.js +0 -2
  91. package/dist/runtime-api.monitor-C2_WVtJf.js +0 -6
  92. package/dist/targets-69w7c3vU.js +0 -3
@@ -1,2 +1,2 @@
1
- import { t as handleDiscordAction } from "./runtime-C6rRmQ6l.js";
1
+ import { t as handleDiscordAction } from "./runtime-C618lis9.js";
2
2
  export { handleDiscordAction };
@@ -192,6 +192,27 @@ function resolveDiscordOwnerAccess(params) {
192
192
  }, { allowNameMatching: params.allowNameMatching }) : false
193
193
  };
194
194
  }
195
+ function resolveDiscordCommandOwnerAllowFrom(cfg) {
196
+ const raw = cfg.commands?.ownerAllowFrom;
197
+ if (!Array.isArray(raw) || raw.length === 0) return;
198
+ const entries = [];
199
+ for (const entry of raw) {
200
+ const trimmed = normalizeOptionalString(String(entry ?? "")) ?? "";
201
+ if (!trimmed) continue;
202
+ const separatorIndex = trimmed.indexOf(":");
203
+ if (separatorIndex > 0) {
204
+ const prefix = trimmed.slice(0, separatorIndex).toLowerCase();
205
+ if (prefix === "discord") {
206
+ const remainder = normalizeOptionalString(trimmed.slice(separatorIndex + 1)) ?? "";
207
+ if (remainder) entries.push(remainder);
208
+ continue;
209
+ }
210
+ if (prefix !== "user" && prefix !== "pk") continue;
211
+ }
212
+ entries.push(trimmed);
213
+ }
214
+ return entries.length > 0 ? entries : void 0;
215
+ }
195
216
  function resolveDiscordCommandAuthorized(params) {
196
217
  if (!params.isDirectMessage) return true;
197
218
  const allowList = normalizeDiscordAllowList(params.allowFrom, [
@@ -351,4 +372,4 @@ function shouldEmitDiscordReactionNotification(params) {
351
372
  return false;
352
373
  }
353
374
  //#endregion
354
- export { resolveTimestampMs as S, resolveGroupDmAllow as _, normalizeDiscordSlug as a, formatDiscordUserTag as b, resolveDiscordChannelConfigWithFallback as c, resolveDiscordGuildEntry as d, resolveDiscordMemberAccessState as f, resolveDiscordShouldRequireMention as g, resolveDiscordOwnerAllowFrom as h, normalizeDiscordDisplaySlug as i, resolveDiscordChannelPolicyCommandAuthorizer as l, resolveDiscordOwnerAccess as m, isDiscordGroupAllowedByPolicy as n, resolveDiscordAllowListMatch as o, resolveDiscordMemberAllowed as p, normalizeDiscordAllowList as r, resolveDiscordChannelConfig as s, allowListMatches as t, resolveDiscordCommandAuthorized as u, shouldEmitDiscordReactionNotification as v, resolveDiscordSystemLocation as x, formatDiscordReactionEmoji as y };
375
+ export { resolveTimestampMs as C, resolveDiscordSystemLocation as S, resolveDiscordShouldRequireMention as _, normalizeDiscordSlug as a, formatDiscordReactionEmoji as b, resolveDiscordChannelConfigWithFallback as c, resolveDiscordCommandOwnerAllowFrom as d, resolveDiscordGuildEntry as f, resolveDiscordOwnerAllowFrom as g, resolveDiscordOwnerAccess as h, normalizeDiscordDisplaySlug as i, resolveDiscordChannelPolicyCommandAuthorizer as l, resolveDiscordMemberAllowed as m, isDiscordGroupAllowedByPolicy as n, resolveDiscordAllowListMatch as o, resolveDiscordMemberAccessState as p, normalizeDiscordAllowList as r, resolveDiscordChannelConfig as s, allowListMatches as t, resolveDiscordCommandAuthorized as u, resolveGroupDmAllow as v, formatDiscordUserTag as x, shouldEmitDiscordReactionNotification as y };
@@ -31,6 +31,7 @@ const DISCORD_API_RETRY_DEFAULTS = {
31
31
  const DISCORD_API_429_FALLBACK_RETRY_AFTER_SECONDS = 60;
32
32
  const DISCORD_API_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
33
33
  const DISCORD_API_RESPONSE_BODY_LIMIT_BYTES = 4 * 1024 * 1024;
34
+ const DISCORD_DIRECTORY_LOOKUP_TIMEOUT_MS = 1e4;
34
35
  function parseDiscordApiErrorPayload(text) {
35
36
  const trimmed = text.trim();
36
37
  if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
@@ -87,9 +88,18 @@ function normalizeDiscordRequestBody(body, headers) {
87
88
  headers.set("Content-Type", headers.get("Content-Type") ?? "application/json");
88
89
  return JSON.stringify(body);
89
90
  }
90
- function resolveDiscordRequestSignal(options) {
91
- if (options.signal || typeof options.timeoutMs !== "number") return options.signal;
92
- return AbortSignal.timeout(resolveTimerTimeoutMs(options.timeoutMs, 1));
91
+ function createDiscordRequestSignal(options) {
92
+ if (typeof options.timeoutMs !== "number" || options.signal?.aborted) return {
93
+ signal: options.signal,
94
+ cleanup: () => void 0
95
+ };
96
+ const controller = new AbortController();
97
+ const timeout = setTimeout(() => controller.abort(), resolveTimerTimeoutMs(options.timeoutMs, 1));
98
+ timeout.unref?.();
99
+ return {
100
+ signal: options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal,
101
+ cleanup: () => clearTimeout(timeout)
102
+ };
93
103
  }
94
104
  async function requestDiscord(path, token, options) {
95
105
  const fetchImpl = resolveFetch(options?.fetcher ?? fetch);
@@ -99,26 +109,31 @@ async function requestDiscord(path, token, options) {
99
109
  const headers = new Headers(options?.headers);
100
110
  headers.set("Authorization", `Bot ${token}`);
101
111
  const body = normalizeDiscordRequestBody(options?.body, headers);
102
- const res = await fetchImpl(`${DISCORD_API_BASE}${path}`, {
103
- method: options?.method ?? (body === void 0 ? "GET" : "POST"),
104
- headers,
105
- body,
106
- signal: resolveDiscordRequestSignal(options ?? {})
107
- });
108
- if (!res.ok) {
109
- const text = await readResponseTextLimited(res, DISCORD_API_ERROR_BODY_LIMIT_BYTES).catch(() => "");
110
- const detail = formatDiscordApiErrorText(text, res);
111
- const suffix = detail ? `: ${detail}` : "";
112
- const retryAfter = res.status === 429 ? parseRetryAfterSeconds(text, res) ?? DISCORD_API_429_FALLBACK_RETRY_AFTER_SECONDS : void 0;
113
- throw new DiscordApiError(`Discord API ${path} failed (${res.status})${suffix}`, res.status, retryAfter);
114
- }
115
- const responseBody = await readResponseWithLimit(res, DISCORD_API_RESPONSE_BODY_LIMIT_BYTES, { onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`Discord API ${path} response body too large: ${size} bytes (limit: ${maxBytes} bytes)`) });
116
- const text = new TextDecoder().decode(responseBody);
117
- if (!text.trim()) return;
112
+ const requestSignal = createDiscordRequestSignal(options ?? {});
118
113
  try {
119
- return JSON.parse(text);
120
- } catch {
121
- throw new DiscordApiError(`Discord API ${path} returned malformed JSON`, 0);
114
+ const res = await fetchImpl(`${DISCORD_API_BASE}${path}`, {
115
+ method: options?.method ?? (body === void 0 ? "GET" : "POST"),
116
+ headers,
117
+ body,
118
+ signal: requestSignal.signal
119
+ });
120
+ if (!res.ok) {
121
+ const text = await readResponseTextLimited(res, DISCORD_API_ERROR_BODY_LIMIT_BYTES).catch(() => "");
122
+ const detail = formatDiscordApiErrorText(text, res);
123
+ const suffix = detail ? `: ${detail}` : "";
124
+ const retryAfter = res.status === 429 ? parseRetryAfterSeconds(text, res) ?? DISCORD_API_429_FALLBACK_RETRY_AFTER_SECONDS : void 0;
125
+ throw new DiscordApiError(`Discord API ${path} failed (${res.status})${suffix}`, res.status, retryAfter);
126
+ }
127
+ const responseBody = await readResponseWithLimit(res, DISCORD_API_RESPONSE_BODY_LIMIT_BYTES, { onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`Discord API ${path} response body too large: ${size} bytes (limit: ${maxBytes} bytes)`) });
128
+ const text = new TextDecoder().decode(responseBody);
129
+ if (!text.trim()) return;
130
+ try {
131
+ return JSON.parse(text);
132
+ } catch {
133
+ throw new DiscordApiError(`Discord API ${path} returned malformed JSON`, 0);
134
+ }
135
+ } finally {
136
+ requestSignal.cleanup();
122
137
  }
123
138
  }, {
124
139
  ...retryConfig,
@@ -135,4 +150,4 @@ async function fetchDiscord(path, token, fetcher = fetch, options) {
135
150
  });
136
151
  }
137
152
  //#endregion
138
- export { summarizeDiscordResponseBody as a, isDiscordRateLimitResponseBody as i, fetchDiscord as n, requestDiscord as r, DiscordApiError as t };
153
+ export { isDiscordRateLimitResponseBody as a, requestDiscord as i, DiscordApiError as n, summarizeDiscordResponseBody as o, fetchDiscord as r, DISCORD_DIRECTORY_LOOKUP_TIMEOUT_MS as t };
package/dist/api.js CHANGED
@@ -1,23 +1,23 @@
1
- import { Kt as parseDiscordTarget, c as normalizeDiscordMessagingTarget, l as normalizeDiscordOutboundTarget, qt as resolveDiscordChannelId, s as looksLikeDiscordTargetId } from "./send.receipt-BpBQED_5.js";
1
+ import { Jt as parseDiscordTarget, Yt as resolveDiscordChannelId, c as normalizeDiscordMessagingTarget, l as normalizeDiscordOutboundTarget, s as looksLikeDiscordTargetId } from "./send.receipt-aegk69an.js";
2
2
  import { t as inspectDiscordAccount } from "./account-inspect-DDZtT5C8.js";
3
3
  import { a as mergeDiscordAccountConfig, f as resolveDiscordMaxLinesPerMessage, i as listEnabledDiscordAccounts, l as resolveDiscordAccountConfig, o as resolveDefaultDiscordAccountId, r as listDiscordAccountIds, s as resolveDiscordAccount, t as createDiscordActionGate } from "./accounts-P19jm1lf.js";
4
- import { _ as parseDiscordComponentCustomId, b as parseDiscordModalCustomIdForInteraction, c as buildDiscordComponentMessage, d as readDiscordComponentSpec, f as resolveDiscordComponentAttachmentName, g as buildDiscordModalCustomId, h as buildDiscordComponentCustomId, l as buildDiscordComponentMessageFlags, m as DISCORD_MODAL_CUSTOM_ID_KEY, n as formatDiscordComponentEventText, o as DiscordFormModal, p as DISCORD_COMPONENT_CUSTOM_ID_KEY, r as buildDiscordInteractiveComponents, s as createDiscordFormModal, u as DISCORD_COMPONENT_ATTACHMENT_PREFIX, v as parseDiscordComponentCustomIdForInteraction, y as parseDiscordModalCustomId } from "./components-BIBizbtZ.js";
5
- import { n as fetchDiscord, r as requestDiscord, t as DiscordApiError } from "./api-DPRqYi4Z.js";
6
- import { i as parseDiscordSendTarget, n as resolveDiscordTarget } from "./target-resolver-CwHaSLt3.js";
7
- import "./targets-69w7c3vU.js";
8
- import { a as getDiscordExecApprovalApprovers, c as shouldSuppressLocalDiscordExecApprovalPrompt, o as isDiscordExecApprovalApprover, s as isDiscordExecApprovalClientEnabled } from "./conversation-identity-DWC5d8Sy.js";
9
- import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-DGWPH5u3.js";
10
- import { i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, o as mergeAbortSignals, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C5TBc_9x.js";
4
+ import { _ as parseDiscordComponentCustomId, b as parseDiscordModalCustomIdForInteraction, c as buildDiscordComponentMessage, d as readDiscordComponentSpec, f as resolveDiscordComponentAttachmentName, g as buildDiscordModalCustomId, h as buildDiscordComponentCustomId, l as buildDiscordComponentMessageFlags, m as DISCORD_MODAL_CUSTOM_ID_KEY, n as formatDiscordComponentEventText, o as DiscordFormModal, p as DISCORD_COMPONENT_CUSTOM_ID_KEY, r as buildDiscordInteractiveComponents, s as createDiscordFormModal, u as DISCORD_COMPONENT_ATTACHMENT_PREFIX, v as parseDiscordComponentCustomIdForInteraction, y as parseDiscordModalCustomId } from "./components-BVrfRS-F.js";
5
+ import { i as requestDiscord, n as DiscordApiError, r as fetchDiscord } from "./api--f62GFaS.js";
6
+ import { i as parseDiscordSendTarget, n as resolveDiscordTarget } from "./target-resolver-BQyEHyeS.js";
7
+ import { i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, o as mergeAbortSignals, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-ZRc9Lw4y.js";
8
+ import "./targets-DvItNIvP.js";
9
+ import { a as isDiscordExecApprovalClientEnabled, i as isDiscordExecApprovalApprover, o as shouldSuppressLocalDiscordExecApprovalPrompt, r as getDiscordExecApprovalApprovers } from "./conversation-identity-BpkAzklg.js";
10
+ import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-nYmJ7FKQ.js";
11
11
  import { t as normalizeExplicitDiscordSessionKey } from "./session-key-normalization-wJgsKPNF.js";
12
- import { t as discordSetupPlugin } from "./channel.setup-tZcpIn4e.js";
13
- import { n as handleDiscordSubagentEnded, r as handleDiscordSubagentSpawning, t as handleDiscordSubagentDeliveryTarget } from "./subagent-hooks-B-bJxxGg.js";
14
- import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-CgJSNVui.js";
15
- import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-ByaUKL1f.js";
16
- import { t as fetchPluralKitMessageInfo } from "./pluralkit-DcD-3EcL.js";
17
- import { a as resolveDiscordPrivilegedIntentsFromFlags, i as probeDiscord, n as fetchDiscordApplicationSummary, r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-D1ImJEo2.js";
12
+ import { t as discordSetupPlugin } from "./channel.setup-DyihrqHH.js";
13
+ import { n as handleDiscordSubagentEnded, r as handleDiscordSubagentSpawning, t as handleDiscordSubagentDeliveryTarget } from "./subagent-hooks-DKJ4p-Oy.js";
14
+ import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-C_PQcBEV.js";
15
+ import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BUe-qq_C.js";
16
+ import { t as fetchPluralKitMessageInfo } from "./pluralkit-UXq1OyUI.js";
17
+ import { a as resolveDiscordPrivilegedIntentsFromFlags, i as probeDiscord, n as fetchDiscordApplicationSummary, r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-DxjMBeVG.js";
18
18
  import { t as collectDiscordSecurityAuditFindings } from "./security-audit-Bh_65L5C.js";
19
19
  import { resolveOpenProviderRuntimeGroupPolicy as resolveDiscordRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
20
20
  //#region extensions/discord/api.ts
21
- const handleDiscordMessageAction = async (...args) => (await import("./channel-actions.runtime-CVHlFqQg.js")).handleDiscordMessageAction(...args);
21
+ const handleDiscordMessageAction = async (...args) => (await import("./channel-actions.runtime-D8V8tyCq.js")).handleDiscordMessageAction(...args);
22
22
  //#endregion
23
23
  export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_COMPONENT_ATTACHMENT_PREFIX, DISCORD_COMPONENT_CUSTOM_ID_KEY, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, DISCORD_MODAL_CUSTOM_ID_KEY, DiscordApiError, DiscordFormModal, buildDiscordComponentCustomId, buildDiscordComponentMessage, buildDiscordComponentMessageFlags, buildDiscordInteractiveComponents, buildDiscordModalCustomId, collectDiscordSecurityAuditFindings, collectDiscordStatusIssues, createDiscordActionGate, createDiscordFormModal, discordPlugin, discordSetupPlugin, fetchDiscord, fetchDiscordApplicationId, fetchDiscordApplicationSummary, fetchPluralKitMessageInfo, formatDiscordComponentEventText, getDiscordExecApprovalApprovers, handleDiscordMessageAction, handleDiscordSubagentDeliveryTarget, handleDiscordSubagentEnded, handleDiscordSubagentSpawning, inspectDiscordAccount, isDiscordExecApprovalApprover, isDiscordExecApprovalClientEnabled, listDiscordAccountIds, listDiscordDirectoryGroupsFromConfig, listDiscordDirectoryPeersFromConfig, listEnabledDiscordAccounts, looksLikeDiscordTargetId, mergeAbortSignals, mergeDiscordAccountConfig, normalizeDiscordMessagingTarget, normalizeDiscordOutboundTarget, normalizeExplicitDiscordSessionKey, parseApplicationIdFromToken, parseDiscordComponentCustomId, parseDiscordComponentCustomIdForInteraction as parseDiscordComponentCustomIdForCarbon, parseDiscordComponentCustomIdForInteraction, parseDiscordModalCustomId, parseDiscordModalCustomIdForInteraction as parseDiscordModalCustomIdForCarbon, parseDiscordModalCustomIdForInteraction, parseDiscordSendTarget, parseDiscordTarget, probeDiscord, readDiscordComponentSpec, requestDiscord, resolveDefaultDiscordAccountId, resolveDiscordAccount, resolveDiscordAccountConfig, resolveDiscordChannelId, resolveDiscordComponentAttachmentName, resolveDiscordGroupRequireMention, resolveDiscordGroupToolPolicy, resolveDiscordMaxLinesPerMessage, resolveDiscordPrivilegedIntentsFromFlags, resolveDiscordRuntimeGroupPolicy, resolveDiscordTarget, shouldSuppressLocalDiscordExecApprovalPrompt, tryHandleDiscordMessageActionGuildAdmin };
@@ -0,0 +1,58 @@
1
+ import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
2
+ //#region extensions/discord/src/approval-custom-id.ts
3
+ const DISCORD_APPROVAL_CUSTOM_ID_MAX_CHARS = 100;
4
+ function encodeDiscordApprovalCustomId(action) {
5
+ return [
6
+ `execapproval:kind=${action.approvalKind}`,
7
+ `id=${encodeURIComponent(action.approvalId)}`,
8
+ `action=${action.decision}`
9
+ ].join(";");
10
+ }
11
+ function encodeBoundedDiscordApprovalCustomId(action) {
12
+ const exact = encodeDiscordApprovalCustomId(action);
13
+ if (exact.length <= DISCORD_APPROVAL_CUSTOM_ID_MAX_CHARS) return exact;
14
+ return encodeDiscordApprovalCustomId({
15
+ ...action,
16
+ approvalId: buildApprovalResolutionRef({
17
+ approvalId: action.approvalId,
18
+ approvalKind: action.approvalKind
19
+ })
20
+ });
21
+ }
22
+ function buildDiscordApprovalCustomId(action) {
23
+ if (!action.approvalId || action.approvalKind !== "exec" && action.approvalKind !== "plugin" || action.decision !== "allow-once" && action.decision !== "allow-always" && action.decision !== "deny") return;
24
+ return encodeBoundedDiscordApprovalCustomId(action);
25
+ }
26
+ function buildExecApprovalCustomId(approvalId, approvalKind, decision) {
27
+ return encodeBoundedDiscordApprovalCustomId({
28
+ type: "approval",
29
+ approvalId,
30
+ approvalKind,
31
+ decision
32
+ });
33
+ }
34
+ function decodeCustomIdValue(value) {
35
+ try {
36
+ return decodeURIComponent(value);
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ function parseExecApprovalData(data) {
42
+ if (!data || typeof data !== "object") return null;
43
+ const coerce = (value) => typeof value === "string" || typeof value === "number" ? String(value) : "";
44
+ const rawId = coerce(data.id);
45
+ const rawKind = coerce(data.kind);
46
+ const rawAction = coerce(data.action);
47
+ if (!rawId || rawKind !== "exec" && rawKind !== "plugin" || !rawAction) return null;
48
+ if (rawAction !== "allow-once" && rawAction !== "allow-always" && rawAction !== "deny") return null;
49
+ const approvalId = decodeCustomIdValue(rawId);
50
+ if (!approvalId) return null;
51
+ return {
52
+ approvalId,
53
+ approvalKind: rawKind,
54
+ action: rawAction
55
+ };
56
+ }
57
+ //#endregion
58
+ export { buildExecApprovalCustomId as n, parseExecApprovalData as r, buildDiscordApprovalCustomId as t };
@@ -1,7 +1,10 @@
1
- import { F as serializePayload, H as Button, Jt as __exportAll, Q as Separator, W as Container, X as Row, dt as createChannelMessage, et as TextDisplay, gt as editChannelMessage, mt as deleteChannelMessage, ot as createUserDmChannel } from "./send.receipt-BpBQED_5.js";
1
+ import { K as Container, L as serializePayload, Q as Row, W as Button, ct as createUserDmChannel, et as Separator, gt as deleteChannelMessage, nt as TextDisplay, pt as createChannelMessage, vt as editChannelMessage } from "./send.receipt-aegk69an.js";
2
2
  import { t as inspectDiscordAccount } from "./account-inspect-DDZtT5C8.js";
3
- import { F as createDiscordClient, b as stripUndefinedFields } from "./send.shared-wAwMhHDN.js";
4
- import { i as shouldHandleDiscordApprovalRequest, s as isDiscordExecApprovalClientEnabled } from "./conversation-identity-DWC5d8Sy.js";
3
+ import { F as createDiscordClient, b as stripUndefinedFields, g as createDiscordMessageNonce } from "./send.shared-Xz7IMVpu.js";
4
+ import { n as buildExecApprovalCustomId } from "./approval-custom-id-NYPYj9Po.js";
5
+ import { a as isDiscordExecApprovalClientEnabled } from "./conversation-identity-BpkAzklg.js";
6
+ import { a as shouldHandleDiscordApprovalRequest } from "./channel-nYmJ7FKQ.js";
7
+ import { n as formatDiscordApprovalDisplayValue, t as DISCORD_APPROVAL_ALLOWED_MENTIONS } from "./approval-message-safety-C-8BL6Kv.js";
5
8
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
9
  import { ButtonStyle } from "discord-api-types/v10";
7
10
  import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
@@ -37,10 +40,6 @@ var DiscordUiContainer = class extends Container {
37
40
  };
38
41
  //#endregion
39
42
  //#region extensions/discord/src/approval-handler.runtime.ts
40
- var approval_handler_runtime_exports = /* @__PURE__ */ __exportAll({
41
- buildExecApprovalCustomId: () => buildExecApprovalCustomId,
42
- discordApprovalNativeRuntime: () => discordApprovalNativeRuntime
43
- });
44
43
  function resolveHandlerContext(params) {
45
44
  const context = params.context;
46
45
  const accountId = normalizeOptionalString(params.accountId) ?? "";
@@ -80,7 +79,7 @@ var ExecApprovalContainer = class extends DiscordUiContainer {
80
79
  var ExecApprovalActionButton = class extends Button {
81
80
  constructor(params) {
82
81
  super();
83
- this.customId = buildExecApprovalCustomId(params.approvalId, params.descriptor.decision);
82
+ this.customId = buildExecApprovalCustomId(params.approvalId, params.approvalKind, params.descriptor.decision);
84
83
  this.label = params.descriptor.label;
85
84
  this.style = params.descriptor.style === "success" ? ButtonStyle.Success : params.descriptor.style === "primary" ? ButtonStyle.Primary : params.descriptor.style === "danger" ? ButtonStyle.Danger : ButtonStyle.Secondary;
86
85
  }
@@ -89,6 +88,7 @@ var ExecApprovalActionRow = class extends Row {
89
88
  constructor(params) {
90
89
  super(params.actions.map((descriptor) => new ExecApprovalActionButton({
91
90
  approvalId: params.approvalId,
91
+ approvalKind: params.approvalKind,
92
92
  descriptor
93
93
  })));
94
94
  }
@@ -96,6 +96,7 @@ var ExecApprovalActionRow = class extends Row {
96
96
  function createApprovalActionRow(view) {
97
97
  return new ExecApprovalActionRow({
98
98
  approvalId: view.approvalId,
99
+ approvalKind: view.approvalKind,
99
100
  actions: view.actions
100
101
  });
101
102
  }
@@ -103,7 +104,10 @@ function buildApprovalMetadataLines(metadata) {
103
104
  return metadata.map((item) => `- ${item.label}: ${item.value}`);
104
105
  }
105
106
  function buildExecApprovalPayload(container) {
106
- return { components: [container] };
107
+ return {
108
+ components: [container],
109
+ allowed_mentions: DISCORD_APPROVAL_ALLOWED_MENTIONS
110
+ };
107
111
  }
108
112
  const commandPreviewSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
109
113
  function* iterateCommandPreviewSegments(commandText) {
@@ -150,7 +154,7 @@ function createExecApprovalRequestContainer(params) {
150
154
  commandSecondaryPreview,
151
155
  metadataLines: buildApprovalMetadataLines(params.view.metadata),
152
156
  actionRow: params.actionRow,
153
- footer: `Expires <t:${expiresAtSeconds}:R> · ID: ${params.view.approvalId}`,
157
+ footer: `Expires <t:${expiresAtSeconds}:R> · ID: ${formatDiscordApprovalDisplayValue(params.view.approvalId)}`,
154
158
  accentColor: "#FFA500"
155
159
  });
156
160
  }
@@ -167,7 +171,7 @@ function createPluginApprovalRequestContainer(params) {
167
171
  commandSecondaryPreview: formatOptionalCommandPreview(params.view.description, 1e3),
168
172
  metadataLines: buildApprovalMetadataLines(params.view.metadata),
169
173
  actionRow: params.actionRow,
170
- footer: `Expires <t:${expiresAtSeconds}:R> · ID: ${params.view.approvalId}`,
174
+ footer: `Expires <t:${expiresAtSeconds}:R> · ID: ${formatDiscordApprovalDisplayValue(params.view.approvalId)}`,
171
175
  accentColor
172
176
  });
173
177
  }
@@ -179,11 +183,11 @@ function createExecResolvedContainer(params) {
179
183
  cfg: params.cfg,
180
184
  accountId: params.accountId,
181
185
  title: `Exec Approval: ${decisionLabel}`,
182
- description: params.view.resolvedBy ? `Resolved by ${params.view.resolvedBy}` : "Resolved",
186
+ description: params.view.resolvedBy ? `Resolved by ${formatDiscordApprovalDisplayValue(params.view.resolvedBy)}` : "Resolved",
183
187
  commandPreview,
184
188
  commandSecondaryPreview,
185
189
  metadataLines: buildApprovalMetadataLines(params.view.metadata),
186
- footer: `ID: ${params.view.approvalId}`,
190
+ footer: `ID: ${formatDiscordApprovalDisplayValue(params.view.approvalId)}`,
187
191
  accentColor
188
192
  });
189
193
  }
@@ -194,11 +198,11 @@ function createPluginResolvedContainer(params) {
194
198
  cfg: params.cfg,
195
199
  accountId: params.accountId,
196
200
  title: `Plugin Approval: ${decisionLabel}`,
197
- description: params.view.resolvedBy ? `Resolved by ${params.view.resolvedBy}` : "Resolved",
201
+ description: params.view.resolvedBy ? `Resolved by ${formatDiscordApprovalDisplayValue(params.view.resolvedBy)}` : "Resolved",
198
202
  commandPreview: formatCommandPreview(params.view.title, 700),
199
203
  commandSecondaryPreview: formatOptionalCommandPreview(params.view.description, 1e3),
200
204
  metadataLines: buildApprovalMetadataLines(params.view.metadata),
201
- footer: `ID: ${params.view.approvalId}`,
205
+ footer: `ID: ${formatDiscordApprovalDisplayValue(params.view.approvalId)}`,
202
206
  accentColor
203
207
  });
204
208
  }
@@ -212,7 +216,7 @@ function createExecExpiredContainer(params) {
212
216
  commandPreview,
213
217
  commandSecondaryPreview,
214
218
  metadataLines: buildApprovalMetadataLines(params.view.metadata),
215
- footer: `ID: ${params.view.approvalId}`,
219
+ footer: `ID: ${formatDiscordApprovalDisplayValue(params.view.approvalId)}`,
216
220
  accentColor: "#99AAB5"
217
221
  });
218
222
  }
@@ -225,13 +229,10 @@ function createPluginExpiredContainer(params) {
225
229
  commandPreview: formatCommandPreview(params.view.title, 700),
226
230
  commandSecondaryPreview: formatOptionalCommandPreview(params.view.description, 1e3),
227
231
  metadataLines: buildApprovalMetadataLines(params.view.metadata),
228
- footer: `ID: ${params.view.approvalId}`,
232
+ footer: `ID: ${formatDiscordApprovalDisplayValue(params.view.approvalId)}`,
229
233
  accentColor: "#99AAB5"
230
234
  });
231
235
  }
232
- function buildExecApprovalCustomId(approvalId, action) {
233
- return [`execapproval:id=${encodeURIComponent(approvalId)}`, `action=${action}`].join(";");
234
- }
235
236
  async function updateMessage(params) {
236
237
  try {
237
238
  const { rest, request: discordRequest } = createDiscordClient({
@@ -264,7 +265,6 @@ async function finalizeMessage(params) {
264
265
  }
265
266
  const discordApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
266
267
  eventKinds: ["exec", "plugin"],
267
- resolveApprovalKind: (request) => request.id.startsWith("plugin:") ? "plugin" : "exec",
268
268
  availability: {
269
269
  isConfigured: (params) => {
270
270
  const resolved = resolveHandlerContext(params);
@@ -392,7 +392,12 @@ const discordApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
392
392
  token: resolved.context.token,
393
393
  accountId: resolved.accountId
394
394
  });
395
- const message = await discordRequest(() => createChannelMessage(rest, preparedTarget.discordChannelId, { body: pendingPayload.body }), plannedTarget.surface === "origin" ? "send-approval-channel" : "send-approval");
395
+ const body = {
396
+ ...pendingPayload.body,
397
+ nonce: createDiscordMessageNonce(),
398
+ enforce_nonce: true
399
+ };
400
+ const message = await discordRequest(() => createChannelMessage(rest, preparedTarget.discordChannelId, { body }), plannedTarget.surface === "origin" ? "send-approval-channel" : "send-approval", { safety: "nonce-protected-create" });
396
401
  if (!message?.id) {
397
402
  if (plannedTarget.surface === "origin") logError("discord approvals: failed to send to channel");
398
403
  else if (preparedTarget.recipientUserId) logError(`discord approvals: failed to send message to user ${preparedTarget.recipientUserId}`);
@@ -443,4 +448,4 @@ const discordApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
443
448
  }
444
449
  });
445
450
  //#endregion
446
- export { approval_handler_runtime_exports as t };
451
+ export { discordApprovalNativeRuntime };
@@ -0,0 +1,47 @@
1
+ //#region extensions/discord/src/approval-message-safety.ts
2
+ const DISCORD_APPROVAL_ALLOWED_MENTIONS = { parse: [] };
3
+ const DISCORD_MARKDOWN_META_CHARACTERS = /* @__PURE__ */ new Set([
4
+ "\\",
5
+ "`",
6
+ "*",
7
+ "_",
8
+ "{",
9
+ "}",
10
+ "[",
11
+ "]",
12
+ "(",
13
+ ")",
14
+ "<",
15
+ ">",
16
+ "#",
17
+ "+",
18
+ "-",
19
+ ".",
20
+ "!",
21
+ "|",
22
+ "~"
23
+ ]);
24
+ function escapeDiscordApprovalDisplayCharacter(character) {
25
+ if (character === "\n") return "\\n";
26
+ if (character === "\r") return "\\r";
27
+ if (character === " ") return "\\t";
28
+ const codePoint = character.codePointAt(0) ?? 0;
29
+ if (codePoint <= 31 || codePoint >= 127 && codePoint <= 159 || codePoint === 8232 || codePoint === 8233) return `\\u{${codePoint.toString(16).padStart(4, "0")}}`;
30
+ return DISCORD_MARKDOWN_META_CHARACTERS.has(character) ? `\\${character}` : character;
31
+ }
32
+ /** Keep opaque approval metadata bounded, single-line, and inert in Discord Markdown. */
33
+ function formatDiscordApprovalDisplayValue(value, maxChars = 200) {
34
+ const limit = Number.isFinite(maxChars) ? Math.max(0, Math.trunc(maxChars)) : 200;
35
+ const escapedParts = Array.from(value, escapeDiscordApprovalDisplayCharacter);
36
+ const escaped = escapedParts.join("");
37
+ if (escaped.length <= limit) return escaped;
38
+ if (limit <= 3) return ".".repeat(limit);
39
+ let bounded = "";
40
+ for (const part of escapedParts) {
41
+ if (bounded.length + part.length > limit - 3) break;
42
+ bounded += part;
43
+ }
44
+ return `${bounded}...`;
45
+ }
46
+ //#endregion
47
+ export { formatDiscordApprovalDisplayValue as n, DISCORD_APPROVAL_ALLOWED_MENTIONS as t };
@@ -1,7 +1,7 @@
1
- import { Jt as __exportAll } from "./send.receipt-BpBQED_5.js";
1
+ import { Xt as __exportAll } from "./send.receipt-aegk69an.js";
2
2
  import { t as inspectDiscordAccount } from "./account-inspect-DDZtT5C8.js";
3
- import { O as fetchChannelPermissionsDiscord } from "./send.shared-wAwMhHDN.js";
4
- import "./send-iJ0B4bAX.js";
3
+ import { O as fetchChannelPermissionsDiscord } from "./send.shared-Xz7IMVpu.js";
4
+ import "./send-BFpa_DHn.js";
5
5
  import { n as collectDiscordAuditChannelIdsForAccount, t as auditDiscordChannelPermissionsWithFetcher } from "./audit-core-xwjIczO0.js";
6
6
  //#region extensions/discord/src/audit.ts
7
7
  var audit_exports = /* @__PURE__ */ __exportAll({
@@ -1,6 +1,6 @@
1
1
  import { t as inspectDiscordAccount } from "./account-inspect-DDZtT5C8.js";
2
2
  import { r as listDiscordAccountIds, t as createDiscordActionGate } from "./accounts-P19jm1lf.js";
3
- import { d as readDiscordComponentSpec } from "./components-BIBizbtZ.js";
3
+ import { d as readDiscordComponentSpec } from "./components-BVrfRS-F.js";
4
4
  import { i as withDiscordInboundEventDeliveryMetadata } from "./inbound-event-delivery-CEPlt2uz.js";
5
5
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -41,7 +41,7 @@ const localExecutionActions = /* @__PURE__ */ new Set([
41
41
  function resolveDiscordActionExecutionMode({ action }) {
42
42
  return localExecutionActions.has(action) ? "local" : "gateway";
43
43
  }
44
- const loadDiscordChannelActionsRuntime = createLazyRuntimeModule(() => import("./channel-actions.runtime-CVHlFqQg.js"));
44
+ const loadDiscordChannelActionsRuntime = createLazyRuntimeModule(() => import("./channel-actions.runtime-D8V8tyCq.js"));
45
45
  function listDiscoverableDiscordAccounts(cfg) {
46
46
  return listDiscordAccountIds(cfg).map((accountId) => inspectDiscordAccount({
47
47
  cfg,
@@ -185,7 +185,7 @@ const discordMessageActions = {
185
185
  }
186
186
  };
187
187
  },
188
- handleAction: async ({ action, params, cfg, accountId, requesterSenderId, senderIsOwner, toolContext, mediaAccess, mediaLocalRoots, mediaReadFile, sessionKey, inboundEventKind }) => {
188
+ handleAction: async ({ action, params, cfg, accountId, requesterAccountId, requesterSenderId, senderIsOwner, toolContext, mediaAccess, mediaLocalRoots, mediaReadFile, sessionKey, inboundEventKind, conversationReadOrigin }) => {
189
189
  return await (await loadDiscordChannelActionsRuntime()).handleDiscordMessageAction({
190
190
  action,
191
191
  params,
@@ -198,7 +198,9 @@ const discordMessageActions = {
198
198
  mediaLocalRoots,
199
199
  mediaReadFile,
200
200
  ...sessionKey ? { sessionKey } : {},
201
- ...inboundEventKind ? { inboundEventKind } : {}
201
+ ...inboundEventKind ? { inboundEventKind } : {},
202
+ ...requesterAccountId ? { requesterAccountId } : {},
203
+ ...conversationReadOrigin ? { conversationReadOrigin } : {}
202
204
  });
203
205
  }
204
206
  };
@@ -1,14 +1,15 @@
1
- import { qt as resolveDiscordChannelId } from "./send.receipt-BpBQED_5.js";
2
- import { i as buildDiscordPresentationComponents, r as buildDiscordInteractiveComponents } from "./components-BIBizbtZ.js";
3
- import "./targets-69w7c3vU.js";
4
- import { t as handleDiscordAction } from "./runtime-C6rRmQ6l.js";
1
+ import { Yt as resolveDiscordChannelId } from "./send.receipt-aegk69an.js";
2
+ import { i as buildDiscordPresentationComponents, r as buildDiscordInteractiveComponents } from "./components-BVrfRS-F.js";
3
+ import "./targets-DvItNIvP.js";
4
+ import { t as handleDiscordAction } from "./runtime-C618lis9.js";
5
5
  import "./action-runtime-api.js";
6
6
  import { r as notifyDiscordInboundEventOutboundSuccess } from "./inbound-event-delivery-CEPlt2uz.js";
7
- import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-CgJSNVui.js";
7
+ import { r as isDiscordComponentSpecWithinMessageLimit, t as DISCORD_PRESENTATION_CAPABILITIES } from "./outbound-components-oJKLj62G.js";
8
+ import { t as tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin-C_PQcBEV.js";
8
9
  import { normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
9
10
  import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
10
11
  import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
11
- import { normalizeInteractiveReply, normalizeMessagePresentation } from "openclaw/plugin-sdk/interactive-runtime";
12
+ import { adaptMessagePresentationForChannel, normalizeInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
12
13
  import { readPositiveIntegerParam, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
13
14
  //#region extensions/discord/src/actions/handle-action.ts
14
15
  const providerId = "discord";
@@ -20,10 +21,20 @@ function readCurrentDiscordTarget(toolContext) {
20
21
  async function handleDiscordMessageAction(ctx) {
21
22
  const { action, params, cfg } = ctx;
22
23
  const accountId = ctx.accountId ?? readStringParam(params, "accountId");
24
+ const readContext = ctx.requesterAccountId && ctx.toolContext?.currentChannelProvider && ctx.toolContext.currentChannelId ? {
25
+ requesterAccountId: ctx.requesterAccountId,
26
+ currentChannelProvider: ctx.toolContext.currentChannelProvider,
27
+ currentChannelId: ctx.toolContext.currentChannelId
28
+ } : void 0;
29
+ const readPolicyOptions = ctx.conversationReadOrigin || readContext ? {
30
+ ...ctx.conversationReadOrigin ? { conversationReadOrigin: ctx.conversationReadOrigin } : {},
31
+ ...readContext ? { readContext } : {}
32
+ } : void 0;
23
33
  const actionOptions = {
24
34
  mediaAccess: ctx.mediaAccess,
25
35
  mediaLocalRoots: ctx.mediaLocalRoots,
26
- mediaReadFile: ctx.mediaReadFile
36
+ mediaReadFile: ctx.mediaReadFile,
37
+ ...readPolicyOptions
27
38
  };
28
39
  const notifyVisibleOutbound = (to, fallbackSessionKey) => notifyDiscordInboundEventOutboundSuccess({
29
40
  sessionKey: ctx.sessionKey ?? fallbackSessionKey ?? void 0,
@@ -45,14 +56,31 @@ async function handleDiscordMessageAction(ctx) {
45
56
  if (action === "send") {
46
57
  const to = readSendTarget();
47
58
  const asVoice = readBooleanParam(params, "asVoice") === true;
48
- const rawComponents = params.components ?? buildDiscordPresentationComponents(normalizeMessagePresentation(params.presentation)) ?? buildDiscordInteractiveComponents(normalizeInteractiveReply(params.interactive));
59
+ const mediaUrl = readStringParam(params, "media", { trim: false }) ?? readStringParam(params, "path", { trim: false }) ?? readStringParam(params, "filePath", { trim: false });
60
+ const requestedContent = readStringParam(params, "message", { allowEmpty: true });
61
+ const presentation = params.components == null ? normalizeMessagePresentation(params.presentation) : void 0;
62
+ const adaptedPresentation = presentation ? adaptMessagePresentationForChannel({
63
+ presentation,
64
+ capabilities: DISCORD_PRESENTATION_CAPABILITIES
65
+ }) : void 0;
66
+ const generatedPresentationComponents = buildDiscordPresentationComponents(adaptedPresentation);
67
+ const presentationComponents = generatedPresentationComponents && isDiscordComponentSpecWithinMessageLimit({
68
+ spec: generatedPresentationComponents,
69
+ fallbackText: requestedContent,
70
+ includesMedia: Boolean(mediaUrl)
71
+ }) ? generatedPresentationComponents : void 0;
72
+ const presentationFellBack = Boolean(generatedPresentationComponents && !presentationComponents);
73
+ const rawComponents = presentationFellBack ? void 0 : params.components ?? presentationComponents ?? buildDiscordInteractiveComponents(normalizeInteractiveReply(params.interactive));
49
74
  const hasComponents = Boolean(rawComponents) && (typeof rawComponents === "function" || typeof rawComponents === "object");
50
75
  const components = hasComponents ? rawComponents : void 0;
51
- const mediaUrl = readStringParam(params, "media", { trim: false }) ?? readStringParam(params, "path", { trim: false }) ?? readStringParam(params, "filePath", { trim: false });
52
76
  const content = readStringParam(params, "message", {
53
- required: !asVoice && !hasComponents && !mediaUrl,
77
+ required: !asVoice && !hasComponents && !mediaUrl && !presentationFellBack,
54
78
  allowEmpty: true
55
79
  });
80
+ const deliveryContent = presentationFellBack && adaptedPresentation ? renderMessagePresentationFallbackText({
81
+ text: content,
82
+ presentation: adaptedPresentation
83
+ }) : content;
56
84
  const filename = readStringParam(params, "filename");
57
85
  const replyTo = readStringParam(params, "replyTo");
58
86
  const rawEmbeds = params.embeds;
@@ -66,7 +94,7 @@ async function handleDiscordMessageAction(ctx) {
66
94
  action: "sendMessage",
67
95
  accountId: accountId ?? void 0,
68
96
  to,
69
- content: content ?? "",
97
+ content: deliveryContent ?? "",
70
98
  ...threadName ? { threadName } : {},
71
99
  mediaUrl: mediaUrl ?? void 0,
72
100
  filename: filename ?? void 0,
@@ -248,7 +276,8 @@ async function handleDiscordMessageAction(ctx) {
248
276
  }, cfg, actionOptions);
249
277
  const adminResult = await tryHandleDiscordMessageActionGuildAdmin({
250
278
  ctx,
251
- resolveChannelId
279
+ resolveChannelId,
280
+ readPolicyOptions
252
281
  });
253
282
  if (adminResult !== void 0) {
254
283
  if (action === "thread-reply") notifyVisibleOutbound(readStringParam(params, "threadId") ?? readTarget());
@@ -1,2 +1,2 @@
1
- import { t as DiscordChannelConfigSchema } from "./config-schema-BgIhO3ko.js";
1
+ import { t as DiscordChannelConfigSchema } from "./config-schema-_bUKcWRm.js";
2
2
  export { DiscordChannelConfigSchema };