@openclaw/slack 2026.10.10 → 2026.11.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/dist/.setup/{account-inspect-Bc7TVU8F.mjs → account-inspect-DgQgj0wk.mjs} +11 -8
  2. package/dist/.setup/{accounts-CEgdyqoW.mjs → accounts-EaPP0fFY.mjs} +10 -1
  3. package/dist/.setup/{action-runtime-DPoxYao5.mjs → action-runtime-CK9QZgQl.mjs} +38 -45
  4. package/dist/.setup/action-runtime.runtime-CpZktret.mjs +1 -0
  5. package/dist/.setup/{actions-PF2cP6to.mjs → actions-s3CcFO45.mjs} +89 -76
  6. package/dist/.setup/{approval-handler.runtime-BtRklemy.mjs → approval-handler.runtime-Ch7BecYK.mjs} +26 -30
  7. package/dist/.setup/{approval-message-updates-CpwbsEj6.mjs → approval-message-updates-CqcRoa28.mjs} +1 -1
  8. package/dist/.setup/{channel-B6bRmYmX.mjs → channel-CAvo_WNZ.mjs} +566 -338
  9. package/dist/.setup/{channel-type-Dh4vwh1Y.mjs → channel-type-9Lw6yLf2.mjs} +4 -8
  10. package/dist/.setup/{channel.setup-BBzT6uKA.mjs → channel.setup-BlgXNuCJ.mjs} +13 -13
  11. package/dist/.setup/{config-schema-Cz3uId-c.mjs → config-schema-Bx1tCZB0.mjs} +3 -7
  12. package/dist/.setup/cursor-pages-jVn3Vkfi.mjs +309 -0
  13. package/dist/.setup/{directory-config-BEPra1E2.mjs → directory-config-CGvKYg9F.mjs} +3 -3
  14. package/dist/.setup/{directory-live-BkUwPrS0.mjs → directory-live-DNdw97LA.mjs} +4 -4
  15. package/dist/.setup/{doctor-contract-HK8aedwU.mjs → doctor-contract-BB2KJ9Ni.mjs} +37 -45
  16. package/dist/.setup/{message-tool-api-DeiQJoRV.mjs → message-tool-api-B38BpEaE.mjs} +4 -3
  17. package/dist/.setup/{monitor-DsZUQtTM.mjs → monitor-BD86SotB.mjs} +3397 -3672
  18. package/dist/.setup/{outbound-adapter-C0R5jz6S.mjs → outbound-adapter-BH6iPWBj.mjs} +30 -36
  19. package/dist/.setup/paths-CQZI_5WY.mjs +7 -0
  20. package/dist/.setup/{pipeline.runtime-CIFVL0kf.mjs → pipeline.runtime-C4ELxaRU.mjs} +415 -534
  21. package/dist/.setup/{policy-Bp1FvE6m.mjs → policy-C6_DdlSf.mjs} +1 -2
  22. package/dist/.setup/{session-status-CHkEn3HM.mjs → probe-B_Ax1vS1.mjs} +985 -622
  23. package/dist/.setup/question-delivery-D3qAIwuv.mjs +38 -0
  24. package/dist/.setup/{relay-source-DFBDTA5Z.mjs → relay-source-a8jodKuO.mjs} +11 -4
  25. package/dist/.setup/{replies-7DRN46EL.mjs → replies-Bq7n0gfM.mjs} +34 -19
  26. package/dist/.setup/{reply-blocks-DOjiDr44.mjs → reply-blocks-DyYYRrP_.mjs} +200 -205
  27. package/dist/.setup/{resolve-channels-BNQ1KZXh.mjs → resolve-channels-CF2JME9q.mjs} +4 -7
  28. package/dist/.setup/{resolve-users-C4dC8Z7D.mjs → resolve-users-DDcCAjH1.mjs} +8 -16
  29. package/dist/.setup/{scopes-C1aeCBa6.mjs → scopes-CzHC_dwV.mjs} +2 -1
  30. package/dist/.setup/{secret-contract-D0UY2JWF.mjs → secret-contract-CqVqR7MP.mjs} +4 -2
  31. package/dist/.setup/{secret-contract-api-BhzGpUb0.mjs → secret-contract-api-DaCXZ47j.mjs} +1 -1
  32. package/dist/.setup/{send-C5uXkmZV.mjs → send-WJZ73VSf.mjs} +297 -333
  33. package/dist/.setup/{send-results-D-o6PgtS.mjs → send-results-Bm6V1ekL.mjs} +3 -4
  34. package/dist/.setup/setup-plugin-api-DJXIB8CF.mjs +2 -0
  35. package/dist/.setup/{setup-surface-CtM1pm-9.mjs → setup-surface-uIqP2B0Y.mjs} +5 -6
  36. package/dist/.setup/{slash-dispatch.runtime-Bnn9a5qB.mjs → slash-dispatch.runtime-Cwuwv7FL.mjs} +2 -2
  37. package/dist/.setup/{target-parsing-0pRZtahO.mjs → target-parsing-DwYAP3ts.mjs} +1 -2
  38. package/dist/.setup/{targets-BqXz7CpG.mjs → targets-eeOxA_b_.mjs} +1 -1
  39. package/dist/.source-module-urls/c5ffd0957b234c7c12090e7de4eca2482ef339b8561e078da55b734211b0ba58.json +1 -0
  40. package/dist/account-inspect-api.js +1 -1
  41. package/dist/api.js +16 -17
  42. package/dist/channel-config-api.js +1 -1
  43. package/dist/channel-plugin-api.js +1 -1
  44. package/dist/directory-contract-api.js +1 -1
  45. package/dist/doctor-contract-api.js +1 -1
  46. package/dist/index.js +0 -6
  47. package/dist/message-tool-api.js +1 -1
  48. package/dist/runtime-api.js +10 -12
  49. package/dist/secret-contract-api.js +1 -1
  50. package/dist/setup-entry.js +2 -2
  51. package/dist/setup-plugin-api.js +1 -1
  52. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  53. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  54. package/node_modules/@slack/bolt/node_modules/@types/node/util.d.ts +6 -3
  55. package/node_modules/@slack/bolt/node_modules/body-parser/README.md +13 -17
  56. package/node_modules/@slack/bolt/node_modules/body-parser/lib/read.js +57 -74
  57. package/node_modules/@slack/bolt/node_modules/body-parser/lib/types/json.js +11 -11
  58. package/node_modules/@slack/bolt/node_modules/body-parser/lib/types/urlencoded.js +5 -5
  59. package/node_modules/@slack/bolt/node_modules/body-parser/lib/utils.js +15 -0
  60. package/node_modules/@slack/bolt/node_modules/body-parser/package.json +12 -7
  61. package/node_modules/@slack/bolt/node_modules/content-disposition/README.md +105 -35
  62. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.d.ts +72 -0
  63. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js +388 -0
  64. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js.map +1 -0
  65. package/node_modules/@slack/bolt/node_modules/content-disposition/package.json +31 -19
  66. package/node_modules/@slack/bolt/node_modules/content-type/README.md +34 -57
  67. package/node_modules/@slack/bolt/node_modules/content-type/package.json +35 -25
  68. package/node_modules/@slack/bolt/node_modules/express/Readme.md +15 -9
  69. package/node_modules/@slack/bolt/node_modules/express/lib/application.js +2 -2
  70. package/node_modules/@slack/bolt/node_modules/express/lib/request.js +32 -19
  71. package/node_modules/@slack/bolt/node_modules/express/lib/response.js +27 -30
  72. package/node_modules/@slack/bolt/node_modules/express/package.json +10 -10
  73. package/node_modules/@slack/bolt/node_modules/qs/.github/THREAT_MODEL.md +4 -2
  74. package/node_modules/@slack/bolt/node_modules/qs/CHANGELOG.md +38 -14
  75. package/node_modules/@slack/bolt/node_modules/qs/README.md +31 -3
  76. package/node_modules/@slack/bolt/node_modules/qs/dist/qs.js +20 -20
  77. package/node_modules/@slack/bolt/node_modules/qs/lib/parse.js +94 -4
  78. package/node_modules/@slack/bolt/node_modules/qs/lib/stringify.js +4 -4
  79. package/node_modules/@slack/bolt/node_modules/qs/lib/utils.js +130 -6
  80. package/node_modules/@slack/bolt/node_modules/qs/package.json +4 -4
  81. package/node_modules/@slack/bolt/node_modules/qs/test/parse.js +174 -0
  82. package/node_modules/@slack/bolt/node_modules/qs/test/stringify.js +263 -33
  83. package/node_modules/@slack/bolt/node_modules/qs/test/utils.js +184 -0
  84. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  85. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  86. package/node_modules/@slack/web-api/node_modules/@types/node/util.d.ts +6 -3
  87. package/node_modules/typebox/build/format/duration.d.mts +2 -2
  88. package/node_modules/typebox/build/format/duration.mjs +2 -2
  89. package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
  90. package/node_modules/typebox/build/format/idn_email.mjs +1 -0
  91. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
  92. package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
  93. package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
  94. package/node_modules/typebox/build/format/ipv4.mjs +2 -2
  95. package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
  96. package/node_modules/typebox/build/format/ipv6.mjs +1 -1
  97. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  98. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  99. package/node_modules/typebox/build/schema/build.mjs +1 -0
  100. package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
  101. package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
  102. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
  103. package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
  104. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
  105. package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
  106. package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
  107. package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
  108. package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
  109. package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
  110. package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
  111. package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
  112. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
  113. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
  114. package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
  115. package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
  116. package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
  117. package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
  118. package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
  119. package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
  120. package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
  121. package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
  122. package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
  123. package/node_modules/typebox/build/system/memory/create.mjs +18 -13
  124. package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
  125. package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
  126. package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
  127. package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
  128. package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
  129. package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
  130. package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
  131. package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
  132. package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
  133. package/node_modules/typebox/build/system/memory/update.mjs +43 -16
  134. package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
  135. package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
  136. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
  137. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
  138. package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
  139. package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
  140. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
  141. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
  142. package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
  143. package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
  144. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
  145. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
  146. package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
  147. package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
  148. package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
  149. package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
  150. package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
  151. package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
  152. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
  153. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
  154. package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
  155. package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
  156. package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
  157. package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
  158. package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
  159. package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
  160. package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
  161. package/node_modules/typebox/package.json +1 -1
  162. package/node_modules/typebox/readme.md +1 -1
  163. package/node_modules/undici/docs/docs/api/Interceptors.md +15 -2
  164. package/node_modules/undici/lib/dispatcher/client-h2.js +78 -3
  165. package/node_modules/undici/lib/dispatcher/pool-base.js +20 -3
  166. package/node_modules/undici/package.json +3 -3
  167. package/node_modules/undici/types/api.d.ts +1 -1
  168. package/node_modules/undici/types/utility.d.ts +4 -4
  169. package/node_modules/zod/package.json +1 -1
  170. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  171. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  172. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  173. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  174. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  175. package/node_modules/zod/src/v4/core/util.ts +13 -0
  176. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  177. package/node_modules/zod/v4/core/compile.cjs +8 -0
  178. package/node_modules/zod/v4/core/compile.js +8 -0
  179. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  180. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  181. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  182. package/node_modules/zod/v4/core/schemas.js +30 -0
  183. package/node_modules/zod/v4/core/util.cjs +15 -0
  184. package/node_modules/zod/v4/core/util.d.cts +2 -0
  185. package/node_modules/zod/v4/core/util.d.ts +2 -0
  186. package/node_modules/zod/v4/core/util.js +14 -0
  187. package/node_modules/zod/v4/core/versions.cjs +1 -1
  188. package/node_modules/zod/v4/core/versions.js +1 -1
  189. package/openclaw.plugin.json +6 -30
  190. package/package.json +7 -7
  191. package/dist/.setup/action-runtime.runtime-DWKWaKgC.mjs +0 -1
  192. package/dist/.setup/http-GpAVKwSX.mjs +0 -2
  193. package/dist/.setup/plugin-routes-lXsy_bNV.mjs +0 -21
  194. package/dist/.setup/probe-C5VWf3sz.mjs +0 -686
  195. package/dist/.setup/registry-1G0f1zuZ.mjs +0 -34
  196. package/dist/.setup/setup-plugin-api-D7DoueEh.mjs +0 -2
  197. package/dist/.setup/shared-CohTHxM1.mjs +0 -255
  198. package/dist/.source-module-urls/562d694877afe9d9dcbb3b32a8883c16974738f2aa892c48d45572cdc9a62529.json +0 -1
  199. package/dist/http-routes-api.js +0 -1
  200. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/LICENSE +0 -22
  201. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +0 -71
  202. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +0 -52
  203. package/node_modules/@slack/bolt/node_modules/content-disposition/index.js +0 -536
  204. package/node_modules/@slack/bolt/node_modules/content-type/HISTORY.md +0 -29
  205. package/node_modules/@slack/bolt/node_modules/content-type/index.js +0 -225
  206. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +0 -22
  207. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +0 -71
  208. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +0 -46
  209. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +0 -176
  210. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +0 -1
  211. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +0 -52
  212. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/LICENSE +0 -22
  213. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +0 -71
  214. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +0 -46
  215. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +0 -176
  216. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +0 -1
  217. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +0 -52
  218. package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
  219. package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
  220. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.d.ts +0 -0
  221. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js +0 -0
  222. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js.map +0 -0
@@ -1,16 +1,16 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-nwUcYXjP.mjs";
2
- import { d as resolveSlackOperationToken, s as resolveSlackAccount } from "./accounts-CEgdyqoW.mjs";
3
- import { a as parseSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-0pRZtahO.mjs";
4
- import { A as SLACK_MESSAGE_TEXT_HARD_LIMIT, D as buildSlackCompleteBlocksFallbackText, F as truncateSlackTextByUtf8Bytes, K as resolveSlackQuestionActionIds, L as SLACK_QUESTION_FINALIZATION_BLOCKS, M as SLACK_TEXT_LIMIT, O as renderSlackBlockFallbackText, P as truncateSlackText, T as stripSlackNativeDataBlocks, X as chunkSlackMrkdwnText, Z as markdownToSlackMrkdwnChunks, b as hasSlackNativeDataBlock, gt as validateSlackBlocksArray, j as SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT, k as SLACK_EDIT_TEXT_MAX_BYTES, m as assertSlackDetachedTargetAllowed, v as buildSlackNativeDataAccessibilityText, w as renderSlackNativeDataPlainTextBlock, x as isSlackInvalidBlocksError, y as createSlackNativeDataBaseTextConsumer } from "./session-status-CHkEn3HM.mjs";
5
- import { _ as getSlackWriteClient, b as writeLruMapEntry, d as createSlackReadClient, h as createSlackWriteClient, o as formatSlackError, p as createSlackTokenCacheKey, s as getSlackWebApiErrorData } from "./probe-C5VWf3sz.mjs";
2
+ import { f as resolveSlackOperationToken, s as resolveSlackAccount } from "./accounts-EaPP0fFY.mjs";
3
+ import { a as parseSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-DwYAP3ts.mjs";
4
+ import { Ct as markdownToSlackMrkdwnChunks, D as createSlackNativeDataBaseTextConsumer, E as buildSlackNativeDataAccessibilityText, F as truncateSlackText, I as truncateSlackTextByUtf8Bytes, J as resolveSlackQuestionActionIds, M as renderSlackNativeDataPlainTextBlock, N as stripSlackNativeDataBlocks, O as hasSlackNativeDataBlock, R as SLACK_QUESTION_FINALIZATION_BLOCKS, S as assertSlackDetachedTargetAllowed, St as chunkSlackMrkdwnText, at as buildSlackCompleteBlocksFallbackText, bt as SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT, h as getSlackWebApiErrorData, k as isSlackInvalidBlocksError, m as formatSlackError, ot as renderSlackBlockFallbackText, rt as validateSlackBlocksArray, vt as SLACK_EDIT_TEXT_MAX_BYTES, xt as SLACK_TEXT_LIMIT, yt as SLACK_MESSAGE_TEXT_HARD_LIMIT } from "./probe-B_Ax1vS1.mjs";
6
5
  import { r as resolveSlackThreadTsValue, t as normalizeSlackThreadTsCandidate } from "./thread-ts-47Au2-Yn.mjs";
6
+ import { c as createSlackWriteClient, d as getOrCreateWeakOwnerMap, i as createSlackReadClient, m as writeLruMapEntry, o as createSlackTokenCacheKey, u as getSlackWriteClient } from "./cursor-pages-jVn3Vkfi.mjs";
7
7
  import { t as getOptionalSlackRuntime } from "./runtime-C6HKn7Av.mjs";
8
- import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
9
8
  import { asOptionalObjectRecord, asOptionalRecord, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
9
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
10
10
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
11
11
  import { logVerbose, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
12
12
  import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
13
- import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
13
+ import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
14
14
  import { resolveTextChunksWithFallback } from "openclaw/plugin-sdk/reply-payload";
15
15
  import { createHash, createHmac } from "node:crypto";
16
16
  import { withTrustedEnvProxyGuardedFetchMode } from "openclaw/plugin-sdk/fetch-runtime";
@@ -111,62 +111,9 @@ function buildSlackMessageIdentityPayload(identity) {
111
111
  ...identity?.iconUrl ? { icon_url: identity.iconUrl } : identity?.iconEmoji ? { icon_emoji: identity.iconEmoji } : {}
112
112
  };
113
113
  }
114
- function classifySlackCustomIdentityError(err) {
115
- const data = getSlackWebApiErrorData(err);
116
- const code = normalizeLowercaseStringOrEmpty(data?.error);
117
- if (code === "invalid_arguments" || code === "invalid_arg_name") return "argument";
118
- if (code !== "missing_scope") return;
119
- if (normalizeLowercaseStringOrEmpty(data?.needed).includes("chat:write.customize")) return "scope";
120
- return [...normalizeTrimmedStringList(data?.response_metadata?.scopes), ...normalizeTrimmedStringList(data?.response_metadata?.acceptedScopes)].map((scope) => normalizeLowercaseStringOrEmpty(scope)).includes("chat:write.customize") ? "scope" : void 0;
121
- }
122
114
  function hasSlackMessageIdentity(identity) {
123
115
  return Boolean(identity?.username || identity?.iconUrl || identity?.iconEmoji);
124
116
  }
125
- /** Post with the requested identity, degrading only on Slack identity-specific errors. */
126
- async function postSlackMessageWithIdentityFallback(params) {
127
- const { basePayload, identity, post } = params;
128
- try {
129
- if (!identity) return await post(basePayload);
130
- return await post({
131
- ...basePayload,
132
- ...buildSlackMessageIdentityPayload(identity)
133
- }, identity);
134
- } catch (err) {
135
- if (!identity || !hasSlackMessageIdentity(identity)) throw err;
136
- const rejection = classifySlackCustomIdentityError(err);
137
- if (!rejection) throw err;
138
- if (rejection === "argument" && identity.username && (identity.iconUrl || identity.iconEmoji)) {
139
- logVerbose("slack send: custom icon rejected, retrying with username only");
140
- try {
141
- return await post({
142
- ...basePayload,
143
- username: identity.username
144
- }, { username: identity.username });
145
- } catch (retryError) {
146
- if (!classifySlackCustomIdentityError(retryError)) throw retryError;
147
- }
148
- }
149
- logVerbose("slack send: custom identity rejected, retrying without custom identity");
150
- return post(basePayload);
151
- }
152
- }
153
- // extensions/slack/src/post-message-payload.ts
154
- function buildSlackPostMessagePayload(params) {
155
- const threadPayload = params.replyBroadcast && params.threadTs ? {
156
- thread_ts: params.threadTs,
157
- reply_broadcast: true
158
- } : params.threadTs ? { thread_ts: params.threadTs } : {};
159
- return {
160
- channel: params.channelId,
161
- text: params.text,
162
- ...params.blocks?.length ? { blocks: params.blocks } : {},
163
- ...params.metadata ? { metadata: params.metadata } : {},
164
- ...typeof params.mrkdwn === "boolean" ? { mrkdwn: params.mrkdwn } : {},
165
- ...threadPayload,
166
- unfurl_links: params.unfurl?.unfurlLinks ?? false,
167
- ...typeof params.unfurl?.unfurlMedia === "boolean" ? { unfurl_media: params.unfurl.unfurlMedia } : {}
168
- };
169
- }
170
117
  // extensions/slack/src/client-delivery.ts
171
118
  const SLACK_COMMERCIAL_API_HOSTNAME = "slack.com";
172
119
  const SLACK_COMMERCIAL_UPLOAD_HOSTNAME = "files.slack.com";
@@ -288,18 +235,61 @@ function requireSlackPostMessageTimestamp(response) {
288
235
  if (!timestamp) throw new Error("Slack chat.postMessage returned no message timestamp");
289
236
  return timestamp;
290
237
  }
238
+ function classifySlackCustomIdentityError(err) {
239
+ const data = getSlackWebApiErrorData(err);
240
+ const code = normalizeLowercaseStringOrEmpty(data?.error);
241
+ if (code === "invalid_arguments" || code === "invalid_arg_name") return "argument";
242
+ if (code !== "missing_scope") return;
243
+ if (normalizeLowercaseStringOrEmpty(data?.needed).includes("chat:write.customize")) return "scope";
244
+ return [...normalizeTrimmedStringList(data?.response_metadata?.scopes), ...normalizeTrimmedStringList(data?.response_metadata?.acceptedScopes)].map((scope) => normalizeLowercaseStringOrEmpty(scope)).includes("chat:write.customize") ? "scope" : void 0;
245
+ }
291
246
  async function postSlackMessageBestEffort(params) {
292
- const basePayload = buildSlackPostMessagePayload(params);
247
+ const threadPayload = params.replyBroadcast && params.threadTs ? {
248
+ thread_ts: params.threadTs,
249
+ reply_broadcast: true
250
+ } : params.threadTs ? { thread_ts: params.threadTs } : {};
251
+ const basePayload = {
252
+ channel: params.channelId,
253
+ text: params.text,
254
+ ...params.blocks?.length ? { blocks: params.blocks } : {},
255
+ ...params.metadata ? { metadata: params.metadata } : {},
256
+ ...params.mrkdwn !== void 0 ? { mrkdwn: params.mrkdwn } : {},
257
+ ...threadPayload,
258
+ unfurl_links: params.unfurl?.unfurlLinks ?? false,
259
+ ...params.unfurl?.unfurlMedia !== void 0 ? { unfurl_media: params.unfurl.unfurlMedia } : {}
260
+ };
293
261
  const postChatMessage = params.client.chat.postMessage.bind(params.client.chat);
294
262
  const post = async (payload, identity) => ({
295
263
  response: await withSlackDnsRequestRetry("chat.postMessage", () => postChatMessage(payload)).catch(rethrowSlackPermanentOutboundApiRejection),
296
264
  identity
297
265
  });
298
- const posted = await postSlackMessageWithIdentityFallback({
299
- basePayload,
300
- identity: params.identity,
301
- post
302
- });
266
+ const identity = params.identity;
267
+ const posted = await (async () => {
268
+ try {
269
+ if (!identity) return await post(basePayload);
270
+ return await post({
271
+ ...basePayload,
272
+ ...buildSlackMessageIdentityPayload(identity)
273
+ }, identity);
274
+ } catch (err) {
275
+ if (!identity || !hasSlackMessageIdentity(identity)) throw err;
276
+ const rejection = classifySlackCustomIdentityError(err);
277
+ if (!rejection) throw err;
278
+ if (rejection === "argument" && identity.username && (identity.iconUrl || identity.iconEmoji)) {
279
+ logVerbose("slack send: custom icon rejected, retrying with username only");
280
+ try {
281
+ return await post({
282
+ ...basePayload,
283
+ username: identity.username
284
+ }, { username: identity.username });
285
+ } catch (retryError) {
286
+ if (!classifySlackCustomIdentityError(retryError)) throw retryError;
287
+ }
288
+ }
289
+ logVerbose("slack send: custom identity rejected, retrying without custom identity");
290
+ return post(basePayload);
291
+ }
292
+ })();
303
293
  const timestamp = requireSlackPostMessageTimestamp(posted.response);
304
294
  return {
305
295
  ...posted,
@@ -458,18 +448,11 @@ const slackDmChannelCaches = /* @__PURE__ */ new WeakMap();
458
448
  function createSlackDmCacheKey(params) {
459
449
  return `${params.accountId ?? "default"}:${createSlackTokenCacheKey(params.token)}:${params.recipientId}`;
460
450
  }
461
- function getSlackDmChannelCache(client) {
462
- const existing = slackDmChannelCaches.get(client);
463
- if (existing) return existing;
464
- const cache = /* @__PURE__ */ new Map();
465
- slackDmChannelCaches.set(client, cache);
466
- return cache;
467
- }
468
451
  function readCachedSlackDmChannelId(params) {
469
- return getSlackDmChannelCache(params.cacheOwner).get(createSlackDmCacheKey(params));
452
+ return slackDmChannelCaches.get(params.cacheOwner)?.get(createSlackDmCacheKey(params));
470
453
  }
471
454
  function cacheSlackDmChannelId(params, channelId) {
472
- const cache = getSlackDmChannelCache(params.cacheOwner);
455
+ const cache = getOrCreateWeakOwnerMap(slackDmChannelCaches, params.cacheOwner);
473
456
  const key = createSlackDmCacheKey(params);
474
457
  writeLruMapEntry(cache, key, channelId, SLACK_DM_CHANNEL_CACHE_MAX);
475
458
  }
@@ -536,17 +519,23 @@ function resolvePostedMessageThreadTs(response) {
536
519
  }
537
520
  async function updateMessageSlack(params) {
538
521
  const cfg = requireRuntimeConfig(params.cfg, "Slack update");
539
- const account = resolveSlackAccount({
540
- cfg,
541
- accountId: params.accountId
542
- });
543
- assertSlackDetachedTargetAllowed(account.accountId, params.teamId);
544
- const token = resolveToken({
545
- accountId: account.accountId,
546
- fallbackToken: account.botToken,
547
- fallbackSource: account.botTokenSource
522
+ const { client } = resolveSlackDelivery({
523
+ account: resolveSlackAccount({
524
+ cfg,
525
+ accountId: params.accountId
526
+ }),
527
+ eventScope: params.eventScope,
528
+ opts: {
529
+ cfg,
530
+ token: params.token
531
+ },
532
+ recipient: {
533
+ kind: "channel",
534
+ id: params.channelId,
535
+ teamId: params.teamId
536
+ }
548
537
  });
549
- await getSlackWriteClient(token, { teamId: params.teamId }).chat.update({
538
+ await client.chat.update({
550
539
  channel: params.channelId,
551
540
  ts: params.messageTs,
552
541
  text: truncateSlackTextByUtf8Bytes(params.text, SLACK_EDIT_TEXT_MAX_BYTES),
@@ -623,19 +612,20 @@ function parseEnterpriseEventRecipient(raw) {
623
612
  function resolveSlackDelivery(params) {
624
613
  if (params.eventScope) {
625
614
  if (!params.eventScope.writeClient) throw new Error("missing_enterprise_slack_write_client");
626
- return Object.freeze({
615
+ return {
627
616
  client: params.eventScope.writeClient,
628
617
  credential: SLACK_ENTERPRISE_LISTENER_QUEUE_CREDENTIAL,
629
618
  identity: normalizeSlackSendIdentity(params.opts.identity),
630
619
  recipient: params.recipient,
631
620
  teamId: params.eventScope.teamId,
632
621
  unfurl: { unfurlMedia: params.account.config.unfurlMedia },
633
- upload: Object.freeze({
622
+ upload: {
634
623
  client: params.eventScope.client,
635
624
  auditContext: "slack-enterprise-immediate-upload"
636
- })
637
- });
625
+ }
626
+ };
638
627
  }
628
+ assertSlackDetachedTargetAllowed(params.account.accountId, params.recipient.teamId);
639
629
  const credential = resolveToken({
640
630
  explicit: params.opts.token,
641
631
  accountId: params.account.accountId,
@@ -644,7 +634,7 @@ function resolveSlackDelivery(params) {
644
634
  });
645
635
  const cachedClient = params.recipient.teamId ? getSlackWriteClient(credential, { teamId: params.recipient.teamId }) : params.opts.client ?? getSlackWriteClient(credential);
646
636
  const client = params.opts.assertDirectAdapterHandoff ? createSlackWriteClient(credential, { teamId: params.recipient.teamId }, params.opts.assertDirectAdapterHandoff) : cachedClient;
647
- return Object.freeze({
637
+ return {
648
638
  client,
649
639
  ...client !== cachedClient ? { dmCacheOwner: cachedClient } : {},
650
640
  credential,
@@ -655,7 +645,7 @@ function resolveSlackDelivery(params) {
655
645
  unfurlLinks: params.account.config.unfurlLinks,
656
646
  unfurlMedia: params.account.config.unfurlMedia
657
647
  }
658
- });
648
+ };
659
649
  }
660
650
  async function resolveChannelId(client, recipient, params) {
661
651
  if (recipient.kind !== "user") return recipient.id;
@@ -672,20 +662,6 @@ async function resolveChannelId(client, recipient, params) {
672
662
  cacheSlackDmChannelId(cacheParams, channelId);
673
663
  return channelId;
674
664
  }
675
- function resolveSlackTextChunks(params) {
676
- const text = params.text;
677
- const chunkLimit = params.chunkLimit;
678
- if (params.preservePlainText) return text ? chunkTextForOutbound(text, chunkLimit, { preserveWhitespace: true }) : [];
679
- if (params.textIsSlackMrkdwn) return resolveTextChunksWithFallback(text, chunkSlackMrkdwnText(text, chunkLimit));
680
- const tableMode = resolveMarkdownTableMode({
681
- cfg: params.cfg,
682
- channel: "slack",
683
- ...params.accountId ? { accountId: params.accountId } : {}
684
- });
685
- const chunkMode = resolveChunkMode(params.cfg, "slack", params.accountId);
686
- const chunks = (chunkMode === "newline" ? chunkMarkdownTextWithMode(text, chunkLimit, chunkMode) : [text]).flatMap((markdown) => markdownToSlackMrkdwnChunks(markdown, chunkLimit, { tableMode }));
687
- return resolveTextChunksWithFallback(text, chunks);
688
- }
689
665
  async function resolveSlackDmChannelId(params) {
690
666
  return await resolveChannelId(params.client, {
691
667
  kind: "user",
@@ -756,37 +732,8 @@ const SLACK_RECONCILIATION_EVIDENCE_RANK = {
756
732
  conflict: 2,
757
733
  complete: 3
758
734
  };
759
- function findSlackConversationDeliveryParts(params) {
760
- const matches = [];
761
- for (const message of params.messages) {
762
- const marker = asOptionalRecord(asOptionalRecord(message.metadata)?.event_payload);
763
- if (!marker || marker[SLACK_DELIVERY_METADATA_KEY] !== params.deliveryId) continue;
764
- const partIndex = marker[SLACK_DELIVERY_METADATA_PART_INDEX_KEY];
765
- const partCount = marker[SLACK_DELIVERY_METADATA_PART_COUNT_KEY];
766
- if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || typeof partCount !== "number" || !Number.isInteger(partCount) || partIndex < 0 || partCount <= 0 || partIndex >= partCount) continue;
767
- const expectedSignature = createSlackDeliveryMetadataSignature({
768
- queueId: params.queueId,
769
- channelId: params.channelId,
770
- threadTs: params.threadTs,
771
- partIndex,
772
- partCount
773
- });
774
- const actualSignature = marker[SLACK_DELIVERY_METADATA_SIGNATURE_KEY];
775
- if (typeof actualSignature !== "string" || !safeEqualSecret(actualSignature, expectedSignature)) continue;
776
- const messageId = typeof message.ts === "string" ? normalizeSlackThreadTsCandidate(message.ts) : void 0;
777
- if (!messageId) continue;
778
- const threadTs = typeof message.thread_ts === "string" ? normalizeSlackThreadTsCandidate(message.thread_ts) : void 0;
779
- matches.push({
780
- messageId,
781
- partIndex,
782
- partCount,
783
- ...threadTs ? { threadTs } : {}
784
- });
785
- }
786
- return matches;
787
- }
788
735
  async function scanSlackConversationForDelivery(params) {
789
- const threadTs = params.threadTs;
736
+ const lookupThreadTs = params.threadTs;
790
737
  let cursor;
791
738
  let expectedPartCount;
792
739
  const deliveryParts = /* @__PURE__ */ new Map();
@@ -799,17 +746,36 @@ async function scanSlackConversationForDelivery(params) {
799
746
  limit: SLACK_RECONCILE_LIMIT,
800
747
  ...cursor ? { cursor } : {}
801
748
  };
802
- const response = threadTs ? await withSlackDnsRequestRetry("conversations.replies", () => params.client.conversations.replies({
749
+ const response = lookupThreadTs ? await withSlackDnsRequestRetry("conversations.replies", () => params.client.conversations.replies({
803
750
  ...query,
804
- ts: threadTs
751
+ ts: lookupThreadTs
805
752
  })) : await withSlackDnsRequestRetry("conversations.history", () => params.client.conversations.history(query));
806
- const matches = findSlackConversationDeliveryParts({
807
- messages: asSlackConversationMessages(response),
808
- queueId: params.queueId,
809
- deliveryId: params.deliveryId,
810
- channelId: params.channelId,
811
- ...threadTs ? { threadTs } : {}
812
- });
753
+ const matches = [];
754
+ for (const message of asSlackConversationMessages(response)) {
755
+ const marker = asOptionalRecord(asOptionalRecord(message.metadata)?.event_payload);
756
+ if (!marker || marker[SLACK_DELIVERY_METADATA_KEY] !== params.deliveryId) continue;
757
+ const partIndex = marker[SLACK_DELIVERY_METADATA_PART_INDEX_KEY];
758
+ const partCount = marker[SLACK_DELIVERY_METADATA_PART_COUNT_KEY];
759
+ if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || typeof partCount !== "number" || !Number.isInteger(partCount) || partIndex < 0 || partCount <= 0 || partIndex >= partCount) continue;
760
+ const expectedSignature = createSlackDeliveryMetadataSignature({
761
+ queueId: params.queueId,
762
+ channelId: params.channelId,
763
+ threadTs: lookupThreadTs,
764
+ partIndex,
765
+ partCount
766
+ });
767
+ const actualSignature = marker[SLACK_DELIVERY_METADATA_SIGNATURE_KEY];
768
+ if (typeof actualSignature !== "string" || !safeEqualSecret(actualSignature, expectedSignature)) continue;
769
+ const messageId = typeof message.ts === "string" ? normalizeSlackThreadTsCandidate(message.ts) : void 0;
770
+ if (!messageId) continue;
771
+ const threadTs = typeof message.thread_ts === "string" ? normalizeSlackThreadTsCandidate(message.thread_ts) : void 0;
772
+ matches.push({
773
+ messageId,
774
+ partIndex,
775
+ partCount,
776
+ ...threadTs ? { threadTs } : {}
777
+ });
778
+ }
813
779
  for (const match of matches) {
814
780
  expectedPartCount ??= match.partCount;
815
781
  const existing = deliveryParts.get(match.partIndex);
@@ -915,208 +881,206 @@ async function reconcileSlackUnknownSend(ctx) {
915
881
  return unresolvedSlackDelivery(readSlackRequestErrorMessage(enrichSlackWebApiError(err)), ctx.retryCount < 3);
916
882
  }
917
883
  }
918
- async function sendMessageSlack(to, message, opts) {
884
+ async function sendMessageSlack(to, message, options) {
919
885
  const normalizedMessage = normalizeOptionalString(message) ?? "";
920
- const trimmedMessage = opts.textIsSlackPlainText && normalizedMessage ? message : normalizedMessage;
921
- const cfg = requireRuntimeConfig(opts.cfg, "Slack send");
886
+ const trimmedMessage = options.textIsSlackPlainText && normalizedMessage ? message : normalizedMessage;
887
+ const cfg = requireRuntimeConfig(options.cfg, "Slack send");
922
888
  const account = resolveSlackAccount({
923
889
  cfg,
924
- accountId: opts.accountId
890
+ accountId: options.accountId
925
891
  });
926
- const eventScope = opts.eventScope;
892
+ const eventScope = options.eventScope;
927
893
  if (eventScope && (!/^T[A-Z0-9]+$/i.test(eventScope.teamId) || !eventScope.client)) throw new Error("invalid_enterprise_slack_listener_scope");
928
- const recipient = eventScope ? parseEnterpriseEventRecipient(to) : parseRecipient(to);
929
- if (!eventScope) assertSlackDetachedTargetAllowed(account.accountId, recipient.teamId);
930
- const blocks = opts.blocks == null ? void 0 : validateSlackBlocksArray(opts.blocks);
931
- if (!normalizedMessage && !opts.mediaUrl && !blocks) throw new Error("Slack send requires text, blocks, or media");
932
- const queuedOpts = Object.freeze({ ...opts });
894
+ const parsedRecipient = eventScope ? parseEnterpriseEventRecipient(to) : parseRecipient(to);
895
+ const blocks = options.blocks == null ? void 0 : validateSlackBlocksArray(options.blocks);
896
+ if (!normalizedMessage && !options.mediaUrl && !blocks) throw new Error("Slack send requires text, blocks, or media");
897
+ const opts = { ...options };
933
898
  const delivery = resolveSlackDelivery({
934
899
  account,
935
900
  eventScope,
936
- opts: queuedOpts,
937
- recipient
901
+ opts,
902
+ recipient: parsedRecipient
938
903
  });
939
904
  const workspaceScope = delivery.teamId ? `:${delivery.teamId}` : "";
940
- const queueKey = `${account.accountId}:${createSlackTokenCacheKey(delivery.credential)}${workspaceScope}:${delivery.recipient.kind}:${delivery.recipient.id}:${opts.threadTs ?? ""}`;
941
- const result = await slackSendQueue.enqueue(queueKey, () => sendMessageSlackQueued({
942
- trimmedMessage,
943
- opts: queuedOpts,
944
- cfg,
945
- account,
946
- blocks,
947
- delivery
948
- }).catch((err) => {
949
- throw enrichSlackWebApiError(err);
950
- }));
951
- const threadTs = result.threadTs ?? normalizeSlackThreadTsCandidate(queuedOpts.threadTs);
952
- if (threadTs && result.channelId && account.accountId) recordSlackThreadParticipation(account.accountId, result.channelId, threadTs, { teamId: delivery.teamId });
953
- return result;
954
- }
955
- async function sendMessageSlackQueued(params) {
956
- const { opts, cfg, account, blocks, trimmedMessage, delivery } = params;
957
- const { client, identity, recipient, unfurl } = delivery;
958
- if (opts.replyBroadcast && opts.mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
959
- const directUserPostChannelId = !opts.deliveryQueueId && recipient.kind === "user" && !opts.mediaUrl && !opts.threadTs ? recipient.id : void 0;
960
- const channelId = directUserPostChannelId ? directUserPostChannelId : await resolveChannelId(client, recipient, {
961
- accountId: account.accountId,
962
- token: delivery.credential,
963
- ...delivery.dmCacheOwner ? { dmCacheOwner: delivery.dmCacheOwner } : {}
964
- });
965
- const deliveredResults = [];
966
- const reportDelivery = async (result, deliveredBlocks) => {
967
- const slackQuestionActionIds = resolveSlackQuestionActionIds(deliveredBlocks);
968
- const deliveryResult = slackQuestionActionIds.length ? {
969
- ...result,
970
- meta: {
971
- ...result.meta,
972
- slackQuestionActionIds,
973
- [SLACK_QUESTION_FINALIZATION_BLOCKS]: deliveredBlocks.filter((block) => block.type !== "actions")
974
- }
975
- } : result;
976
- deliveredResults.push(deliveryResult);
977
- await opts.onDeliveryResult?.(deliveryResult);
978
- return deliveryResult;
979
- };
980
- let didDispatch = false;
981
- const dispatchOnce = async () => {
982
- if (didDispatch) return;
983
- didDispatch = true;
984
- await opts.onPlatformSendDispatch?.();
985
- };
986
- const explicitNativeDataFallbackBase = Object.hasOwn(opts, "nativeDataFallbackBaseText") ? opts.nativeDataFallbackBaseText?.trim() ?? "" : void 0;
987
- const authoredTextPlacement = opts.authoredTextPlacement ?? "outside-blocks";
988
- const nativeDataFallbackBase = blocks && authoredTextPlacement === "outside-blocks" ? explicitNativeDataFallbackBase ?? trimmedMessage : "";
989
- const hasNativeData = Boolean(blocks && hasSlackNativeDataBlock(blocks));
990
- const textChunkLimit = Math.min(opts.textLimit ?? resolveTextChunkLimit(cfg, "slack", account.accountId, { fallbackLimit: 8e3 }), SLACK_TEXT_LIMIT);
991
- const usesOrderedBlockAccessibility = Boolean(blocks && (hasNativeData || opts.authoredTextPlacement !== void 0));
992
- const orderedBlockDeliveryPlan = blocks && usesOrderedBlockAccessibility ? buildSlackNativeDataDeliveryPlan({
993
- baseText: nativeDataFallbackBase,
994
- blocks,
995
- textLimit: textChunkLimit
996
- }) : void 0;
997
- const completeBlockFallbackText = blocks ? buildSlackCompleteBlocksFallbackText(blocks) : "";
998
- const rawBlockAccessibilityText = trimmedMessage ? [trimmedMessage, ...completeBlockFallbackText.includes(trimmedMessage) ? [] : [completeBlockFallbackText]].join("\n\n") : completeBlockFallbackText;
999
- const blockAccessibilityText = blocks ? orderedBlockDeliveryPlan?.accessibilityText ?? rawBlockAccessibilityText : void 0;
1000
- let pendingBlockFallback = orderedBlockDeliveryPlan?.skipOriginalBlocks ? orderedBlockDeliveryPlan : void 0;
1001
- let lastMessageId = "";
1002
- let deliveredChannelId = channelId;
1003
- let canonicalDeliveredThreadTs;
1004
- let sendIdentity = identity;
1005
- const postPart = async (part) => {
1006
- const posted = await postSlackMessageBestEffort({
1007
- client,
1008
- channelId,
1009
- threadTs: opts.threadTs,
1010
- identity: sendIdentity,
1011
- unfurl,
1012
- ...part
1013
- });
1014
- const { response } = posted;
1015
- sendIdentity = posted.identity;
1016
- lastMessageId = response.ts;
1017
- deliveredChannelId = (typeof response.channel === "string" ? normalizeOptionalString(response.channel) : null) ?? deliveredChannelId;
1018
- const responseThreadTs = resolvePostedMessageThreadTs(response);
1019
- canonicalDeliveredThreadTs ??= responseThreadTs;
1020
- return await reportDelivery(createSlackSendResult(response.ts, deliveredChannelId, part.blocks ? "card" : "text", responseThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs)), part.blocks);
1021
- };
1022
- if (blocks && opts.mediaUrl) throw new Error("Slack send does not support blocks with mediaUrl");
1023
- if (blocks) {
1024
- if (pendingBlockFallback) logVerbose("slack send: native data accessibility exceeds hard limit, using text fallback");
1025
- else {
1026
- const accessibilityText = usesOrderedBlockAccessibility ? blockAccessibilityText ?? "Slack could not render this Block Kit message." : truncateSlackText(blockAccessibilityText ?? "", SLACK_TEXT_LIMIT);
1027
- const initialBlockMetadata = withSlackDeliveryMetadata(opts.metadata, {
1028
- queueId: opts.deliveryQueueId,
1029
- channelId,
1030
- threadTs: opts.threadTs,
1031
- partIndex: 0,
1032
- partCount: 1
905
+ const queueKey = `${account.accountId}:${createSlackTokenCacheKey(delivery.credential)}${workspaceScope}:${delivery.recipient.kind}:${delivery.recipient.id}:${options.threadTs ?? ""}`;
906
+ const sent = await slackSendQueue.enqueue(queueKey, async () => {
907
+ try {
908
+ const { client, identity, recipient, unfurl } = delivery;
909
+ if (opts.replyBroadcast && opts.mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
910
+ const directUserPostChannelId = !opts.deliveryQueueId && recipient.kind === "user" && !opts.mediaUrl && !opts.threadTs ? recipient.id : void 0;
911
+ const channelId = directUserPostChannelId ? directUserPostChannelId : await resolveChannelId(client, recipient, {
912
+ accountId: account.accountId,
913
+ token: delivery.credential,
914
+ ...delivery.dmCacheOwner ? { dmCacheOwner: delivery.dmCacheOwner } : {}
1033
915
  });
1034
- await dispatchOnce();
1035
- try {
1036
- return await postPart({
1037
- text: accessibilityText,
1038
- replyBroadcast: opts.replyBroadcast,
1039
- blocks,
1040
- metadata: initialBlockMetadata,
1041
- ...usesOrderedBlockAccessibility ? { mrkdwn: false } : {}
916
+ const deliveredResults = [];
917
+ const reportDelivery = async (result, deliveredBlocks) => {
918
+ const slackQuestionActionIds = resolveSlackQuestionActionIds(deliveredBlocks);
919
+ const deliveryResult = slackQuestionActionIds.length ? {
920
+ ...result,
921
+ meta: {
922
+ ...result.meta,
923
+ slackQuestionActionIds,
924
+ [SLACK_QUESTION_FINALIZATION_BLOCKS]: deliveredBlocks
925
+ }
926
+ } : result;
927
+ deliveredResults.push(deliveryResult);
928
+ await opts.onDeliveryResult?.(deliveryResult);
929
+ return deliveryResult;
930
+ };
931
+ let didDispatch = false;
932
+ const dispatchOnce = async () => {
933
+ if (didDispatch) return;
934
+ didDispatch = true;
935
+ await opts.onPlatformSendDispatch?.();
936
+ };
937
+ const explicitNativeDataFallbackBase = Object.hasOwn(opts, "nativeDataFallbackBaseText") ? opts.nativeDataFallbackBaseText?.trim() ?? "" : void 0;
938
+ const authoredTextPlacement = opts.authoredTextPlacement ?? "outside-blocks";
939
+ const nativeDataFallbackBase = blocks && authoredTextPlacement === "outside-blocks" ? explicitNativeDataFallbackBase ?? trimmedMessage : "";
940
+ const hasNativeData = Boolean(blocks && hasSlackNativeDataBlock(blocks));
941
+ const textChunkLimit = Math.min(opts.textLimit ?? resolveTextChunkLimit(cfg, "slack", account.accountId, { fallbackLimit: 8e3 }), SLACK_TEXT_LIMIT);
942
+ const usesOrderedBlockAccessibility = Boolean(blocks && (hasNativeData || opts.authoredTextPlacement !== void 0));
943
+ const orderedBlockDeliveryPlan = blocks && usesOrderedBlockAccessibility ? buildSlackNativeDataDeliveryPlan({
944
+ baseText: nativeDataFallbackBase,
945
+ blocks,
946
+ textLimit: textChunkLimit
947
+ }) : void 0;
948
+ let pendingBlockFallback = orderedBlockDeliveryPlan?.skipOriginalBlocks ? orderedBlockDeliveryPlan : void 0;
949
+ let lastMessageId = "";
950
+ let deliveredChannelId = channelId;
951
+ let canonicalDeliveredThreadTs;
952
+ let sendIdentity = identity;
953
+ const postPart = async (part) => {
954
+ const posted = await postSlackMessageBestEffort({
955
+ client,
956
+ channelId,
957
+ threadTs: opts.threadTs,
958
+ identity: sendIdentity,
959
+ unfurl,
960
+ ...part
961
+ });
962
+ const { response } = posted;
963
+ sendIdentity = posted.identity;
964
+ lastMessageId = response.ts;
965
+ deliveredChannelId = (typeof response.channel === "string" ? normalizeOptionalString(response.channel) : null) ?? deliveredChannelId;
966
+ const responseThreadTs = resolvePostedMessageThreadTs(response);
967
+ canonicalDeliveredThreadTs ??= responseThreadTs;
968
+ return await reportDelivery(createSlackSendResult(response.ts, deliveredChannelId, part.blocks ? "card" : "text", responseThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs)), part.blocks);
969
+ };
970
+ if (blocks && opts.mediaUrl) throw new Error("Slack send does not support blocks with mediaUrl");
971
+ if (blocks) {
972
+ if (pendingBlockFallback) logVerbose("slack send: native data accessibility exceeds hard limit, using text fallback");
973
+ else {
974
+ let accessibilityText = orderedBlockDeliveryPlan?.accessibilityText;
975
+ if (accessibilityText === void 0) {
976
+ const fallback = buildSlackCompleteBlocksFallbackText(blocks);
977
+ accessibilityText = truncateSlackText(trimmedMessage ? [trimmedMessage, ...fallback.includes(trimmedMessage) ? [] : [fallback]].join("\n\n") : fallback, SLACK_TEXT_LIMIT);
978
+ }
979
+ const initialBlockMetadata = withSlackDeliveryMetadata(opts.metadata, {
980
+ queueId: opts.deliveryQueueId,
981
+ channelId,
982
+ threadTs: opts.threadTs,
983
+ partIndex: 0,
984
+ partCount: 1
985
+ });
986
+ await dispatchOnce();
987
+ try {
988
+ return await postPart({
989
+ text: accessibilityText,
990
+ replyBroadcast: opts.replyBroadcast,
991
+ blocks,
992
+ metadata: initialBlockMetadata,
993
+ ...usesOrderedBlockAccessibility ? { mrkdwn: false } : {}
994
+ });
995
+ } catch (error) {
996
+ if (!hasNativeData || !isSlackInvalidBlocksError(error)) throw error;
997
+ logVerbose("slack send: native data rejected, delivering complete text fallback");
998
+ pendingBlockFallback = orderedBlockDeliveryPlan;
999
+ }
1000
+ }
1001
+ }
1002
+ let messages;
1003
+ if (pendingBlockFallback) messages = pendingBlockFallback.fallbackMessages;
1004
+ else {
1005
+ let resolvedChunks;
1006
+ if (opts.textIsSlackPlainText) resolvedChunks = trimmedMessage ? chunkTextForOutbound(trimmedMessage, textChunkLimit, { preserveWhitespace: true }) : [];
1007
+ else if (opts.textIsSlackMrkdwn) resolvedChunks = resolveTextChunksWithFallback(trimmedMessage, chunkSlackMrkdwnText(trimmedMessage, textChunkLimit));
1008
+ else {
1009
+ const tableMode = resolveMarkdownTableMode({
1010
+ cfg,
1011
+ channel: "slack",
1012
+ ...account.accountId ? { accountId: account.accountId } : {}
1013
+ });
1014
+ const chunkMode = resolveChunkMode(cfg, "slack", account.accountId);
1015
+ const chunks = (chunkMode === "newline" ? chunkMarkdownTextWithMode(trimmedMessage, textChunkLimit, chunkMode) : [trimmedMessage]).flatMap((markdown) => markdownToSlackMrkdwnChunks(markdown, textChunkLimit, { tableMode }));
1016
+ resolvedChunks = resolveTextChunksWithFallback(trimmedMessage, chunks);
1017
+ }
1018
+ const mediaMaxBytes = opts.mediaMaxBytes ?? (typeof account.config.mediaMaxMb === "number" ? account.config.mediaMaxMb * 1024 * 1024 : void 0);
1019
+ let chunksToPost;
1020
+ if (opts.mediaUrl) {
1021
+ const [firstChunk, ...rest] = resolvedChunks;
1022
+ lastMessageId = await uploadSlackFile({
1023
+ client: delivery.upload?.client ?? client,
1024
+ completionClient: client,
1025
+ channelId,
1026
+ mediaUrl: opts.mediaUrl,
1027
+ mediaAccess: opts.mediaAccess,
1028
+ uploadFileName: opts.uploadFileName,
1029
+ uploadTitle: opts.uploadTitle,
1030
+ mediaLocalRoots: opts.mediaLocalRoots,
1031
+ mediaReadFile: opts.mediaReadFile,
1032
+ caption: firstChunk,
1033
+ threadTs: opts.threadTs,
1034
+ maxBytes: mediaMaxBytes,
1035
+ ...opts.forceDocument ? { optimizeImages: false } : {},
1036
+ onPlatformSendDispatch: dispatchOnce,
1037
+ assertDirectAdapterHandoff: opts.assertDirectAdapterHandoff,
1038
+ ...delivery.upload ? { auditContext: delivery.upload.auditContext } : {}
1039
+ });
1040
+ await reportDelivery(createSlackSendResult(lastMessageId, channelId, "media", normalizeSlackThreadTsCandidate(opts.threadTs)));
1041
+ chunksToPost = rest;
1042
+ } else chunksToPost = resolvedChunks.length ? resolvedChunks : [""];
1043
+ messages = chunksToPost.map((text) => opts.textIsSlackPlainText ? {
1044
+ text,
1045
+ mrkdwn: false
1046
+ } : { text });
1047
+ }
1048
+ let questionDelivery;
1049
+ for (const [partIndex, part] of messages.entries()) {
1050
+ const carriesPrimaryMessageOptions = partIndex === 0 && !opts.mediaUrl;
1051
+ const baseMetadata = carriesPrimaryMessageOptions ? opts.metadata : void 0;
1052
+ const metadata = opts.mediaUrl ? baseMetadata : withSlackDeliveryMetadata(baseMetadata, {
1053
+ queueId: opts.deliveryQueueId,
1054
+ channelId,
1055
+ threadTs: opts.threadTs,
1056
+ partIndex,
1057
+ partCount: messages.length
1042
1058
  });
1043
- } catch (error) {
1044
- if (!hasNativeData || !isSlackInvalidBlocksError(error)) throw error;
1045
- logVerbose("slack send: native data rejected, delivering complete text fallback");
1046
- pendingBlockFallback = orderedBlockDeliveryPlan;
1059
+ if (partIndex === 0 && !opts.mediaUrl) await dispatchOnce();
1060
+ const partDelivery = await postPart({
1061
+ ...part,
1062
+ replyBroadcast: carriesPrimaryMessageOptions ? opts.replyBroadcast : void 0,
1063
+ metadata
1064
+ });
1065
+ if (pendingBlockFallback && partDelivery.meta?.slackQuestionActionIds.length) questionDelivery = partDelivery;
1047
1066
  }
1067
+ const deliveredThreadTs = canonicalDeliveredThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
1068
+ return {
1069
+ messageId: lastMessageId,
1070
+ channelId: deliveredChannelId,
1071
+ threadTs: deliveredThreadTs,
1072
+ ...questionDelivery?.meta ? { meta: {
1073
+ ...questionDelivery.meta,
1074
+ slackQuestionMessageId: questionDelivery.messageId
1075
+ } } : {},
1076
+ receipt: createSlackSendReceiptFromResults(deliveredResults, deliveredThreadTs)
1077
+ };
1078
+ } catch (err) {
1079
+ throw enrichSlackWebApiError(err);
1048
1080
  }
1049
- }
1050
- let messages;
1051
- if (pendingBlockFallback) messages = pendingBlockFallback.fallbackMessages;
1052
- else {
1053
- const resolvedChunks = resolveSlackTextChunks({
1054
- cfg,
1055
- accountId: account.accountId,
1056
- text: trimmedMessage,
1057
- chunkLimit: textChunkLimit,
1058
- ...opts.textIsSlackMrkdwn ? { textIsSlackMrkdwn: true } : {},
1059
- ...opts.textIsSlackPlainText ? { preservePlainText: true } : {}
1060
- });
1061
- const mediaMaxBytes = opts.mediaMaxBytes ?? (typeof account.config.mediaMaxMb === "number" ? account.config.mediaMaxMb * 1024 * 1024 : void 0);
1062
- let chunksToPost;
1063
- if (opts.mediaUrl) {
1064
- const [firstChunk, ...rest] = resolvedChunks;
1065
- lastMessageId = await uploadSlackFile({
1066
- client: delivery.upload?.client ?? client,
1067
- completionClient: client,
1068
- channelId,
1069
- mediaUrl: opts.mediaUrl,
1070
- mediaAccess: opts.mediaAccess,
1071
- uploadFileName: opts.uploadFileName,
1072
- uploadTitle: opts.uploadTitle,
1073
- mediaLocalRoots: opts.mediaLocalRoots,
1074
- mediaReadFile: opts.mediaReadFile,
1075
- caption: firstChunk,
1076
- threadTs: opts.threadTs,
1077
- maxBytes: mediaMaxBytes,
1078
- ...opts.forceDocument ? { optimizeImages: false } : {},
1079
- onPlatformSendDispatch: dispatchOnce,
1080
- assertDirectAdapterHandoff: opts.assertDirectAdapterHandoff,
1081
- ...delivery.upload ? { auditContext: delivery.upload.auditContext } : {}
1082
- });
1083
- await reportDelivery(createSlackSendResult(lastMessageId, channelId, "media", normalizeSlackThreadTsCandidate(opts.threadTs)));
1084
- chunksToPost = rest;
1085
- } else chunksToPost = resolvedChunks.length ? resolvedChunks : [""];
1086
- messages = chunksToPost.map((text) => opts.textIsSlackPlainText ? {
1087
- text,
1088
- mrkdwn: false
1089
- } : { text });
1090
- }
1091
- let questionDelivery;
1092
- for (const [partIndex, part] of messages.entries()) {
1093
- const carriesPrimaryMessageOptions = partIndex === 0 && !opts.mediaUrl;
1094
- const baseMetadata = carriesPrimaryMessageOptions ? opts.metadata : void 0;
1095
- const metadata = opts.mediaUrl ? baseMetadata : withSlackDeliveryMetadata(baseMetadata, {
1096
- queueId: opts.deliveryQueueId,
1097
- channelId,
1098
- threadTs: opts.threadTs,
1099
- partIndex,
1100
- partCount: messages.length
1101
- });
1102
- if (partIndex === 0 && !opts.mediaUrl) await dispatchOnce();
1103
- const partDelivery = await postPart({
1104
- ...part,
1105
- replyBroadcast: carriesPrimaryMessageOptions ? opts.replyBroadcast : void 0,
1106
- metadata
1107
- });
1108
- if (pendingBlockFallback && partDelivery.meta?.slackQuestionActionIds.length) questionDelivery = partDelivery;
1109
- }
1110
- const deliveredThreadTs = canonicalDeliveredThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
1111
- return {
1112
- messageId: lastMessageId,
1113
- channelId: deliveredChannelId,
1114
- threadTs: deliveredThreadTs,
1115
- ...questionDelivery?.meta ? { meta: {
1116
- ...questionDelivery.meta,
1117
- slackQuestionMessageId: questionDelivery.messageId
1118
- } } : {},
1119
- receipt: createSlackSendReceiptFromResults(deliveredResults, deliveredThreadTs)
1120
- };
1081
+ });
1082
+ const threadTs = sent.threadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
1083
+ if (threadTs && sent.channelId && account.accountId) recordSlackThreadParticipation(account.accountId, sent.channelId, threadTs, { teamId: delivery.teamId });
1084
+ return sent;
1121
1085
  }
1122
- export { clearSlackThreadParticipationCache as a, hasSlackThreadParticipationWithPersistence as c, requireSlackPostMessageTimestamp as d, buildSlackMessageIdentityPayload as f, chunkSlackTextAtHardLimit as h, clearSlackThreadFailureNotice as i, recordSlackThreadFailureNotice as l, buildSlackNativeDataDeliveryPlan as m, send_exports as n, hasSlackThreadFailureNotice as o, hasSlackMessageIdentity as p, setSlackDefaultSendIdentity as r, hasSlackThreadParticipation as s, sendMessageSlack as t, recordSlackThreadParticipation as u };
1086
+ export { clearSlackThreadFailureNotice as a, hasSlackThreadParticipation as c, recordSlackThreadParticipation as d, requireSlackPostMessageTimestamp as f, chunkSlackTextAtHardLimit as g, buildSlackNativeDataDeliveryPlan as h, updateMessageSlack as i, hasSlackThreadParticipationWithPersistence as l, hasSlackMessageIdentity as m, send_exports as n, clearSlackThreadParticipationCache as o, buildSlackMessageIdentityPayload as p, setSlackDefaultSendIdentity as r, hasSlackThreadFailureNotice as s, sendMessageSlack as t, recordSlackThreadFailureNotice as u };