@openclaw/slack 2026.7.2-beta.2 → 2026.7.2-beta.3

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 (57) hide show
  1. package/dist/{account-configured-DzC407uv.js → account-configured-BwfXBo_F.js} +1 -1
  2. package/dist/{account-inspect-Di7ditqZ.js → account-inspect-Bvbtu3iH.js} +9 -2
  3. package/dist/account-inspect-api.js +1 -1
  4. package/dist/{accounts-BOJJiHSr.js → accounts-DQEbYKh9.js} +9 -0
  5. package/dist/accounts.runtime-BIKmJdtJ.js +2 -0
  6. package/dist/{action-runtime-Cee2ih0s.js → action-runtime-DqkRwO3Z.js} +10 -16
  7. package/dist/action-runtime.runtime-DEWOcFM4.js +2 -0
  8. package/dist/{actions-BZiuSTIq.js → actions-CF0tUY5q.js} +4 -4
  9. package/dist/{actions.runtime-DoD0-gxw.js → actions.runtime-hCbx4RXg.js} +1 -1
  10. package/dist/api.js +13 -14
  11. package/dist/{approval-handler.runtime-CUPtIM4k.js → approval-handler.runtime-Em8I1-8-.js} +2 -2
  12. package/dist/{channel-DaIiGUOp.js → channel-4-TRi1D6.js} +72 -40
  13. package/dist/channel-config-api.js +1 -1
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/{channel-type-Cfm6_6n1.js → channel-type-Cu1yjNg2.js} +3 -3
  16. package/dist/{channel.setup-C-mLz50O.js → channel.setup-CgkADtZg.js} +6 -4
  17. package/dist/{config-schema-xPSnK2VK.js → config-schema-XjJGfwQC.js} +6 -5
  18. package/dist/{directory-config-DRkFujwG.js → directory-config-Bv0lcUlH.js} +1 -1
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-D_yZhjgp.js → directory-live-CzUIB7th.js} +2 -2
  21. package/dist/{doctor-contract-DddfkMlF.js → doctor-contract-DKpe5VBr.js} +80 -12
  22. package/dist/doctor-contract-api.js +1 -1
  23. package/dist/{group-policy-85UWiriS.js → group-policy-Bw-65m3V.js} +67 -121
  24. package/dist/{interactive-replies-BilWUdcI.js → interactive-replies-Dm_t2R9S.js} +1 -1
  25. package/dist/interactive-replies-api.js +1 -1
  26. package/dist/{message-tool-api-CA9jZrCY.js → message-tool-api-C2pcf5du.js} +3 -3
  27. package/dist/message-tool-api.js +1 -1
  28. package/dist/{monitor-CalGciTs.js → monitor-CNFeF30h.js} +3 -3
  29. package/dist/{outbound-adapter-BiLKcnyH.js → outbound-adapter-CVi2uok0.js} +49 -5
  30. package/dist/{pipeline.runtime-DofAvTtb.js → pipeline.runtime-CTvokbty.js} +391 -279
  31. package/dist/{policy-BVs4LiSa.js → policy-b_dOPDCq.js} +1 -1
  32. package/dist/probe-Borhn9PQ.js +340 -0
  33. package/dist/{provider-CmeoUiIM.js → provider-B-HVL5ZE.js} +573 -306
  34. package/dist/{relay-source-DMmgtvg4.js → relay-source-Ea_P9VcO.js} +6 -11
  35. package/dist/{replies-CJJCp6qz.js → replies-B4bOdrYb.js} +3 -3
  36. package/dist/{resolve-channels-Rfts6POK.js → resolve-channels-KTc568SU.js} +1 -1
  37. package/dist/{resolve-users-y6wAxR8E.js → resolve-users-DeGJf1yp.js} +1 -1
  38. package/dist/{runtime-api-BGDyOt1D.js → runtime-api-BFfNpzDe.js} +1 -1
  39. package/dist/runtime-api.js +11 -11
  40. package/dist/{scopes-CuxNQZ6v.js → scopes-lx08L56K.js} +1 -2
  41. package/dist/{secret-contract-CMohXFWS.js → secret-contract-DxmvbxBF.js} +1 -0
  42. package/dist/secret-contract-api.js +1 -1
  43. package/dist/{send-DYp8ca-l.js → send-KuTDky7i.js} +28 -11
  44. package/dist/send.runtime-CXyxws1D.js +2 -0
  45. package/dist/{setup-core-CkwVLzFO.js → setup-core-CeiAVwQ3.js} +218 -53
  46. package/dist/setup-plugin-api.js +1 -1
  47. package/dist/{setup-surface-oSd3NX9J.js → setup-surface-DLA0vHXp.js} +23 -13
  48. package/dist/{shared-D9yz5Otg.js → shared-C4yVB0Q-.js} +55 -9
  49. package/dist/{slash-dispatch.runtime-CSja9VuD.js → slash-dispatch.runtime-BT-mMm-f.js} +1 -1
  50. package/npm-shrinkwrap.json +3 -3
  51. package/openclaw.plugin.json +66 -10
  52. package/package.json +4 -4
  53. package/dist/accounts.runtime-KvftRRek.js +0 -2
  54. package/dist/action-runtime.runtime-DZfd7IFr.js +0 -2
  55. package/dist/client-WIPAS3Yr.js +0 -160
  56. package/dist/probe-CN0ssfLN.js +0 -48
  57. package/dist/send.runtime-CJLxAt26.js +0 -2
@@ -18,6 +18,35 @@ function hasLegacySlackChannelAllowAlias(value) {
18
18
  if (!channels) return false;
19
19
  return Object.values(channels).some((channel) => Object.hasOwn(asObjectRecord(channel) ?? {}, "allow"));
20
20
  }
21
+ function hasLegacySlackThreadMentionPolicy(value) {
22
+ const thread = asObjectRecord(asObjectRecord(value)?.thread);
23
+ return Boolean(thread && Object.hasOwn(thread, "requireExplicitMention"));
24
+ }
25
+ function normalizeSlackThreadMentionPolicy(params) {
26
+ const thread = asObjectRecord(params.value.thread);
27
+ if (!thread || !Object.hasOwn(thread, "requireExplicitMention")) return {
28
+ value: params.value,
29
+ changed: false
30
+ };
31
+ const next = { ...params.value };
32
+ const nextThread = { ...thread };
33
+ const nextImplicitMentions = { ...asObjectRecord(params.value.implicitMentions) ?? {} };
34
+ const legacyValue = thread.requireExplicitMention;
35
+ const targetPath = `${params.pathPrefix}.implicitMentions.threadParticipation`;
36
+ if (nextImplicitMentions.threadParticipation !== void 0) params.changes.push(`Removed ${params.pathPrefix}.thread.requireExplicitMention (${targetPath} already set).`);
37
+ else if (typeof legacyValue === "boolean") {
38
+ nextImplicitMentions.threadParticipation = !legacyValue;
39
+ params.changes.push(`Moved ${params.pathPrefix}.thread.requireExplicitMention → ${targetPath} (${String(!legacyValue)}).`);
40
+ } else params.changes.push(`Removed invalid ${params.pathPrefix}.thread.requireExplicitMention value.`);
41
+ delete nextThread.requireExplicitMention;
42
+ if (Object.keys(nextThread).length > 0) next.thread = nextThread;
43
+ else delete next.thread;
44
+ if (Object.keys(nextImplicitMentions).length > 0) next.implicitMentions = nextImplicitMentions;
45
+ return {
46
+ value: next,
47
+ changed: true
48
+ };
49
+ }
21
50
  function normalizeSlackChannelAllowAliases(params) {
22
51
  let changed = false;
23
52
  const nextChannels = { ...params.channels };
@@ -40,6 +69,23 @@ function normalizeSlackChannelAllowAliases(params) {
40
69
  }
41
70
  const legacyConfigRules = [
42
71
  ...streamingAliasMigration.legacyConfigRules,
72
+ {
73
+ path: ["channels", "slack"],
74
+ message: "channels.slack.thread.requireExplicitMention is legacy; use channels.slack.implicitMentions.threadParticipation instead. Run \"openclaw doctor --fix\".",
75
+ match: hasLegacySlackThreadMentionPolicy
76
+ },
77
+ {
78
+ path: [
79
+ "channels",
80
+ "slack",
81
+ "accounts"
82
+ ],
83
+ message: "channels.slack.accounts.<id>.thread.requireExplicitMention is legacy; use channels.slack.accounts.<id>.implicitMentions.threadParticipation instead. Run \"openclaw doctor --fix\".",
84
+ match: (value) => {
85
+ const accounts = asObjectRecord(value);
86
+ return Boolean(accounts && Object.values(accounts).some((account) => hasLegacySlackThreadMentionPolicy(account)));
87
+ }
88
+ },
43
89
  {
44
90
  path: ["channels", "slack"],
45
91
  message: "channels.slack.channels.<id>.allow is legacy; use channels.slack.channels.<id>.enabled instead. Run \"openclaw doctor --fix\".",
@@ -72,6 +118,15 @@ function normalizeCompatibilityConfig({ cfg }) {
72
118
  };
73
119
  let updated = rawEntry;
74
120
  let changed = aliases.config !== cfg;
121
+ const normalizedThreadPolicy = normalizeSlackThreadMentionPolicy({
122
+ value: updated,
123
+ pathPrefix: "channels.slack",
124
+ changes
125
+ });
126
+ if (normalizedThreadPolicy.changed) {
127
+ updated = normalizedThreadPolicy.value;
128
+ changed = true;
129
+ }
75
130
  const channels = asObjectRecord(updated.channels);
76
131
  if (channels) {
77
132
  const normalized = normalizeSlackChannelAllowAliases({
@@ -92,20 +147,33 @@ function normalizeCompatibilityConfig({ cfg }) {
92
147
  let accountsChanged = false;
93
148
  const nextAccounts = { ...accounts };
94
149
  for (const [accountId, accountValue] of Object.entries(accounts)) {
95
- const account = asObjectRecord(accountValue);
96
- const channelEntries = asObjectRecord(account?.channels);
97
- if (!account || !channelEntries) continue;
98
- const normalized = normalizeSlackChannelAllowAliases({
99
- channels: channelEntries,
100
- pathPrefix: `channels.slack.accounts.${accountId}.channels`,
150
+ let account = asObjectRecord(accountValue);
151
+ if (!account) continue;
152
+ const normalizedAccountThreadPolicy = normalizeSlackThreadMentionPolicy({
153
+ value: account,
154
+ pathPrefix: `channels.slack.accounts.${accountId}`,
101
155
  changes
102
156
  });
103
- if (!normalized.changed) continue;
104
- nextAccounts[accountId] = {
105
- ...account,
106
- channels: normalized.channels
107
- };
108
- accountsChanged = true;
157
+ if (normalizedAccountThreadPolicy.changed) {
158
+ account = normalizedAccountThreadPolicy.value;
159
+ nextAccounts[accountId] = account;
160
+ accountsChanged = true;
161
+ }
162
+ const channelEntries = asObjectRecord(account.channels);
163
+ if (channelEntries) {
164
+ const normalized = normalizeSlackChannelAllowAliases({
165
+ channels: channelEntries,
166
+ pathPrefix: `channels.slack.accounts.${accountId}.channels`,
167
+ changes
168
+ });
169
+ if (normalized.changed) {
170
+ nextAccounts[accountId] = {
171
+ ...account,
172
+ channels: normalized.channels
173
+ };
174
+ accountsChanged = true;
175
+ }
176
+ }
109
177
  }
110
178
  if (accountsChanged) {
111
179
  updated = {
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-DddfkMlF.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-DKpe5VBr.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -1,21 +1,21 @@
1
- import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-BOJJiHSr.js";
1
+ import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-DQEbYKh9.js";
2
2
  import { i as parseSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-N6lHogYZ.js";
3
- import { t as isSlackPluginAccountConfigured } from "./account-configured-DzC407uv.js";
3
+ import { t as isSlackPluginAccountConfigured } from "./account-configured-BwfXBo_F.js";
4
4
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
5
- import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { normalizeMessageChannel } from "openclaw/plugin-sdk/routing";
7
7
  import { chunkTextForOutbound, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-chunking";
8
8
  import { createNativeApprovalChannelRouteGates, doesApprovalRequestMatchChannelAccount, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
9
9
  import { createChannelApprovalAuth, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
10
10
  import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, isChannelExecApprovalTargetRecipient, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
11
11
  import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
12
- import { normalizeMessagePresentation, reduceInteractiveReply, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
12
+ import { normalizeMessagePresentation, reduceLegacyInteractiveReply, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
13
13
  import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
14
14
  import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
15
+ import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
15
16
  import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
16
17
  import { compileAllowlist, resolveCompiledAllowlistMatch } from "openclaw/plugin-sdk/allow-from";
17
18
  import { normalizeHyphenSlug, normalizeStringEntries as normalizeStringEntries$1, normalizeStringEntriesLower as normalizeStringEntriesLower$1 } from "openclaw/plugin-sdk/string-normalization-runtime";
18
- import { redactSensitiveText } from "openclaw/plugin-sdk/logging-core";
19
19
  import { resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
20
20
  //#region extensions/slack/src/exec-approvals.ts
21
21
  function normalizeSlackUserLikeId(value) {
@@ -819,6 +819,39 @@ function renderSlackDataVisualizationMrkdwnFallbackText(value) {
819
819
  return typeof block.title === "string" && block.title.trim() ? escapeSlackMrkdwn(block.title.trim()) : void 0;
820
820
  }
821
821
  //#endregion
822
+ //#region extensions/slack/src/question-actions.ts
823
+ const SLACK_QUESTION_VALUE_PREFIX = "slq1:";
824
+ const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
825
+ function encodeSlackQuestionAction(action) {
826
+ if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
827
+ const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
828
+ return value.length <= 2e3 ? value : void 0;
829
+ }
830
+ function decodeSlackQuestionAction(value) {
831
+ if (typeof value !== "string" || value.length > 2e3) return null;
832
+ const match = /^slq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(value);
833
+ return match?.[1] && match[2] ? {
834
+ questionId: match[1],
835
+ optionIndex: Number(match[2])
836
+ } : null;
837
+ }
838
+ async function resolveSlackQuestionAction(params) {
839
+ let result;
840
+ try {
841
+ result = await (params.resolveQuestion ?? questionGatewayRuntime.resolveOption)({
842
+ cfg: params.cfg,
843
+ questionId: params.action.questionId,
844
+ optionIndex: params.action.optionIndex,
845
+ senderId: params.userId,
846
+ clientDisplayName: `Slack question (${params.accountId})`
847
+ });
848
+ } catch {
849
+ await params.respond("Could not submit this answer.").catch(() => {});
850
+ return;
851
+ }
852
+ await params.respond(result.status === "answered" ? "Answer submitted." : "This question was already answered.").catch(() => {});
853
+ }
854
+ //#endregion
822
855
  //#region extensions/slack/src/reply-action-ids.ts
823
856
  const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
824
857
  const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
@@ -827,6 +860,10 @@ const SLACK_CALLBACK_BUTTON_ACTION_ID = "openclaw:callback_button";
827
860
  const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
828
861
  const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
829
862
  const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
863
+ const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
864
+ function isSlackQuestionActionId(actionId) {
865
+ return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
866
+ }
830
867
  function isSlackApprovalActionId(actionId) {
831
868
  return actionId === "openclaw:approval_button" || actionId === "openclaw:approval_select" || actionId.startsWith(`openclaw:approval_button:`) || actionId.startsWith(`openclaw:approval_select:`);
832
869
  }
@@ -865,16 +902,29 @@ function buildSlackCallbackButtonActionId(buttonIndex, choiceIndex) {
865
902
  function buildSlackCallbackSelectActionId(selectIndex) {
866
903
  return `${SLACK_CALLBACK_SELECT_ACTION_ID}:${String(selectIndex)}`;
867
904
  }
905
+ function buildSlackQuestionButtonActionId(buttonIndex, choiceIndex) {
906
+ return `${SLACK_QUESTION_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
907
+ }
868
908
  function resolveSlackButtonStyle(style) {
869
909
  if (style === "primary" || style === "danger") return style;
870
910
  if (style === "success") return "primary";
871
911
  }
872
- function resolveSlackActionTarget(action) {
912
+ function resolveSlackActionTarget(action, optionIndex) {
873
913
  if (!action) return;
874
914
  if (action.type === "approval") return {
875
915
  kind: "approval",
876
916
  value: encodeSlackApprovalAction(action)
877
917
  };
918
+ if (action.type === "question") {
919
+ const value = optionIndex === void 0 ? void 0 : encodeSlackQuestionAction({
920
+ questionId: action.questionId,
921
+ optionIndex
922
+ });
923
+ return value ? {
924
+ kind: "question",
925
+ value
926
+ } : void 0;
927
+ }
878
928
  if (action.type === "url" || action.type === "web-app") {
879
929
  const url = normalizeOptionalString(action.url);
880
930
  return url ? {
@@ -895,10 +945,10 @@ function resolveSlackActionTarget(action) {
895
945
  value: command
896
946
  } : void 0;
897
947
  }
898
- function resolveSlackButtonTarget(button) {
948
+ function resolveSlackButtonTarget(button, optionIndex) {
899
949
  if (button.action !== void 0) {
900
950
  const action = resolveMessagePresentationButtonAction(button);
901
- return action ? resolveSlackActionTarget(action) : void 0;
951
+ return action ? resolveSlackActionTarget(action, optionIndex) : void 0;
902
952
  }
903
953
  const legacyUrl = normalizeOptionalString(button.url ?? button.webApp?.url ?? button.web_app?.url);
904
954
  if (legacyUrl && isWithinSlackLimit(legacyUrl, SLACK_BUTTON_URL_MAX)) return {
@@ -919,7 +969,7 @@ function resolveSlackOptionTarget(option) {
919
969
  if (option.action !== void 0) {
920
970
  const action = resolveMessagePresentationOptionAction(option);
921
971
  const target = action ? resolveSlackActionTarget(action) : void 0;
922
- return target?.kind === "link" ? void 0 : target;
972
+ return target?.kind === "link" || target?.kind === "question" ? void 0 : target;
923
973
  }
924
974
  const value = normalizeOptionalString(option.value);
925
975
  return value ? {
@@ -966,7 +1016,7 @@ function resolveSlackBlockOffsets(blocks) {
966
1016
  * @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
967
1017
  */
968
1018
  function buildSlackInteractiveBlocks(interactive, options = {}) {
969
- return reduceInteractiveReply(interactive, {
1019
+ return reduceLegacyInteractiveReply(interactive, {
970
1020
  blocks: [],
971
1021
  buttonIndex: options.buttonIndexOffset ?? 0,
972
1022
  selectIndex: options.selectIndexOffset ?? 0
@@ -985,12 +1035,12 @@ function buildSlackInteractiveBlocks(interactive, options = {}) {
985
1035
  }
986
1036
  if (block.type === "buttons") {
987
1037
  const elements = block.buttons.flatMap((button, choiceIndex) => {
988
- const target = resolveSlackButtonTarget(button);
1038
+ const target = resolveSlackButtonTarget(button, choiceIndex);
989
1039
  if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
990
1040
  const style = resolveSlackButtonStyle(button.style);
991
1041
  return [{
992
1042
  type: "button",
993
- action_id: target.kind === "link" ? buildSlackReplyLinkActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "approval" ? buildSlackApprovalButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "callback" ? buildSlackCallbackButtonActionId(state.buttonIndex + 1, choiceIndex) : buildSlackReplyButtonActionId(state.buttonIndex + 1, choiceIndex),
1043
+ action_id: target.kind === "link" ? buildSlackReplyLinkActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "approval" ? buildSlackApprovalButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "callback" ? buildSlackCallbackButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "question" ? buildSlackQuestionButtonActionId(state.buttonIndex + 1, choiceIndex) : buildSlackReplyButtonActionId(state.buttonIndex + 1, choiceIndex),
994
1044
  text: {
995
1045
  type: "plain_text",
996
1046
  text: truncateSlackText(button.label, 75),
@@ -1133,12 +1183,12 @@ function buildSlackPresentationChartBlock(block) {
1133
1183
  }
1134
1184
  function buildSlackPresentationButtonBlock(block, buttonIndex) {
1135
1185
  const elements = block.buttons.flatMap((button, choiceIndex) => {
1136
- const target = resolveSlackButtonTarget(button);
1186
+ const target = resolveSlackButtonTarget(button, choiceIndex);
1137
1187
  if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
1138
1188
  const style = resolveSlackButtonStyle(button.style);
1139
1189
  return [{
1140
1190
  type: "button",
1141
- action_id: target.kind === "link" ? buildSlackReplyLinkActionId(buttonIndex, choiceIndex) : target.kind === "approval" ? buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) : target.kind === "callback" ? buildSlackCallbackButtonActionId(buttonIndex, choiceIndex) : buildSlackReplyButtonActionId(buttonIndex, choiceIndex),
1191
+ 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),
1142
1192
  text: {
1143
1193
  type: "plain_text",
1144
1194
  text: truncateSlackText(button.label, 75),
@@ -1176,9 +1226,9 @@ function canRenderSlackPresentation(presentation, options = {}) {
1176
1226
  continue;
1177
1227
  }
1178
1228
  if (block.type === "buttons") {
1179
- if (!(block.buttons.length <= 25 && block.buttons.every((button) => {
1229
+ if (!(block.buttons.length <= 25 && block.buttons.every((button, choiceIndex) => {
1180
1230
  if (!isWithinSlackLimit(button.label, 75)) return false;
1181
- const target = resolveSlackButtonTarget(button);
1231
+ const target = resolveSlackButtonTarget(button, choiceIndex);
1182
1232
  return target ? target.kind === "link" ? isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : isWithinSlackLimit(target.value, 2e3) : false;
1183
1233
  }))) return false;
1184
1234
  continue;
@@ -2195,110 +2245,6 @@ function assertSlackDirectSendAllowed(account) {
2195
2245
  if (account.config.enterpriseOrgInstall === true) throw new Error("unsupported_enterprise_slack_delivery");
2196
2246
  }
2197
2247
  //#endregion
2198
- //#region extensions/slack/src/errors.ts
2199
- const NO_ERROR_DETAIL = "no error detail";
2200
- function redact(value) {
2201
- return redactSensitiveText(value);
2202
- }
2203
- function addStringDetail(details, label, value) {
2204
- if (typeof value !== "string") return;
2205
- const trimmed = redact(value.trim());
2206
- if (trimmed) details.push(label ? `${label}: ${trimmed}` : trimmed);
2207
- }
2208
- function addScalarDetail(details, label, value) {
2209
- if (typeof value === "string") {
2210
- addStringDetail(details, label, value);
2211
- return;
2212
- }
2213
- if (typeof value === "number" || typeof value === "boolean") details.push(`${label}: ${String(value)}`);
2214
- }
2215
- function addStringListDetail(details, label, value) {
2216
- if (!Array.isArray(value)) return;
2217
- const entries = value.flatMap((entry) => {
2218
- if (typeof entry !== "string") return [];
2219
- const trimmed = redact(entry.trim());
2220
- return trimmed ? [trimmed] : [];
2221
- });
2222
- if (entries.length) details.push(`${label}: ${entries.join(", ")}`);
2223
- }
2224
- function safeStringify(value) {
2225
- const seen = /* @__PURE__ */ new WeakSet();
2226
- try {
2227
- const result = JSON.stringify(value, (_key, nested) => {
2228
- if (typeof nested !== "object" || nested === null) return nested;
2229
- if (seen.has(nested)) return "[Circular]";
2230
- seen.add(nested);
2231
- return nested;
2232
- });
2233
- return result ? redact(result) : void 0;
2234
- } catch {
2235
- return;
2236
- }
2237
- }
2238
- function addSlackResponseMetadata(details, value) {
2239
- if (!isRecord(value)) return;
2240
- addStringListDetail(details, "scopes", value.scopes);
2241
- addStringListDetail(details, "accepted", value.acceptedScopes);
2242
- const messages = value.messages;
2243
- if (Array.isArray(messages)) for (const message of messages) addStringDetail(details, "slack message", message);
2244
- const warnings = value.warnings;
2245
- if (Array.isArray(warnings)) for (const warning of warnings) addStringDetail(details, "slack warning", warning);
2246
- }
2247
- function addSlackDataDetails(details, value) {
2248
- if (!isRecord(value)) return;
2249
- addScalarDetail(details, "slack error", value.error);
2250
- addScalarDetail(details, "needed", value.needed);
2251
- addScalarDetail(details, "provided", value.provided);
2252
- addSlackResponseMetadata(details, value.response_metadata);
2253
- }
2254
- function addRecordDetails(details, value) {
2255
- addScalarDetail(details, "code", value.code);
2256
- addScalarDetail(details, "status", value.status);
2257
- addScalarDetail(details, "statusCode", value.statusCode);
2258
- addScalarDetail(details, "statusMessage", value.statusMessage);
2259
- addScalarDetail(details, "retryAfter", value.retryAfter);
2260
- addScalarDetail(details, "errno", value.errno);
2261
- addScalarDetail(details, "syscall", value.syscall);
2262
- addScalarDetail(details, "hostname", value.hostname);
2263
- addScalarDetail(details, "type", value.type);
2264
- addStringDetail(details, "statusText", value.statusText);
2265
- addStringDetail(details, "body", value.body);
2266
- addSlackDataDetails(details, value.data);
2267
- if (isRecord(value.response)) {
2268
- addScalarDetail(details, "response status", value.response.status);
2269
- addStringDetail(details, "response statusText", value.response.statusText);
2270
- addSlackDataDetails(details, value.response.data);
2271
- }
2272
- }
2273
- function collectSlackErrorDetails(error) {
2274
- const details = [];
2275
- if (error === void 0 || error === null) return details;
2276
- if (typeof error === "string") {
2277
- addStringDetail(details, "", error);
2278
- return details;
2279
- }
2280
- if (error instanceof Error) {
2281
- addStringDetail(details, "", error.message || error.name);
2282
- if (error.cause !== void 0) {
2283
- const cause = formatSlackError(error.cause, "");
2284
- if (cause) details.push(`cause: ${cause}`);
2285
- }
2286
- }
2287
- if (isRecord(error)) {
2288
- addRecordDetails(details, error);
2289
- const fallback = safeStringify(error);
2290
- if (details.length === 0 && fallback && fallback !== "{}") details.push(fallback);
2291
- }
2292
- return details;
2293
- }
2294
- function formatSlackError(error, fallback = NO_ERROR_DETAIL) {
2295
- const details = collectSlackErrorDetails(error);
2296
- if (details.length > 0) return details.join("; ");
2297
- if (error === void 0 || error === null) return fallback;
2298
- if (typeof error === "string" && !error.trim()) return fallback;
2299
- return safeStringify(error) ?? fallback;
2300
- }
2301
- //#endregion
2302
2248
  //#region extensions/slack/src/group-policy.ts
2303
2249
  function buildSlackChannelPolicyScope(params) {
2304
2250
  const channels = params.channels ?? {};
@@ -2342,4 +2288,4 @@ function resolveSlackGroupToolPolicy(params) {
2342
2288
  });
2343
2289
  }
2344
2290
  //#endregion
2345
- export { hasSlackPluginApprovers as $, buildSlackBlocksFallbackText as A, truncateSlackText as B, createSlackNativeDataBaseTextConsumer as C, chunkSlackMrkdwnText as D, stripSlackNativeDataBlocks as E, SLACK_MESSAGE_TEXT_HARD_LIMIT as F, isSlackCallbackActionId as G, SLACK_REPLY_LINK_ACTION_ID as H, SLACK_TEXT_LIMIT as I, decodeSlackApprovalAction as J, renderSlackMessagePresentationFallbackText as K, buildSlackInteractiveBlocks as L, renderSlackBlockFallbackText as M, resolveSlackAuthoredTextPlacement as N, markdownToSlackMrkdwnChunks as O, SLACK_EDIT_TEXT_LIMIT as P, validateSlackBlocksArray as Q, buildSlackPresentationBlocks as R, buildSlackNativeDataAccessibilityText as S, isSlackInvalidBlocksError as T, SLACK_REPLY_SELECT_ACTION_ID as U, SLACK_REPLY_BUTTON_ACTION_ID as V, isSlackApprovalActionId as W, SLACK_MAX_BLOCKS as X, SLACK_PRESENTATION_CAPABILITIES as Y, parseSlackBlocksInput as Z, resolveSlackReplyDeliveryMessages as _, assertSlackDirectSendAllowed as a, resolveTurnSourceSlackOriginTarget as at, appendSlackNativeDataFallbackText as b, normalizeAllowListLower as c, slackTargetsMatch as ct, resolveSlackAllowListMatch as d, getSlackExecApprovalApprovers as dt, isSlackAnyNativeApprovalClientEnabled as et, resolveSlackUserAllowed as f, isSlackExecApprovalAuthorizedSender as ft, resolveSlackReplyBlocks as g, shouldSuppressLocalSlackExecApprovalPrompt as gt, resolveSlackReplyBlockResolution as h, resolveSlackExecApprovalTarget as ht, formatSlackError as i, resolveSlackFallbackOriginTarget as it, buildSlackCompleteBlocksFallbackText as j, normalizeSlackOutboundText as k, normalizeSlackAllowOwnerEntry as l, getSlackApprovalApprovers as lt, parseSlackReplyBlockSegments as m, normalizeSlackApproverId as mt, resolveSlackGroupRequireMention as n, normalizeSlackOriginTarget as nt, allowListMatches as o, shouldHandleSlackNativeApprovalRequest as ot, hasSlackReplyStructuredContent as p, isSlackExecApprovalClientEnabled as pt, escapeSlackMrkdwn as q, resolveSlackGroupToolPolicy as r, resolveSessionSlackOriginTarget as rt, normalizeAllowList as s, shouldHandleSlackPluginViaForwardingSession as st, buildSlackChannelPolicyScope as t, normalizeSlackForwardTarget as tt, normalizeSlackSlug as u, isSlackApprovalAuthorizedSender as ut, resolveSlackReplyRenderPlan as v, hasSlackNativeDataBlock as w, appendSlackNativeDataPlainTextFallback as x, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as y, canRenderSlackPresentation as z };
2291
+ export { parseSlackBlocksInput as $, buildSlackCompleteBlocksFallbackText as A, SLACK_REPLY_BUTTON_ACTION_ID as B, hasSlackNativeDataBlock as C, markdownToSlackMrkdwnChunks as D, chunkSlackMrkdwnText as E, SLACK_TEXT_LIMIT as F, isSlackQuestionActionId as G, SLACK_REPLY_SELECT_ACTION_ID as H, buildSlackInteractiveBlocks as I, renderSlackMessagePresentationFallbackText as J, decodeSlackQuestionAction as K, buildSlackPresentationBlocks as L, resolveSlackAuthoredTextPlacement as M, SLACK_EDIT_TEXT_LIMIT as N, normalizeSlackOutboundText as O, SLACK_MESSAGE_TEXT_HARD_LIMIT as P, SLACK_MAX_BLOCKS as Q, canRenderSlackPresentation as R, createSlackNativeDataBaseTextConsumer as S, stripSlackNativeDataBlocks as T, isSlackApprovalActionId as U, SLACK_REPLY_LINK_ACTION_ID as V, isSlackCallbackActionId as W, decodeSlackApprovalAction as X, escapeSlackMrkdwn as Y, SLACK_PRESENTATION_CAPABILITIES as Z, resolveSlackReplyRenderPlan as _, resolveSlackExecApprovalTarget as _t, allowListMatches as a, resolveSessionSlackOriginTarget as at, appendSlackNativeDataPlainTextFallback as b, normalizeSlackAllowOwnerEntry as c, shouldHandleSlackNativeApprovalRequest as ct, resolveSlackUserAllowed as d, getSlackApprovalApprovers as dt, validateSlackBlocksArray as et, hasSlackReplyStructuredContent as f, isSlackApprovalAuthorizedSender as ft, resolveSlackReplyDeliveryMessages as g, normalizeSlackApproverId as gt, resolveSlackReplyBlocks as h, isSlackExecApprovalClientEnabled as ht, assertSlackDirectSendAllowed as i, normalizeSlackOriginTarget as it, renderSlackBlockFallbackText as j, buildSlackBlocksFallbackText as k, normalizeSlackSlug as l, shouldHandleSlackPluginViaForwardingSession as lt, resolveSlackReplyBlockResolution as m, isSlackExecApprovalAuthorizedSender as mt, resolveSlackGroupRequireMention as n, isSlackAnyNativeApprovalClientEnabled as nt, normalizeAllowList as o, resolveSlackFallbackOriginTarget as ot, parseSlackReplyBlockSegments as p, getSlackExecApprovalApprovers as pt, resolveSlackQuestionAction as q, resolveSlackGroupToolPolicy as r, normalizeSlackForwardTarget as rt, normalizeAllowListLower as s, resolveTurnSourceSlackOriginTarget as st, buildSlackChannelPolicyScope as t, hasSlackPluginApprovers as tt, resolveSlackAllowListMatch as u, slackTargetsMatch as ut, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as v, shouldSuppressLocalSlackExecApprovalPrompt as vt, isSlackInvalidBlocksError as w, buildSlackNativeDataAccessibilityText as x, appendSlackNativeDataFallbackText as y, truncateSlackText as z };
@@ -1,4 +1,4 @@
1
- import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId } from "./accounts-BOJJiHSr.js";
1
+ import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId } from "./accounts-DQEbYKh9.js";
2
2
  import { normalizeLowercaseStringOrEmpty, normalizeStringEntries, normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  //#region extensions/slack/src/interactive-replies.ts
4
4
  const SLACK_BUTTON_MAX_ITEMS = 5;
@@ -1,2 +1,2 @@
1
- import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-BilWUdcI.js";
1
+ import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-Dm_t2R9S.js";
2
2
  export { compileSlackInteractiveReplies, isSlackInteractiveRepliesEnabled };
@@ -1,6 +1,6 @@
1
- import { a as resolveSlackAccount, t as listEnabledSlackAccounts } from "./accounts-BOJJiHSr.js";
1
+ import { a as resolveSlackAccount, t as listEnabledSlackAccounts } from "./accounts-DQEbYKh9.js";
2
2
  import { n as resolveSlackThreadTsValue, t as normalizeSlackThreadTsCandidate } from "./thread-ts-DUGhaYKq.js";
3
- import { n as isSlackInteractiveRepliesEnabled } from "./interactive-replies-BilWUdcI.js";
3
+ import { n as isSlackInteractiveRepliesEnabled } from "./interactive-replies-Dm_t2R9S.js";
4
4
  import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
5
5
  import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
6
6
  import { Type } from "typebox";
@@ -9,7 +9,7 @@ function listSlackMessageActions(cfg, accountId) {
9
9
  const accounts = (accountId ? [resolveSlackAccount({
10
10
  cfg,
11
11
  accountId
12
- })] : listEnabledSlackAccounts(cfg)).filter((account) => account.enabled && account.botTokenSource !== "none");
12
+ })] : listEnabledSlackAccounts(cfg)).filter((account) => account.enabled && (account.identity === "user" ? account.userTokenSource !== "none" : account.botTokenSource !== "none"));
13
13
  if (accounts.length === 0) return [];
14
14
  const isActionEnabled = (key, defaultValue = true) => {
15
15
  for (const account of accounts) if (createActionGate(account.actions ?? cfg.channels?.slack?.actions)(key, defaultValue)) return true;
@@ -1,2 +1,2 @@
1
- import { t as describeSlackMessageTool } from "./message-tool-api-CA9jZrCY.js";
1
+ import { t as describeSlackMessageTool } from "./message-tool-api-C2pcf5du.js";
2
2
  export { describeSlackMessageTool as describeMessageTool };
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { C as buildSlackSlashCommandMatcher, t as monitorSlackProvider } from "./provider-CmeoUiIM.js";
3
- import { t as isSlackChannelAllowedByPolicy } from "./policy-BVs4LiSa.js";
4
- import { o as resolveSlackThreadTs } from "./replies-CJJCp6qz.js";
2
+ import { S as buildSlackSlashCommandMatcher, t as monitorSlackProvider } from "./provider-B-HVL5ZE.js";
3
+ import { t as isSlackChannelAllowedByPolicy } from "./policy-b_dOPDCq.js";
4
+ import { o as resolveSlackThreadTs } from "./replies-B4bOdrYb.js";
5
5
  //#region extensions/slack/src/monitor.ts
6
6
  var monitor_exports = /* @__PURE__ */ __exportAll({
7
7
  buildSlackSlashCommandMatcher: () => buildSlackSlashCommandMatcher,
@@ -1,15 +1,16 @@
1
- import { I as SLACK_TEXT_LIMIT, N as resolveSlackAuthoredTextPlacement, Y as SLACK_PRESENTATION_CAPABILITIES, _ as resolveSlackReplyDeliveryMessages, h as resolveSlackReplyBlockResolution, m as parseSlackReplyBlockSegments } from "./group-policy-85UWiriS.js";
1
+ import { F as SLACK_TEXT_LIMIT, M as resolveSlackAuthoredTextPlacement, Y as escapeSlackMrkdwn, Z as SLACK_PRESENTATION_CAPABILITIES, g as resolveSlackReplyDeliveryMessages, m as resolveSlackReplyBlockResolution, p as parseSlackReplyBlockSegments } from "./group-policy-Bw-65m3V.js";
2
2
  import { n as resolveSlackThreadTsValue } from "./thread-ts-DUGhaYKq.js";
3
- import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-BilWUdcI.js";
3
+ import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-Dm_t2R9S.js";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
6
6
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
7
- import { normalizeMessagePresentation, resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
7
+ import { normalizeMessagePresentation, resolveLegacyInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
8
+ import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
8
9
  import { resolvePayloadMediaUrls, sendPayloadMediaSequenceAndFinalize, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
9
10
  import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
10
11
  //#region extensions/slack/src/outbound-adapter.ts
11
12
  const SLACK_RENDERED_PRESENTATION_PROVENANCE = Object.freeze({});
12
- const loadSlackSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-CJLxAt26.js"));
13
+ const loadSlackSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-CXyxws1D.js"));
13
14
  function resolveSlackSendIdentity(identity) {
14
15
  if (!identity) return;
15
16
  const username = normalizeOptionalString(identity.name);
@@ -143,7 +144,7 @@ const slackOutbound = {
143
144
  sendPayload: async (ctx) => {
144
145
  const payload = {
145
146
  ...ctx.payload,
146
- text: resolveInteractiveTextFallback({
147
+ text: resolveLegacyInteractiveTextFallback({
147
148
  text: ctx.payload.text,
148
149
  interactive: ctx.payload.interactive
149
150
  }) ?? ""
@@ -222,6 +223,49 @@ const slackOutbound = {
222
223
  }
223
224
  }));
224
225
  },
226
+ afterDeliverPayload: async ({ cfg, target, payload, results }) => {
227
+ const questionId = questionGatewayRuntime.readAskUserQuestionId(payload);
228
+ const slackData = payload.channelData?.slack;
229
+ if (!questionId || slackData?.renderedPresentationProvenance !== SLACK_RENDERED_PRESENTATION_PROVENANCE) return;
230
+ const segments = parseSlackReplyBlockSegments(slackData.renderedPresentationSegments);
231
+ const placement = readSlackAuthoredTextPlacement(slackData.authoredTextPlacement);
232
+ if (!segments || !placement) return;
233
+ const deliveryMessages = resolveSlackReplyDeliveryMessages({
234
+ authoredTextPlacement: placement,
235
+ segments,
236
+ text: payload.text
237
+ });
238
+ const blockMessageIndex = deliveryMessages.findIndex((message) => message.blocks?.some((block) => block.type === "actions"));
239
+ const deliveryMessage = deliveryMessages[blockMessageIndex];
240
+ const result = results[blockMessageIndex] ?? results.find((candidate) => candidate.channel === "slack");
241
+ const deliveryBlocks = deliveryMessage?.blocks;
242
+ if (!deliveryMessage || !deliveryBlocks || !result?.messageId) return;
243
+ const channelId = result.channelId;
244
+ if (!channelId) return;
245
+ questionGatewayRuntime.registerChannelDelivery({
246
+ questionId,
247
+ deliveryId: `slack:${target.accountId ?? "default"}:${channelId}:${result.messageId}`,
248
+ finalize: async (statusLine) => {
249
+ const { updateMessageSlack } = await loadSlackSendRuntime();
250
+ const escapedStatusLine = escapeSlackMrkdwn(statusLine);
251
+ const blocks = [...deliveryBlocks.filter((block) => block.type !== "actions"), {
252
+ type: "context",
253
+ elements: [{
254
+ type: "mrkdwn",
255
+ text: escapedStatusLine
256
+ }]
257
+ }];
258
+ await updateMessageSlack({
259
+ cfg,
260
+ accountId: target.accountId ?? void 0,
261
+ channelId,
262
+ messageTs: result.messageId,
263
+ text: `${deliveryMessage.text}\n\n${escapedStatusLine}`,
264
+ blocks
265
+ });
266
+ }
267
+ });
268
+ },
225
269
  ...createSlackAttachedSendAdapter()
226
270
  };
227
271
  //#endregion