@openclaw/slack 2026.7.1 → 2026.7.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/accounts.runtime-KvftRRek.js +2 -0
  2. package/dist/{action-runtime-DoQGk_8D.js → action-runtime-p6M2ULpv.js} +205 -29
  3. package/dist/action-runtime.runtime-DQstDkHG.js +2 -0
  4. package/dist/{actions-DMpDmKEA.js → actions-DkTcWmpT.js} +87 -138
  5. package/dist/{actions.runtime-C103_BPW.js → actions.runtime-BSxpwgUc.js} +1 -1
  6. package/dist/api.js +14 -13
  7. package/dist/{approval-handler.runtime-CIUbOt5T.js → approval-handler.runtime-UGbnz9OC.js} +3 -3
  8. package/dist/{channel-BjlsaGHn.js → channel-B0_j6C6z.js} +116 -140
  9. package/dist/channel-config-api.js +1 -1
  10. package/dist/channel-plugin-api.js +1 -1
  11. package/dist/channel-type-BpeTezY4.js +109 -0
  12. package/dist/{channel.setup-Dq6syTNU.js → channel.setup-BQFut21T.js} +2 -2
  13. package/dist/{client-DGxwSL7f.js → client-D2F6m8CP.js} +38 -2
  14. package/dist/config-api-Df9a1B8C.js +3 -0
  15. package/dist/{config-schema-BzqzFW__.js → config-schema-DYI01PV2.js} +20 -37
  16. package/dist/cursor-pages-DSmTg0su.js +13 -0
  17. package/dist/{directory-config-BZuS8141.js → directory-config-DRkFujwG.js} +2 -2
  18. package/dist/directory-contract-api.js +1 -1
  19. package/dist/{directory-live-BNsxCgqP.js → directory-live-DX7yFsM-.js} +2 -2
  20. package/dist/{doctor-contract-XL6HeNCb.js → doctor-contract-DddfkMlF.js} +25 -38
  21. package/dist/doctor-contract-api.js +1 -1
  22. package/dist/group-policy-C-b2ZnSl.js +2332 -0
  23. package/dist/{interactive-replies-CXpT-vA_.js → interactive-replies-BilWUdcI.js} +5 -1
  24. package/dist/interactive-replies-api.js +1 -1
  25. package/dist/{message-tool-api-BgWKyu2r.js → message-tool-api-CA9jZrCY.js} +1 -1
  26. package/dist/message-tool-api.js +1 -1
  27. package/dist/{monitor-Ux-wzUWI.js → monitor-BN_uuvrQ.js} +3 -3
  28. package/dist/outbound-adapter-ECl0go7d.js +228 -0
  29. package/dist/{pipeline.runtime-rpVpay59.js → pipeline.runtime-f0eJJoJL.js} +492 -178
  30. package/dist/{policy-Dj-puVPb.js → policy-f8b0edSi.js} +1 -1
  31. package/dist/preflight-audio.runtime-D5Bgags0.js +3 -0
  32. package/dist/{probe-CuwRDE5j.js → probe-CfALk0l4.js} +2 -2
  33. package/dist/{provider-C1-DFSpw.js → provider-Ds-y-imP.js} +658 -192
  34. package/dist/{relay-source-D2jv1iGg.js → relay-source-B-6LFUdz.js} +6 -17
  35. package/dist/replies-BMvf3ihj.js +420 -0
  36. package/dist/{resolve-channels-CstkChBE.js → resolve-channels-DOMgNCWb.js} +17 -6
  37. package/dist/{resolve-users-C3NP2c-Q.js → resolve-users-aL6-Ssee.js} +11 -6
  38. package/dist/{runtime-BOk7xkOl.js → runtime-CauEvswP.js} +1 -1
  39. package/dist/{runtime-api-CEmqYxR-.js → runtime-api-CVb6CQjX.js} +3 -3
  40. package/dist/runtime-api.js +11 -11
  41. package/dist/runtime-setter-api.js +1 -1
  42. package/dist/{scopes-DCWVD5-8.js → scopes-Dw8wbU0j.js} +2 -2
  43. package/dist/{secret-contract-C3ChHo5A.js → secret-contract-CMohXFWS.js} +18 -113
  44. package/dist/secret-contract-api.js +1 -1
  45. package/dist/{send-DKDXoeoV.js → send-NEfJ0GvM.js} +662 -325
  46. package/dist/{send.runtime-GPRa63l1.js → send.runtime-BkKpitPu.js} +1 -1
  47. package/dist/setup-plugin-api.js +1 -1
  48. package/dist/{setup-surface-Dv2fIJNB.js → setup-surface-BN2WeG5c.js} +3 -3
  49. package/dist/{shared-CosfcFri.js → shared-BLnB9R1T.js} +7 -5
  50. package/dist/{slash-dispatch.runtime-CcMbbT3_.js → slash-dispatch.runtime-C0Otuf_T.js} +1 -1
  51. package/dist/{streaming-compat-DjlgH-Be.js → streaming-compat-3_X-21wW.js} +1 -0
  52. package/dist/{target-parsing-3jYH8LfB.js → target-parsing-N6lHogYZ.js} +16 -3
  53. package/dist/{targets-Dll4NJgs.js → targets-KmjP2E8s.js} +1 -1
  54. package/node_modules/p-map/index.d.ts +155 -0
  55. package/node_modules/p-map/index.js +284 -0
  56. package/node_modules/p-map/license +9 -0
  57. package/node_modules/p-map/package.json +57 -0
  58. package/node_modules/p-map/readme.md +190 -0
  59. package/npm-shrinkwrap.json +16 -3
  60. package/openclaw.plugin.json +16 -0
  61. package/package.json +6 -4
  62. package/dist/accounts.runtime-DWvaCb-X.js +0 -2
  63. package/dist/action-runtime.runtime-BABj3aM-.js +0 -2
  64. package/dist/config-api-DnT9ohtE.js +0 -2
  65. package/dist/format-YCNoNkM2.js +0 -107
  66. package/dist/outbound-adapter-DVoBfBW5.js +0 -272
  67. package/dist/replies-DpF38e1y.js +0 -287
  68. package/dist/reply-blocks-BGQ6zSqM.js +0 -877
  69. package/dist/resolve-allowlist-common-CP8SH0Zf.js +0 -43
@@ -1,877 +0,0 @@
1
- import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-BOJJiHSr.js";
2
- import { r as parseSlackTarget } from "./target-parsing-3jYH8LfB.js";
3
- import "./targets-Dll4NJgs.js";
4
- import { t as isSlackPluginAccountConfigured } from "./account-configured-DzC407uv.js";
5
- import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
6
- import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
- import { normalizeMessageChannel } from "openclaw/plugin-sdk/routing";
8
- import { createNativeApprovalChannelRouteGates, doesApprovalRequestMatchChannelAccount, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
9
- import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
10
- import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, isChannelExecApprovalTargetRecipient, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
11
- import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
12
- import { reduceInteractiveReply, resolveMessagePresentationControlValue } from "openclaw/plugin-sdk/interactive-runtime";
13
- import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
14
- import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
15
- import { compileAllowlist, resolveCompiledAllowlistMatch } from "openclaw/plugin-sdk/allow-from";
16
- import { normalizeHyphenSlug, normalizeStringEntries as normalizeStringEntries$1, normalizeStringEntriesLower as normalizeStringEntriesLower$1 } from "openclaw/plugin-sdk/string-normalization-runtime";
17
- import { redactSensitiveText } from "openclaw/plugin-sdk/logging-core";
18
- import { resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";
19
- //#region extensions/slack/src/exec-approvals.ts
20
- function normalizeSlackUserLikeId(value) {
21
- const upper = value.toUpperCase();
22
- return /^[UW][A-Z0-9]+$/.test(upper) ? upper : void 0;
23
- }
24
- function normalizeSlackApproverId(value) {
25
- const trimmed = normalizeStringifiedOptionalString(value);
26
- if (!trimmed) return;
27
- const prefixed = trimmed.match(/^(?:slack|user):([A-Z0-9]+)$/i);
28
- if (prefixed?.[1]) return normalizeSlackUserLikeId(prefixed[1]);
29
- const mention = trimmed.match(/^<@([A-Z0-9]+)>$/i);
30
- if (mention?.[1]) return normalizeSlackUserLikeId(mention[1]);
31
- return normalizeSlackUserLikeId(trimmed);
32
- }
33
- function resolveSlackOwnerApprovers(cfg) {
34
- const ownerAllowFrom = cfg.commands?.ownerAllowFrom;
35
- if (!Array.isArray(ownerAllowFrom) || ownerAllowFrom.length === 0) return [];
36
- return resolveApprovalApprovers({
37
- explicit: ownerAllowFrom,
38
- normalizeApprover: normalizeSlackApproverId
39
- });
40
- }
41
- function getSlackExecApprovalApprovers(params) {
42
- const account = resolveSlackAccount(params).config;
43
- return resolveApprovalApprovers({
44
- explicit: account.execApprovals?.approvers ?? resolveSlackOwnerApprovers(params.cfg),
45
- normalizeApprover: normalizeSlackApproverId
46
- });
47
- }
48
- function isSlackExecApprovalTargetRecipient(params) {
49
- return isChannelExecApprovalTargetRecipient({
50
- ...params,
51
- channel: "slack",
52
- normalizeSenderId: normalizeSlackApproverId,
53
- matchTarget: ({ target, normalizedSenderId }) => normalizeSlackApproverId(target.to) === normalizedSenderId
54
- });
55
- }
56
- const slackExecApprovalProfile = createChannelExecApprovalProfile({
57
- resolveConfig: (params) => resolveSlackAccount(params).config.execApprovals,
58
- resolveApprovers: getSlackExecApprovalApprovers,
59
- normalizeSenderId: normalizeSlackApproverId,
60
- isTargetRecipient: isSlackExecApprovalTargetRecipient,
61
- matchesRequestAccount: (params) => doesApprovalRequestMatchChannelAccount({
62
- cfg: params.cfg,
63
- request: params.request,
64
- channel: "slack",
65
- accountId: params.accountId
66
- })
67
- });
68
- const isSlackExecApprovalClientEnabled = slackExecApprovalProfile.isClientEnabled;
69
- slackExecApprovalProfile.isApprover;
70
- const isSlackExecApprovalAuthorizedSender = slackExecApprovalProfile.isAuthorizedSender;
71
- const resolveSlackExecApprovalTarget = slackExecApprovalProfile.resolveTarget;
72
- slackExecApprovalProfile.shouldHandleRequest;
73
- const shouldSuppressLocalSlackExecApprovalPrompt = slackExecApprovalProfile.shouldSuppressLocalPrompt;
74
- //#endregion
75
- //#region extensions/slack/src/approval-auth.ts
76
- function getSlackApprovalApprovers(params) {
77
- const account = resolveSlackAccount(params).config;
78
- return resolveApprovalApprovers({
79
- allowFrom: resolveSlackAccountAllowFrom(params),
80
- defaultTo: account.defaultTo,
81
- normalizeApprover: normalizeSlackApproverId,
82
- normalizeDefaultTo: normalizeSlackApproverId
83
- });
84
- }
85
- function isSlackApprovalAuthorizedSender(params) {
86
- const senderId = params.senderId ? normalizeSlackApproverId(params.senderId) : void 0;
87
- if (!senderId) return false;
88
- const approvers = getSlackApprovalApprovers(params);
89
- if (approvers.length > 0) return approvers.includes(senderId);
90
- return (resolveSlackAccountAllowFrom(params) ?? []).some((entry) => entry.trim() === "*");
91
- }
92
- createResolvedApproverActionAuthAdapter({
93
- channelLabel: "Slack",
94
- resolveApprovers: ({ cfg, accountId }) => getSlackApprovalApprovers({
95
- cfg,
96
- accountId
97
- }),
98
- normalizeSenderId: (value) => normalizeSlackApproverId(value)
99
- });
100
- //#endregion
101
- //#region extensions/slack/src/approval-native-gates.ts
102
- const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
103
- const SLACK_DM_CHANNEL_ID_RE = /^D[A-Z0-9]{8,}$/i;
104
- const SLACK_USER_ID_RE = /^[UW][A-Z0-9]{8,}$/i;
105
- function resolveSlackApprovalKind(request) {
106
- return request.id.startsWith("plugin:") ? "plugin" : "exec";
107
- }
108
- function isSlackApprovalTransportEnabled(params) {
109
- return isSlackPluginAccountConfigured(resolveSlackAccount(params));
110
- }
111
- function resolveSlackNativeApprovalConfig(params) {
112
- return resolveSlackAccount(params).config.execApprovals;
113
- }
114
- function resolvePluginApprovalForwardingConfig(cfg) {
115
- return cfg.approvals?.plugin;
116
- }
117
- function normalizeSlackThreadMatchKey(threadId) {
118
- return threadId == null ? "" : String(threadId).trim();
119
- }
120
- function normalizeComparableTarget(value) {
121
- return normalizeLowercaseStringOrEmpty(value);
122
- }
123
- function extractSlackSessionKind(sessionKey) {
124
- if (!sessionKey) return null;
125
- const kind = normalizeLowercaseStringOrEmpty(sessionKey.match(/slack:(direct|channel|group):/i)?.[1]);
126
- return kind ? kind : null;
127
- }
128
- function resolveSlackTurnSourceDefaultKind(params) {
129
- if (SLACK_DM_CHANNEL_ID_RE.test(params.turnSourceTo)) return "channel";
130
- return params.sessionKind === "direct" ? "user" : "channel";
131
- }
132
- function resolveTurnSourceSlackOriginTarget(request) {
133
- const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel);
134
- const turnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? "";
135
- if (turnSourceChannel !== "slack" || !turnSourceTo) return null;
136
- const parsed = parseSlackTarget(turnSourceTo, { defaultKind: resolveSlackTurnSourceDefaultKind({
137
- turnSourceTo,
138
- sessionKind: extractSlackSessionKind(request.request.sessionKey ?? void 0)
139
- }) });
140
- if (!parsed) return null;
141
- return {
142
- to: `${parsed.kind}:${parsed.id}`,
143
- threadId: stringifyRouteThreadId(request.request.turnSourceThreadId)
144
- };
145
- }
146
- function resolveSessionSlackOriginTarget(sessionTarget) {
147
- return {
148
- to: sessionTarget.to,
149
- threadId: stringifyRouteThreadId(sessionTarget.threadId)
150
- };
151
- }
152
- function resolveSlackFallbackOriginTarget(request) {
153
- const sessionTarget = resolveApprovalRequestSessionConversation({
154
- request,
155
- channel: "slack",
156
- bundledFallback: false
157
- });
158
- if (!sessionTarget) return null;
159
- const parsed = parseSlackTarget(sessionTarget.id.toUpperCase(), { defaultKind: "channel" });
160
- if (!parsed) return null;
161
- return {
162
- to: `${parsed.kind}:${parsed.id}`,
163
- threadId: sessionTarget.threadId
164
- };
165
- }
166
- function normalizeSlackOriginTarget(target) {
167
- return {
168
- ...target,
169
- to: normalizeComparableTarget(target.to)
170
- };
171
- }
172
- function parseComparableSlackTarget(target) {
173
- return parseSlackTarget(target.to, { defaultKind: "channel" });
174
- }
175
- function isSlackDmChannelToUserRoutePair(a, b) {
176
- const left = parseComparableSlackTarget(a);
177
- const right = parseComparableSlackTarget(b);
178
- if (!left || !right) return false;
179
- return left.kind === "channel" && SLACK_DM_CHANNEL_ID_RE.test(left.id) && right.kind === "user" || right.kind === "channel" && SLACK_DM_CHANNEL_ID_RE.test(right.id) && left.kind === "user";
180
- }
181
- function slackTargetsMatch(a, b) {
182
- const threadKey = normalizeSlackThreadMatchKey(a.threadId);
183
- if (threadKey !== normalizeSlackThreadMatchKey(b.threadId)) return false;
184
- if (channelRouteTargetsMatchExact({
185
- left: {
186
- channel: "slack",
187
- to: a.to
188
- },
189
- right: {
190
- channel: "slack",
191
- to: b.to
192
- }
193
- })) return true;
194
- return Boolean(threadKey && isSlackDmChannelToUserRoutePair(a, b));
195
- }
196
- function normalizeSlackForwardTarget(target) {
197
- if ((normalizeMessageChannel(target.channel) ?? target.channel) !== "slack") return null;
198
- const to = normalizeOptionalString(target.to);
199
- if (!to) return null;
200
- const parsed = parseSlackTarget(to, { defaultKind: SLACK_USER_ID_RE.test(to) ? "user" : "channel" });
201
- if (!parsed) return null;
202
- return {
203
- to: `${parsed.kind}:${parsed.id}`,
204
- accountId: normalizeOptionalString(target.accountId),
205
- threadId: stringifyRouteThreadId(target.threadId)
206
- };
207
- }
208
- const { canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToSlack, isSessionApprovalEligible: isForwardedSlackSessionApprovalEligible, isExplicitTargetEligible: isForwardedSlackExplicitTargetEligible } = createNativeApprovalChannelRouteGates({
209
- channel: "slack",
210
- defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE,
211
- isTransportEnabled: isSlackApprovalTransportEnabled,
212
- listAccountIds: listSlackAccountIds,
213
- resolveDefaultAccountId: resolveDefaultSlackAccountId,
214
- normalizeForwardTarget: normalizeSlackForwardTarget,
215
- resolveTurnSourceTarget: resolveTurnSourceSlackOriginTarget,
216
- targetsMatch: slackTargetsMatch
217
- });
218
- function hasSlackPluginApprovers(params) {
219
- return getSlackApprovalApprovers(params).length > 0;
220
- }
221
- function isSlackPluginNativeApprovalClientConfigEnabled(params) {
222
- return isChannelExecApprovalClientEnabledFromConfig({
223
- enabled: resolveSlackNativeApprovalConfig(params)?.enabled,
224
- approverCount: getSlackApprovalApprovers(params).length
225
- });
226
- }
227
- function isSlackPluginForwardingRoutePotentiallyEnabled(params) {
228
- return canApprovalPotentiallyRouteToSlack({
229
- ...params,
230
- approvalKind: "plugin"
231
- });
232
- }
233
- function isSlackPluginNativeApprovalClientEnabled(params) {
234
- return isSlackPluginNativeApprovalClientConfigEnabled(params) || isSlackPluginForwardingRoutePotentiallyEnabled(params);
235
- }
236
- function shouldHandleSlackPluginViaNativeClientConfig(params) {
237
- if (!doesApprovalRequestMatchChannelAccount({
238
- cfg: params.cfg,
239
- request: params.request,
240
- channel: "slack",
241
- accountId: params.accountId
242
- })) return false;
243
- const config = resolveSlackNativeApprovalConfig(params);
244
- if (!isChannelExecApprovalClientEnabledFromConfig({
245
- enabled: config?.enabled,
246
- approverCount: getSlackApprovalApprovers(params).length
247
- })) return false;
248
- return matchesSlackNativeApprovalFilters({
249
- request: params.request,
250
- agentFilter: config?.agentFilter,
251
- sessionFilter: config?.sessionFilter
252
- });
253
- }
254
- function matchesSlackNativeApprovalFilters(params) {
255
- return matchesApprovalRequestFilters({
256
- request: params.request.request,
257
- agentFilter: params.agentFilter,
258
- sessionFilter: params.sessionFilter
259
- });
260
- }
261
- function isAnyForwardedSlackExplicitTargetEligible(params) {
262
- return (resolvePluginApprovalForwardingConfig(params.cfg)?.targets ?? []).some((target) => isForwardedSlackExplicitTargetEligible({
263
- ...params,
264
- approvalKind: "plugin",
265
- target
266
- }));
267
- }
268
- function shouldHandleSlackPluginViaForwarding(params) {
269
- return isForwardedSlackSessionApprovalEligible({
270
- ...params,
271
- approvalKind: "plugin"
272
- }) || isAnyForwardedSlackExplicitTargetEligible(params);
273
- }
274
- function shouldHandleSlackPluginViaForwardingSession(params) {
275
- return isForwardedSlackSessionApprovalEligible({
276
- ...params,
277
- approvalKind: "plugin"
278
- });
279
- }
280
- function isSlackNativeApprovalClientEnabled(params) {
281
- if (params.approvalKind === "exec") return isSlackExecApprovalClientEnabled(params);
282
- return isSlackPluginNativeApprovalClientEnabled(params);
283
- }
284
- function isSlackAnyNativeApprovalClientEnabled(params) {
285
- return isSlackNativeApprovalClientEnabled({
286
- ...params,
287
- approvalKind: "exec"
288
- }) || isSlackNativeApprovalClientEnabled({
289
- ...params,
290
- approvalKind: "plugin"
291
- });
292
- }
293
- function shouldHandleSlackNativeApprovalRequest(params) {
294
- if ((params.approvalKind ?? resolveSlackApprovalKind(params.request)) === "plugin") return shouldHandleSlackPluginViaNativeClientConfig(params) || shouldHandleSlackPluginViaForwarding(params);
295
- if (!doesApprovalRequestMatchChannelAccount({
296
- cfg: params.cfg,
297
- request: params.request,
298
- channel: "slack",
299
- accountId: params.accountId
300
- })) return false;
301
- const config = resolveSlackNativeApprovalConfig(params);
302
- if (!isChannelExecApprovalClientEnabledFromConfig({
303
- enabled: config?.enabled,
304
- approverCount: getSlackExecApprovalApprovers(params).length
305
- })) return false;
306
- return matchesSlackNativeApprovalFilters({
307
- request: params.request,
308
- agentFilter: config?.agentFilter,
309
- sessionFilter: config?.sessionFilter
310
- });
311
- }
312
- const SLACK_BUTTON_VALUE_MAX = 2e3;
313
- const SLACK_SECTION_TEXT_MAX = 3e3;
314
- const SLACK_PRESENTATION_CAPABILITIES = {
315
- supported: true,
316
- buttons: true,
317
- selects: true,
318
- context: true,
319
- divider: true,
320
- limits: {
321
- actions: {
322
- maxActionsPerRow: 25,
323
- maxLabelLength: 75,
324
- maxValueBytes: SLACK_BUTTON_VALUE_MAX,
325
- supportsStyles: true
326
- },
327
- selects: {
328
- maxOptions: 100,
329
- maxLabelLength: 75,
330
- maxValueBytes: 150
331
- },
332
- text: {
333
- encoding: "characters",
334
- markdownDialect: "slack-mrkdwn",
335
- supportsEdit: true
336
- }
337
- }
338
- };
339
- //#endregion
340
- //#region extensions/slack/src/reply-action-ids.ts
341
- const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
342
- const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
343
- const SLACK_REPLY_SELECT_ACTION_ID = "openclaw:reply_select";
344
- //#endregion
345
- //#region extensions/slack/src/truncate.ts
346
- function truncateSlackText(value, max) {
347
- const trimmed = value.trim();
348
- if (trimmed.length <= max) return trimmed;
349
- if (max <= 1) return sliceUtf16Safe(trimmed, 0, max);
350
- return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
351
- }
352
- //#endregion
353
- //#region extensions/slack/src/blocks-render.ts
354
- const SLACK_BUTTON_URL_MAX = 3e3;
355
- function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
356
- return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
357
- }
358
- function buildSlackReplyLinkActionId(buttonIndex, choiceIndex) {
359
- return `${SLACK_REPLY_LINK_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
360
- }
361
- function buildSlackReplySelectActionId(selectIndex) {
362
- return `${SLACK_REPLY_SELECT_ACTION_ID}:${String(selectIndex)}`;
363
- }
364
- function resolveSlackButtonStyle(style) {
365
- if (style === "primary" || style === "danger") return style;
366
- if (style === "success") return "primary";
367
- }
368
- function resolveSlackControlValue(control) {
369
- if (control.action?.type === "command") {
370
- const command = normalizeOptionalString(control.action.command);
371
- if (command && parseExecApprovalCommandText(command)) return command;
372
- const legacyValue = normalizeOptionalString(control.value);
373
- return legacyValue && parseExecApprovalCommandText(legacyValue) ? legacyValue : void 0;
374
- }
375
- return resolveMessagePresentationControlValue(control);
376
- }
377
- function isWithinSlackLimit(value, maxLength) {
378
- return value.length <= maxLength;
379
- }
380
- function isRenderableSlackOption(option) {
381
- return option.value !== void 0 && isWithinSlackLimit(option.value, 150);
382
- }
383
- function readSlackBlockId(block) {
384
- const value = block.block_id;
385
- return typeof value === "string" ? value : void 0;
386
- }
387
- function readSlackOpenClawBlockIndex(blockId, prefix) {
388
- if (!blockId.startsWith(prefix)) return;
389
- const value = Number.parseInt(blockId.slice(prefix.length), 10);
390
- return Number.isSafeInteger(value) && value > 0 ? value : void 0;
391
- }
392
- /** Resolve existing OpenClaw Block Kit indexes so appended controls keep stable unique IDs. */
393
- function resolveSlackInteractiveBlockOffsets(blocks) {
394
- let buttonIndexOffset = 0;
395
- let selectIndexOffset = 0;
396
- for (const block of blocks ?? []) {
397
- const blockId = readSlackBlockId(block);
398
- if (!blockId) continue;
399
- buttonIndexOffset = Math.max(buttonIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_buttons_") ?? 0);
400
- selectIndexOffset = Math.max(selectIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_select_") ?? 0);
401
- }
402
- return {
403
- buttonIndexOffset,
404
- selectIndexOffset
405
- };
406
- }
407
- /**
408
- * @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
409
- */
410
- function buildSlackInteractiveBlocks(interactive, options = {}) {
411
- return reduceInteractiveReply(interactive, {
412
- blocks: [],
413
- buttonIndex: options.buttonIndexOffset ?? 0,
414
- selectIndex: options.selectIndexOffset ?? 0
415
- }, (state, block) => {
416
- if (block.type === "text") {
417
- const trimmed = block.text.trim();
418
- if (!trimmed) return state;
419
- state.blocks.push({
420
- type: "section",
421
- text: {
422
- type: "mrkdwn",
423
- text: truncateSlackText(trimmed, SLACK_SECTION_TEXT_MAX)
424
- }
425
- });
426
- return state;
427
- }
428
- if (block.type === "buttons") {
429
- const elements = block.buttons.flatMap((button, choiceIndex) => {
430
- const callbackData = resolveSlackControlValue(button);
431
- const value = callbackData && isWithinSlackLimit(callbackData, 2e3) ? callbackData : void 0;
432
- const url = button.url && isWithinSlackLimit(button.url, SLACK_BUTTON_URL_MAX) ? button.url : void 0;
433
- if (!value && !url) return [];
434
- const target = url ? { url } : { value };
435
- const style = resolveSlackButtonStyle(button.style);
436
- return [{
437
- type: "button",
438
- action_id: url ? buildSlackReplyLinkActionId(state.buttonIndex + 1, choiceIndex) : buildSlackReplyButtonActionId(state.buttonIndex + 1, choiceIndex),
439
- text: {
440
- type: "plain_text",
441
- text: truncateSlackText(button.label, 75),
442
- emoji: true
443
- },
444
- ...target,
445
- ...style ? { style } : {}
446
- }];
447
- }).slice(0, 25);
448
- if (elements.length === 0) return state;
449
- state.blocks.push({
450
- type: "actions",
451
- block_id: `openclaw_reply_buttons_${++state.buttonIndex}`,
452
- elements
453
- });
454
- return state;
455
- }
456
- const optionsLocal = block.options.map((option) => ({
457
- label: option.label,
458
- value: resolveSlackControlValue(option)
459
- })).filter(isRenderableSlackOption).slice(0, 100);
460
- if (optionsLocal.length === 0) return state;
461
- state.blocks.push({
462
- type: "actions",
463
- block_id: `openclaw_reply_select_${++state.selectIndex}`,
464
- elements: [{
465
- type: "static_select",
466
- action_id: buildSlackReplySelectActionId(state.selectIndex),
467
- placeholder: {
468
- type: "plain_text",
469
- text: truncateSlackText(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75),
470
- emoji: true
471
- },
472
- options: optionsLocal.map((option, _choiceIndex) => ({
473
- text: {
474
- type: "plain_text",
475
- text: truncateSlackText(option.label, 75),
476
- emoji: true
477
- },
478
- value: option.value
479
- }))
480
- }]
481
- });
482
- return state;
483
- }).blocks;
484
- }
485
- /** Render portable presentation blocks as Slack Block Kit blocks. */
486
- function buildSlackPresentationBlocks(presentation, options = {}) {
487
- if (!presentation) return [];
488
- const blocks = [];
489
- if (presentation.title) blocks.push({
490
- type: "header",
491
- text: {
492
- type: "plain_text",
493
- text: truncateSlackText(presentation.title, 150),
494
- emoji: true
495
- }
496
- });
497
- let buttonIndex = options.buttonIndexOffset ?? 0;
498
- let selectIndex = options.selectIndexOffset ?? 0;
499
- for (const block of presentation.blocks) {
500
- if (block.type === "text" || block.type === "context") {
501
- const text = block.text.trim();
502
- if (!text) continue;
503
- if (block.type === "context") blocks.push({
504
- type: "context",
505
- elements: [{
506
- type: "mrkdwn",
507
- text: truncateSlackText(text, SLACK_SECTION_TEXT_MAX)
508
- }]
509
- });
510
- else blocks.push({
511
- type: "section",
512
- text: {
513
- type: "mrkdwn",
514
- text: truncateSlackText(text, SLACK_SECTION_TEXT_MAX)
515
- }
516
- });
517
- continue;
518
- }
519
- if (block.type === "divider") {
520
- blocks.push({ type: "divider" });
521
- continue;
522
- }
523
- if (block.type === "buttons") {
524
- const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1);
525
- if (rendered) {
526
- buttonIndex += 1;
527
- blocks.push(rendered);
528
- }
529
- continue;
530
- }
531
- if (block.type === "select") {
532
- const rendered = buildSlackPresentationSelectBlock(block, selectIndex + 1);
533
- if (rendered) {
534
- selectIndex += 1;
535
- blocks.push(rendered);
536
- }
537
- }
538
- }
539
- return blocks;
540
- }
541
- function buildSlackPresentationButtonBlock(block, buttonIndex) {
542
- const elements = block.buttons.flatMap((button, choiceIndex) => {
543
- const target = resolveSlackPresentationButtonTarget(button);
544
- if (!target) return [];
545
- const style = resolveSlackButtonStyle(button.style);
546
- return [{
547
- type: "button",
548
- action_id: target.url ? buildSlackReplyLinkActionId(buttonIndex, choiceIndex) : buildSlackReplyButtonActionId(buttonIndex, choiceIndex),
549
- text: {
550
- type: "plain_text",
551
- text: truncateSlackText(button.label, 75),
552
- emoji: true
553
- },
554
- ...target,
555
- ...style ? { style } : {}
556
- }];
557
- }).slice(0, 25);
558
- return elements.length > 0 ? {
559
- type: "actions",
560
- block_id: `openclaw_reply_buttons_${buttonIndex}`,
561
- elements
562
- } : void 0;
563
- }
564
- function resolveSlackPresentationButtonTarget(button) {
565
- const callbackData = resolveSlackControlValue(button);
566
- const value = callbackData && isWithinSlackLimit(callbackData, 2e3) ? callbackData : void 0;
567
- const rawUrl = button.url ?? button.webApp?.url ?? button.web_app?.url;
568
- const url = rawUrl && isWithinSlackLimit(rawUrl, SLACK_BUTTON_URL_MAX) ? rawUrl : void 0;
569
- return url ? { url } : value ? { value } : void 0;
570
- }
571
- /** True when native Slack rendering preserves every portable control. */
572
- function canRenderSlackPresentation(presentation) {
573
- if (presentation.title && !isWithinSlackLimit(presentation.title.trim(), 150)) return false;
574
- return presentation.blocks.every((block) => {
575
- if (block.type === "text" || block.type === "context") return isWithinSlackLimit(block.text.trim(), SLACK_SECTION_TEXT_MAX);
576
- if (block.type === "buttons") return block.buttons.length <= 25 && block.buttons.every((button) => resolveSlackPresentationButtonTarget(button) !== void 0);
577
- if (block.type === "select") return block.options.length <= 100 && block.options.every((option) => isRenderableSlackOption({
578
- label: option.label,
579
- value: resolveSlackControlValue(option)
580
- }));
581
- return true;
582
- });
583
- }
584
- function buildSlackPresentationSelectBlock(block, selectIndex) {
585
- const options = block.options.map((option) => ({
586
- label: option.label,
587
- value: resolveSlackControlValue(option)
588
- })).filter(isRenderableSlackOption).slice(0, 100);
589
- return options.length > 0 ? {
590
- type: "actions",
591
- block_id: `openclaw_reply_select_${selectIndex}`,
592
- elements: [{
593
- type: "static_select",
594
- action_id: buildSlackReplySelectActionId(selectIndex),
595
- placeholder: {
596
- type: "plain_text",
597
- text: truncateSlackText(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75),
598
- emoji: true
599
- },
600
- options: options.map((option) => ({
601
- text: {
602
- type: "plain_text",
603
- text: truncateSlackText(option.label, 75),
604
- emoji: true
605
- },
606
- value: option.value
607
- }))
608
- }]
609
- } : void 0;
610
- }
611
- //#endregion
612
- //#region extensions/slack/src/monitor/allow-list.ts
613
- const SLACK_SLUG_CACHE_MAX = 512;
614
- const slackSlugCache = /* @__PURE__ */ new Map();
615
- function normalizeSlackSlug(raw) {
616
- const key = raw ?? "";
617
- const cached = slackSlugCache.get(key);
618
- if (cached !== void 0) return cached;
619
- const normalized = normalizeHyphenSlug(raw);
620
- slackSlugCache.set(key, normalized);
621
- if (slackSlugCache.size > SLACK_SLUG_CACHE_MAX) {
622
- const oldest = slackSlugCache.keys().next();
623
- if (!oldest.done) slackSlugCache.delete(oldest.value);
624
- }
625
- return normalized;
626
- }
627
- function normalizeAllowList(list) {
628
- return normalizeStringEntries$1(list);
629
- }
630
- function normalizeAllowListLower(list) {
631
- return normalizeStringEntriesLower$1(list);
632
- }
633
- function normalizeSlackAllowOwnerEntry(entry) {
634
- const trimmed = normalizeOptionalLowercaseString(entry);
635
- if (!trimmed || trimmed === "*") return;
636
- const withoutPrefix = trimmed.replace(/^(slack:|user:)/, "");
637
- return /^u[a-z0-9]+$/.test(withoutPrefix) ? withoutPrefix : void 0;
638
- }
639
- function resolveSlackAllowListMatch(params) {
640
- const compiledAllowList = compileAllowlist(params.allowList);
641
- const id = normalizeOptionalLowercaseString(params.id);
642
- const name = normalizeOptionalLowercaseString(params.name);
643
- const slug = normalizeSlackSlug(name);
644
- return resolveCompiledAllowlistMatch({
645
- compiledAllowlist: compiledAllowList,
646
- candidates: [
647
- {
648
- value: id,
649
- source: "id"
650
- },
651
- {
652
- value: id ? `slack:${id}` : void 0,
653
- source: "prefixed-id"
654
- },
655
- {
656
- value: id ? `user:${id}` : void 0,
657
- source: "prefixed-user"
658
- },
659
- ...params.allowNameMatching === true ? [
660
- {
661
- value: name,
662
- source: "name"
663
- },
664
- {
665
- value: name ? `slack:${name}` : void 0,
666
- source: "prefixed-name"
667
- },
668
- {
669
- value: slug,
670
- source: "slug"
671
- }
672
- ] : []
673
- ]
674
- });
675
- }
676
- function allowListMatches(params) {
677
- return resolveSlackAllowListMatch(params).allowed;
678
- }
679
- function resolveSlackUserAllowed(params) {
680
- const allowList = normalizeAllowListLower(params.allowList);
681
- if (allowList.length === 0) return true;
682
- return allowListMatches({
683
- allowList,
684
- id: params.userId,
685
- name: params.userName,
686
- allowNameMatching: params.allowNameMatching
687
- });
688
- }
689
- //#endregion
690
- //#region extensions/slack/src/errors.ts
691
- const NO_ERROR_DETAIL = "no error detail";
692
- function redact(value) {
693
- return redactSensitiveText(value);
694
- }
695
- function addStringDetail(details, label, value) {
696
- if (typeof value !== "string") return;
697
- const trimmed = redact(value.trim());
698
- if (trimmed) details.push(label ? `${label}: ${trimmed}` : trimmed);
699
- }
700
- function addScalarDetail(details, label, value) {
701
- if (typeof value === "string") {
702
- addStringDetail(details, label, value);
703
- return;
704
- }
705
- if (typeof value === "number" || typeof value === "boolean") details.push(`${label}: ${String(value)}`);
706
- }
707
- function addStringListDetail(details, label, value) {
708
- if (!Array.isArray(value)) return;
709
- const entries = value.flatMap((entry) => {
710
- if (typeof entry !== "string") return [];
711
- const trimmed = redact(entry.trim());
712
- return trimmed ? [trimmed] : [];
713
- });
714
- if (entries.length) details.push(`${label}: ${entries.join(", ")}`);
715
- }
716
- function safeStringify(value) {
717
- const seen = /* @__PURE__ */ new WeakSet();
718
- try {
719
- const result = JSON.stringify(value, (_key, nested) => {
720
- if (typeof nested !== "object" || nested === null) return nested;
721
- if (seen.has(nested)) return "[Circular]";
722
- seen.add(nested);
723
- return nested;
724
- });
725
- return result ? redact(result) : void 0;
726
- } catch {
727
- return;
728
- }
729
- }
730
- function addSlackResponseMetadata(details, value) {
731
- if (!isRecord(value)) return;
732
- addStringListDetail(details, "scopes", value.scopes);
733
- addStringListDetail(details, "accepted", value.acceptedScopes);
734
- const messages = value.messages;
735
- if (Array.isArray(messages)) for (const message of messages) addStringDetail(details, "slack message", message);
736
- const warnings = value.warnings;
737
- if (Array.isArray(warnings)) for (const warning of warnings) addStringDetail(details, "slack warning", warning);
738
- }
739
- function addSlackDataDetails(details, value) {
740
- if (!isRecord(value)) return;
741
- addScalarDetail(details, "slack error", value.error);
742
- addScalarDetail(details, "needed", value.needed);
743
- addScalarDetail(details, "provided", value.provided);
744
- addSlackResponseMetadata(details, value.response_metadata);
745
- }
746
- function addRecordDetails(details, value) {
747
- addScalarDetail(details, "code", value.code);
748
- addScalarDetail(details, "status", value.status);
749
- addScalarDetail(details, "statusCode", value.statusCode);
750
- addScalarDetail(details, "statusMessage", value.statusMessage);
751
- addScalarDetail(details, "retryAfter", value.retryAfter);
752
- addScalarDetail(details, "errno", value.errno);
753
- addScalarDetail(details, "syscall", value.syscall);
754
- addScalarDetail(details, "hostname", value.hostname);
755
- addScalarDetail(details, "type", value.type);
756
- addStringDetail(details, "statusText", value.statusText);
757
- addStringDetail(details, "body", value.body);
758
- addSlackDataDetails(details, value.data);
759
- if (isRecord(value.response)) {
760
- addScalarDetail(details, "response status", value.response.status);
761
- addStringDetail(details, "response statusText", value.response.statusText);
762
- addSlackDataDetails(details, value.response.data);
763
- }
764
- }
765
- function collectSlackErrorDetails(error) {
766
- const details = [];
767
- if (error === void 0 || error === null) return details;
768
- if (typeof error === "string") {
769
- addStringDetail(details, "", error);
770
- return details;
771
- }
772
- if (error instanceof Error) {
773
- addStringDetail(details, "", error.message || error.name);
774
- if (error.cause !== void 0) {
775
- const cause = formatSlackError(error.cause, "");
776
- if (cause) details.push(`cause: ${cause}`);
777
- }
778
- }
779
- if (isRecord(error)) {
780
- addRecordDetails(details, error);
781
- const fallback = safeStringify(error);
782
- if (details.length === 0 && fallback && fallback !== "{}") details.push(fallback);
783
- }
784
- return details;
785
- }
786
- function formatSlackError(error, fallback = NO_ERROR_DETAIL) {
787
- const details = collectSlackErrorDetails(error);
788
- if (details.length > 0) return details.join("; ");
789
- if (error === void 0 || error === null) return fallback;
790
- if (typeof error === "string" && !error.trim()) return fallback;
791
- return safeStringify(error) ?? fallback;
792
- }
793
- //#endregion
794
- //#region extensions/slack/src/group-policy.ts
795
- function resolveSlackChannelPolicyEntry(params) {
796
- const accountId = normalizeAccountId(params.accountId ?? resolveDefaultSlackAccountId(params.cfg));
797
- const channelMap = mergeSlackAccountConfig(params.cfg, accountId).channels ?? {};
798
- if (Object.keys(channelMap).length === 0) return;
799
- const channelId = params.groupId?.trim();
800
- const channelName = params.groupChannel?.replace(/^#/, "");
801
- const normalizedName = normalizeHyphenSlug(channelName);
802
- const candidates = [
803
- channelId ?? "",
804
- channelName ? `#${channelName}` : "",
805
- channelName ?? "",
806
- normalizedName
807
- ].filter(Boolean);
808
- for (const candidate of candidates) if (candidate && channelMap[candidate]) return channelMap[candidate];
809
- return channelMap["*"];
810
- }
811
- function resolveSenderToolsEntry(entry, params) {
812
- if (!entry) return;
813
- return resolveToolsBySender({
814
- toolsBySender: entry.toolsBySender,
815
- senderId: params.senderId,
816
- senderName: params.senderName,
817
- senderUsername: params.senderUsername,
818
- senderE164: params.senderE164
819
- }) ?? entry.tools;
820
- }
821
- function resolveSlackGroupRequireMention(params) {
822
- const resolved = resolveSlackChannelPolicyEntry(params);
823
- if (typeof resolved?.requireMention === "boolean") return resolved.requireMention;
824
- return true;
825
- }
826
- function resolveSlackGroupToolPolicy(params) {
827
- return resolveSenderToolsEntry(resolveSlackChannelPolicyEntry(params), params);
828
- }
829
- //#endregion
830
- //#region extensions/slack/src/limits.ts
831
- const SLACK_TEXT_LIMIT = 8e3;
832
- //#endregion
833
- //#region extensions/slack/src/blocks-input.ts
834
- const SLACK_MAX_BLOCKS = 50;
835
- function parseBlocksJson(raw) {
836
- try {
837
- return JSON.parse(raw);
838
- } catch {
839
- throw new Error("blocks must be valid JSON");
840
- }
841
- }
842
- function assertBlocksArray(raw) {
843
- if (!Array.isArray(raw)) throw new Error("blocks must be an array");
844
- if (raw.length === 0) throw new Error("blocks must contain at least one block");
845
- if (raw.length > 50) throw new Error(`blocks cannot exceed 50 items`);
846
- for (const block of raw) {
847
- if (!block || typeof block !== "object" || Array.isArray(block)) throw new Error("each block must be an object");
848
- const type = block.type;
849
- if (typeof type !== "string" || type.trim().length === 0) throw new Error("each block must include a non-empty string type");
850
- }
851
- }
852
- function validateSlackBlocksArray(raw) {
853
- assertBlocksArray(raw);
854
- return raw;
855
- }
856
- function parseSlackBlocksInput(raw) {
857
- if (raw == null) return;
858
- return validateSlackBlocksArray(typeof raw === "string" ? parseBlocksJson(raw) : raw);
859
- }
860
- //#endregion
861
- //#region extensions/slack/src/reply-blocks.ts
862
- function resolveSlackReplyBlocks(payload) {
863
- const slackData = payload.channelData?.slack;
864
- let channelBlocks = [];
865
- if (slackData && typeof slackData === "object" && !Array.isArray(slackData)) channelBlocks = parseSlackBlocksInput(slackData.blocks) ?? [];
866
- const presentationBlocks = buildSlackPresentationBlocks(payload.presentation, resolveSlackInteractiveBlockOffsets(channelBlocks));
867
- const interactiveBlocks = buildSlackInteractiveBlocks(payload.interactive, resolveSlackInteractiveBlockOffsets([...channelBlocks, ...presentationBlocks]));
868
- const blocks = [
869
- ...channelBlocks,
870
- ...presentationBlocks,
871
- ...interactiveBlocks
872
- ];
873
- if (blocks.length > 50) throw new Error(`Slack blocks cannot exceed 50 items after interactive render`);
874
- return blocks.length > 0 ? blocks : void 0;
875
- }
876
- //#endregion
877
- export { resolveSessionSlackOriginTarget as A, isSlackExecApprovalAuthorizedSender as B, SLACK_REPLY_SELECT_ACTION_ID as C, isSlackAnyNativeApprovalClientEnabled as D, hasSlackPluginApprovers as E, shouldHandleSlackPluginViaForwardingSession as F, normalizeSlackApproverId as H, slackTargetsMatch as I, getSlackApprovalApprovers as L, resolveSlackFallbackOriginTarget as M, resolveTurnSourceSlackOriginTarget as N, normalizeSlackForwardTarget as O, shouldHandleSlackNativeApprovalRequest as P, isSlackApprovalAuthorizedSender as R, SLACK_REPLY_LINK_ACTION_ID as S, SLACK_SECTION_TEXT_MAX as T, resolveSlackExecApprovalTarget as U, isSlackExecApprovalClientEnabled as V, shouldSuppressLocalSlackExecApprovalPrompt as W, buildSlackPresentationBlocks as _, SLACK_TEXT_LIMIT as a, truncateSlackText as b, formatSlackError as c, normalizeAllowListLower as d, normalizeSlackAllowOwnerEntry as f, buildSlackInteractiveBlocks as g, resolveSlackUserAllowed as h, validateSlackBlocksArray as i, resolveSlackApprovalKind as j, normalizeSlackOriginTarget as k, allowListMatches as l, resolveSlackAllowListMatch as m, SLACK_MAX_BLOCKS as n, resolveSlackGroupRequireMention as o, normalizeSlackSlug as p, parseSlackBlocksInput as r, resolveSlackGroupToolPolicy as s, resolveSlackReplyBlocks as t, normalizeAllowList as u, canRenderSlackPresentation as v, SLACK_PRESENTATION_CAPABILITIES as w, SLACK_REPLY_BUTTON_ACTION_ID as x, resolveSlackInteractiveBlockOffsets as y, getSlackExecApprovalApprovers as z };