@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,15 +1,15 @@
|
|
|
1
1
|
import { n as registerSlackHttpHandler, r as normalizeSlackWebhookPath } from "./registry-bbjH7IHX.js";
|
|
2
2
|
import { a as resolveSlackAccount, d as resolveSlackAppToken, f as resolveSlackBotToken, i as resolveDefaultSlackAccountId, o as resolveSlackAccountAllowFrom, s as resolveSlackAccountDmPolicy, u as formatSlackBotTokenIdentityWarning } from "./accounts-Dm_H77gH.js";
|
|
3
|
-
import { a as parseSlackTarget, n as formatSlackTarget } from "./target-parsing-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { a as parseSlackTarget, n as formatSlackTarget } from "./target-parsing-PbxGDbr9.js";
|
|
4
|
+
import { Ct as isSlackApprovalAuthorizedSender, G as isSlackCallbackActionId, J as decodeSlackQuestionAction, K as isSlackQuestionActionId, L as truncateSlackText, M as SLACK_TEXT_LIMIT, Tt as isSlackExecApprovalAuthorizedSender, W as isSlackApprovalActionId, Y as resolveSlackQuestionAction, a as qualifySlackConversationId, et as escapeSlackMrkdwn, lt as isSlackAnyNativeApprovalClientEnabled, nt as decodeSlackApprovalAction, o as qualifySlackRoutePeerId, s as resolveSlackEnterpriseMainDmSessionKey, t as buildSlackChannelIdCandidates, xt as registerSlackInstallationState } from "./group-policy-BKjMqT-8.js";
|
|
5
|
+
import { C as normalizeAllowListLower, D as resolveSlackUserAllowListForTeam, E as resolveSlackAllowListMatch, S as normalizeAllowList, T as normalizeSlackSlug, _ as resolveSlackLookupClientOptions, a as slackIngressIdentity, d as createSlackWebClient, i as createSlackIngressSubject, l as createSlackStartupAuthClient, o as formatSlackError, p as getSlackListenerUploadCompletionClient, v as resolveSlackProxyDispatcher, w as normalizeSlackAllowOwnerEntry, x as allowListMatches, y as resolveSlackWebClientOptions } from "./probe-gj5yQgN2.js";
|
|
6
6
|
import { n as getSlackRuntime, t as getOptionalSlackRuntime } from "./runtime-JSVZSWAj.js";
|
|
7
|
-
import {
|
|
8
|
-
import { i as setSlackDefaultSendIdentity, p as requireSlackPostMessageTimestamp } from "./send-
|
|
9
|
-
import { t as collectSlackCursorPages } from "./cursor-pages-
|
|
10
|
-
import { t as resolveSlackChannelAllowlist } from "./resolve-channels-
|
|
11
|
-
import { t as resolveSlackUserAllowlist } from "./resolve-users-
|
|
12
|
-
import { n as resolveSlackChannelConfig, r as resolveSlackChannelLabel, t as isSlackChannelAllowedByPolicy } from "./policy-
|
|
7
|
+
import { C as hasSlackMessageTableBlock, b as saveRemoteMedia, f as readSlackMessages, y as isGovSlackClient } from "./actions-fh66A6lc.js";
|
|
8
|
+
import { i as setSlackDefaultSendIdentity, p as requireSlackPostMessageTimestamp } from "./send-Djswy6lf.js";
|
|
9
|
+
import { t as collectSlackCursorPages } from "./cursor-pages-ByFwo-Py.js";
|
|
10
|
+
import { t as resolveSlackChannelAllowlist } from "./resolve-channels-CU7Bg5Ka.js";
|
|
11
|
+
import { t as resolveSlackUserAllowlist } from "./resolve-users-DrhttvRQ.js";
|
|
12
|
+
import { n as resolveSlackChannelConfig, r as resolveSlackChannelLabel, t as isSlackChannelAllowedByPolicy } from "./policy-D7PKkiet.js";
|
|
13
13
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
14
14
|
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
15
15
|
import { asNonArrayRecord, asOptionalRecord, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeUniqueTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
@@ -20,12 +20,13 @@ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
|
20
20
|
import { computeBackoff, createNonExitingRuntime, createSubsystemLogger, danger, getChildLogger, logVerbose, shouldLogVerbose, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
21
21
|
import { chunkItems } from "openclaw/plugin-sdk/text-chunking";
|
|
22
22
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
23
|
+
import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, formatAllowlistMatchMeta, mergeAllowlist, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
23
24
|
import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
|
|
24
25
|
import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
25
26
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
26
27
|
import { WebAPIHTTPError, WebAPIPlatformError, WebAPIRateLimitedError, WebAPIRequestError, WebClient } from "@slack/web-api";
|
|
27
|
-
import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, formatAllowlistMatchMeta, mergeAllowlist, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
28
28
|
import { buildPluginBindingResolvedText, parsePluginBindingApprovalCustomId, resolveConversationLabel as resolveConversationLabel$1, resolvePluginConversationBindingApproval, resolveRuntimeConversationBindingRoute, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
|
|
29
|
+
import { createChannelIngressResolver, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
29
30
|
import { collectErrorGraphCandidates, extractErrorCode, formatErrorMessage, isApprovalNotFoundError, readErrorName, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
30
31
|
import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
31
32
|
import { buildChannelMetadata } from "openclaw/plugin-sdk/security-runtime";
|
|
@@ -44,12 +45,12 @@ import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy as res
|
|
|
44
45
|
import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-writes";
|
|
45
46
|
import { mutateConfigFile, readConfigFileSnapshotForWrite } from "openclaw/plugin-sdk/config-mutation";
|
|
46
47
|
import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
47
|
-
import { createChannelIngressResolver, defineStableChannelIngressIdentity, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
48
48
|
import { asDateTimestampMs, parseFiniteNumber, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
49
49
|
import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
|
|
50
50
|
import { formatCommandArgMenuTitle, resolveCommandAuthorization, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride } from "openclaw/plugin-sdk/command-auth-native";
|
|
51
51
|
import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
|
|
52
52
|
import { createChannelInteractiveDispatcher } from "openclaw/plugin-sdk/plugin-runtime";
|
|
53
|
+
import { reportChannelRoomJoin } from "openclaw/plugin-sdk/channel-join-intro-runtime";
|
|
53
54
|
import { createChannelInboundDebouncer, shouldDebounceTextInbound } from "openclaw/plugin-sdk/channel-inbound";
|
|
54
55
|
import { createChannelReplayGuard, runClaimableDedupeClaimLoop } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
55
56
|
import { channelBlockedPatch, channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
@@ -160,10 +161,7 @@ function createSlackAgentViewState(params) {
|
|
|
160
161
|
if (enabled) return true;
|
|
161
162
|
if (loaded) return false;
|
|
162
163
|
const stateKey = workspaceStateKey();
|
|
163
|
-
if (!stateKey)
|
|
164
|
-
loaded = true;
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
164
|
+
if (!stateKey) return false;
|
|
167
165
|
const openedStore = openWorkspaceStore();
|
|
168
166
|
if (!openedStore) return false;
|
|
169
167
|
try {
|
|
@@ -236,8 +234,8 @@ function createSlackAgentViewState(params) {
|
|
|
236
234
|
//#endregion
|
|
237
235
|
//#region extensions/slack/src/monitor/assistant-thread-context.ts
|
|
238
236
|
const SLACK_ASSISTANT_THREAD_CONTEXT_METADATA_EVENT = "assistant_thread_context";
|
|
239
|
-
const SLACK_ASSISTANT_CONTEXT_TTL_MS =
|
|
240
|
-
const SLACK_ASSISTANT_CONTEXT_CLEANUP_INTERVAL_MS =
|
|
237
|
+
const SLACK_ASSISTANT_CONTEXT_TTL_MS = 864e5;
|
|
238
|
+
const SLACK_ASSISTANT_CONTEXT_CLEANUP_INTERVAL_MS = 6e5;
|
|
241
239
|
function buildSlackAssistantThreadMetadata(context) {
|
|
242
240
|
const eventPayload = {};
|
|
243
241
|
if (context.channelId) eventPayload.channel_id = context.channelId;
|
|
@@ -356,11 +354,14 @@ const DEFAULT_SLACK_SUGGESTED_PROMPTS = [
|
|
|
356
354
|
}
|
|
357
355
|
];
|
|
358
356
|
async function updateSlackSuggestedPrompts(params) {
|
|
359
|
-
const prompts = params.prompts.map((
|
|
360
|
-
title:
|
|
361
|
-
message:
|
|
357
|
+
const prompts = params.prompts.map(({ title, message }) => ({
|
|
358
|
+
title: title.trim(),
|
|
359
|
+
message: message.trim()
|
|
362
360
|
})).filter((prompt) => prompt.title && prompt.message).slice(0, 4);
|
|
363
|
-
if (prompts.length === 0)
|
|
361
|
+
if (prompts.length === 0) {
|
|
362
|
+
logVerbose(`slack suggested prompts update failed for channel ${params.channelId}: failed (no prompts)`);
|
|
363
|
+
return "failed";
|
|
364
|
+
}
|
|
364
365
|
try {
|
|
365
366
|
await params.client.assistant.threads.setSuggestedPrompts({
|
|
366
367
|
token: params.botToken,
|
|
@@ -369,10 +370,12 @@ async function updateSlackSuggestedPrompts(params) {
|
|
|
369
370
|
...params.title?.trim() ? { title: params.title.trim() } : {},
|
|
370
371
|
prompts
|
|
371
372
|
});
|
|
372
|
-
return
|
|
373
|
+
return "accepted";
|
|
373
374
|
} catch (error) {
|
|
374
|
-
|
|
375
|
-
|
|
375
|
+
const code = error instanceof WebAPIPlatformError ? error.data.error : void 0;
|
|
376
|
+
const outcome = code === "not_agent_app" || code === "missing_scope" ? "rejected" : code === "internal_error" ? "internal_error" : "failed";
|
|
377
|
+
logVerbose(`slack suggested prompts update failed for channel ${params.channelId}: ${outcome}: ${formatSlackError(error)}`);
|
|
378
|
+
return outcome;
|
|
376
379
|
}
|
|
377
380
|
}
|
|
378
381
|
//#endregion
|
|
@@ -476,12 +479,12 @@ function resolveSlackSystemEventRoute(params) {
|
|
|
476
479
|
const SLACK_CHANNEL_CACHE_MAX_ENTRIES = 1024;
|
|
477
480
|
const SLACK_USER_CACHE_MAX_ENTRIES = 2048;
|
|
478
481
|
const SLACK_AVATAR_CACHE_MAX_ENTRIES = 128;
|
|
479
|
-
const SLACK_AVATAR_MAX_BYTES =
|
|
482
|
+
const SLACK_AVATAR_MAX_BYTES = 262144;
|
|
480
483
|
const SLACK_AVATAR_SSRF_POLICY = {
|
|
481
484
|
allowedHostnames: ["avatars.slack-edge.com", "*.slack-edge.com"],
|
|
482
485
|
hostnameAllowlist: ["avatars.slack-edge.com", "*.slack-edge.com"]
|
|
483
486
|
};
|
|
484
|
-
const SLACK_CHANNEL_DENIAL_WARNING_TTL_MS =
|
|
487
|
+
const SLACK_CHANNEL_DENIAL_WARNING_TTL_MS = 3e5;
|
|
485
488
|
const SLACK_CHANNEL_DENIAL_WARNING_MAX_ENTRIES = 1024;
|
|
486
489
|
function createSlackMonitorContext(params) {
|
|
487
490
|
const channelHistories = /* @__PURE__ */ new Map();
|
|
@@ -586,7 +589,8 @@ function createSlackMonitorContext(params) {
|
|
|
586
589
|
}
|
|
587
590
|
};
|
|
588
591
|
const resolveUserAvatar = (userId, eventScope) => {
|
|
589
|
-
|
|
592
|
+
const client = eventScope?.client ?? params.app.client;
|
|
593
|
+
if (isGovSlackClient(client)) return;
|
|
590
594
|
const imageUrl = readLruMapEntry(userCache, scopedKey(userId, eventScope))?.imageUrl;
|
|
591
595
|
if (!imageUrl) return;
|
|
592
596
|
const cacheKey = scopedKey(`${userId}\0${imageUrl}`, eventScope);
|
|
@@ -888,9 +892,9 @@ function resolveSlackInstallationIdentity(params) {
|
|
|
888
892
|
const isEnterpriseInstall = auth.is_enterprise_install === true;
|
|
889
893
|
const apiAppId = normalizeOptionalString(auth.app_id);
|
|
890
894
|
const enterpriseId = normalizeOptionalString(auth.enterprise_id);
|
|
895
|
+
const transportApiAppId = normalizeOptionalString(params.transportApiAppId);
|
|
891
896
|
if (isEnterpriseInstall) {
|
|
892
897
|
if (!enterpriseId) throw new Error("Slack org-wide auth.test returned no enterprise_id");
|
|
893
|
-
const transportApiAppId = normalizeOptionalString(params.transportApiAppId);
|
|
894
898
|
if (apiAppId && transportApiAppId && apiAppId !== transportApiAppId) throw new Error(`Slack token mismatch: bot token app_id=${apiAppId} but transport app_id=${transportApiAppId}`);
|
|
895
899
|
const effectiveApiAppId = apiAppId ?? transportApiAppId;
|
|
896
900
|
return {
|
|
@@ -902,11 +906,12 @@ function resolveSlackInstallationIdentity(params) {
|
|
|
902
906
|
const teamId = normalizeOptionalString(auth.team_id);
|
|
903
907
|
if (!teamId) throw new Error("Slack workspace auth.test returned no team_id");
|
|
904
908
|
const teamName = normalizeOptionalString(auth.team);
|
|
909
|
+
const workspaceApiAppId = apiAppId ?? transportApiAppId;
|
|
905
910
|
return {
|
|
906
911
|
kind: "workspace",
|
|
907
912
|
teamId,
|
|
908
913
|
...teamName ? { teamName } : {},
|
|
909
|
-
...
|
|
914
|
+
...workspaceApiAppId ? { apiAppId: workspaceApiAppId } : {},
|
|
910
915
|
...enterpriseId ? { enterpriseId } : {}
|
|
911
916
|
};
|
|
912
917
|
}
|
|
@@ -1388,7 +1393,8 @@ function createSlackDurableIngress(options) {
|
|
|
1388
1393
|
}
|
|
1389
1394
|
};
|
|
1390
1395
|
try {
|
|
1391
|
-
|
|
1396
|
+
const event = raw.kind === "events-api" ? asOptionalRecord(raw.body)?.event : void 0;
|
|
1397
|
+
if (asOptionalRecord(event)?.type === "channel_id_changed") {
|
|
1392
1398
|
const channelTurns = activeChannelTurns.get(laneKey);
|
|
1393
1399
|
if (channelTurns && channelTurns.size > 0) {
|
|
1394
1400
|
adoptOnCompletion = true;
|
|
@@ -1500,7 +1506,8 @@ async function resolveThreadTsFromHistory(params) {
|
|
|
1500
1506
|
inclusive: true,
|
|
1501
1507
|
limit: 1
|
|
1502
1508
|
});
|
|
1503
|
-
|
|
1509
|
+
const message = response.messages?.find((entry) => entry.ts === params.messageTs) ?? response.messages?.[0];
|
|
1510
|
+
return normalizeOptionalString(message?.thread_ts);
|
|
1504
1511
|
}
|
|
1505
1512
|
function createSlackThreadTsResolver(params) {
|
|
1506
1513
|
const ttlMs = Math.max(0, parseFiniteNumber(params.cacheTtlMs) ?? DEFAULT_THREAD_TS_CACHE_TTL_MS);
|
|
@@ -1586,88 +1593,7 @@ const slackChannelMembersCache = /* @__PURE__ */ new WeakMap();
|
|
|
1586
1593
|
const DEFAULT_CHANNEL_MEMBERS_CACHE_TTL_MS = 6e4;
|
|
1587
1594
|
const CHANNEL_MEMBERS_CACHE_MAX = 512;
|
|
1588
1595
|
const SLACK_CHANNEL_ID = "slack";
|
|
1589
|
-
const SLACK_USER_NAME_KIND = "plugin:slack-user-name";
|
|
1590
|
-
const SLACK_WORKSPACE_USER_ID_KIND = "plugin:slack-workspace-user-id";
|
|
1591
1596
|
var SlackSystemEventAuthRetryError = class extends Error {};
|
|
1592
|
-
function normalizeSlackUserId(raw) {
|
|
1593
|
-
const value = (raw ?? "").trim().toLowerCase();
|
|
1594
|
-
if (!value) return "";
|
|
1595
|
-
const mention = value.match(/^<@([a-z0-9_]+)>$/i);
|
|
1596
|
-
if (mention?.[1]) return mention[1];
|
|
1597
|
-
return value.replace(/^(slack:|user:)/, "");
|
|
1598
|
-
}
|
|
1599
|
-
function isSlackStableUserId(value) {
|
|
1600
|
-
return /^[ubw][a-z0-9_]+$/i.test(value);
|
|
1601
|
-
}
|
|
1602
|
-
function normalizeSlackWorkspaceUserEntry(entry) {
|
|
1603
|
-
const normalized = entry.trim().toLowerCase();
|
|
1604
|
-
if (!normalized) return null;
|
|
1605
|
-
try {
|
|
1606
|
-
const target = parseSlackTarget(normalized);
|
|
1607
|
-
if (target?.kind === "user" && target.teamId) return target.normalized;
|
|
1608
|
-
} catch {
|
|
1609
|
-
return null;
|
|
1610
|
-
}
|
|
1611
|
-
return null;
|
|
1612
|
-
}
|
|
1613
|
-
function normalizeSlackBareUserEntry(entry) {
|
|
1614
|
-
const normalized = entry.trim().toLowerCase();
|
|
1615
|
-
if (!normalized || normalizeSlackWorkspaceUserEntry(normalized)) return null;
|
|
1616
|
-
const userId = normalizeSlackUserId(normalized);
|
|
1617
|
-
return isSlackStableUserId(userId) ? userId : null;
|
|
1618
|
-
}
|
|
1619
|
-
function normalizeSlackStableEntry(entry) {
|
|
1620
|
-
return normalizeSlackBareUserEntry(entry) ?? normalizeSlackWorkspaceUserEntry(entry);
|
|
1621
|
-
}
|
|
1622
|
-
function normalizeSlackNameEntry(entry) {
|
|
1623
|
-
const normalized = entry.trim().toLowerCase();
|
|
1624
|
-
if (!normalized || normalizeSlackStableEntry(normalized)) return null;
|
|
1625
|
-
return normalized.replace(/^slack:/, "") || null;
|
|
1626
|
-
}
|
|
1627
|
-
function normalizeSlackNameSubject(value) {
|
|
1628
|
-
return value.trim().toLowerCase() || null;
|
|
1629
|
-
}
|
|
1630
|
-
function normalizeSlackNameSlugEntry(entry) {
|
|
1631
|
-
const name = normalizeSlackNameEntry(entry);
|
|
1632
|
-
if (!name) return null;
|
|
1633
|
-
const slug = normalizeSlackSlug(name);
|
|
1634
|
-
return slug && slug !== name ? slug : null;
|
|
1635
|
-
}
|
|
1636
|
-
const slackIngressIdentity = defineStableChannelIngressIdentity({
|
|
1637
|
-
key: "senderId",
|
|
1638
|
-
kind: "stable-id",
|
|
1639
|
-
normalizeEntry: normalizeSlackBareUserEntry,
|
|
1640
|
-
normalizeSubject: normalizeSlackUserId,
|
|
1641
|
-
sensitivity: "pii",
|
|
1642
|
-
aliases: [{
|
|
1643
|
-
key: "workspaceSenderId",
|
|
1644
|
-
kind: SLACK_WORKSPACE_USER_ID_KIND,
|
|
1645
|
-
normalizeEntry: normalizeSlackWorkspaceUserEntry,
|
|
1646
|
-
normalizeSubject: normalizeSlackWorkspaceUserEntry,
|
|
1647
|
-
sensitivity: "pii"
|
|
1648
|
-
}, ...[["senderName", normalizeSlackNameEntry], ["senderNameSlug", normalizeSlackNameSlugEntry]].map(([key, normalizeEntry]) => ({
|
|
1649
|
-
key,
|
|
1650
|
-
kind: SLACK_USER_NAME_KIND,
|
|
1651
|
-
normalizeEntry,
|
|
1652
|
-
normalizeSubject: normalizeSlackNameSubject,
|
|
1653
|
-
dangerous: true,
|
|
1654
|
-
sensitivity: "pii"
|
|
1655
|
-
}))]
|
|
1656
|
-
});
|
|
1657
|
-
function createSlackIngressSubject(params) {
|
|
1658
|
-
const senderId = normalizeSlackUserId(params.senderId);
|
|
1659
|
-
const teamId = normalizeOptionalLowercaseString(params.teamId);
|
|
1660
|
-
const senderName = params.senderName?.trim().toLowerCase();
|
|
1661
|
-
const senderNameSlug = senderName ? normalizeSlackSlug(senderName) : void 0;
|
|
1662
|
-
return {
|
|
1663
|
-
stableId: senderId,
|
|
1664
|
-
aliases: {
|
|
1665
|
-
workspaceSenderId: teamId && senderId ? `team:${teamId}:user:${senderId}` : void 0,
|
|
1666
|
-
senderName,
|
|
1667
|
-
senderNameSlug
|
|
1668
|
-
}
|
|
1669
|
-
};
|
|
1670
|
-
}
|
|
1671
1597
|
function createSlackIngressResolver(ctx) {
|
|
1672
1598
|
return createChannelIngressResolver({
|
|
1673
1599
|
channelId: SLACK_CHANNEL_ID,
|
|
@@ -1909,7 +1835,7 @@ async function decideSlackSystemIngress(params) {
|
|
|
1909
1835
|
} : void 0
|
|
1910
1836
|
};
|
|
1911
1837
|
const result = await resolver.message(input);
|
|
1912
|
-
if (result.ingress.decision !== "allow" && params.retryNameLookup && result.state.allowlists[isDirectMessage ? "dm" : "group"].normalizedEntries.some((entry) => entry.kind ===
|
|
1838
|
+
if (result.ingress.decision !== "allow" && params.retryNameLookup && result.state.allowlists[isDirectMessage ? "dm" : "group"].normalizedEntries.some((entry) => entry.kind === "plugin:slack-user-name")) {
|
|
1913
1839
|
const lookup = await params.ctx.resolveUserName(params.senderId, params.eventScope);
|
|
1914
1840
|
if (lookup.error && isTransientSlackThreadLookupError(lookup.error)) throw new SlackSystemEventAuthRetryError(formatErrorMessage(lookup.error));
|
|
1915
1841
|
if (lookup.name) return (await resolver.message({
|
|
@@ -2037,7 +1963,8 @@ function resolveSlackEventScope(params) {
|
|
|
2037
1963
|
ok: false,
|
|
2038
1964
|
reason: "enterprise_event_for_workspace_account"
|
|
2039
1965
|
} : { ok: true };
|
|
2040
|
-
const
|
|
1966
|
+
const body = params.body && typeof params.body === "object" ? params.body : {};
|
|
1967
|
+
const apiAppId = normalizeOptionalString(body.api_app_id);
|
|
2041
1968
|
if (apiAppId && params.identity.apiAppId && apiAppId !== params.identity.apiAppId) return {
|
|
2042
1969
|
ok: false,
|
|
2043
1970
|
reason: "wrong_app"
|
|
@@ -2200,9 +2127,10 @@ function registerSlackChannelIdChangedEvent(params) {
|
|
|
2200
2127
|
const oldChannelId = payload.old_channel_id;
|
|
2201
2128
|
const newChannelId = payload.new_channel_id;
|
|
2202
2129
|
if (!oldChannelId || !newChannelId) return;
|
|
2130
|
+
const channelInfo = await ctx.resolveChannelName(newChannelId);
|
|
2203
2131
|
const label = resolveSlackChannelLabel({
|
|
2204
2132
|
channelId: newChannelId,
|
|
2205
|
-
channelName:
|
|
2133
|
+
channelName: channelInfo?.name
|
|
2206
2134
|
});
|
|
2207
2135
|
ctx.runtime.log?.(warn(`[slack] Channel ID changed: ${oldChannelId} → ${newChannelId} (${label})`));
|
|
2208
2136
|
if (!resolveChannelConfigWrites({
|
|
@@ -2287,11 +2215,12 @@ function registerSlackHomeEvents(params) {
|
|
|
2287
2215
|
if (!payload.user) return;
|
|
2288
2216
|
if (payload.tab === "messages") {
|
|
2289
2217
|
if (!payload.channel) return;
|
|
2290
|
-
|
|
2218
|
+
const outcome = await ctx.setSlackSuggestedPrompts({
|
|
2291
2219
|
channelId: payload.channel,
|
|
2292
2220
|
title: "Try asking",
|
|
2293
2221
|
prompts: DEFAULT_SLACK_SUGGESTED_PROMPTS
|
|
2294
|
-
})
|
|
2222
|
+
});
|
|
2223
|
+
if (outcome === "accepted" || outcome === "internal_error") await ctx.recordSlackAgentView();
|
|
2295
2224
|
return;
|
|
2296
2225
|
}
|
|
2297
2226
|
await ctx.app.client.views.publish({
|
|
@@ -2455,7 +2384,8 @@ function isSlackReplyActionId(actionId) {
|
|
|
2455
2384
|
return actionId === "openclaw:reply_button" || actionId === "openclaw:reply_select" || actionId.startsWith(`openclaw:reply_button:`) || actionId.startsWith(`openclaw:reply_select:`);
|
|
2456
2385
|
}
|
|
2457
2386
|
function readSlackApprovalAction(parsed) {
|
|
2458
|
-
|
|
2387
|
+
const value = normalizeOptionalString(parsed.actionSummary.value) ?? parsed.actionSummary.selectedValues?.map((entry) => normalizeOptionalString(entry)).find((entry) => Boolean(entry));
|
|
2388
|
+
return decodeSlackApprovalAction(value);
|
|
2459
2389
|
}
|
|
2460
2390
|
function isSlackReplyLinkAction(parsed) {
|
|
2461
2391
|
if (parsed.actionId === "openclaw:session_link") return true;
|
|
@@ -2580,11 +2510,19 @@ async function handleSlackPluginBindingApproval(params) {
|
|
|
2580
2510
|
await respondEphemeral(params.respond, buildPluginBindingResolvedText(resolved));
|
|
2581
2511
|
return true;
|
|
2582
2512
|
}
|
|
2513
|
+
function formatSlackPluginApprovalSenderId(userId, eventScope) {
|
|
2514
|
+
return formatSlackTarget({
|
|
2515
|
+
kind: "user",
|
|
2516
|
+
id: userId,
|
|
2517
|
+
teamId: eventScope?.teamId
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2583
2520
|
async function handleSlackApprovalInteraction(params) {
|
|
2521
|
+
const pluginSenderId = formatSlackPluginApprovalSenderId(params.parsed.userId, params.eventScope);
|
|
2584
2522
|
const pluginApprovalAuthorizedSender = isSlackApprovalAuthorizedSender({
|
|
2585
2523
|
cfg: params.ctx.cfg,
|
|
2586
2524
|
accountId: params.ctx.accountId,
|
|
2587
|
-
senderId:
|
|
2525
|
+
senderId: pluginSenderId
|
|
2588
2526
|
});
|
|
2589
2527
|
const execApprovalAuthorizedSender = isSlackExecApprovalAuthorizedSender({
|
|
2590
2528
|
cfg: params.ctx.cfg,
|
|
@@ -2604,7 +2542,7 @@ async function handleSlackApprovalInteraction(params) {
|
|
|
2604
2542
|
decision: params.approval.decision,
|
|
2605
2543
|
channel: "slack",
|
|
2606
2544
|
accountId: params.ctx.accountId,
|
|
2607
|
-
senderId: params.parsed.userId
|
|
2545
|
+
senderId: params.approval.approvalKind === "plugin" ? pluginSenderId : params.parsed.userId
|
|
2608
2546
|
});
|
|
2609
2547
|
const terminalLabel = resolveSlackApprovalTerminalLabel(result.approval);
|
|
2610
2548
|
const prefix = result.applied ? "Resolved" : "Already resolved";
|
|
@@ -2640,10 +2578,11 @@ async function handleSlackApprovalInteraction(params) {
|
|
|
2640
2578
|
async function handleSlackLegacyApprovalInteraction(params) {
|
|
2641
2579
|
const parsedApproval = parseExecApprovalCommandText(params.pluginInteractionData);
|
|
2642
2580
|
if (!parsedApproval) return false;
|
|
2581
|
+
const pluginSenderId = formatSlackPluginApprovalSenderId(params.parsed.userId, params.eventScope);
|
|
2643
2582
|
const pluginAuthorized = isSlackApprovalAuthorizedSender({
|
|
2644
2583
|
cfg: params.ctx.cfg,
|
|
2645
2584
|
accountId: params.ctx.accountId,
|
|
2646
|
-
senderId:
|
|
2585
|
+
senderId: pluginSenderId
|
|
2647
2586
|
});
|
|
2648
2587
|
const execAuthorized = isSlackExecApprovalAuthorizedSender({
|
|
2649
2588
|
cfg: params.ctx.cfg,
|
|
@@ -2665,7 +2604,7 @@ async function handleSlackLegacyApprovalInteraction(params) {
|
|
|
2665
2604
|
decision: parsedApproval.decision,
|
|
2666
2605
|
channel: "slack",
|
|
2667
2606
|
accountId: params.ctx.accountId,
|
|
2668
|
-
senderId: params.parsed.userId,
|
|
2607
|
+
senderId: resolveMethod === "plugin" ? pluginSenderId : params.parsed.userId,
|
|
2669
2608
|
resolveMethod
|
|
2670
2609
|
});
|
|
2671
2610
|
try {
|
|
@@ -3651,6 +3590,55 @@ function registerSlackMemberEvents(params) {
|
|
|
3651
3590
|
const channelId = payload.channel;
|
|
3652
3591
|
const channelInfo = channelId ? await ctx.resolveChannelName(channelId, eventScope) : {};
|
|
3653
3592
|
const channelType = payload.channel_type ?? channelInfo?.type;
|
|
3593
|
+
if (paramsLocal.verb === "joined" && payload.user === ctx.botUserId && channelId) {
|
|
3594
|
+
const roomType = normalizeSlackChannelType(channelType, channelId);
|
|
3595
|
+
if (roomType === "channel" || roomType === "group") {
|
|
3596
|
+
const roomAllowed = ctx.isChannelAllowed({
|
|
3597
|
+
teamId: eventScope?.teamId ?? ctx.teamId,
|
|
3598
|
+
channelId,
|
|
3599
|
+
channelName: channelInfo.name,
|
|
3600
|
+
channelType: roomType
|
|
3601
|
+
});
|
|
3602
|
+
const inviterLabel = roomAllowed && payload.inviter ? (await ctx.resolveUserName(payload.inviter, eventScope)).name ?? payload.inviter : void 0;
|
|
3603
|
+
await reportChannelRoomJoin({
|
|
3604
|
+
cfg: ctx.cfg,
|
|
3605
|
+
channel: "slack",
|
|
3606
|
+
accountId: ctx.accountId,
|
|
3607
|
+
conversationId: channelId,
|
|
3608
|
+
deliverTo: `channel:${channelId}`,
|
|
3609
|
+
route: ctx.resolveSlackSystemEventRoute({
|
|
3610
|
+
channelId,
|
|
3611
|
+
channelType: roomType,
|
|
3612
|
+
eventScope
|
|
3613
|
+
}),
|
|
3614
|
+
inviterLabel,
|
|
3615
|
+
roomAllowed,
|
|
3616
|
+
resolveRoomContext: async ({ messageLimit }) => {
|
|
3617
|
+
const purpose = [channelInfo.purpose, channelInfo.topic].filter((value) => Boolean(value?.trim())).join("\n");
|
|
3618
|
+
const roomContext = {
|
|
3619
|
+
title: channelInfo.name ? `#${channelInfo.name}` : void 0,
|
|
3620
|
+
purpose: purpose || void 0
|
|
3621
|
+
};
|
|
3622
|
+
try {
|
|
3623
|
+
const { messages } = await readSlackMessages(channelId, {
|
|
3624
|
+
limit: messageLimit,
|
|
3625
|
+
client: eventScope?.client ?? ctx.app.client
|
|
3626
|
+
});
|
|
3627
|
+
return {
|
|
3628
|
+
...roomContext,
|
|
3629
|
+
recentMessages: messages.toReversed().flatMap(({ user, text }) => text?.trim() ? [{
|
|
3630
|
+
sender: user,
|
|
3631
|
+
text
|
|
3632
|
+
}] : [])
|
|
3633
|
+
};
|
|
3634
|
+
} catch {
|
|
3635
|
+
return roomContext;
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
});
|
|
3639
|
+
return;
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3654
3642
|
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
|
3655
3643
|
ctx,
|
|
3656
3644
|
senderId: payload.user,
|
|
@@ -3660,7 +3648,8 @@ function registerSlackMemberEvents(params) {
|
|
|
3660
3648
|
eventScope
|
|
3661
3649
|
});
|
|
3662
3650
|
if (!ingressContext) return;
|
|
3663
|
-
|
|
3651
|
+
const userLabel = (payload.user ? await ctx.resolveUserName(payload.user, eventScope) : {})?.name ?? payload.user ?? "someone";
|
|
3652
|
+
enqueueRoutedSystemEvent(`Slack: ${userLabel} ${paramsLocal.verb} ${ingressContext.channelLabel}.`, ingressContext.route, { contextKey: `slack:member:${eventScope ? `${eventScope.teamId}:` : ""}${paramsLocal.verb}:${channelId ?? "unknown"}:${payload.user ?? "unknown"}:${paramsLocal.eventId}` });
|
|
3664
3653
|
} catch (err) {
|
|
3665
3654
|
ctx.runtime.error?.(danger(`slack ${paramsLocal.verb} handler failed: ${formatErrorMessage(err)}`));
|
|
3666
3655
|
if (err instanceof SlackSystemEventAuthRetryError) throw err;
|
|
@@ -3850,7 +3839,8 @@ function addUserCandidate(candidates, value, botUserId) {
|
|
|
3850
3839
|
candidates.add(id);
|
|
3851
3840
|
}
|
|
3852
3841
|
function collectMetadataUserCandidates(candidates, value, botUserId) {
|
|
3853
|
-
const
|
|
3842
|
+
const metadata = asOptionalRecord(value);
|
|
3843
|
+
const payload = asOptionalRecord(metadata?.event_payload);
|
|
3854
3844
|
if (!payload) return;
|
|
3855
3845
|
for (const key of [
|
|
3856
3846
|
"user",
|
|
@@ -4150,7 +4140,8 @@ function registerSlackReactionEvents(params) {
|
|
|
4150
4140
|
const emojiLabel = event.reaction ?? "emoji";
|
|
4151
4141
|
const authorLabel = authorInfo?.name ?? event.item_user;
|
|
4152
4142
|
const baseText = `Slack reaction ${action}: :${emojiLabel}: by ${actorLabel} in ${ingressContext.channelLabel} msg ${item.ts}`;
|
|
4153
|
-
|
|
4143
|
+
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
|
4144
|
+
enqueueRoutedSystemEvent(text, ingressContext.route, { contextKey: `slack:reaction:${eventScope ? `${eventScope.teamId}:` : ""}${action}:${item.channel}:${item.ts}:${event.user}:${emojiLabel}:${eventId}` });
|
|
4154
4145
|
} catch (err) {
|
|
4155
4146
|
ctx.runtime.error?.(danger(`slack reaction handler failed: ${formatErrorMessage(err)}`));
|
|
4156
4147
|
}
|
|
@@ -4229,7 +4220,7 @@ function registerSlackWorkspaceEvents(params) {
|
|
|
4229
4220
|
}
|
|
4230
4221
|
//#endregion
|
|
4231
4222
|
//#region extensions/slack/src/monitor/message-dispatch-dedupe.ts
|
|
4232
|
-
const SLACK_MESSAGE_DISPATCH_DEDUPE_TTL_MS =
|
|
4223
|
+
const SLACK_MESSAGE_DISPATCH_DEDUPE_TTL_MS = 864e5;
|
|
4233
4224
|
const SLACK_MESSAGE_DISPATCH_DEDUPE_MEMORY_MAX_ENTRIES = 2e4;
|
|
4234
4225
|
const SLACK_MESSAGE_DISPATCH_DEDUPE_STATE_MAX_ENTRIES = 2e4;
|
|
4235
4226
|
const SLACK_MESSAGE_DISPATCH_DEDUPE_NAMESPACE = "global";
|
|
@@ -4296,7 +4287,7 @@ function buildSlackDebounceKey(message, accountId, teamId) {
|
|
|
4296
4287
|
}
|
|
4297
4288
|
//#endregion
|
|
4298
4289
|
//#region extensions/slack/src/monitor/message-handler.ts
|
|
4299
|
-
const loadSlackMessagePipeline = createLazyRuntimeModule(() => import("./pipeline.runtime-
|
|
4290
|
+
const loadSlackMessagePipeline = createLazyRuntimeModule(() => import("./pipeline.runtime-BklS_NEj.js"));
|
|
4300
4291
|
const RETRYABLE_FLUSH_MAX_ATTEMPTS = 3;
|
|
4301
4292
|
const RETRYABLE_FLUSH_RETRY_DELAY_MS = 1e3;
|
|
4302
4293
|
const REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE = /reply session initialization conflicted for \S+/u;
|
|
@@ -4304,8 +4295,9 @@ function isRetryableSlackInboundError(error) {
|
|
|
4304
4295
|
return collectErrorGraphCandidates(error, (current) => [current.cause, current.error]).some((candidate) => REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE.test(formatErrorMessage(candidate)));
|
|
4305
4296
|
}
|
|
4306
4297
|
function shouldDebounceSlackMessage(message, cfg) {
|
|
4298
|
+
const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
|
|
4307
4299
|
return shouldDebounceTextInbound({
|
|
4308
|
-
text:
|
|
4300
|
+
text: textForCommandDetection,
|
|
4309
4301
|
cfg,
|
|
4310
4302
|
hasMedia: Boolean(message.files && message.files.length > 0) || hasSlackMessageTableBlock(message)
|
|
4311
4303
|
});
|
|
@@ -4477,6 +4469,10 @@ function createSlackMessageHandler(params) {
|
|
|
4477
4469
|
if (admissionLifecycle.onDeferred() === false) return false;
|
|
4478
4470
|
settlementHandedOff = true;
|
|
4479
4471
|
},
|
|
4472
|
+
onDeferredHeartbeat: () => {
|
|
4473
|
+
turnAdoptionLifecycle?.onDeferredHeartbeat?.();
|
|
4474
|
+
admissionLifecycle.onDeferredHeartbeat?.();
|
|
4475
|
+
},
|
|
4480
4476
|
onAbandoned: () => {
|
|
4481
4477
|
settlementHandedOff = true;
|
|
4482
4478
|
releaseClaims();
|
|
@@ -4512,14 +4508,20 @@ function createSlackMessageHandler(params) {
|
|
|
4512
4508
|
ctx.runtime.error?.(`slack inbound debounce flush failed: ${formatErrorMessage(err)}`);
|
|
4513
4509
|
}
|
|
4514
4510
|
});
|
|
4515
|
-
const
|
|
4511
|
+
const threadTsResolvers = /* @__PURE__ */ new WeakMap();
|
|
4516
4512
|
const pendingTopLevelDebounceKeys = /* @__PURE__ */ new Map();
|
|
4517
4513
|
async function enqueueSlackMessage(message, opts) {
|
|
4518
4514
|
if (opts.source === "message" && message.type !== "message") return;
|
|
4519
4515
|
if (opts.source === "message" && message.subtype && message.subtype !== "file_share" && message.subtype !== "bot_message" && message.subtype !== "thread_broadcast") return;
|
|
4520
4516
|
ctx.rememberSlackChannelType(message.channel, message.channel_type, opts.eventScope);
|
|
4521
4517
|
trackEvent?.();
|
|
4522
|
-
const
|
|
4518
|
+
const client = opts.eventScope?.client ?? ctx.app.client;
|
|
4519
|
+
let threadTsResolver = threadTsResolvers.get(client);
|
|
4520
|
+
if (!threadTsResolver) {
|
|
4521
|
+
threadTsResolver = createSlackThreadTsResolver({ client });
|
|
4522
|
+
threadTsResolvers.set(client, threadTsResolver);
|
|
4523
|
+
}
|
|
4524
|
+
const resolvedMessage = await threadTsResolver.resolve({
|
|
4523
4525
|
message,
|
|
4524
4526
|
source: opts.source,
|
|
4525
4527
|
...opts.turnAdoptionLifecycle ? { turnAdoptionLifecycle: opts.turnAdoptionLifecycle } : {}
|
|
@@ -4559,11 +4561,11 @@ function createSlackMessageHandler(params) {
|
|
|
4559
4561
|
}
|
|
4560
4562
|
//#endregion
|
|
4561
4563
|
//#region extensions/slack/src/monitor/presence-monitor.ts
|
|
4562
|
-
const SLACK_PRESENCE_GREETING_COOLDOWN_MS =
|
|
4564
|
+
const SLACK_PRESENCE_GREETING_COOLDOWN_MS = 288e5;
|
|
4563
4565
|
const SLACK_PRESENCE_REQUEST_TIMEOUT_MS = 3e4;
|
|
4564
4566
|
const SLACK_PRESENCE_POLL_INTERVAL_MS = 6e4;
|
|
4565
4567
|
const SLACK_PRESENCE_AUTO_MAX_PARTICIPANTS = 8;
|
|
4566
|
-
const SLACK_PRESENCE_TARGET_TTL_MS =
|
|
4568
|
+
const SLACK_PRESENCE_TARGET_TTL_MS = 864e5;
|
|
4567
4569
|
const SLACK_PRESENCE_MAX_POLLS_PER_INTERVAL = 45;
|
|
4568
4570
|
const SLACK_PRESENCE_MAX_TARGETS = 2e3;
|
|
4569
4571
|
const DEFAULT_SLACK_PRESENCE_EVENT_PROMPT = ["Before greeting, retrieve relevant memory and wiki context for this immutable user_id, including a known timezone when available. Use their local time; if their timezone is unknown, do not guess.", "Send at most one short, natural greeting in this Slack conversation. Do not reveal private memory. If no greeting is appropriate, stay silent."];
|
|
@@ -5015,7 +5017,10 @@ function createSlackBoltApp(params) {
|
|
|
5015
5017
|
...appReceiver ? { receiver: appReceiver } : {}
|
|
5016
5018
|
});
|
|
5017
5019
|
app.use(async (args) => {
|
|
5018
|
-
await params.onContextIdentity?.(
|
|
5020
|
+
await params.onContextIdentity?.({
|
|
5021
|
+
...args.context,
|
|
5022
|
+
apiAppId: normalizeOptionalString(asOptionalRecord(args.body)?.api_app_id)
|
|
5023
|
+
});
|
|
5019
5024
|
if (shouldSkipOpenClawSlackSelfEvent(args)) return;
|
|
5020
5025
|
await args.next();
|
|
5021
5026
|
});
|
|
@@ -5171,8 +5176,8 @@ async function authorizeSlackDirectMessage(params) {
|
|
|
5171
5176
|
//#endregion
|
|
5172
5177
|
//#region extensions/slack/src/monitor/external-arg-menu-store.ts
|
|
5173
5178
|
const SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES = 18;
|
|
5174
|
-
const SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${Math.ceil(
|
|
5175
|
-
const SLACK_EXTERNAL_ARG_MENU_TTL_MS =
|
|
5179
|
+
const SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${Math.ceil(24)}}$`);
|
|
5180
|
+
const SLACK_EXTERNAL_ARG_MENU_TTL_MS = 6e5;
|
|
5176
5181
|
const SLACK_EXTERNAL_ARG_MENU_PREFIX = "openclaw_cmdarg_ext:";
|
|
5177
5182
|
function pruneSlackExternalArgMenuStore(store, rawNow) {
|
|
5178
5183
|
const now = asDateTimestampMs(rawNow);
|
|
@@ -5264,7 +5269,7 @@ const SLACK_COMMAND_ARG_CONFIRM_TEXT_MAX = 300;
|
|
|
5264
5269
|
const SLACK_HEADER_TEXT_MAX = 150;
|
|
5265
5270
|
const SLACK_COMMAND_ARG_ACTION_BLOCKS_MAX = 47;
|
|
5266
5271
|
const loadSlashCommandsRuntime = createLazyRuntimeModule(() => import("./slash-commands.runtime-BTTMlmwy.js"));
|
|
5267
|
-
const loadSlashDispatchRuntime = createLazyRuntimeModule(() => import("./slash-dispatch.runtime-
|
|
5272
|
+
const loadSlashDispatchRuntime = createLazyRuntimeModule(() => import("./slash-dispatch.runtime-C3B4h5ZM.js"));
|
|
5268
5273
|
const loadSlashSkillCommandsRuntime = createLazyRuntimeModule(() => import("./slash-skill-commands.runtime-CD1J2ODY.js"));
|
|
5269
5274
|
const loadPluginCommandRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/plugin-command-runtime"));
|
|
5270
5275
|
function resolveSlackCommandMenuModelContext(params) {
|
|
@@ -5315,6 +5320,8 @@ function resolveSlackCommandMenuModelContext(params) {
|
|
|
5315
5320
|
}
|
|
5316
5321
|
const slackExternalArgMenuStore = createSlackExternalArgMenuStore();
|
|
5317
5322
|
function buildSlackArgMenuConfirm(params) {
|
|
5323
|
+
const command = escapeSlackMrkdwn(params.command);
|
|
5324
|
+
const arg = escapeSlackMrkdwn(params.arg);
|
|
5318
5325
|
return {
|
|
5319
5326
|
title: {
|
|
5320
5327
|
type: "plain_text",
|
|
@@ -5322,7 +5329,7 @@ function buildSlackArgMenuConfirm(params) {
|
|
|
5322
5329
|
},
|
|
5323
5330
|
text: {
|
|
5324
5331
|
type: "mrkdwn",
|
|
5325
|
-
text: truncateSlackText(`Run */${
|
|
5332
|
+
text: truncateSlackText(`Run */${command}* with *${arg}* set to this value?`, SLACK_COMMAND_ARG_CONFIRM_TEXT_MAX)
|
|
5326
5333
|
},
|
|
5327
5334
|
confirm: {
|
|
5328
5335
|
type: "plain_text",
|
|
@@ -6123,12 +6130,13 @@ async function deliverSlackSlashResponseWithWebApi(params) {
|
|
|
6123
6130
|
const mrkdwn = "mrkdwn" in payload && typeof payload.mrkdwn === "boolean" ? payload.mrkdwn : void 0;
|
|
6124
6131
|
if (payload.response_type === "in_channel") {
|
|
6125
6132
|
const postSlackMessage = params.client.chat.postMessage;
|
|
6126
|
-
|
|
6133
|
+
const response = await postSlackMessage({
|
|
6127
6134
|
channel: params.command.channel_id,
|
|
6128
6135
|
text,
|
|
6129
6136
|
...blocks ? { blocks } : {},
|
|
6130
6137
|
...mrkdwn !== void 0 ? { mrkdwn } : {}
|
|
6131
|
-
})
|
|
6138
|
+
});
|
|
6139
|
+
requireSlackPostMessageTimestamp(response);
|
|
6132
6140
|
} else await params.client.chat.postEphemeral({
|
|
6133
6141
|
channel: params.command.channel_id,
|
|
6134
6142
|
user: params.command.user_id,
|
|
@@ -6160,8 +6168,8 @@ async function getSlackBoltInterop() {
|
|
|
6160
6168
|
}
|
|
6161
6169
|
return slackBoltInterop;
|
|
6162
6170
|
}
|
|
6163
|
-
const loadSlackRelaySource = createLazyRuntimeModule(() => import("./relay-source-
|
|
6164
|
-
const SLACK_WEBHOOK_MAX_BODY_BYTES =
|
|
6171
|
+
const loadSlackRelaySource = createLazyRuntimeModule(() => import("./relay-source-DWuduiJ2.js"));
|
|
6172
|
+
const SLACK_WEBHOOK_MAX_BODY_BYTES = 1048576;
|
|
6165
6173
|
const SLACK_WEBHOOK_BODY_TIMEOUT_MS = 3e4;
|
|
6166
6174
|
function resolveSlackRuntimeIdentity(params) {
|
|
6167
6175
|
const botUserId = normalizeOptionalString(params.botUserId);
|
|
@@ -6262,10 +6270,10 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6262
6270
|
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
|
|
6263
6271
|
const slackMode = opts.mode ?? account.config.mode ?? "socket";
|
|
6264
6272
|
const slackWebhookPath = normalizeSlackWebhookPath(account.config.webhookPath);
|
|
6265
|
-
const signingSecret = normalizeResolvedSecretInputString({
|
|
6273
|
+
const signingSecret = slackMode === "http" ? normalizeResolvedSecretInputString({
|
|
6266
6274
|
value: account.config.signingSecret,
|
|
6267
6275
|
path: `channels.slack.accounts.${account.accountId}.signingSecret`
|
|
6268
|
-
});
|
|
6276
|
+
}) : void 0;
|
|
6269
6277
|
const botToken = resolveSlackBotToken(opts.botToken ?? account.botToken);
|
|
6270
6278
|
const userToken = account.userToken;
|
|
6271
6279
|
const appToken = resolveSlackAppToken(opts.appToken ?? account.appToken);
|
|
@@ -6302,8 +6310,9 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6302
6310
|
const groupDmChannels = dmConfig?.groupChannels;
|
|
6303
6311
|
let channelsConfig = slackCfg.channels;
|
|
6304
6312
|
const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
|
|
6313
|
+
const providerConfigPresent = cfg.channels?.slack !== void 0;
|
|
6305
6314
|
const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy$1({
|
|
6306
|
-
providerConfigPresent
|
|
6315
|
+
providerConfigPresent,
|
|
6307
6316
|
groupPolicy: slackCfg.groupPolicy,
|
|
6308
6317
|
defaultGroupPolicy
|
|
6309
6318
|
});
|
|
@@ -6339,7 +6348,7 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6339
6348
|
slackMode,
|
|
6340
6349
|
token,
|
|
6341
6350
|
appToken: slackMode === "socket" ? appToken ?? void 0 : void 0,
|
|
6342
|
-
signingSecret:
|
|
6351
|
+
signingSecret: signingSecret ?? void 0,
|
|
6343
6352
|
slackWebhookPath,
|
|
6344
6353
|
clientOptions,
|
|
6345
6354
|
dispatcher: slackDispatcher,
|
|
@@ -6366,6 +6375,13 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6366
6375
|
installationState.update(contextInstallationIdentity.kind);
|
|
6367
6376
|
await installSlackRuntimeForIdentity(contextInstallationIdentity);
|
|
6368
6377
|
}
|
|
6378
|
+
if (!current.apiAppId && identity.apiAppId && current.installationIdentity.kind !== "degraded") {
|
|
6379
|
+
applySlackInstallationIdentity(current, {
|
|
6380
|
+
...current.installationIdentity,
|
|
6381
|
+
apiAppId: identity.apiAppId
|
|
6382
|
+
});
|
|
6383
|
+
runtime.log?.(`[${account.accountId}] slack app id ${identity.apiAppId} learned from signed event`);
|
|
6384
|
+
}
|
|
6369
6385
|
if (recovered || adopted) publishSlackConnectedStatus(opts.setStatus, current.identityHealth);
|
|
6370
6386
|
}
|
|
6371
6387
|
});
|
|
@@ -6604,10 +6620,11 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6604
6620
|
summarizeMapping("slack users", mapping, [], runtime);
|
|
6605
6621
|
}
|
|
6606
6622
|
if (allowNameMatching) try {
|
|
6607
|
-
const
|
|
6623
|
+
const resolvedUsers = await resolveSlackUserAllowlist({
|
|
6608
6624
|
token: resolveToken,
|
|
6609
6625
|
entries: allowEntries
|
|
6610
|
-
})
|
|
6626
|
+
});
|
|
6627
|
+
const { mapping, unresolved, additions } = buildAllowlistResolutionSummary(resolvedUsers, { formatResolved: formatSlackUserResolved });
|
|
6611
6628
|
allowFrom = mergeAllowlist({
|
|
6612
6629
|
existing: allowFrom,
|
|
6613
6630
|
additions
|
|
@@ -6634,10 +6651,11 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6634
6651
|
summarizeMapping("slack channel users", mapping, [], runtime);
|
|
6635
6652
|
}
|
|
6636
6653
|
if (allowNameMatching) try {
|
|
6637
|
-
const
|
|
6654
|
+
const resolvedUsers = await resolveSlackUserAllowlist({
|
|
6638
6655
|
token: resolveToken,
|
|
6639
6656
|
entries: Array.from(userEntries)
|
|
6640
|
-
})
|
|
6657
|
+
});
|
|
6658
|
+
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers, { formatResolved: formatSlackUserResolved });
|
|
6641
6659
|
const nextChannels = patchAllowlistUsersInConfigEntries({
|
|
6642
6660
|
entries: channelsConfig,
|
|
6643
6661
|
resolvedMap
|
|
@@ -6686,10 +6704,7 @@ async function monitorSlackProvider(opts = {}) {
|
|
|
6686
6704
|
app,
|
|
6687
6705
|
config: slackCfg.execApprovals ?? {},
|
|
6688
6706
|
resolveClient,
|
|
6689
|
-
...identity.kind === "enterprise" ? { enterprise: {
|
|
6690
|
-
apiAppId: identity.apiAppId,
|
|
6691
|
-
enterpriseId: identity.enterpriseId
|
|
6692
|
-
} } : {}
|
|
6707
|
+
...identity.kind === "enterprise" ? { enterprise: { enterpriseId: identity.enterpriseId } } : {}
|
|
6693
6708
|
},
|
|
6694
6709
|
abortSignal: opts.abortSignal
|
|
6695
6710
|
});
|