@openclaw/slack 2026.5.12-beta.7

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 (88) hide show
  1. package/dist/account-inspect-D7AZNs8C.js +77 -0
  2. package/dist/account-inspect-api.js +10 -0
  3. package/dist/accounts-ClAPP5ry.js +139 -0
  4. package/dist/accounts.runtime-DDVcLJUI.js +2 -0
  5. package/dist/action-runtime-e2UhRsNx.js +350 -0
  6. package/dist/action-runtime.runtime-BFcqMbOm.js +2 -0
  7. package/dist/actions-CYLFK-Zy.js +292 -0
  8. package/dist/actions.runtime-CO3OaTLb.js +2 -0
  9. package/dist/allow-list-BPnnlRPL.js +82 -0
  10. package/dist/api.js +21 -0
  11. package/dist/approval-handler.runtime-CmeRr9qA.js +256 -0
  12. package/dist/blocks-input-CwTFVImV.js +29 -0
  13. package/dist/blocks-render-BIDw-Pom.js +161 -0
  14. package/dist/channel-DRjHBTDB.js +1020 -0
  15. package/dist/channel-api-B_nZwosg.js +20 -0
  16. package/dist/channel-config-api.js +2 -0
  17. package/dist/channel-entry.js +22 -0
  18. package/dist/channel-plugin-api.js +2 -0
  19. package/dist/channel.setup-Cayn7afd.js +73 -0
  20. package/dist/client-CPe4GmDR.js +103 -0
  21. package/dist/config-api-B_jq4NJW.js +2 -0
  22. package/dist/config-schema-D9B5LB_L.js +167 -0
  23. package/dist/configured-state.js +11 -0
  24. package/dist/contract-api.js +5 -0
  25. package/dist/directory-config-B3JiHeB7.js +54 -0
  26. package/dist/directory-contract-api.js +2 -0
  27. package/dist/directory-live-Bf16GwDh.js +133 -0
  28. package/dist/doctor-contract-KUjHnkQm.js +147 -0
  29. package/dist/doctor-contract-api.js +2 -0
  30. package/dist/errors-BYFHR24f.js +109 -0
  31. package/dist/exec-approvals-7xUNgLi9.js +58 -0
  32. package/dist/group-policy-CyLUK6My.js +41 -0
  33. package/dist/http-routes-api.js +2 -0
  34. package/dist/inbound-contract-test-api.js +3 -0
  35. package/dist/index.js +33 -0
  36. package/dist/interactive-replies-api.js +2 -0
  37. package/dist/interactive-replies-qAIfuBor.js +173 -0
  38. package/dist/magic-string.es-BMaGRRZ1.js +1011 -0
  39. package/dist/media-D1XCd1uP.js +469 -0
  40. package/dist/message-tool-api-6lowf9zE.js +104 -0
  41. package/dist/message-tool-api.js +2 -0
  42. package/dist/monitor-a97o17G6.js +13 -0
  43. package/dist/mrkdwn-Cax-eSfK.js +6 -0
  44. package/dist/outbound-adapter-B_5sEhCg.js +174 -0
  45. package/dist/outbound-payload-test-api.js +2 -0
  46. package/dist/outbound-payload.test-harness-CVCamg1x.js +13558 -0
  47. package/dist/pipeline.runtime-DT0hLnq2.js +1379 -0
  48. package/dist/plugin-routes-DtTPmga1.js +20 -0
  49. package/dist/prepare-D3YqV8jB.js +1482 -0
  50. package/dist/prepare.test-helpers-DVcjRhfG.js +49 -0
  51. package/dist/probe-3eZf1FjI.js +42 -0
  52. package/dist/provider-D7uAN3Fq.js +3235 -0
  53. package/dist/registry-CeaoNfoP.js +39 -0
  54. package/dist/replies-Xe_jMR6o.js +139 -0
  55. package/dist/reply-blocks-Z5l6_R6H.js +14 -0
  56. package/dist/resolve-allowlist-common-Bk3clYPK.js +43 -0
  57. package/dist/resolve-channels-BRYqyNVJ.js +81 -0
  58. package/dist/resolve-users-Bd_SdP8j.js +113 -0
  59. package/dist/rolldown-runtime-CiIaOW0V.js +13 -0
  60. package/dist/room-context-0vovmZPU.js +787 -0
  61. package/dist/runtime-Bo-KHM-F.js +8 -0
  62. package/dist/runtime-api-Dd1xIV5v.js +9 -0
  63. package/dist/runtime-api.js +14 -0
  64. package/dist/runtime-setter-api.js +2 -0
  65. package/dist/scopes-CDevO8jg.js +74 -0
  66. package/dist/secret-contract-Bo6lbSkh.js +141 -0
  67. package/dist/secret-contract-api.js +2 -0
  68. package/dist/security-audit-BtHGnD3d.js +51 -0
  69. package/dist/security-contract-api.js +2 -0
  70. package/dist/send-D_A9kL-C.js +721 -0
  71. package/dist/send.runtime-BRE_ncCU.js +2 -0
  72. package/dist/send.runtime-_l76lUuL.js +2 -0
  73. package/dist/setup-core-B9NetDkM.js +320 -0
  74. package/dist/setup-entry.js +15 -0
  75. package/dist/setup-plugin-api.js +2 -0
  76. package/dist/setup-surface-D88QBVOW.js +128 -0
  77. package/dist/shared-D8U42xFL.js +208 -0
  78. package/dist/slash-commands.runtime-22kgyst2.js +19 -0
  79. package/dist/slash-dispatch.runtime-BJgT0jwV.js +32 -0
  80. package/dist/slash-plugin-commands.runtime-CF-n3MeP.js +2 -0
  81. package/dist/slash-skill-commands.runtime-BMs0VjTe.js +7 -0
  82. package/dist/streaming-compat-RkZgTmQ2.js +43 -0
  83. package/dist/target-parsing-CQmv-iSm.js +55 -0
  84. package/dist/targets-B1tYCAr6.js +2 -0
  85. package/dist/test-api.js +8 -0
  86. package/dist/thread-ts-C2x7c5PP.js +24 -0
  87. package/openclaw.plugin.json +2405 -0
  88. package/package.json +84 -0
@@ -0,0 +1,1020 @@
1
+ import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, l as resolveSlackReplyToMode, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom } from "./accounts-ClAPP5ry.js";
2
+ import { i as resolveSlackChannelId, n as normalizeSlackMessagingTarget, r as parseSlackTarget, t as looksLikeSlackTargetId } from "./target-parsing-CQmv-iSm.js";
3
+ import "./targets-B1tYCAr6.js";
4
+ import { a as normalizeSlackApproverId, c as shouldSuppressLocalSlackExecApprovalPrompt, i as isSlackExecApprovalClientEnabled, o as resolveSlackExecApprovalTarget, r as isSlackExecApprovalAuthorizedSender, s as shouldHandleSlackExecApprovalRequest, t as getSlackExecApprovalApprovers } from "./exec-approvals-7xUNgLi9.js";
5
+ import { n as buildSlackPresentationBlocks, r as resolveSlackInteractiveBlockOffsets, t as buildSlackInteractiveBlocks } from "./blocks-render-BIDw-Pom.js";
6
+ import { n as resolveSlackThreadTsValue, r as SLACK_TEXT_LIMIT, t as normalizeSlackThreadTsCandidate } from "./thread-ts-C2x7c5PP.js";
7
+ import { n as extractSlackToolSend, t as describeSlackMessageTool } from "./message-tool-api-6lowf9zE.js";
8
+ import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-qAIfuBor.js";
9
+ import { a as resolveConfiguredFromRequiredCredentialStatuses, i as projectCredentialSnapshotFields, n as PAIRING_APPROVED_MESSAGE, t as DEFAULT_ACCOUNT_ID } from "./channel-api-B_nZwosg.js";
10
+ import { r as createSlackWebClient } from "./client-CPe4GmDR.js";
11
+ import { r as normalizeAllowListLower } from "./allow-list-BPnnlRPL.js";
12
+ import { n as resolveSlackGroupToolPolicy, t as resolveSlackGroupRequireMention } from "./group-policy-CyLUK6My.js";
13
+ import { t as resolveSlackReplyBlocks } from "./reply-blocks-Z5l6_R6H.js";
14
+ import { t as getOptionalSlackRuntime } from "./runtime-Bo-KHM-F.js";
15
+ import { i as slackSecurityAdapter, n as isSlackPluginAccountConfigured, r as slackConfigAdapter, t as createSlackPluginBase } from "./shared-D8U42xFL.js";
16
+ import { i as SLACK_CHANNEL, n as createSlackSetupWizardProxy, r as slackSetupAdapter } from "./setup-core-B9NetDkM.js";
17
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
18
+ import { adaptScopedAccountAccessor } from "openclaw/plugin-sdk/channel-config-helpers";
19
+ import { buildOutboundBaseSessionKey } from "openclaw/plugin-sdk/routing";
20
+ import { buildLegacyDmAccountAllowlistAdapter, createAccountScopedAllowlistNameResolver, createFlatAllowlistOverrideResolver } from "openclaw/plugin-sdk/allowlist-config-edit";
21
+ import { buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
22
+ import { createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-message";
23
+ import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
24
+ import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
25
+ import { createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter } from "openclaw/plugin-sdk/directory-runtime";
26
+ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
27
+ import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-send-deps";
28
+ import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
29
+ import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
30
+ import { createApproverRestrictedNativeApprovalCapability, splitChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
31
+ import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
32
+ import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
33
+ import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
34
+ import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
35
+ import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
36
+ import { normalizeInteractiveReply, normalizeMessagePresentation } from "openclaw/plugin-sdk/interactive-runtime";
37
+ import { readNumberParam, readStringParam } from "openclaw/plugin-sdk/param-readers";
38
+ //#region extensions/slack/src/action-threading.ts
39
+ function resolveSlackAutoThreadId(params) {
40
+ const context = params.toolContext;
41
+ if (!context?.currentThreadTs || !context.currentChannelId) return;
42
+ if (context.replyToMode !== "all" && !isSingleUseReplyToMode(context.replyToMode ?? "off")) return;
43
+ const parsedTarget = parseSlackTarget(params.to, { defaultKind: "channel" });
44
+ if (!parsedTarget || parsedTarget.kind !== "channel") return;
45
+ if (normalizeLowercaseStringOrEmpty(parsedTarget.id) !== normalizeLowercaseStringOrEmpty(context.currentChannelId)) return;
46
+ if (isSingleUseReplyToMode(context.replyToMode ?? "off") && context.hasRepliedRef?.value) return;
47
+ return context.currentThreadTs;
48
+ }
49
+ //#endregion
50
+ //#region extensions/slack/src/approval-auth.ts
51
+ function getSlackApprovalApprovers(params) {
52
+ const account = resolveSlackAccount(params).config;
53
+ return resolveApprovalApprovers({
54
+ allowFrom: resolveSlackAccountAllowFrom(params),
55
+ defaultTo: account.defaultTo,
56
+ normalizeApprover: normalizeSlackApproverId,
57
+ normalizeDefaultTo: normalizeSlackApproverId
58
+ });
59
+ }
60
+ function isSlackApprovalAuthorizedSender(params) {
61
+ const senderId = params.senderId ? normalizeSlackApproverId(params.senderId) : void 0;
62
+ if (!senderId) return false;
63
+ return getSlackApprovalApprovers(params).includes(senderId);
64
+ }
65
+ createResolvedApproverActionAuthAdapter({
66
+ channelLabel: "Slack",
67
+ resolveApprovers: ({ cfg, accountId }) => getSlackApprovalApprovers({
68
+ cfg,
69
+ accountId
70
+ }),
71
+ normalizeSenderId: (value) => normalizeSlackApproverId(value)
72
+ });
73
+ //#endregion
74
+ //#region extensions/slack/src/approval-native.ts
75
+ function extractSlackSessionKind(sessionKey) {
76
+ if (!sessionKey) return null;
77
+ const kind = normalizeLowercaseStringOrEmpty(sessionKey.match(/slack:(direct|channel|group):/i)?.[1]);
78
+ return kind ? kind : null;
79
+ }
80
+ function normalizeComparableTarget(value) {
81
+ return normalizeLowercaseStringOrEmpty(value);
82
+ }
83
+ function normalizeSlackThreadMatchKey(threadId) {
84
+ const trimmed = threadId?.trim();
85
+ if (!trimmed) return "";
86
+ return trimmed.match(/^\d+/)?.[0] ?? trimmed;
87
+ }
88
+ function resolveTurnSourceSlackOriginTarget(request) {
89
+ const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel);
90
+ const turnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? "";
91
+ if (turnSourceChannel !== "slack" || !turnSourceTo) return null;
92
+ const parsed = parseSlackTarget(turnSourceTo, { defaultKind: extractSlackSessionKind(request.request.sessionKey ?? void 0) === "direct" ? "user" : "channel" });
93
+ if (!parsed) return null;
94
+ const threadId = stringifyRouteThreadId(request.request.turnSourceThreadId);
95
+ return {
96
+ to: `${parsed.kind}:${parsed.id}`,
97
+ threadId
98
+ };
99
+ }
100
+ function resolveSessionSlackOriginTarget(sessionTarget) {
101
+ return {
102
+ to: sessionTarget.to,
103
+ threadId: stringifyRouteThreadId(sessionTarget.threadId)
104
+ };
105
+ }
106
+ function resolveSlackFallbackOriginTarget(request) {
107
+ const sessionTarget = resolveApprovalRequestSessionConversation({
108
+ request,
109
+ channel: "slack",
110
+ bundledFallback: false
111
+ });
112
+ if (!sessionTarget) return null;
113
+ const parsed = parseSlackTarget(sessionTarget.id.toUpperCase(), { defaultKind: "channel" });
114
+ if (!parsed) return null;
115
+ return {
116
+ to: `${parsed.kind}:${parsed.id}`,
117
+ threadId: sessionTarget.threadId
118
+ };
119
+ }
120
+ function normalizeSlackOriginTarget(target) {
121
+ return {
122
+ ...target,
123
+ to: normalizeComparableTarget(target.to)
124
+ };
125
+ }
126
+ function slackTargetsMatch(a, b) {
127
+ return channelRouteTargetsMatchExact({
128
+ left: {
129
+ channel: "slack",
130
+ to: a.to
131
+ },
132
+ right: {
133
+ channel: "slack",
134
+ to: b.to
135
+ }
136
+ }) && normalizeSlackThreadMatchKey(a.threadId) === normalizeSlackThreadMatchKey(b.threadId);
137
+ }
138
+ const slackApprovalCapability = createApproverRestrictedNativeApprovalCapability({
139
+ channel: "slack",
140
+ channelLabel: "Slack",
141
+ describeExecApprovalSetup: ({ accountId }) => {
142
+ const prefix = accountId && accountId !== "default" ? `channels.slack.accounts.${accountId}` : "channels.slack";
143
+ return `Approve it from the Web UI or terminal UI for now. Slack supports native exec approvals for this account. Configure \`${prefix}.execApprovals.approvers\` or \`commands.ownerAllowFrom\`; leave \`${prefix}.execApprovals.enabled\` unset/\`auto\` or set it to \`true\`.`;
144
+ },
145
+ listAccountIds: listSlackAccountIds,
146
+ hasApprovers: ({ cfg, accountId }) => getSlackExecApprovalApprovers({
147
+ cfg,
148
+ accountId
149
+ }).length > 0,
150
+ isExecAuthorizedSender: ({ cfg, accountId, senderId }) => isSlackExecApprovalAuthorizedSender({
151
+ cfg,
152
+ accountId,
153
+ senderId
154
+ }),
155
+ isPluginAuthorizedSender: ({ cfg, accountId, senderId }) => isSlackApprovalAuthorizedSender({
156
+ cfg,
157
+ accountId,
158
+ senderId
159
+ }),
160
+ isNativeDeliveryEnabled: ({ cfg, accountId }) => isSlackExecApprovalClientEnabled({
161
+ cfg,
162
+ accountId
163
+ }),
164
+ resolveNativeDeliveryMode: ({ cfg, accountId }) => resolveSlackExecApprovalTarget({
165
+ cfg,
166
+ accountId
167
+ }),
168
+ requireMatchingTurnSourceChannel: true,
169
+ resolveSuppressionAccountId: ({ target, request }) => normalizeOptionalString(target.accountId) ?? normalizeOptionalString(request.request.turnSourceAccountId),
170
+ resolveOriginTarget: createChannelNativeOriginTargetResolver({
171
+ channel: "slack",
172
+ shouldHandleRequest: ({ cfg, accountId, request }) => shouldHandleSlackExecApprovalRequest({
173
+ cfg,
174
+ accountId,
175
+ request
176
+ }),
177
+ resolveTurnSourceTarget: resolveTurnSourceSlackOriginTarget,
178
+ resolveSessionTarget: resolveSessionSlackOriginTarget,
179
+ normalizeTargetForMatch: normalizeSlackOriginTarget,
180
+ targetsMatch: slackTargetsMatch,
181
+ resolveFallbackTarget: resolveSlackFallbackOriginTarget
182
+ }),
183
+ resolveApproverDmTargets: createChannelApproverDmTargetResolver({
184
+ shouldHandleRequest: ({ cfg, accountId, request }) => shouldHandleSlackExecApprovalRequest({
185
+ cfg,
186
+ accountId,
187
+ request
188
+ }),
189
+ resolveApprovers: getSlackExecApprovalApprovers,
190
+ mapApprover: (approver) => ({ to: `user:${approver}` })
191
+ }),
192
+ notifyOriginWhenDmOnly: true,
193
+ nativeRuntime: createLazyChannelApprovalNativeRuntimeAdapter({
194
+ eventKinds: ["exec"],
195
+ isConfigured: ({ cfg, accountId }) => isSlackExecApprovalClientEnabled({
196
+ cfg,
197
+ accountId
198
+ }),
199
+ shouldHandle: ({ cfg, accountId, request }) => shouldHandleSlackExecApprovalRequest({
200
+ cfg,
201
+ accountId,
202
+ request
203
+ }),
204
+ load: async () => (await import("./approval-handler.runtime-CmeRr9qA.js")).slackApprovalNativeRuntime
205
+ })
206
+ });
207
+ splitChannelApprovalCapability(slackApprovalCapability);
208
+ //#endregion
209
+ //#region extensions/slack/src/message-action-dispatch.ts
210
+ /** Translate generic channel action requests into Slack-specific tool invocations and payload shapes. */
211
+ async function handleSlackMessageAction(params) {
212
+ const { providerId, ctx, invoke, normalizeChannelId, includeReadThreadId = false } = params;
213
+ const { action, cfg, params: actionParams } = ctx;
214
+ const accountId = ctx.accountId ?? void 0;
215
+ const resolveChannelId = () => {
216
+ const channelId = readStringParam(actionParams, "channelId") ?? readStringParam(actionParams, "to", { required: true });
217
+ return normalizeChannelId ? normalizeChannelId(channelId) : channelId;
218
+ };
219
+ if (action === "send") {
220
+ const to = readStringParam(actionParams, "to", { required: true });
221
+ const content = readStringParam(actionParams, "message", {
222
+ required: false,
223
+ allowEmpty: true
224
+ });
225
+ const mediaUrl = readStringParam(actionParams, "media", { trim: false });
226
+ const presentation = normalizeMessagePresentation(actionParams.presentation);
227
+ const interactive = normalizeInteractiveReply(actionParams.interactive);
228
+ const presentationBlocks = presentation ? buildSlackPresentationBlocks(presentation) : void 0;
229
+ const interactiveBlocks = interactive ? buildSlackInteractiveBlocks(interactive, resolveSlackInteractiveBlockOffsets(presentationBlocks)) : void 0;
230
+ const mergedBlocks = [...presentationBlocks ?? [], ...interactiveBlocks ?? []];
231
+ const blocks = mergedBlocks.length > 0 ? mergedBlocks : void 0;
232
+ if (!content && !mediaUrl && !blocks) throw new Error("Slack send requires message, blocks, or media.");
233
+ const replyBroadcast = readBooleanParam(actionParams, "replyBroadcast");
234
+ if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
235
+ const threadId = readStringParam(actionParams, "threadId");
236
+ const replyTo = readStringParam(actionParams, "replyTo");
237
+ const topLevel = readBooleanParam(actionParams, "topLevel") === true || actionParams.threadId === null;
238
+ return await invoke({
239
+ action: "sendMessage",
240
+ to,
241
+ content: content ?? "",
242
+ mediaUrl: mediaUrl ?? void 0,
243
+ accountId,
244
+ threadTs: threadId ?? replyTo ?? void 0,
245
+ ...topLevel ? { topLevel: true } : {},
246
+ ...replyBroadcast ? { replyBroadcast } : {},
247
+ ...blocks ? { blocks } : {}
248
+ }, cfg, ctx.toolContext);
249
+ }
250
+ if (action === "react") {
251
+ const messageId = readStringParam(actionParams, "messageId", { required: true });
252
+ const emoji = readStringParam(actionParams, "emoji", { allowEmpty: true });
253
+ const remove = typeof actionParams.remove === "boolean" ? actionParams.remove : void 0;
254
+ return await invoke({
255
+ action: "react",
256
+ channelId: resolveChannelId(),
257
+ messageId,
258
+ emoji,
259
+ remove,
260
+ accountId
261
+ }, cfg);
262
+ }
263
+ if (action === "reactions") {
264
+ const messageId = readStringParam(actionParams, "messageId", { required: true });
265
+ const limit = readNumberParam(actionParams, "limit", { integer: true });
266
+ return await invoke({
267
+ action: "reactions",
268
+ channelId: resolveChannelId(),
269
+ messageId,
270
+ limit,
271
+ accountId
272
+ }, cfg);
273
+ }
274
+ if (action === "read") {
275
+ const limit = readNumberParam(actionParams, "limit", { integer: true });
276
+ const readAction = {
277
+ action: "readMessages",
278
+ channelId: resolveChannelId(),
279
+ limit,
280
+ before: readStringParam(actionParams, "before"),
281
+ after: readStringParam(actionParams, "after"),
282
+ messageId: readStringParam(actionParams, "messageId"),
283
+ accountId
284
+ };
285
+ if (includeReadThreadId) readAction.threadId = readStringParam(actionParams, "threadId");
286
+ return await invoke(readAction, cfg);
287
+ }
288
+ if (action === "edit") {
289
+ const messageId = readStringParam(actionParams, "messageId", { required: true });
290
+ const content = readStringParam(actionParams, "message", { allowEmpty: true });
291
+ const presentation = normalizeMessagePresentation(actionParams.presentation);
292
+ const blocks = presentation ? buildSlackPresentationBlocks(presentation) : void 0;
293
+ if (!content && !blocks) throw new Error("Slack edit requires message or blocks.");
294
+ return await invoke({
295
+ action: "editMessage",
296
+ channelId: resolveChannelId(),
297
+ messageId,
298
+ content: content ?? "",
299
+ blocks,
300
+ accountId
301
+ }, cfg);
302
+ }
303
+ if (action === "delete") {
304
+ const messageId = readStringParam(actionParams, "messageId", { required: true });
305
+ return await invoke({
306
+ action: "deleteMessage",
307
+ channelId: resolveChannelId(),
308
+ messageId,
309
+ accountId
310
+ }, cfg);
311
+ }
312
+ if (action === "pin" || action === "unpin" || action === "list-pins") {
313
+ const messageId = action === "list-pins" ? void 0 : readStringParam(actionParams, "messageId", { required: true });
314
+ return await invoke({
315
+ action: action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins",
316
+ channelId: resolveChannelId(),
317
+ messageId,
318
+ accountId
319
+ }, cfg);
320
+ }
321
+ if (action === "member-info") return await invoke({
322
+ action: "memberInfo",
323
+ userId: readStringParam(actionParams, "userId", { required: true }),
324
+ accountId
325
+ }, cfg);
326
+ if (action === "emoji-list") return await invoke({
327
+ action: "emojiList",
328
+ limit: readNumberParam(actionParams, "limit", { integer: true }),
329
+ accountId
330
+ }, cfg);
331
+ if (action === "download-file") {
332
+ const fileIdParam = readStringParam(actionParams, "fileId");
333
+ const messageIdParam = readStringParam(actionParams, "messageId") ?? readStringParam(actionParams, "message_id");
334
+ if (!fileIdParam && messageIdParam) throw new Error("download-file requires fileId (the Slack file id, for example F0B0LTT8M36 from event.files[].id), not messageId. Did you mean to pass fileId? messageId is the Slack message timestamp and is used by react / reactions / edit / delete / pin / unpin actions, not download-file.");
335
+ const fileId = readStringParam(actionParams, "fileId", { required: true });
336
+ const channelId = readStringParam(actionParams, "channelId") ?? readStringParam(actionParams, "to");
337
+ const threadId = readStringParam(actionParams, "threadId") ?? readStringParam(actionParams, "replyTo");
338
+ return await invoke({
339
+ action: "downloadFile",
340
+ fileId,
341
+ channelId: channelId ?? void 0,
342
+ threadId: threadId ?? void 0,
343
+ accountId
344
+ }, cfg);
345
+ }
346
+ if (action === "upload-file") {
347
+ if (readBooleanParam(actionParams, "replyBroadcast")) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
348
+ const to = readStringParam(actionParams, "to") ?? resolveChannelId();
349
+ const filePath = readStringParam(actionParams, "filePath", { trim: false }) ?? readStringParam(actionParams, "path", { trim: false }) ?? readStringParam(actionParams, "media", { trim: false });
350
+ if (!filePath) throw new Error("upload-file requires filePath, path, or media");
351
+ const threadId = readStringParam(actionParams, "threadId") ?? readStringParam(actionParams, "replyTo");
352
+ const topLevel = readBooleanParam(actionParams, "topLevel") === true || actionParams.threadId === null;
353
+ return await invoke({
354
+ action: "uploadFile",
355
+ to,
356
+ filePath,
357
+ initialComment: readStringParam(actionParams, "initialComment", { allowEmpty: true }) ?? readStringParam(actionParams, "message", { allowEmpty: true }) ?? "",
358
+ filename: readStringParam(actionParams, "filename"),
359
+ title: readStringParam(actionParams, "title"),
360
+ threadTs: threadId ?? void 0,
361
+ ...topLevel ? { topLevel: true } : {},
362
+ accountId
363
+ }, cfg, ctx.toolContext);
364
+ }
365
+ throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
366
+ }
367
+ //#endregion
368
+ //#region extensions/slack/src/channel-actions.ts
369
+ let slackActionRuntimePromise$1;
370
+ async function loadSlackActionRuntime$1() {
371
+ slackActionRuntimePromise$1 ??= import("./action-runtime.runtime-BFcqMbOm.js");
372
+ return await slackActionRuntimePromise$1;
373
+ }
374
+ function resolveSlackActionContext(params) {
375
+ if (!params.toolContext && !params.mediaLocalRoots && !params.mediaReadFile) return;
376
+ return {
377
+ ...params.toolContext,
378
+ ...params.mediaLocalRoots ? { mediaLocalRoots: params.mediaLocalRoots } : {},
379
+ ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {}
380
+ };
381
+ }
382
+ function createSlackActions(providerId, options) {
383
+ return {
384
+ describeMessageTool: describeSlackMessageTool,
385
+ extractToolSend: ({ args }) => extractSlackToolSend(args),
386
+ prepareSendPayload: ({ ctx, payload }) => ctx.action === "send" ? payload : null,
387
+ handleAction: async (ctx) => {
388
+ return await handleSlackMessageAction({
389
+ providerId,
390
+ ctx,
391
+ normalizeChannelId: resolveSlackChannelId,
392
+ includeReadThreadId: true,
393
+ invoke: async (action, cfg, toolContext) => {
394
+ const actionContext = resolveSlackActionContext({
395
+ toolContext,
396
+ mediaLocalRoots: ctx.mediaLocalRoots,
397
+ mediaReadFile: ctx.mediaReadFile
398
+ });
399
+ return await (options?.invoke ? options.invoke(action, cfg, actionContext) : (await loadSlackActionRuntime$1()).handleSlackAction(action, cfg, actionContext));
400
+ }
401
+ });
402
+ }
403
+ };
404
+ }
405
+ //#endregion
406
+ //#region extensions/slack/src/channel-type.ts
407
+ const SLACK_CONVERSATION_INFO_CACHE = /* @__PURE__ */ new Map();
408
+ async function resolveSlackConversationInfo(params) {
409
+ const channelId = params.channelId.trim();
410
+ if (!channelId) return { type: "unknown" };
411
+ const account = resolveSlackAccount({
412
+ cfg: params.cfg,
413
+ accountId: params.accountId
414
+ });
415
+ const cacheKey = `${account.accountId}:${channelId}`;
416
+ const cached = SLACK_CONVERSATION_INFO_CACHE.get(cacheKey);
417
+ if (cached) return cached;
418
+ const isNativeImChannel = /^D/i.test(channelId);
419
+ const groupChannels = normalizeAllowListLower(account.dm?.groupChannels);
420
+ const channelIdLower = normalizeLowercaseStringOrEmpty(channelId);
421
+ if (!isNativeImChannel && (groupChannels.includes(channelIdLower) || groupChannels.includes(`slack:${channelIdLower}`) || groupChannels.includes(`channel:${channelIdLower}`) || groupChannels.includes(`group:${channelIdLower}`) || groupChannels.includes(`mpim:${channelIdLower}`))) {
422
+ const result = { type: "group" };
423
+ SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
424
+ return result;
425
+ }
426
+ const channelKeys = Object.keys(account.channels ?? {});
427
+ if (!isNativeImChannel && channelKeys.some((key) => {
428
+ const normalized = normalizeLowercaseStringOrEmpty(key);
429
+ return normalized === channelIdLower || normalized === `channel:${channelIdLower}` || normalized.replace(/^#/, "") === channelIdLower;
430
+ })) {
431
+ const result = { type: "channel" };
432
+ SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
433
+ return result;
434
+ }
435
+ const token = normalizeOptionalString(account.botToken) ?? normalizeOptionalString(account.config.userToken) ?? "";
436
+ if (!token) {
437
+ const result = { type: isNativeImChannel ? "dm" : "unknown" };
438
+ if (!isNativeImChannel) SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
439
+ return result;
440
+ }
441
+ try {
442
+ const client = createSlackWebClient(token);
443
+ if (isNativeImChannel) {
444
+ const opened = await client.conversations.open({
445
+ channel: channelId,
446
+ prevent_creation: true,
447
+ return_im: true
448
+ });
449
+ const user = typeof opened.channel?.user === "string" && opened.channel.user.trim() ? opened.channel.user.trim() : void 0;
450
+ const result = user ? {
451
+ type: "dm",
452
+ user
453
+ } : { type: "dm" };
454
+ if (user) SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
455
+ return result;
456
+ }
457
+ const channel = (await client.conversations.info({ channel: channelId })).channel;
458
+ const result = { type: channel?.is_im ? "dm" : channel?.is_mpim ? "group" : "channel" };
459
+ SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
460
+ return result;
461
+ } catch {
462
+ const result = { type: isNativeImChannel ? "dm" : "unknown" };
463
+ if (!isNativeImChannel) SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
464
+ return result;
465
+ }
466
+ }
467
+ async function resolveSlackChannelType(params) {
468
+ return (await resolveSlackConversationInfo(params)).type;
469
+ }
470
+ function __resetSlackChannelTypeCacheForTest() {
471
+ SLACK_CONVERSATION_INFO_CACHE.clear();
472
+ }
473
+ //#endregion
474
+ //#region extensions/slack/src/threading-tool-context.ts
475
+ function buildSlackThreadingToolContext(params) {
476
+ const configuredReplyToMode = resolveSlackReplyToMode(resolveSlackAccount({
477
+ cfg: params.cfg,
478
+ accountId: params.accountId
479
+ }), params.context.ChatType);
480
+ const effectiveReplyToMode = params.context.MessageThreadId != null ? "all" : configuredReplyToMode;
481
+ const threadId = params.context.MessageThreadId ?? params.context.ReplyToId;
482
+ return {
483
+ currentChannelId: params.context.To?.startsWith("channel:") ? params.context.To.slice(8) : normalizeOptionalString(params.context.NativeChannelId),
484
+ currentThreadTs: normalizeSlackThreadTsCandidate(threadId),
485
+ replyToMode: effectiveReplyToMode,
486
+ hasRepliedRef: params.hasRepliedRef
487
+ };
488
+ }
489
+ //#endregion
490
+ //#region extensions/slack/src/channel.ts
491
+ const EXTENSION_SHARED_MODULE_ID = "openclaw/plugin-sdk/extension-shared";
492
+ const TARGET_RESOLVER_RUNTIME_MODULE_ID = "openclaw/plugin-sdk/target-resolver-runtime";
493
+ const loadExtensionSharedSdk = createLazyRuntimeModule(() => import(EXTENSION_SHARED_MODULE_ID));
494
+ const loadTargetResolverRuntimeSdk = createLazyRuntimeModule(() => import(TARGET_RESOLVER_RUNTIME_MODULE_ID));
495
+ const loadSlackSetupSurfaceModule = createLazyRuntimeModule(() => import("./setup-surface-D88QBVOW.js"));
496
+ const loadSlackScopesModule = createLazyRuntimeModule(() => import("./scopes-CDevO8jg.js"));
497
+ const loadSlackOutboundAdapterModule = createLazyRuntimeModule(() => import("./outbound-adapter-B_5sEhCg.js").then((n) => n.t));
498
+ async function resolveSlackHandleAction() {
499
+ return getOptionalSlackRuntime()?.channel?.slack?.handleSlackAction ?? (await loadSlackActionRuntime()).handleSlackAction;
500
+ }
501
+ function shouldTreatSlackDeliveredTextAsVisible(params) {
502
+ return params.kind === "block" && typeof params.text === "string" && params.text.trim().length > 0;
503
+ }
504
+ function getTokenForOperation(account, operation) {
505
+ const userToken = normalizeOptionalString(account.config.userToken);
506
+ const botToken = normalizeOptionalString(account.botToken);
507
+ const allowUserWrites = account.config.userTokenReadOnly === false;
508
+ if (operation === "read") return userToken ?? botToken;
509
+ if (!allowUserWrites) return botToken;
510
+ return botToken ?? userToken;
511
+ }
512
+ let slackActionRuntimePromise;
513
+ let slackSendRuntimePromise;
514
+ let slackProbeModulePromise;
515
+ let slackMonitorModulePromise;
516
+ let slackDirectoryLiveModulePromise;
517
+ const loadSlackDirectoryConfigModule = createLazyRuntimeModule(() => import("./directory-config-B3JiHeB7.js").then((n) => n.t));
518
+ const loadSlackResolveChannelsModule = createLazyRuntimeModule(() => import("./resolve-channels-BRYqyNVJ.js").then((n) => n.n));
519
+ const loadSlackResolveUsersModule = createLazyRuntimeModule(() => import("./resolve-users-Bd_SdP8j.js").then((n) => n.n));
520
+ async function loadSlackActionRuntime() {
521
+ slackActionRuntimePromise ??= import("./action-runtime.runtime-BFcqMbOm.js");
522
+ return await slackActionRuntimePromise;
523
+ }
524
+ async function loadSlackSendRuntime() {
525
+ slackSendRuntimePromise ??= import("./send.runtime-_l76lUuL.js");
526
+ return await slackSendRuntimePromise;
527
+ }
528
+ async function loadSlackProbeModule() {
529
+ slackProbeModulePromise ??= import("./probe-3eZf1FjI.js").then((n) => n.n);
530
+ return await slackProbeModulePromise;
531
+ }
532
+ async function loadSlackMonitorModule() {
533
+ slackMonitorModulePromise ??= import("./monitor-a97o17G6.js").then((n) => n.t);
534
+ return await slackMonitorModulePromise;
535
+ }
536
+ async function loadSlackDirectoryLiveModule() {
537
+ slackDirectoryLiveModulePromise ??= import("./directory-live-Bf16GwDh.js").then((n) => n.t);
538
+ return await slackDirectoryLiveModulePromise;
539
+ }
540
+ async function resolveSlackSendContext(params) {
541
+ const send = resolveOutboundSendDep(params.deps, "slack") ?? (await loadSlackSendRuntime()).sendMessageSlack;
542
+ const account = resolveSlackAccount({
543
+ cfg: params.cfg,
544
+ accountId: params.accountId
545
+ });
546
+ const token = getTokenForOperation(account, "write");
547
+ const botToken = account.botToken?.trim();
548
+ const tokenOverride = token && token !== botToken ? token : void 0;
549
+ return {
550
+ send,
551
+ threadTsValue: resolveSlackThreadTsValue(params),
552
+ tokenOverride
553
+ };
554
+ }
555
+ function parseSlackExplicitTarget(raw) {
556
+ const target = parseSlackTarget(raw, { defaultKind: "channel" });
557
+ if (!target) return null;
558
+ return {
559
+ to: target.id,
560
+ chatType: target.kind === "user" ? "direct" : "channel"
561
+ };
562
+ }
563
+ function normalizeSlackAcpConversationId(raw) {
564
+ const trimmed = normalizeOptionalString(raw);
565
+ if (!trimmed) return null;
566
+ const conversationId = normalizeLowercaseStringOrEmpty(parseSlackTarget(trimmed, { defaultKind: "channel" })?.id ?? trimmed.replace(/^slack:/i, "").replace(/^(?:channel|group|direct|user):/i, ""));
567
+ return conversationId ? { conversationId } : null;
568
+ }
569
+ function matchSlackAcpConversation(params) {
570
+ const bindingConversationId = normalizeSlackAcpConversationId(params.bindingConversationId)?.conversationId;
571
+ const conversationId = normalizeSlackAcpConversationId(params.conversationId)?.conversationId;
572
+ const parentConversationId = normalizeSlackAcpConversationId(params.parentConversationId)?.conversationId;
573
+ if (!bindingConversationId || !conversationId) return null;
574
+ if (bindingConversationId === conversationId) return {
575
+ conversationId,
576
+ matchPriority: 2
577
+ };
578
+ if (parentConversationId && parentConversationId !== conversationId && bindingConversationId === parentConversationId) return {
579
+ conversationId: parentConversationId,
580
+ matchPriority: 1
581
+ };
582
+ return null;
583
+ }
584
+ function buildSlackBaseSessionKey(params) {
585
+ return buildOutboundBaseSessionKey({
586
+ ...params,
587
+ channel: "slack"
588
+ });
589
+ }
590
+ function shouldRecoverSlackThreadFromCurrentSession(params) {
591
+ if (params.peerKind === "direct" && (params.cfg.session?.dmScope ?? "main") === "main") return false;
592
+ return true;
593
+ }
594
+ async function resolveSlackOutboundSessionRoute(params) {
595
+ const parsed = parseSlackTarget(params.target, { defaultKind: "channel" });
596
+ if (!parsed) return null;
597
+ const isDm = parsed.kind === "user";
598
+ let peerKind = isDm ? "direct" : "channel";
599
+ let peerId = parsed.id;
600
+ if (!isDm && /^D/i.test(parsed.id)) {
601
+ const conversation = await resolveSlackConversationInfo({
602
+ cfg: params.cfg,
603
+ accountId: params.accountId,
604
+ channelId: parsed.id
605
+ });
606
+ if (conversation.type !== "dm" || !conversation.user) return null;
607
+ peerKind = "direct";
608
+ peerId = conversation.user;
609
+ } else if (!isDm && /^G/i.test(parsed.id)) {
610
+ const channelType = await resolveSlackChannelType({
611
+ cfg: params.cfg,
612
+ accountId: params.accountId,
613
+ channelId: parsed.id
614
+ });
615
+ if (channelType === "group") peerKind = "group";
616
+ if (channelType === "dm") peerKind = "direct";
617
+ }
618
+ const peer = {
619
+ kind: peerKind,
620
+ id: peerId
621
+ };
622
+ const baseSessionKey = buildSlackBaseSessionKey({
623
+ cfg: params.cfg,
624
+ agentId: params.agentId,
625
+ accountId: params.accountId,
626
+ peer
627
+ });
628
+ return buildThreadAwareOutboundSessionRoute({
629
+ route: {
630
+ sessionKey: baseSessionKey,
631
+ baseSessionKey,
632
+ peer,
633
+ chatType: peerKind === "direct" ? "direct" : "channel",
634
+ from: peerKind === "direct" ? `slack:${peerId}` : peerKind === "group" ? `slack:group:${peerId}` : `slack:channel:${peerId}`,
635
+ to: peerKind === "direct" ? `user:${peerId}` : `channel:${peerId}`
636
+ },
637
+ replyToId: params.replyToId,
638
+ threadId: params.threadId,
639
+ currentSessionKey: params.currentSessionKey,
640
+ canRecoverCurrentThread: () => shouldRecoverSlackThreadFromCurrentSession({
641
+ cfg: params.cfg,
642
+ peerKind
643
+ })
644
+ });
645
+ }
646
+ function formatSlackScopeDiagnostic(params) {
647
+ const source = params.result.source ? ` (${params.result.source})` : "";
648
+ const label = params.tokenType === "user" ? "User scopes" : "Bot scopes";
649
+ if (params.result.ok && params.result.scopes?.length) return { text: `${label}${source}: ${params.result.scopes.join(", ")}` };
650
+ return {
651
+ text: `${label}: ${params.result.error ?? "scope lookup failed"}`,
652
+ tone: "error"
653
+ };
654
+ }
655
+ const resolveSlackAllowlistGroupOverrides = createFlatAllowlistOverrideResolver({
656
+ resolveRecord: (account) => account.channels,
657
+ label: (key) => key,
658
+ resolveEntries: (value) => value?.users
659
+ });
660
+ const resolveSlackAllowlistNames = createAccountScopedAllowlistNameResolver({
661
+ resolveAccount: resolveSlackAccount,
662
+ resolveToken: (account) => normalizeOptionalString(account.config.userToken) ?? normalizeOptionalString(account.botToken),
663
+ resolveNames: async ({ token, entries }) => (await loadSlackResolveUsersModule()).resolveSlackUserAllowlist({
664
+ token,
665
+ entries
666
+ })
667
+ });
668
+ const slackChannelOutbound = {
669
+ deliveryMode: "direct",
670
+ chunker: null,
671
+ textChunkLimit: SLACK_TEXT_LIMIT,
672
+ normalizePayload: ({ payload, cfg, accountId }) => isSlackInteractiveRepliesEnabled({
673
+ cfg,
674
+ accountId
675
+ }) ? compileSlackInteractiveReplies(payload) : payload,
676
+ deliveryCapabilities: { durableFinal: {
677
+ text: true,
678
+ media: true,
679
+ payload: true,
680
+ replyTo: true,
681
+ thread: true,
682
+ messageSendingHooks: true
683
+ } },
684
+ shouldTreatDeliveredTextAsVisible: shouldTreatSlackDeliveredTextAsVisible,
685
+ shouldSuppressLocalPayloadPrompt: ({ cfg, accountId, payload }) => shouldSuppressLocalSlackExecApprovalPrompt({
686
+ cfg,
687
+ accountId,
688
+ payload
689
+ }),
690
+ sendPayload: async (ctx) => {
691
+ const { send, threadTsValue, tokenOverride } = await resolveSlackSendContext({
692
+ cfg: ctx.cfg,
693
+ accountId: ctx.accountId ?? void 0,
694
+ deps: ctx.deps,
695
+ replyToId: ctx.replyToId,
696
+ threadId: ctx.threadId
697
+ });
698
+ const { slackOutbound } = await loadSlackOutboundAdapterModule();
699
+ return await slackOutbound.sendPayload({
700
+ ...ctx,
701
+ replyToId: threadTsValue,
702
+ threadId: null,
703
+ deps: {
704
+ ...ctx.deps,
705
+ slack: async (to, text, opts) => await send(to, text, {
706
+ ...opts,
707
+ ...tokenOverride ? { token: tokenOverride } : {}
708
+ })
709
+ }
710
+ });
711
+ },
712
+ ...createAttachedChannelResultAdapter({
713
+ channel: "slack",
714
+ sendText: async ({ to, text, accountId, deps, replyToId, threadId, cfg }) => {
715
+ const { send, threadTsValue, tokenOverride } = await resolveSlackSendContext({
716
+ cfg,
717
+ accountId: accountId ?? void 0,
718
+ deps,
719
+ replyToId,
720
+ threadId
721
+ });
722
+ return await send(to, text, {
723
+ cfg,
724
+ threadTs: threadTsValue,
725
+ accountId: accountId ?? void 0,
726
+ ...tokenOverride ? { token: tokenOverride } : {}
727
+ });
728
+ },
729
+ sendMedia: async ({ to, text, mediaUrl, mediaLocalRoots, accountId, deps, replyToId, threadId, cfg }) => {
730
+ const { send, threadTsValue, tokenOverride } = await resolveSlackSendContext({
731
+ cfg,
732
+ accountId: accountId ?? void 0,
733
+ deps,
734
+ replyToId,
735
+ threadId
736
+ });
737
+ return await send(to, text, {
738
+ cfg,
739
+ mediaUrl,
740
+ mediaLocalRoots,
741
+ threadTs: threadTsValue,
742
+ accountId: accountId ?? void 0,
743
+ ...tokenOverride ? { token: tokenOverride } : {}
744
+ });
745
+ }
746
+ })
747
+ };
748
+ const slackMessageAdapter = createChannelMessageAdapterFromOutbound({
749
+ id: "slack",
750
+ outbound: slackChannelOutbound,
751
+ live: {
752
+ capabilities: {
753
+ draftPreview: true,
754
+ previewFinalization: true,
755
+ progressUpdates: true,
756
+ nativeStreaming: true
757
+ },
758
+ finalizer: { capabilities: {
759
+ finalEdit: true,
760
+ normalFallback: true,
761
+ discardPending: true
762
+ } }
763
+ }
764
+ });
765
+ const slackPlugin = createChatChannelPlugin({
766
+ base: {
767
+ ...createSlackPluginBase({
768
+ setupWizard: createSlackSetupWizardProxy(loadSlackSetupSurfaceModule),
769
+ setup: slackSetupAdapter
770
+ }),
771
+ allowlist: {
772
+ ...buildLegacyDmAccountAllowlistAdapter({
773
+ channelId: "slack",
774
+ resolveAccount: resolveSlackAccount,
775
+ normalize: ({ cfg, accountId, values }) => slackConfigAdapter.formatAllowFrom({
776
+ cfg,
777
+ accountId,
778
+ allowFrom: values
779
+ }),
780
+ resolveDmAllowFrom: (account, { cfg }) => resolveSlackAccountAllowFrom({
781
+ cfg,
782
+ accountId: account.accountId
783
+ }),
784
+ resolveGroupPolicy: (account) => account.groupPolicy,
785
+ resolveGroupOverrides: resolveSlackAllowlistGroupOverrides
786
+ }),
787
+ resolveNames: resolveSlackAllowlistNames
788
+ },
789
+ approvalCapability: slackApprovalCapability,
790
+ groups: {
791
+ resolveRequireMention: resolveSlackGroupRequireMention,
792
+ resolveToolPolicy: resolveSlackGroupToolPolicy
793
+ },
794
+ bindings: {
795
+ compileConfiguredBinding: ({ conversationId }) => normalizeSlackAcpConversationId(conversationId),
796
+ matchInboundConversation: ({ compiledBinding, conversationId, parentConversationId }) => matchSlackAcpConversation({
797
+ bindingConversationId: compiledBinding.conversationId,
798
+ conversationId,
799
+ parentConversationId
800
+ })
801
+ },
802
+ messaging: {
803
+ targetPrefixes: ["slack"],
804
+ normalizeTarget: normalizeSlackMessagingTarget,
805
+ resolveDeliveryTarget: ({ conversationId, parentConversationId }) => {
806
+ const parent = parentConversationId?.trim();
807
+ const child = conversationId.trim();
808
+ return parent && parent !== child ? {
809
+ to: `channel:${parent}`,
810
+ threadId: child
811
+ } : { to: normalizeSlackMessagingTarget(`channel:${child}`) };
812
+ },
813
+ resolveSessionTarget: ({ id }) => normalizeSlackMessagingTarget(`channel:${id}`),
814
+ parseExplicitTarget: ({ raw }) => parseSlackExplicitTarget(raw),
815
+ inferTargetChatType: ({ to }) => parseSlackExplicitTarget(to)?.chatType,
816
+ resolveOutboundSessionRoute: async (params) => await resolveSlackOutboundSessionRoute(params),
817
+ transformReplyPayload: ({ payload, cfg, accountId }) => isSlackInteractiveRepliesEnabled({
818
+ cfg,
819
+ accountId
820
+ }) ? compileSlackInteractiveReplies(payload) : payload,
821
+ enableInteractiveReplies: ({ cfg, accountId }) => isSlackInteractiveRepliesEnabled({
822
+ cfg,
823
+ accountId
824
+ }),
825
+ hasStructuredReplyPayload: ({ payload }) => {
826
+ try {
827
+ return Boolean(resolveSlackReplyBlocks(payload)?.length);
828
+ } catch {
829
+ return false;
830
+ }
831
+ },
832
+ targetResolver: {
833
+ looksLikeId: looksLikeSlackTargetId,
834
+ hint: "<channelId|user:ID|channel:ID>",
835
+ resolveTarget: async ({ input }) => {
836
+ const parsed = parseSlackExplicitTarget(input);
837
+ if (!parsed) return null;
838
+ return {
839
+ to: parsed.to,
840
+ kind: parsed.chatType === "direct" ? "user" : "group",
841
+ source: "normalized"
842
+ };
843
+ }
844
+ }
845
+ },
846
+ directory: createChannelDirectoryAdapter({
847
+ listPeers: async (params) => (await loadSlackDirectoryConfigModule()).listSlackDirectoryPeersFromConfig(params),
848
+ listGroups: async (params) => (await loadSlackDirectoryConfigModule()).listSlackDirectoryGroupsFromConfig(params),
849
+ ...createRuntimeDirectoryLiveAdapter({
850
+ getRuntime: loadSlackDirectoryLiveModule,
851
+ self: (runtime) => runtime.getSlackDirectorySelfLive,
852
+ listPeersLive: (runtime) => runtime.listSlackDirectoryPeersLive,
853
+ listGroupsLive: (runtime) => runtime.listSlackDirectoryGroupsLive
854
+ })
855
+ }),
856
+ resolver: { resolveTargets: async ({ cfg, accountId, inputs, kind }) => {
857
+ const toResolvedTarget = (entry, note) => ({
858
+ input: entry.input,
859
+ resolved: entry.resolved,
860
+ id: entry.id,
861
+ name: entry.name,
862
+ note
863
+ });
864
+ const account = resolveSlackAccount({
865
+ cfg,
866
+ accountId
867
+ });
868
+ const { resolveTargetsWithOptionalToken } = await loadTargetResolverRuntimeSdk();
869
+ if (kind === "group") return resolveTargetsWithOptionalToken({
870
+ token: normalizeOptionalString(account.config.userToken) ?? normalizeOptionalString(account.botToken),
871
+ inputs,
872
+ missingTokenNote: "missing Slack token",
873
+ resolveWithToken: async ({ token, inputs }) => (await loadSlackResolveChannelsModule()).resolveSlackChannelAllowlist({
874
+ token,
875
+ entries: inputs
876
+ }),
877
+ mapResolved: (entry) => toResolvedTarget(entry, entry.archived ? "archived" : void 0)
878
+ });
879
+ return resolveTargetsWithOptionalToken({
880
+ token: normalizeOptionalString(account.config.userToken) ?? normalizeOptionalString(account.botToken),
881
+ inputs,
882
+ missingTokenNote: "missing Slack token",
883
+ resolveWithToken: async ({ token, inputs }) => (await loadSlackResolveUsersModule()).resolveSlackUserAllowlist({
884
+ token,
885
+ entries: inputs
886
+ }),
887
+ mapResolved: (entry) => toResolvedTarget(entry, entry.note)
888
+ });
889
+ } },
890
+ actions: createSlackActions(SLACK_CHANNEL, { invoke: async (action, cfg, toolContext) => await (await resolveSlackHandleAction())(action, cfg, toolContext) }),
891
+ message: slackMessageAdapter,
892
+ status: createComputedAccountStatusAdapter({
893
+ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
894
+ buildChannelSummary: async ({ snapshot }) => {
895
+ const { buildPassiveProbedChannelStatusSummary } = await loadExtensionSharedSdk();
896
+ return buildPassiveProbedChannelStatusSummary(snapshot, {
897
+ botTokenSource: snapshot.botTokenSource ?? "none",
898
+ appTokenSource: snapshot.appTokenSource ?? "none"
899
+ });
900
+ },
901
+ probeAccount: async ({ account, timeoutMs }) => {
902
+ const token = account.botToken?.trim();
903
+ if (!token) return {
904
+ ok: false,
905
+ error: "missing token"
906
+ };
907
+ return await (await loadSlackProbeModule()).probeSlack(token, timeoutMs);
908
+ },
909
+ formatCapabilitiesProbe: ({ probe }) => {
910
+ const slackProbe = probe;
911
+ const lines = [];
912
+ if (slackProbe?.bot?.name) lines.push({ text: `Bot: @${slackProbe.bot.name}` });
913
+ if (slackProbe?.team?.name || slackProbe?.team?.id) {
914
+ const id = slackProbe.team?.id ? ` (${slackProbe.team.id})` : "";
915
+ lines.push({ text: `Team: ${slackProbe.team?.name ?? "unknown"}${id}` });
916
+ }
917
+ return lines;
918
+ },
919
+ buildCapabilitiesDiagnostics: async ({ account, timeoutMs }) => {
920
+ const lines = [];
921
+ const details = {};
922
+ const botToken = account.botToken?.trim();
923
+ const userToken = account.config.userToken?.trim();
924
+ const { fetchSlackScopes } = await loadSlackScopesModule();
925
+ const botScopes = botToken ? await fetchSlackScopes(botToken, timeoutMs) : {
926
+ ok: false,
927
+ error: "Slack bot token missing."
928
+ };
929
+ lines.push(formatSlackScopeDiagnostic({
930
+ tokenType: "bot",
931
+ result: botScopes
932
+ }));
933
+ details.botScopes = botScopes;
934
+ if (userToken) {
935
+ const userScopes = await fetchSlackScopes(userToken, timeoutMs);
936
+ lines.push(formatSlackScopeDiagnostic({
937
+ tokenType: "user",
938
+ result: userScopes
939
+ }));
940
+ details.userScopes = userScopes;
941
+ }
942
+ return {
943
+ lines,
944
+ details
945
+ };
946
+ },
947
+ resolveAccountSnapshot: ({ account }) => {
948
+ const configured = ((account.config.mode ?? "socket") === "http" ? resolveConfiguredFromRequiredCredentialStatuses(account, ["botTokenStatus", "signingSecretStatus"]) : resolveConfiguredFromRequiredCredentialStatuses(account, ["botTokenStatus", "appTokenStatus"])) ?? isSlackPluginAccountConfigured(account);
949
+ return {
950
+ accountId: account.accountId,
951
+ name: account.name,
952
+ enabled: account.enabled,
953
+ configured,
954
+ extra: { ...projectCredentialSnapshotFields(account) }
955
+ };
956
+ }
957
+ }),
958
+ gateway: { startAccount: async (ctx) => {
959
+ const account = ctx.account;
960
+ const botToken = account.botToken?.trim();
961
+ const appToken = account.appToken?.trim();
962
+ ctx.log?.info(`[${account.accountId}] starting provider`);
963
+ return (await loadSlackMonitorModule()).monitorSlackProvider({
964
+ botToken: botToken ?? "",
965
+ appToken: appToken ?? "",
966
+ accountId: account.accountId,
967
+ config: ctx.cfg,
968
+ runtime: ctx.runtime,
969
+ channelRuntime: ctx.channelRuntime,
970
+ abortSignal: ctx.abortSignal,
971
+ mediaMaxMb: account.config.mediaMaxMb,
972
+ slashCommand: account.config.slashCommand,
973
+ setStatus: ctx.setStatus,
974
+ getStatus: ctx.getStatus
975
+ });
976
+ } },
977
+ mentions: { stripPatterns: () => ["<@[^>\\s]+>"] }
978
+ },
979
+ pairing: { text: {
980
+ idLabel: "slackUserId",
981
+ message: PAIRING_APPROVED_MESSAGE,
982
+ normalizeAllowEntry: createPairingPrefixStripper(/^(slack|user):/i),
983
+ notify: async ({ cfg, id, message }) => {
984
+ const account = resolveSlackAccount({
985
+ cfg,
986
+ accountId: resolveDefaultSlackAccountId(cfg)
987
+ });
988
+ const { sendMessageSlack } = await loadSlackSendRuntime();
989
+ const token = getTokenForOperation(account, "write");
990
+ await sendMessageSlack(`user:${id}`, message, {
991
+ cfg,
992
+ accountId: account.accountId,
993
+ ...token ? { token } : {}
994
+ });
995
+ }
996
+ } },
997
+ security: slackSecurityAdapter,
998
+ threading: {
999
+ scopedAccountReplyToMode: {
1000
+ resolveAccount: adaptScopedAccountAccessor(resolveSlackAccount),
1001
+ resolveReplyToMode: (account, chatType) => resolveSlackReplyToMode(account, chatType)
1002
+ },
1003
+ allowExplicitReplyTagsWhenOff: false,
1004
+ buildToolContext: (params) => buildSlackThreadingToolContext(params),
1005
+ resolveAutoThreadId: ({ to, toolContext, replyToId }) => normalizeSlackThreadTsCandidate(replyToId) ? void 0 : normalizeSlackThreadTsCandidate(resolveSlackAutoThreadId({
1006
+ to,
1007
+ toolContext
1008
+ })),
1009
+ resolveReplyTransport: ({ threadId, replyToId }) => ({
1010
+ replyToId: resolveSlackThreadTsValue({
1011
+ replyToId,
1012
+ threadId
1013
+ }),
1014
+ threadId: null
1015
+ })
1016
+ },
1017
+ outbound: slackChannelOutbound
1018
+ });
1019
+ //#endregion
1020
+ export { createSlackActions as a, resolveSlackChannelType as i, buildSlackThreadingToolContext as n, resolveSlackAutoThreadId as o, __resetSlackChannelTypeCacheForTest as r, slackPlugin as t };