@openclaw/slack 2026.7.1 → 2026.7.2-beta.2
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-Cee2ih0s.js} +209 -30
- package/dist/action-runtime.runtime-DZfd7IFr.js +2 -0
- package/dist/{actions-DMpDmKEA.js → actions-BZiuSTIq.js} +88 -143
- package/dist/{actions.runtime-C103_BPW.js → actions.runtime-DoD0-gxw.js} +1 -1
- package/dist/api.js +14 -13
- package/dist/{approval-handler.runtime-CIUbOt5T.js → approval-handler.runtime-CUPtIM4k.js} +3 -3
- package/dist/{channel-BjlsaGHn.js → channel-DaIiGUOp.js} +119 -141
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel-type-Cfm6_6n1.js +109 -0
- package/dist/{channel.setup-Dq6syTNU.js → channel.setup-C-mLz50O.js} +3 -3
- package/dist/{client-DGxwSL7f.js → client-WIPAS3Yr.js} +46 -2
- package/dist/config-api-Df9a1B8C.js +3 -0
- package/dist/{config-schema-BzqzFW__.js → config-schema-xPSnK2VK.js} +32 -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-D_yZhjgp.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-85UWiriS.js +2345 -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-CalGciTs.js} +3 -3
- package/dist/outbound-adapter-BiLKcnyH.js +228 -0
- package/dist/{pipeline.runtime-rpVpay59.js → pipeline.runtime-DofAvTtb.js} +657 -221
- package/dist/{policy-Dj-puVPb.js → policy-BVs4LiSa.js} +7 -7
- package/dist/preflight-audio.runtime-D5Bgags0.js +3 -0
- package/dist/{probe-CuwRDE5j.js → probe-CN0ssfLN.js} +2 -2
- package/dist/{provider-C1-DFSpw.js → provider-CmeoUiIM.js} +907 -206
- package/dist/{relay-source-D2jv1iGg.js → relay-source-DMmgtvg4.js} +6 -17
- package/dist/replies-CJJCp6qz.js +420 -0
- package/dist/{resolve-channels-CstkChBE.js → resolve-channels-Rfts6POK.js} +17 -6
- package/dist/{resolve-users-C3NP2c-Q.js → resolve-users-y6wAxR8E.js} +11 -6
- package/dist/runtime-JSVZSWAj.js +8 -0
- package/dist/{runtime-api-CEmqYxR-.js → runtime-api-BGDyOt1D.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-CuxNQZ6v.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-DYp8ca-l.js} +662 -325
- package/dist/{send.runtime-GPRa63l1.js → send.runtime-CJLxAt26.js} +1 -1
- package/dist/{setup-core-fGd6Gquy.js → setup-core-CkwVLzFO.js} +15 -21
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-Dv2fIJNB.js → setup-surface-oSd3NX9J.js} +4 -4
- package/dist/{shared-CosfcFri.js → shared-D9yz5Otg.js} +17 -38
- package/dist/{slash-dispatch.runtime-CcMbbT3_.js → slash-dispatch.runtime-CSja9VuD.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 +84 -0
- package/package.json +7 -7
- 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/configured-state.js +0 -11
- 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
- package/dist/runtime-BOk7xkOl.js +0 -8
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as slackContextTargetsMatch } from "./targets-
|
|
3
|
-
import {
|
|
4
|
-
import { a as readPositiveIntegerParam, c as withNormalizedTimestamp, n as imageResultFromFile, o as readReactionParams, r as jsonResult, s as readStringParam, t as createActionGate } from "./runtime-api-
|
|
5
|
-
import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-
|
|
1
|
+
import { a as resolveSlackChannelId, i as parseSlackTarget } from "./target-parsing-N6lHogYZ.js";
|
|
2
|
+
import { t as slackContextTargetsMatch } from "./targets-KmjP2E8s.js";
|
|
3
|
+
import { Z as parseSlackBlocksInput, w as hasSlackNativeDataBlock } from "./group-policy-85UWiriS.js";
|
|
4
|
+
import { a as readPositiveIntegerParam, c as withNormalizedTimestamp, n as imageResultFromFile, o as readReactionParams, r as jsonResult, s as readStringParam, t as createActionGate } from "./runtime-api-BGDyOt1D.js";
|
|
5
|
+
import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-BVs4LiSa.js";
|
|
6
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
7
|
+
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
8
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
7
9
|
import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
|
|
8
10
|
import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
|
|
@@ -22,8 +24,9 @@ const pinActions = /* @__PURE__ */ new Set([
|
|
|
22
24
|
"unpinMessage",
|
|
23
25
|
"listPins"
|
|
24
26
|
]);
|
|
25
|
-
const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-
|
|
26
|
-
const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-
|
|
27
|
+
const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-DoD0-gxw.js"));
|
|
28
|
+
const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-KvftRRek.js"));
|
|
29
|
+
const loadSlackChannelTypeRuntime = createLazyRuntimeModule(() => import("./channel-type-Cfm6_6n1.js").then((n) => n.t));
|
|
27
30
|
function createLazySlackAction(key) {
|
|
28
31
|
return (async (...args) => {
|
|
29
32
|
const action = (await loadSlackActionsRuntime())[key];
|
|
@@ -45,6 +48,8 @@ const slackActionRuntime = {
|
|
|
45
48
|
removeOwnSlackReactions: createLazySlackAction("removeOwnSlackReactions"),
|
|
46
49
|
removeSlackReaction: createLazySlackAction("removeSlackReaction"),
|
|
47
50
|
resolveSlackConversationName: createLazySlackAction("resolveSlackConversationName"),
|
|
51
|
+
resolveSlackConversationInfo: async (params) => (await loadSlackChannelTypeRuntime()).resolveSlackConversationInfo(params),
|
|
52
|
+
resolveSlackChannelType: async (params) => (await loadSlackChannelTypeRuntime()).resolveSlackChannelType(params),
|
|
48
53
|
sendSlackMessage: createLazySlackAction("sendSlackMessage"),
|
|
49
54
|
unpinSlackMessage: createLazySlackAction("unpinSlackMessage")
|
|
50
55
|
};
|
|
@@ -75,7 +80,51 @@ function readSlackBlocksParam(params) {
|
|
|
75
80
|
function isImageContentType(value) {
|
|
76
81
|
return value?.trim().toLowerCase().startsWith("image/") === true;
|
|
77
82
|
}
|
|
78
|
-
function
|
|
83
|
+
function hasPotentialSlackNamedPolicy(params) {
|
|
84
|
+
if (params.allowNameMatching !== true) return false;
|
|
85
|
+
return Object.entries(params.channels ?? {}).some(([key, entry]) => {
|
|
86
|
+
if (entry == null || key === "*") return false;
|
|
87
|
+
const named = !/^(?:channel:)?[CDG][A-Z0-9]+$/i.test(key);
|
|
88
|
+
const entryAllows = entry.enabled !== false;
|
|
89
|
+
return named && (params.decision === "allow" ? entryAllows : !entryAllows);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function resolveSlackDmReadAllowed(account) {
|
|
93
|
+
const dmPolicy = account.config.dmPolicy ?? account.config.dm?.policy ?? "pairing";
|
|
94
|
+
return account.config.dm?.enabled !== false && dmPolicy !== "disabled";
|
|
95
|
+
}
|
|
96
|
+
function normalizeConfiguredSlackDmUserId(value) {
|
|
97
|
+
const target = parseSlackTarget(String(value), { defaultKind: "user" });
|
|
98
|
+
if (target?.kind !== "user") return;
|
|
99
|
+
const userId = target.id.trim().toLowerCase();
|
|
100
|
+
return /^[uw][a-z0-9]+$/i.test(userId) ? userId : void 0;
|
|
101
|
+
}
|
|
102
|
+
async function isSlackDmTargetConfigured(params) {
|
|
103
|
+
const defaultTo = params.account.config.defaultTo?.trim();
|
|
104
|
+
if (defaultTo && slackContextTargetsMatch(params.channelId, { currentChannelId: defaultTo })) return true;
|
|
105
|
+
const userId = normalizeConfiguredSlackDmUserId(params.userId);
|
|
106
|
+
if (!userId) return false;
|
|
107
|
+
const { resolveSlackAccountAllowFrom } = await loadSlackAccountsRuntime();
|
|
108
|
+
return [
|
|
109
|
+
...resolveSlackAccountAllowFrom({
|
|
110
|
+
cfg: params.cfg,
|
|
111
|
+
accountId: params.account.accountId
|
|
112
|
+
}) ?? [],
|
|
113
|
+
...Object.keys(params.account.config.dms ?? {}),
|
|
114
|
+
...defaultTo ? [defaultTo] : []
|
|
115
|
+
].some((entry) => normalizeConfiguredSlackDmUserId(entry) === userId);
|
|
116
|
+
}
|
|
117
|
+
function isCurrentSlackReadTarget(params) {
|
|
118
|
+
const requesterAccountId = params.context?.requesterAccountId?.trim();
|
|
119
|
+
return Boolean(normalizeOptionalLowercaseString(params.context?.currentChannelProvider) === "slack" && requesterAccountId && normalizeAccountId(requesterAccountId) === normalizeAccountId(params.account.accountId) && params.context && slackContextTargetsMatch(params.channelId, params.context));
|
|
120
|
+
}
|
|
121
|
+
function assertSlackMemberInfoAllowed(params) {
|
|
122
|
+
if (params.context?.conversationReadOrigin === "direct-operator") return;
|
|
123
|
+
const requesterAccountId = params.context?.requesterAccountId?.trim();
|
|
124
|
+
const requesterSenderId = normalizeOptionalLowercaseString(params.context?.requesterSenderId);
|
|
125
|
+
if (normalizeOptionalLowercaseString(params.context?.currentChannelProvider) !== "slack" || !requesterAccountId || normalizeAccountId(requesterAccountId) !== normalizeAccountId(params.account.accountId) || !requesterSenderId || requesterSenderId !== normalizeOptionalLowercaseString(params.userId)) throw new Error("Delegated Slack member info is limited to the current requester.");
|
|
126
|
+
}
|
|
127
|
+
function resolveSlackChannelReadPolicy(params) {
|
|
79
128
|
const channels = params.account.config.channels;
|
|
80
129
|
const channelKeys = Object.keys(channels ?? {});
|
|
81
130
|
const channelConfig = resolveSlackChannelConfig({
|
|
@@ -87,29 +136,103 @@ function resolveSlackReadTargetDecision(params) {
|
|
|
87
136
|
defaultRequireMention: params.account.config.requireMention
|
|
88
137
|
});
|
|
89
138
|
const channelAllowed = channelConfig?.allowed !== false;
|
|
139
|
+
const channelExplicitlyDisabled = !channelAllowed && channelConfig?.matchSource === "direct";
|
|
140
|
+
const channelWildcardDisabled = !channelAllowed && channelConfig?.matchSource === "wildcard";
|
|
90
141
|
const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
|
|
91
142
|
providerConfigPresent: params.cfg.channels?.slack !== void 0,
|
|
92
143
|
groupPolicy: params.account.config.groupPolicy,
|
|
93
144
|
defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
|
|
94
145
|
});
|
|
95
|
-
|
|
146
|
+
const delegatedChannelAllowed = isSlackChannelAllowedByPolicy({
|
|
96
147
|
groupPolicy,
|
|
97
148
|
channelAllowlistConfigured: channelKeys.length > 0,
|
|
98
149
|
channelAllowed
|
|
99
|
-
})
|
|
100
|
-
|
|
150
|
+
}) && !(!channelAllowed && (groupPolicy !== "open" || channelConfig?.matchSource));
|
|
151
|
+
const directChannelAllowed = groupPolicy !== "disabled" && !channelExplicitlyDisabled && !channelWildcardDisabled;
|
|
152
|
+
const baseChannelAllowed = params.conversationReadOrigin === "direct-operator" || params.currentConversation ? directChannelAllowed : delegatedChannelAllowed;
|
|
153
|
+
const allowNameMatching = params.account.config.dangerouslyAllowNameMatching;
|
|
154
|
+
const shouldResolveName = !params.metadataResolved && !params.channelName && (baseChannelAllowed && channelConfig?.matchSource !== "direct" && hasPotentialSlackNamedPolicy({
|
|
155
|
+
channels,
|
|
156
|
+
allowNameMatching,
|
|
157
|
+
decision: "deny"
|
|
158
|
+
}) || !baseChannelAllowed && groupPolicy !== "disabled" && !channelExplicitlyDisabled && hasPotentialSlackNamedPolicy({
|
|
159
|
+
channels,
|
|
160
|
+
allowNameMatching,
|
|
161
|
+
decision: "allow"
|
|
162
|
+
}));
|
|
163
|
+
return {
|
|
164
|
+
channelAllowed: baseChannelAllowed,
|
|
165
|
+
channelExplicitlyDisabled,
|
|
166
|
+
groupDmAllowed: params.account.config.dm?.enabled !== false && params.account.config.dm?.groupEnabled === true && (params.currentConversation || isSlackGroupDmTargetConfigured(params.account, params.channelId)),
|
|
167
|
+
shouldResolveName
|
|
168
|
+
};
|
|
101
169
|
}
|
|
102
170
|
async function assertSlackReadTargetAllowed(params) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
171
|
+
const deny = () => {
|
|
172
|
+
throw new Error("Slack read target channel is not allowed.");
|
|
173
|
+
};
|
|
174
|
+
const currentConversation = isCurrentSlackReadTarget({
|
|
175
|
+
account: params.account,
|
|
176
|
+
channelId: params.channelId,
|
|
177
|
+
context: params.context
|
|
178
|
+
});
|
|
179
|
+
const directOperator = params.conversationReadOrigin === "direct-operator";
|
|
180
|
+
if (/^D/i.test(params.channelId)) {
|
|
181
|
+
if (!resolveSlackDmReadAllowed(params.account)) deny();
|
|
182
|
+
if (directOperator || currentConversation) return;
|
|
183
|
+
const info = await slackActionRuntime.resolveSlackConversationInfo({
|
|
184
|
+
cfg: params.cfg,
|
|
185
|
+
accountId: params.account.accountId,
|
|
186
|
+
channelId: params.channelId,
|
|
187
|
+
operation: "read"
|
|
188
|
+
});
|
|
189
|
+
if (info.type !== "dm" || !await isSlackDmTargetConfigured({
|
|
108
190
|
...params,
|
|
109
|
-
|
|
110
|
-
})
|
|
191
|
+
userId: info.user
|
|
192
|
+
})) deny();
|
|
193
|
+
return;
|
|
111
194
|
}
|
|
112
|
-
|
|
195
|
+
const preliminary = resolveSlackChannelReadPolicy({
|
|
196
|
+
...params,
|
|
197
|
+
currentConversation
|
|
198
|
+
});
|
|
199
|
+
if (preliminary.channelExplicitlyDisabled) deny();
|
|
200
|
+
if (!(preliminary.shouldResolveName || preliminary.channelAllowed !== preliminary.groupDmAllowed)) {
|
|
201
|
+
if (!preliminary.channelAllowed) deny();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const info = await slackActionRuntime.resolveSlackConversationInfo({
|
|
205
|
+
cfg: params.cfg,
|
|
206
|
+
accountId: params.account.accountId,
|
|
207
|
+
channelId: params.channelId,
|
|
208
|
+
operation: "read",
|
|
209
|
+
...preliminary.shouldResolveName ? { requireFreshName: true } : {}
|
|
210
|
+
});
|
|
211
|
+
if (preliminary.shouldResolveName && (info.type === "channel" || info.type === "unknown") && !info.name) deny();
|
|
212
|
+
const resolved = resolveSlackChannelReadPolicy({
|
|
213
|
+
...params,
|
|
214
|
+
channelName: info.name,
|
|
215
|
+
metadataResolved: true,
|
|
216
|
+
currentConversation
|
|
217
|
+
});
|
|
218
|
+
if (resolved.channelExplicitlyDisabled) deny();
|
|
219
|
+
if (info.type === "dm") {
|
|
220
|
+
if (!resolveSlackDmReadAllowed(params.account) || !directOperator && !currentConversation && !await isSlackDmTargetConfigured({
|
|
221
|
+
...params,
|
|
222
|
+
userId: info.user
|
|
223
|
+
})) deny();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (!(info.type === "channel" ? resolved.channelAllowed : info.type === "group" ? resolved.groupDmAllowed : resolved.channelAllowed && resolved.groupDmAllowed)) deny();
|
|
227
|
+
}
|
|
228
|
+
function isSlackGroupDmTargetConfigured(account, channelId) {
|
|
229
|
+
const entries = account.config.dm?.groupChannels ?? [];
|
|
230
|
+
if (entries.length === 0) return true;
|
|
231
|
+
const target = channelId.trim().toLowerCase();
|
|
232
|
+
return entries.some((entry) => {
|
|
233
|
+
const candidate = String(entry).trim().toLowerCase();
|
|
234
|
+
return candidate === "*" || candidate === target || candidate === `slack:${target}` || candidate === `channel:${target}` || candidate === `group:${target}` || candidate === `mpim:${target}`;
|
|
235
|
+
});
|
|
113
236
|
}
|
|
114
237
|
async function handleSlackAction(params, cfg, context) {
|
|
115
238
|
const resolveChannelId = () => resolveSlackChannelId(readStringParam(params, "channelId", { required: true }));
|
|
@@ -120,6 +243,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
120
243
|
cfg,
|
|
121
244
|
accountId
|
|
122
245
|
});
|
|
246
|
+
if (account.config.enterpriseOrgInstall === true) throw new Error("Slack action tools are unavailable for Enterprise Grid org installs.");
|
|
123
247
|
const isActionEnabled = createActionGate(account.actions ?? cfg.channels?.slack?.actions);
|
|
124
248
|
const userToken = account.userToken;
|
|
125
249
|
const botToken = account.botToken?.trim();
|
|
@@ -144,7 +268,8 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
144
268
|
account,
|
|
145
269
|
cfg,
|
|
146
270
|
channelId,
|
|
147
|
-
|
|
271
|
+
conversationReadOrigin: context?.conversationReadOrigin,
|
|
272
|
+
context
|
|
148
273
|
});
|
|
149
274
|
if (reactionsActions.has(action)) {
|
|
150
275
|
if (!isActionEnabled("reactions")) throw new Error("Slack reactions are disabled.");
|
|
@@ -152,6 +277,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
152
277
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
153
278
|
if (action === "react") {
|
|
154
279
|
const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove a Slack reaction." });
|
|
280
|
+
await assertReadTargetAllowed(channelId);
|
|
155
281
|
if (remove) {
|
|
156
282
|
if (writeOpts) await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji, writeOpts);
|
|
157
283
|
else await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji);
|
|
@@ -186,25 +312,66 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
186
312
|
const mediaUrl = readStringParam(params, "mediaUrl");
|
|
187
313
|
const blocks = readSlackBlocksParam(params);
|
|
188
314
|
const replyBroadcast = readBooleanParam(params, "replyBroadcast");
|
|
189
|
-
|
|
315
|
+
const textIsSlackMrkdwn = readBooleanParam(params, "textIsSlackMrkdwn");
|
|
316
|
+
const textIsSlackPlainText = readBooleanParam(params, "textIsSlackPlainText");
|
|
317
|
+
const preparedMessages = context?.preparedMessages;
|
|
318
|
+
const authoredTextPlacement = readStringParam(params, "authoredTextPlacement");
|
|
319
|
+
if (authoredTextPlacement && authoredTextPlacement !== "none" && authoredTextPlacement !== "blocks" && authoredTextPlacement !== "outside-blocks") throw new Error("Slack authoredTextPlacement is invalid.");
|
|
320
|
+
const nativeDataFallbackBaseText = readStringParam(params, "nativeDataFallbackBaseText", { allowEmpty: true });
|
|
321
|
+
if (!content && !mediaUrl && !blocks && !preparedMessages?.length) throw new Error("Slack sendMessage requires content, blocks, or mediaUrl.");
|
|
190
322
|
if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
|
|
191
323
|
const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), to, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
|
|
192
|
-
const
|
|
324
|
+
const baseSendOpts = {
|
|
193
325
|
...writeOpts,
|
|
194
326
|
mediaLocalRoots: context?.mediaLocalRoots,
|
|
195
327
|
mediaReadFile: context?.mediaReadFile,
|
|
196
|
-
threadTs: threadTs ?? void 0
|
|
197
|
-
...replyBroadcast ? { replyBroadcast } : {}
|
|
328
|
+
threadTs: threadTs ?? void 0
|
|
198
329
|
};
|
|
199
|
-
const
|
|
200
|
-
|
|
330
|
+
const sendOpts = {
|
|
331
|
+
...baseSendOpts,
|
|
332
|
+
...replyBroadcast ? { replyBroadcast } : {},
|
|
333
|
+
...textIsSlackMrkdwn ? { textIsSlackMrkdwn: true } : {},
|
|
334
|
+
...textIsSlackPlainText ? { textIsSlackPlainText: true } : {},
|
|
335
|
+
...authoredTextPlacement ? { authoredTextPlacement } : {},
|
|
336
|
+
...nativeDataFallbackBaseText !== void 0 ? { nativeDataFallbackBaseText } : {}
|
|
337
|
+
};
|
|
338
|
+
const sendContentAndBlocks = async () => {
|
|
339
|
+
const shouldSplitLongContent = content && content.length > 8e3 && !hasSlackNativeDataBlock(blocks);
|
|
340
|
+
if (content && shouldSplitLongContent) {
|
|
341
|
+
const { replyBroadcast: _replyBroadcast, ...blockSendOpts } = sendOpts;
|
|
342
|
+
await slackActionRuntime.sendSlackMessage(to, "", {
|
|
343
|
+
...blockSendOpts,
|
|
344
|
+
blocks
|
|
345
|
+
});
|
|
346
|
+
return await slackActionRuntime.sendSlackMessage(to, content, sendOpts);
|
|
347
|
+
}
|
|
348
|
+
return await slackActionRuntime.sendSlackMessage(to, content ?? "", {
|
|
201
349
|
...sendOpts,
|
|
350
|
+
blocks
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
const result = preparedMessages?.length ? await (async () => {
|
|
354
|
+
let lastResult;
|
|
355
|
+
if (mediaUrl) lastResult = await slackActionRuntime.sendSlackMessage(to, "", {
|
|
356
|
+
...baseSendOpts,
|
|
202
357
|
mediaUrl
|
|
203
358
|
});
|
|
204
|
-
|
|
359
|
+
for (const [index, message] of preparedMessages.entries()) lastResult = await slackActionRuntime.sendSlackMessage(to, message.text, {
|
|
360
|
+
...baseSendOpts,
|
|
361
|
+
...index === 0 && replyBroadcast ? { replyBroadcast: true } : {},
|
|
362
|
+
...message.blocks ? { blocks: message.blocks } : {},
|
|
363
|
+
...message.authoredTextPlacement ? { authoredTextPlacement: message.authoredTextPlacement } : {},
|
|
364
|
+
...Object.hasOwn(message, "nativeDataFallbackBaseText") ? { nativeDataFallbackBaseText: message.nativeDataFallbackBaseText } : {},
|
|
365
|
+
...message.textIsSlackPlainText ? { textIsSlackPlainText: true } : {}
|
|
366
|
+
});
|
|
367
|
+
if (!lastResult) throw new Error("Slack prepared message plan produced no delivery.");
|
|
368
|
+
return lastResult;
|
|
369
|
+
})() : blocks ? await (async () => {
|
|
370
|
+
if (mediaUrl) await slackActionRuntime.sendSlackMessage(to, "", {
|
|
205
371
|
...sendOpts,
|
|
206
|
-
|
|
372
|
+
mediaUrl
|
|
207
373
|
});
|
|
374
|
+
return await sendContentAndBlocks();
|
|
208
375
|
})() : await slackActionRuntime.sendSlackMessage(to, content ?? "", {
|
|
209
376
|
...sendOpts,
|
|
210
377
|
mediaUrl: mediaUrl ?? void 0,
|
|
@@ -248,6 +415,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
248
415
|
const content = readStringParam(params, "content", { allowEmpty: true });
|
|
249
416
|
const blocks = readSlackBlocksParam(params);
|
|
250
417
|
if (!content && !blocks) throw new Error("Slack editMessage requires content or blocks.");
|
|
418
|
+
await assertReadTargetAllowed(channelId);
|
|
251
419
|
if (writeOpts) await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", {
|
|
252
420
|
...writeOpts,
|
|
253
421
|
blocks
|
|
@@ -258,6 +426,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
258
426
|
case "deleteMessage": {
|
|
259
427
|
const channelId = resolveChannelId();
|
|
260
428
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
429
|
+
await assertReadTargetAllowed(channelId);
|
|
261
430
|
if (writeOpts) await slackActionRuntime.deleteSlackMessage(channelId, messageId, writeOpts);
|
|
262
431
|
else await slackActionRuntime.deleteSlackMessage(channelId, messageId);
|
|
263
432
|
return jsonResult({ ok: true });
|
|
@@ -278,9 +447,12 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
278
447
|
threadId: threadId ?? void 0,
|
|
279
448
|
messageId: messageId ?? void 0
|
|
280
449
|
});
|
|
450
|
+
const messages = result.messages.map((message) => withNormalizedTimestamp(message, message.ts));
|
|
281
451
|
return jsonResult({
|
|
282
452
|
ok: true,
|
|
283
|
-
|
|
453
|
+
channelId,
|
|
454
|
+
...threadId ? { threadId } : {},
|
|
455
|
+
messages,
|
|
284
456
|
hasMore: result.hasMore
|
|
285
457
|
});
|
|
286
458
|
}
|
|
@@ -336,12 +508,14 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
336
508
|
const channelId = resolveChannelId();
|
|
337
509
|
if (action === "pinMessage") {
|
|
338
510
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
511
|
+
await assertReadTargetAllowed(channelId);
|
|
339
512
|
if (writeOpts) await slackActionRuntime.pinSlackMessage(channelId, messageId, writeOpts);
|
|
340
513
|
else await slackActionRuntime.pinSlackMessage(channelId, messageId);
|
|
341
514
|
return jsonResult({ ok: true });
|
|
342
515
|
}
|
|
343
516
|
if (action === "unpinMessage") {
|
|
344
517
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
518
|
+
await assertReadTargetAllowed(channelId);
|
|
345
519
|
if (writeOpts) await slackActionRuntime.unpinSlackMessage(channelId, messageId, writeOpts);
|
|
346
520
|
else await slackActionRuntime.unpinSlackMessage(channelId, messageId);
|
|
347
521
|
return jsonResult({ ok: true });
|
|
@@ -358,9 +532,14 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
358
532
|
if (action === "memberInfo") {
|
|
359
533
|
if (!isActionEnabled("memberInfo")) throw new Error("Slack member info is disabled.");
|
|
360
534
|
const userId = readStringParam(params, "userId", { required: true });
|
|
535
|
+
assertSlackMemberInfoAllowed({
|
|
536
|
+
account,
|
|
537
|
+
context,
|
|
538
|
+
userId
|
|
539
|
+
});
|
|
361
540
|
return jsonResult({
|
|
362
541
|
ok: true,
|
|
363
|
-
info:
|
|
542
|
+
info: readOpts ? await slackActionRuntime.getSlackMemberInfo(userId, readOpts) : await slackActionRuntime.getSlackMemberInfo(userId)
|
|
364
543
|
});
|
|
365
544
|
}
|
|
366
545
|
if (action === "emojiList") {
|