@openclaw/slack 2026.7.2-beta.7 → 2026.8.1-beta.3

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 (87) hide show
  1. package/dist/{account-inspect-DEKpg9Ip.js → account-inspect-YJvFBbCR.js} +1 -1
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CHAeNZOX.js → accounts-BlzxuYle.js} +7 -3
  4. package/dist/{accounts.runtime-BHD4Ma2R.js → accounts.runtime-CbabBL8x.js} +1 -1
  5. package/dist/{action-runtime-DfuYoMjG.js → action-runtime-D6jg2CQd.js} +193 -125
  6. package/dist/action-runtime.runtime-JtoOK9l5.js +2 -0
  7. package/dist/{actions-D3NuJvva.js → actions-DFk0ANVB.js} +116 -235
  8. package/dist/actions.runtime-CYLsYRai.js +2 -0
  9. package/dist/api.js +17 -17
  10. package/dist/{approval-handler.runtime-BA05P0QT.js → approval-handler.runtime-BNvAoKdK.js} +53 -14
  11. package/dist/{channel-B9fVdW3s.js → channel-CA5w7qDF.js} +209 -110
  12. package/dist/channel-config-api.js +1 -1
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel-type-DXyos1d2.js → channel-type-CZWv55Wu.js} +9 -12
  15. package/dist/{config-adapter-CxBQH8fq.js → channel.setup-CpyYsEXH.js} +83 -25
  16. package/dist/{config-schema-SgZT6nXV.js → config-schema-CN3XZRX5.js} +27 -17
  17. package/dist/conversation-binding-route-DFVLUdYF.js +115 -0
  18. package/dist/{directory-config-CnCIAktf.js → directory-config-BGYyuzWh.js} +3 -3
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-DKunWh3A.js → directory-live-DjUJQLbq.js} +13 -22
  21. package/dist/{doctor-contract-CsGH1Dfc.js → doctor-contract-BAy7-EUQ.js} +30 -3
  22. package/dist/doctor-contract-api.js +1 -1
  23. package/dist/{group-policy-NQZti9t-.js → group-policy-DyfB_ZIE.js} +282 -183
  24. package/dist/index.js +4 -1
  25. package/dist/{message-tool-api-DkhFpMoy.js → message-tool-api-CqMr5Rmc.js} +14 -3
  26. package/dist/message-tool-api.js +1 -1
  27. package/dist/{monitor-CmKz0wtI.js → monitor-Chrecrb9.js} +3 -3
  28. package/dist/{outbound-adapter-BkuMp2Vs.js → outbound-adapter-DuRqAQXK.js} +35 -23
  29. package/dist/{pipeline.runtime-DgtmuYCP.js → pipeline.runtime-Bbfd5VFW.js} +1386 -929
  30. package/dist/{policy-PRysPn23.js → policy-BKXSxrIS.js} +18 -14
  31. package/dist/{probe-CgDsSops.js → probe-BVA65leh.js} +38 -18
  32. package/dist/{provider-DmRizMZt.js → provider-CUUiwsg2.js} +3454 -2601
  33. package/dist/{relay-source-Blxj8xb4.js → relay-source-mhpMMRG-.js} +11 -21
  34. package/dist/{replies-4s_Vq_z9.js → replies-SnWyXcsL.js} +84 -27
  35. package/dist/{resolve-channels-yEqmM-3I.js → resolve-channels-BSpqC8jU.js} +39 -12
  36. package/dist/{resolve-users-BOrt5K-5.js → resolve-users-Dvz9pDe0.js} +28 -5
  37. package/dist/{runtime-api-QMb-Q5Ko.js → runtime-api-DBi7xc_g.js} +3 -3
  38. package/dist/runtime-api.js +11 -11
  39. package/dist/{scopes-BJSrkAp6.js → scopes-BSk4GZvZ.js} +1 -1
  40. package/dist/security-contract-api.js +1 -1
  41. package/dist/{send-DsLeZpST.js → send-CtnOxKCc.js} +249 -163
  42. package/dist/{send.runtime-gUdK6V3h.js → send.runtime-kYctMHSd.js} +1 -1
  43. package/dist/setup-entry.js +1 -4
  44. package/dist/setup-plugin-api.js +1 -1
  45. package/dist/{setup-surface-BeNzrMrJ.js → setup-surface-BPFfp6So.js} +6 -6
  46. package/dist/{shared-DgIN3Dcr.js → shared-DJBaslN7.js} +45 -45
  47. package/dist/{block-text-DkHaoGem.js → slack-client-kind-BXyOOICI.js} +17 -2
  48. package/dist/{slash-dispatch.runtime-zPkyl7dB.js → slash-dispatch.runtime-Cf2FTrnf.js} +2 -2
  49. package/dist/{streaming-compat-3_X-21wW.js → streaming-compat-B-e0mqM0.js} +3 -8
  50. package/dist/{target-parsing-N6lHogYZ.js → target-parsing-BnMD2ZqZ.js} +40 -2
  51. package/dist/{targets-KmjP2E8s.js → targets-Cx5W_n3W.js} +1 -1
  52. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  53. package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +1 -1
  54. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  55. package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
  56. package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +1 -1
  57. package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
  58. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  59. package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +1 -1
  60. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  61. package/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
  62. package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
  63. package/node_modules/undici/lib/core/request.js +12 -1
  64. package/node_modules/undici/lib/dispatcher/client-h1.js +11 -2
  65. package/node_modules/undici/lib/handler/cache-handler.js +246 -64
  66. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +3 -3
  67. package/node_modules/undici/lib/handler/retry-handler.js +24 -0
  68. package/node_modules/undici/lib/interceptor/cache.js +159 -52
  69. package/node_modules/undici/lib/util/cache.js +324 -62
  70. package/node_modules/undici/lib/util/date.js +23 -6
  71. package/node_modules/undici/lib/web/cookies/util.js +79 -9
  72. package/node_modules/undici/package.json +1 -1
  73. package/openclaw.plugin.json +280 -33
  74. package/package.json +9 -11
  75. package/skills/slack/SKILL.md +10 -68
  76. package/dist/account-reply-mode-DrUXogvO.js +0 -14
  77. package/dist/action-runtime.runtime-DQErZYpz.js +0 -2
  78. package/dist/actions.runtime-BIRU_G4M.js +0 -2
  79. package/dist/channel.setup-CLP5oTvh.js +0 -56
  80. package/dist/preflight-audio.runtime-D5Bgags0.js +0 -3
  81. package/dist/slash-plugin-commands.runtime-Dosfcx3X.js +0 -2
  82. package/node_modules/p-map/index.d.ts +0 -155
  83. package/node_modules/p-map/index.js +0 -285
  84. package/node_modules/p-map/license +0 -9
  85. package/node_modules/p-map/package.json +0 -57
  86. package/node_modules/p-map/readme.md +0 -190
  87. package/dist/{security-audit-DR097212.js → security-audit-B_yKr7MW.js} +1 -1
@@ -1,4 +1,4 @@
1
- import { i as resolveDefaultSlackAccountId, r as mergeSlackAccountConfig } from "./accounts-CHAeNZOX.js";
1
+ import { i as resolveDefaultSlackAccountId, r as mergeSlackAccountConfig } from "./accounts-BlzxuYle.js";
2
2
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
3
3
  import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -1,4 +1,4 @@
1
- import { t as inspectSlackAccount } from "./account-inspect-DEKpg9Ip.js";
1
+ import { t as inspectSlackAccount } from "./account-inspect-YJvFBbCR.js";
2
2
  //#region extensions/slack/account-inspect-api.ts
3
3
  function inspectSlackReadOnlyAccount(cfg, accountId) {
4
4
  return inspectSlackAccount({
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, hasConfiguredAccountValue, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
2
2
  import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
3
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { mapAllowFromEntries, normalizeChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-helpers";
5
5
  import { resolveAccountEntry } from "openclaw/plugin-sdk/routing";
6
6
  //#region extensions/slack/src/token.ts
@@ -39,7 +39,11 @@ function resolveSlackOperationToken(account, operation) {
39
39
  return account.config.userTokenReadOnly === false ? botToken ?? userToken : botToken;
40
40
  }
41
41
  const { listAccountIds, resolveDefaultAccountId, resolveAccountConfig: resolveMergedSlackAccountConfig } = createAccountListHelpers("slack", {
42
- nestedObjectKeys: ["botLoopProtection", "relay"],
42
+ nestedObjectKeys: [
43
+ "botLoopProtection",
44
+ "presenceEvents",
45
+ "relay"
46
+ ],
43
47
  hasImplicitDefaultAccount: (cfg) => {
44
48
  const slack = cfg.channels?.slack;
45
49
  if (slack?.postAs === "user") {
@@ -60,7 +64,7 @@ function resolveSlackAccountConfig(cfg, accountId) {
60
64
  return resolveAccountEntry(cfg.channels?.slack?.accounts, accountId);
61
65
  }
62
66
  function asStreamingConfigObject(value) {
63
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
67
+ return asOptionalRecord(value);
64
68
  }
65
69
  function asLegacyStreamingScalar(value) {
66
70
  return typeof value === "boolean" || typeof value === "string" ? value : void 0;
@@ -1,2 +1,2 @@
1
- import { a as resolveSlackAccount, l as resolveSlackOperationToken, o as resolveSlackAccountAllowFrom } from "./accounts-CHAeNZOX.js";
1
+ import { a as resolveSlackAccount, l as resolveSlackOperationToken, o as resolveSlackAccountAllowFrom } from "./accounts-BlzxuYle.js";
2
2
  export { resolveSlackAccount, resolveSlackAccountAllowFrom, resolveSlackOperationToken };
@@ -1,8 +1,8 @@
1
- import { a as resolveSlackChannelId, i as parseSlackTarget } from "./target-parsing-N6lHogYZ.js";
2
- import { t as slackContextTargetsMatch } from "./targets-KmjP2E8s.js";
3
- import { C as hasSlackNativeDataBlock, rt as parseSlackBlocksInput } from "./group-policy-NQZti9t-.js";
4
- import { a as readPositiveIntegerParam, c as withNormalizedTimestamp, n as imageResultFromFile, o as readReactionParams, r as jsonResult, s as readStringParam, t as createActionGate } from "./runtime-api-QMb-Q5Ko.js";
5
- import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-PRysPn23.js";
1
+ import { a as parseSlackTarget, n as formatSlackTarget, o as resolveSlackChannelId } from "./target-parsing-BnMD2ZqZ.js";
2
+ import { t as slackContextTargetsMatch } from "./targets-Cx5W_n3W.js";
3
+ import { Et as getSlackInstallationKind, Lt as SLACK_PRIVATE_ACTION_DELIVERY_RESULT, O as hasSlackNativeDataBlock, Rt as resolveSlackAutoThreadId, g as assertSlackDetachedTargetAllowed, pt as parseSlackBlocksInput, t as buildSlackChannelIdCandidates } from "./group-policy-DyfB_ZIE.js";
4
+ import { a as readPositiveIntegerParam, c as withNormalizedTimestamp, n as imageResultFromFile, o as readReactionParams, r as jsonResult, s as readStringParam, t as createActionGate } from "./runtime-api-DBi7xc_g.js";
5
+ import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-BKXSxrIS.js";
6
6
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
7
7
  import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
@@ -24,9 +24,10 @@ const pinActions = /* @__PURE__ */ new Set([
24
24
  "unpinMessage",
25
25
  "listPins"
26
26
  ]);
27
- const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-BIRU_G4M.js"));
28
- const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-BHD4Ma2R.js"));
29
- const loadSlackChannelTypeRuntime = createLazyRuntimeModule(() => import("./channel-type-DXyos1d2.js").then((n) => n.t));
27
+ const SLACK_REACTION_USER_LIMIT = 100;
28
+ const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-CYLsYRai.js"));
29
+ const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-CbabBL8x.js"));
30
+ const loadSlackChannelTypeRuntime = createLazyRuntimeModule(() => import("./channel-type-CZWv55Wu.js").then((n) => n.t));
30
31
  function createLazySlackAction(key) {
31
32
  return (async (...args) => {
32
33
  const action = (await loadSlackActionsRuntime())[key];
@@ -53,26 +54,15 @@ const slackActionRuntime = {
53
54
  sendSlackMessage: createLazySlackAction("sendSlackMessage"),
54
55
  unpinSlackMessage: createLazySlackAction("unpinSlackMessage")
55
56
  };
56
- /**
57
- * Resolve threadTs for a Slack message based on context and replyToMode.
58
- * - "all": always inject threadTs
59
- * - "first"/"batched": inject only for the first eligible message (updates hasRepliedRef)
60
- * - "off": never auto-inject
61
- */
62
57
  function resolveThreadTsFromContext(explicitThreadTs, targetChannel, context, opts) {
63
58
  if (explicitThreadTs) return explicitThreadTs;
64
59
  if (opts?.suppressImplicitThread) return;
65
- if (!context?.currentChannelId && !context?.currentMessagingTarget) return;
66
- if (!slackContextTargetsMatch(targetChannel, context)) return;
67
- if (!context.currentThreadTs) {
68
- if (context.sameChannelThreadRequired) throw new Error("Slack thread context is required for same-channel replies from a threaded Slack turn. Set topLevel=true or threadId=null to post at the channel root.");
69
- return;
70
- }
71
- if (context.replyToMode === "all") return context.currentThreadTs;
72
- if (isSingleUseReplyToMode(context.replyToMode ?? "off") && context.hasRepliedRef && !context.hasRepliedRef.value) {
73
- context.hasRepliedRef.value = true;
74
- return context.currentThreadTs;
75
- }
60
+ const threadTs = resolveSlackAutoThreadId({
61
+ to: targetChannel,
62
+ toolContext: context
63
+ });
64
+ if (isSingleUseReplyToMode(context?.replyToMode ?? "off") && !context?.hasRepliedRef) return;
65
+ return threadTs;
76
66
  }
77
67
  function readSlackBlocksParam(params) {
78
68
  return slackActionRuntime.parseSlackBlocksInput(params.blocks);
@@ -116,7 +106,7 @@ async function isSlackDmTargetConfigured(params) {
116
106
  }
117
107
  function isCurrentSlackReadTarget(params) {
118
108
  const requesterAccountId = params.context?.requesterAccountId?.trim();
119
- return Boolean(normalizeOptionalLowercaseString(params.context?.currentChannelProvider) === "slack" && requesterAccountId && normalizeAccountId(requesterAccountId) === normalizeAccountId(params.account.accountId) && params.context && slackContextTargetsMatch(params.channelId, params.context));
109
+ return Boolean(normalizeOptionalLowercaseString(params.context?.currentChannelProvider) === "slack" && requesterAccountId && normalizeAccountId(requesterAccountId) === normalizeAccountId(params.account.accountId) && params.context && slackContextTargetsMatch(params.target, params.context));
120
110
  }
121
111
  function assertSlackMemberInfoAllowed(params) {
122
112
  if (params.context?.conversationReadOrigin === "direct-operator") return;
@@ -128,6 +118,8 @@ function resolveSlackChannelReadPolicy(params) {
128
118
  const channels = params.account.config.channels;
129
119
  const channelKeys = Object.keys(channels ?? {});
130
120
  const channelConfig = resolveSlackChannelConfig({
121
+ teamId: params.teamId,
122
+ allowUnscoped: getSlackInstallationKind(params.account.accountId) !== "enterprise",
131
123
  channelId: params.channelId,
132
124
  channelName: params.channelName,
133
125
  channels,
@@ -163,7 +155,7 @@ function resolveSlackChannelReadPolicy(params) {
163
155
  return {
164
156
  channelAllowed: baseChannelAllowed,
165
157
  channelExplicitlyDisabled,
166
- groupDmAllowed: params.account.config.dm?.enabled !== false && params.account.config.dm?.groupEnabled === true && (params.currentConversation || isSlackGroupDmTargetConfigured(params.account, params.channelId)),
158
+ groupDmAllowed: params.account.config.dm?.enabled !== false && params.account.config.dm?.groupEnabled === true && (params.currentConversation || isSlackGroupDmTargetConfigured(params.account, params.channelId, params.teamId)),
167
159
  shouldResolveName
168
160
  };
169
161
  }
@@ -173,7 +165,11 @@ async function assertSlackReadTargetAllowed(params) {
173
165
  };
174
166
  const currentConversation = isCurrentSlackReadTarget({
175
167
  account: params.account,
176
- channelId: params.channelId,
168
+ target: formatSlackTarget({
169
+ teamId: params.teamId,
170
+ kind: "channel",
171
+ id: params.channelId
172
+ }),
177
173
  context: params.context
178
174
  });
179
175
  const directOperator = params.conversationReadOrigin === "direct-operator";
@@ -184,6 +180,7 @@ async function assertSlackReadTargetAllowed(params) {
184
180
  cfg: params.cfg,
185
181
  accountId: params.account.accountId,
186
182
  channelId: params.channelId,
183
+ teamId: params.teamId,
187
184
  operation: "read"
188
185
  });
189
186
  if (info.type !== "dm" || !await isSlackDmTargetConfigured({
@@ -205,6 +202,7 @@ async function assertSlackReadTargetAllowed(params) {
205
202
  cfg: params.cfg,
206
203
  accountId: params.account.accountId,
207
204
  channelId: params.channelId,
205
+ teamId: params.teamId,
208
206
  operation: "read",
209
207
  ...preliminary.shouldResolveName ? { requireFreshName: true } : {}
210
208
  });
@@ -225,17 +223,53 @@ async function assertSlackReadTargetAllowed(params) {
225
223
  }
226
224
  if (!(info.type === "channel" ? resolved.channelAllowed : info.type === "group" ? resolved.groupDmAllowed : resolved.channelAllowed && resolved.groupDmAllowed)) deny();
227
225
  }
228
- function isSlackGroupDmTargetConfigured(account, channelId) {
226
+ function isSlackGroupDmTargetConfigured(account, channelId, teamId) {
229
227
  const entries = account.config.dm?.groupChannels ?? [];
230
228
  if (entries.length === 0) return true;
229
+ const candidates = new Set(buildSlackChannelIdCandidates(channelId, teamId, { allowUnscoped: getSlackInstallationKind(account.accountId) !== "enterprise" }).map((candidate) => candidate.toLowerCase()));
231
230
  const target = channelId.trim().toLowerCase();
232
231
  return entries.some((entry) => {
233
232
  const candidate = String(entry).trim().toLowerCase();
234
- return candidate === "*" || candidate === target || candidate === `slack:${target}` || candidate === `channel:${target}` || candidate === `group:${target}` || candidate === `mpim:${target}`;
233
+ return candidate === "*" || candidates.has(candidate) || candidate === target || candidate === `slack:${target}` || candidate === `channel:${target}` || candidate === `group:${target}` || candidate === `mpim:${target}`;
235
234
  });
236
235
  }
236
+ function resolveTrustedCurrentSlackTeamId(params) {
237
+ const requesterAccountId = params.context?.requesterAccountId?.trim();
238
+ if (normalizeOptionalLowercaseString(params.context?.currentChannelProvider) !== "slack" || !requesterAccountId || normalizeAccountId(requesterAccountId) !== normalizeAccountId(params.account.accountId)) return;
239
+ const matchingTeams = /* @__PURE__ */ new Map();
240
+ for (const raw of [params.context?.currentChannelId, params.context?.currentMessagingTarget]) {
241
+ if (!raw) continue;
242
+ const current = parseSlackTarget(raw);
243
+ if (current?.teamId && (!params.target || current.kind === params.target.kind && current.id.toLowerCase() === params.target.id.toLowerCase())) matchingTeams.set(current.teamId.toLowerCase(), current.teamId);
244
+ }
245
+ return matchingTeams.size === 1 ? matchingTeams.values().next().value : void 0;
246
+ }
247
+ function resolveSlackActionTarget(account, raw, context) {
248
+ const parsed = parseSlackTarget(raw, { defaultKind: "channel" });
249
+ if (!parsed) throw new Error("Slack target is required.");
250
+ const teamId = parsed.teamId ?? resolveTrustedCurrentSlackTeamId({
251
+ account,
252
+ target: parsed,
253
+ context
254
+ });
255
+ assertSlackDetachedTargetAllowed(account.accountId, teamId);
256
+ return {
257
+ routingTarget: teamId ? formatSlackTarget({
258
+ teamId,
259
+ kind: parsed.kind,
260
+ id: parsed.id
261
+ }) : raw,
262
+ teamId
263
+ };
264
+ }
265
+ function resolveSlackActionChannelTarget(account, raw, context) {
266
+ const resolved = resolveSlackActionTarget(account, raw, context);
267
+ return {
268
+ channelId: resolveSlackChannelId(raw),
269
+ teamId: resolved.teamId
270
+ };
271
+ }
237
272
  async function handleSlackAction(params, cfg, context) {
238
- const resolveChannelId = () => resolveSlackChannelId(readStringParam(params, "channelId", { required: true }));
239
273
  const action = readStringParam(params, "action", { required: true });
240
274
  const accountId = readStringParam(params, "accountId");
241
275
  const { resolveSlackAccount, resolveSlackOperationToken } = await loadSlackAccountsRuntime();
@@ -243,38 +277,42 @@ async function handleSlackAction(params, cfg, context) {
243
277
  cfg,
244
278
  accountId
245
279
  });
246
- if (account.config.enterpriseOrgInstall === true) throw new Error("Slack action tools are unavailable for Enterprise Grid org installs.");
280
+ const resolveChannelTarget = () => resolveSlackActionChannelTarget(account, readStringParam(params, "channelId", { required: true }), context);
247
281
  const isActionEnabled = createActionGate(account.actions ?? cfg.channels?.slack?.actions);
248
282
  const botToken = account.botToken?.trim();
249
- const buildActionOpts = (operation) => {
283
+ const buildActionOpts = (operation, teamId) => {
250
284
  const token = resolveSlackOperationToken(account, operation);
251
285
  if (!token && account.identity === "user") throw new Error(`Slack operation token missing for account "${account.accountId}".`);
252
286
  const tokenOverride = token && token !== botToken ? token : void 0;
253
287
  return {
254
288
  cfg,
255
289
  ...accountId ? { accountId } : {},
256
- ...tokenOverride ? { token: tokenOverride } : {}
290
+ ...tokenOverride ? { token: tokenOverride } : {},
291
+ teamId
257
292
  };
258
293
  };
259
- const readOpts = buildActionOpts("read");
260
- const writeOpts = buildActionOpts("write");
261
- const assertReadTargetAllowed = async (channelId) => await assertSlackReadTargetAllowed({
262
- account,
263
- cfg,
264
- channelId,
265
- conversationReadOrigin: context?.conversationReadOrigin,
266
- context
267
- });
294
+ const assertReadTargetAllowed = async (target) => {
295
+ await assertSlackReadTargetAllowed({
296
+ account,
297
+ cfg,
298
+ channelId: target.channelId,
299
+ teamId: target.teamId,
300
+ conversationReadOrigin: context?.conversationReadOrigin,
301
+ context
302
+ });
303
+ };
268
304
  if (reactionsActions.has(action)) {
269
305
  if (!isActionEnabled("reactions")) throw new Error("Slack reactions are disabled.");
270
- const channelId = resolveChannelId();
306
+ const target = resolveChannelTarget();
307
+ const { channelId } = target;
308
+ const readOpts = buildActionOpts("read", target.teamId);
309
+ const writeOpts = buildActionOpts("write", target.teamId);
271
310
  const messageId = readStringParam(params, "messageId", { required: true });
272
311
  if (action === "react") {
273
312
  const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove a Slack reaction." });
274
- await assertReadTargetAllowed(channelId);
313
+ await assertReadTargetAllowed(target);
275
314
  if (remove) {
276
- if (writeOpts) await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji, writeOpts);
277
- else await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji);
315
+ await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji, writeOpts);
278
316
  return jsonResult({
279
317
  ok: true,
280
318
  removed: emoji
@@ -282,44 +320,58 @@ async function handleSlackAction(params, cfg, context) {
282
320
  }
283
321
  if (isEmpty) return jsonResult({
284
322
  ok: true,
285
- removed: writeOpts ? await slackActionRuntime.removeOwnSlackReactions(channelId, messageId, writeOpts) : await slackActionRuntime.removeOwnSlackReactions(channelId, messageId)
323
+ removed: await slackActionRuntime.removeOwnSlackReactions(channelId, messageId, writeOpts)
286
324
  });
287
- if (writeOpts) await slackActionRuntime.reactSlackMessage(channelId, messageId, emoji, writeOpts);
288
- else await slackActionRuntime.reactSlackMessage(channelId, messageId, emoji);
325
+ await slackActionRuntime.reactSlackMessage(channelId, messageId, emoji, writeOpts);
289
326
  return jsonResult({
290
327
  ok: true,
291
328
  added: emoji
292
329
  });
293
330
  }
294
- await assertReadTargetAllowed(channelId);
331
+ await assertReadTargetAllowed(target);
332
+ const limit = Math.min(readPositiveIntegerParam(params, "limit", { message: "limit must be a positive integer." }) ?? SLACK_REACTION_USER_LIMIT, SLACK_REACTION_USER_LIMIT);
295
333
  return jsonResult({
296
334
  ok: true,
297
- reactions: readOpts ? await slackActionRuntime.listSlackReactions(channelId, messageId, readOpts) : await slackActionRuntime.listSlackReactions(channelId, messageId)
335
+ reactions: (await slackActionRuntime.listSlackReactions(channelId, messageId, readOpts))?.map((reaction) => reaction.users ? Object.assign({}, reaction, { users: reaction.users.slice(0, limit) }) : reaction)
298
336
  });
299
337
  }
300
338
  if (messagingActions.has(action)) {
301
339
  if (!isActionEnabled("messages")) throw new Error("Slack messages are disabled.");
340
+ const sendSlackMessage = async (target, content, options) => {
341
+ const replyReference = context?.hasRepliedRef && slackContextTargetsMatch(target, context) ? context.hasRepliedRef : void 0;
342
+ const result = await slackActionRuntime.sendSlackMessage(target, content, {
343
+ ...options,
344
+ ...replyReference ? { [SLACK_PRIVATE_ACTION_DELIVERY_RESULT]: () => {
345
+ replyReference.value = true;
346
+ } } : {}
347
+ });
348
+ if (replyReference) replyReference.value = true;
349
+ return result;
350
+ };
302
351
  switch (action) {
303
352
  case "sendMessage": {
304
- const to = readStringParam(params, "to", { required: true });
353
+ const destination = resolveSlackActionTarget(account, readStringParam(params, "to", { required: true }), context).routingTarget;
305
354
  const content = readStringParam(params, "content", { allowEmpty: true });
306
355
  const mediaUrl = readStringParam(params, "mediaUrl");
307
356
  const blocks = readSlackBlocksParam(params);
308
357
  const replyBroadcast = readBooleanParam(params, "replyBroadcast");
309
358
  const textIsSlackMrkdwn = readBooleanParam(params, "textIsSlackMrkdwn");
310
359
  const textIsSlackPlainText = readBooleanParam(params, "textIsSlackPlainText");
360
+ const forceDocument = readBooleanParam(params, "forceDocument") === true;
311
361
  const preparedMessages = context?.preparedMessages;
312
362
  const authoredTextPlacement = readStringParam(params, "authoredTextPlacement");
313
363
  if (authoredTextPlacement && authoredTextPlacement !== "none" && authoredTextPlacement !== "blocks" && authoredTextPlacement !== "outside-blocks") throw new Error("Slack authoredTextPlacement is invalid.");
314
364
  const nativeDataFallbackBaseText = readStringParam(params, "nativeDataFallbackBaseText", { allowEmpty: true });
315
365
  if (!content && !mediaUrl && !blocks && !preparedMessages?.length) throw new Error("Slack sendMessage requires content, blocks, or mediaUrl.");
316
366
  if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
317
- const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), to, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
367
+ const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), destination, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
318
368
  const baseSendOpts = {
319
- ...writeOpts,
369
+ ...buildActionOpts("write"),
370
+ mediaAccess: context?.mediaAccess,
320
371
  mediaLocalRoots: context?.mediaLocalRoots,
321
372
  mediaReadFile: context?.mediaReadFile,
322
- threadTs: threadTs ?? void 0
373
+ threadTs: threadTs ?? void 0,
374
+ ...forceDocument ? { forceDocument: true } : {}
323
375
  };
324
376
  const sendOpts = {
325
377
  ...baseSendOpts,
@@ -333,52 +385,50 @@ async function handleSlackAction(params, cfg, context) {
333
385
  const shouldSplitLongContent = content && content.length > 8e3 && !hasSlackNativeDataBlock(blocks);
334
386
  if (content && shouldSplitLongContent) {
335
387
  const { replyBroadcast: _replyBroadcast, ...blockSendOpts } = sendOpts;
336
- await slackActionRuntime.sendSlackMessage(to, "", {
388
+ await sendSlackMessage(destination, "", {
337
389
  ...blockSendOpts,
338
390
  blocks
339
391
  });
340
- return await slackActionRuntime.sendSlackMessage(to, content, sendOpts);
392
+ return await sendSlackMessage(destination, content, sendOpts);
341
393
  }
342
- return await slackActionRuntime.sendSlackMessage(to, content ?? "", {
394
+ return await sendSlackMessage(destination, content ?? "", {
343
395
  ...sendOpts,
344
396
  blocks
345
397
  });
346
398
  };
347
- const result = preparedMessages?.length ? await (async () => {
348
- let lastResult;
349
- if (mediaUrl) lastResult = await slackActionRuntime.sendSlackMessage(to, "", {
350
- ...baseSendOpts,
351
- mediaUrl
352
- });
353
- for (const [index, message] of preparedMessages.entries()) lastResult = await slackActionRuntime.sendSlackMessage(to, message.text, {
354
- ...baseSendOpts,
355
- ...index === 0 && replyBroadcast ? { replyBroadcast: true } : {},
356
- ...message.blocks ? { blocks: message.blocks } : {},
357
- ...message.authoredTextPlacement ? { authoredTextPlacement: message.authoredTextPlacement } : {},
358
- ...Object.hasOwn(message, "nativeDataFallbackBaseText") ? { nativeDataFallbackBaseText: message.nativeDataFallbackBaseText } : {},
359
- ...message.textIsSlackPlainText ? { textIsSlackPlainText: true } : {}
360
- });
361
- if (!lastResult) throw new Error("Slack prepared message plan produced no delivery.");
362
- return lastResult;
363
- })() : blocks ? await (async () => {
364
- if (mediaUrl) await slackActionRuntime.sendSlackMessage(to, "", {
365
- ...sendOpts,
366
- mediaUrl
367
- });
368
- return await sendContentAndBlocks();
369
- })() : await slackActionRuntime.sendSlackMessage(to, content ?? "", {
370
- ...sendOpts,
371
- mediaUrl: mediaUrl ?? void 0,
372
- blocks
373
- });
374
- if (context?.hasRepliedRef && slackContextTargetsMatch(to, context)) context.hasRepliedRef.value = true;
375
399
  return jsonResult({
376
400
  ok: true,
377
- result
401
+ result: preparedMessages?.length ? await (async () => {
402
+ let lastResult;
403
+ if (mediaUrl) lastResult = await sendSlackMessage(destination, "", {
404
+ ...baseSendOpts,
405
+ mediaUrl
406
+ });
407
+ for (const [index, message] of preparedMessages.entries()) lastResult = await sendSlackMessage(destination, message.text, {
408
+ ...baseSendOpts,
409
+ ...index === 0 && replyBroadcast ? { replyBroadcast: true } : {},
410
+ ...message.blocks ? { blocks: message.blocks } : {},
411
+ ...message.authoredTextPlacement ? { authoredTextPlacement: message.authoredTextPlacement } : {},
412
+ ...Object.hasOwn(message, "nativeDataFallbackBaseText") ? { nativeDataFallbackBaseText: message.nativeDataFallbackBaseText } : {},
413
+ ...message.textIsSlackPlainText ? { textIsSlackPlainText: true } : {}
414
+ });
415
+ if (!lastResult) throw new Error("Slack prepared message plan produced no delivery.");
416
+ return lastResult;
417
+ })() : blocks ? await (async () => {
418
+ if (mediaUrl) await sendSlackMessage(destination, "", {
419
+ ...sendOpts,
420
+ mediaUrl
421
+ });
422
+ return await sendContentAndBlocks();
423
+ })() : await sendSlackMessage(destination, content ?? "", {
424
+ ...sendOpts,
425
+ mediaUrl: mediaUrl ?? void 0,
426
+ blocks
427
+ })
378
428
  });
379
429
  }
380
430
  case "uploadFile": {
381
- const to = readStringParam(params, "to", { required: true });
431
+ const destination = resolveSlackActionTarget(account, readStringParam(params, "to", { required: true }), context).routingTarget;
382
432
  const filePath = readStringParam(params, "filePath", {
383
433
  required: true,
384
434
  trim: false
@@ -386,48 +436,53 @@ async function handleSlackAction(params, cfg, context) {
386
436
  const initialComment = readStringParam(params, "initialComment", { allowEmpty: true });
387
437
  const filename = readStringParam(params, "filename");
388
438
  const title = readStringParam(params, "title");
439
+ const forceDocument = readBooleanParam(params, "forceDocument") === true;
389
440
  if (readBooleanParam(params, "replyBroadcast")) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
390
- const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), to, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
391
- const result = await slackActionRuntime.sendSlackMessage(to, initialComment ?? "", {
392
- ...writeOpts,
393
- mediaUrl: filePath,
394
- mediaLocalRoots: context?.mediaLocalRoots,
395
- mediaReadFile: context?.mediaReadFile,
396
- threadTs: threadTs ?? void 0,
397
- ...filename ? { uploadFileName: filename } : {},
398
- ...title ? { uploadTitle: title } : {}
399
- });
400
- if (context?.hasRepliedRef && slackContextTargetsMatch(to, context)) context.hasRepliedRef.value = true;
441
+ const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), destination, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
401
442
  return jsonResult({
402
443
  ok: true,
403
- result
444
+ result: await sendSlackMessage(destination, initialComment ?? "", {
445
+ ...buildActionOpts("write"),
446
+ mediaUrl: filePath,
447
+ mediaAccess: context?.mediaAccess,
448
+ mediaLocalRoots: context?.mediaLocalRoots,
449
+ mediaReadFile: context?.mediaReadFile,
450
+ threadTs: threadTs ?? void 0,
451
+ ...forceDocument ? { forceDocument: true } : {},
452
+ ...filename ? { uploadFileName: filename } : {},
453
+ ...title ? { uploadTitle: title } : {}
454
+ })
404
455
  });
405
456
  }
406
457
  case "editMessage": {
407
- const channelId = resolveChannelId();
458
+ const target = resolveChannelTarget();
459
+ const { channelId } = target;
408
460
  const messageId = readStringParam(params, "messageId", { required: true });
409
461
  const content = readStringParam(params, "content", { allowEmpty: true });
410
462
  const blocks = readSlackBlocksParam(params);
411
463
  if (!content && !blocks) throw new Error("Slack editMessage requires content or blocks.");
412
- await assertReadTargetAllowed(channelId);
413
- if (writeOpts) await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", {
464
+ await assertReadTargetAllowed(target);
465
+ const writeOpts = buildActionOpts("write", target.teamId);
466
+ await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", {
414
467
  ...writeOpts,
415
468
  blocks
416
469
  });
417
- else await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", { blocks });
418
470
  return jsonResult({ ok: true });
419
471
  }
420
472
  case "deleteMessage": {
421
- const channelId = resolveChannelId();
473
+ const target = resolveChannelTarget();
474
+ const { channelId } = target;
422
475
  const messageId = readStringParam(params, "messageId", { required: true });
423
- await assertReadTargetAllowed(channelId);
424
- if (writeOpts) await slackActionRuntime.deleteSlackMessage(channelId, messageId, writeOpts);
425
- else await slackActionRuntime.deleteSlackMessage(channelId, messageId);
476
+ await assertReadTargetAllowed(target);
477
+ const writeOpts = buildActionOpts("write", target.teamId);
478
+ await slackActionRuntime.deleteSlackMessage(channelId, messageId, writeOpts);
426
479
  return jsonResult({ ok: true });
427
480
  }
428
481
  case "readMessages": {
429
- const channelId = resolveChannelId();
430
- await assertReadTargetAllowed(channelId);
482
+ const target = resolveChannelTarget();
483
+ const { channelId } = target;
484
+ await assertReadTargetAllowed(target);
485
+ const readOpts = buildActionOpts("read", target.teamId);
431
486
  const limit = readPositiveIntegerParam(params, "limit", { message: "limit must be a positive integer." });
432
487
  const before = readStringParam(params, "before");
433
488
  const after = readStringParam(params, "after");
@@ -454,14 +509,16 @@ async function handleSlackAction(params, cfg, context) {
454
509
  const fileId = readStringParam(params, "fileId", { required: true });
455
510
  const channelTarget = readStringParam(params, "channelId") ?? readStringParam(params, "to") ?? context?.currentChannelId;
456
511
  if (!channelTarget) throw new Error("Slack file download requires channelId or to so the read target can be authorized.");
457
- const channelId = resolveSlackChannelId(channelTarget);
458
- await assertReadTargetAllowed(channelId);
512
+ const target = resolveSlackActionChannelTarget(account, channelTarget, context);
513
+ const { channelId } = target;
514
+ await assertReadTargetAllowed(target);
459
515
  const threadId = readStringParam(params, "threadId") ?? readStringParam(params, "replyTo");
460
516
  const maxBytes = account.config?.mediaMaxMb ? account.config.mediaMaxMb * 1024 * 1024 : 20 * 1024 * 1024;
461
517
  const readToken = resolveSlackOperationToken(account, "read");
518
+ const readOpts = buildActionOpts("read", target.teamId);
462
519
  const downloaded = await slackActionRuntime.downloadSlackFile(fileId, {
463
520
  ...readOpts,
464
- ...readToken && !readOpts?.token ? { token: readToken } : {},
521
+ ...readToken && !readOpts.token ? { token: readToken } : {},
465
522
  maxBytes,
466
523
  channelId,
467
524
  threadId: threadId ?? void 0
@@ -499,25 +556,26 @@ async function handleSlackAction(params, cfg, context) {
499
556
  }
500
557
  if (pinActions.has(action)) {
501
558
  if (!isActionEnabled("pins")) throw new Error("Slack pins are disabled.");
502
- const channelId = resolveChannelId();
559
+ const target = resolveChannelTarget();
560
+ const { channelId } = target;
561
+ const readOpts = buildActionOpts("read", target.teamId);
562
+ const writeOpts = buildActionOpts("write", target.teamId);
503
563
  if (action === "pinMessage") {
504
564
  const messageId = readStringParam(params, "messageId", { required: true });
505
- await assertReadTargetAllowed(channelId);
506
- if (writeOpts) await slackActionRuntime.pinSlackMessage(channelId, messageId, writeOpts);
507
- else await slackActionRuntime.pinSlackMessage(channelId, messageId);
565
+ await assertReadTargetAllowed(target);
566
+ await slackActionRuntime.pinSlackMessage(channelId, messageId, writeOpts);
508
567
  return jsonResult({ ok: true });
509
568
  }
510
569
  if (action === "unpinMessage") {
511
570
  const messageId = readStringParam(params, "messageId", { required: true });
512
- await assertReadTargetAllowed(channelId);
513
- if (writeOpts) await slackActionRuntime.unpinSlackMessage(channelId, messageId, writeOpts);
514
- else await slackActionRuntime.unpinSlackMessage(channelId, messageId);
571
+ await assertReadTargetAllowed(target);
572
+ await slackActionRuntime.unpinSlackMessage(channelId, messageId, writeOpts);
515
573
  return jsonResult({ ok: true });
516
574
  }
517
- await assertReadTargetAllowed(channelId);
575
+ await assertReadTargetAllowed(target);
518
576
  return jsonResult({
519
577
  ok: true,
520
- pins: (writeOpts ? await slackActionRuntime.listSlackPins(channelId, readOpts) : await slackActionRuntime.listSlackPins(channelId)).map((pin) => {
578
+ pins: (await slackActionRuntime.listSlackPins(channelId, readOpts)).map((pin) => {
521
579
  const message = pin.message ? withNormalizedTimestamp(pin.message, pin.message.ts) : pin.message;
522
580
  return message ? Object.assign({}, pin, { message }) : pin;
523
581
  })
@@ -531,15 +589,25 @@ async function handleSlackAction(params, cfg, context) {
531
589
  context,
532
590
  userId
533
591
  });
592
+ const teamId = resolveTrustedCurrentSlackTeamId({
593
+ account,
594
+ context
595
+ });
596
+ assertSlackDetachedTargetAllowed(account.accountId, teamId);
534
597
  return jsonResult({
535
598
  ok: true,
536
- info: readOpts ? await slackActionRuntime.getSlackMemberInfo(userId, readOpts) : await slackActionRuntime.getSlackMemberInfo(userId)
599
+ info: await slackActionRuntime.getSlackMemberInfo(userId, buildActionOpts("read", teamId))
537
600
  });
538
601
  }
539
602
  if (action === "emojiList") {
540
603
  if (!isActionEnabled("emojiList")) throw new Error("Slack emoji list is disabled.");
541
604
  const limit = readPositiveIntegerParam(params, "limit", { message: "limit must be a positive integer." });
542
- const result = readOpts ? await slackActionRuntime.listSlackEmojis(readOpts) : await slackActionRuntime.listSlackEmojis();
605
+ const teamId = resolveTrustedCurrentSlackTeamId({
606
+ account,
607
+ context
608
+ });
609
+ assertSlackDetachedTargetAllowed(account.accountId, teamId);
610
+ const result = await slackActionRuntime.listSlackEmojis(buildActionOpts("read", teamId));
543
611
  if (limit != null && limit > 0 && result.emoji != null) {
544
612
  const entries = Object.entries(result.emoji).toSorted(([a], [b]) => a.localeCompare(b));
545
613
  if (entries.length > limit) return jsonResult({
@@ -0,0 +1,2 @@
1
+ import { t as handleSlackAction } from "./action-runtime-D6jg2CQd.js";
2
+ export { handleSlackAction };