@openclaw/slack 2026.9.1 → 2026.9.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.
Files changed (70) hide show
  1. package/dist/{action-runtime-DND4Pyp2.js → action-runtime-DftQWpI4.js} +4 -4
  2. package/dist/action-runtime.runtime-rHI3UAh4.js +2 -0
  3. package/dist/{actions-fh66A6lc.js → actions-CFkvEv1d.js} +3 -3
  4. package/dist/api.js +9 -9
  5. package/dist/{approval-handler.runtime-D7d8sKM0.js → approval-handler.runtime-BeILKdw4.js} +31 -15
  6. package/dist/{channel-4m8IAdMD.js → channel-CmOuxbOD.js} +24 -23
  7. package/dist/channel-config-api.js +1 -1
  8. package/dist/channel-plugin-api.js +1 -1
  9. package/dist/{channel-type-3-SqEMVc.js → channel-type-BWt2CRaI.js} +2 -2
  10. package/dist/{channel.setup-t_ghLGb_.js → channel.setup-D5z1ReaT.js} +8 -3
  11. package/dist/{config-schema-bP3eV2ra.js → config-schema-JDx_f9Zb.js} +2 -2
  12. package/dist/{directory-live-q32AW7N1.js → directory-live-BuBPHmju.js} +1 -1
  13. package/dist/{monitor-Chwu_SiZ.js → monitor-DI07pfJl.js} +3 -3
  14. package/dist/{outbound-adapter-BB8wAjm5.js → outbound-adapter-B5QyTRpJ.js} +3 -2
  15. package/dist/{pipeline.runtime-BklS_NEj.js → pipeline.runtime-BdIwZgm4.js} +567 -733
  16. package/dist/{policy-D7PKkiet.js → policy-Bh5TOqII.js} +2 -2
  17. package/dist/{probe-gj5yQgN2.js → probe-Biy--yhL.js} +42 -10
  18. package/dist/{provider-Do50wMWn.js → provider-DoaUvAM4.js} +5583 -4921
  19. package/dist/{relay-source-DWuduiJ2.js → relay-source-D4uecp68.js} +1 -1
  20. package/dist/{replies-Dc6WVh_Q.js → replies-DENuTcPO.js} +4 -3
  21. package/dist/reply-blocks-PRkhyAN7.js +790 -0
  22. package/dist/{resolve-channels-CU7Bg5Ka.js → resolve-channels-DQGV2VrE.js} +1 -1
  23. package/dist/{resolve-users-DrhttvRQ.js → resolve-users-DRGt_Q4I.js} +1 -1
  24. package/dist/runtime-api.js +10 -10
  25. package/dist/{scopes-B9HRguDe.js → scopes-CZzeGdWV.js} +1 -1
  26. package/dist/{send-Djswy6lf.js → send-DElUcgIs.js} +10 -10
  27. package/dist/{send.runtime-__WVTWLQ.js → send.runtime-C8D6cKGm.js} +1 -1
  28. package/dist/{group-policy-BKjMqT-8.js → session-status-BynwcZSO.js} +169 -799
  29. package/dist/setup-plugin-api.js +1 -1
  30. package/dist/{setup-surface-DO0e-MMS.js → setup-surface-B1_gpGBl.js} +4 -4
  31. package/dist/{shared-DEQBEKBL.js → shared-CNQsWJT7.js} +2 -2
  32. package/dist/{slash-dispatch.runtime-C3B4h5ZM.js → slash-dispatch.runtime-DhsXavSY.js} +1 -1
  33. package/node_modules/typebox/build/format/json_pointer.d.mts +2 -2
  34. package/node_modules/typebox/build/format/json_pointer.mjs +2 -2
  35. package/node_modules/typebox/build/format/json_pointer_uri_fragment.d.mts +2 -2
  36. package/node_modules/typebox/build/format/json_pointer_uri_fragment.mjs +2 -2
  37. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  38. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  39. package/node_modules/typebox/build/system/memory/assign.mjs +2 -1
  40. package/node_modules/typebox/build/system/memory/create.mjs +3 -4
  41. package/node_modules/typebox/build/system/memory/discard.mjs +2 -2
  42. package/node_modules/typebox/build/system/memory/freeze.d.mts +4 -0
  43. package/node_modules/typebox/build/system/memory/freeze.mjs +6 -0
  44. package/node_modules/typebox/build/system/memory/update.mjs +3 -2
  45. package/node_modules/typebox/package.json +1 -1
  46. package/node_modules/undici/lib/dispatcher/balanced-pool.js +4 -2
  47. package/node_modules/undici/lib/dispatcher/client-h1.js +12 -4
  48. package/node_modules/undici/lib/dispatcher/client-h2.js +70 -14
  49. package/node_modules/undici/lib/dispatcher/client.js +6 -2
  50. package/node_modules/undici/lib/handler/cache-handler.js +21 -5
  51. package/node_modules/undici/lib/handler/retry-handler.js +42 -7
  52. package/node_modules/undici/lib/interceptor/cache.js +20 -1
  53. package/node_modules/undici/lib/interceptor/decompress.js +146 -14
  54. package/node_modules/undici/lib/interceptor/dump.js +10 -23
  55. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +245 -150
  56. package/node_modules/undici/lib/web/websocket/connection.js +1 -1
  57. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +5 -0
  58. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -10
  59. package/node_modules/undici/package.json +1 -1
  60. package/node_modules/undici/types/interceptors.d.ts +2 -0
  61. package/openclaw.plugin.json +3 -3
  62. package/package.json +6 -6
  63. package/skills/_vendor/slack-skills-plugin.LICENSE +21 -0
  64. package/skills/_vendor/slack-skills-plugin.json +31 -0
  65. package/skills/block-kit/SKILL.md +37 -0
  66. package/skills/block-kit/references/official-block-kit.md +257 -0
  67. package/skills/block-kit/references/official-common-patterns.md +385 -0
  68. package/skills/slack/SKILL.md +1 -1
  69. package/dist/action-runtime.runtime-CEhbmS-Z.js +0 -2
  70. package/dist/conversation-binding-route-Vee8Dgbf.js +0 -115
@@ -2,10 +2,11 @@ import { n as isSlackPluginAccountConfigured } from "./account-configured-sUohAx
2
2
  import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-Dm_H77gH.js";
3
3
  import { a as parseSlackTarget, n as formatSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-PbxGDbr9.js";
4
4
  import { t as slackContextTargetsMatch } from "./targets-7FexXJ62.js";
5
- import { C as normalizeAllowListLower, D as resolveSlackUserAllowListForTeam, E as resolveSlackAllowListMatch } from "./probe-gj5yQgN2.js";
5
+ import { C as normalizeAllowListLower, D as resolveSlackUserAllowListForTeam, E as resolveSlackAllowListMatch, o as formatSlackError } from "./probe-Biy--yhL.js";
6
6
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
7
7
  import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { normalizeMessageChannel } from "openclaw/plugin-sdk/routing";
9
+ import { defaultRuntime, logVerbose, warn } from "openclaw/plugin-sdk/runtime-env";
9
10
  import { FormatCapabilityProfile, chunkTextForOutbound, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-chunking";
10
11
  import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
11
12
  import { buildChannelKeyCandidates } from "openclaw/plugin-sdk/channel-targets";
@@ -15,15 +16,25 @@ import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFro
15
16
  import { normalizeHyphenSlug } from "openclaw/plugin-sdk/string-normalization-runtime";
16
17
  import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
17
18
  import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
18
- import { legacyInteractiveReplyToPresentation, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
19
- import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
20
- import { resolveAskUserQuestionOptionIndex, resolveAskUserQuestionOptionIndices } from "openclaw/plugin-sdk/reply-payload";
21
- import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
19
+ import { normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
22
20
  import { eastAsianWidthType } from "get-east-asian-width";
23
- import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
24
- import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
21
+ import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
25
22
  import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
23
+ import { resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
26
24
  import { resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
25
+ //#region extensions/slack/src/account-reply-mode.ts
26
+ function normalizeSlackChatType(raw) {
27
+ const value = raw?.trim().toLowerCase();
28
+ if (!value) return;
29
+ if (value === "direct" || value === "dm") return "direct";
30
+ if (value === "group" || value === "channel") return value;
31
+ }
32
+ function resolveSlackReplyToMode(account, chatType) {
33
+ const normalized = normalizeSlackChatType(chatType ?? void 0);
34
+ if (normalized && account.replyToModeByChatType?.[normalized] !== void 0) return account.replyToModeByChatType[normalized] ?? "off";
35
+ return account.replyToMode ?? "off";
36
+ }
37
+ //#endregion
27
38
  //#region extensions/slack/src/action-threading.ts
28
39
  const SLACK_PRIVATE_ACTION_DELIVERY_RESULT = Symbol("slack.action.delivery-result");
29
40
  function resolveSlackAutoThreadId(params) {
@@ -439,75 +450,10 @@ function parseSlackBlocksInput(raw) {
439
450
  if (raw == null) return;
440
451
  return validateSlackBlocksArray(typeof raw === "string" ? parseBlocksJson(raw) : raw);
441
452
  }
442
- const SLACK_BUTTON_VALUE_MAX = 2e3;
443
- const SLACK_SECTION_TEXT_MAX = 3e3;
444
- const SLACK_PRESENTATION_CAPABILITIES = {
445
- supported: true,
446
- buttons: true,
447
- selects: true,
448
- context: true,
449
- divider: true,
450
- charts: true,
451
- tables: true,
452
- limits: {
453
- actions: {
454
- maxActionsPerRow: 25,
455
- maxValueBytes: SLACK_BUTTON_VALUE_MAX,
456
- supportsStyles: true
457
- },
458
- selects: {
459
- maxOptions: 100,
460
- maxValueBytes: 150
461
- },
462
- text: {
463
- encoding: "characters",
464
- markdownDialect: "slack-mrkdwn",
465
- supportsEdit: true
466
- }
467
- }
468
- };
469
- //#endregion
470
- //#region extensions/slack/src/approval-actions.ts
471
- const SLACK_APPROVAL_VALUE_PREFIX = "openclaw:approval:v1:";
472
- const SLACK_APPROVAL_HEADER_BLOCK_ID = "openclaw_approval_header";
473
- function isApprovalDecision(value) {
474
- return value === "allow-once" || value === "allow-always" || value === "deny";
475
- }
476
- /** Encode portable approval facts without exposing a slash command to Slack callbacks. */
477
- function encodeSlackApprovalAction(action) {
478
- const encode = (approvalId) => `${SLACK_APPROVAL_VALUE_PREFIX}${JSON.stringify({
479
- approvalId,
480
- approvalKind: action.approvalKind,
481
- decision: action.decision
482
- })}`;
483
- const exact = encode(action.approvalId);
484
- return exact.length <= 2e3 ? exact : encode(buildApprovalResolutionRef({
485
- approvalId: action.approvalId,
486
- approvalKind: action.approvalKind
487
- }));
488
- }
489
- /** Decode only the exact Slack-owned approval envelope. Malformed callbacks fail closed. */
490
- function decodeSlackApprovalAction(value) {
491
- if (typeof value !== "string" || !value.startsWith(SLACK_APPROVAL_VALUE_PREFIX)) return null;
492
- try {
493
- const decoded = JSON.parse(value.slice(21));
494
- if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return null;
495
- const record = decoded;
496
- if (Object.keys(record).length !== 3 || typeof record.approvalId !== "string" || record.approvalId.length === 0 || record.approvalKind !== "exec" && record.approvalKind !== "plugin" || !isApprovalDecision(record.decision)) return null;
497
- return {
498
- type: "approval",
499
- approvalId: record.approvalId,
500
- approvalKind: record.approvalKind,
501
- decision: record.decision
502
- };
503
- } catch {
504
- return null;
505
- }
506
- }
507
453
  //#endregion
508
454
  //#region extensions/slack/src/monitor/mrkdwn.ts
509
455
  function escapeSlackMrkdwn(value) {
510
- return value.replaceAll("\\", "\\\\").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replace(/([*_`~])/g, "\\$1");
456
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
511
457
  }
512
458
  //#endregion
513
459
  //#region extensions/slack/src/presentation-fallback.ts
@@ -645,6 +591,7 @@ function renderSlackRichText(value, mode, separator = "") {
645
591
  //#region extensions/slack/src/data-table.ts
646
592
  const SLACK_DATA_TABLE_COLUMNS_MAX = 20;
647
593
  const SLACK_DATA_TABLE_ROWS_MAX = 100;
594
+ const SLACK_DATA_TABLE_AGGREGATE_CELL_CHARACTERS_MAX = 1e4;
648
595
  function countCharacters(value) {
649
596
  return Array.from(value).length;
650
597
  }
@@ -786,7 +733,7 @@ function escapeCompactFallbackCell(value) {
786
733
  return value.replaceAll("\\", "\\\\").replaceAll(" ", "\\t").replaceAll("\r", "\\r").replaceAll("\n", "\\n");
787
734
  }
788
735
  function escapeSlackBasicTableCell(value, mrkdwnSafe) {
789
- return (mrkdwnSafe ? escapeSlackMrkdwn(value) : value.replaceAll("\\", "\\\\")).replaceAll(" ", "\\t").replaceAll("\r", "\\r").replaceAll("\n", "\\n");
736
+ return escapeCompactFallbackCell(mrkdwnSafe ? escapeSlackMrkdwn(value) : value);
790
737
  }
791
738
  function renderSlackBasicTableRows(value, mrkdwnSafe) {
792
739
  return parseSlackBasicTableRows(value)?.map((row) => row.map((cell) => escapeSlackBasicTableCell(cell, mrkdwnSafe)).join(" ")).join("\n");
@@ -953,16 +900,14 @@ function renderSlackDataVisualizationMrkdwnFallbackText(value) {
953
900
  }
954
901
  //#endregion
955
902
  //#region extensions/slack/src/format.ts
956
- function escapeSlackMrkdwnSegment(text) {
957
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
958
- }
959
903
  const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
960
904
  function isAllowedSlackAngleToken(token) {
961
905
  if (!token.startsWith("<") || !token.endsWith(">")) return false;
962
906
  const inner = token.slice(1, -1);
963
907
  return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
964
908
  }
965
- function escapeSlackMrkdwnContent(text) {
909
+ function escapeSlackMrkdwnContent(text, mentions) {
910
+ if (mentions === "escape") return escapeSlackMrkdwn(text);
966
911
  if (!text) return "";
967
912
  if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
968
913
  SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
@@ -970,20 +915,20 @@ function escapeSlackMrkdwnContent(text) {
970
915
  let lastIndex = 0;
971
916
  for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
972
917
  const matchIndex = match.index ?? 0;
973
- out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
918
+ out.push(escapeSlackMrkdwn(text.slice(lastIndex, matchIndex)));
974
919
  const token = match[0] ?? "";
975
- out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
920
+ out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwn(token));
976
921
  lastIndex = matchIndex + token.length;
977
922
  }
978
- out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
923
+ out.push(escapeSlackMrkdwn(text.slice(lastIndex)));
979
924
  return out.join("");
980
925
  }
981
- function escapeSlackMrkdwnText(text) {
926
+ function escapeSlackMrkdwnText(text, mentions) {
982
927
  if (!text) return "";
983
928
  if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
984
929
  return text.split("\n").map((line) => {
985
- if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
986
- return escapeSlackMrkdwnContent(line);
930
+ if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2), mentions)}`;
931
+ return escapeSlackMrkdwnContent(line, mentions);
987
932
  }).join("\n");
988
933
  }
989
934
  function buildSlackLink(link, text) {
@@ -992,7 +937,7 @@ function buildSlackLink(link, text) {
992
937
  const trimmedLabel = text.slice(link.start, link.end).trim();
993
938
  const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
994
939
  if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
995
- const safeHref = escapeSlackMrkdwnSegment(href);
940
+ const safeHref = escapeSlackMrkdwn(href);
996
941
  return {
997
942
  start: link.start,
998
943
  end: link.end,
@@ -1194,7 +1139,7 @@ function protectSlackAssistantTranscriptRoleHeaders(text) {
1194
1139
  if (!slackProjectionHasRoleHeader(projectSlackMrkdwnVisibleText(text, "token")) && (!text.includes("<!date^") || !slackProjectionHasRoleHeader(projectSlackMrkdwnVisibleText(text, "fallback")))) return text;
1195
1140
  return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
1196
1141
  }
1197
- function buildSlackRenderOptions() {
1142
+ function buildSlackRenderOptions({ enclosingStyle, mentions } = {}) {
1198
1143
  return {
1199
1144
  annotationMarkers: { assistant_transcript_role: {
1200
1145
  open: "`",
@@ -1202,14 +1147,14 @@ function buildSlackRenderOptions() {
1202
1147
  suppressNestedFormatting: true
1203
1148
  } },
1204
1149
  styleMarkers: {
1205
- bold: {
1150
+ ...enclosingStyle !== "bold" ? { bold: {
1206
1151
  open: "*",
1207
1152
  close: "*"
1208
- },
1209
- italic: {
1153
+ } } : {},
1154
+ ...enclosingStyle !== "italic" ? { italic: {
1210
1155
  open: "_",
1211
1156
  close: "_"
1212
- },
1157
+ } } : {},
1213
1158
  strikethrough: {
1214
1159
  open: "~",
1215
1160
  close: "~"
@@ -1223,7 +1168,7 @@ function buildSlackRenderOptions() {
1223
1168
  close: "```"
1224
1169
  }
1225
1170
  },
1226
- escapeText: escapeSlackMrkdwnText,
1171
+ escapeText: (text) => escapeSlackMrkdwnText(text, mentions),
1227
1172
  buildLink: buildSlackLink
1228
1173
  };
1229
1174
  }
@@ -1236,7 +1181,7 @@ function normalizeSlackOutboundText(markdown, options = {}) {
1236
1181
  blockquotePrefix: "> ",
1237
1182
  tableMode: options.tableMode
1238
1183
  }));
1239
- return protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(ir, buildSlackRenderOptions(), SLACK_FORMAT_PROFILE));
1184
+ return protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(ir, buildSlackRenderOptions(options), SLACK_FORMAT_PROFILE));
1240
1185
  }
1241
1186
  /** Chunk already-rendered Slack mrkdwn without splitting entities or code markers. */
1242
1187
  function chunkSlackMrkdwnText(text, limit) {
@@ -1270,7 +1215,7 @@ function chunkSlackMrkdwnText(text, limit) {
1270
1215
  const marker = wrapper(activeMarker);
1271
1216
  if (activeMarker && isAllowedSlackAngleToken(token)) {
1272
1217
  if (marker) chunks.push(...chunkTextForOutbound(token, Math.max(1, Math.floor(contentLimit)), { preserveWhitespace: true }).map((fragment) => `${marker}${fragment}${marker}`));
1273
- else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwnSegment(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
1218
+ else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwn(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
1274
1219
  continue;
1275
1220
  }
1276
1221
  chunks.push(...token.length <= limit ? [token] : chunkTextForOutbound(token, limit));
@@ -1299,39 +1244,6 @@ function markdownToSlackMrkdwnChunks(markdown, limit, options = {}) {
1299
1244
  }).map(({ rendered }) => rendered);
1300
1245
  }
1301
1246
  //#endregion
1302
- //#region extensions/slack/src/question-actions.ts
1303
- const SLACK_QUESTION_VALUE_PREFIX = "slq1:";
1304
- const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
1305
- function encodeSlackQuestionAction(action) {
1306
- if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
1307
- const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
1308
- return value.length <= 2e3 ? value : void 0;
1309
- }
1310
- function decodeSlackQuestionAction(value) {
1311
- if (typeof value !== "string" || value.length > 2e3) return null;
1312
- const match = /^slq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(value);
1313
- return match?.[1] && match[2] ? {
1314
- questionId: match[1],
1315
- optionIndex: Number(match[2])
1316
- } : null;
1317
- }
1318
- async function resolveSlackQuestionAction(params) {
1319
- let result;
1320
- try {
1321
- result = await (params.resolveQuestion ?? questionGatewayRuntime.resolveOption)({
1322
- cfg: params.cfg,
1323
- questionId: params.action.questionId,
1324
- optionIndex: params.action.optionIndex,
1325
- senderId: params.userId,
1326
- clientDisplayName: `Slack question (${params.accountId})`
1327
- });
1328
- } catch {
1329
- await params.respond("Could not submit this answer.").catch(() => {});
1330
- return;
1331
- }
1332
- await params.respond(result.status === "answered" ? "Answer submitted." : "This question was already answered.").catch(() => {});
1333
- }
1334
- //#endregion
1335
1247
  //#region extensions/slack/src/reply-action-ids.ts
1336
1248
  const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
1337
1249
  const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
@@ -1389,381 +1301,12 @@ function truncateSlackTextByUtf8Bytes(value, maxBytes) {
1389
1301
  return maxBytes >= suffixBytes ? `${prefix}${suffix}` : prefix;
1390
1302
  }
1391
1303
  //#endregion
1392
- //#region extensions/slack/src/blocks-render.ts
1393
- const SLACK_BUTTON_URL_MAX = 3e3;
1394
- function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
1395
- return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1396
- }
1397
- function buildSlackReplyLinkActionId(buttonIndex, choiceIndex) {
1398
- return `${SLACK_REPLY_LINK_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1399
- }
1400
- function buildSlackReplySelectActionId(selectIndex) {
1401
- return `${SLACK_REPLY_SELECT_ACTION_ID}:${String(selectIndex)}`;
1402
- }
1403
- function buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) {
1404
- return `${SLACK_APPROVAL_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1405
- }
1406
- function buildSlackApprovalSelectActionId(selectIndex) {
1407
- return `${SLACK_APPROVAL_SELECT_ACTION_ID}:${String(selectIndex)}`;
1408
- }
1409
- function buildSlackCallbackButtonActionId(buttonIndex, choiceIndex) {
1410
- return `${SLACK_CALLBACK_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1411
- }
1412
- function buildSlackCallbackSelectActionId(selectIndex) {
1413
- return `${SLACK_CALLBACK_SELECT_ACTION_ID}:${String(selectIndex)}`;
1414
- }
1415
- function buildSlackQuestionButtonActionId(buttonIndex, choiceIndex) {
1416
- return `${SLACK_QUESTION_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1417
- }
1418
- function resolveSlackButtonStyle(style) {
1419
- if (style === "primary" || style === "danger") return style;
1420
- if (style === "success") return "primary";
1421
- }
1422
- function resolveSlackActionTarget(action, questionOptionIndices) {
1423
- if (!action) return;
1424
- if (action.type === "approval") return {
1425
- kind: "approval",
1426
- value: encodeSlackApprovalAction(action)
1427
- };
1428
- if (action.type === "question") {
1429
- if ("intent" in action) return;
1430
- const optionIndex = resolveAskUserQuestionOptionIndex({
1431
- questionOptionIndices,
1432
- questionId: action.questionId,
1433
- optionValue: action.optionValue
1434
- });
1435
- const value = optionIndex === void 0 ? void 0 : encodeSlackQuestionAction({
1436
- questionId: action.questionId,
1437
- optionIndex
1438
- });
1439
- return value ? {
1440
- kind: "question",
1441
- value
1442
- } : void 0;
1443
- }
1444
- if (action.type === "url" || action.type === "web-app") {
1445
- const url = normalizeOptionalString(action.url);
1446
- return url ? {
1447
- kind: "link",
1448
- url
1449
- } : void 0;
1450
- }
1451
- if (action.type === "callback") {
1452
- const value = normalizeOptionalString(action.value);
1453
- return value ? {
1454
- kind: "callback",
1455
- value
1456
- } : void 0;
1457
- }
1458
- const command = normalizeOptionalString(action.command);
1459
- return command && parseExecApprovalCommandText(command) ? {
1460
- kind: "reply",
1461
- value: command
1462
- } : void 0;
1463
- }
1464
- function resolveSlackButtonTarget(button, questionOptionIndices) {
1465
- if (button.action !== void 0) {
1466
- const action = resolveMessagePresentationButtonAction(button);
1467
- return action ? resolveSlackActionTarget(action, questionOptionIndices) : void 0;
1468
- }
1469
- const legacyUrl = normalizeOptionalString(button.url ?? button.webApp?.url ?? button.web_app?.url);
1470
- if (legacyUrl && isWithinSlackLimit(legacyUrl, SLACK_BUTTON_URL_MAX)) return {
1471
- kind: "link",
1472
- url: legacyUrl
1473
- };
1474
- const legacyValue = normalizeOptionalString(button.value);
1475
- if (legacyValue) return {
1476
- kind: "reply",
1477
- value: legacyValue
1478
- };
1479
- return legacyUrl ? {
1480
- kind: "link",
1481
- url: legacyUrl
1482
- } : void 0;
1483
- }
1484
- function isSlackTextFallbackButton(button) {
1485
- const action = resolveMessagePresentationButtonAction(button);
1486
- return action?.type === "question" && "intent" in action && action.intent === "custom-input";
1487
- }
1488
- function resolveSlackOptionTarget(option) {
1489
- if (option.action !== void 0) {
1490
- const action = resolveMessagePresentationOptionAction(option);
1491
- const target = action ? resolveSlackActionTarget(action) : void 0;
1492
- return target?.kind === "link" || target?.kind === "question" ? void 0 : target;
1493
- }
1494
- const value = normalizeOptionalString(option.value);
1495
- return value ? {
1496
- kind: "reply",
1497
- value
1498
- } : void 0;
1499
- }
1500
- function isWithinSlackLimit(value, maxLength) {
1501
- return value.length <= maxLength;
1502
- }
1503
- function isRenderableSlackOption(option) {
1504
- return isWithinSlackLimit(option.value, 150);
1505
- }
1506
- function readSlackBlockId(block) {
1507
- const value = block.block_id;
1508
- return typeof value === "string" ? value : void 0;
1509
- }
1510
- function readSlackOpenClawBlockIndex(blockId, prefix) {
1511
- if (!blockId.startsWith(prefix)) return;
1512
- const value = Number.parseInt(blockId.slice(prefix.length), 10);
1513
- return Number.isSafeInteger(value) && value > 0 ? value : void 0;
1514
- }
1515
- /** Resolve existing Block Kit indexes and native-data budgets before appending portable blocks. */
1516
- function resolveSlackBlockOffsets(blocks) {
1517
- let buttonIndexOffset = 0;
1518
- const dataTableCellCharacterCountOffset = countSlackDataTableBlocksCellCharacters(blocks) ?? 10001;
1519
- let dataVisualizationCountOffset = 0;
1520
- let selectIndexOffset = 0;
1521
- for (const block of blocks ?? []) {
1522
- if (hasSlackDataVisualizationBlock([block])) dataVisualizationCountOffset += 1;
1523
- const blockId = readSlackBlockId(block);
1524
- if (!blockId) continue;
1525
- buttonIndexOffset = Math.max(buttonIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_buttons_") ?? 0);
1526
- selectIndexOffset = Math.max(selectIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_select_") ?? 0);
1527
- }
1528
- return {
1529
- buttonIndexOffset,
1530
- dataTableCellCharacterCountOffset,
1531
- dataVisualizationCountOffset,
1532
- selectIndexOffset
1533
- };
1534
- }
1535
- /**
1536
- * @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
1537
- */
1538
- function buildSlackInteractiveBlocks(interactive, options = {}) {
1539
- return buildSlackPresentationBlocks(interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0, options);
1540
- }
1541
- /** Render portable presentation blocks as Slack Block Kit blocks. */
1542
- function buildSlackPresentationBlocks(presentation, options = {}) {
1543
- if (!presentation) return [];
1544
- const renderTablesNatively = canRenderSlackPresentationTables(presentation, options);
1545
- const blocks = [];
1546
- if (presentation.title) blocks.push({
1547
- type: "header",
1548
- text: {
1549
- type: "plain_text",
1550
- text: truncateSlackText(presentation.title, 150),
1551
- emoji: true
1552
- }
1553
- });
1554
- let buttonIndex = options.buttonIndexOffset ?? 0;
1555
- let dataTableCellCharacterCount = options.dataTableCellCharacterCountOffset ?? 0;
1556
- let dataVisualizationCount = options.dataVisualizationCountOffset ?? 0;
1557
- let selectIndex = options.selectIndexOffset ?? 0;
1558
- for (const block of presentation.blocks) {
1559
- if (block.type === "text" || block.type === "context") {
1560
- const text = block.text.trim();
1561
- if (!text) continue;
1562
- for (const chunk of chunkSlackMrkdwnText(text, SLACK_SECTION_TEXT_MAX)) blocks.push(block.type === "context" ? {
1563
- type: "context",
1564
- elements: [{
1565
- type: "mrkdwn",
1566
- text: chunk,
1567
- verbatim: true
1568
- }]
1569
- } : {
1570
- type: "section",
1571
- text: {
1572
- type: "mrkdwn",
1573
- text: chunk
1574
- }
1575
- });
1576
- continue;
1577
- }
1578
- if (block.type === "divider") {
1579
- blocks.push({ type: "divider" });
1580
- continue;
1581
- }
1582
- if (block.type === "buttons") {
1583
- const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1, options.questionOptionIndices);
1584
- if (rendered) {
1585
- buttonIndex += 1;
1586
- blocks.push(rendered);
1587
- }
1588
- continue;
1589
- }
1590
- if (block.type === "chart") {
1591
- const rendered = dataVisualizationCount < 2 ? buildSlackPresentationChartBlock(block) : void 0;
1592
- if (rendered) {
1593
- dataVisualizationCount += 1;
1594
- blocks.push(rendered);
1595
- } else {
1596
- const fallback = renderSlackMessagePresentationChartFallbackText(block);
1597
- blocks.push(...chunkTextForOutbound(fallback, SLACK_SECTION_TEXT_MAX).map((text) => ({
1598
- type: "context",
1599
- elements: [{
1600
- type: "mrkdwn",
1601
- text,
1602
- verbatim: true
1603
- }]
1604
- })));
1605
- }
1606
- continue;
1607
- }
1608
- if (block.type === "table") {
1609
- if (!renderTablesNatively) continue;
1610
- const rendered = buildSlackDataTableBlock(block, { cellCharacterCountOffset: dataTableCellCharacterCount });
1611
- if (rendered) {
1612
- dataTableCellCharacterCount += countSlackDataTableCellCharacters(rendered);
1613
- blocks.push(rendered);
1614
- }
1615
- continue;
1616
- }
1617
- if (block.type === "select") {
1618
- const rendered = buildSlackPresentationSelectBlock(block, selectIndex + 1);
1619
- if (rendered) {
1620
- selectIndex += 1;
1621
- blocks.push(rendered);
1622
- }
1623
- }
1624
- }
1625
- return blocks;
1626
- }
1627
- function buildSlackPresentationChartBlock(block) {
1628
- return buildSlackDataVisualizationBlock(block);
1629
- }
1630
- function buildSlackPresentationButtonBlock(block, buttonIndex, questionOptionIndices) {
1631
- const elements = block.buttons.flatMap((button, choiceIndex) => {
1632
- const target = resolveSlackButtonTarget(button, questionOptionIndices);
1633
- if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
1634
- const style = resolveSlackButtonStyle(button.style);
1635
- return [{
1636
- type: "button",
1637
- action_id: target.kind === "link" ? buildSlackReplyLinkActionId(buttonIndex, choiceIndex) : target.kind === "approval" ? buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) : target.kind === "callback" ? buildSlackCallbackButtonActionId(buttonIndex, choiceIndex) : target.kind === "question" ? buildSlackQuestionButtonActionId(buttonIndex, choiceIndex) : buildSlackReplyButtonActionId(buttonIndex, choiceIndex),
1638
- text: {
1639
- type: "plain_text",
1640
- text: truncateSlackText(button.label, 75),
1641
- emoji: true
1642
- },
1643
- ...target.kind === "link" ? { url: target.url } : { value: target.value },
1644
- ...style ? { style } : {}
1645
- }];
1646
- }).slice(0, 25);
1647
- return elements.length > 0 ? {
1648
- type: "actions",
1649
- block_id: `openclaw_reply_buttons_${buttonIndex}`,
1650
- elements
1651
- } : void 0;
1652
- }
1653
- /** True when every portable table fits Slack's native per-message table budget. */
1654
- function canRenderSlackPresentationTables(presentation, options = {}) {
1655
- let cellCharacterCount = options.dataTableCellCharacterCountOffset ?? 0;
1656
- for (const block of presentation.blocks) {
1657
- if (block.type !== "table") continue;
1658
- const rendered = buildSlackDataTableBlock(block, { cellCharacterCountOffset: cellCharacterCount });
1659
- if (!rendered) return false;
1660
- cellCharacterCount += countSlackDataTableCellCharacters(rendered);
1661
- }
1662
- return true;
1663
- }
1664
- /** True when native Slack rendering preserves every portable control. */
1665
- function canRenderSlackPresentation(presentation, options = {}) {
1666
- if (presentation.title && !isWithinSlackLimit(presentation.title.trim(), 150)) return false;
1667
- if (!canRenderSlackPresentationTables(presentation, options)) return false;
1668
- let dataVisualizationCount = options.dataVisualizationCountOffset ?? 0;
1669
- for (const block of presentation.blocks) {
1670
- if (block.type === "text" || block.type === "context") continue;
1671
- if (block.type === "buttons") {
1672
- let nativeButtonCount = 0;
1673
- if (!(block.buttons.every((button) => {
1674
- if (isSlackTextFallbackButton(button)) return true;
1675
- nativeButtonCount += 1;
1676
- if (!isWithinSlackLimit(button.label, 75)) return false;
1677
- const target = resolveSlackButtonTarget(button, options.questionOptionIndices);
1678
- return target ? target.kind === "link" ? isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : isWithinSlackLimit(target.value, 2e3) : false;
1679
- }) && nativeButtonCount <= 25)) return false;
1680
- continue;
1681
- }
1682
- if (block.type === "select") {
1683
- if (!(isWithinSlackLimit(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75) && block.options.length <= 100 && (!block.placeholder || isWithinSlackLimit(block.placeholder, 75)) && block.options.every((option) => {
1684
- if (!isWithinSlackLimit(option.label, 75)) return false;
1685
- const target = resolveSlackOptionTarget(option);
1686
- return target ? isRenderableSlackOption({
1687
- label: option.label,
1688
- ...target
1689
- }) : false;
1690
- }) && new Set(block.options.map((option) => resolveSlackOptionTarget(option)?.kind)).size === 1)) return false;
1691
- continue;
1692
- }
1693
- if (block.type === "chart") {
1694
- if (dataVisualizationCount >= 2 || !canRenderSlackDataVisualization(block)) return false;
1695
- dataVisualizationCount += 1;
1696
- continue;
1697
- }
1698
- if (block.type === "table") continue;
1699
- }
1700
- return true;
1701
- }
1702
- function buildSlackPresentationSelectBlock(block, selectIndex) {
1703
- const options = block.options.flatMap((option) => {
1704
- const target = resolveSlackOptionTarget(option);
1705
- return target ? [{
1706
- label: option.label,
1707
- ...target
1708
- }] : [];
1709
- }).filter(isRenderableSlackOption).slice(0, 100);
1710
- const optionKinds = new Set(options.map((option) => option.kind));
1711
- return options.length > 0 && optionKinds.size === 1 ? {
1712
- type: "actions",
1713
- block_id: `openclaw_reply_select_${selectIndex}`,
1714
- elements: [{
1715
- type: "static_select",
1716
- action_id: options[0]?.kind === "approval" ? buildSlackApprovalSelectActionId(selectIndex) : options[0]?.kind === "callback" ? buildSlackCallbackSelectActionId(selectIndex) : buildSlackReplySelectActionId(selectIndex),
1717
- placeholder: {
1718
- type: "plain_text",
1719
- text: truncateSlackText(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75),
1720
- emoji: true
1721
- },
1722
- options: options.map((option) => ({
1723
- text: {
1724
- type: "plain_text",
1725
- text: truncateSlackText(option.label, 75),
1726
- emoji: true
1727
- },
1728
- value: option.value
1729
- }))
1730
- }]
1731
- } : void 0;
1732
- }
1733
- //#endregion
1734
1304
  //#region extensions/slack/src/limits.ts
1735
1305
  const SLACK_TEXT_LIMIT = 8e3;
1736
1306
  const SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT = 4e3;
1737
1307
  const SLACK_EDIT_TEXT_MAX_BYTES = 4e3;
1738
1308
  const SLACK_MESSAGE_TEXT_HARD_LIMIT = 4e4;
1739
1309
  //#endregion
1740
- //#region extensions/slack/src/authored-text.ts
1741
- function normalizeComparableSlackText(text) {
1742
- return text.trim().replace(/\s+/g, " ");
1743
- }
1744
- function isSlackAuthoredTextRepresentedInInteractive(text, interactive) {
1745
- return isSlackAuthoredTextRepresentedInFragments(text, interactive?.blocks.flatMap((block) => block.type === "text" ? [block.text] : []) ?? []);
1746
- }
1747
- function isSlackAuthoredTextRepresentedInFragments(text, rawFragments) {
1748
- const target = normalizeComparableSlackText(text);
1749
- const fragments = rawFragments.map(normalizeComparableSlackText).filter(Boolean);
1750
- for (let start = 0; start < fragments.length; start += 1) {
1751
- let combined = "";
1752
- for (let end = start; end < fragments.length; end += 1) {
1753
- combined = normalizeComparableSlackText(`${combined} ${fragments[end]}`);
1754
- if (combined === target) return true;
1755
- if (combined.length > target.length) break;
1756
- }
1757
- }
1758
- return false;
1759
- }
1760
- /** Resolve placement from producer facts, before accessibility text changes the payload text. */
1761
- function resolveSlackAuthoredTextPlacement(params) {
1762
- const text = normalizeOptionalString(params.text);
1763
- if (!text) return "none";
1764
- return params.renderedInBlocks || isSlackAuthoredTextRepresentedInFragments(text, params.renderedTextFragments ?? []) || isSlackAuthoredTextRepresentedInInteractive(text, params.interactive) ? "blocks" : "outside-blocks";
1765
- }
1766
- //#endregion
1767
1310
  //#region extensions/slack/src/blocks-fallback.ts
1768
1311
  const SLACK_SELECT_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1769
1312
  "static_select",
@@ -1981,324 +1524,109 @@ function appendSlackNativeDataPlainTextFallback(text, blocks) {
1981
1524
  return appendSlackNativeDataFallback(text, blocks, renderSlackNativeDataPlainTextBlock);
1982
1525
  }
1983
1526
  //#endregion
1984
- //#region extensions/slack/src/reply-blocks.ts
1985
- function parseSlackReplyBlockSegments(value) {
1986
- if (value === void 0) return;
1987
- if (!Array.isArray(value)) throw new Error("Slack rendered presentation segments must be an array");
1988
- return value.map((raw) => {
1989
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error("Slack rendered presentation segment must be an object");
1990
- const segment = raw;
1991
- if (segment.kind === "text" && typeof segment.text === "string" && segment.mrkdwn === false) return {
1992
- kind: "text",
1993
- text: segment.text,
1994
- mrkdwn: false
1995
- };
1996
- if (segment.kind === "blocks") {
1997
- const blocks = parseSlackBlocksInput(segment.blocks);
1998
- if (blocks?.length) return {
1999
- kind: "blocks",
2000
- blocks
2001
- };
2002
- }
2003
- throw new Error("Slack rendered presentation segment is invalid");
2004
- });
2005
- }
2006
- /** Convert compiled segments into ordered sender calls without re-inferring text placement. */
2007
- function resolveSlackReplyDeliveryMessages(params) {
2008
- const messages = [];
2009
- let outsideText = params.authoredTextPlacement === "outside-blocks" ? params.text?.trim() ?? "" : "";
2010
- for (const segment of params.segments) {
2011
- if (segment.kind === "text") {
2012
- const text = [outsideText, segment.text].filter(Boolean).join("\n\n");
2013
- outsideText = "";
2014
- if (text) messages.push({
2015
- text,
2016
- textIsSlackPlainText: true
2017
- });
2018
- continue;
2019
- }
2020
- const baseText = outsideText;
2021
- outsideText = "";
2022
- const text = buildSlackNativeDataAccessibilityText(baseText, segment.blocks) || buildSlackBlocksFallbackText(segment.blocks);
2023
- const authoredTextPlacement = baseText ? "outside-blocks" : params.authoredTextPlacement === "blocks" ? "blocks" : "none";
2024
- messages.push({
2025
- text,
2026
- blocks: segment.blocks,
2027
- authoredTextPlacement,
2028
- ...baseText ? { nativeDataFallbackBaseText: baseText } : {}
2029
- });
2030
- }
2031
- if (outsideText) messages.push({
2032
- text: outsideText,
2033
- authoredTextPlacement: "outside-blocks"
2034
- });
2035
- return messages;
2036
- }
2037
- function resolveSlackReplyText(payload, text = payload.text) {
2038
- const presentation = normalizeMessagePresentation(payload.presentation);
2039
- return presentation ? renderSlackMessagePresentationFallbackText({
2040
- text,
2041
- presentation
2042
- }) : text ?? "";
1527
+ //#region extensions/slack/src/detached-target-admission.ts
1528
+ function assertSlackDetachedTargetAllowed(accountId, teamId) {
1529
+ const installationKind = getSlackInstallationKind(accountId);
1530
+ if (installationKind && installationKind !== "workspace" && !teamId) throw new Error("unsupported_enterprise_slack_delivery: detached Slack operations require team:<team-id>:channel:<channel-id> or team:<team-id>:user:<user-id> until a workspace install is authenticated");
2043
1531
  }
2044
- function resolveSlackReplyRenderPlan(payload, text = payload.text) {
2045
- const hasStructuredContent = hasSlackReplyStructuredContent(payload);
2046
- const resolution = resolveSlackReplyBlockResolution({
2047
- ...payload,
2048
- text
2049
- }, { materializeAuthoredText: hasStructuredContent });
2050
- const messages = resolveSlackReplyDeliveryMessages({
2051
- authoredTextPlacement: resolution.authoredTextPlacement,
2052
- segments: resolution.segments,
2053
- text
2054
- });
2055
- if (messages.length <= 1) {
2056
- const [message] = messages;
2057
- const sourceText = text?.trim() ?? "";
2058
- const blocks = message?.authoredTextPlacement === "blocks" ? addPreviewVerbatimToAuthoredTextBlocks(message.blocks, sourceText) : message?.blocks;
2059
- let renderedText = message?.text ?? resolveSlackReplyText(payload, text);
2060
- let textIsSlackMrkdwn = Boolean(message && !message.textIsSlackPlainText && (message.authoredTextPlacement !== "outside-blocks" || message.nativeDataFallbackBaseText));
2061
- if (blocks?.length && sourceText) {
2062
- if (hasSlackNativeDataBlock(blocks)) {
2063
- renderedText = appendSlackNativeDataFallbackText(sourceText, blocks) || renderedText;
2064
- textIsSlackMrkdwn = true;
2065
- } else if (message?.authoredTextPlacement === "blocks") {
2066
- renderedText = sourceText;
2067
- textIsSlackMrkdwn = false;
2068
- }
1532
+ //#endregion
1533
+ //#region extensions/slack/src/conversation-binding-route.ts
1534
+ const slackRouteBindingConfigCache = /* @__PURE__ */ new WeakMap();
1535
+ function slackTargetDefaultKindForPeer(kind) {
1536
+ return kind === "direct" ? "user" : "channel";
1537
+ }
1538
+ function slackTargetKindMatchesPeer(peerKind, targetKind) {
1539
+ if (targetKind === "user") return peerKind === "direct";
1540
+ return peerKind === "channel" || peerKind === "group";
1541
+ }
1542
+ function normalizeSlackRouteBindingPeer(peer) {
1543
+ const rawId = peer.id.trim();
1544
+ if (!rawId || rawId === "*") return peer;
1545
+ const target = (() => {
1546
+ try {
1547
+ return parseSlackTarget(rawId, { defaultKind: slackTargetDefaultKindForPeer(peer.kind) });
1548
+ } catch {
1549
+ return;
2069
1550
  }
2070
- return {
2071
- mode: "single",
2072
- text: renderedText,
2073
- ...blocks ? { blocks } : {},
2074
- ...textIsSlackMrkdwn ? { textIsSlackMrkdwn: true } : {}
2075
- };
2076
- }
2077
- const blockPart = messages.find((message) => message.blocks?.length);
2078
- return {
2079
- mode: "split",
2080
- fallbackText: messages.map((message) => message.text).filter(Boolean).join("\n\n"),
2081
- ...blockPart ? { blockPart: {
2082
- text: blockPart.text,
2083
- blocks: blockPart.blocks
2084
- } } : {}
1551
+ })();
1552
+ if (!target || !slackTargetKindMatchesPeer(peer.kind, target.kind)) return peer;
1553
+ const normalizedId = target.teamId ? `team:${target.teamId}:${target.kind}:${target.id}` : target.id;
1554
+ return normalizedId === peer.id ? peer : {
1555
+ ...peer,
1556
+ id: normalizedId
2085
1557
  };
2086
1558
  }
2087
- function readSlackChannelBlocks(payload) {
2088
- const slackData = payload.channelData?.slack;
2089
- if (!slackData || typeof slackData !== "object" || Array.isArray(slackData)) return [];
2090
- return parseSlackBlocksInput(slackData.blocks) ?? [];
2091
- }
2092
- function hasSlackReplyStructuredContent(payload) {
2093
- return Boolean(readSlackChannelBlocks(payload).length || normalizeMessagePresentation(payload.presentation) || payload.interactive?.blocks.length);
2094
- }
2095
- function renderSlackAuthoredTextFragments(blocks) {
2096
- return blocks.flatMap((block) => {
2097
- if (block.type === "actions") return [];
2098
- const text = renderSlackBlockFallbackText(block, { nativeDataFormat: "plain" });
2099
- return text ? [text] : [];
2100
- });
2101
- }
2102
- function buildSlackAuthoredTextBlocks(text) {
2103
- return markdownToSlackMrkdwnChunks(text, SLACK_SECTION_TEXT_MAX).map((chunk) => ({
2104
- type: "section",
2105
- text: {
2106
- type: "mrkdwn",
2107
- text: chunk,
2108
- verbatim: true
2109
- }
2110
- }));
2111
- }
2112
- function addPreviewVerbatimToAuthoredTextBlocks(blocks, sourceText) {
2113
- if (!blocks?.length || !sourceText) return blocks;
2114
- const authoredChunks = new Set(markdownToSlackMrkdwnChunks(sourceText, SLACK_SECTION_TEXT_MAX));
2115
- return blocks.map((block) => {
2116
- const text = block.text;
2117
- if (block.type !== "section" || text?.type !== "mrkdwn" || typeof text.text !== "string" || !authoredChunks.has(text.text)) return block;
1559
+ function normalizeSlackRouteBindingConfig(cfg) {
1560
+ const bindings = cfg.bindings;
1561
+ const cached = slackRouteBindingConfigCache.get(cfg);
1562
+ if (cached && cached.bindingsRef === bindings) return cached.normalizedCfg;
1563
+ if (!Array.isArray(bindings)) return cfg;
1564
+ let changed = false;
1565
+ const normalizedBindings = bindings.map((binding) => {
1566
+ if (binding.type === "acp" || binding.match.channel.trim().toLowerCase() !== "slack") return binding;
1567
+ const peer = binding.match.peer;
1568
+ if (!peer) return binding;
1569
+ const normalizedPeer = normalizeSlackRouteBindingPeer(peer);
1570
+ if (normalizedPeer === peer) return binding;
1571
+ changed = true;
2118
1572
  return {
2119
- ...block,
2120
- text: {
2121
- ...text,
2122
- verbatim: true
1573
+ ...binding,
1574
+ match: {
1575
+ ...binding.match,
1576
+ peer: normalizedPeer
2123
1577
  }
2124
1578
  };
2125
1579
  });
2126
- }
2127
- function readLastBlockSegment(segments) {
2128
- const last = segments.at(-1);
2129
- return last?.kind === "blocks" ? last.blocks : [];
2130
- }
2131
- function readAllNativeBlocks(segments) {
2132
- return segments.flatMap((segment) => segment.kind === "blocks" ? segment.blocks : []);
2133
- }
2134
- function appendTextSegment(segments, text) {
2135
- const trimmed = text.trim();
2136
- if (!trimmed) return;
2137
- const last = segments.at(-1);
2138
- if (last?.kind === "text") {
2139
- last.text = `${last.text}\n\n${trimmed}`;
2140
- return;
2141
- }
2142
- segments.push({
2143
- kind: "text",
2144
- text: trimmed,
2145
- mrkdwn: false
2146
- });
2147
- }
2148
- function appendBlockSegment(segments, blocks, startNew = false) {
2149
- let shouldStartNew = startNew;
2150
- for (const block of blocks) {
2151
- const last = segments.at(-1);
2152
- if (!shouldStartNew && last?.kind === "blocks" && last.blocks.length < 50) last.blocks.push(block);
2153
- else segments.push({
2154
- kind: "blocks",
2155
- blocks: [block]
2156
- });
2157
- shouldStartNew = false;
2158
- }
2159
- }
2160
- function resolvePresentationRenderOptions(segments, mode) {
2161
- const allOffsets = resolveSlackBlockOffsets(readAllNativeBlocks(segments));
2162
- return {
2163
- ...mode === "current" ? resolveSlackBlockOffsets(readLastBlockSegment(segments)) : {},
2164
- buttonIndexOffset: allOffsets.buttonIndexOffset,
2165
- selectIndexOffset: allOffsets.selectIndexOffset
2166
- };
2167
- }
2168
- function renderNativePresentation(presentation, options) {
2169
- if (!canRenderSlackPresentation(presentation, options)) return;
2170
- const blocks = buildSlackPresentationBlocks(presentation, options);
2171
- return blocks.length > 0 ? blocks : void 0;
2172
- }
2173
- function appendPresentationPart(segments, presentation, questionOptionIndices) {
2174
- const currentBlocks = readLastBlockSegment(segments);
2175
- const currentRendered = renderNativePresentation(presentation, {
2176
- ...resolvePresentationRenderOptions(segments, "current"),
2177
- questionOptionIndices
2178
- });
2179
- if (currentRendered && currentBlocks.length + currentRendered.length <= 50) {
2180
- appendBlockSegment(segments, currentRendered);
2181
- return;
2182
- }
2183
- const freshRendered = renderNativePresentation(presentation, {
2184
- ...resolvePresentationRenderOptions(segments, "new-message"),
2185
- questionOptionIndices
2186
- });
2187
- if (freshRendered) {
2188
- appendBlockSegment(segments, freshRendered, true);
2189
- return;
2190
- }
2191
- appendTextSegment(segments, renderMessagePresentationFallbackText({ presentation }));
2192
- }
2193
- const SLACK_BUTTON_CONTROL_ACTION_IDS = [
2194
- SLACK_APPROVAL_BUTTON_ACTION_ID,
2195
- SLACK_CALLBACK_BUTTON_ACTION_ID,
2196
- SLACK_QUESTION_BUTTON_ACTION_ID,
2197
- SLACK_REPLY_BUTTON_ACTION_ID,
2198
- SLACK_REPLY_LINK_ACTION_ID
2199
- ];
2200
- const SLACK_SELECT_CONTROL_ACTION_IDS = [
2201
- SLACK_APPROVAL_SELECT_ACTION_ID,
2202
- SLACK_CALLBACK_SELECT_ACTION_ID,
2203
- SLACK_REPLY_SELECT_ACTION_ID
2204
- ];
2205
- function readGeneratedSlackControlRowKey(block) {
2206
- const record = block;
2207
- if (record.type !== "actions" || typeof record.block_id !== "string") return;
2208
- const expectedElementType = /^openclaw_reply_buttons_[1-9]\d*$/.test(record.block_id) ? "button" : /^openclaw_reply_select_[1-9]\d*$/.test(record.block_id) ? "static_select" : void 0;
2209
- if (!expectedElementType || !Array.isArray(record.elements) || record.elements.length === 0) return;
2210
- const actionIds = expectedElementType === "button" ? SLACK_BUTTON_CONTROL_ACTION_IDS : SLACK_SELECT_CONTROL_ACTION_IDS;
2211
- const elements = record.elements.map((element) => {
2212
- if (!element || typeof element !== "object" || Array.isArray(element)) return;
2213
- const { action_id: actionId, ...content } = element;
2214
- const actionFamily = typeof actionId === "string" ? actionIds.find((candidate) => actionId.startsWith(`${candidate}:`)) : void 0;
2215
- return actionFamily && content.type === expectedElementType ? [actionFamily, content] : void 0;
2216
- });
2217
- return elements.some((element) => element === void 0) ? void 0 : JSON.stringify(elements);
2218
- }
2219
- function subtractMirroredSlackControlRows(params) {
2220
- const remainingMirrors = /* @__PURE__ */ new Map();
2221
- for (const block of params.presentationBlocks) {
2222
- const key = readGeneratedSlackControlRowKey(block);
2223
- if (key) remainingMirrors.set(key, (remainingMirrors.get(key) ?? 0) + 1);
2224
- }
2225
- return params.interactiveBlocks.filter((block) => {
2226
- const key = readGeneratedSlackControlRowKey(block);
2227
- const remaining = key ? remainingMirrors.get(key) ?? 0 : 0;
2228
- if (!key || remaining === 0) return true;
2229
- remainingMirrors.set(key, remaining - 1);
2230
- return false;
1580
+ const normalizedCfg = changed ? {
1581
+ ...cfg,
1582
+ bindings: normalizedBindings
1583
+ } : cfg;
1584
+ slackRouteBindingConfigCache.set(cfg, {
1585
+ bindingsRef: bindings,
1586
+ normalizedCfg
2231
1587
  });
1588
+ return normalizedCfg;
2232
1589
  }
2233
- /**
2234
- * Resolve reply content into transport-order segments. Each blocks segment is
2235
- * one Slack message; text segments carry complete fallback content between it.
2236
- */
2237
- function resolveSlackReplyBlockResolution(payload, options = {}) {
2238
- const segments = [];
2239
- const channelBlocks = readSlackChannelBlocks(payload);
2240
- let compiledChannelBlocks = channelBlocks;
2241
- let authoredTextKnownInBlocks = false;
2242
- if (options.materializeAuthoredText) {
2243
- const rawTextFragments = renderSlackAuthoredTextFragments(channelBlocks);
2244
- const initialPlacement = resolveSlackAuthoredTextPlacement({
2245
- text: payload.text,
2246
- interactive: payload.interactive,
2247
- renderedTextFragments: rawTextFragments
2248
- });
2249
- authoredTextKnownInBlocks = initialPlacement === "blocks";
2250
- const text = normalizeOptionalString(payload.text);
2251
- if (text && initialPlacement === "outside-blocks") {
2252
- const textBlocks = buildSlackAuthoredTextBlocks(text);
2253
- if (resolveSlackAuthoredTextPlacement({
2254
- text: renderSlackAuthoredTextFragments(textBlocks).join(" "),
2255
- renderedTextFragments: rawTextFragments
2256
- }) !== "blocks") compiledChannelBlocks = [...channelBlocks, ...textBlocks];
2257
- authoredTextKnownInBlocks = true;
1590
+ function resolveSlackConversationBindingRoute(params) {
1591
+ const boundThreadRoute = params.bindingsEnabled && params.runtimeBindingThreadId ? resolveRuntimeConversationBindingRoute({
1592
+ route: params.route,
1593
+ touchBinding: params.touchBinding,
1594
+ conversation: {
1595
+ channel: "slack",
1596
+ accountId: params.accountId,
1597
+ conversationId: params.runtimeBindingThreadId,
1598
+ parentConversationId: params.baseConversationId
1599
+ }
1600
+ }) : null;
1601
+ const runtimeRoute = !params.bindingsEnabled ? {
1602
+ bindingOwnerAvailable: true,
1603
+ route: params.route,
1604
+ bindingRecord: null,
1605
+ boundSessionKey: void 0
1606
+ } : boundThreadRoute?.boundSessionKey || boundThreadRoute?.bindingRecord ? boundThreadRoute : resolveRuntimeConversationBindingRoute({
1607
+ route: params.route,
1608
+ touchBinding: params.touchBinding,
1609
+ conversation: {
1610
+ channel: "slack",
1611
+ accountId: params.accountId,
1612
+ conversationId: params.baseConversationId
2258
1613
  }
2259
- }
2260
- if (compiledChannelBlocks.length > 0) appendBlockSegment(segments, compiledChannelBlocks);
2261
- const presentation = normalizeMessagePresentation(payload.presentation);
2262
- const questionOptionIndices = resolveAskUserQuestionOptionIndices(payload);
2263
- const presentationBlockOffset = readAllNativeBlocks(segments).length;
2264
- if (presentation?.title) appendPresentationPart(segments, {
2265
- title: presentation.title,
2266
- blocks: []
2267
- }, questionOptionIndices);
2268
- for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] }, questionOptionIndices);
2269
- const renderedPresentationBlocks = readAllNativeBlocks(segments).slice(presentationBlockOffset);
2270
- appendBlockSegment(segments, subtractMirroredSlackControlRows({
2271
- interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive, {
2272
- ...resolveSlackBlockOffsets(readAllNativeBlocks(segments)),
2273
- questionOptionIndices
2274
- }),
2275
- presentationBlocks: renderedPresentationBlocks
2276
- }));
2277
- const renderedTextFragments = segments.flatMap((segment) => {
2278
- if (segment.kind === "text") return [segment.text];
2279
- return renderSlackAuthoredTextFragments(segment.blocks);
2280
- });
2281
- const authoredTextPlacement = resolveSlackAuthoredTextPlacement({
2282
- text: payload.text,
2283
- interactive: payload.interactive,
2284
- renderedTextFragments
2285
1614
  });
1615
+ const configuredRoute = params.bindingsEnabled && !runtimeRoute.boundSessionKey && !runtimeRoute.bindingRecord ? resolveConfiguredBindingRoute({
1616
+ cfg: params.cfg,
1617
+ route: params.route,
1618
+ conversation: {
1619
+ channel: "slack",
1620
+ accountId: params.accountId,
1621
+ conversationId: params.baseConversationId
1622
+ }
1623
+ }) : null;
2286
1624
  return {
2287
- authoredTextPlacement: authoredTextKnownInBlocks ? "blocks" : authoredTextPlacement,
2288
- segments
1625
+ runtimeRoute,
1626
+ configuredRoute,
1627
+ route: runtimeRoute.boundSessionKey ? runtimeRoute.route : configuredRoute?.route ?? params.route
2289
1628
  };
2290
1629
  }
2291
- /** Return the single-message native shape when no ordered text fallback is required. */
2292
- function resolveSlackReplyBlocks(payload) {
2293
- const { segments } = resolveSlackReplyBlockResolution(payload);
2294
- return segments.length === 1 && segments[0]?.kind === "blocks" ? segments[0].blocks : void 0;
2295
- }
2296
- //#endregion
2297
- //#region extensions/slack/src/detached-target-admission.ts
2298
- function assertSlackDetachedTargetAllowed(accountId, teamId) {
2299
- const installationKind = getSlackInstallationKind(accountId);
2300
- if (installationKind && installationKind !== "workspace" && !teamId) throw new Error("unsupported_enterprise_slack_delivery: detached Slack operations require team:<team-id>:channel:<channel-id> or team:<team-id>:user:<user-id> until a workspace install is authenticated");
2301
- }
2302
1630
  //#endregion
2303
1631
  //#region extensions/slack/src/monitor/workspace-routing.ts
2304
1632
  function resolveSlackEnterpriseMainDmSessionKey(params) {
@@ -2366,4 +1694,46 @@ function resolveSlackGroupToolPolicy(params) {
2366
1694
  });
2367
1695
  }
2368
1696
  //#endregion
2369
- export { renderSlackMessagePresentationFallbackText as $, SLACK_MESSAGE_TEXT_HARD_LIMIT as A, SLACK_PRIVATE_ACTION_DELIVERY_RESULT as At, SLACK_REPLY_BUTTON_ACTION_ID as B, isSlackNativeResponseUrlRejection as C, isSlackApprovalAuthorizedSender as Ct, renderSlackBlockFallbackText as D, normalizeSlackApproverId as Dt, buildSlackCompleteBlocksFallbackText as E, isSlackExecApprovalClientEnabled as Et, canRenderSlackPresentation as F, isSlackCallbackActionId as G, SLACK_REPLY_SELECT_ACTION_ID as H, countSlackTextUtf8Bytes as I, decodeSlackQuestionAction as J, isSlackQuestionActionId as K, truncateSlackText as L, SLACK_TEXT_LIMIT as M, buildSlackInteractiveBlocks as N, resolveSlackAuthoredTextPlacement as O, resolveSlackExecApprovalTarget as Ot, buildSlackPresentationBlocks as P, normalizeSlackOutboundText as Q, truncateSlackTextByUtf8Bytes as R, isSlackInvalidBlocksResponse as S, getSlackApprovalApproversForTeam as St, buildSlackBlocksFallbackText as T, isSlackExecApprovalAuthorizedSender as Tt, SLACK_SESSION_LINK_ACTION_ID as U, SLACK_REPLY_LINK_ACTION_ID as V, isSlackApprovalActionId as W, chunkSlackMrkdwnText as X, resolveSlackQuestionAction as Y, markdownToSlackMrkdwnChunks as Z, appendSlackNativeDataPlainTextFallback as _, shouldHandleSlackPluginViaForwardingSession as _t, qualifySlackConversationId as a, SLACK_MAX_BLOCKS as at, hasSlackNativeDataBlock as b, isSlackWorkspaceInstallation as bt, assertSlackDetachedTargetAllowed as c, hasSlackPluginApprovers as ct, resolveSlackReplyBlockResolution as d, normalizeSlackOriginTarget as dt, escapeSlackMrkdwn as et, resolveSlackReplyBlocks as f, resolveEnterpriseApprovalTeamId as ft, appendSlackNativeDataFallbackText as g, shouldHandleSlackNativeApprovalRequest as gt, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as h, resolveTurnSourceSlackOriginTarget as ht, resolveSlackGroupToolPolicy as i, SLACK_SECTION_TEXT_MAX as it, SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT as j, resolveSlackAutoThreadId as jt, SLACK_EDIT_TEXT_MAX_BYTES as k, shouldSuppressLocalSlackExecApprovalPrompt as kt, hasSlackReplyStructuredContent as l, isSlackAnyNativeApprovalClientEnabled as lt, resolveSlackReplyRenderPlan as m, resolveSlackFallbackOriginTarget as mt, buildSlackChannelPolicyScope as n, decodeSlackApprovalAction as nt, qualifySlackRoutePeerId as o, parseSlackBlocksInput as ot, resolveSlackReplyDeliveryMessages as p, resolveSessionSlackOriginTarget as pt, resolveSlackQuestionActionIds as q, resolveSlackGroupRequireMention as r, SLACK_PRESENTATION_CAPABILITIES as rt, resolveSlackEnterpriseMainDmSessionKey as s, validateSlackBlocksArray as st, buildSlackChannelIdCandidates as t, SLACK_APPROVAL_HEADER_BLOCK_ID as tt, parseSlackReplyBlockSegments as u, normalizeSlackForwardTarget as ut, buildSlackNativeDataAccessibilityText as v, slackTargetsMatch as vt, stripSlackNativeDataBlocks as w, getSlackExecApprovalApprovers as wt, isSlackInvalidBlocksError as x, registerSlackInstallationState as xt, createSlackNativeDataBaseTextConsumer as y, getSlackInstallationKind as yt, SLACK_QUESTION_FINALIZATION_BLOCKS as z };
1697
+ //#region extensions/slack/src/session-status.ts
1698
+ const MISSING_STOP_SUBSCRIPTION = "missing_agent_session_stopped_event_subscription";
1699
+ let warnedMissingStopSubscription = false;
1700
+ async function setSlackSessionStatus(params) {
1701
+ if (!params.threadTs) return { ok: false };
1702
+ const request = {
1703
+ channel_id: params.channelId,
1704
+ thread_ts: params.threadTs,
1705
+ status: params.status,
1706
+ ...params.token ? { token: params.token } : {},
1707
+ ...params.title !== void 0 ? { title: truncateUtf16Safe(params.title, 200) } : {}
1708
+ };
1709
+ try {
1710
+ const response = await params.client.apiCall("agents.sessions.setStatus", request);
1711
+ if (!warnedMissingStopSubscription && (response.warning === MISSING_STOP_SUBSCRIPTION || response.response_metadata?.warnings?.includes(MISSING_STOP_SUBSCRIPTION))) {
1712
+ warnedMissingStopSubscription = true;
1713
+ (params.runtime ?? defaultRuntime).log?.(warn("Slack's Stop button is unavailable until the app subscribes to agent_session_stopped. See https://docs.openclaw.ai/channels/slack#additional-manifest-settings"));
1714
+ }
1715
+ return response.ok ? {
1716
+ ok: true,
1717
+ title: response.title
1718
+ } : { ok: false };
1719
+ } catch (error) {
1720
+ logVerbose(`slack status update failed for channel ${params.channelId}: ${formatSlackError(error)}`);
1721
+ return { ok: false };
1722
+ }
1723
+ }
1724
+ async function renameSlackSession(params) {
1725
+ const request = {
1726
+ channel_id: params.channelId,
1727
+ thread_ts: params.threadTs,
1728
+ title: truncateUtf16Safe(params.title, 200),
1729
+ ...params.token ? { token: params.token } : {}
1730
+ };
1731
+ try {
1732
+ return (await params.client.apiCall("agents.sessions.rename", request)).ok;
1733
+ } catch (error) {
1734
+ logVerbose(`slack session rename failed for channel ${params.channelId}: ${formatSlackError(error)}`);
1735
+ return false;
1736
+ }
1737
+ }
1738
+ //#endregion
1739
+ export { SLACK_DATA_TABLE_AGGREGATE_CELL_CHARACTERS_MAX as $, countSlackTextUtf8Bytes as A, shouldSuppressLocalSlackExecApprovalPrompt as At, SLACK_REPLY_LINK_ACTION_ID as B, buildSlackBlocksFallbackText as C, getSlackApprovalApproversForTeam as Ct, SLACK_MESSAGE_TEXT_HARD_LIMIT as D, isSlackExecApprovalClientEnabled as Dt, SLACK_EDIT_TEXT_MAX_BYTES as E, isSlackExecApprovalAuthorizedSender as Et, SLACK_CALLBACK_BUTTON_ACTION_ID as F, isSlackQuestionActionId as G, SLACK_SESSION_LINK_ACTION_ID as H, SLACK_CALLBACK_SELECT_ACTION_ID as I, markdownToSlackMrkdwnChunks as J, resolveSlackQuestionActionIds as K, SLACK_QUESTION_BUTTON_ACTION_ID as L, truncateSlackTextByUtf8Bytes as M, resolveSlackAutoThreadId as Mt, SLACK_APPROVAL_BUTTON_ACTION_ID as N, resolveSlackReplyToMode as Nt, SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT as O, normalizeSlackApproverId as Ot, SLACK_APPROVAL_SELECT_ACTION_ID as P, hasSlackDataVisualizationBlock as Q, SLACK_QUESTION_FINALIZATION_BLOCKS as R, stripSlackNativeDataBlocks as S, registerSlackInstallationState as St, renderSlackBlockFallbackText as T, getSlackExecApprovalApprovers as Tt, isSlackApprovalActionId as U, SLACK_REPLY_SELECT_ACTION_ID as V, isSlackCallbackActionId as W, buildSlackDataVisualizationBlock as X, normalizeSlackOutboundText as Y, canRenderSlackDataVisualization as Z, createSlackNativeDataBaseTextConsumer as _, shouldHandleSlackNativeApprovalRequest as _t, resolveSlackGroupRequireMention as a, escapeSlackMrkdwn as at, isSlackInvalidBlocksResponse as b, getSlackInstallationKind as bt, qualifySlackRoutePeerId as c, validateSlackBlocksArray as ct, resolveSlackConversationBindingRoute as d, normalizeSlackForwardTarget as dt, buildSlackDataTableBlock as et, assertSlackDetachedTargetAllowed as f, normalizeSlackOriginTarget as ft, buildSlackNativeDataAccessibilityText as g, resolveTurnSourceSlackOriginTarget as gt, appendSlackNativeDataPlainTextFallback as h, resolveSlackFallbackOriginTarget as ht, buildSlackChannelPolicyScope as i, renderSlackMessagePresentationFallbackText as it, truncateSlackText as j, SLACK_PRIVATE_ACTION_DELIVERY_RESULT as jt, SLACK_TEXT_LIMIT as k, resolveSlackExecApprovalTarget as kt, resolveSlackEnterpriseMainDmSessionKey as l, hasSlackPluginApprovers as lt, appendSlackNativeDataFallbackText as m, resolveSessionSlackOriginTarget as mt, setSlackSessionStatus as n, countSlackDataTableCellCharacters as nt, resolveSlackGroupToolPolicy as o, SLACK_MAX_BLOCKS as ot, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as p, resolveEnterpriseApprovalTeamId as pt, chunkSlackMrkdwnText as q, buildSlackChannelIdCandidates as r, renderSlackMessagePresentationChartFallbackText as rt, qualifySlackConversationId as s, parseSlackBlocksInput as st, renameSlackSession as t, countSlackDataTableBlocksCellCharacters as tt, normalizeSlackRouteBindingConfig as u, isSlackAnyNativeApprovalClientEnabled as ut, hasSlackNativeDataBlock as v, shouldHandleSlackPluginViaForwardingSession as vt, buildSlackCompleteBlocksFallbackText as w, isSlackApprovalAuthorizedSender as wt, isSlackNativeResponseUrlRejection as x, isSlackWorkspaceInstallation as xt, isSlackInvalidBlocksError as y, slackTargetsMatch as yt, SLACK_REPLY_BUTTON_ACTION_ID as z };