@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.
- package/dist/accounts.runtime-KvftRRek.js +2 -0
- package/dist/{action-runtime-DoQGk_8D.js → action-runtime-p6M2ULpv.js} +205 -29
- package/dist/action-runtime.runtime-DQstDkHG.js +2 -0
- package/dist/{actions-DMpDmKEA.js → actions-DkTcWmpT.js} +87 -138
- package/dist/{actions.runtime-C103_BPW.js → actions.runtime-BSxpwgUc.js} +1 -1
- package/dist/api.js +14 -13
- package/dist/{approval-handler.runtime-CIUbOt5T.js → approval-handler.runtime-UGbnz9OC.js} +3 -3
- package/dist/{channel-BjlsaGHn.js → channel-B0_j6C6z.js} +116 -140
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel-type-BpeTezY4.js +109 -0
- package/dist/{channel.setup-Dq6syTNU.js → channel.setup-BQFut21T.js} +2 -2
- package/dist/{client-DGxwSL7f.js → client-D2F6m8CP.js} +38 -2
- package/dist/config-api-Df9a1B8C.js +3 -0
- package/dist/{config-schema-BzqzFW__.js → config-schema-DYI01PV2.js} +20 -37
- package/dist/cursor-pages-DSmTg0su.js +13 -0
- package/dist/{directory-config-BZuS8141.js → directory-config-DRkFujwG.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-BNsxCgqP.js → directory-live-DX7yFsM-.js} +2 -2
- package/dist/{doctor-contract-XL6HeNCb.js → doctor-contract-DddfkMlF.js} +25 -38
- package/dist/doctor-contract-api.js +1 -1
- package/dist/group-policy-C-b2ZnSl.js +2332 -0
- package/dist/{interactive-replies-CXpT-vA_.js → interactive-replies-BilWUdcI.js} +5 -1
- package/dist/interactive-replies-api.js +1 -1
- package/dist/{message-tool-api-BgWKyu2r.js → message-tool-api-CA9jZrCY.js} +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-Ux-wzUWI.js → monitor-BN_uuvrQ.js} +3 -3
- package/dist/outbound-adapter-ECl0go7d.js +228 -0
- package/dist/{pipeline.runtime-rpVpay59.js → pipeline.runtime-f0eJJoJL.js} +492 -178
- package/dist/{policy-Dj-puVPb.js → policy-f8b0edSi.js} +1 -1
- package/dist/preflight-audio.runtime-D5Bgags0.js +3 -0
- package/dist/{probe-CuwRDE5j.js → probe-CfALk0l4.js} +2 -2
- package/dist/{provider-C1-DFSpw.js → provider-Ds-y-imP.js} +658 -192
- package/dist/{relay-source-D2jv1iGg.js → relay-source-B-6LFUdz.js} +6 -17
- package/dist/replies-BMvf3ihj.js +420 -0
- package/dist/{resolve-channels-CstkChBE.js → resolve-channels-DOMgNCWb.js} +17 -6
- package/dist/{resolve-users-C3NP2c-Q.js → resolve-users-aL6-Ssee.js} +11 -6
- package/dist/{runtime-BOk7xkOl.js → runtime-CauEvswP.js} +1 -1
- package/dist/{runtime-api-CEmqYxR-.js → runtime-api-CVb6CQjX.js} +3 -3
- package/dist/runtime-api.js +11 -11
- package/dist/runtime-setter-api.js +1 -1
- package/dist/{scopes-DCWVD5-8.js → scopes-Dw8wbU0j.js} +2 -2
- package/dist/{secret-contract-C3ChHo5A.js → secret-contract-CMohXFWS.js} +18 -113
- package/dist/secret-contract-api.js +1 -1
- package/dist/{send-DKDXoeoV.js → send-NEfJ0GvM.js} +662 -325
- package/dist/{send.runtime-GPRa63l1.js → send.runtime-BkKpitPu.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-Dv2fIJNB.js → setup-surface-BN2WeG5c.js} +3 -3
- package/dist/{shared-CosfcFri.js → shared-BLnB9R1T.js} +7 -5
- package/dist/{slash-dispatch.runtime-CcMbbT3_.js → slash-dispatch.runtime-C0Otuf_T.js} +1 -1
- package/dist/{streaming-compat-DjlgH-Be.js → streaming-compat-3_X-21wW.js} +1 -0
- package/dist/{target-parsing-3jYH8LfB.js → target-parsing-N6lHogYZ.js} +16 -3
- package/dist/{targets-Dll4NJgs.js → targets-KmjP2E8s.js} +1 -1
- package/node_modules/p-map/index.d.ts +155 -0
- package/node_modules/p-map/index.js +284 -0
- package/node_modules/p-map/license +9 -0
- package/node_modules/p-map/package.json +57 -0
- package/node_modules/p-map/readme.md +190 -0
- package/npm-shrinkwrap.json +16 -3
- package/openclaw.plugin.json +16 -0
- package/package.json +6 -4
- package/dist/accounts.runtime-DWvaCb-X.js +0 -2
- package/dist/action-runtime.runtime-BABj3aM-.js +0 -2
- package/dist/config-api-DnT9ohtE.js +0 -2
- package/dist/format-YCNoNkM2.js +0 -107
- package/dist/outbound-adapter-DVoBfBW5.js +0 -272
- package/dist/replies-DpF38e1y.js +0 -287
- package/dist/reply-blocks-BGQ6zSqM.js +0 -877
- 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 };
|