@openclaw/slack 2026.11.3 → 2026.11.5-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/dist/.setup/{account-inspect-CmkKiSb9.mjs → account-inspect-BLVha-ov.mjs} +11 -8
  2. package/dist/.setup/{accounts-msihSF3-.mjs → accounts-CGJScKtk.mjs} +10 -1
  3. package/dist/.setup/{action-runtime-ChRfnnBu.mjs → action-runtime-D01wBhx5.mjs} +38 -45
  4. package/dist/.setup/action-runtime.runtime-VQGaR6g8.mjs +1 -0
  5. package/dist/.setup/{actions-By7tvpvv.mjs → actions-D5S6D_BU.mjs} +89 -76
  6. package/dist/.setup/{approval-handler.runtime-D8ArtDQt.mjs → approval-handler.runtime-Buw5jh2Y.mjs} +26 -30
  7. package/dist/.setup/{approval-message-updates-DT7XBPbV.mjs → approval-message-updates-pmXcve5E.mjs} +1 -1
  8. package/dist/.setup/{channel-DLFiMJm2.mjs → channel-C_R98Nbv.mjs} +569 -339
  9. package/dist/.setup/{channel-type-BEFP2ORi.mjs → channel-type-B5P3w9eA.mjs} +4 -8
  10. package/dist/.setup/{channel.setup-CzFw73mU.mjs → channel.setup-Lq2OxKkF.mjs} +13 -13
  11. package/dist/.setup/{config-schema-DNnh6bWU.mjs → config-schema-BWAaa5au.mjs} +3 -7
  12. package/dist/.setup/cursor-pages-CATAzbTT.mjs +313 -0
  13. package/dist/.setup/{directory-config-Cjj0N8R0.mjs → directory-config-D-hf9KGQ.mjs} +3 -3
  14. package/dist/.setup/{directory-live-BIKD-5B_.mjs → directory-live-onKAFI1E.mjs} +4 -4
  15. package/dist/.setup/{doctor-contract-Cd4-VzIM.mjs → doctor-contract-9-QJRCXk.mjs} +37 -45
  16. package/dist/.setup/{message-tool-api-BS5ekEA_.mjs → message-tool-api-LGIgVXJf.mjs} +4 -3
  17. package/dist/.setup/{monitor-CV6Z6FKP.mjs → monitor-Cm1TuqxN.mjs} +3424 -3703
  18. package/dist/.setup/{outbound-adapter-9dbnYtL1.mjs → outbound-adapter-C-95EWl2.mjs} +30 -36
  19. package/dist/.setup/paths-B1u59oLK.mjs +8 -0
  20. package/dist/.setup/{pipeline.runtime-DLIQf1Bo.mjs → pipeline.runtime-DGnV6akc.mjs} +416 -534
  21. package/dist/.setup/{policy-yhn48xf5.mjs → policy-DxhGRvc2.mjs} +1 -2
  22. package/dist/.setup/{session-status-Dv8wNBEt.mjs → probe-DANukR3O.mjs} +1206 -839
  23. package/dist/.setup/question-delivery-CWC7sRhH.mjs +39 -0
  24. package/dist/.setup/{relay-source-CxDcrn16.mjs → relay-source-DoyOlTbK.mjs} +5 -3
  25. package/dist/.setup/{replies-MRkrg3rC.mjs → replies-BcmUKord.mjs} +34 -19
  26. package/dist/.setup/{reply-blocks-Ca-raz2z.mjs → reply-blocks-BzsXUUUL.mjs} +201 -206
  27. package/dist/.setup/{resolve-channels-DRRhElwz.mjs → resolve-channels-XDPgnesf.mjs} +4 -7
  28. package/dist/.setup/{resolve-users-Cz8e17ky.mjs → resolve-users-aDAv24U2.mjs} +8 -16
  29. package/dist/.setup/runtime-setter-api-Cx_PV-xu.mjs +2 -0
  30. package/dist/.setup/{scopes-DfQVi8Jw.mjs → scopes-BocHwImV.mjs} +2 -1
  31. package/dist/.setup/secret-contract-api-BlLz88mj.mjs +2 -0
  32. package/dist/.setup/{secret-contract-vVRMoE1D.mjs → secret-contract-uiQtoNlu.mjs} +2 -2
  33. package/dist/.setup/{send-results-eeOu_HYm.mjs → send-results-BGxlroJ-.mjs} +3 -4
  34. package/dist/.setup/{send-C-8wY0lK.mjs → send-yK6_-px6.mjs} +297 -334
  35. package/dist/.setup/setup-plugin-api-Cfz58xoh.mjs +2 -0
  36. package/dist/.setup/{setup-surface--n8VsDvV.mjs → setup-surface-C0KRtyqa.mjs} +5 -6
  37. package/dist/.setup/{slash-dispatch.runtime-D3Wq45ER.mjs → slash-dispatch.runtime-CyVC3bYx.mjs} +2 -2
  38. package/dist/.setup/{target-parsing-FFE26kOV.mjs → target-parsing-Bx2UZniD.mjs} +1 -2
  39. package/dist/.setup/{targets-C6LZQL1Q.mjs → targets-D-ASeWHy.mjs} +1 -1
  40. package/dist/.source-module-urls/c5ffd0957b234c7c12090e7de4eca2482ef339b8561e078da55b734211b0ba58.json +1 -0
  41. package/dist/account-inspect-api.js +1 -1
  42. package/dist/api.js +16 -17
  43. package/dist/channel-config-api.js +1 -2
  44. package/dist/channel-plugin-api.js +1 -2
  45. package/dist/directory-contract-api.js +1 -2
  46. package/dist/doctor-contract-api.js +1 -2
  47. package/dist/index.js +0 -6
  48. package/dist/message-tool-api.js +1 -2
  49. package/dist/runtime-api.js +10 -12
  50. package/dist/runtime-setter-api.js +1 -2
  51. package/dist/secret-contract-api.js +1 -2
  52. package/dist/security-contract-api.js +1 -2
  53. package/dist/setup-entry.js +3 -3
  54. package/dist/setup-plugin-api.js +1 -2
  55. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  56. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  57. package/node_modules/@slack/bolt/node_modules/@types/node/util.d.ts +6 -3
  58. package/node_modules/@slack/bolt/node_modules/content-disposition/README.md +105 -35
  59. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.d.ts +72 -0
  60. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js +388 -0
  61. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js.map +1 -0
  62. package/node_modules/@slack/bolt/node_modules/content-disposition/package.json +31 -19
  63. package/node_modules/@slack/bolt/node_modules/content-type/README.md +34 -57
  64. package/node_modules/@slack/bolt/node_modules/content-type/package.json +35 -25
  65. package/node_modules/@slack/bolt/node_modules/express/Readme.md +15 -9
  66. package/node_modules/@slack/bolt/node_modules/express/lib/application.js +2 -2
  67. package/node_modules/@slack/bolt/node_modules/express/lib/request.js +32 -19
  68. package/node_modules/@slack/bolt/node_modules/express/lib/response.js +27 -30
  69. package/node_modules/@slack/bolt/node_modules/express/package.json +10 -10
  70. package/node_modules/@slack/bolt/node_modules/qs/.github/THREAT_MODEL.md +4 -2
  71. package/node_modules/@slack/bolt/node_modules/qs/CHANGELOG.md +38 -14
  72. package/node_modules/@slack/bolt/node_modules/qs/README.md +31 -3
  73. package/node_modules/@slack/bolt/node_modules/qs/dist/qs.js +20 -20
  74. package/node_modules/@slack/bolt/node_modules/qs/lib/parse.js +94 -4
  75. package/node_modules/@slack/bolt/node_modules/qs/lib/stringify.js +4 -4
  76. package/node_modules/@slack/bolt/node_modules/qs/lib/utils.js +130 -6
  77. package/node_modules/@slack/bolt/node_modules/qs/package.json +4 -4
  78. package/node_modules/@slack/bolt/node_modules/qs/test/parse.js +174 -0
  79. package/node_modules/@slack/bolt/node_modules/qs/test/stringify.js +263 -33
  80. package/node_modules/@slack/bolt/node_modules/qs/test/utils.js +184 -0
  81. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  82. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  83. package/node_modules/@slack/web-api/node_modules/@types/node/util.d.ts +6 -3
  84. package/node_modules/typebox/build/format/duration.d.mts +2 -2
  85. package/node_modules/typebox/build/format/duration.mjs +2 -2
  86. package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
  87. package/node_modules/typebox/build/format/idn_email.mjs +1 -0
  88. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
  89. package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
  90. package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
  91. package/node_modules/typebox/build/format/ipv4.mjs +2 -2
  92. package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
  93. package/node_modules/typebox/build/format/ipv6.mjs +1 -1
  94. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  95. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  96. package/node_modules/typebox/build/schema/build.mjs +1 -0
  97. package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
  98. package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
  99. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
  100. package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
  101. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
  102. package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
  103. package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
  104. package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
  105. package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
  106. package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
  107. package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
  108. package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
  109. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
  110. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
  111. package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
  112. package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
  113. package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
  114. package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
  115. package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
  116. package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
  117. package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
  118. package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
  119. package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
  120. package/node_modules/typebox/build/system/memory/create.mjs +18 -13
  121. package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
  122. package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
  123. package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
  124. package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
  125. package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
  126. package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
  127. package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
  128. package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
  129. package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
  130. package/node_modules/typebox/build/system/memory/update.mjs +43 -16
  131. package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
  132. package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
  133. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
  134. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
  135. package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
  136. package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
  137. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
  138. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
  139. package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
  140. package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
  141. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
  142. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
  143. package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
  144. package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
  145. package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
  146. package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
  147. package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
  148. package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
  149. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
  150. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
  151. package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
  152. package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
  153. package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
  154. package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
  155. package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
  156. package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
  157. package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
  158. package/node_modules/typebox/package.json +1 -1
  159. package/node_modules/typebox/readme.md +1 -1
  160. package/node_modules/undici/docs/docs/api/Interceptors.md +15 -2
  161. package/node_modules/undici/lib/dispatcher/client-h2.js +78 -3
  162. package/node_modules/undici/lib/dispatcher/pool-base.js +20 -3
  163. package/node_modules/undici/package.json +3 -3
  164. package/node_modules/undici/types/api.d.ts +1 -1
  165. package/node_modules/undici/types/utility.d.ts +4 -4
  166. package/node_modules/zod/package.json +1 -1
  167. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  168. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  169. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  170. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  171. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  172. package/node_modules/zod/src/v4/core/util.ts +13 -0
  173. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  174. package/node_modules/zod/v4/core/compile.cjs +8 -0
  175. package/node_modules/zod/v4/core/compile.js +8 -0
  176. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  177. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  178. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  179. package/node_modules/zod/v4/core/schemas.js +30 -0
  180. package/node_modules/zod/v4/core/util.cjs +15 -0
  181. package/node_modules/zod/v4/core/util.d.cts +2 -0
  182. package/node_modules/zod/v4/core/util.d.ts +2 -0
  183. package/node_modules/zod/v4/core/util.js +14 -0
  184. package/node_modules/zod/v4/core/versions.cjs +1 -1
  185. package/node_modules/zod/v4/core/versions.js +1 -1
  186. package/openclaw.plugin.json +6 -30
  187. package/package.json +7 -7
  188. package/dist/.setup/action-runtime.runtime-vLxx_7s2.mjs +0 -2
  189. package/dist/.setup/http-C9sM-FXe.mjs +0 -2
  190. package/dist/.setup/plugin-routes-D4qozHVn.mjs +0 -22
  191. package/dist/.setup/probe-IiHogLQN.mjs +0 -694
  192. package/dist/.setup/registry-DizWcnNp.mjs +0 -36
  193. package/dist/.setup/runtime-setter-api-CMFvhrAr.mjs +0 -3
  194. package/dist/.setup/secret-contract-api-DK9gZldc.mjs +0 -3
  195. package/dist/.setup/setup-plugin-api-BGD1TYnK.mjs +0 -3
  196. package/dist/.setup/shared-BhJHIZs1.mjs +0 -259
  197. package/dist/http-routes-api.js +0 -2
  198. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/LICENSE +0 -22
  199. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +0 -71
  200. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +0 -52
  201. package/node_modules/@slack/bolt/node_modules/content-disposition/index.js +0 -536
  202. package/node_modules/@slack/bolt/node_modules/content-type/HISTORY.md +0 -29
  203. package/node_modules/@slack/bolt/node_modules/content-type/index.js +0 -225
  204. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +0 -22
  205. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +0 -71
  206. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +0 -46
  207. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +0 -176
  208. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +0 -1
  209. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +0 -52
  210. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/LICENSE +0 -22
  211. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +0 -71
  212. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +0 -46
  213. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +0 -176
  214. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +0 -1
  215. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +0 -52
  216. package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
  217. package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
  218. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.d.ts +0 -0
  219. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js +0 -0
  220. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js.map +0 -0
@@ -1,21 +1,23 @@
1
1
  import { r as isSlackPluginAccountConfigured } from "./account-configured-zcR9TJJN.mjs";
2
- import { c as resolveSlackAccountAllowFrom, d as resolveSlackOperationToken, f as resolveSlackReplyToMode, i as listSlackAccountIds, n as hasImplicitDefaultSlackAccount, o as resolveDefaultSlackAccountId, s as resolveSlackAccount } from "./accounts-msihSF3-.mjs";
3
- import { a as parseSlackTarget, i as normalizeSlackMessagingTarget, n as formatSlackTarget, o as resolveSlackChannelId, r as looksLikeSlackTargetId, t as canonicalizeSlackApiTargetId } from "./target-parsing-FFE26kOV.mjs";
4
- import { t as slackContextTargetsMatch } from "./targets-C6LZQL1Q.mjs";
5
- import { At as resolveSlackApprovalTeamId, Bt as resolvePluginApprovalSlackApprovers, Ct as resolveSlackFallbackOriginTarget, Dt as slackTargetsMatch, Et as shouldHandleSlackPluginViaForwardingSession, Ft as isSlackExecApprovalAuthorizedSender, Ht as resolveSlackAutoThreadId, It as isSlackExecApprovalClientEnabled, M as SLACK_TEXT_LIMIT, Mt as isSlackWorkspaceInstallation, N as countSlackTextUtf8Bytes, Ot as getSlackApprovalApproversForTeam, Pt as getSlackExecApprovalApprovers, Q as normalizeSlackOutboundText, Rt as resolveSlackExecApprovalTarget, St as resolveSlackApproverDmTargets, Tt as shouldHandleSlackNativeApprovalRequest, _t as isSlackAnyNativeApprovalClientEnabled, a as resolveSlackGroupRequireMention, bt as normalizeSlackOriginTarget, c as qualifySlackConversationId, d as normalizeSlackRouteBindingConfig, f as resolveSlackConversationBindingRoute, ft as SLACK_PRESENTATION_CAPABILITIES, jt as getSlackInstallationKind, k as SLACK_EDIT_TEXT_MAX_BYTES, kt as isSlackPluginApprovalAuthorizedSender, l as qualifySlackRoutePeerId, m as assertSlackDetachedTargetAllowed, n as setSlackSessionStatus, o as resolveSlackGroupToolPolicy, ot as renderSlackMessagePresentationFallbackText, vt as isSlackPluginApprovalRequest, wt as resolveTurnSourceSlackOriginTarget, xt as resolveSessionSlackOriginTarget, yt as normalizeSlackForwardTarget, zt as shouldSuppressLocalSlackExecApprovalPrompt } from "./session-status-Dv8wNBEt.mjs";
6
- import { _ as getSlackWriteClient, c as collectSlackCursorPages, o as formatSlackError, u as createSlackLookupClient } from "./probe-IiHogLQN.mjs";
7
- import { c as resolveSlackReplyDeliveryMessages, o as resolveSlackReplyBlockResolution, p as buildSlackPresentationBlocksIfComplete, r as normalizeSlackReplyPayload, s as resolveSlackReplyBlocks } from "./reply-blocks-Ca-raz2z.mjs";
2
+ import { a as mergeSlackAccountConfig, c as resolveSlackAccountAllowFrom, d as resolveSlackMarkdownOptions, f as resolveSlackOperationToken, i as listSlackAccountIds, l as resolveSlackAccountDmPolicy, n as hasImplicitDefaultSlackAccount, o as resolveDefaultSlackAccountId, p as resolveSlackReplyToMode, s as resolveSlackAccount } from "./accounts-CGJScKtk.mjs";
3
+ import { t as inspectSlackAccount } from "./account-inspect-BLVha-ov.mjs";
4
+ import { a as parseSlackTarget, i as normalizeSlackMessagingTarget, n as formatSlackTarget, o as resolveSlackChannelId, r as looksLikeSlackTargetId, t as canonicalizeSlackApiTargetId } from "./target-parsing-Bx2UZniD.mjs";
5
+ import { t as slackContextTargetsMatch } from "./targets-D-ASeWHy.mjs";
6
+ import { $t as resolveSlackExecApprovalTarget, At as resolveSessionSlackOriginTarget, Dt as isSlackPluginApprovalRequest, Et as isSlackAnyNativeApprovalClientEnabled, Ft as shouldHandleSlackPluginViaForwardingSession, It as slackTargetsMatch, Kt as getSlackInstallationKind, Lt as getSlackApprovalApproversForTeam, Mt as resolveSlackFallbackOriginTarget, Nt as resolveTurnSourceSlackOriginTarget, Ot as normalizeSlackForwardTarget, P as countSlackTextUtf8Bytes, Pt as shouldHandleSlackNativeApprovalRequest, Rt as isSlackPluginApprovalAuthorizedSender, S as assertSlackDetachedTargetAllowed, Xt as isSlackExecApprovalAuthorizedSender, Yt as getSlackExecApprovalApprovers, Zt as isSlackExecApprovalClientEnabled, _ as qualifySlackRoutePeerId, _t as renderSlackMessagePresentationFallbackText, b as resolveSlackConversationBindingRoute, d as resolveSlackGroupRequireMention, en as shouldSuppressLocalSlackExecApprovalPrompt, f as resolveSlackGroupToolPolicy, g as qualifySlackConversationId, i as setSlackSessionStatus, jt as resolveSlackApproverDmTargets, kt as normalizeSlackOriginTarget, m as formatSlackError, mt as SLACK_PRESENTATION_CAPABILITIES, qt as isSlackWorkspaceInstallation, rn as resolveSlackAutoThreadId, s as slackIngressIdentity, t as probeSlack, tn as resolvePluginApprovalSlackApprovers, vt as SLACK_EDIT_TEXT_MAX_BYTES, wt as normalizeSlackOutboundText, xt as SLACK_TEXT_LIMIT, y as normalizeSlackRouteBindingConfig, zt as resolveSlackApprovalTeamId } from "./probe-DANukR3O.mjs";
8
7
  import { n as resolveSlackReplyThreadTs, r as resolveSlackThreadTsValue, t as normalizeSlackThreadTsCandidate } from "./thread-ts-Cvt7WD6B.mjs";
9
- import { n as extractSlackToolSend, t as describeSlackMessageTool } from "./message-tool-api-BS5ekEA_.mjs";
10
- import { n as resolveSlackChannelType, r as resolveSlackConversationInfo } from "./channel-type-BEFP2ORi.mjs";
11
- import { t as getOptionalSlackRuntime } from "./runtime-JSVZSWAj.mjs";
12
- import { n as slackPluginBase, r as slackSecurityAdapter, t as slackConfigAdapter } from "./shared-BhJHIZs1.mjs";
13
- import { i as SLACK_CHANNEL } from "./channel.setup-CzFw73mU.mjs";
14
- import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
15
- import { normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/account-resolution";
8
+ import { n as extractSlackToolSend, t as describeSlackMessageTool } from "./message-tool-api-LGIgVXJf.mjs";
9
+ import { a as resolveSlackReplyBlockResolution, o as resolveSlackReplyBlocks, r as normalizeSlackReplyPayload, s as resolveSlackReplyDeliveryMessages } from "./reply-blocks-BzsXUUUL.mjs";
10
+ import { r as createSlackLookupClient, t as collectSlackCursorPages, u as getSlackWriteClient } from "./cursor-pages-CATAzbTT.mjs";
11
+ import { n as resolveSlackChannelType, r as resolveSlackConversationInfo } from "./channel-type-B5P3w9eA.mjs";
12
+ import { n as SLACK_CHANNEL_META } from "./channel-meta-C443t-lI.mjs";
13
+ import { i as SLACK_CHANNEL, r as slackBaseConfigAdapter, t as slackSetupPlugin } from "./channel.setup-Lq2OxKkF.mjs";
14
+ import { n as normalizeCompatibilityConfig, r as runtime_doctor_migrations_exports, t as legacyConfigRules } from "./doctor-contract-9-QJRCXk.mjs";
15
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-uiQtoNlu.mjs";
16
+ import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
16
17
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
17
- import { adaptScopedAccountAccessor } from "openclaw/plugin-sdk/channel-config-helpers";
18
+ import { adaptScopedAccountAccessor, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
18
19
  import { buildOutboundBaseSessionKey, normalizeMessageChannel, resolveAccountEntry, resolveAgentRoute } from "openclaw/plugin-sdk/routing";
20
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$2 } from "openclaw/plugin-sdk/account-id";
19
21
  import { buildLegacyDmAccountAllowlistAdapter, createAccountScopedAllowlistNameResolver, createFlatAllowlistOverrideResolver } from "openclaw/plugin-sdk/allowlist-config-edit";
20
22
  import { buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
21
23
  import { createChannelMessageAdapterFromOutbound, createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/channel-outbound";
@@ -33,8 +35,10 @@ import { createChannelNativeOriginTargetResolverAsync, createNativeApprovalForwa
33
35
  import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
34
36
  import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
35
37
  import { normalizeLegacyInteractiveReply, normalizeMessagePresentation } from "openclaw/plugin-sdk/interactive-runtime";
36
- import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
37
38
  import { readPositiveIntegerParam as readPositiveIntegerParam$1, readStringParam as readStringParam$1 } from "openclaw/plugin-sdk/param-readers";
39
+ import { buildMutableAllowEntryDetector, collectStandardAllowlistLists, createConditionalWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, createOpenProviderConfiguredRouteWarningCollector } from "openclaw/plugin-sdk/channel-policy";
40
+ import { identityEntryAuthenticationClassifier } from "openclaw/plugin-sdk/channel-ingress-runtime";
41
+ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
38
42
  //#region extensions/slack/src/approval-native.ts
39
43
  function resolveSlackNativeSuppressionAccountId({ target, request }) {
40
44
  return normalizeOptionalString(target.accountId) ?? normalizeOptionalString(request.request.turnSourceAccountId);
@@ -99,7 +103,7 @@ const baseSlackApprovalCapability = createApproverRestrictedNativeApprovalCapabi
99
103
  ],
100
104
  isConfigured: isSlackAnyNativeApprovalClientEnabled,
101
105
  shouldHandle: shouldHandleSlackNativeApprovalRequest,
102
- load: async () => (await import("./approval-handler.runtime-D8ArtDQt.mjs")).slackApprovalNativeRuntime
106
+ load: async () => (await import("./approval-handler.runtime-Buw5jh2Y.mjs")).slackApprovalNativeRuntime
103
107
  })
104
108
  });
105
109
  const baseSlackNativeAdapter = baseSlackApprovalCapability.nativeAsync;
@@ -168,7 +172,7 @@ const slackApprovalCapability = {
168
172
  } : void 0
169
173
  };
170
174
  //#endregion
171
- //#region extensions/slack/src/message-action-dispatch.ts
175
+ //#region extensions/slack/src/channel-actions.ts
172
176
  const SLACK_MESSAGE_ACTIONS = /* @__PURE__ */ new Map([
173
177
  ["reactions", "reactions"],
174
178
  ["delete", "deleteMessage"],
@@ -179,196 +183,28 @@ const SLACK_MESSAGE_ACTIONS = /* @__PURE__ */ new Map([
179
183
  function readSlackForceDocument(params) {
180
184
  return readBooleanParam(params, "forceDocument") ?? readBooleanParam(params, "asDocument") ?? false;
181
185
  }
182
- function renderSlackActionPresentation(content, presentation) {
186
+ function renderSlackActionPresentation(content, presentation, markdownOptions) {
187
+ const renderedContent = normalizeSlackOutboundText(content ?? "", markdownOptions);
183
188
  if (!presentation) return {
184
- text: content ?? "",
189
+ text: renderedContent,
185
190
  usesPresentationTextFallback: false
186
191
  };
187
- const renderedBlocks = presentation.blocks.some((block) => (block.type === "text" || block.type === "context") && block.text.trim().length > 3e3) ? void 0 : buildSlackPresentationBlocksIfComplete(presentation);
188
- const usesPresentationTextFallback = !renderedBlocks || renderedBlocks.length > 50;
189
- const blocks = usesPresentationTextFallback ? void 0 : renderedBlocks;
192
+ const resolution = resolveSlackReplyBlockResolution({
193
+ text: content,
194
+ presentation
195
+ }, markdownOptions);
196
+ const segment = resolution.segments.length === 1 ? resolution.segments[0] : void 0;
197
+ const usesPresentationTextFallback = segment?.kind !== "blocks" || presentation.blocks.some((block) => (block.type === "text" || block.type === "context") && block.text.trim().length > 3e3);
198
+ const blocks = !usesPresentationTextFallback && segment?.kind === "blocks" ? segment.blocks : void 0;
190
199
  return {
191
200
  ...blocks?.length ? { blocks } : {},
192
201
  text: usesPresentationTextFallback || presentation.blocks.some((block) => block.type === "chart" || block.type === "table") ? renderSlackMessagePresentationFallbackText({
193
- text: content,
202
+ text: resolution.authoredTextPlacement === "blocks" ? void 0 : renderedContent,
194
203
  presentation
195
- }) : content ?? "",
204
+ }) : renderedContent,
196
205
  usesPresentationTextFallback
197
206
  };
198
207
  }
199
- async function handleSlackMessageAction(params) {
200
- const { providerId, ctx, invoke } = params;
201
- const { action, cfg, params: actionParams } = ctx;
202
- const accountId = ctx.accountId ?? void 0;
203
- const invokeSlackAction = (request, toolContext = ctx.toolContext) => invoke({
204
- ...request,
205
- accountId
206
- }, cfg, toolContext);
207
- const resolveChannelId = () => {
208
- const raw = readStringParam$1(actionParams, "channelId") ?? readStringParam$1(actionParams, "to", { required: true });
209
- const target = parseSlackTarget(raw, { defaultKind: "channel" });
210
- const channelId = resolveSlackChannelId(raw);
211
- return formatSlackTarget({
212
- teamId: target?.teamId,
213
- kind: "channel",
214
- id: channelId
215
- });
216
- };
217
- if (action === "conversation-open") return await invokeSlackAction({
218
- action: "openConversation",
219
- userIds: actionParams.userIds,
220
- teamId: readStringParam$1(actionParams, "teamId")
221
- });
222
- if (action === "send") {
223
- const to = readStringParam$1(actionParams, "to", { required: true });
224
- const content = readStringParam$1(actionParams, "message", {
225
- required: false,
226
- allowEmpty: true
227
- });
228
- const mediaUrl = readStringParam$1(actionParams, "media", { trim: false });
229
- const presentation = normalizeMessagePresentation(actionParams.presentation);
230
- const interactive = normalizeLegacyInteractiveReply(actionParams.interactive);
231
- const hasStructuredContent = Boolean(presentation || interactive?.blocks.length);
232
- const resolution = resolveSlackReplyBlockResolution({
233
- text: content,
234
- presentation,
235
- interactive
236
- }, { materializeAuthoredText: hasStructuredContent });
237
- const preparedMessages = resolution.segments.length > 0 ? resolveSlackReplyDeliveryMessages({
238
- authoredTextPlacement: resolution.authoredTextPlacement,
239
- segments: resolution.segments,
240
- text: content
241
- }) : [];
242
- if (!content && preparedMessages.length === 0 && !mediaUrl) throw new Error("Slack send requires message, blocks, or media.");
243
- const replyBroadcast = readBooleanParam(actionParams, "replyBroadcast");
244
- if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
245
- const threadId = readStringParam$1(actionParams, "threadId");
246
- const replyTo = readStringParam$1(actionParams, "replyTo");
247
- const topLevel = readBooleanParam(actionParams, "topLevel") === true || actionParams.threadId === null;
248
- const toolContext = preparedMessages.length > 0 ? {
249
- ...ctx.toolContext,
250
- preparedMessages
251
- } : ctx.toolContext;
252
- return await invokeSlackAction({
253
- action: "sendMessage",
254
- to,
255
- content: content ?? "",
256
- mediaUrl: mediaUrl ?? void 0,
257
- ...readSlackForceDocument(actionParams) ? { forceDocument: true } : {},
258
- threadTs: resolveSlackThreadTsValue({
259
- replyToId: replyTo,
260
- threadId
261
- }),
262
- ...topLevel ? { topLevel: true } : {},
263
- ...replyBroadcast ? { replyBroadcast } : {}
264
- }, toolContext);
265
- }
266
- if (action === "react") {
267
- const messageIdRaw = resolveReactionMessageId({
268
- args: actionParams,
269
- toolContext: ctx.toolContext
270
- });
271
- if (messageIdRaw == null) throw new Error("messageId required. Provide messageId explicitly or react to the current inbound message.");
272
- const messageId = String(messageIdRaw);
273
- const emoji = readStringParam$1(actionParams, "emoji", { allowEmpty: true });
274
- const remove = typeof actionParams.remove === "boolean" ? actionParams.remove : void 0;
275
- return await invokeSlackAction({
276
- action: "react",
277
- channelId: resolveChannelId(),
278
- messageId,
279
- emoji,
280
- remove
281
- });
282
- }
283
- const messageAction = SLACK_MESSAGE_ACTIONS.get(action);
284
- if (messageAction) {
285
- const messageId = action === "list-pins" ? void 0 : readStringParam$1(actionParams, "messageId", { required: true });
286
- return await invokeSlackAction({
287
- action: messageAction,
288
- channelId: resolveChannelId(),
289
- messageId,
290
- ...action === "reactions" ? { limit: actionParams.limit } : {}
291
- });
292
- }
293
- if (action === "read") return await invokeSlackAction({
294
- action: "readMessages",
295
- channelId: resolveChannelId(),
296
- limit: actionParams.limit,
297
- before: readStringParam$1(actionParams, "before"),
298
- after: readStringParam$1(actionParams, "after"),
299
- messageId: readStringParam$1(actionParams, "messageId"),
300
- threadId: readStringParam$1(actionParams, "threadId")
301
- });
302
- if (action === "edit") {
303
- const messageId = readStringParam$1(actionParams, "messageId", { required: true });
304
- const { blocks, text: accessibleContent, usesPresentationTextFallback } = renderSlackActionPresentation(readStringParam$1(actionParams, "message", { allowEmpty: true }), normalizeMessagePresentation(actionParams.presentation));
305
- const tableMode = resolveMarkdownTableMode({
306
- cfg,
307
- channel: "slack",
308
- accountId: accountId ?? resolveDefaultSlackAccountId(cfg)
309
- });
310
- if (!blocks && countSlackTextUtf8Bytes(normalizeSlackOutboundText(accessibleContent, { tableMode })) > 4e3) throw new Error(`${usesPresentationTextFallback ? "Slack presentation fallback" : "Slack edit"} exceeds the ${String(SLACK_EDIT_TEXT_MAX_BYTES)}-byte edit limit. Send a new message instead.`);
311
- if (!accessibleContent && !blocks) throw new Error("Slack edit requires message or blocks.");
312
- return await invokeSlackAction({
313
- action: "editMessage",
314
- channelId: resolveChannelId(),
315
- messageId,
316
- content: accessibleContent,
317
- blocks
318
- });
319
- }
320
- if (action === "member-info") {
321
- const requesterAccountId = ctx.requesterAccountId ? normalizeAccountId$1(ctx.requesterAccountId) : void 0;
322
- const targetAccountId = normalizeAccountId$1(accountId ?? resolveDefaultSlackAccountId(cfg));
323
- const requesterUserId = normalizeOptionalLowercaseString(ctx.toolContext?.currentChannelProvider) === "slack" && requesterAccountId !== void 0 && requesterAccountId === targetAccountId ? normalizeOptionalString(ctx.requesterSenderId) : void 0;
324
- const userId = readStringParam$1(actionParams, "userId") ?? requesterUserId;
325
- if (!userId) throw new Error("member-info requires a userId outside a current Slack conversation.");
326
- return await invokeSlackAction({
327
- action: "memberInfo",
328
- userId
329
- });
330
- }
331
- if (action === "emoji-list") return await invokeSlackAction({
332
- action: "emojiList",
333
- limit: readPositiveIntegerParam$1(actionParams, "limit", { message: "limit must be a positive integer." })
334
- });
335
- if (action === "download-file") {
336
- const fileIdParam = readStringParam$1(actionParams, "fileId");
337
- const messageIdParam = readStringParam$1(actionParams, "messageId") ?? readStringParam$1(actionParams, "message_id");
338
- if (!fileIdParam && messageIdParam) throw new Error("download-file requires fileId (the Slack file id, for example F0B0LTT8M36 from event.files[].id), not messageId. Did you mean to pass fileId? messageId is the Slack message timestamp and is used by react / reactions / edit / delete / pin / unpin actions, not download-file.");
339
- const fileId = readStringParam$1(actionParams, "fileId", { required: true });
340
- const channelId = readStringParam$1(actionParams, "channelId") ?? readStringParam$1(actionParams, "to");
341
- const threadId = readStringParam$1(actionParams, "threadId") ?? readStringParam$1(actionParams, "replyTo");
342
- return await invokeSlackAction({
343
- action: "downloadFile",
344
- fileId,
345
- channelId: channelId ?? void 0,
346
- threadId: threadId ?? void 0
347
- });
348
- }
349
- if (action === "upload-file") {
350
- if (readBooleanParam(actionParams, "replyBroadcast")) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
351
- const to = readStringParam$1(actionParams, "to") ?? resolveChannelId();
352
- const filePath = readStringParam$1(actionParams, "filePath", { trim: false }) ?? readStringParam$1(actionParams, "path", { trim: false }) ?? readStringParam$1(actionParams, "media", { trim: false });
353
- if (!filePath) throw new Error("upload-file requires filePath, path, or media");
354
- const threadId = readStringParam$1(actionParams, "threadId") ?? readStringParam$1(actionParams, "replyTo");
355
- const topLevel = readBooleanParam(actionParams, "topLevel") === true || actionParams.threadId === null;
356
- return await invokeSlackAction({
357
- action: "uploadFile",
358
- to,
359
- filePath,
360
- initialComment: readStringParam$1(actionParams, "initialComment", { allowEmpty: true }) ?? readStringParam$1(actionParams, "message", { allowEmpty: true }) ?? readStringParam$1(actionParams, "caption", { allowEmpty: true }) ?? "",
361
- filename: readStringParam$1(actionParams, "filename"),
362
- title: readStringParam$1(actionParams, "title"),
363
- threadTs: threadId ?? void 0,
364
- ...readSlackForceDocument(actionParams) ? { forceDocument: true } : {},
365
- ...topLevel ? { topLevel: true } : {}
366
- });
367
- }
368
- throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
369
- }
370
- //#endregion
371
- //#region extensions/slack/src/channel-actions.ts
372
208
  const SLACK_TOOL_DELIVERY_ACTIONS = /* @__PURE__ */ new Set([
373
209
  "deleteMessage",
374
210
  "editMessage",
@@ -378,7 +214,7 @@ const SLACK_TOOL_DELIVERY_ACTIONS = /* @__PURE__ */ new Set([
378
214
  "unpinMessage",
379
215
  "uploadFile"
380
216
  ]);
381
- const loadSlackActionRuntime$1 = createLazyRuntimeModule(() => import("./action-runtime.runtime-vLxx_7s2.mjs"));
217
+ const loadSlackActionRuntime = createLazyRuntimeModule(() => import("./action-runtime.runtime-VQGaR6g8.mjs"));
382
218
  function resolveSlackActionContext(ctx, toolContext) {
383
219
  if (!toolContext && !ctx.mediaAccess && !ctx.mediaLocalRoots && !ctx.mediaReadFile && !ctx.conversationReadOrigin && !ctx.requesterAccountId && !ctx.requesterSenderId && !ctx.assertDirectAdapterHandoff) return;
384
220
  return {
@@ -408,14 +244,187 @@ function createSlackActions(providerId, options) {
408
244
  isToolDeliveryAction: ({ args }) => typeof args.action === "string" && SLACK_TOOL_DELIVERY_ACTIONS.has(args.action),
409
245
  prepareSendPayload: ({ ctx, to, payload }) => ctx.action === "send" && !shouldUseWorkspaceAwareSlackActionSend(to, ctx.toolContext) ? payload : null,
410
246
  handleAction: async (ctx) => {
411
- return await handleSlackMessageAction({
412
- providerId,
413
- ctx,
414
- invoke: async (action, cfg, toolContext) => {
415
- const actionContext = resolveSlackActionContext(ctx, toolContext);
416
- return await (options?.invoke ? options.invoke(action, cfg, actionContext) : (await loadSlackActionRuntime$1()).handleSlackAction(action, cfg, actionContext));
417
- }
247
+ const { action, cfg, params: actionParams } = ctx;
248
+ const accountId = ctx.accountId ?? void 0;
249
+ const invokeSlackAction = async (request, toolContext = ctx.toolContext) => {
250
+ const requestAction = {
251
+ ...request,
252
+ accountId
253
+ };
254
+ const actionContext = resolveSlackActionContext(ctx, toolContext);
255
+ return await (options?.invoke ? options.invoke(requestAction, cfg, actionContext) : (await loadSlackActionRuntime()).handleSlackAction(requestAction, cfg, actionContext));
256
+ };
257
+ const resolveChannelId = () => {
258
+ const raw = readStringParam$1(actionParams, "channelId") ?? readStringParam$1(actionParams, "to", { required: true });
259
+ const target = parseSlackTarget(raw, { defaultKind: "channel" });
260
+ const channelId = resolveSlackChannelId(raw);
261
+ return formatSlackTarget({
262
+ teamId: target?.teamId,
263
+ kind: "channel",
264
+ id: channelId
265
+ });
266
+ };
267
+ if (action === "channel-create") return await invokeSlackAction({
268
+ action: "createChannel",
269
+ name: readStringParam$1(actionParams, "name", { required: true }),
270
+ teamId: readStringParam$1(actionParams, "teamId")
418
271
  });
272
+ if (action === "conversation-open") return await invokeSlackAction({
273
+ action: "openConversation",
274
+ userIds: actionParams.userIds,
275
+ teamId: readStringParam$1(actionParams, "teamId")
276
+ });
277
+ if (action === "send") {
278
+ const to = readStringParam$1(actionParams, "to", { required: true });
279
+ const content = readStringParam$1(actionParams, "message", {
280
+ required: false,
281
+ allowEmpty: true
282
+ });
283
+ const mediaUrl = readStringParam$1(actionParams, "media", { trim: false });
284
+ const presentation = normalizeMessagePresentation(actionParams.presentation);
285
+ const interactive = normalizeLegacyInteractiveReply(actionParams.interactive);
286
+ const hasStructuredContent = Boolean(presentation || interactive?.blocks.length);
287
+ const resolution = resolveSlackReplyBlockResolution({
288
+ text: content,
289
+ presentation,
290
+ interactive
291
+ }, {
292
+ ...resolveSlackMarkdownOptions({
293
+ cfg,
294
+ accountId
295
+ }),
296
+ materializeAuthoredText: hasStructuredContent
297
+ });
298
+ const preparedMessages = resolution.segments.length > 0 ? resolveSlackReplyDeliveryMessages({
299
+ authoredTextPlacement: resolution.authoredTextPlacement,
300
+ segments: resolution.segments,
301
+ text: content
302
+ }) : [];
303
+ if (!content && preparedMessages.length === 0 && !mediaUrl) throw new Error("Slack send requires message, blocks, or media.");
304
+ const replyBroadcast = readBooleanParam(actionParams, "replyBroadcast");
305
+ if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
306
+ const threadId = readStringParam$1(actionParams, "threadId");
307
+ const replyTo = readStringParam$1(actionParams, "replyTo");
308
+ const topLevel = readBooleanParam(actionParams, "topLevel") === true || actionParams.threadId === null;
309
+ const toolContext = preparedMessages.length > 0 ? {
310
+ ...ctx.toolContext,
311
+ preparedMessages
312
+ } : ctx.toolContext;
313
+ return await invokeSlackAction({
314
+ action: "sendMessage",
315
+ to,
316
+ content: content ?? "",
317
+ mediaUrl,
318
+ ...readSlackForceDocument(actionParams) ? { forceDocument: true } : {},
319
+ threadTs: resolveSlackThreadTsValue({
320
+ replyToId: replyTo,
321
+ threadId
322
+ }),
323
+ ...topLevel ? { topLevel: true } : {},
324
+ ...replyBroadcast ? { replyBroadcast } : {}
325
+ }, toolContext);
326
+ }
327
+ if (action === "react") {
328
+ const messageIdRaw = resolveReactionMessageId({
329
+ args: actionParams,
330
+ toolContext: ctx.toolContext
331
+ });
332
+ if (messageIdRaw == null) throw new Error("messageId required. Provide messageId explicitly or react to the current inbound message.");
333
+ const messageId = String(messageIdRaw);
334
+ const emoji = readStringParam$1(actionParams, "emoji", { allowEmpty: true });
335
+ const remove = typeof actionParams.remove === "boolean" ? actionParams.remove : void 0;
336
+ return await invokeSlackAction({
337
+ action: "react",
338
+ channelId: resolveChannelId(),
339
+ messageId,
340
+ emoji,
341
+ remove
342
+ });
343
+ }
344
+ const messageAction = SLACK_MESSAGE_ACTIONS.get(action);
345
+ if (messageAction) {
346
+ const messageId = action === "list-pins" ? void 0 : readStringParam$1(actionParams, "messageId", { required: true });
347
+ return await invokeSlackAction({
348
+ action: messageAction,
349
+ channelId: resolveChannelId(),
350
+ messageId,
351
+ ...action === "reactions" ? { limit: actionParams.limit } : {}
352
+ });
353
+ }
354
+ if (action === "read") return await invokeSlackAction({
355
+ action: "readMessages",
356
+ channelId: resolveChannelId(),
357
+ limit: actionParams.limit,
358
+ before: readStringParam$1(actionParams, "before"),
359
+ after: readStringParam$1(actionParams, "after"),
360
+ messageId: readStringParam$1(actionParams, "messageId"),
361
+ threadId: readStringParam$1(actionParams, "threadId")
362
+ });
363
+ if (action === "edit") {
364
+ const messageId = readStringParam$1(actionParams, "messageId", { required: true });
365
+ const { blocks, text: accessibleContent, usesPresentationTextFallback } = renderSlackActionPresentation(readStringParam$1(actionParams, "message", { allowEmpty: true }), normalizeMessagePresentation(actionParams.presentation), resolveSlackMarkdownOptions({
366
+ cfg,
367
+ accountId
368
+ }));
369
+ if (!blocks && countSlackTextUtf8Bytes(accessibleContent) > 4e3) throw new Error(`${usesPresentationTextFallback ? "Slack presentation fallback" : "Slack edit"} exceeds the ${String(SLACK_EDIT_TEXT_MAX_BYTES)}-byte edit limit. Send a new message instead.`);
370
+ if (!accessibleContent && !blocks) throw new Error("Slack edit requires message or blocks.");
371
+ return await invokeSlackAction({
372
+ action: "editMessage",
373
+ channelId: resolveChannelId(),
374
+ messageId,
375
+ content: accessibleContent,
376
+ blocks
377
+ }, {
378
+ ...ctx.toolContext,
379
+ preparedEditText: accessibleContent
380
+ });
381
+ }
382
+ if (action === "member-info") {
383
+ const requesterAccountId = ctx.requesterAccountId ? normalizeAccountId(ctx.requesterAccountId) : void 0;
384
+ const targetAccountId = normalizeAccountId(accountId ?? resolveDefaultSlackAccountId(cfg));
385
+ const requesterUserId = normalizeOptionalLowercaseString(ctx.toolContext?.currentChannelProvider) === "slack" && requesterAccountId !== void 0 && requesterAccountId === targetAccountId ? normalizeOptionalString(ctx.requesterSenderId) : void 0;
386
+ const userId = readStringParam$1(actionParams, "userId") ?? requesterUserId;
387
+ if (!userId) throw new Error("member-info requires a userId outside a current Slack conversation.");
388
+ return await invokeSlackAction({
389
+ action: "memberInfo",
390
+ userId
391
+ });
392
+ }
393
+ if (action === "emoji-list") return await invokeSlackAction({
394
+ action: "emojiList",
395
+ limit: readPositiveIntegerParam$1(actionParams, "limit", { message: "limit must be a positive integer." })
396
+ });
397
+ if (action === "download-file") {
398
+ const fileIdParam = readStringParam$1(actionParams, "fileId");
399
+ const messageIdParam = readStringParam$1(actionParams, "messageId") ?? readStringParam$1(actionParams, "message_id");
400
+ if (!fileIdParam && messageIdParam) throw new Error("download-file requires fileId (the Slack file id, for example F0B0LTT8M36 from event.files[].id), not messageId. Did you mean to pass fileId? messageId is the Slack message timestamp and is used by react / reactions / edit / delete / pin / unpin actions, not download-file.");
401
+ return await invokeSlackAction({
402
+ action: "downloadFile",
403
+ fileId: fileIdParam ?? readStringParam$1(actionParams, "fileId", { required: true }),
404
+ channelId: readStringParam$1(actionParams, "channelId") ?? readStringParam$1(actionParams, "to"),
405
+ threadId: readStringParam$1(actionParams, "threadId") ?? readStringParam$1(actionParams, "replyTo")
406
+ });
407
+ }
408
+ if (action === "upload-file") {
409
+ if (readBooleanParam(actionParams, "replyBroadcast")) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
410
+ const to = readStringParam$1(actionParams, "to") ?? resolveChannelId();
411
+ const filePath = readStringParam$1(actionParams, "filePath", { trim: false }) ?? readStringParam$1(actionParams, "path", { trim: false }) ?? readStringParam$1(actionParams, "media", { trim: false });
412
+ if (!filePath) throw new Error("upload-file requires filePath, path, or media");
413
+ const threadId = readStringParam$1(actionParams, "threadId") ?? readStringParam$1(actionParams, "replyTo");
414
+ const topLevel = readBooleanParam(actionParams, "topLevel") === true || actionParams.threadId === null;
415
+ return await invokeSlackAction({
416
+ action: "uploadFile",
417
+ to,
418
+ filePath,
419
+ initialComment: readStringParam$1(actionParams, "initialComment", { allowEmpty: true }) ?? readStringParam$1(actionParams, "message", { allowEmpty: true }) ?? readStringParam$1(actionParams, "caption", { allowEmpty: true }) ?? "",
420
+ filename: readStringParam$1(actionParams, "filename"),
421
+ title: readStringParam$1(actionParams, "title"),
422
+ threadTs: threadId,
423
+ ...readSlackForceDocument(actionParams) ? { forceDocument: true } : {},
424
+ ...topLevel ? { topLevel: true } : {}
425
+ });
426
+ }
427
+ throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
419
428
  }
420
429
  };
421
430
  }
@@ -432,9 +441,9 @@ function shouldUseWorkspaceAwareSlackActionSend(rawTarget, context) {
432
441
  //#endregion
433
442
  //#region extensions/slack/src/conversation-route-owner.ts
434
443
  function prepareSlackConversationRouteOwner(params) {
435
- const accountId = normalizeAccountId(params.accountId);
444
+ const accountId = normalizeAccountId$2(params.accountId);
436
445
  const accountConfig = resolveAccountEntry(params.cfg.channels?.slack?.accounts, accountId);
437
- if (params.cfg.channels?.slack?.enabled === false || accountConfig?.enabled === false || !accountConfig && (accountId !== DEFAULT_ACCOUNT_ID || !hasImplicitDefaultSlackAccount(params.cfg))) return {
446
+ if (params.cfg.channels?.slack?.enabled === false || accountConfig?.enabled === false || !accountConfig && (accountId !== DEFAULT_ACCOUNT_ID$1 || !hasImplicitDefaultSlackAccount(params.cfg))) return {
438
447
  kind: "terminal",
439
448
  owner: null
440
449
  };
@@ -516,7 +525,7 @@ function prepareSlackConversationRouteOwner(params) {
516
525
  }
517
526
  };
518
527
  }
519
- async function prepareSlackConversationRouteOwnersAsync(inputs, inspectBindings) {
528
+ const slackConversationRouteOwners = { prepareConversationRouteOwnersAsync: async (inputs, inspectBindings) => {
520
529
  const prepared = inputs.map(prepareSlackConversationRouteOwner);
521
530
  const inspect = await inspectBindings(prepared.flatMap((item) => item.kind === "prepared" && item.route.bindingsEnabled ? [{
522
531
  channel: "slack",
@@ -549,8 +558,7 @@ async function prepareSlackConversationRouteOwnersAsync(inputs, inspectBindings)
549
558
  thread: thread()
550
559
  });
551
560
  });
552
- }
553
- const slackConversationRouteOwners = { prepareConversationRouteOwnersAsync: prepareSlackConversationRouteOwnersAsync };
561
+ } };
554
562
  //#endregion
555
563
  //#region extensions/slack/src/enterprise-user-route.ts
556
564
  /** Resolve a workspace for a detached Enterprise DM without opening a conversation. */
@@ -578,6 +586,247 @@ async function resolveSlackEnterpriseUserTeamId(params) {
578
586
  return teamId;
579
587
  }
580
588
  //#endregion
589
+ //#region extensions/slack/src/security.ts
590
+ const resolveSlackDmPolicy = createScopedDmSecurityResolver({
591
+ channelKey: "slack",
592
+ resolvePolicy: (account) => account.config.dmPolicy,
593
+ resolveAllowFrom: (account) => account.config.allowFrom,
594
+ resolveAccess: ({ cfg, account }) => ({
595
+ dmPolicy: resolveSlackAccountDmPolicy({
596
+ cfg,
597
+ accountId: account.accountId
598
+ }),
599
+ allowFrom: resolveSlackAccountAllowFrom({
600
+ cfg,
601
+ accountId: account.accountId
602
+ })
603
+ }),
604
+ policyPathSuffix: "dmPolicy",
605
+ classifyEntryAuthentication: identityEntryAuthenticationClassifier(slackIngressIdentity),
606
+ normalizeEntry: (raw) => raw.trim().replace(/^(slack|user):/i, "").trim()
607
+ });
608
+ const collectSlackSecurityWarnings = createOpenProviderConfiguredRouteWarningCollector({
609
+ providerConfigPresent: (cfg) => cfg.channels?.slack !== void 0,
610
+ resolveGroupPolicy: (account) => account.config.groupPolicy,
611
+ resolveRouteAllowlistConfigured: (account) => Boolean(account.config.channels) && Object.keys(account.config.channels ?? {}).length > 0,
612
+ configureRouteAllowlist: {
613
+ surface: "Slack channels",
614
+ openScope: "any channel not explicitly denied",
615
+ groupPolicyPath: "channels.slack.groupPolicy",
616
+ routeAllowlistPath: "channels.slack.channels"
617
+ },
618
+ missingRouteAllowlist: {
619
+ surface: "Slack channels",
620
+ openBehavior: "with no channel allowlist; any channel can trigger (mention-gated)",
621
+ remediation: "Set channels.slack.groupPolicy=\"allowlist\" and configure channels.slack.channels"
622
+ }
623
+ });
624
+ const collectSlackSecurityFindings = createConditionalWarningCollector.findings({
625
+ collectWarnings: collectSlackSecurityWarnings,
626
+ checkId: "channels.slack.groups.open",
627
+ severity: "warn",
628
+ title: "Slack security warning"
629
+ });
630
+ const loadSlackSecurityAuditModule = createLazyRuntimeModule(() => import("./security-audit-DFGiFLqd.mjs").then((n) => n.n));
631
+ const slackSecurityAdapter = {
632
+ resolveDmPolicy: resolveSlackDmPolicy,
633
+ collectWarnings: collectSlackSecurityFindings,
634
+ collectAuditFindings: async (params) => {
635
+ const { collectSlackSecurityAuditFindings } = await loadSlackSecurityAuditModule();
636
+ return await collectSlackSecurityAuditFindings(params);
637
+ }
638
+ };
639
+ //#endregion
640
+ //#region extensions/slack/src/doctor.ts
641
+ const isSlackMutableUnqualifiedAllowEntry = buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:(?:[sS][lL][aA][cC][kK]|[uU][sS][eE][rR]):)?(?:[UWBCGDT][A-Z0-9]{2,}|[A-Za-z0-9]{8,})|<@[A-Za-z0-9]{8,}>)$/ });
642
+ const collectSlackMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
643
+ channel: "slack",
644
+ detector: (entry) => {
645
+ if (/^team:/i.test(entry)) try {
646
+ const target = parseSlackTarget(entry);
647
+ if (target?.kind === "user" && target.teamId) return false;
648
+ } catch {}
649
+ return isSlackMutableUnqualifiedAllowEntry(entry);
650
+ },
651
+ collectLists: (scope) => collectStandardAllowlistLists(scope, {
652
+ includeGroupAllowFrom: false,
653
+ includeDm: true,
654
+ includeGroups: true,
655
+ groupsKey: "channels",
656
+ groupField: "users"
657
+ })
658
+ });
659
+ const SLACK_CANONICAL_CHANNEL_ID_RE = /^(?:channel:)?[CG][A-Z0-9]{8,}$/;
660
+ const SLACK_LOWERCASE_CHANNEL_ID_RE = /^(?:channel:)?[cg][0-9][a-z0-9]{7,}$/;
661
+ const SLACK_CANONICAL_DM_ID_RE = /^(?:channel:)?D[A-Z0-9]{8,}$/;
662
+ const SLACK_PREFIXED_LOWERCASE_DM_ID_RE = /^channel:d[a-z0-9]{8,}$/;
663
+ const SLACK_AMBIGUOUS_LOWERCASE_DM_ID_RE = /^d[a-z0-9]{8,}$/;
664
+ const SLACK_AMBIGUOUS_LOWERCASE_CHANNEL_ID_RE = /^(?:channel:)?[cgd][a-z][a-z0-9]{7,}$/;
665
+ const SLACK_CHANNEL_NAME_RE = /^[\p{L}\p{M}\p{N}_-]{1,80}$/u;
666
+ const SLACK_CHANNEL_NAME_ALPHANUMERIC_RE = /[\p{L}\p{N}]/u;
667
+ function looksLikeSlackChannelId(channelKey) {
668
+ const workspaceChannelId = parseWorkspaceQualifiedChannelId(channelKey);
669
+ return workspaceChannelId !== void 0 && /^[CG]/i.test(workspaceChannelId) || SLACK_CANONICAL_CHANNEL_ID_RE.test(channelKey) || SLACK_LOWERCASE_CHANNEL_ID_RE.test(channelKey);
670
+ }
671
+ function looksLikeSlackDmId(channelKey) {
672
+ const workspaceChannelId = parseWorkspaceQualifiedChannelId(channelKey);
673
+ return workspaceChannelId !== void 0 && /^D/i.test(workspaceChannelId) || SLACK_CANONICAL_DM_ID_RE.test(channelKey) || SLACK_PREFIXED_LOWERCASE_DM_ID_RE.test(channelKey);
674
+ }
675
+ function parseWorkspaceQualifiedChannelId(channelKey) {
676
+ if (!/^team:/i.test(channelKey)) return;
677
+ try {
678
+ const target = parseSlackTarget(channelKey);
679
+ return target?.kind === "channel" && target.teamId ? target.id : void 0;
680
+ } catch {
681
+ return;
682
+ }
683
+ }
684
+ function looksLikeSlackChannelNameKey(channelKey) {
685
+ const name = channelKey.startsWith("#") ? channelKey.slice(1) : channelKey;
686
+ return name === name.toLowerCase() && SLACK_CHANNEL_NAME_RE.test(name) && SLACK_CHANNEL_NAME_ALPHANUMERIC_RE.test(name);
687
+ }
688
+ function collectSlackNameKeyedChannelWarnings({ cfg }) {
689
+ const warnings = /* @__PURE__ */ new Set();
690
+ const slackCfg = (0, runtime_doctor_migrations_exports.asObjectRecord)((0, runtime_doctor_migrations_exports.asObjectRecord)(cfg.channels)?.slack);
691
+ const providerChannels = (0, runtime_doctor_migrations_exports.asObjectRecord)(slackCfg?.channels);
692
+ const accounts = (0, runtime_doctor_migrations_exports.asObjectRecord)(slackCfg?.accounts);
693
+ for (const accountId of listSlackAccountIds(cfg)) {
694
+ const account = (0, runtime_doctor_migrations_exports.asObjectRecord)(mergeSlackAccountConfig(cfg, accountId));
695
+ if (!account || slackCfg?.enabled === false || account.enabled === false) continue;
696
+ const effectiveGroupPolicy = (typeof account.groupPolicy === "string" ? account.groupPolicy : void 0) ?? "allowlist";
697
+ const rawAccount = (0, runtime_doctor_migrations_exports.asObjectRecord)(accounts?.[accountId]);
698
+ const accountPrefix = rawAccount ? `channels.slack.accounts.${accountId}` : "channels.slack";
699
+ const accountChannels = (0, runtime_doctor_migrations_exports.asObjectRecord)(rawAccount?.channels);
700
+ const channels = accountChannels ?? providerChannels;
701
+ if (!channels) continue;
702
+ const channelsPrefix = accountChannels ? `channels.slack.accounts.${accountId}` : "channels.slack";
703
+ const fallbackDescription = Object.hasOwn(channels, "*") ? `${channelsPrefix}.channels."*" applies instead and this entry's overrides are ignored` : effectiveGroupPolicy === "open" ? "this entry's overrides are ignored and the channel remains allowed by groupPolicy: \"open\"" : "messages from the channel are dropped";
704
+ for (const channelKey of Object.keys(channels)) {
705
+ if (channelKey === "*") continue;
706
+ if (looksLikeSlackDmId(channelKey)) {
707
+ warnings.add(`${channelsPrefix}.channels."${channelKey}" is a Slack DM conversation ID, but ${channelsPrefix}.channels only configures channel and group rooms. Configure DM access with ${accountPrefix}.dmPolicy and ${accountPrefix}.allowFrom instead.`);
708
+ continue;
709
+ }
710
+ if (SLACK_AMBIGUOUS_LOWERCASE_DM_ID_RE.test(channelKey)) {
711
+ if (account.dangerouslyAllowNameMatching === true && looksLikeSlackChannelNameKey(channelKey)) continue;
712
+ warnings.add(`${channelsPrefix}.channels."${channelKey}" is ambiguous: it may be a lowercase Slack DM conversation ID or a channel name. Configure DMs with ${accountPrefix}.dmPolicy and ${accountPrefix}.allowFrom; otherwise re-key the room with its stable C/G ID.`);
713
+ continue;
714
+ }
715
+ if (effectiveGroupPolicy === "disabled") continue;
716
+ const channelConfig = (0, runtime_doctor_migrations_exports.asObjectRecord)(channels[channelKey]);
717
+ if (effectiveGroupPolicy === "open" && Object.keys(channelConfig ?? {}).length === 0) continue;
718
+ if (looksLikeSlackChannelId(channelKey)) continue;
719
+ if (account.dangerouslyAllowNameMatching === true && looksLikeSlackChannelNameKey(channelKey)) continue;
720
+ if (SLACK_AMBIGUOUS_LOWERCASE_CHANNEL_ID_RE.test(channelKey)) {
721
+ warnings.add(`${channelsPrefix}.channels."${channelKey}" is ambiguous: it may be a lowercase Slack channel ID or a channel name. If it is a channel name, inbound routing will not match it and ${fallbackDescription}. Re-key it with the channel's stable ID (e.g. C0123ABCD, from the channel's About details or conversations.info).`);
722
+ continue;
723
+ }
724
+ warnings.add(`${channelsPrefix}.channels."${channelKey}" is keyed by a channel name or unsupported ID form, not a routable Slack channel ID; under groupPolicy: "${effectiveGroupPolicy}" inbound routing does not match this entry, so ${fallbackDescription}. Re-key it with the channel's ID (e.g. C0123ABCD, from the channel's About details or conversations.info).`);
725
+ }
726
+ }
727
+ return [...warnings];
728
+ }
729
+ async function collectSlackUserIdentityWarnings(params) {
730
+ const warnings = [];
731
+ for (const accountId of listSlackAccountIds(params.cfg)) {
732
+ const account = inspectSlackAccount({
733
+ cfg: params.cfg,
734
+ accountId,
735
+ envBotToken: params.env?.SLACK_BOT_TOKEN,
736
+ envAppToken: params.env?.SLACK_APP_TOKEN,
737
+ envUserToken: params.env?.SLACK_USER_TOKEN
738
+ });
739
+ if (!account.enabled || account.identity !== "user") continue;
740
+ const path = accountId === "default" ? "channels.slack" : `channels.slack.accounts.${accountId}`;
741
+ const mode = account.mode ?? "socket";
742
+ if (mode === "socket" && account.appTokenStatus === "missing") warnings.push(`- ${path}: identity "user" in Socket Mode requires appToken for companion-app events.`);
743
+ else if (mode === "http" && account.signingSecretStatus === "missing") warnings.push(`- ${path}: identity "user" in HTTP mode requires signingSecret for companion-app events.`);
744
+ if (!account.userToken) {
745
+ warnings.push(account.userTokenStatus === "configured_unavailable" ? `- ${path}: userToken is configured but unavailable; Slack auth.test validation was skipped.` : `- ${path}: identity "user" requires userToken for the authorizing human.`);
746
+ continue;
747
+ }
748
+ const probe = await probeSlack(account.userToken, 2500, {
749
+ accountId,
750
+ identity: "user"
751
+ });
752
+ if (!probe.ok) {
753
+ warnings.push(`- ${path}: userToken auth.test failed: ${probe.error ?? "unknown error"}.`);
754
+ continue;
755
+ }
756
+ const userId = probe.user?.id?.trim();
757
+ const userName = probe.user?.name?.trim();
758
+ if (!userId) {
759
+ warnings.push(`- ${path}: userToken auth.test succeeded but returned no human user_id.`);
760
+ continue;
761
+ }
762
+ warnings.push(`- ${path}: user identity authenticated as ${userName ? `@${userName} ` : ""}(${userId}).`);
763
+ }
764
+ return warnings;
765
+ }
766
+ const slackDoctor = {
767
+ dmAllowFromMode: "topOnly",
768
+ groupModel: "route",
769
+ groupAllowFromFallbackToAllowFrom: false,
770
+ warnOnEmptyGroupSenderAllowlist: false,
771
+ legacyConfigRules,
772
+ normalizeCompatibilityConfig,
773
+ collectPreviewWarnings: collectSlackUserIdentityWarnings,
774
+ collectMutableAllowlistWarnings: ({ cfg }) => [...collectSlackMutableAllowlistWarnings({ cfg }), ...collectSlackNameKeyedChannelWarnings({ cfg })]
775
+ };
776
+ //#endregion
777
+ //#region extensions/slack/src/shared.ts
778
+ const slackConfigAdapter = {
779
+ ...slackBaseConfigAdapter,
780
+ inspectAccount: adaptScopedAccountAccessor(inspectSlackAccount)
781
+ };
782
+ const slackPluginBase = {
783
+ ...slackSetupPlugin,
784
+ meta: {
785
+ ...SLACK_CHANNEL_META,
786
+ preferSessionLookupForAnnounceTarget: true
787
+ },
788
+ doctor: slackDoctor,
789
+ agentPrompt: {
790
+ questionInputMode: "buttons",
791
+ customInlineButtonHint: true,
792
+ inboundFormattingHints: () => ({
793
+ text_markup: "markdown",
794
+ rules: [
795
+ "Write replies in standard Markdown; OpenClaw converts them to Slack mrkdwn.",
796
+ "Bold uses **double asterisks**; *single asterisks* or _underscores_ produce italics.",
797
+ "Links use [label](url). Keep Slack mentions as <@USER_ID>.",
798
+ "Use presentation table blocks for tabular data; Markdown pipe tables are not auto-promoted.",
799
+ "Only raw Block Kit or presentation text fields use Slack mrkdwn directly: *bold*, _italic_, ~strike~, and <url|label> links. Avoid Markdown headings or pipe tables in those fields."
800
+ ]
801
+ }),
802
+ messageToolHints: () => [
803
+ "- Use `presentation` buttons/selects for discrete choices or parameter picks instead of asking the user to type one.",
804
+ "- For line, bar, area, or pie data, use a `presentation` chart block; Slack renders it as a native chart and retains a text data summary for accessibility.",
805
+ "- For row-and-column data, use an explicit `presentation` table block; Slack renders it as a native table and retains a linear text summary for accessibility. Markdown pipe tables are not auto-promoted.",
806
+ "- Slack plain text sends: write standard Markdown; OpenClaw converts it to Slack mrkdwn, including `**bold**`, headings, lists, and `[label](url)` links.",
807
+ "- When mentioning Slack users, use the stable `<@USER_ID>` token from Slack context instead of plain `@name` text so Slack notifies and links the user.",
808
+ "- Slack Block Kit or presentation text fields are sent as Slack mrkdwn directly; use `*bold*`, `_italic_`, `~strike~`, `<url|label>` links, and avoid Markdown headings or pipe tables there."
809
+ ]
810
+ },
811
+ config: {
812
+ ...slackSetupPlugin.config,
813
+ ...slackConfigAdapter,
814
+ isConfigured: isSlackPluginAccountConfigured,
815
+ describeAccount: (account) => describeAccountSnapshot({
816
+ account,
817
+ configured: isSlackPluginAccountConfigured(account),
818
+ extra: {
819
+ botTokenSource: account.botTokenSource,
820
+ appTokenSource: account.appTokenSource
821
+ }
822
+ })
823
+ },
824
+ secrets: {
825
+ secretTargetRegistryEntries,
826
+ collectRuntimeConfigAssignments
827
+ }
828
+ };
829
+ //#endregion
581
830
  //#region extensions/slack/src/threading-tool-context.ts
582
831
  function buildSlackThreadingToolContext(params) {
583
832
  const account = resolveSlackAccount({
@@ -612,20 +861,16 @@ function buildSlackThreadingToolContext(params) {
612
861
  //#region extensions/slack/src/channel.ts
613
862
  const loadExtensionSharedSdk = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/extension-shared"));
614
863
  const loadTargetResolverRuntimeSdk = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/target-resolver-runtime"));
615
- const loadSlackScopesModule = createLazyRuntimeModule(() => import("./scopes-DfQVi8Jw.mjs"));
616
- const loadSlackOutboundAdapterModule = createLazyRuntimeModule(() => import("./outbound-adapter-9dbnYtL1.mjs"));
864
+ const loadSlackScopesModule = createLazyRuntimeModule(() => import("./scopes-BocHwImV.mjs"));
865
+ const loadSlackOutboundAdapterModule = createLazyRuntimeModule(() => import("./outbound-adapter-C-95EWl2.mjs"));
617
866
  const bindSlackOutbound = createLazyRuntimeMethodBinder(loadSlackOutboundAdapterModule);
618
- async function resolveSlackHandleAction() {
619
- return getOptionalSlackRuntime()?.channel?.slack?.handleSlackAction ?? (await loadSlackActionRuntime()).handleSlackAction;
620
- }
621
- const loadSlackDirectoryConfigModule = createLazyRuntimeModule(() => import("./directory-config-Cjj0N8R0.mjs").then((n) => n.t));
622
- const loadSlackResolveChannelsModule = createLazyRuntimeModule(() => import("./resolve-channels-DRRhElwz.mjs").then((n) => n.n));
623
- const loadSlackResolveUsersModule = createLazyRuntimeModule(() => import("./resolve-users-Cz8e17ky.mjs").then((n) => n.n));
624
- const loadSlackActionRuntime = createLazyRuntimeModule(() => import("./action-runtime.runtime-vLxx_7s2.mjs"));
625
- const loadSlackSendRuntime = createLazyRuntimeModule(() => import("./send-C-8wY0lK.mjs").then((n) => n.n));
626
- const loadSlackProbeModule = createLazyRuntimeModule(() => import("./probe-IiHogLQN.mjs").then((n) => n.n));
627
- const loadSlackMonitorModule = createLazyRuntimeModule(() => import("./monitor-CV6Z6FKP.mjs").then((n) => n.t));
628
- const loadSlackDirectoryLiveModule = createLazyRuntimeModule(() => import("./directory-live-BIKD-5B_.mjs").then((n) => n.t));
867
+ const loadSlackDirectoryConfigModule = createLazyRuntimeModule(() => import("./directory-config-D-hf9KGQ.mjs").then((n) => n.t));
868
+ const loadSlackResolveChannelsModule = createLazyRuntimeModule(() => import("./resolve-channels-XDPgnesf.mjs").then((n) => n.n));
869
+ const loadSlackResolveUsersModule = createLazyRuntimeModule(() => import("./resolve-users-aDAv24U2.mjs").then((n) => n.n));
870
+ const loadSlackSendRuntime = createLazyRuntimeModule(() => import("./send-yK6_-px6.mjs").then((n) => n.n));
871
+ const loadSlackProbeModule = createLazyRuntimeModule(() => import("./probe-DANukR3O.mjs").then((n) => n.n));
872
+ const loadSlackMonitorModule = createLazyRuntimeModule(() => import("./monitor-Cm1TuqxN.mjs").then((n) => n.t));
873
+ const loadSlackDirectoryLiveModule = createLazyRuntimeModule(() => import("./directory-live-onKAFI1E.mjs").then((n) => n.t));
629
874
  async function setSlackHeartbeatThreadStatus(params) {
630
875
  const threadTs = resolveSlackThreadTsValue({ threadId: params.threadId });
631
876
  const target = parseSlackTarget(params.to, { defaultKind: "channel" });
@@ -672,106 +917,6 @@ function normalizeSlackAcpConversationId(raw) {
672
917
  const conversationId = normalizeLowercaseStringOrEmpty(parsed?.id ?? trimmed.replace(/^slack:/i, "").replace(/^(?:channel|group|direct|user):/i, ""));
673
918
  return conversationId ? { conversationId } : null;
674
919
  }
675
- function matchSlackAcpConversation(params) {
676
- const bindingConversationId = normalizeSlackAcpConversationId(params.bindingConversationId)?.conversationId;
677
- const conversationId = normalizeSlackAcpConversationId(params.conversationId)?.conversationId;
678
- const parentConversationId = normalizeSlackAcpConversationId(params.parentConversationId)?.conversationId;
679
- if (!bindingConversationId || !conversationId) return null;
680
- if (bindingConversationId === conversationId) return {
681
- conversationId,
682
- matchPriority: 2
683
- };
684
- if (parentConversationId && parentConversationId !== conversationId && bindingConversationId === parentConversationId) return {
685
- conversationId: parentConversationId,
686
- matchPriority: 1
687
- };
688
- return null;
689
- }
690
- async function resolveSlackOutboundSessionRoute(params) {
691
- const parsed = parseSlackTarget(params.target, { defaultKind: "channel" });
692
- if (!parsed) return null;
693
- const apiTargetId = canonicalizeSlackApiTargetId(parsed.kind, parsed.id, params.target);
694
- const isDm = parsed.kind === "user";
695
- if (params.deliveryPurpose === "heartbeat-owner" && isDm && !parsed.teamId && /^[UW][A-Z0-9]{8,}$/.test(apiTargetId)) {
696
- const teamId = await resolveSlackEnterpriseUserTeamId({
697
- cfg: params.cfg,
698
- accountId: params.accountId,
699
- userId: apiTargetId
700
- });
701
- if (teamId) {
702
- parsed.teamId = teamId;
703
- parsed.id = apiTargetId;
704
- }
705
- }
706
- let peerKind = isDm ? "direct" : "channel";
707
- let peerId = formatSlackTarget(parsed);
708
- let recipientSessionExact = isDm ? /^[UW][A-Z0-9]{8,}$/i.test(parsed.id) : /^C[A-Z0-9]{8,}$/i.test(parsed.id);
709
- if (!isDm && /^D/i.test(parsed.id)) {
710
- const conversation = await resolveSlackConversationInfo({
711
- cfg: params.cfg,
712
- accountId: params.accountId,
713
- channelId: apiTargetId,
714
- teamId: parsed.teamId
715
- });
716
- if (conversation.type !== "dm" || !conversation.user) return null;
717
- peerKind = "direct";
718
- peerId = formatSlackTarget({
719
- teamId: parsed.teamId,
720
- kind: "user",
721
- id: conversation.user
722
- });
723
- recipientSessionExact = true;
724
- } else if (!isDm && /^G/i.test(parsed.id)) {
725
- const channelType = await resolveSlackChannelType({
726
- cfg: params.cfg,
727
- accountId: params.accountId,
728
- channelId: apiTargetId,
729
- teamId: parsed.teamId
730
- });
731
- if (channelType === "group") peerKind = "group";
732
- if (channelType === "dm") peerKind = "direct";
733
- recipientSessionExact = channelType !== "unknown";
734
- }
735
- const peer = {
736
- kind: peerKind,
737
- id: peerId
738
- };
739
- const unpartitionedBaseSessionKey = buildOutboundBaseSessionKey({
740
- channel: "slack",
741
- cfg: params.cfg,
742
- agentId: params.agentId,
743
- accountId: params.accountId,
744
- peer
745
- });
746
- const baseSessionKey = parsed.teamId && peerKind === "direct" && (params.cfg.session?.dmScope ?? "main") === "main" ? `${unpartitionedBaseSessionKey}:account:${encodeURIComponent(resolveSlackAccount({
747
- cfg: params.cfg,
748
- accountId: params.accountId
749
- }).accountId).toLowerCase()}:team:${encodeURIComponent(parsed.teamId).toLowerCase()}` : unpartitionedBaseSessionKey;
750
- return buildThreadAwareOutboundSessionRoute({
751
- route: {
752
- sessionKey: baseSessionKey,
753
- baseSessionKey,
754
- recipientSessionExact,
755
- peer,
756
- chatType: peerKind === "direct" ? "direct" : "channel",
757
- from: peerKind === "direct" ? `slack:${peerId}` : peerKind === "group" ? `slack:group:${peerId}` : `slack:channel:${peerId}`,
758
- to: parsed.teamId ? peerId : peerKind === "direct" ? `user:${peerId}` : `channel:${peerId}`
759
- },
760
- replyToId: params.replyToId,
761
- threadId: params.threadId,
762
- currentSessionKey: params.currentSessionKey,
763
- canRecoverCurrentThread: () => peerKind !== "direct" || (params.cfg.session?.dmScope ?? "main") !== "main"
764
- });
765
- }
766
- function formatSlackScopeDiagnostic(params) {
767
- const source = params.result.source ? ` (${params.result.source})` : "";
768
- const label = params.tokenType === "user" ? "User scopes" : "Bot scopes";
769
- if (params.result.ok && params.result.scopes?.length) return { text: `${label}${source}: ${params.result.scopes.join(", ")}` };
770
- return {
771
- text: `${label}: ${params.result.error ?? "scope lookup failed"}`,
772
- tone: "error"
773
- };
774
- }
775
920
  const resolveSlackAllowlistGroupOverrides = createFlatAllowlistOverrideResolver({
776
921
  resolveRecord: (account) => account.channels,
777
922
  label: (key) => key,
@@ -887,11 +1032,21 @@ const slackPlugin = createChatChannelPlugin({
887
1032
  },
888
1033
  bindings: {
889
1034
  compileConfiguredBinding: ({ conversationId }) => normalizeSlackAcpConversationId(conversationId),
890
- matchInboundConversation: ({ compiledBinding, conversationId, parentConversationId }) => matchSlackAcpConversation({
891
- bindingConversationId: compiledBinding.conversationId,
892
- conversationId,
893
- parentConversationId
894
- })
1035
+ matchInboundConversation: ({ compiledBinding, conversationId: rawConversationId, parentConversationId: rawParentConversationId }) => {
1036
+ const bindingConversationId = normalizeSlackAcpConversationId(compiledBinding.conversationId)?.conversationId;
1037
+ const conversationId = normalizeSlackAcpConversationId(rawConversationId)?.conversationId;
1038
+ const parentConversationId = normalizeSlackAcpConversationId(rawParentConversationId)?.conversationId;
1039
+ if (!bindingConversationId || !conversationId) return null;
1040
+ if (bindingConversationId === conversationId) return {
1041
+ conversationId,
1042
+ matchPriority: 2
1043
+ };
1044
+ if (parentConversationId && parentConversationId !== conversationId && bindingConversationId === parentConversationId) return {
1045
+ conversationId: parentConversationId,
1046
+ matchPriority: 1
1047
+ };
1048
+ return null;
1049
+ }
895
1050
  },
896
1051
  conversationBindings: { isCurrentConversationBindingSupported: ({ accountId }) => isSlackWorkspaceInstallation(accountId) },
897
1052
  messaging: {
@@ -912,7 +1067,82 @@ const slackPlugin = createChatChannelPlugin({
912
1067
  return normalizeSlackMessagingTarget(`channel:${id}`);
913
1068
  },
914
1069
  inferTargetChatType: ({ to }) => resolveSlackRouteTarget(to)?.chatType,
915
- resolveOutboundSessionRoute: resolveSlackOutboundSessionRoute,
1070
+ resolveOutboundSessionRoute: async (params) => {
1071
+ const parsed = parseSlackTarget(params.target, { defaultKind: "channel" });
1072
+ if (!parsed) return null;
1073
+ const apiTargetId = canonicalizeSlackApiTargetId(parsed.kind, parsed.id, params.target);
1074
+ const isDm = parsed.kind === "user";
1075
+ if (params.deliveryPurpose === "heartbeat-owner" && isDm && !parsed.teamId && /^[UW][A-Z0-9]{8,}$/.test(apiTargetId)) {
1076
+ const teamId = await resolveSlackEnterpriseUserTeamId({
1077
+ cfg: params.cfg,
1078
+ accountId: params.accountId,
1079
+ userId: apiTargetId
1080
+ });
1081
+ if (teamId) {
1082
+ parsed.teamId = teamId;
1083
+ parsed.id = apiTargetId;
1084
+ }
1085
+ }
1086
+ let peerKind = isDm ? "direct" : "channel";
1087
+ let peerId = formatSlackTarget(parsed);
1088
+ let recipientSessionExact = isDm ? /^[UW][A-Z0-9]{8,}$/i.test(parsed.id) : /^C[A-Z0-9]{8,}$/i.test(parsed.id);
1089
+ if (!isDm && /^D/i.test(parsed.id)) {
1090
+ const conversation = await resolveSlackConversationInfo({
1091
+ cfg: params.cfg,
1092
+ accountId: params.accountId,
1093
+ channelId: apiTargetId,
1094
+ teamId: parsed.teamId
1095
+ });
1096
+ if (conversation.type !== "dm" || !conversation.user) return null;
1097
+ peerKind = "direct";
1098
+ peerId = formatSlackTarget({
1099
+ teamId: parsed.teamId,
1100
+ kind: "user",
1101
+ id: conversation.user
1102
+ });
1103
+ recipientSessionExact = true;
1104
+ } else if (!isDm && /^G/i.test(parsed.id)) {
1105
+ const channelType = await resolveSlackChannelType({
1106
+ cfg: params.cfg,
1107
+ accountId: params.accountId,
1108
+ channelId: apiTargetId,
1109
+ teamId: parsed.teamId
1110
+ });
1111
+ if (channelType === "group") peerKind = "group";
1112
+ if (channelType === "dm") peerKind = "direct";
1113
+ recipientSessionExact = channelType !== "unknown";
1114
+ }
1115
+ const peer = {
1116
+ kind: peerKind,
1117
+ id: peerId
1118
+ };
1119
+ const unpartitionedBaseSessionKey = buildOutboundBaseSessionKey({
1120
+ channel: "slack",
1121
+ cfg: params.cfg,
1122
+ agentId: params.agentId,
1123
+ accountId: params.accountId,
1124
+ peer
1125
+ });
1126
+ const baseSessionKey = parsed.teamId && peerKind === "direct" && (params.cfg.session?.dmScope ?? "main") === "main" ? `${unpartitionedBaseSessionKey}:account:${encodeURIComponent(resolveSlackAccount({
1127
+ cfg: params.cfg,
1128
+ accountId: params.accountId
1129
+ }).accountId).toLowerCase()}:team:${encodeURIComponent(parsed.teamId).toLowerCase()}` : unpartitionedBaseSessionKey;
1130
+ return buildThreadAwareOutboundSessionRoute({
1131
+ route: {
1132
+ sessionKey: baseSessionKey,
1133
+ baseSessionKey,
1134
+ recipientSessionExact,
1135
+ peer,
1136
+ chatType: peerKind === "direct" ? "direct" : "channel",
1137
+ from: peerKind === "direct" ? `slack:${peerId}` : peerKind === "group" ? `slack:group:${peerId}` : `slack:channel:${peerId}`,
1138
+ to: parsed.teamId ? peerId : peerKind === "direct" ? `user:${peerId}` : `channel:${peerId}`
1139
+ },
1140
+ replyToId: params.replyToId,
1141
+ threadId: params.threadId,
1142
+ currentSessionKey: params.currentSessionKey,
1143
+ canRecoverCurrentThread: () => peerKind !== "direct" || (params.cfg.session?.dmScope ?? "main") !== "main"
1144
+ });
1145
+ },
916
1146
  hasStructuredReplyPayload: ({ payload }) => {
917
1147
  try {
918
1148
  return Boolean(resolveSlackReplyBlocks(payload)?.length);
@@ -974,7 +1204,7 @@ const slackPlugin = createChatChannelPlugin({
974
1204
  mapResolved: (entry) => entry
975
1205
  });
976
1206
  } },
977
- actions: createSlackActions(SLACK_CHANNEL, { invoke: async (action, cfg, toolContext) => await (await resolveSlackHandleAction())(action, cfg, toolContext) }),
1207
+ actions: createSlackActions(SLACK_CHANNEL),
978
1208
  message: slackMessageAdapter,
979
1209
  heartbeat: {
980
1210
  sendTyping: (params) => setSlackHeartbeatThreadStatus({
@@ -987,7 +1217,7 @@ const slackPlugin = createChatChannelPlugin({
987
1217
  })
988
1218
  },
989
1219
  status: createComputedAccountStatusAdapter({
990
- defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
1220
+ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID$1),
991
1221
  buildChannelSummary: async ({ snapshot }) => {
992
1222
  const { buildPassiveProbedChannelStatusSummary } = await loadExtensionSharedSdk();
993
1223
  return buildPassiveProbedChannelStatusSummary(snapshot, snapshot.identity === "user" ? {
@@ -1010,8 +1240,7 @@ const slackPlugin = createChatChannelPlugin({
1010
1240
  ...account.identity === "user" ? { identity: "user" } : {}
1011
1241
  });
1012
1242
  },
1013
- formatCapabilitiesProbe: ({ probe }) => {
1014
- const slackProbe = probe;
1243
+ formatCapabilitiesProbe: ({ probe: slackProbe }) => {
1015
1244
  const lines = [];
1016
1245
  if (slackProbe?.warning) lines.push({
1017
1246
  text: `Warning: ${slackProbe.warning}`,
@@ -1041,10 +1270,12 @@ const slackPlugin = createChatChannelPlugin({
1041
1270
  ok: false,
1042
1271
  error: `Slack ${tokenType} token missing.`
1043
1272
  };
1044
- lines.push(formatSlackScopeDiagnostic({
1045
- tokenType,
1046
- result
1047
- }));
1273
+ const source = result.source ? ` (${result.source})` : "";
1274
+ const label = tokenType === "user" ? "User scopes" : "Bot scopes";
1275
+ lines.push(result.ok && result.scopes?.length ? { text: `${label}${source}: ${result.scopes.join(", ")}` } : {
1276
+ text: `${label}: ${result.error ?? "scope lookup failed"}`,
1277
+ tone: "error"
1278
+ });
1048
1279
  details[`${tokenType}Scopes`] = result;
1049
1280
  }
1050
1281
  return {
@@ -1090,8 +1321,7 @@ const slackPlugin = createChatChannelPlugin({
1090
1321
  abortSignal: ctx.abortSignal,
1091
1322
  mediaMaxMb: account.config.mediaMaxMb,
1092
1323
  slashCommand: account.config.slashCommand,
1093
- setStatus: ctx.setStatus,
1094
- getStatus: ctx.getStatus
1324
+ setStatus: ctx.setStatus
1095
1325
  });
1096
1326
  }
1097
1327
  },