@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,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as formatUnknownError, s as SLACK_SOCKET_RECONNECT_POLICY } from "./provider-Ds-y-imP.js";
|
|
2
2
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import { computeBackoff, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
4
4
|
import { Buffer } from "node:buffer";
|
|
@@ -49,7 +49,7 @@ async function monitorSlackRelaySource(params) {
|
|
|
49
49
|
params.runtime.log?.(warn(`slack relay mode disconnected; reconnecting in ${Math.round(delayMs / 1e3)}s (attempt ${reconnectAttempts}) reason="${formatUnknownError(err)}"`));
|
|
50
50
|
await sleepWithAbort(delayMs, params.abortSignal);
|
|
51
51
|
} finally {
|
|
52
|
-
closeRelayWebSocket(connection
|
|
52
|
+
closeRelayWebSocket(connection);
|
|
53
53
|
params.setIdentity?.(void 0);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -58,10 +58,6 @@ function openRelayWebSocket(config, abortSignal) {
|
|
|
58
58
|
if (abortSignal?.aborted) return Promise.reject(/* @__PURE__ */ new Error("Slack relay websocket aborted before connect"));
|
|
59
59
|
return new Promise((resolve, reject) => {
|
|
60
60
|
const ws = new WebSocket(buildRelayWebSocketUrl(config), buildRelayWebSocketOptions(config.authToken));
|
|
61
|
-
const bufferedMessages = [];
|
|
62
|
-
const onEarlyMessage = (data) => bufferedMessages.push(data);
|
|
63
|
-
const detachBuffer = () => ws.off("message", onEarlyMessage);
|
|
64
|
-
ws.on("message", onEarlyMessage);
|
|
65
61
|
const cleanup = () => {
|
|
66
62
|
ws.off("open", onOpen);
|
|
67
63
|
ws.off("error", onError);
|
|
@@ -69,26 +65,20 @@ function openRelayWebSocket(config, abortSignal) {
|
|
|
69
65
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
70
66
|
};
|
|
71
67
|
const onOpen = () => {
|
|
68
|
+
ws.pause();
|
|
72
69
|
cleanup();
|
|
73
|
-
resolve(
|
|
74
|
-
ws,
|
|
75
|
-
bufferedMessages,
|
|
76
|
-
detachBuffer
|
|
77
|
-
});
|
|
70
|
+
resolve(ws);
|
|
78
71
|
};
|
|
79
72
|
const onError = (error) => {
|
|
80
73
|
cleanup();
|
|
81
|
-
detachBuffer();
|
|
82
74
|
reject(error);
|
|
83
75
|
};
|
|
84
76
|
const onClose = (code, reason) => {
|
|
85
77
|
cleanup();
|
|
86
|
-
detachBuffer();
|
|
87
78
|
reject(new Error(formatRelayClose(code, reason)));
|
|
88
79
|
};
|
|
89
80
|
const onAbort = () => {
|
|
90
81
|
cleanup();
|
|
91
|
-
detachBuffer();
|
|
92
82
|
closeRelayWebSocket(ws);
|
|
93
83
|
reject(/* @__PURE__ */ new Error("Slack relay websocket aborted during connect"));
|
|
94
84
|
};
|
|
@@ -99,7 +89,7 @@ function openRelayWebSocket(config, abortSignal) {
|
|
|
99
89
|
});
|
|
100
90
|
}
|
|
101
91
|
function runRelayWebSocket(params) {
|
|
102
|
-
const
|
|
92
|
+
const ws = params.connection;
|
|
103
93
|
const relayState = {};
|
|
104
94
|
let pending = Promise.resolve();
|
|
105
95
|
return new Promise((resolve, reject) => {
|
|
@@ -149,12 +139,11 @@ function runRelayWebSocket(params) {
|
|
|
149
139
|
closeRelayWebSocket(ws);
|
|
150
140
|
settleResolve();
|
|
151
141
|
};
|
|
152
|
-
params.connection.detachBuffer();
|
|
153
142
|
ws.on("message", onMessage);
|
|
154
143
|
ws.once("error", onError);
|
|
155
144
|
ws.once("close", onClose);
|
|
156
145
|
params.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
157
|
-
|
|
146
|
+
ws.resume();
|
|
158
147
|
});
|
|
159
148
|
}
|
|
160
149
|
async function handleRelayFrame(params) {
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { C as hasSlackNativeDataBlock, D as markdownToSlackMrkdwnChunks, F as SLACK_TEXT_LIMIT, f as hasSlackReplyStructuredContent, h as resolveSlackReplyBlocks, k as buildSlackBlocksFallbackText, m as resolveSlackReplyBlockResolution, w as isSlackInvalidBlocksError, x as buildSlackNativeDataAccessibilityText } from "./group-policy-C-b2ZnSl.js";
|
|
2
|
+
import { l as buildSlackNativeDataDeliveryPlan, r as sendMessageSlack, u as chunkSlackTextAtHardLimit } from "./send-NEfJ0GvM.js";
|
|
3
|
+
import { a as createSlackResponseUrlBudget, i as SlackResponseAlreadyReportedError } from "./provider-Ds-y-imP.js";
|
|
4
|
+
import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-reference";
|
|
5
|
+
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
6
|
+
import { SILENT_REPLY_TOKEN, chunkMarkdownTextWithMode, isSilentReplyText } from "openclaw/plugin-sdk/reply-chunking";
|
|
7
|
+
import { deliverTextOrMediaReply, getReplyPayloadTtsSupplement, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
8
|
+
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
9
|
+
import { buildCanonicalSentMessageHookContext, createInternalHookEvent, fireAndForgetHook, toInternalMessageSentContext, toPluginMessageContext, toPluginMessageSentEvent, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
|
|
10
|
+
//#region extensions/slack/src/message-sent-hook.ts
|
|
11
|
+
/**
|
|
12
|
+
* Slack-side emission of the `message_sent` plugin hook.
|
|
13
|
+
*
|
|
14
|
+
* Mirrors the Telegram pattern in `extensions/telegram/src/bot/delivery.replies.ts`
|
|
15
|
+
* (`buildTelegramSentHookContext`, `emitMessageSentHooks`, `emitTelegramMessageSentHooks`).
|
|
16
|
+
*
|
|
17
|
+
* Without this, plugins observing `message_sent` see Telegram outbound but not
|
|
18
|
+
* Slack outbound — even though `docs/plugins/hooks.md` documents the hook as
|
|
19
|
+
* firing for all successful outbound deliveries.
|
|
20
|
+
*/
|
|
21
|
+
function buildSlackSentHookContext(params) {
|
|
22
|
+
return buildCanonicalSentMessageHookContext({
|
|
23
|
+
to: params.to,
|
|
24
|
+
content: params.content,
|
|
25
|
+
success: params.success,
|
|
26
|
+
error: params.error,
|
|
27
|
+
channelId: "slack",
|
|
28
|
+
accountId: params.accountId ?? void 0,
|
|
29
|
+
conversationId: params.to,
|
|
30
|
+
sessionKey: params.sessionKeyForInternalHooks,
|
|
31
|
+
messageId: params.messageId,
|
|
32
|
+
isGroup: params.isGroup,
|
|
33
|
+
groupId: params.groupId
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function emitInternalSlackMessageSentHook(params) {
|
|
37
|
+
if (!params.sessionKeyForInternalHooks) return;
|
|
38
|
+
const canonical = buildSlackSentHookContext(params);
|
|
39
|
+
fireAndForgetHook(triggerInternalHook(createInternalHookEvent("message", "sent", params.sessionKeyForInternalHooks, toInternalMessageSentContext(canonical))), "slack: message:sent internal hook failed");
|
|
40
|
+
}
|
|
41
|
+
function emitMessageSentHooks(params) {
|
|
42
|
+
if (!params.enabled && !params.sessionKeyForInternalHooks) return;
|
|
43
|
+
const canonical = buildSlackSentHookContext(params);
|
|
44
|
+
if (params.enabled) fireAndForgetHook(Promise.resolve(params.hookRunner.runMessageSent(toPluginMessageSentEvent(canonical), toPluginMessageContext(canonical))), "slack: message_sent plugin hook failed");
|
|
45
|
+
emitInternalSlackMessageSentHook(params);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fire both the plugin `message_sent` hook and (if a session key is supplied)
|
|
49
|
+
* the internal `message:sent` hook for a successful or failed Slack outbound
|
|
50
|
+
* delivery.
|
|
51
|
+
*
|
|
52
|
+
* Safe to call after every `chat.postMessage` — the function self-gates on
|
|
53
|
+
* `hookRunner.hasHooks("message_sent")` so plugins not observing the hook
|
|
54
|
+
* incur no cost.
|
|
55
|
+
*/
|
|
56
|
+
function emitSlackMessageSentHooks(params) {
|
|
57
|
+
const hookRunner = getGlobalHookRunner();
|
|
58
|
+
emitMessageSentHooks({
|
|
59
|
+
...params,
|
|
60
|
+
hookRunner,
|
|
61
|
+
enabled: hookRunner?.hasHooks("message_sent") ?? false
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region extensions/slack/src/monitor/replies.ts
|
|
66
|
+
function readSlackReplyBlocks(payload) {
|
|
67
|
+
return resolveSlackReplyBlocks(payload);
|
|
68
|
+
}
|
|
69
|
+
function resolveSlackMediaHookSpokenText(payload) {
|
|
70
|
+
return (getReplyPayloadTtsSupplement(payload)?.spokenText ?? payload.spokenText)?.trim() || void 0;
|
|
71
|
+
}
|
|
72
|
+
function resolveDeliveredSlackReplyThreadTs(params) {
|
|
73
|
+
return (params.replyToMode === "off" ? void 0 : params.payloadReplyToId) ?? params.replyThreadTs;
|
|
74
|
+
}
|
|
75
|
+
async function deliverReplies(params) {
|
|
76
|
+
let latestResult;
|
|
77
|
+
const sendReply = async (input) => {
|
|
78
|
+
return await sendMessageSlack(params.target, input.text, {
|
|
79
|
+
cfg: params.cfg,
|
|
80
|
+
token: params.token,
|
|
81
|
+
threadTs: input.threadTs,
|
|
82
|
+
accountId: params.accountId,
|
|
83
|
+
...input.mediaUrl ? { mediaUrl: input.mediaUrl } : {},
|
|
84
|
+
...input.blocks ? { blocks: input.blocks } : {},
|
|
85
|
+
...input.authoredTextPlacement ? { authoredTextPlacement: input.authoredTextPlacement } : {},
|
|
86
|
+
...Object.hasOwn(input, "nativeDataFallbackBaseText") ? { nativeDataFallbackBaseText: input.nativeDataFallbackBaseText } : {},
|
|
87
|
+
...input.textIsSlackMrkdwn ? { textIsSlackMrkdwn: true } : {},
|
|
88
|
+
...input.textIsSlackPlainText ? { textIsSlackPlainText: true } : {},
|
|
89
|
+
...params.eventScope ? {
|
|
90
|
+
client: params.eventScope.client,
|
|
91
|
+
enterpriseEventScope: params.eventScope,
|
|
92
|
+
textLimit: params.textLimit,
|
|
93
|
+
...params.mediaMaxBytes !== void 0 ? { mediaMaxBytes: params.mediaMaxBytes } : {}
|
|
94
|
+
} : {},
|
|
95
|
+
...params.identity ? { identity: params.identity } : {},
|
|
96
|
+
...params.metadata ? { metadata: params.metadata } : {}
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
for (const payload of params.replies) {
|
|
100
|
+
if (payload.isReasoning === true) continue;
|
|
101
|
+
const threadTs = resolveDeliveredSlackReplyThreadTs({
|
|
102
|
+
replyToMode: params.replyToMode,
|
|
103
|
+
payloadReplyToId: payload.replyToId,
|
|
104
|
+
replyThreadTs: params.replyThreadTs
|
|
105
|
+
});
|
|
106
|
+
const reply = resolveSendableOutboundReplyParts(payload);
|
|
107
|
+
const textRaw = reply.hasText && !isSilentReplyText(reply.trimmedText, SILENT_REPLY_TOKEN) ? reply.trimmedText : void 0;
|
|
108
|
+
const { authoredTextPlacement, segments } = resolveSlackReplyBlockResolution(payload, { materializeAuthoredText: !reply.hasMedia && hasSlackReplyStructuredContent(payload) });
|
|
109
|
+
if (!textRaw && !reply.hasMedia && segments.length === 0) continue;
|
|
110
|
+
const emitSent = (content, result) => {
|
|
111
|
+
if (params.deferMessageSentHooks) return;
|
|
112
|
+
emitSlackMessageSentHooks({
|
|
113
|
+
sessionKeyForInternalHooks: params.sessionKeyForInternalHooks,
|
|
114
|
+
to: params.messageSentHookTarget ?? params.target,
|
|
115
|
+
accountId: params.accountId,
|
|
116
|
+
content,
|
|
117
|
+
success: true,
|
|
118
|
+
messageId: result?.messageId,
|
|
119
|
+
isGroup: params.isGroup,
|
|
120
|
+
groupId: params.groupId
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
const emitFailed = (content, error) => {
|
|
124
|
+
if (params.deferMessageSentHooks) return;
|
|
125
|
+
emitSlackMessageSentHooks({
|
|
126
|
+
sessionKeyForInternalHooks: params.sessionKeyForInternalHooks,
|
|
127
|
+
to: params.messageSentHookTarget ?? params.target,
|
|
128
|
+
accountId: params.accountId,
|
|
129
|
+
content,
|
|
130
|
+
success: false,
|
|
131
|
+
error: formatErrorMessage(error),
|
|
132
|
+
isGroup: params.isGroup,
|
|
133
|
+
groupId: params.groupId
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
const spokenText = resolveSlackMediaHookSpokenText(payload);
|
|
137
|
+
const hookParts = [];
|
|
138
|
+
let outsideText = authoredTextPlacement === "outside-blocks" ? textRaw ?? "" : "";
|
|
139
|
+
let lastResult;
|
|
140
|
+
let delivered = false;
|
|
141
|
+
try {
|
|
142
|
+
if (reply.hasMedia) {
|
|
143
|
+
const mediaCaption = outsideText;
|
|
144
|
+
if (mediaCaption) {
|
|
145
|
+
hookParts.push(mediaCaption);
|
|
146
|
+
outsideText = "";
|
|
147
|
+
} else if (!textRaw && spokenText) hookParts.push(spokenText);
|
|
148
|
+
const mediaDelivery = await deliverTextOrMediaReply({
|
|
149
|
+
payload,
|
|
150
|
+
text: mediaCaption,
|
|
151
|
+
sendText: async (text) => {
|
|
152
|
+
lastResult = await sendReply({
|
|
153
|
+
text,
|
|
154
|
+
threadTs
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
sendMedia: async ({ mediaUrl, caption }) => {
|
|
158
|
+
lastResult = await sendReply({
|
|
159
|
+
text: caption ?? "",
|
|
160
|
+
mediaUrl,
|
|
161
|
+
threadTs
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
delivered ||= mediaDelivery !== "empty";
|
|
166
|
+
}
|
|
167
|
+
for (const segment of segments) {
|
|
168
|
+
if (segment.kind === "text") {
|
|
169
|
+
const text = [outsideText, segment.text].filter(Boolean).join("\n\n");
|
|
170
|
+
outsideText = "";
|
|
171
|
+
if (!text) continue;
|
|
172
|
+
hookParts.push(text);
|
|
173
|
+
for (const chunk of chunkSlackTextAtHardLimit(text)) {
|
|
174
|
+
lastResult = await sendReply({
|
|
175
|
+
text: chunk,
|
|
176
|
+
threadTs,
|
|
177
|
+
textIsSlackPlainText: true
|
|
178
|
+
});
|
|
179
|
+
delivered = true;
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const baseText = outsideText;
|
|
184
|
+
outsideText = "";
|
|
185
|
+
const accessibilityText = buildSlackNativeDataAccessibilityText(baseText, segment.blocks) || buildSlackBlocksFallbackText(segment.blocks);
|
|
186
|
+
hookParts.push(accessibilityText);
|
|
187
|
+
const segmentPlacement = baseText ? "outside-blocks" : authoredTextPlacement === "blocks" ? "blocks" : "none";
|
|
188
|
+
lastResult = await sendReply({
|
|
189
|
+
text: baseText,
|
|
190
|
+
threadTs,
|
|
191
|
+
blocks: segment.blocks,
|
|
192
|
+
authoredTextPlacement: segmentPlacement,
|
|
193
|
+
...baseText ? { nativeDataFallbackBaseText: baseText } : {}
|
|
194
|
+
});
|
|
195
|
+
delivered = true;
|
|
196
|
+
}
|
|
197
|
+
if (outsideText && !reply.hasMedia) {
|
|
198
|
+
hookParts.push(outsideText);
|
|
199
|
+
lastResult = await sendReply({
|
|
200
|
+
text: outsideText,
|
|
201
|
+
threadTs
|
|
202
|
+
});
|
|
203
|
+
delivered = true;
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
emitFailed(hookParts.join("\n\n") || textRaw || spokenText || "", error);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
if (delivered) {
|
|
210
|
+
emitSent(hookParts.join("\n\n") || textRaw || spokenText || "", reply.hasMedia ? void 0 : lastResult);
|
|
211
|
+
latestResult = lastResult;
|
|
212
|
+
params.runtime.log?.(`delivered reply to ${params.target}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return latestResult;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Compute effective threadTs for a Slack reply based on replyToMode.
|
|
219
|
+
* - "off": stay in thread if already in one, otherwise main channel
|
|
220
|
+
* - "first": first reply goes to thread, subsequent replies to main channel
|
|
221
|
+
* - "all": all replies go to thread
|
|
222
|
+
*/
|
|
223
|
+
function resolveSlackThreadTs(params) {
|
|
224
|
+
return createSlackReplyReferencePlanner({
|
|
225
|
+
replyToMode: params.replyToMode,
|
|
226
|
+
incomingThreadTs: params.incomingThreadTs,
|
|
227
|
+
messageTs: params.messageTs,
|
|
228
|
+
hasReplied: params.hasReplied,
|
|
229
|
+
isThreadReply: params.isThreadReply
|
|
230
|
+
}).use();
|
|
231
|
+
}
|
|
232
|
+
function createSlackReplyReferencePlanner(params) {
|
|
233
|
+
return createReplyReferencePlanner({
|
|
234
|
+
replyToMode: params.isThreadReply ?? Boolean(params.incomingThreadTs && params.incomingThreadTs !== params.messageTs) ? "all" : params.replyToMode,
|
|
235
|
+
existingId: params.incomingThreadTs,
|
|
236
|
+
startId: params.messageTs,
|
|
237
|
+
hasReplied: params.hasReplied
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function createSlackReplyDeliveryPlan(params) {
|
|
241
|
+
const replyReference = createSlackReplyReferencePlanner({
|
|
242
|
+
replyToMode: params.replyToMode,
|
|
243
|
+
incomingThreadTs: params.incomingThreadTs,
|
|
244
|
+
messageTs: params.messageTs,
|
|
245
|
+
hasReplied: params.hasRepliedRef.value,
|
|
246
|
+
isThreadReply: params.isThreadReply
|
|
247
|
+
});
|
|
248
|
+
return {
|
|
249
|
+
peekThreadTs: () => replyReference.peek(),
|
|
250
|
+
nextThreadTs: () => replyReference.use(),
|
|
251
|
+
markSent: () => {
|
|
252
|
+
replyReference.markSent();
|
|
253
|
+
params.hasRepliedRef.value = replyReference.hasReplied();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
async function deliverSlackSlashReplies(params) {
|
|
258
|
+
const deliveries = [];
|
|
259
|
+
const responseBudget = params.responseBudget ?? createSlackResponseUrlBudget(params.respond);
|
|
260
|
+
const chunkLimit = Math.max(1, Math.min(params.textLimit, SLACK_TEXT_LIMIT));
|
|
261
|
+
const createBlockMessagePlan = (input) => {
|
|
262
|
+
const plan = buildSlackNativeDataDeliveryPlan({
|
|
263
|
+
blocks: input.blocks,
|
|
264
|
+
baseText: input.baseText
|
|
265
|
+
});
|
|
266
|
+
return {
|
|
267
|
+
message: {
|
|
268
|
+
text: plan.accessibilityText,
|
|
269
|
+
blocks: input.blocks,
|
|
270
|
+
mrkdwn: false
|
|
271
|
+
},
|
|
272
|
+
nativeFallback: plan.fallbackMessages,
|
|
273
|
+
...plan.skipOriginalBlocks ? { skipOriginalBlocks: true } : {}
|
|
274
|
+
};
|
|
275
|
+
};
|
|
276
|
+
for (const payload of params.replies) {
|
|
277
|
+
if (payload.isReasoning === true) continue;
|
|
278
|
+
const reply = resolveSendableOutboundReplyParts(payload);
|
|
279
|
+
const textRaw = reply.hasText && !isSilentReplyText(reply.trimmedText, SILENT_REPLY_TOKEN) ? reply.trimmedText : void 0;
|
|
280
|
+
const { authoredTextPlacement, segments } = resolveSlackReplyBlockResolution(payload, { materializeAuthoredText: hasSlackReplyStructuredContent(payload) });
|
|
281
|
+
let outsideText = authoredTextPlacement === "outside-blocks" ? textRaw ?? "" : "";
|
|
282
|
+
const messages = [];
|
|
283
|
+
const hookParts = [];
|
|
284
|
+
for (const segment of segments) {
|
|
285
|
+
if (segment.kind === "text") {
|
|
286
|
+
const text = [outsideText, segment.text].filter(Boolean).join("\n\n");
|
|
287
|
+
outsideText = "";
|
|
288
|
+
if (text) {
|
|
289
|
+
hookParts.push(text);
|
|
290
|
+
messages.push(...chunkSlackTextAtHardLimit(text).map((chunk) => ({ message: {
|
|
291
|
+
text: chunk,
|
|
292
|
+
mrkdwn: false
|
|
293
|
+
} })));
|
|
294
|
+
}
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const baseText = outsideText;
|
|
298
|
+
outsideText = "";
|
|
299
|
+
const accessibilityText = buildSlackNativeDataAccessibilityText(baseText, segment.blocks) || buildSlackBlocksFallbackText(segment.blocks);
|
|
300
|
+
hookParts.push(accessibilityText);
|
|
301
|
+
const blockPlan = createBlockMessagePlan({
|
|
302
|
+
blocks: segment.blocks,
|
|
303
|
+
baseText
|
|
304
|
+
});
|
|
305
|
+
messages.push(hasSlackNativeDataBlock(segment.blocks) || blockPlan.skipOriginalBlocks ? blockPlan : { message: {
|
|
306
|
+
text: accessibilityText,
|
|
307
|
+
blocks: segment.blocks,
|
|
308
|
+
mrkdwn: false
|
|
309
|
+
} });
|
|
310
|
+
}
|
|
311
|
+
if (outsideText) hookParts.push(outsideText);
|
|
312
|
+
if (reply.mediaUrls.length > 0) hookParts.push(...reply.mediaUrls);
|
|
313
|
+
if (segments.length > 0) {
|
|
314
|
+
const trailingText = [outsideText, ...reply.mediaUrls].filter(Boolean).join("\n");
|
|
315
|
+
if (trailingText) messages.push(...chunkSlackTextAtHardLimit(trailingText).map((text) => ({ message: {
|
|
316
|
+
text,
|
|
317
|
+
mrkdwn: false
|
|
318
|
+
} })));
|
|
319
|
+
if (messages.length > 0) deliveries.push({
|
|
320
|
+
hookContent: hookParts.filter(Boolean).join("\n\n"),
|
|
321
|
+
messages
|
|
322
|
+
});
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const combined = [textRaw ?? "", ...reply.mediaUrls].filter(Boolean).join("\n");
|
|
326
|
+
if (!combined) continue;
|
|
327
|
+
const chunkMode = params.chunkMode ?? "length";
|
|
328
|
+
const chunks = (chunkMode === "newline" ? chunkMarkdownTextWithMode(combined, chunkLimit, chunkMode) : [combined]).flatMap((markdown) => markdownToSlackMrkdwnChunks(markdown, chunkLimit, { tableMode: params.tableMode }));
|
|
329
|
+
deliveries.push({
|
|
330
|
+
hookContent: textRaw ?? resolveSlackMediaHookSpokenText(payload) ?? combined,
|
|
331
|
+
messages: (chunks.length > 0 ? chunks : [combined]).map((text) => ({ message: { text } }))
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
if (deliveries.length === 0) return;
|
|
335
|
+
const responseType = params.ephemeral ? "ephemeral" : "in_channel";
|
|
336
|
+
const respond = async (message) => await responseBudget.respond({
|
|
337
|
+
text: message.text,
|
|
338
|
+
response_type: responseType,
|
|
339
|
+
...message.blocks ? { blocks: message.blocks } : {},
|
|
340
|
+
...message.mrkdwn === false ? { mrkdwn: false } : {}
|
|
341
|
+
});
|
|
342
|
+
const emitDeliveryFailure = (delivery, error) => {
|
|
343
|
+
if (!params.messageSentHookTarget) return;
|
|
344
|
+
emitSlackMessageSentHooks({
|
|
345
|
+
sessionKeyForInternalHooks: params.sessionKeyForInternalHooks,
|
|
346
|
+
to: params.messageSentHookTarget,
|
|
347
|
+
accountId: params.accountId,
|
|
348
|
+
content: delivery.hookContent,
|
|
349
|
+
success: false,
|
|
350
|
+
error: formatErrorMessage(error),
|
|
351
|
+
isGroup: params.isGroup,
|
|
352
|
+
groupId: params.groupId
|
|
353
|
+
});
|
|
354
|
+
};
|
|
355
|
+
const minimumCalls = deliveries.flatMap((delivery) => delivery.messages).map((planned) => planned.nativeFallback?.length ?? 1);
|
|
356
|
+
const minimumRemainingCalls = Array.from({ length: minimumCalls.length + 1 }, () => 0);
|
|
357
|
+
for (let index = minimumCalls.length - 1; index >= 0; index -= 1) minimumRemainingCalls[index] = (minimumRemainingCalls[index + 1] ?? 0) + (minimumCalls[index] ?? 0);
|
|
358
|
+
const failOversizedDelivery = async () => {
|
|
359
|
+
const message = "Slack response exceeds the remaining response_url delivery budget.";
|
|
360
|
+
let failure = /* @__PURE__ */ new Error(message);
|
|
361
|
+
if (responseBudget.remaining() !== 0) try {
|
|
362
|
+
await responseBudget.respond({
|
|
363
|
+
text: "This Slack response is too large to deliver within the remaining response window.",
|
|
364
|
+
response_type: "ephemeral"
|
|
365
|
+
});
|
|
366
|
+
failure = new SlackResponseAlreadyReportedError(message);
|
|
367
|
+
} catch (error) {
|
|
368
|
+
failure = error;
|
|
369
|
+
}
|
|
370
|
+
for (const delivery of deliveries) emitDeliveryFailure(delivery, failure);
|
|
371
|
+
throw failure;
|
|
372
|
+
};
|
|
373
|
+
const initialRemaining = responseBudget.remaining();
|
|
374
|
+
const initialMinimumCalls = minimumCalls.reduce((total, calls) => total + calls, 0);
|
|
375
|
+
if (initialRemaining !== void 0 && initialMinimumCalls > initialRemaining) await failOversizedDelivery();
|
|
376
|
+
const deliverNativeFallback = async (messages) => {
|
|
377
|
+
for (const message of messages) if (isSlackInvalidBlocksError(await respond(message))) throw new Error("Slack rejected the native-data fallback blocks with invalid_blocks.");
|
|
378
|
+
};
|
|
379
|
+
let plannedIndex = 0;
|
|
380
|
+
for (const delivery of deliveries) {
|
|
381
|
+
try {
|
|
382
|
+
for (const planned of delivery.messages) {
|
|
383
|
+
const minimumAfter = minimumRemainingCalls[plannedIndex + 1] ?? 0;
|
|
384
|
+
plannedIndex += 1;
|
|
385
|
+
const fallback = planned.nativeFallback;
|
|
386
|
+
if (!fallback) {
|
|
387
|
+
await respond(planned.message);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const remaining = responseBudget.remaining();
|
|
391
|
+
if (!(!planned.skipOriginalBlocks && (remaining === void 0 || 1 + fallback.length + minimumAfter <= remaining))) {
|
|
392
|
+
await deliverNativeFallback(fallback);
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
let rejectedNativeBlocks = false;
|
|
396
|
+
try {
|
|
397
|
+
rejectedNativeBlocks = isSlackInvalidBlocksError(await respond(planned.message));
|
|
398
|
+
} catch (error) {
|
|
399
|
+
if (!isSlackInvalidBlocksError(error)) throw error;
|
|
400
|
+
rejectedNativeBlocks = true;
|
|
401
|
+
}
|
|
402
|
+
if (rejectedNativeBlocks) await deliverNativeFallback(fallback);
|
|
403
|
+
}
|
|
404
|
+
} catch (error) {
|
|
405
|
+
emitDeliveryFailure(delivery, error);
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
if (params.messageSentHookTarget) emitSlackMessageSentHooks({
|
|
409
|
+
sessionKeyForInternalHooks: params.sessionKeyForInternalHooks,
|
|
410
|
+
to: params.messageSentHookTarget,
|
|
411
|
+
accountId: params.accountId,
|
|
412
|
+
content: delivery.hookContent,
|
|
413
|
+
success: true,
|
|
414
|
+
isGroup: params.isGroup,
|
|
415
|
+
groupId: params.groupId
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
//#endregion
|
|
420
|
+
export { resolveDeliveredSlackReplyThreadTs as a, readSlackReplyBlocks as i, deliverReplies as n, resolveSlackThreadTs as o, deliverSlackSlashReplies as r, emitSlackMessageSentHooks as s, createSlackReplyDeliveryPlan as t };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { n as createSlackLookupClient } from "./client-D2F6m8CP.js";
|
|
3
|
+
import { t as collectSlackCursorPages } from "./cursor-pages-DSmTg0su.js";
|
|
4
4
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { resolveDirectoryAllowlistEntries } from "openclaw/plugin-sdk/directory-runtime";
|
|
5
6
|
//#region extensions/slack/src/resolve-channels.ts
|
|
6
7
|
var resolve_channels_exports = /* @__PURE__ */ __exportAll({ resolveSlackChannelAllowlist: () => resolveSlackChannelAllowlist });
|
|
7
8
|
function parseSlackChannelMention(raw) {
|
|
@@ -18,8 +19,8 @@ function parseSlackChannelMention(raw) {
|
|
|
18
19
|
return name ? { name } : {};
|
|
19
20
|
}
|
|
20
21
|
async function listSlackChannels(client) {
|
|
21
|
-
return
|
|
22
|
-
fetchPage:
|
|
22
|
+
return collectSlackCursorPages({
|
|
23
|
+
fetchPage: (cursor) => client.conversations.list({
|
|
23
24
|
types: "public_channel,private_channel",
|
|
24
25
|
exclude_archived: false,
|
|
25
26
|
limit: 1e3,
|
|
@@ -46,8 +47,18 @@ function resolveByName(name, channels) {
|
|
|
46
47
|
return matches.find((channel) => !channel.archived) ?? matches[0];
|
|
47
48
|
}
|
|
48
49
|
async function resolveSlackChannelAllowlist(params) {
|
|
49
|
-
const
|
|
50
|
-
|
|
50
|
+
const parsedEntries = params.entries.map((input) => ({
|
|
51
|
+
input,
|
|
52
|
+
parsed: parseSlackChannelMention(input)
|
|
53
|
+
}));
|
|
54
|
+
if (parsedEntries.every((entry) => Boolean(entry.parsed.id))) return parsedEntries.map(({ input, parsed }) => ({
|
|
55
|
+
input,
|
|
56
|
+
resolved: true,
|
|
57
|
+
id: parsed.id,
|
|
58
|
+
name: parsed.name
|
|
59
|
+
}));
|
|
60
|
+
const channels = await listSlackChannels(params.client ?? createSlackLookupClient(params.token));
|
|
61
|
+
return resolveDirectoryAllowlistEntries({
|
|
51
62
|
entries: params.entries,
|
|
52
63
|
lookup: channels,
|
|
53
64
|
parseInput: parseSlackChannelMention,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { n as createSlackLookupClient } from "./client-D2F6m8CP.js";
|
|
3
|
+
import { t as collectSlackCursorPages } from "./cursor-pages-DSmTg0su.js";
|
|
4
4
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { resolveDirectoryAllowlistEntries } from "openclaw/plugin-sdk/directory-runtime";
|
|
5
6
|
//#region extensions/slack/src/resolve-users.ts
|
|
6
7
|
var resolve_users_exports = /* @__PURE__ */ __exportAll({ resolveSlackUserAllowlist: () => resolveSlackUserAllowlist });
|
|
7
8
|
function parseSlackUserInput(raw) {
|
|
@@ -16,8 +17,8 @@ function parseSlackUserInput(raw) {
|
|
|
16
17
|
return name ? { name } : {};
|
|
17
18
|
}
|
|
18
19
|
async function listSlackUsers(client) {
|
|
19
|
-
return
|
|
20
|
-
fetchPage:
|
|
20
|
+
return collectSlackCursorPages({
|
|
21
|
+
fetchPage: (cursor) => client.users.list({
|
|
21
22
|
limit: 200,
|
|
22
23
|
cursor
|
|
23
24
|
}),
|
|
@@ -59,6 +60,10 @@ function resolveSlackUserFromMatches(input, matches, parsed) {
|
|
|
59
60
|
user,
|
|
60
61
|
score: scoreSlackUser(user, parsed)
|
|
61
62
|
})).toSorted((a, b) => b.score - a.score)[0]?.user ?? matches[0];
|
|
63
|
+
if (!best) return {
|
|
64
|
+
input,
|
|
65
|
+
resolved: false
|
|
66
|
+
};
|
|
62
67
|
return {
|
|
63
68
|
input,
|
|
64
69
|
resolved: true,
|
|
@@ -71,8 +76,8 @@ function resolveSlackUserFromMatches(input, matches, parsed) {
|
|
|
71
76
|
};
|
|
72
77
|
}
|
|
73
78
|
async function resolveSlackUserAllowlist(params) {
|
|
74
|
-
const users = await listSlackUsers(params.client ??
|
|
75
|
-
return
|
|
79
|
+
const users = await listSlackUsers(params.client ?? createSlackLookupClient(params.token));
|
|
80
|
+
return resolveDirectoryAllowlistEntries({
|
|
76
81
|
entries: params.entries,
|
|
77
82
|
lookup: users,
|
|
78
83
|
parseInput: parseSlackUserInput,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
2
|
//#region extensions/slack/src/runtime.ts
|
|
3
|
-
const { setRuntime: setSlackRuntime,
|
|
3
|
+
const { setRuntime: setSlackRuntime, tryGetRuntime: getOptionalSlackRuntime } = createPluginRuntimeStore({
|
|
4
4
|
pluginId: "slack",
|
|
5
5
|
errorMessage: "Slack runtime not initialized"
|
|
6
6
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "./target-parsing-
|
|
2
|
-
import "./client-
|
|
3
|
-
import "./config-api-
|
|
1
|
+
import "./target-parsing-N6lHogYZ.js";
|
|
2
|
+
import "./client-D2F6m8CP.js";
|
|
3
|
+
import "./config-api-Df9a1B8C.js";
|
|
4
4
|
import "openclaw/plugin-sdk/account-id";
|
|
5
5
|
import { createActionGate as createActionGate$1, imageResultFromFile, jsonResult, readPositiveIntegerParam, readReactionParams, readStringParam, withNormalizedTimestamp } from "openclaw/plugin-sdk/channel-actions";
|
|
6
6
|
import "openclaw/plugin-sdk/channel-status";
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { t as registerSlackPluginHttpRoutes } from "./plugin-routes-CLp4obpN.js";
|
|
2
2
|
import { a as resolveSlackAccount, f as resolveSlackAppToken, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, p as resolveSlackBotToken, t as listEnabledSlackAccounts } from "./accounts-BOJJiHSr.js";
|
|
3
|
-
import {
|
|
4
|
-
import { n as setSlackRuntime } from "./runtime-
|
|
5
|
-
import { r as
|
|
6
|
-
import {
|
|
7
|
-
import { t as probeSlack } from "./probe-
|
|
8
|
-
import { t as resolveSlackChannelAllowlist } from "./resolve-channels-
|
|
9
|
-
import { t as resolveSlackUserAllowlist } from "./resolve-users-
|
|
10
|
-
import { t as monitorSlackProvider } from "./provider-
|
|
11
|
-
import { n as slackActionRuntime, t as handleSlackAction } from "./action-runtime-
|
|
12
|
-
import { n as listSlackDirectoryGroupsLive, r as listSlackDirectoryPeersLive } from "./directory-live-
|
|
13
|
-
import "./monitor-
|
|
3
|
+
import { n as resolveSlackGroupToolPolicy, t as resolveSlackGroupRequireMention } from "./group-policy-C-b2ZnSl.js";
|
|
4
|
+
import { n as setSlackRuntime } from "./runtime-CauEvswP.js";
|
|
5
|
+
import { a as listSlackEmojis, c as pinSlackMessage, d as removeOwnSlackReactions, f as removeSlackReaction, h as unpinSlackMessage, i as getSlackMemberInfo, l as reactSlackMessage, m as sendSlackMessage, o as listSlackPins, r as editSlackMessage, s as listSlackReactions, t as deleteSlackMessage, u as readSlackMessages } from "./actions-DkTcWmpT.js";
|
|
6
|
+
import { r as sendMessageSlack } from "./send-NEfJ0GvM.js";
|
|
7
|
+
import { t as probeSlack } from "./probe-CfALk0l4.js";
|
|
8
|
+
import { t as resolveSlackChannelAllowlist } from "./resolve-channels-DOMgNCWb.js";
|
|
9
|
+
import { t as resolveSlackUserAllowlist } from "./resolve-users-aL6-Ssee.js";
|
|
10
|
+
import { t as monitorSlackProvider } from "./provider-Ds-y-imP.js";
|
|
11
|
+
import { n as slackActionRuntime, t as handleSlackAction } from "./action-runtime-p6M2ULpv.js";
|
|
12
|
+
import { n as listSlackDirectoryGroupsLive, r as listSlackDirectoryPeersLive } from "./directory-live-DX7yFsM-.js";
|
|
13
|
+
import "./monitor-BN_uuvrQ.js";
|
|
14
14
|
export { deleteSlackMessage, editSlackMessage, getSlackMemberInfo, handleSlackAction, listEnabledSlackAccounts, listSlackAccountIds, listSlackDirectoryGroupsLive, listSlackDirectoryPeersLive, listSlackEmojis, listSlackPins, listSlackReactions, monitorSlackProvider, pinSlackMessage, probeSlack, reactSlackMessage, readSlackMessages, registerSlackPluginHttpRoutes, removeOwnSlackReactions, removeSlackReaction, resolveDefaultSlackAccountId, resolveSlackAccount, resolveSlackAppToken, resolveSlackBotToken, resolveSlackChannelAllowlist, resolveSlackGroupRequireMention, resolveSlackGroupToolPolicy, resolveSlackUserAllowlist, sendMessageSlack, sendSlackMessage, setSlackRuntime, slackActionRuntime, unpinSlackMessage };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as setSlackRuntime } from "./runtime-
|
|
1
|
+
import { n as setSlackRuntime } from "./runtime-CauEvswP.js";
|
|
2
2
|
export { setSlackRuntime };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { r as formatSlackError } from "./group-policy-C-b2ZnSl.js";
|
|
2
|
+
import { i as createSlackWebClient } from "./client-D2F6m8CP.js";
|
|
3
3
|
import { isRecord, normalizeOptionalString, normalizeStringEntries, sortUniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
//#region extensions/slack/src/scopes.ts
|
|
5
5
|
function collectScopes(value, into) {
|