@openclaw/slack 2026.9.1-beta.1 → 2026.9.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/{account-inspect-CN2hBsim.js → account-inspect-C3sePHWa.js} +3 -3
- package/dist/account-inspect-api.js +1 -1
- package/dist/{action-runtime-BoSeX09X.js → action-runtime-DND4Pyp2.js} +84 -66
- package/dist/action-runtime.runtime-CEhbmS-Z.js +2 -0
- package/dist/{actions-XdQyjG_p.js → actions-fh66A6lc.js} +198 -54
- package/dist/api.js +14 -14
- package/dist/{approval-handler.runtime-DxXfGX_Z.js → approval-handler.runtime-D7d8sKM0.js} +18 -12
- package/dist/{channel-C_vnTgxo.js → channel-4m8IAdMD.js} +70 -128
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-type-j-2lalcC.js → channel-type-3-SqEMVc.js} +2 -2
- package/dist/{channel.setup-aal8tokM.js → channel.setup-t_ghLGb_.js} +23 -22
- package/dist/{config-schema-CN3XZRX5.js → config-schema-bP3eV2ra.js} +25 -16
- package/dist/{conversation-binding-route-DFVLUdYF.js → conversation-binding-route-Vee8Dgbf.js} +2 -2
- package/dist/{cursor-pages-eX7p8Wwt.js → cursor-pages-ByFwo-Py.js} +7 -1
- package/dist/{directory-config-DqfQ42OV.js → directory-config-Bmw4ykSy.js} +4 -3
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-lC6X_Ru-.js → directory-live-q32AW7N1.js} +3 -8
- package/dist/{doctor-contract-BAy7-EUQ.js → doctor-contract-BNjw9bxb.js} +5 -4
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{group-policy-CU1tEGpS.js → group-policy-BKjMqT-8.js} +161 -260
- package/dist/{message-tool-api-CWosHSi5.js → message-tool-api-uNEfQYGY.js} +19 -2
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-DrNCGneD.js → monitor-Chwu_SiZ.js} +3 -3
- package/dist/{outbound-adapter-DkT2vUE9.js → outbound-adapter-BB8wAjm5.js} +95 -91
- package/dist/{pipeline.runtime-CRRng_Nw.js → pipeline.runtime-BklS_NEj.js} +347 -505
- package/dist/{policy-BoP6t88v.js → policy-D7PKkiet.js} +7 -4
- package/dist/{probe-4_aHtVT3.js → probe-gj5yQgN2.js} +210 -3
- package/dist/{provider-D4nDgxCh.js → provider-Do50wMWn.js} +168 -153
- package/dist/{relay-source-CEmze11m.js → relay-source-DWuduiJ2.js} +6 -4
- package/dist/{replies-D9XMM_S0.js → replies-Dc6WVh_Q.js} +20 -16
- package/dist/{resolve-channels-DSamDgVs.js → resolve-channels-CU7Bg5Ka.js} +6 -10
- package/dist/{resolve-users-CIzwbaJR.js → resolve-users-DrhttvRQ.js} +5 -4
- package/dist/runtime-api.js +10 -10
- package/dist/{scopes-BBrUzpBH.js → scopes-B9HRguDe.js} +1 -1
- package/dist/{send-DtjEnlLh.js → send-Djswy6lf.js} +24 -16
- package/dist/send-results-eeOu_HYm.js +23 -0
- package/dist/{send.runtime-DQeNKa2J.js → send.runtime-__WVTWLQ.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-CsBCM4rP.js → setup-surface-DO0e-MMS.js} +5 -5
- package/dist/{shared-D9GeeR9K.js → shared-DEQBEKBL.js} +7 -5
- package/dist/{slash-dispatch.runtime-Chr3YHnT.js → slash-dispatch.runtime-C3B4h5ZM.js} +2 -2
- package/dist/{target-parsing-BnMD2ZqZ.js → target-parsing-PbxGDbr9.js} +11 -6
- package/dist/{targets-Cx5W_n3W.js → targets-7FexXJ62.js} +1 -1
- package/dist/{thread-ts-DUGhaYKq.js → thread-ts-CukseRVL.js} +5 -1
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/package.json +16 -10
- package/node_modules/typebox/build/format/email.mjs +1 -1
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
- package/node_modules/typebox/package.json +1 -1
- package/openclaw.plugin.json +15 -7
- package/package.json +5 -5
- package/dist/action-runtime.runtime-Dpa16J87.js +0 -2
- package/dist/slack-client-kind-hSfjXyUM.js +0 -94
- package/node_modules/@slack/bolt/node_modules/negotiator/HISTORY.md +0 -114
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import { a as resolveSlackAccount, f as resolveSlackBotToken } from "./accounts-Dm_H77gH.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { m as buildSlackNativeDataDeliveryPlan, r as sendMessageSlack } from "./send-
|
|
2
|
+
import { a as resolveSlackAccount, f as resolveSlackBotToken, i as resolveDefaultSlackAccountId } from "./accounts-Dm_H77gH.js";
|
|
3
|
+
import { n as formatSlackTarget } from "./target-parsing-PbxGDbr9.js";
|
|
4
|
+
import { At as SLACK_PRIVATE_ACTION_DELIVERY_RESULT, D as renderSlackBlockFallbackText, E as buildSlackCompleteBlocksFallbackText, I as countSlackTextUtf8Bytes, Q as normalizeSlackOutboundText, R as truncateSlackTextByUtf8Bytes, T as buildSlackBlocksFallbackText, _ as appendSlackNativeDataPlainTextFallback, b as hasSlackNativeDataBlock, c as assertSlackDetachedTargetAllowed, et as escapeSlackMrkdwn, g as appendSlackNativeDataFallbackText, k as SLACK_EDIT_TEXT_MAX_BYTES, st as validateSlackBlocksArray, w as stripSlackNativeDataBlocks, x as isSlackInvalidBlocksError } from "./group-policy-BKjMqT-8.js";
|
|
5
|
+
import { m as getSlackWriteClient, s as createSlackLookupClient } from "./probe-gj5yQgN2.js";
|
|
6
|
+
import { m as buildSlackNativeDataDeliveryPlan, r as sendMessageSlack } from "./send-Djswy6lf.js";
|
|
7
7
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
8
8
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
-
import { logVerbose, logVerbose as logVerbose$1 } from "openclaw/plugin-sdk/runtime-env";
|
|
9
|
+
import { createSubsystemLogger, logVerbose, logVerbose as logVerbose$1 } from "openclaw/plugin-sdk/runtime-env";
|
|
10
|
+
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
11
|
+
import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
10
12
|
import { z } from "zod";
|
|
11
13
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
12
14
|
import fs from "node:fs/promises";
|
|
@@ -14,6 +16,31 @@ import { runTasksWithConcurrency } from "openclaw/plugin-sdk/concurrency-runtime
|
|
|
14
16
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
15
17
|
import { normalizeHostname } from "openclaw/plugin-sdk/host-runtime";
|
|
16
18
|
import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
|
|
19
|
+
import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch";
|
|
20
|
+
import { saveRemoteMedia } from "openclaw/plugin-sdk/media-runtime";
|
|
21
|
+
//#region extensions/slack/src/conversation-open.ts
|
|
22
|
+
function parseSlackConversationOpenInput(userIds, teamId) {
|
|
23
|
+
const users = z.array(z.string().trim().regex(/^[UW][A-Z0-9]+$/)).min(1).max(8).parse(userIds);
|
|
24
|
+
if (new Set(users).size !== users.length) throw new Error("Slack conversation-open requires distinct userIds.");
|
|
25
|
+
return {
|
|
26
|
+
users,
|
|
27
|
+
teamId: teamId === void 0 ? void 0 : z.string().trim().regex(/^T[A-Z0-9]+$/i).parse(teamId)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function openSlackConversationWithClient(client, input) {
|
|
31
|
+
const channelId = (await client.conversations.open({ users: input.users.join(",") })).channel?.id?.trim();
|
|
32
|
+
if (!channelId || !/^[CDG][A-Z0-9]+$/i.test(channelId)) throw new Error("Slack conversations.open did not return a valid conversation ID.");
|
|
33
|
+
return {
|
|
34
|
+
channelId,
|
|
35
|
+
target: formatSlackTarget({
|
|
36
|
+
teamId: input.teamId,
|
|
37
|
+
kind: "channel",
|
|
38
|
+
id: channelId,
|
|
39
|
+
explicitKind: true
|
|
40
|
+
})
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
17
44
|
//#region extensions/slack/src/edit-text.ts
|
|
18
45
|
function buildSlackEditTextPayload(content, blocks) {
|
|
19
46
|
const trimmedContent = content.trim();
|
|
@@ -21,12 +48,92 @@ function buildSlackEditTextPayload(content, blocks) {
|
|
|
21
48
|
if (trimmedContent && !blockText) return trimmedContent;
|
|
22
49
|
if (trimmedContent) {
|
|
23
50
|
const nativePlainText = blocks?.length ? appendSlackNativeDataPlainTextFallback("", blocks).trim() : "";
|
|
24
|
-
|
|
51
|
+
const fallbackText = Boolean(blockText && trimmedContent.includes(blockText)) || Boolean(nativePlainText && trimmedContent.includes(nativePlainText)) ? trimmedContent : blockText && !blockText.includes(trimmedContent) ? `${trimmedContent}\n\n${blockText}` : blockText || trimmedContent;
|
|
52
|
+
return truncateSlackTextByUtf8Bytes(fallbackText, SLACK_EDIT_TEXT_MAX_BYTES);
|
|
25
53
|
}
|
|
26
54
|
if (blockText) return truncateSlackTextByUtf8Bytes(blockText, SLACK_EDIT_TEXT_MAX_BYTES);
|
|
27
55
|
return " ";
|
|
28
56
|
}
|
|
29
57
|
//#endregion
|
|
58
|
+
//#region extensions/slack/src/monitor/block-text.ts
|
|
59
|
+
function readSlackBlockType(block) {
|
|
60
|
+
return block && typeof block === "object" && !Array.isArray(block) ? block.type : void 0;
|
|
61
|
+
}
|
|
62
|
+
function hasSlackTableBlock(blocks) {
|
|
63
|
+
return blocks?.some((block) => readSlackBlockType(block) === "table") ?? false;
|
|
64
|
+
}
|
|
65
|
+
function hasSlackMessageTableBlock(message) {
|
|
66
|
+
return hasSlackTableBlock(message.blocks) || message.attachments?.some((attachment) => !isSlackUnfurlAttachment(attachment) && hasSlackTableBlock(attachment.blocks)) === true;
|
|
67
|
+
}
|
|
68
|
+
function isSlackUnfurlAttachment(attachment) {
|
|
69
|
+
return attachment.is_msg_unfurl === true || attachment.is_app_unfurl === true || typeof attachment.app_unfurl_url === "string" && attachment.app_unfurl_url.trim().length > 0;
|
|
70
|
+
}
|
|
71
|
+
function resolveSlackBlocksText(blocks) {
|
|
72
|
+
if (!blocks?.length) return;
|
|
73
|
+
const parts = [];
|
|
74
|
+
let hasRichText = false;
|
|
75
|
+
let hasNativeData = false;
|
|
76
|
+
for (const block of blocks) {
|
|
77
|
+
const blockType = readSlackBlockType(block);
|
|
78
|
+
hasRichText ||= blockType === "rich_text";
|
|
79
|
+
hasNativeData ||= blockType === "data_visualization" || blockType === "data_table" || blockType === "table";
|
|
80
|
+
const text = renderSlackBlockFallbackText(block, {
|
|
81
|
+
nativeDataFormat: "plain",
|
|
82
|
+
nativeReferenceFormat: "plain"
|
|
83
|
+
});
|
|
84
|
+
if (text) parts.push(text);
|
|
85
|
+
}
|
|
86
|
+
return parts.length > 0 ? {
|
|
87
|
+
text: parts.join("\n"),
|
|
88
|
+
hasRichText,
|
|
89
|
+
hasNativeData
|
|
90
|
+
} : void 0;
|
|
91
|
+
}
|
|
92
|
+
function appendDistinctSlackText(base, addition) {
|
|
93
|
+
if (!base) return addition;
|
|
94
|
+
const comparableBase = `\n${base.replace(/\r\n?/g, "\n")}\n`;
|
|
95
|
+
const comparableAddition = `\n${addition.replace(/\r\n?/g, "\n")}\n`;
|
|
96
|
+
if (comparableBase.includes(comparableAddition)) return base;
|
|
97
|
+
return `${base}\n${addition}`;
|
|
98
|
+
}
|
|
99
|
+
function resolveSlackAttachmentTableTexts(attachments) {
|
|
100
|
+
const seen = /* @__PURE__ */ new Set();
|
|
101
|
+
const texts = [];
|
|
102
|
+
for (const attachment of attachments ?? []) {
|
|
103
|
+
if (isSlackUnfurlAttachment(attachment)) continue;
|
|
104
|
+
for (const block of attachment.blocks ?? []) {
|
|
105
|
+
if (readSlackBlockType(block) !== "table") continue;
|
|
106
|
+
const text = renderSlackBlockFallbackText(block, { nativeDataFormat: "plain" });
|
|
107
|
+
if (!text || seen.has(text)) continue;
|
|
108
|
+
seen.add(text);
|
|
109
|
+
texts.push(text);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return texts;
|
|
113
|
+
}
|
|
114
|
+
/** Resolve agent-visible Slack text while admitting only native tables from attachments. */
|
|
115
|
+
function resolveSlackMessageText(message, options = {}) {
|
|
116
|
+
let resolved = chooseSlackPrimaryText({
|
|
117
|
+
messageText: options.preserveMessageTextWhitespace ? typeof message.text === "string" && message.text.trim().length > 0 ? message.text : void 0 : normalizeOptionalString(message.text),
|
|
118
|
+
blocksText: resolveSlackBlocksText(message.blocks)
|
|
119
|
+
});
|
|
120
|
+
for (const tableText of resolveSlackAttachmentTableTexts(message.attachments)) resolved = appendDistinctSlackText(resolved, tableText);
|
|
121
|
+
return resolved;
|
|
122
|
+
}
|
|
123
|
+
function chooseSlackPrimaryText(params) {
|
|
124
|
+
const { messageText, blocksText } = params;
|
|
125
|
+
if (!blocksText) return messageText;
|
|
126
|
+
if (!messageText) return blocksText.text;
|
|
127
|
+
if (blocksText.hasNativeData) {
|
|
128
|
+
const comparableMessageText = messageText.replace(/\s+/g, " ").trim();
|
|
129
|
+
const comparableBlocksText = blocksText.text.replace(/\s+/g, " ").trim();
|
|
130
|
+
if (comparableMessageText.includes(comparableBlocksText)) return messageText;
|
|
131
|
+
return comparableBlocksText.startsWith(comparableMessageText) ? blocksText.text : `${messageText}\n${blocksText.text}`;
|
|
132
|
+
}
|
|
133
|
+
if (blocksText.hasRichText && blocksText.text.length > messageText.length) return blocksText.text;
|
|
134
|
+
return blocksText.text.length > messageText.length && blocksText.text.startsWith(messageText) ? blocksText.text : messageText;
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
30
137
|
//#region extensions/slack/src/file-reference.ts
|
|
31
138
|
function formatSlackFileReference(file) {
|
|
32
139
|
const name = normalizeOptionalString(file?.name) ?? "file";
|
|
@@ -45,6 +152,21 @@ function formatSlackFileReferenceList(files) {
|
|
|
45
152
|
return files.map((file) => formatSlackFileReference(file)).join(", ");
|
|
46
153
|
}
|
|
47
154
|
//#endregion
|
|
155
|
+
//#region extensions/slack/src/monitor/media.runtime.ts
|
|
156
|
+
const slackMediaLog = createSubsystemLogger("gateway/channels/slack").child("media");
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region extensions/slack/src/monitor/slack-client-kind.ts
|
|
159
|
+
/** Detects the isolated GovSlack API plane without consulting mutable config. */
|
|
160
|
+
function isGovSlackClient(client) {
|
|
161
|
+
if (!client?.slackApiUrl) return false;
|
|
162
|
+
try {
|
|
163
|
+
const apiUrl = new URL(client.slackApiUrl);
|
|
164
|
+
return apiUrl.protocol === "https:" && !apiUrl.port && normalizeHostname(apiUrl.hostname) === "slack-gov.com";
|
|
165
|
+
} catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
48
170
|
//#region extensions/slack/src/monitor/media.ts
|
|
49
171
|
var media_exports = /* @__PURE__ */ __exportAll({
|
|
50
172
|
SLACK_MEDIA_READ_IDLE_TIMEOUT_MS: () => SLACK_MEDIA_READ_IDLE_TIMEOUT_MS,
|
|
@@ -180,6 +302,10 @@ async function looksLikeHtmlFile(filePath) {
|
|
|
180
302
|
}
|
|
181
303
|
const MAX_SLACK_MEDIA_CONCURRENCY = 3;
|
|
182
304
|
const MAX_SLACK_FORWARDED_ATTACHMENTS = 8;
|
|
305
|
+
const SLACK_MEDIA_LIMIT_REASON = `omitted: 8-file limit`;
|
|
306
|
+
function formatSlackMediaFailure(error) {
|
|
307
|
+
return redactToolPayloadText(formatErrorMessage(error)).replace(/\s+/g, " ").slice(0, 200);
|
|
308
|
+
}
|
|
183
309
|
async function fetchFreshSlackFileUrl(params) {
|
|
184
310
|
if (!params.file.id || !params.client) return null;
|
|
185
311
|
try {
|
|
@@ -221,7 +347,7 @@ async function downloadSlackMediaFile(params) {
|
|
|
221
347
|
if (!(fileMime === "text/html" || fileName.endsWith(".html") || fileName.endsWith(".htm"))) {
|
|
222
348
|
if (normalizeOptionalLowercaseString(saved.contentType?.split(";")[0]) === "text/html" || await looksLikeHtmlFile(saved.path)) {
|
|
223
349
|
await fs.rm(saved.path, { force: true }).catch(() => void 0);
|
|
224
|
-
|
|
350
|
+
throw new Error("blocked: unexpected HTML content");
|
|
225
351
|
}
|
|
226
352
|
}
|
|
227
353
|
const effectiveMime = resolveSlackMediaMimetype(params.file, saved.contentType);
|
|
@@ -259,6 +385,7 @@ async function resolveSlackMedia(params) {
|
|
|
259
385
|
const govSlack = isGovSlackClient(params.client);
|
|
260
386
|
const files = params.files ?? [];
|
|
261
387
|
const limitedFiles = files.length > 8 ? files.slice(0, 8) : files;
|
|
388
|
+
for (const file of files.slice(8)) params.unavailableFiles?.set(file, SLACK_MEDIA_LIMIT_REASON);
|
|
262
389
|
const refreshFileUrl = (file) => fetchFreshSlackFileUrl({
|
|
263
390
|
file,
|
|
264
391
|
client: params.client,
|
|
@@ -269,40 +396,30 @@ async function resolveSlackMedia(params) {
|
|
|
269
396
|
const preloaded = params.preloadedMedia?.get(file);
|
|
270
397
|
if (preloaded) return preloaded;
|
|
271
398
|
const eventUrl = file.url_private_download ?? file.url_private;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
token: params.token,
|
|
291
|
-
maxBytes: params.maxBytes,
|
|
292
|
-
readIdleTimeoutMs: params.readIdleTimeoutMs,
|
|
293
|
-
totalTimeoutMs: params.totalTimeoutMs,
|
|
294
|
-
abortSignal: params.abortSignal,
|
|
295
|
-
govSlack
|
|
296
|
-
}).catch(() => null);
|
|
399
|
+
let url = eventUrl ?? await refreshFileUrl(file);
|
|
400
|
+
let reason = "no private download URL";
|
|
401
|
+
for (let attempt = 0; url && attempt < 2; attempt += 1) {
|
|
402
|
+
try {
|
|
403
|
+
return await downloadSlackMediaFile({
|
|
404
|
+
...params,
|
|
405
|
+
file,
|
|
406
|
+
url,
|
|
407
|
+
govSlack
|
|
408
|
+
});
|
|
409
|
+
} catch (error) {
|
|
410
|
+
reason = formatSlackMediaFailure(error);
|
|
411
|
+
}
|
|
412
|
+
url = attempt === 0 && eventUrl ? await refreshFileUrl(file) : null;
|
|
413
|
+
}
|
|
414
|
+
params.unavailableFiles?.set(file, reason);
|
|
415
|
+
slackMediaLog.warn(`slack: file ${formatSlackFileReference(file)} unavailable (${reason})`);
|
|
416
|
+
return null;
|
|
297
417
|
}),
|
|
298
418
|
limit: MAX_SLACK_MEDIA_CONCURRENCY,
|
|
299
419
|
errorMode: "stop",
|
|
300
420
|
throwOnError: true
|
|
301
421
|
});
|
|
302
|
-
const resolved = results.filter((result
|
|
303
|
-
if (result) params.resolvedFiles?.add(limitedFiles[index]);
|
|
304
|
-
return result !== null;
|
|
305
|
-
});
|
|
422
|
+
const resolved = results.filter((result) => result !== null);
|
|
306
423
|
return resolved.length > 0 ? resolved : null;
|
|
307
424
|
}
|
|
308
425
|
/** Extracts text and media from forwarded-message attachments. Returns null when empty. */
|
|
@@ -317,7 +434,8 @@ async function resolveSlackAttachmentContent(params) {
|
|
|
317
434
|
if (fileIds.has(fileId)) return false;
|
|
318
435
|
fileIds.add(fileId);
|
|
319
436
|
return true;
|
|
320
|
-
}).
|
|
437
|
+
}).map((file, index) => {
|
|
438
|
+
if (index >= 8) return file;
|
|
321
439
|
const fileId = normalizeOptionalString(file.id);
|
|
322
440
|
const preloaded = fileId && candidates.find((candidate) => normalizeOptionalString(candidate.id) === fileId && params.preloadedMedia?.has(candidate));
|
|
323
441
|
if (preloaded) return preloaded;
|
|
@@ -325,11 +443,11 @@ async function resolveSlackAttachmentContent(params) {
|
|
|
325
443
|
const downloadable = candidates.find((candidate) => normalizeOptionalString(candidate.id) === fileId && (candidate.url_private_download || candidate.url_private));
|
|
326
444
|
return downloadable ? Object.assign({}, file, downloadable) : file;
|
|
327
445
|
});
|
|
328
|
-
const pendingFiles = new Map(allFiles.map((file) => [normalizeOptionalString(file.id) ?? file, file]));
|
|
329
|
-
const
|
|
446
|
+
const pendingFiles = new Map(allFiles.slice(0, 8).map((file) => [normalizeOptionalString(file.id) ?? file, file]));
|
|
447
|
+
const unavailableFileReasons = /* @__PURE__ */ new Map();
|
|
330
448
|
const resolveFiles = (files) => resolveSlackMedia({
|
|
331
449
|
...params,
|
|
332
|
-
|
|
450
|
+
unavailableFiles: unavailableFileReasons,
|
|
333
451
|
files: files?.flatMap((file) => {
|
|
334
452
|
const key = normalizeOptionalString(file.id) ?? file;
|
|
335
453
|
const selected = pendingFiles.get(key);
|
|
@@ -340,7 +458,7 @@ async function resolveSlackAttachmentContent(params) {
|
|
|
340
458
|
const directMediaPromise = resolveFiles(params.files);
|
|
341
459
|
const textBlocks = [];
|
|
342
460
|
const attachmentMedia = [];
|
|
343
|
-
let
|
|
461
|
+
let unavailableMediaCount = 0;
|
|
344
462
|
const govSlack = isGovSlackClient(params.client);
|
|
345
463
|
for (const att of forwardedAttachments) {
|
|
346
464
|
const text = att.text?.trim() || att.fallback?.trim();
|
|
@@ -371,19 +489,27 @@ async function resolveSlackAttachmentContent(params) {
|
|
|
371
489
|
...saved.fileName ? { fileName: saved.fileName } : {},
|
|
372
490
|
placeholder: `[Forwarded image: ${label}]`
|
|
373
491
|
});
|
|
374
|
-
} catch {
|
|
375
|
-
|
|
492
|
+
} catch (error) {
|
|
493
|
+
unavailableMediaCount += 1;
|
|
494
|
+
slackMediaLog.warn(`slack: forwarded image unavailable (${formatSlackMediaFailure(error)})`);
|
|
376
495
|
}
|
|
377
496
|
attachmentMedia.push(...await resolveFiles(att.files) ?? []);
|
|
378
497
|
}
|
|
379
498
|
const allMedia = [...await directMediaPromise ?? [], ...attachmentMedia];
|
|
380
|
-
const unavailableFiles = allFiles.
|
|
499
|
+
const unavailableFiles = allFiles.flatMap((file, index) => {
|
|
500
|
+
const reason = index >= 8 ? SLACK_MEDIA_LIMIT_REASON : unavailableFileReasons.get(file);
|
|
501
|
+
return reason ? [{
|
|
502
|
+
...file,
|
|
503
|
+
reason
|
|
504
|
+
}] : [];
|
|
505
|
+
});
|
|
506
|
+
unavailableMediaCount += unavailableFiles.length;
|
|
381
507
|
const combinedText = textBlocks.join("\n\n");
|
|
382
|
-
if (!combinedText && allMedia.length === 0 && allFiles.length === 0 &&
|
|
508
|
+
if (!combinedText && allMedia.length === 0 && allFiles.length === 0 && unavailableMediaCount === 0) return null;
|
|
383
509
|
return {
|
|
384
510
|
text: combinedText,
|
|
385
511
|
media: allMedia,
|
|
386
|
-
|
|
512
|
+
unavailableMediaCount,
|
|
387
513
|
...unavailableFiles.length > 0 ? { files: unavailableFiles } : {}
|
|
388
514
|
};
|
|
389
515
|
}
|
|
@@ -398,6 +524,7 @@ var actions_exports = /* @__PURE__ */ __exportAll({
|
|
|
398
524
|
listSlackEmojis: () => listSlackEmojis,
|
|
399
525
|
listSlackPins: () => listSlackPins,
|
|
400
526
|
listSlackReactions: () => listSlackReactions,
|
|
527
|
+
openSlackConversation: () => openSlackConversation,
|
|
401
528
|
pinSlackMessage: () => pinSlackMessage,
|
|
402
529
|
reactSlackMessage: () => reactSlackMessage,
|
|
403
530
|
readSlackMessages: () => readSlackMessages,
|
|
@@ -421,8 +548,9 @@ function resolveToken(explicit, accountId, cfg) {
|
|
|
421
548
|
if (token) return token;
|
|
422
549
|
}
|
|
423
550
|
if (!cfg) throw new Error("Slack actions requires a resolved runtime config. Load and resolve config at the command or gateway boundary, then pass cfg through the runtime path.");
|
|
551
|
+
const resolvedCfg = requireRuntimeConfig(cfg, "Slack actions");
|
|
424
552
|
const account = resolveSlackAccount({
|
|
425
|
-
cfg:
|
|
553
|
+
cfg: resolvedCfg,
|
|
426
554
|
accountId
|
|
427
555
|
});
|
|
428
556
|
const token = resolveSlackBotToken(account.botToken ?? void 0);
|
|
@@ -509,10 +637,11 @@ function hasSlackPlatformError(err, code) {
|
|
|
509
637
|
}
|
|
510
638
|
async function getClient(opts = {}, mode = "read") {
|
|
511
639
|
if (opts.client) return opts.client;
|
|
512
|
-
|
|
640
|
+
const accountId = opts.cfg ? resolveSlackAccount({
|
|
513
641
|
cfg: requireRuntimeConfig(opts.cfg, "Slack actions"),
|
|
514
642
|
accountId: opts.accountId
|
|
515
|
-
}).accountId : normalizeAccountId(opts.accountId)
|
|
643
|
+
}).accountId : normalizeAccountId(opts.accountId);
|
|
644
|
+
assertSlackDetachedTargetAllowed(accountId, opts.teamId);
|
|
516
645
|
const token = resolveToken(opts.token, opts.accountId, opts.cfg);
|
|
517
646
|
if (mode === "write") return getSlackWriteClient(token, { teamId: opts.teamId });
|
|
518
647
|
return createSlackLookupClient(token, { teamId: opts.teamId });
|
|
@@ -597,7 +726,13 @@ async function sendSlackMessage(to, content, opts) {
|
|
|
597
726
|
});
|
|
598
727
|
}
|
|
599
728
|
async function editSlackMessage(channelId, messageId, content, opts = {}) {
|
|
600
|
-
|
|
729
|
+
const accountId = opts.accountId ?? (opts.cfg ? resolveDefaultSlackAccountId(opts.cfg) : void 0);
|
|
730
|
+
const tableMode = resolveMarkdownTableMode({
|
|
731
|
+
cfg: opts.cfg,
|
|
732
|
+
channel: "slack",
|
|
733
|
+
accountId
|
|
734
|
+
});
|
|
735
|
+
await editSlackRenderedMessage(channelId, messageId, normalizeSlackOutboundText(content, { tableMode }), opts);
|
|
601
736
|
}
|
|
602
737
|
async function editSlackRenderedMessage(channelId, messageId, content, opts = {}) {
|
|
603
738
|
const client = await getClient(opts, "write");
|
|
@@ -617,10 +752,12 @@ async function editSlackRenderedMessage(channelId, messageId, content, opts = {}
|
|
|
617
752
|
} catch (error) {
|
|
618
753
|
if (!hasSlackNativeDataBlock(blocks) || !isSlackInvalidBlocksError(error)) throw error;
|
|
619
754
|
logVerbose("slack edit: native data block rejected, retrying with text fallback");
|
|
620
|
-
const
|
|
755
|
+
const survivorBlocks = stripSlackNativeDataBlocks(blocks);
|
|
756
|
+
const survivorText = buildSlackBlocksFallbackText(survivorBlocks) ?? "";
|
|
621
757
|
const authoredEditText = content.trim();
|
|
758
|
+
const baseText = authoredEditText && !survivorText.includes(authoredEditText) ? authoredEditText : "";
|
|
622
759
|
const fallbackPlan = buildSlackNativeDataDeliveryPlan({
|
|
623
|
-
baseText
|
|
760
|
+
baseText,
|
|
624
761
|
blocks: blocks ?? []
|
|
625
762
|
});
|
|
626
763
|
if (fallbackPlan.fallbackMessages.length !== 1) throw new Error("Slack native chart or table edit fallback requires multiple messages. Send a new message instead.", { cause: error });
|
|
@@ -642,6 +779,13 @@ async function deleteSlackMessage(channelId, messageId, opts = {}) {
|
|
|
642
779
|
ts: messageId
|
|
643
780
|
});
|
|
644
781
|
}
|
|
782
|
+
async function openSlackConversation(userIds, opts = {}) {
|
|
783
|
+
const input = parseSlackConversationOpenInput(userIds, opts.teamId);
|
|
784
|
+
return await openSlackConversationWithClient(await getClient({
|
|
785
|
+
...opts,
|
|
786
|
+
teamId: input.teamId
|
|
787
|
+
}, "write"), input);
|
|
788
|
+
}
|
|
645
789
|
async function resolveSlackConversationName(channelId, opts = {}) {
|
|
646
790
|
return (await (await getClient(opts, "read")).conversations.info({ channel: channelId })).channel?.name?.trim() || void 0;
|
|
647
791
|
}
|
|
@@ -786,4 +930,4 @@ async function downloadSlackFile(fileId, opts) {
|
|
|
786
930
|
}))?.[0] ?? null;
|
|
787
931
|
}
|
|
788
932
|
//#endregion
|
|
789
|
-
export { media_exports as _, editSlackRenderedMessage as a,
|
|
933
|
+
export { hasSlackMessageTableBlock as C, resolveSlackMessageText as D, resolveSlackBlocksText as E, buildSlackEditTextPayload as O, formatSlackFileReferenceList as S, isSlackUnfurlAttachment as T, media_exports as _, editSlackRenderedMessage as a, saveRemoteMedia as b, listSlackPins as c, reactSlackMessage as d, readSlackMessages as f, unpinSlackMessage as g, sendSlackMessage as h, editSlackMessage as i, listSlackReactions as l, removeSlackReaction as m, deleteSlackMessage as n, getSlackMemberInfo as o, removeOwnSlackReactions as p, downloadSlackFile as r, listSlackEmojis as s, actions_exports as t, pinSlackMessage as u, logVerbose$1 as v, hasSlackTableBlock as w, formatSlackFileReference as x, isGovSlackClient as y };
|
package/dist/api.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { n as registerSlackHttpHandler, r as normalizeSlackWebhookPath, t as handleSlackHttpRequest } from "./registry-bbjH7IHX.js";
|
|
2
2
|
import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, r as mergeSlackAccountConfig, t as listEnabledSlackAccounts } from "./accounts-Dm_H77gH.js";
|
|
3
|
-
import { r as resolveSlackReplyToMode } from "./conversation-binding-route-
|
|
4
|
-
import { t as inspectSlackAccount } from "./account-inspect-
|
|
5
|
-
import { a as parseSlackTarget, i as normalizeSlackMessagingTarget, o as resolveSlackChannelId, r as looksLikeSlackTargetId } from "./target-parsing-
|
|
6
|
-
import "./targets-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { n as
|
|
10
|
-
import {
|
|
11
|
-
import { n as resolveSlackChannelType } from "./channel-type-
|
|
12
|
-
import { t as slackSetupPlugin } from "./channel.setup-
|
|
13
|
-
import { c as listSlackPins, d as reactSlackMessage, f as readSlackMessages, g as unpinSlackMessage, h as sendSlackMessage, i as editSlackMessage, l as listSlackReactions, m as removeSlackReaction, n as deleteSlackMessage, o as getSlackMemberInfo, p as removeOwnSlackReactions, r as downloadSlackFile, s as listSlackEmojis, u as pinSlackMessage } from "./actions-
|
|
14
|
-
import { f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, s as clearSlackThreadParticipationCache } from "./send-
|
|
15
|
-
import { n as listSlackDirectoryGroupsFromConfig, r as listSlackDirectoryPeersFromConfig } from "./directory-config-
|
|
3
|
+
import { r as resolveSlackReplyToMode } from "./conversation-binding-route-Vee8Dgbf.js";
|
|
4
|
+
import { t as inspectSlackAccount } from "./account-inspect-C3sePHWa.js";
|
|
5
|
+
import { a as parseSlackTarget, i as normalizeSlackMessagingTarget, o as resolveSlackChannelId, r as looksLikeSlackTargetId } from "./target-parsing-PbxGDbr9.js";
|
|
6
|
+
import "./targets-7FexXJ62.js";
|
|
7
|
+
import { N as buildSlackInteractiveBlocks, P as buildSlackPresentationBlocks, at as SLACK_MAX_BLOCKS, i as resolveSlackGroupToolPolicy, jt as resolveSlackAutoThreadId, ot as parseSlackBlocksInput, r as resolveSlackGroupRequireMention, st as validateSlackBlocksArray } from "./group-policy-BKjMqT-8.js";
|
|
8
|
+
import { C as normalizeAllowListLower, E as resolveSlackAllowListMatch, O as resolveSlackUserAllowed, S as normalizeAllowList, T as normalizeSlackSlug, b as resolveSlackWriteClientOptions, d as createSlackWebClient, f as createSlackWriteClient, g as SLACK_WRITE_RETRY_OPTIONS, h as SLACK_DEFAULT_RETRY_OPTIONS, m as getSlackWriteClient, t as probeSlack, u as createSlackTokenCacheKey, w as normalizeSlackAllowOwnerEntry, x as allowListMatches, y as resolveSlackWebClientOptions } from "./probe-gj5yQgN2.js";
|
|
9
|
+
import { n as buildSlackThreadingToolContext, t as slackPlugin } from "./channel-4m8IAdMD.js";
|
|
10
|
+
import { n as extractSlackToolSend, r as listSlackMessageActions } from "./message-tool-api-uNEfQYGY.js";
|
|
11
|
+
import { n as resolveSlackChannelType } from "./channel-type-3-SqEMVc.js";
|
|
12
|
+
import { t as slackSetupPlugin } from "./channel.setup-t_ghLGb_.js";
|
|
13
|
+
import { c as listSlackPins, d as reactSlackMessage, f as readSlackMessages, g as unpinSlackMessage, h as sendSlackMessage, i as editSlackMessage, l as listSlackReactions, m as removeSlackReaction, n as deleteSlackMessage, o as getSlackMemberInfo, p as removeOwnSlackReactions, r as downloadSlackFile, s as listSlackEmojis, u as pinSlackMessage } from "./actions-fh66A6lc.js";
|
|
14
|
+
import { f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, s as clearSlackThreadParticipationCache } from "./send-Djswy6lf.js";
|
|
15
|
+
import { n as listSlackDirectoryGroupsFromConfig, r as listSlackDirectoryPeersFromConfig } from "./directory-config-Bmw4ykSy.js";
|
|
16
16
|
import { t as collectSlackSecurityAuditFindings } from "./security-audit-B_yKr7MW.js";
|
|
17
|
-
import { n as resolveSlackRuntimeGroupPolicy } from "./provider-
|
|
17
|
+
import { n as resolveSlackRuntimeGroupPolicy } from "./provider-Do50wMWn.js";
|
|
18
18
|
export { SLACK_DEFAULT_RETRY_OPTIONS, SLACK_MAX_BLOCKS, SLACK_WRITE_RETRY_OPTIONS, allowListMatches, buildSlackInteractiveBlocks, buildSlackPresentationBlocks, buildSlackThreadingToolContext, clearSlackThreadParticipationCache, collectSlackSecurityAuditFindings, createSlackTokenCacheKey, createSlackWebClient, createSlackWriteClient, deleteSlackMessage, downloadSlackFile, editSlackMessage, extractSlackToolSend, getSlackMemberInfo, getSlackWriteClient, handleSlackHttpRequest, hasSlackThreadParticipation, inspectSlackAccount, listEnabledSlackAccounts, listSlackAccountIds, listSlackDirectoryGroupsFromConfig, listSlackDirectoryPeersFromConfig, listSlackEmojis, listSlackMessageActions, listSlackPins, listSlackReactions, looksLikeSlackTargetId, mergeSlackAccountConfig, normalizeAllowList, normalizeAllowListLower, normalizeSlackAllowOwnerEntry, normalizeSlackMessagingTarget, normalizeSlackSlug, normalizeSlackWebhookPath, parseSlackBlocksInput, parseSlackTarget, pinSlackMessage, probeSlack, reactSlackMessage, readSlackMessages, recordSlackThreadParticipation, registerSlackHttpHandler, removeOwnSlackReactions, removeSlackReaction, resolveDefaultSlackAccountId, resolveSlackAccount, resolveSlackAllowListMatch, resolveSlackAutoThreadId, resolveSlackChannelId, resolveSlackChannelType, resolveSlackGroupRequireMention, resolveSlackGroupToolPolicy, resolveSlackReplyToMode, resolveSlackRuntimeGroupPolicy, resolveSlackUserAllowed, resolveSlackWebClientOptions, resolveSlackWriteClientOptions, sendSlackMessage, slackPlugin, slackSetupPlugin, unpinSlackMessage, validateSlackBlocksArray };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as parseSlackTarget } from "./target-parsing-
|
|
2
|
-
import {
|
|
3
|
-
import { r as sendMessageSlack } from "./send-
|
|
1
|
+
import { a as parseSlackTarget } from "./target-parsing-PbxGDbr9.js";
|
|
2
|
+
import { Dt as normalizeSlackApproverId, R as truncateSlackTextByUtf8Bytes, f as resolveSlackReplyBlocks, gt as shouldHandleSlackNativeApprovalRequest, k as SLACK_EDIT_TEXT_MAX_BYTES, lt as isSlackAnyNativeApprovalClientEnabled, tt as SLACK_APPROVAL_HEADER_BLOCK_ID } from "./group-policy-BKjMqT-8.js";
|
|
3
|
+
import { r as sendMessageSlack } from "./send-Djswy6lf.js";
|
|
4
4
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
5
|
import { buildChannelApprovalNativeTargetKey } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
6
6
|
import { buildApprovalPresentationFromActionDescriptors } from "openclaw/plugin-sdk/approval-reply-runtime";
|
|
@@ -46,7 +46,7 @@ function buildSlackMetadataLines(metadata) {
|
|
|
46
46
|
}
|
|
47
47
|
function buildSlackMetadataContextElements(metadata) {
|
|
48
48
|
const lines = buildSlackMetadataLines(metadata);
|
|
49
|
-
const visibleLineCount = lines.length > SLACK_CONTEXT_ELEMENTS_MAX ?
|
|
49
|
+
const visibleLineCount = lines.length > SLACK_CONTEXT_ELEMENTS_MAX ? 9 : lines.length;
|
|
50
50
|
const elements = [];
|
|
51
51
|
for (let index = 0; index < visibleLineCount; index += 1) {
|
|
52
52
|
const line = lines[index];
|
|
@@ -93,14 +93,15 @@ function buildSlackPluginRequestBlocks(view) {
|
|
|
93
93
|
function buildSlackApprovalPayload(input) {
|
|
94
94
|
const { phase, view } = input;
|
|
95
95
|
const isPlugin = view.approvalKind === "plugin";
|
|
96
|
-
const
|
|
96
|
+
const isSystemAgent = view.approvalKind === "system-agent";
|
|
97
|
+
const approvalName = isPlugin ? "Plugin" : isSystemAgent ? "OpenClaw change" : "Exec";
|
|
97
98
|
let heading;
|
|
98
99
|
let description;
|
|
99
100
|
if (phase === "pending") {
|
|
100
101
|
heading = `*${approvalName} approval required*`;
|
|
101
|
-
description = view.approvalKind === "plugin" ? resolveSlackPluginDescription(view) : "A command needs your approval.";
|
|
102
|
+
description = view.approvalKind === "plugin" ? resolveSlackPluginDescription(view) : isSystemAgent ? "An OpenClaw change needs your approval." : "A command needs your approval.";
|
|
102
103
|
} else if (phase === "resolved") {
|
|
103
|
-
heading = `*${approvalName} approval: ${resolveSlackApprovalDecisionLabel(view.decision)}*`;
|
|
104
|
+
heading = `*${approvalName} approval: ${isSystemAgent && view.terminalStatus === "cancelled" ? "Cancelled" : isSystemAgent && view.applicationStatus === "applied" ? "Applied" : isSystemAgent && view.applicationStatus === "not-applied" ? "Not applied" : resolveSlackApprovalDecisionLabel(view.decision)}*`;
|
|
104
105
|
const resolvedBy = formatSlackApprover(view.resolvedBy);
|
|
105
106
|
description = resolvedBy ? `Resolved by ${resolvedBy}.` : "Resolved.";
|
|
106
107
|
} else {
|
|
@@ -108,7 +109,7 @@ function buildSlackApprovalPayload(input) {
|
|
|
108
109
|
description = "This approval request expired before it was resolved.";
|
|
109
110
|
}
|
|
110
111
|
const metadata = isPlugin ? buildSlackPluginMetadata(view) : view.metadata;
|
|
111
|
-
const bodyLabel = isPlugin ? "*Request*" : "*Command*";
|
|
112
|
+
const bodyLabel = isPlugin ? "*Request*" : isSystemAgent ? "*Change*" : "*Command*";
|
|
112
113
|
const bodyText = isPlugin ? view.title : buildSlackCodeBlock(view.commandText);
|
|
113
114
|
const text = [
|
|
114
115
|
heading,
|
|
@@ -130,7 +131,7 @@ function buildSlackApprovalPayload(input) {
|
|
|
130
131
|
type: "section",
|
|
131
132
|
text: {
|
|
132
133
|
type: "mrkdwn",
|
|
133
|
-
text:
|
|
134
|
+
text: `${bodyLabel}\n${buildSlackCodeBlock(truncateSlackMrkdwn(view.commandText, 2600))}`
|
|
134
135
|
}
|
|
135
136
|
}, ...phase === "pending" ? buildSlackMetadataContextBlocks(view.metadata) : []]];
|
|
136
137
|
if (phase === "pending") blocks.push(...resolveSlackReplyBlocks({
|
|
@@ -155,7 +156,11 @@ async function updateMessage(params) {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
const slackApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
|
|
158
|
-
eventKinds: [
|
|
159
|
+
eventKinds: [
|
|
160
|
+
"exec",
|
|
161
|
+
"plugin",
|
|
162
|
+
"system-agent"
|
|
163
|
+
],
|
|
159
164
|
availability: {
|
|
160
165
|
isConfigured: (params) => {
|
|
161
166
|
const resolved = resolveHandlerContext(params);
|
|
@@ -272,10 +277,11 @@ async function resolveApprovalChannel(client, target, teamId) {
|
|
|
272
277
|
const parsed = parseSlackTarget(target, { defaultKind: "channel" });
|
|
273
278
|
if (!parsed) throw new Error("Slack approval delivery target is missing");
|
|
274
279
|
if (parsed.kind === "channel") return `channel:${parsed.id}`;
|
|
275
|
-
const
|
|
280
|
+
const opened = await client.conversations.open({
|
|
276
281
|
users: parsed.id,
|
|
277
282
|
return_im: true
|
|
278
|
-
})
|
|
283
|
+
});
|
|
284
|
+
const channelId = normalizeOptionalString(opened.channel?.id);
|
|
279
285
|
if (!channelId) throw new Error("Slack Enterprise Grid approval DM did not return a channel id");
|
|
280
286
|
return `channel:${channelId}`;
|
|
281
287
|
}
|