@openclaw/slack 2026.8.1-beta.3 → 2026.8.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 (237) hide show
  1. package/dist/account-configured-sUohAxZr.js +33 -0
  2. package/dist/account-inspect-CN2hBsim.js +87 -0
  3. package/dist/account-inspect-api.js +1 -1
  4. package/dist/{accounts-BlzxuYle.js → accounts-Dm_H77gH.js} +7 -10
  5. package/dist/{accounts.runtime-CbabBL8x.js → accounts.runtime-DRuEK6mL.js} +1 -1
  6. package/dist/{action-runtime-D6jg2CQd.js → action-runtime-044ldvNL.js} +53 -48
  7. package/dist/action-runtime.runtime-BL3KzX13.js +2 -0
  8. package/dist/{actions-DFk0ANVB.js → actions-BI7JkfVm.js} +266 -96
  9. package/dist/api.js +12 -12
  10. package/dist/{approval-handler.runtime-BNvAoKdK.js → approval-handler.runtime-DYv0UIZS.js} +53 -176
  11. package/dist/{channel-CA5w7qDF.js → channel-1vIJOzPx.js} +77 -142
  12. package/dist/channel-config-api.js +1 -1
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel-type-CZWv55Wu.js → channel-type-DlFSKeIZ.js} +3 -3
  15. package/dist/{channel.setup-CpyYsEXH.js → channel.setup-ofDi3_Pu.js} +34 -49
  16. package/dist/{config-schema-CN3XZRX5.js → config-schema-BVIMyiDN.js} +19 -12
  17. package/dist/configured-state.js +34 -0
  18. package/dist/{directory-config-BGYyuzWh.js → directory-config-DqfQ42OV.js} +1 -1
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-DjUJQLbq.js → directory-live-BPaNHjmP.js} +2 -2
  21. package/dist/{group-policy-DyfB_ZIE.js → group-policy-BdwszjYn.js} +581 -743
  22. package/dist/{message-tool-api-CqMr5Rmc.js → message-tool-api-CJ0kjcg5.js} +23 -5
  23. package/dist/message-tool-api.js +1 -1
  24. package/dist/{monitor-Chrecrb9.js → monitor-Dq5Cmrvp.js} +3 -3
  25. package/dist/{outbound-adapter-DuRqAQXK.js → outbound-adapter-DYaI8ThX.js} +93 -68
  26. package/dist/{pipeline.runtime-Bbfd5VFW.js → pipeline.runtime-Bd22U0ga.js} +128 -160
  27. package/dist/{policy-BKXSxrIS.js → policy-CtQVbde1.js} +2 -1
  28. package/dist/{probe-BVA65leh.js → probe-0usmAb0i.js} +209 -22
  29. package/dist/{provider-CUUiwsg2.js → provider-CN_8hFv2.js} +243 -146
  30. package/dist/{relay-source-mhpMMRG-.js → relay-source-BNGpsdwV.js} +1 -1
  31. package/dist/{replies-SnWyXcsL.js → replies-BSiRQOJ1.js} +15 -5
  32. package/dist/{resolve-channels-BSpqC8jU.js → resolve-channels-Czheznc8.js} +1 -1
  33. package/dist/{resolve-users-Dvz9pDe0.js → resolve-users-BAOlNimr.js} +1 -1
  34. package/dist/runtime-api.js +11 -11
  35. package/dist/{scopes-BSk4GZvZ.js → scopes-COSlmhnH.js} +1 -1
  36. package/dist/{send-CtnOxKCc.js → send-DS9ICrBI.js} +39 -31
  37. package/dist/send-results-eeOu_HYm.js +23 -0
  38. package/dist/{send.runtime-kYctMHSd.js → send.runtime-D_Bb6IuH.js} +1 -1
  39. package/dist/setup-plugin-api.js +1 -1
  40. package/dist/{setup-surface-BPFfp6So.js → setup-surface-BGnd2pSe.js} +6 -6
  41. package/dist/{shared-DJBaslN7.js → shared-D5B-5hBg.js} +26 -6
  42. package/dist/{slash-dispatch.runtime-Cf2FTrnf.js → slash-dispatch.runtime-CilDmI0c.js} +3 -3
  43. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  44. package/node_modules/@slack/bolt/node_modules/@types/node/child_process.d.ts +0 -1
  45. package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +6 -6
  46. package/node_modules/@slack/bolt/node_modules/@types/node/dns/promises.d.ts +5 -5
  47. package/node_modules/@slack/bolt/node_modules/@types/node/dns.d.ts +5 -5
  48. package/node_modules/@slack/bolt/node_modules/@types/node/fs.d.ts +7 -0
  49. package/node_modules/@slack/bolt/node_modules/@types/node/http.d.ts +30 -0
  50. package/node_modules/@slack/bolt/node_modules/@types/node/http2.d.ts +4 -4
  51. package/node_modules/@slack/bolt/node_modules/@types/node/os.d.ts +30 -30
  52. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  53. package/node_modules/@slack/bolt/node_modules/@types/node/perf_hooks.d.ts +2 -1
  54. package/node_modules/@slack/bolt/node_modules/@types/node/process.d.ts +42 -43
  55. package/node_modules/@slack/bolt/node_modules/@types/node/quic.d.ts +1049 -84
  56. package/node_modules/@slack/bolt/node_modules/@types/node/sqlite.d.ts +14 -1
  57. package/node_modules/@slack/bolt/node_modules/@types/node/stream/iter.d.ts +3 -2
  58. package/node_modules/@slack/bolt/node_modules/@types/node/test.d.ts +61 -0
  59. package/node_modules/@slack/bolt/node_modules/@types/node/v8.d.ts +20 -23
  60. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  61. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  62. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  63. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  64. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  65. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +2 -0
  66. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  67. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  68. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  69. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +1 -1
  70. package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
  71. package/node_modules/@slack/socket-mode/node_modules/@types/node/child_process.d.ts +0 -1
  72. package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +6 -6
  73. package/node_modules/@slack/socket-mode/node_modules/@types/node/dns/promises.d.ts +5 -5
  74. package/node_modules/@slack/socket-mode/node_modules/@types/node/dns.d.ts +5 -5
  75. package/node_modules/@slack/socket-mode/node_modules/@types/node/fs.d.ts +7 -0
  76. package/node_modules/@slack/socket-mode/node_modules/@types/node/http.d.ts +30 -0
  77. package/node_modules/@slack/socket-mode/node_modules/@types/node/http2.d.ts +4 -4
  78. package/node_modules/@slack/socket-mode/node_modules/@types/node/os.d.ts +30 -30
  79. package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
  80. package/node_modules/@slack/socket-mode/node_modules/@types/node/perf_hooks.d.ts +2 -1
  81. package/node_modules/@slack/socket-mode/node_modules/@types/node/process.d.ts +42 -43
  82. package/node_modules/@slack/socket-mode/node_modules/@types/node/quic.d.ts +1049 -84
  83. package/node_modules/@slack/socket-mode/node_modules/@types/node/sqlite.d.ts +14 -1
  84. package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/iter.d.ts +3 -2
  85. package/node_modules/@slack/socket-mode/node_modules/@types/node/test.d.ts +61 -0
  86. package/node_modules/@slack/socket-mode/node_modules/@types/node/v8.d.ts +20 -23
  87. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  88. package/node_modules/@slack/web-api/node_modules/@types/node/child_process.d.ts +0 -1
  89. package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +6 -6
  90. package/node_modules/@slack/web-api/node_modules/@types/node/dns/promises.d.ts +5 -5
  91. package/node_modules/@slack/web-api/node_modules/@types/node/dns.d.ts +5 -5
  92. package/node_modules/@slack/web-api/node_modules/@types/node/fs.d.ts +7 -0
  93. package/node_modules/@slack/web-api/node_modules/@types/node/http.d.ts +30 -0
  94. package/node_modules/@slack/web-api/node_modules/@types/node/http2.d.ts +4 -4
  95. package/node_modules/@slack/web-api/node_modules/@types/node/os.d.ts +30 -30
  96. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  97. package/node_modules/@slack/web-api/node_modules/@types/node/perf_hooks.d.ts +2 -1
  98. package/node_modules/@slack/web-api/node_modules/@types/node/process.d.ts +42 -43
  99. package/node_modules/@slack/web-api/node_modules/@types/node/quic.d.ts +1049 -84
  100. package/node_modules/@slack/web-api/node_modules/@types/node/sqlite.d.ts +14 -1
  101. package/node_modules/@slack/web-api/node_modules/@types/node/stream/iter.d.ts +3 -2
  102. package/node_modules/@slack/web-api/node_modules/@types/node/test.d.ts +61 -0
  103. package/node_modules/@slack/web-api/node_modules/@types/node/v8.d.ts +20 -23
  104. package/node_modules/typebox/build/format/date.d.mts +1 -1
  105. package/node_modules/typebox/build/format/date.mjs +1 -1
  106. package/node_modules/typebox/build/format/date_time.d.mts +2 -2
  107. package/node_modules/typebox/build/format/date_time.mjs +3 -3
  108. package/node_modules/typebox/build/format/email.d.mts +1 -1
  109. package/node_modules/typebox/build/format/email.mjs +2 -2
  110. package/node_modules/typebox/build/format/hostname.mjs +2 -10
  111. package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
  112. package/node_modules/typebox/build/format/idn_email.mjs +3 -3
  113. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
  114. package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
  115. package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
  116. package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
  117. package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
  118. package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
  119. package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
  120. package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
  121. package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
  122. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
  123. package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
  124. package/node_modules/typebox/build/format/idna/index.mjs +2 -0
  125. package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
  126. package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
  127. package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
  128. package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
  129. package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
  130. package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
  131. package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
  132. package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
  133. package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
  134. package/node_modules/typebox/build/format/ipv4.mjs +2 -32
  135. package/node_modules/typebox/build/format/ipv6.mjs +2 -61
  136. package/node_modules/typebox/build/format/iri.d.mts +2 -2
  137. package/node_modules/typebox/build/format/iri.mjs +26 -8
  138. package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
  139. package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
  140. package/node_modules/typebox/build/format/regex.d.mts +1 -2
  141. package/node_modules/typebox/build/format/regex.mjs +2 -6
  142. package/node_modules/typebox/build/format/time.d.mts +2 -2
  143. package/node_modules/typebox/build/format/time.mjs +19 -14
  144. package/node_modules/typebox/build/format/uri.d.mts +1 -1
  145. package/node_modules/typebox/build/format/uri.mjs +3 -130
  146. package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
  147. package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
  148. package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
  149. package/node_modules/typebox/build/format/uri_template.mjs +4 -5
  150. package/node_modules/typebox/build/format/url.d.mts +3 -3
  151. package/node_modules/typebox/build/format/url.mjs +4 -5
  152. package/node_modules/typebox/build/guard/emit.d.mts +3 -1
  153. package/node_modules/typebox/build/guard/emit.mjs +12 -5
  154. package/node_modules/typebox/build/guard/guard.d.mts +8 -2
  155. package/node_modules/typebox/build/guard/guard.mjs +25 -4
  156. package/node_modules/typebox/build/guard/string.d.mts +2 -2
  157. package/node_modules/typebox/build/guard/string.mjs +7 -7
  158. package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
  159. package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
  160. package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
  161. package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
  162. package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
  163. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
  164. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
  165. package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
  166. package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
  167. package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
  168. package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
  169. package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
  170. package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
  171. package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
  172. package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
  173. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
  174. package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
  175. package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
  176. package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
  177. package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
  178. package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
  179. package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
  180. package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
  181. package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
  182. package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
  183. package/node_modules/typebox/build/schema/types/index.mjs +0 -2
  184. package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
  185. package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
  186. package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
  187. package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
  188. package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
  189. package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
  190. package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
  191. package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
  192. package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
  193. package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
  194. package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
  195. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
  196. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
  197. package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
  198. package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
  199. package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
  200. package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
  201. package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
  202. package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
  203. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
  204. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
  205. package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
  206. package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
  207. package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
  208. package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
  209. package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
  210. package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
  211. package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
  212. package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
  213. package/node_modules/typebox/build/type/script/parser.mjs +27 -23
  214. package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
  215. package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
  216. package/node_modules/typebox/package.json +27 -27
  217. package/node_modules/typebox/readme.md +79 -82
  218. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  219. package/node_modules/ws/package.json +1 -1
  220. package/openclaw.plugin.json +14 -6
  221. package/package.json +9 -7
  222. package/dist/account-configured-BwfXBo_F.js +0 -14
  223. package/dist/account-inspect-YJvFBbCR.js +0 -89
  224. package/dist/action-runtime.runtime-JtoOK9l5.js +0 -2
  225. package/dist/actions.runtime-CYLsYRai.js +0 -2
  226. package/dist/runtime-api-DBi7xc_g.js +0 -10
  227. package/dist/slack-client-kind-BXyOOICI.js +0 -94
  228. package/node_modules/typebox/build/format/_idna.d.mts +0 -2
  229. package/node_modules/typebox/build/format/_idna.mjs +0 -246
  230. package/node_modules/typebox/build/format/_puny.d.mts +0 -1
  231. package/node_modules/typebox/build/format/_puny.mjs +0 -77
  232. package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
  233. package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
  234. package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
  235. package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
  236. package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
  237. package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
@@ -1,9 +1,9 @@
1
- import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-BlzxuYle.js";
1
+ import { n as isSlackPluginAccountConfigured } from "./account-configured-sUohAxZr.js";
2
+ import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-Dm_H77gH.js";
2
3
  import { a as parseSlackTarget, n as formatSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-BnMD2ZqZ.js";
3
4
  import { t as slackContextTargetsMatch } from "./targets-Cx5W_n3W.js";
4
- import { t as isSlackPluginAccountConfigured } from "./account-configured-BwfXBo_F.js";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
6
- import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringifiedOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
+ import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { normalizeMessageChannel } from "openclaw/plugin-sdk/routing";
8
8
  import { FormatCapabilityProfile, chunkTextForOutbound, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-chunking";
9
9
  import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
@@ -13,15 +13,15 @@ import { createChannelApprovalAuth, resolveApprovalApprovers } from "openclaw/pl
13
13
  import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, isChannelExecApprovalTargetRecipient, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
14
14
  import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
15
15
  import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
16
- import { normalizeMessagePresentation, reduceLegacyInteractiveReply, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
16
+ import { legacyInteractiveReplyToPresentation, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
17
17
  import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
18
+ import { resolveAskUserQuestionOptionIndex, resolveAskUserQuestionOptionIndices } from "openclaw/plugin-sdk/reply-payload";
18
19
  import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
20
+ import { eastAsianWidthType } from "get-east-asian-width";
19
21
  import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
20
22
  import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
21
- import { eastAsianWidthType } from "get-east-asian-width";
22
23
  import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
23
- import { compileAllowlist, resolveCompiledAllowlistMatch } from "openclaw/plugin-sdk/allow-from";
24
- import { normalizeHyphenSlug, normalizeStringEntries as normalizeStringEntries$1, normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-normalization-runtime";
24
+ import { normalizeHyphenSlug } from "openclaw/plugin-sdk/string-normalization-runtime";
25
25
  import { resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
26
26
  //#region extensions/slack/src/action-threading.ts
27
27
  const SLACK_PRIVATE_ACTION_DELIVERY_RESULT = Symbol("slack.action.delivery-result");
@@ -924,109 +924,457 @@ function renderSlackDataVisualizationMrkdwnFallbackText(value) {
924
924
  return typeof block.title === "string" && block.title.trim() ? escapeSlackMrkdwn(block.title.trim()) : void 0;
925
925
  }
926
926
  //#endregion
927
- //#region extensions/slack/src/question-actions.ts
928
- const SLACK_QUESTION_VALUE_PREFIX = "slq1:";
929
- const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
930
- function encodeSlackQuestionAction(action) {
931
- if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
932
- const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
933
- return value.length <= 2e3 ? value : void 0;
927
+ //#region extensions/slack/src/format.ts
928
+ function escapeSlackMrkdwnSegment(text) {
929
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
934
930
  }
935
- function decodeSlackQuestionAction(value) {
936
- if (typeof value !== "string" || value.length > 2e3) return null;
937
- const match = /^slq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(value);
938
- return match?.[1] && match[2] ? {
939
- questionId: match[1],
940
- optionIndex: Number(match[2])
941
- } : null;
931
+ const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
932
+ function isAllowedSlackAngleToken(token) {
933
+ if (!token.startsWith("<") || !token.endsWith(">")) return false;
934
+ const inner = token.slice(1, -1);
935
+ return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
942
936
  }
943
- async function resolveSlackQuestionAction(params) {
944
- let result;
945
- try {
946
- result = await (params.resolveQuestion ?? questionGatewayRuntime.resolveOption)({
947
- cfg: params.cfg,
948
- questionId: params.action.questionId,
949
- optionIndex: params.action.optionIndex,
950
- senderId: params.userId,
951
- clientDisplayName: `Slack question (${params.accountId})`
952
- });
953
- } catch {
954
- await params.respond("Could not submit this answer.").catch(() => {});
955
- return;
937
+ function escapeSlackMrkdwnContent(text) {
938
+ if (!text) return "";
939
+ if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
940
+ SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
941
+ const out = [];
942
+ let lastIndex = 0;
943
+ for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
944
+ const matchIndex = match.index ?? 0;
945
+ out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
946
+ const token = match[0] ?? "";
947
+ out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
948
+ lastIndex = matchIndex + token.length;
956
949
  }
957
- await params.respond(result.status === "answered" ? "Answer submitted." : "This question was already answered.").catch(() => {});
950
+ out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
951
+ return out.join("");
958
952
  }
959
- //#endregion
960
- //#region extensions/slack/src/reply-action-ids.ts
961
- const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
962
- const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
963
- const SLACK_SESSION_LINK_ACTION_ID = "openclaw:session_link";
964
- const SLACK_REPLY_SELECT_ACTION_ID = "openclaw:reply_select";
965
- const SLACK_CALLBACK_BUTTON_ACTION_ID = "openclaw:callback_button";
966
- const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
967
- const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
968
- const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
969
- const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
970
- const SLACK_QUESTION_FINALIZATION_BLOCKS = Symbol("slackQuestionFinalizationBlocks");
971
- function isSlackQuestionActionId(actionId) {
972
- return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
953
+ function escapeSlackMrkdwnText(text) {
954
+ if (!text) return "";
955
+ if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
956
+ return text.split("\n").map((line) => {
957
+ if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
958
+ return escapeSlackMrkdwnContent(line);
959
+ }).join("\n");
973
960
  }
974
- /** Read only question control identities from the blocks actually sent to Slack. */
975
- function resolveSlackQuestionActionIds(blocks) {
976
- return (blocks ?? []).flatMap((block) => {
977
- if (block.type !== "actions") return [];
978
- return (block.elements ?? []).flatMap(({ action_id }) => action_id && isSlackQuestionActionId(action_id) ? [action_id] : []);
979
- });
961
+ function buildSlackLink(link, text) {
962
+ const href = link.href.trim();
963
+ if (!href) return null;
964
+ const trimmedLabel = text.slice(link.start, link.end).trim();
965
+ const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
966
+ if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
967
+ const safeHref = escapeSlackMrkdwnSegment(href);
968
+ return {
969
+ start: link.start,
970
+ end: link.end,
971
+ open: `<${safeHref}|`,
972
+ close: ">"
973
+ };
980
974
  }
981
- function isSlackApprovalActionId(actionId) {
982
- return actionId === "openclaw:approval_button" || actionId === "openclaw:approval_select" || actionId.startsWith(`openclaw:approval_button:`) || actionId.startsWith(`openclaw:approval_select:`);
975
+ const SLACK_MRKDWN_WORD_CHARACTER_RE = /[\p{L}\p{M}\p{N}_]/u;
976
+ const SLACK_MRKDWN_PUNCTUATION_RE = /\p{P}/u;
977
+ const SLACK_MRKDWN_SYMBOL_RE = /\p{S}/u;
978
+ const SLACK_MRKDWN_CJK_SCRIPT_RE = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u;
979
+ const SLACK_MRKDWN_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
980
+ function getCodePointBefore(text, index) {
981
+ if (index <= 0) return "";
982
+ const lastCodeUnit = text.charCodeAt(index - 1);
983
+ if (lastCodeUnit >= 56320 && lastCodeUnit <= 57343 && index > 1) {
984
+ const previousCodeUnit = text.charCodeAt(index - 2);
985
+ if (previousCodeUnit >= 55296 && previousCodeUnit <= 56319) return text.slice(index - 2, index);
986
+ }
987
+ return text[index - 1] ?? "";
983
988
  }
984
- function isSlackCallbackActionId(actionId) {
985
- return actionId === "openclaw:callback_button" || actionId === "openclaw:callback_select" || actionId.startsWith(`openclaw:callback_button:`) || actionId.startsWith(`openclaw:callback_select:`);
989
+ function getCodePointAt(text, index) {
990
+ const codePoint = text.codePointAt(index);
991
+ return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
986
992
  }
987
- //#endregion
988
- //#region extensions/slack/src/truncate.ts
989
- function truncateSlackText(value, max) {
990
- const trimmed = value.trim();
991
- if (trimmed.length <= max) return trimmed;
992
- if (max <= 1) return sliceUtf16Safe(trimmed, 0, max);
993
- return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
993
+ function isSlackCjkPunctuation(character) {
994
+ if (!SLACK_MRKDWN_PUNCTUATION_RE.test(character)) return false;
995
+ if (SLACK_MRKDWN_CJK_SCRIPT_RE.test(character)) return true;
996
+ const codePoint = character.codePointAt(0);
997
+ if (codePoint === void 0) return false;
998
+ const width = eastAsianWidthType(codePoint);
999
+ return width === "fullwidth" || width === "halfwidth" || width === "wide" && !SLACK_MRKDWN_EMOJI_PRESENTATION_RE.test(character);
994
1000
  }
995
- function countSlackTextUtf8Bytes(value) {
996
- return Buffer.byteLength(value, "utf8");
1001
+ function isUnsafeSlackEmphasisBoundary(character) {
1002
+ if (SLACK_MRKDWN_WORD_CHARACTER_RE.test(character)) return true;
1003
+ const codePoint = character.codePointAt(0);
1004
+ if (codePoint === void 0 || codePoint <= 127) return false;
1005
+ return SLACK_MRKDWN_SYMBOL_RE.test(character) || isSlackCjkPunctuation(character);
997
1006
  }
998
- /** Truncate Slack text without splitting a code point or exceeding a UTF-8 byte limit. */
999
- function truncateSlackTextByUtf8Bytes(value, maxBytes) {
1000
- const trimmed = value.trim();
1001
- if (maxBytes <= 0) return "";
1002
- if (countSlackTextUtf8Bytes(trimmed) <= maxBytes) return trimmed;
1003
- const suffix = "…";
1004
- const suffixBytes = countSlackTextUtf8Bytes(suffix);
1005
- const prefixBudget = maxBytes >= suffixBytes ? maxBytes - suffixBytes : maxBytes;
1006
- let prefix = "";
1007
- let prefixBytes = 0;
1008
- for (const character of trimmed) {
1009
- const characterBytes = countSlackTextUtf8Bytes(character);
1010
- if (prefixBytes + characterBytes > prefixBudget) break;
1011
- prefix += character;
1012
- prefixBytes += characterBytes;
1007
+ function makeSlackEmphasisStylesSafe(ir) {
1008
+ const styles = ir.styles.filter((span) => {
1009
+ if (span.style !== "italic" && span.style !== "bold") return true;
1010
+ return !isUnsafeSlackEmphasisBoundary(getCodePointBefore(ir.text, span.start)) && !isUnsafeSlackEmphasisBoundary(getCodePointAt(ir.text, span.end));
1011
+ });
1012
+ return styles.length === ir.styles.length ? ir : {
1013
+ ...ir,
1014
+ styles
1015
+ };
1016
+ }
1017
+ const SLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
1018
+ mechanism: "markdown",
1019
+ constructs: {
1020
+ underline: "strip",
1021
+ spoiler: "fallback",
1022
+ codeLanguage: "fallback",
1023
+ heading: "fallback",
1024
+ bulletList: "fallback",
1025
+ orderedList: "fallback",
1026
+ taskList: "fallback",
1027
+ table: "fallback",
1028
+ image: "fallback"
1029
+ },
1030
+ chunk: {
1031
+ limit: 4e3,
1032
+ unit: "chars",
1033
+ hardCap: 4e4
1013
1034
  }
1014
- return maxBytes >= suffixBytes ? `${prefix}${suffix}` : prefix;
1035
+ });
1036
+ const SLACK_ASSISTANT_TRANSCRIPT_PREFIX = "`Assistant:` ";
1037
+ function tokenizeSlackMrkdwn(text) {
1038
+ const tokens = [];
1039
+ for (let index = 0; index < text.length;) {
1040
+ if (text.startsWith("```", index)) {
1041
+ tokens.push("```");
1042
+ index += 3;
1043
+ continue;
1044
+ }
1045
+ const entity = [
1046
+ "&amp;",
1047
+ "&lt;",
1048
+ "&gt;"
1049
+ ].find((candidate) => text.startsWith(candidate, index));
1050
+ if (entity) {
1051
+ tokens.push(entity);
1052
+ index += entity.length;
1053
+ continue;
1054
+ }
1055
+ if (text[index] === "<") {
1056
+ const end = text.indexOf(">", index + 1);
1057
+ const angleToken = end >= 0 ? text.slice(index, end + 1) : void 0;
1058
+ if (angleToken && !angleToken.includes("\n") && isAllowedSlackAngleToken(angleToken)) {
1059
+ tokens.push(angleToken);
1060
+ index += angleToken.length;
1061
+ continue;
1062
+ }
1063
+ }
1064
+ const codePoint = text.codePointAt(index);
1065
+ if (codePoint === void 0) break;
1066
+ const character = String.fromCodePoint(codePoint);
1067
+ index += character.length;
1068
+ if (character === "\\" && index < text.length) {
1069
+ const escapedCodePoint = text.codePointAt(index);
1070
+ if (escapedCodePoint !== void 0) {
1071
+ const escapedCharacter = String.fromCodePoint(escapedCodePoint);
1072
+ tokens.push(character + escapedCharacter);
1073
+ index += escapedCharacter.length;
1074
+ continue;
1075
+ }
1076
+ }
1077
+ tokens.push(character);
1078
+ }
1079
+ return tokens;
1015
1080
  }
1016
- //#endregion
1017
- //#region extensions/slack/src/blocks-render.ts
1018
- const SLACK_BUTTON_URL_MAX = 3e3;
1019
- function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
1020
- return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1081
+ function resolveSlackCodeMarkerTransition(active, token) {
1082
+ if (token === "```" && active !== "`") return active === "```" ? void 0 : "```";
1083
+ if (token === "`" && active !== "```") return active === "`" ? void 0 : "`";
1084
+ return null;
1021
1085
  }
1022
- function buildSlackReplyLinkActionId(buttonIndex, choiceIndex) {
1023
- return `${SLACK_REPLY_LINK_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1086
+ function maskSlackExcludedText(text) {
1087
+ return text.split("\n").map((line) => line.trim() ? `x${" ".repeat(Math.max(0, line.length - 1))}` : " ".repeat(line.length)).join("\n");
1024
1088
  }
1025
- function buildSlackReplySelectActionId(selectIndex) {
1026
- return `${SLACK_REPLY_SELECT_ACTION_ID}:${String(selectIndex)}`;
1089
+ function maskSlackExcludedRanges(projection) {
1090
+ let masked = "";
1091
+ let cursor = 0;
1092
+ for (const range of projection.excludedRanges) {
1093
+ masked += projection.text.slice(cursor, range.start);
1094
+ masked += maskSlackExcludedText(projection.text.slice(range.start, range.end));
1095
+ cursor = range.end;
1096
+ }
1097
+ return masked + projection.text.slice(cursor);
1027
1098
  }
1028
- function buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) {
1029
- return `${SLACK_APPROVAL_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1099
+ function slackProjectionHasRoleHeader(projection) {
1100
+ return Boolean(markdownToIR(maskSlackExcludedRanges(projection), {
1101
+ assistantTranscriptRoleHeaders: true,
1102
+ autolink: false,
1103
+ blockquotePrefix: "",
1104
+ headingStyle: "none",
1105
+ linkify: false,
1106
+ tableMode: "off"
1107
+ }).annotations?.some((annotation) => annotation.type === "assistant_transcript_role"));
1108
+ }
1109
+ function decodeSlackMrkdwnEntities(text) {
1110
+ return text.replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">");
1111
+ }
1112
+ function projectSlackAngleToken(token, dateDisplay) {
1113
+ const inner = token.slice(1, -1);
1114
+ if (inner.startsWith("!date^")) {
1115
+ const fallbackSeparator = inner.indexOf("|");
1116
+ const tokenString = (fallbackSeparator === -1 ? inner : inner.slice(0, fallbackSeparator)).split("^")[2] ?? "";
1117
+ const fallback = fallbackSeparator === -1 ? "" : inner.slice(fallbackSeparator + 1);
1118
+ return decodeSlackMrkdwnEntities(dateDisplay === "fallback" ? fallback || tokenString : tokenString || fallback);
1119
+ }
1120
+ const labelSeparator = inner.indexOf("|");
1121
+ if (labelSeparator >= 0) return decodeSlackMrkdwnEntities(inner.slice(labelSeparator + 1));
1122
+ if (inner.startsWith("@")) return "@";
1123
+ if (inner.startsWith("#")) return "#";
1124
+ if (inner.startsWith("!")) return "!";
1125
+ return decodeSlackMrkdwnEntities(inner);
1126
+ }
1127
+ function appendSlackVisibleProjection(projection, visible, excluded) {
1128
+ if (!visible) return;
1129
+ const start = projection.text.length;
1130
+ projection.text += visible;
1131
+ if (!excluded) return;
1132
+ const previous = projection.excludedRanges.at(-1);
1133
+ if (previous?.end === start) previous.end = projection.text.length;
1134
+ else projection.excludedRanges.push({
1135
+ start,
1136
+ end: projection.text.length
1137
+ });
1138
+ }
1139
+ function projectSlackMrkdwnVisibleText(text, dateDisplay) {
1140
+ const projection = {
1141
+ text: "",
1142
+ excludedRanges: []
1143
+ };
1144
+ let activeMarker;
1145
+ let lineHasVisibleContent = false;
1146
+ for (const token of tokenizeSlackMrkdwn(text)) {
1147
+ const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
1148
+ if (transition !== null) {
1149
+ activeMarker = transition;
1150
+ continue;
1151
+ }
1152
+ let visible = token;
1153
+ if (isAllowedSlackAngleToken(token)) visible = activeMarker ? token : projectSlackAngleToken(token, dateDisplay);
1154
+ else if (token === "&amp;" || token === "&lt;" || token === "&gt;") visible = decodeSlackMrkdwnEntities(token);
1155
+ else if (!activeMarker && (token === "*" || token === "_" || token === "~")) visible = "";
1156
+ else if (!activeMarker && token === ">" && !lineHasVisibleContent) visible = "";
1157
+ else if (token.startsWith("\\") && token.length > 1) visible = token.slice(1);
1158
+ appendSlackVisibleProjection(projection, visible, activeMarker !== void 0);
1159
+ for (const character of visible) if (character === "\n") lineHasVisibleContent = false;
1160
+ else if (character !== " " && character !== " " && character !== "\r") lineHasVisibleContent = true;
1161
+ }
1162
+ return projection;
1163
+ }
1164
+ function protectSlackAssistantTranscriptRoleHeaders(text) {
1165
+ if (text.startsWith(SLACK_ASSISTANT_TRANSCRIPT_PREFIX)) return text;
1166
+ const tokenProjection = projectSlackMrkdwnVisibleText(text, "token");
1167
+ const fallbackProjection = projectSlackMrkdwnVisibleText(text, "fallback");
1168
+ if (!slackProjectionHasRoleHeader(tokenProjection) && !slackProjectionHasRoleHeader(fallbackProjection)) return text;
1169
+ return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
1170
+ }
1171
+ function buildSlackRenderOptions() {
1172
+ return {
1173
+ annotationMarkers: { assistant_transcript_role: {
1174
+ open: "`",
1175
+ close: "`",
1176
+ suppressNestedFormatting: true
1177
+ } },
1178
+ styleMarkers: {
1179
+ bold: {
1180
+ open: "*",
1181
+ close: "*"
1182
+ },
1183
+ italic: {
1184
+ open: "_",
1185
+ close: "_"
1186
+ },
1187
+ strikethrough: {
1188
+ open: "~",
1189
+ close: "~"
1190
+ },
1191
+ code: {
1192
+ open: "`",
1193
+ close: "`"
1194
+ },
1195
+ code_block: {
1196
+ open: "```\n",
1197
+ close: "```"
1198
+ }
1199
+ },
1200
+ escapeText: escapeSlackMrkdwnText,
1201
+ buildLink: buildSlackLink
1202
+ };
1203
+ }
1204
+ function normalizeSlackOutboundText(markdown, options = {}) {
1205
+ return protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
1206
+ assistantTranscriptRoleHeaders: true,
1207
+ linkify: false,
1208
+ autolink: false,
1209
+ headingStyle: "rich",
1210
+ blockquotePrefix: "> ",
1211
+ tableMode: options.tableMode
1212
+ })), buildSlackRenderOptions(), SLACK_FORMAT_PROFILE));
1213
+ }
1214
+ /** Chunk already-rendered Slack mrkdwn without splitting entities or code markers. */
1215
+ function chunkSlackMrkdwnText(text, limit) {
1216
+ if (text.length <= limit) return [text];
1217
+ if (!(text.includes("`") || text.includes("&amp;") || text.includes("&lt;") || text.includes("&gt;") || (text.match(/<[^>\n]+>/gu)?.some(isAllowedSlackAngleToken) ?? false) || /\\[\s\S]/u.test(text))) return chunkTextForOutbound(text, limit, { preserveWhitespace: true });
1218
+ const chunks = [];
1219
+ let activeMarker;
1220
+ let content = "";
1221
+ const wrapper = (marker) => marker && limit > marker.length * 2 ? marker : void 0;
1222
+ const capacity = (marker) => limit - (wrapper(marker)?.length ?? 0);
1223
+ const flush = () => {
1224
+ const marker = wrapper(activeMarker);
1225
+ if (content && content !== marker) chunks.push(marker ? `${content}${marker}` : content);
1226
+ content = "";
1227
+ };
1228
+ for (const token of tokenizeSlackMrkdwn(text)) {
1229
+ const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
1230
+ const nextMarker = transition === null ? activeMarker : transition;
1231
+ const sourceMarker = token === "`" || token === "```" ? token : void 0;
1232
+ if (transition !== null && sourceMarker && !wrapper(sourceMarker)) {
1233
+ activeMarker = nextMarker;
1234
+ continue;
1235
+ }
1236
+ if (content && content.length + token.length > capacity(nextMarker)) flush();
1237
+ activeMarker = nextMarker;
1238
+ if (!content && transition === void 0) continue;
1239
+ content ||= transition === null ? wrapper(activeMarker) ?? "" : "";
1240
+ const contentLimit = capacity(activeMarker) - (wrapper(activeMarker)?.length ?? 0);
1241
+ if (token.length > contentLimit) {
1242
+ flush();
1243
+ const marker = wrapper(activeMarker);
1244
+ if (activeMarker && isAllowedSlackAngleToken(token)) {
1245
+ if (marker) chunks.push(...chunkTextForOutbound(token, Math.max(1, Math.floor(contentLimit)), { preserveWhitespace: true }).map((fragment) => `${marker}${fragment}${marker}`));
1246
+ else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwnSegment(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
1247
+ continue;
1248
+ }
1249
+ chunks.push(...token.length <= limit ? [token] : chunkTextForOutbound(token, limit));
1250
+ continue;
1251
+ }
1252
+ content += token;
1253
+ }
1254
+ flush();
1255
+ return chunks;
1256
+ }
1257
+ function markdownToSlackMrkdwnChunks(markdown, limit, options = {}) {
1258
+ const ir = makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
1259
+ assistantTranscriptRoleHeaders: true,
1260
+ linkify: false,
1261
+ autolink: false,
1262
+ headingStyle: "rich",
1263
+ blockquotePrefix: "> ",
1264
+ tableMode: options.tableMode
1265
+ }));
1266
+ const renderOptions = buildSlackRenderOptions();
1267
+ return renderMarkdownIRChunksWithinLimit({
1268
+ ir,
1269
+ limit,
1270
+ renderChunk: (chunk) => protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(chunk, renderOptions, SLACK_FORMAT_PROFILE)),
1271
+ measureRendered: (rendered) => rendered.length
1272
+ }).map(({ rendered }) => rendered);
1273
+ }
1274
+ //#endregion
1275
+ //#region extensions/slack/src/question-actions.ts
1276
+ const SLACK_QUESTION_VALUE_PREFIX = "slq1:";
1277
+ const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
1278
+ function encodeSlackQuestionAction(action) {
1279
+ if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
1280
+ const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
1281
+ return value.length <= 2e3 ? value : void 0;
1282
+ }
1283
+ function decodeSlackQuestionAction(value) {
1284
+ if (typeof value !== "string" || value.length > 2e3) return null;
1285
+ const match = /^slq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(value);
1286
+ return match?.[1] && match[2] ? {
1287
+ questionId: match[1],
1288
+ optionIndex: Number(match[2])
1289
+ } : null;
1290
+ }
1291
+ async function resolveSlackQuestionAction(params) {
1292
+ let result;
1293
+ try {
1294
+ result = await (params.resolveQuestion ?? questionGatewayRuntime.resolveOption)({
1295
+ cfg: params.cfg,
1296
+ questionId: params.action.questionId,
1297
+ optionIndex: params.action.optionIndex,
1298
+ senderId: params.userId,
1299
+ clientDisplayName: `Slack question (${params.accountId})`
1300
+ });
1301
+ } catch {
1302
+ await params.respond("Could not submit this answer.").catch(() => {});
1303
+ return;
1304
+ }
1305
+ await params.respond(result.status === "answered" ? "Answer submitted." : "This question was already answered.").catch(() => {});
1306
+ }
1307
+ //#endregion
1308
+ //#region extensions/slack/src/reply-action-ids.ts
1309
+ const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
1310
+ const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
1311
+ const SLACK_SESSION_LINK_ACTION_ID = "openclaw:session_link";
1312
+ const SLACK_REPLY_SELECT_ACTION_ID = "openclaw:reply_select";
1313
+ const SLACK_CALLBACK_BUTTON_ACTION_ID = "openclaw:callback_button";
1314
+ const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
1315
+ const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
1316
+ const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
1317
+ const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
1318
+ const SLACK_QUESTION_FINALIZATION_BLOCKS = Symbol("slackQuestionFinalizationBlocks");
1319
+ function isSlackQuestionActionId(actionId) {
1320
+ return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
1321
+ }
1322
+ /** Read only question control identities from the blocks actually sent to Slack. */
1323
+ function resolveSlackQuestionActionIds(blocks) {
1324
+ return (blocks ?? []).flatMap((block) => {
1325
+ if (block.type !== "actions") return [];
1326
+ return (block.elements ?? []).flatMap(({ action_id }) => action_id && isSlackQuestionActionId(action_id) ? [action_id] : []);
1327
+ });
1328
+ }
1329
+ function isSlackApprovalActionId(actionId) {
1330
+ return actionId === "openclaw:approval_button" || actionId === "openclaw:approval_select" || actionId.startsWith(`openclaw:approval_button:`) || actionId.startsWith(`openclaw:approval_select:`);
1331
+ }
1332
+ function isSlackCallbackActionId(actionId) {
1333
+ return actionId === "openclaw:callback_button" || actionId === "openclaw:callback_select" || actionId.startsWith(`openclaw:callback_button:`) || actionId.startsWith(`openclaw:callback_select:`);
1334
+ }
1335
+ //#endregion
1336
+ //#region extensions/slack/src/truncate.ts
1337
+ function truncateSlackText(value, max) {
1338
+ const trimmed = value.trim();
1339
+ if (trimmed.length <= max) return trimmed;
1340
+ if (max <= 1) return sliceUtf16Safe(trimmed, 0, max);
1341
+ return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
1342
+ }
1343
+ function countSlackTextUtf8Bytes(value) {
1344
+ return Buffer.byteLength(value, "utf8");
1345
+ }
1346
+ /** Truncate Slack text without splitting a code point or exceeding a UTF-8 byte limit. */
1347
+ function truncateSlackTextByUtf8Bytes(value, maxBytes) {
1348
+ const trimmed = value.trim();
1349
+ if (maxBytes <= 0) return "";
1350
+ if (countSlackTextUtf8Bytes(trimmed) <= maxBytes) return trimmed;
1351
+ const suffix = "…";
1352
+ const suffixBytes = countSlackTextUtf8Bytes(suffix);
1353
+ const prefixBudget = maxBytes >= suffixBytes ? maxBytes - suffixBytes : maxBytes;
1354
+ let prefix = "";
1355
+ let prefixBytes = 0;
1356
+ for (const character of trimmed) {
1357
+ const characterBytes = countSlackTextUtf8Bytes(character);
1358
+ if (prefixBytes + characterBytes > prefixBudget) break;
1359
+ prefix += character;
1360
+ prefixBytes += characterBytes;
1361
+ }
1362
+ return maxBytes >= suffixBytes ? `${prefix}${suffix}` : prefix;
1363
+ }
1364
+ //#endregion
1365
+ //#region extensions/slack/src/blocks-render.ts
1366
+ const SLACK_BUTTON_URL_MAX = 3e3;
1367
+ function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
1368
+ return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1369
+ }
1370
+ function buildSlackReplyLinkActionId(buttonIndex, choiceIndex) {
1371
+ return `${SLACK_REPLY_LINK_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1372
+ }
1373
+ function buildSlackReplySelectActionId(selectIndex) {
1374
+ return `${SLACK_REPLY_SELECT_ACTION_ID}:${String(selectIndex)}`;
1375
+ }
1376
+ function buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) {
1377
+ return `${SLACK_APPROVAL_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
1030
1378
  }
1031
1379
  function buildSlackApprovalSelectActionId(selectIndex) {
1032
1380
  return `${SLACK_APPROVAL_SELECT_ACTION_ID}:${String(selectIndex)}`;
@@ -1044,13 +1392,19 @@ function resolveSlackButtonStyle(style) {
1044
1392
  if (style === "primary" || style === "danger") return style;
1045
1393
  if (style === "success") return "primary";
1046
1394
  }
1047
- function resolveSlackActionTarget(action, optionIndex) {
1395
+ function resolveSlackActionTarget(action, questionOptionIndices) {
1048
1396
  if (!action) return;
1049
1397
  if (action.type === "approval") return {
1050
1398
  kind: "approval",
1051
1399
  value: encodeSlackApprovalAction(action)
1052
1400
  };
1053
1401
  if (action.type === "question") {
1402
+ if ("intent" in action) return;
1403
+ const optionIndex = resolveAskUserQuestionOptionIndex({
1404
+ questionOptionIndices,
1405
+ questionId: action.questionId,
1406
+ optionValue: action.optionValue
1407
+ });
1054
1408
  const value = optionIndex === void 0 ? void 0 : encodeSlackQuestionAction({
1055
1409
  questionId: action.questionId,
1056
1410
  optionIndex
@@ -1080,10 +1434,10 @@ function resolveSlackActionTarget(action, optionIndex) {
1080
1434
  value: command
1081
1435
  } : void 0;
1082
1436
  }
1083
- function resolveSlackButtonTarget(button, optionIndex) {
1437
+ function resolveSlackButtonTarget(button, questionOptionIndices) {
1084
1438
  if (button.action !== void 0) {
1085
1439
  const action = resolveMessagePresentationButtonAction(button);
1086
- return action ? resolveSlackActionTarget(action, optionIndex) : void 0;
1440
+ return action ? resolveSlackActionTarget(action, questionOptionIndices) : void 0;
1087
1441
  }
1088
1442
  const legacyUrl = normalizeOptionalString(button.url ?? button.webApp?.url ?? button.web_app?.url);
1089
1443
  if (legacyUrl && isWithinSlackLimit(legacyUrl, SLACK_BUTTON_URL_MAX)) return {
@@ -1100,6 +1454,10 @@ function resolveSlackButtonTarget(button, optionIndex) {
1100
1454
  url: legacyUrl
1101
1455
  } : void 0;
1102
1456
  }
1457
+ function isSlackTextFallbackButton(button) {
1458
+ const action = resolveMessagePresentationButtonAction(button);
1459
+ return action?.type === "question" && "intent" in action && action.intent === "custom-input";
1460
+ }
1103
1461
  function resolveSlackOptionTarget(option) {
1104
1462
  if (option.action !== void 0) {
1105
1463
  const action = resolveMessagePresentationOptionAction(option);
@@ -1139,92 +1497,19 @@ function resolveSlackBlockOffsets(blocks) {
1139
1497
  if (!blockId) continue;
1140
1498
  buttonIndexOffset = Math.max(buttonIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_buttons_") ?? 0);
1141
1499
  selectIndexOffset = Math.max(selectIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_select_") ?? 0);
1142
- }
1143
- return {
1144
- buttonIndexOffset,
1145
- dataTableCellCharacterCountOffset,
1146
- dataVisualizationCountOffset,
1147
- selectIndexOffset
1148
- };
1149
- }
1150
- /**
1151
- * @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
1152
- */
1153
- function buildSlackInteractiveBlocks(interactive, options = {}) {
1154
- return reduceLegacyInteractiveReply(interactive, {
1155
- blocks: [],
1156
- buttonIndex: options.buttonIndexOffset ?? 0,
1157
- selectIndex: options.selectIndexOffset ?? 0
1158
- }, (state, block) => {
1159
- if (block.type === "text") {
1160
- const trimmed = block.text.trim();
1161
- if (!trimmed) return state;
1162
- state.blocks.push({
1163
- type: "section",
1164
- text: {
1165
- type: "mrkdwn",
1166
- text: truncateSlackText(trimmed, SLACK_SECTION_TEXT_MAX)
1167
- }
1168
- });
1169
- return state;
1170
- }
1171
- if (block.type === "buttons") {
1172
- const elements = block.buttons.flatMap((button, choiceIndex) => {
1173
- const target = resolveSlackButtonTarget(button, choiceIndex);
1174
- if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
1175
- const style = resolveSlackButtonStyle(button.style);
1176
- return [{
1177
- type: "button",
1178
- action_id: target.kind === "link" ? buildSlackReplyLinkActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "approval" ? buildSlackApprovalButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "callback" ? buildSlackCallbackButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "question" ? buildSlackQuestionButtonActionId(state.buttonIndex + 1, choiceIndex) : buildSlackReplyButtonActionId(state.buttonIndex + 1, choiceIndex),
1179
- text: {
1180
- type: "plain_text",
1181
- text: truncateSlackText(button.label, 75),
1182
- emoji: true
1183
- },
1184
- ...target.kind === "link" ? { url: target.url } : { value: target.value },
1185
- ...style ? { style } : {}
1186
- }];
1187
- }).slice(0, 25);
1188
- if (elements.length === 0) return state;
1189
- state.blocks.push({
1190
- type: "actions",
1191
- block_id: `openclaw_reply_buttons_${++state.buttonIndex}`,
1192
- elements
1193
- });
1194
- return state;
1195
- }
1196
- const optionsLocal = block.options.flatMap((option) => {
1197
- const target = resolveSlackOptionTarget(option);
1198
- return target ? [{
1199
- label: option.label,
1200
- ...target
1201
- }] : [];
1202
- }).filter(isRenderableSlackOption).slice(0, 100);
1203
- const optionKinds = new Set(optionsLocal.map((option) => option.kind));
1204
- if (optionsLocal.length === 0 || optionKinds.size !== 1) return state;
1205
- state.blocks.push({
1206
- type: "actions",
1207
- block_id: `openclaw_reply_select_${++state.selectIndex}`,
1208
- elements: [{
1209
- type: "static_select",
1210
- action_id: optionsLocal[0]?.kind === "approval" ? buildSlackApprovalSelectActionId(state.selectIndex) : optionsLocal[0]?.kind === "callback" ? buildSlackCallbackSelectActionId(state.selectIndex) : buildSlackReplySelectActionId(state.selectIndex),
1211
- placeholder: {
1212
- type: "plain_text",
1213
- text: truncateSlackText(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75),
1214
- emoji: true
1215
- },
1216
- options: optionsLocal.map((option, _choiceIndex) => ({
1217
- text: {
1218
- type: "plain_text",
1219
- text: truncateSlackText(option.label, 75),
1220
- emoji: true
1221
- },
1222
- value: option.value
1223
- }))
1224
- }]
1225
- });
1226
- return state;
1227
- }).blocks;
1500
+ }
1501
+ return {
1502
+ buttonIndexOffset,
1503
+ dataTableCellCharacterCountOffset,
1504
+ dataVisualizationCountOffset,
1505
+ selectIndexOffset
1506
+ };
1507
+ }
1508
+ /**
1509
+ * @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
1510
+ */
1511
+ function buildSlackInteractiveBlocks(interactive, options = {}) {
1512
+ return buildSlackPresentationBlocks(interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0, options);
1228
1513
  }
1229
1514
  /** Render portable presentation blocks as Slack Block Kit blocks. */
1230
1515
  function buildSlackPresentationBlocks(presentation, options = {}) {
@@ -1247,19 +1532,18 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
1247
1532
  if (block.type === "text" || block.type === "context") {
1248
1533
  const text = block.text.trim();
1249
1534
  if (!text) continue;
1250
- if (block.type === "context") blocks.push({
1535
+ for (const chunk of chunkSlackMrkdwnText(text, SLACK_SECTION_TEXT_MAX)) blocks.push(block.type === "context" ? {
1251
1536
  type: "context",
1252
1537
  elements: [{
1253
1538
  type: "mrkdwn",
1254
- text: truncateSlackText(text, SLACK_SECTION_TEXT_MAX),
1539
+ text: chunk,
1255
1540
  verbatim: true
1256
1541
  }]
1257
- });
1258
- else blocks.push({
1542
+ } : {
1259
1543
  type: "section",
1260
1544
  text: {
1261
1545
  type: "mrkdwn",
1262
- text: truncateSlackText(text, SLACK_SECTION_TEXT_MAX)
1546
+ text: chunk
1263
1547
  }
1264
1548
  });
1265
1549
  continue;
@@ -1269,7 +1553,7 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
1269
1553
  continue;
1270
1554
  }
1271
1555
  if (block.type === "buttons") {
1272
- const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1);
1556
+ const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1, options.questionOptionIndices);
1273
1557
  if (rendered) {
1274
1558
  buttonIndex += 1;
1275
1559
  blocks.push(rendered);
@@ -1316,9 +1600,9 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
1316
1600
  function buildSlackPresentationChartBlock(block) {
1317
1601
  return buildSlackDataVisualizationBlock(block);
1318
1602
  }
1319
- function buildSlackPresentationButtonBlock(block, buttonIndex) {
1603
+ function buildSlackPresentationButtonBlock(block, buttonIndex, questionOptionIndices) {
1320
1604
  const elements = block.buttons.flatMap((button, choiceIndex) => {
1321
- const target = resolveSlackButtonTarget(button, choiceIndex);
1605
+ const target = resolveSlackButtonTarget(button, questionOptionIndices);
1322
1606
  if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
1323
1607
  const style = resolveSlackButtonStyle(button.style);
1324
1608
  return [{
@@ -1356,16 +1640,16 @@ function canRenderSlackPresentation(presentation, options = {}) {
1356
1640
  if (!canRenderSlackPresentationTables(presentation, options)) return false;
1357
1641
  let dataVisualizationCount = options.dataVisualizationCountOffset ?? 0;
1358
1642
  for (const block of presentation.blocks) {
1359
- if (block.type === "text" || block.type === "context") {
1360
- if (!isWithinSlackLimit(block.text.trim(), 3e3)) return false;
1361
- continue;
1362
- }
1643
+ if (block.type === "text" || block.type === "context") continue;
1363
1644
  if (block.type === "buttons") {
1364
- if (!(block.buttons.length <= 25 && block.buttons.every((button, choiceIndex) => {
1645
+ let nativeButtonCount = 0;
1646
+ if (!(block.buttons.every((button) => {
1647
+ if (isSlackTextFallbackButton(button)) return true;
1648
+ nativeButtonCount += 1;
1365
1649
  if (!isWithinSlackLimit(button.label, 75)) return false;
1366
- const target = resolveSlackButtonTarget(button, choiceIndex);
1650
+ const target = resolveSlackButtonTarget(button, options.questionOptionIndices);
1367
1651
  return target ? target.kind === "link" ? isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : isWithinSlackLimit(target.value, 2e3) : false;
1368
- }))) return false;
1652
+ }) && nativeButtonCount <= 25)) return false;
1369
1653
  continue;
1370
1654
  }
1371
1655
  if (block.type === "select") {
@@ -1476,469 +1760,116 @@ function readTextObject(value, options = {}) {
1476
1760
  function readTextValue(value, options = {}) {
1477
1761
  return normalizeOptionalString(value) ?? readTextObject(value, options);
1478
1762
  }
1479
- function renderSlackRichTextLeaf(element) {
1763
+ function renderSlackRichTextElement(value, renderReference) {
1764
+ const element = asOptionalRecord(value);
1765
+ if (!element) return "";
1480
1766
  switch (element.type) {
1767
+ case "rich_text_section":
1768
+ case "rich_text_preformatted":
1769
+ case "rich_text_quote": return renderSlackRichTextElements(element.elements, "", renderReference);
1770
+ case "rich_text_list": return renderSlackRichTextElements(element.elements, "\n", renderReference);
1481
1771
  case "text": return typeof element.text === "string" ? escapeSlackMrkdwn(element.text) : "";
1482
1772
  case "link": return escapeSlackMrkdwn(normalizeOptionalString(element.text) ?? normalizeOptionalString(element.url) ?? "");
1483
1773
  case "user": {
1484
1774
  const userId = normalizeOptionalString(element.user_id);
1485
- return userId ? escapeSlackMrkdwn(`<@${userId}>`) : "";
1775
+ return userId ? renderReference(`<@${userId}>`) : "";
1486
1776
  }
1487
1777
  case "channel": {
1488
1778
  const channelId = normalizeOptionalString(element.channel_id);
1489
- return channelId ? escapeSlackMrkdwn(`<#${channelId}>`) : "";
1779
+ return channelId ? renderReference(`<#${channelId}>`) : "";
1490
1780
  }
1491
1781
  case "usergroup": {
1492
1782
  const usergroupId = normalizeOptionalString(element.usergroup_id);
1493
- return usergroupId ? escapeSlackMrkdwn(`<!subteam^${usergroupId}>`) : "";
1783
+ return usergroupId ? renderReference(`<!subteam^${usergroupId}>`) : "";
1494
1784
  }
1495
1785
  case "broadcast": {
1496
1786
  const range = normalizeOptionalString(element.range);
1497
- return range ? escapeSlackMrkdwn(`<!${range}>`) : "";
1787
+ return range ? renderReference(`<!${range}>`) : "";
1498
1788
  }
1499
1789
  case "emoji": {
1500
1790
  const name = normalizeOptionalString(element.name);
1501
1791
  return name ? `:${name}:` : "";
1502
1792
  }
1503
1793
  case "date": return escapeSlackMrkdwn(normalizeOptionalString(element.fallback) ?? "");
1504
- default: return "";
1505
- }
1506
- }
1507
- function renderSlackRichTextElement(value) {
1508
- const element = asOptionalRecord(value);
1509
- if (!element) return "";
1510
- switch (element.type) {
1511
- case "rich_text_section":
1512
- case "rich_text_preformatted":
1513
- case "rich_text_quote": return renderSlackRichTextElements(element.elements, "");
1514
- case "rich_text_list": return renderSlackRichTextElements(element.elements, "\n");
1515
- default: return renderSlackRichTextLeaf(element);
1516
- }
1517
- }
1518
- function renderSlackRichTextElements(value, separator) {
1519
- if (!Array.isArray(value)) return "";
1520
- return value.map(renderSlackRichTextElement).filter(Boolean).join(separator);
1521
- }
1522
- function readImageText(block) {
1523
- const altText = normalizeOptionalString(block.alt_text);
1524
- return (altText ? escapeSlackMrkdwn(altText) : void 0) ?? readTextObject(block.title);
1525
- }
1526
- function readVideoText(block, options = {}) {
1527
- const altText = normalizeOptionalString(block.alt_text);
1528
- return readTextObject(block.title, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
1529
- }
1530
- function readContextText(block, options = {}) {
1531
- if (!Array.isArray(block.elements)) return;
1532
- const parts = block.elements.map((element) => {
1533
- const record = asOptionalRecord(element);
1534
- const altText = normalizeOptionalString(record?.alt_text);
1535
- return readTextObject(record, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
1536
- }).filter((part) => Boolean(part));
1537
- return parts.length > 0 ? parts.join(" ") : void 0;
1538
- }
1539
- function readControlElementText(value, options = {}) {
1540
- const element = asOptionalRecord(value);
1541
- const type = normalizeOptionalString(element?.type);
1542
- if (type === "button" || type === "workflow_button") return readTextValue(element?.text, options);
1543
- if (type && SLACK_SELECT_ELEMENT_TYPES.has(type)) return readTextObject(element?.placeholder, options);
1544
- }
1545
- function readControlElementsText(values, options = {}) {
1546
- const seen = /* @__PURE__ */ new Set();
1547
- const labels = [];
1548
- for (const value of values) {
1549
- const candidate = readControlElementText(value, options);
1550
- if (!candidate || seen.has(candidate)) continue;
1551
- seen.add(candidate);
1552
- labels.push(candidate);
1553
- }
1554
- return labels.length > 0 ? labels.join("\n") : void 0;
1555
- }
1556
- function readSectionText(block, options = {}) {
1557
- const parts = [readTextObject(block.text, options)];
1558
- if (Array.isArray(block.fields)) parts.push(...block.fields.map((field) => readTextObject(field, options)));
1559
- parts.push(readControlElementText(block.accessory, options));
1560
- const visibleParts = parts.filter((part) => Boolean(part));
1561
- return visibleParts.length > 0 ? visibleParts.join("\n") : void 0;
1562
- }
1563
- function readActionsText(block, options = {}) {
1564
- return Array.isArray(block.elements) ? readControlElementsText(block.elements, options) : void 0;
1565
- }
1566
- /** Read only user-visible text from one Slack block. */
1567
- function renderSlackBlockFallbackText(raw, options = {}) {
1568
- const block = asOptionalRecord(raw);
1569
- if (!block) return;
1570
- switch (block.type) {
1571
- case "rich_text": return normalizeOptionalString(renderSlackRichTextElements(block.elements, "\n"));
1572
- case "header": return readTextObject(block.text, options);
1573
- case "section": return readSectionText(block, options);
1574
- case "image": return readImageText(block) ?? "Shared an image";
1575
- case "video": return readVideoText(block, options) ?? "Shared a video";
1576
- case "file": return "Shared a file";
1577
- case "context": return readContextText(block, options);
1578
- case "actions": return readActionsText(block, options);
1579
- case "data_visualization": return options.nativeDataFormat === "plain" ? renderSlackDataVisualizationFallbackText(block) : renderSlackDataVisualizationMrkdwnFallbackText(block);
1580
- case "data_table": return options.nativeDataFormat === "plain" ? renderSlackDataTableFallbackText(block) : renderSlackDataTableMrkdwnFallbackText(block);
1581
- case "table": return options.nativeDataFormat === "plain" ? renderSlackTableFallbackText(block) : renderSlackTableMrkdwnFallbackText(block);
1582
- default: return;
1583
- }
1584
- }
1585
- function buildSlackBlocksFallbackText(blocks) {
1586
- for (const block of blocks) {
1587
- const text = renderSlackBlockFallbackText(block);
1588
- if (text) return text;
1589
- }
1590
- return "Shared a Block Kit message";
1591
- }
1592
- function buildSlackCompleteBlocksFallbackText(blocks) {
1593
- return blocks.map((block) => renderSlackBlockFallbackText(block)).filter(Boolean).join("\n\n").trim() || buildSlackBlocksFallbackText(blocks);
1594
- }
1595
- //#endregion
1596
- //#region extensions/slack/src/format.ts
1597
- function escapeSlackMrkdwnSegment(text) {
1598
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1599
- }
1600
- const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
1601
- function isAllowedSlackAngleToken(token) {
1602
- if (!token.startsWith("<") || !token.endsWith(">")) return false;
1603
- const inner = token.slice(1, -1);
1604
- return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
1605
- }
1606
- function escapeSlackMrkdwnContent(text) {
1607
- if (!text) return "";
1608
- if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
1609
- SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
1610
- const out = [];
1611
- let lastIndex = 0;
1612
- for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
1613
- const matchIndex = match.index ?? 0;
1614
- out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
1615
- const token = match[0] ?? "";
1616
- out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
1617
- lastIndex = matchIndex + token.length;
1618
- }
1619
- out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
1620
- return out.join("");
1621
- }
1622
- function escapeSlackMrkdwnText(text) {
1623
- if (!text) return "";
1624
- if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
1625
- return text.split("\n").map((line) => {
1626
- if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
1627
- return escapeSlackMrkdwnContent(line);
1628
- }).join("\n");
1629
- }
1630
- function buildSlackLink(link, text) {
1631
- const href = link.href.trim();
1632
- if (!href) return null;
1633
- const trimmedLabel = text.slice(link.start, link.end).trim();
1634
- const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
1635
- if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
1636
- const safeHref = escapeSlackMrkdwnSegment(href);
1637
- return {
1638
- start: link.start,
1639
- end: link.end,
1640
- open: `<${safeHref}|`,
1641
- close: ">"
1642
- };
1643
- }
1644
- const SLACK_MRKDWN_WORD_CHARACTER_RE = /[\p{L}\p{M}\p{N}_]/u;
1645
- const SLACK_MRKDWN_PUNCTUATION_RE = /\p{P}/u;
1646
- const SLACK_MRKDWN_SYMBOL_RE = /\p{S}/u;
1647
- const SLACK_MRKDWN_CJK_SCRIPT_RE = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u;
1648
- const SLACK_MRKDWN_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
1649
- function getCodePointBefore(text, index) {
1650
- if (index <= 0) return "";
1651
- const lastCodeUnit = text.charCodeAt(index - 1);
1652
- if (lastCodeUnit >= 56320 && lastCodeUnit <= 57343 && index > 1) {
1653
- const previousCodeUnit = text.charCodeAt(index - 2);
1654
- if (previousCodeUnit >= 55296 && previousCodeUnit <= 56319) return text.slice(index - 2, index);
1655
- }
1656
- return text[index - 1] ?? "";
1657
- }
1658
- function getCodePointAt(text, index) {
1659
- const codePoint = text.codePointAt(index);
1660
- return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
1661
- }
1662
- function isSlackCjkPunctuation(character) {
1663
- if (!SLACK_MRKDWN_PUNCTUATION_RE.test(character)) return false;
1664
- if (SLACK_MRKDWN_CJK_SCRIPT_RE.test(character)) return true;
1665
- const codePoint = character.codePointAt(0);
1666
- if (codePoint === void 0) return false;
1667
- const width = eastAsianWidthType(codePoint);
1668
- return width === "fullwidth" || width === "halfwidth" || width === "wide" && !SLACK_MRKDWN_EMOJI_PRESENTATION_RE.test(character);
1669
- }
1670
- function isUnsafeSlackEmphasisBoundary(character) {
1671
- if (SLACK_MRKDWN_WORD_CHARACTER_RE.test(character)) return true;
1672
- const codePoint = character.codePointAt(0);
1673
- if (codePoint === void 0 || codePoint <= 127) return false;
1674
- return SLACK_MRKDWN_SYMBOL_RE.test(character) || isSlackCjkPunctuation(character);
1675
- }
1676
- function makeSlackEmphasisStylesSafe(ir) {
1677
- const styles = ir.styles.filter((span) => {
1678
- if (span.style !== "italic" && span.style !== "bold") return true;
1679
- return !isUnsafeSlackEmphasisBoundary(getCodePointBefore(ir.text, span.start)) && !isUnsafeSlackEmphasisBoundary(getCodePointAt(ir.text, span.end));
1680
- });
1681
- return styles.length === ir.styles.length ? ir : {
1682
- ...ir,
1683
- styles
1684
- };
1685
- }
1686
- const SLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
1687
- mechanism: "markdown",
1688
- constructs: {
1689
- underline: "strip",
1690
- spoiler: "fallback",
1691
- codeLanguage: "fallback",
1692
- heading: "fallback",
1693
- bulletList: "fallback",
1694
- orderedList: "fallback",
1695
- taskList: "fallback",
1696
- table: "fallback",
1697
- image: "fallback"
1698
- },
1699
- chunk: {
1700
- limit: 4e3,
1701
- unit: "chars",
1702
- hardCap: 4e4
1703
- }
1704
- });
1705
- const SLACK_ASSISTANT_TRANSCRIPT_PREFIX = "`Assistant:` ";
1706
- function tokenizeSlackMrkdwn(text) {
1707
- const tokens = [];
1708
- for (let index = 0; index < text.length;) {
1709
- if (text.startsWith("```", index)) {
1710
- tokens.push("```");
1711
- index += 3;
1712
- continue;
1713
- }
1714
- const entity = [
1715
- "&amp;",
1716
- "&lt;",
1717
- "&gt;"
1718
- ].find((candidate) => text.startsWith(candidate, index));
1719
- if (entity) {
1720
- tokens.push(entity);
1721
- index += entity.length;
1722
- continue;
1723
- }
1724
- if (text[index] === "<") {
1725
- const end = text.indexOf(">", index + 1);
1726
- const angleToken = end >= 0 ? text.slice(index, end + 1) : void 0;
1727
- if (angleToken && !angleToken.includes("\n") && isAllowedSlackAngleToken(angleToken)) {
1728
- tokens.push(angleToken);
1729
- index += angleToken.length;
1730
- continue;
1731
- }
1732
- }
1733
- const codePoint = text.codePointAt(index);
1734
- if (codePoint === void 0) break;
1735
- const character = String.fromCodePoint(codePoint);
1736
- index += character.length;
1737
- if (character === "\\" && index < text.length) {
1738
- const escapedCodePoint = text.codePointAt(index);
1739
- if (escapedCodePoint !== void 0) {
1740
- const escapedCharacter = String.fromCodePoint(escapedCodePoint);
1741
- tokens.push(character + escapedCharacter);
1742
- index += escapedCharacter.length;
1743
- continue;
1744
- }
1745
- }
1746
- tokens.push(character);
1794
+ default: return "";
1747
1795
  }
1748
- return tokens;
1749
- }
1750
- function resolveSlackCodeMarkerTransition(active, token) {
1751
- if (token === "```" && active !== "`") return active === "```" ? void 0 : "```";
1752
- if (token === "`" && active !== "```") return active === "`" ? void 0 : "`";
1753
- return null;
1754
- }
1755
- function maskSlackExcludedText(text) {
1756
- return text.split("\n").map((line) => line.trim() ? `x${" ".repeat(Math.max(0, line.length - 1))}` : " ".repeat(line.length)).join("\n");
1757
1796
  }
1758
- function maskSlackExcludedRanges(projection) {
1759
- let masked = "";
1760
- let cursor = 0;
1761
- for (const range of projection.excludedRanges) {
1762
- masked += projection.text.slice(cursor, range.start);
1763
- masked += maskSlackExcludedText(projection.text.slice(range.start, range.end));
1764
- cursor = range.end;
1765
- }
1766
- return masked + projection.text.slice(cursor);
1797
+ function renderSlackRichTextElements(value, separator, renderReference) {
1798
+ if (!Array.isArray(value)) return "";
1799
+ return value.map((element) => renderSlackRichTextElement(element, renderReference)).filter(Boolean).join(separator);
1767
1800
  }
1768
- function slackProjectionHasRoleHeader(projection) {
1769
- return Boolean(markdownToIR(maskSlackExcludedRanges(projection), {
1770
- assistantTranscriptRoleHeaders: true,
1771
- autolink: false,
1772
- blockquotePrefix: "",
1773
- headingStyle: "none",
1774
- linkify: false,
1775
- tableMode: "off"
1776
- }).annotations?.some((annotation) => annotation.type === "assistant_transcript_role"));
1801
+ function readImageText(block) {
1802
+ const altText = normalizeOptionalString(block.alt_text);
1803
+ return (altText ? escapeSlackMrkdwn(altText) : void 0) ?? readTextObject(block.title);
1777
1804
  }
1778
- function decodeSlackMrkdwnEntities(text) {
1779
- return text.replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">");
1805
+ function readVideoText(block, options = {}) {
1806
+ const altText = normalizeOptionalString(block.alt_text);
1807
+ return readTextObject(block.title, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
1780
1808
  }
1781
- function projectSlackAngleToken(token, dateDisplay) {
1782
- const inner = token.slice(1, -1);
1783
- if (inner.startsWith("!date^")) {
1784
- const fallbackSeparator = inner.indexOf("|");
1785
- const tokenString = (fallbackSeparator === -1 ? inner : inner.slice(0, fallbackSeparator)).split("^")[2] ?? "";
1786
- const fallback = fallbackSeparator === -1 ? "" : inner.slice(fallbackSeparator + 1);
1787
- return decodeSlackMrkdwnEntities(dateDisplay === "fallback" ? fallback || tokenString : tokenString || fallback);
1788
- }
1789
- const labelSeparator = inner.indexOf("|");
1790
- if (labelSeparator >= 0) return decodeSlackMrkdwnEntities(inner.slice(labelSeparator + 1));
1791
- if (inner.startsWith("@")) return "@";
1792
- if (inner.startsWith("#")) return "#";
1793
- if (inner.startsWith("!")) return "!";
1794
- return decodeSlackMrkdwnEntities(inner);
1809
+ function readContextText(block, options = {}) {
1810
+ if (!Array.isArray(block.elements)) return;
1811
+ const parts = block.elements.map((element) => {
1812
+ const record = asOptionalRecord(element);
1813
+ const altText = normalizeOptionalString(record?.alt_text);
1814
+ return readTextObject(record, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
1815
+ }).filter((part) => Boolean(part));
1816
+ return parts.length > 0 ? parts.join(" ") : void 0;
1795
1817
  }
1796
- function appendSlackVisibleProjection(projection, visible, excluded) {
1797
- if (!visible) return;
1798
- const start = projection.text.length;
1799
- projection.text += visible;
1800
- if (!excluded) return;
1801
- const previous = projection.excludedRanges.at(-1);
1802
- if (previous?.end === start) previous.end = projection.text.length;
1803
- else projection.excludedRanges.push({
1804
- start,
1805
- end: projection.text.length
1806
- });
1818
+ function readControlElementText(value, options = {}) {
1819
+ const element = asOptionalRecord(value);
1820
+ const type = normalizeOptionalString(element?.type);
1821
+ if (type === "button" || type === "workflow_button") return readTextValue(element?.text, options);
1822
+ if (type && SLACK_SELECT_ELEMENT_TYPES.has(type)) return readTextObject(element?.placeholder, options);
1807
1823
  }
1808
- function projectSlackMrkdwnVisibleText(text, dateDisplay) {
1809
- const projection = {
1810
- text: "",
1811
- excludedRanges: []
1812
- };
1813
- let activeMarker;
1814
- let lineHasVisibleContent = false;
1815
- for (const token of tokenizeSlackMrkdwn(text)) {
1816
- const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
1817
- if (transition !== null) {
1818
- activeMarker = transition;
1819
- continue;
1820
- }
1821
- let visible = token;
1822
- if (isAllowedSlackAngleToken(token)) visible = activeMarker ? token : projectSlackAngleToken(token, dateDisplay);
1823
- else if (token === "&amp;" || token === "&lt;" || token === "&gt;") visible = decodeSlackMrkdwnEntities(token);
1824
- else if (!activeMarker && (token === "*" || token === "_" || token === "~")) visible = "";
1825
- else if (!activeMarker && token === ">" && !lineHasVisibleContent) visible = "";
1826
- else if (token.startsWith("\\") && token.length > 1) visible = token.slice(1);
1827
- appendSlackVisibleProjection(projection, visible, activeMarker !== void 0);
1828
- for (const character of visible) if (character === "\n") lineHasVisibleContent = false;
1829
- else if (character !== " " && character !== " " && character !== "\r") lineHasVisibleContent = true;
1824
+ function readControlElementsText(values, options = {}) {
1825
+ const seen = /* @__PURE__ */ new Set();
1826
+ const labels = [];
1827
+ for (const value of values) {
1828
+ const candidate = readControlElementText(value, options);
1829
+ if (!candidate || seen.has(candidate)) continue;
1830
+ seen.add(candidate);
1831
+ labels.push(candidate);
1830
1832
  }
1831
- return projection;
1832
- }
1833
- function protectSlackAssistantTranscriptRoleHeaders(text) {
1834
- if (text.startsWith(SLACK_ASSISTANT_TRANSCRIPT_PREFIX)) return text;
1835
- const tokenProjection = projectSlackMrkdwnVisibleText(text, "token");
1836
- const fallbackProjection = projectSlackMrkdwnVisibleText(text, "fallback");
1837
- if (!slackProjectionHasRoleHeader(tokenProjection) && !slackProjectionHasRoleHeader(fallbackProjection)) return text;
1838
- return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
1833
+ return labels.length > 0 ? labels.join("\n") : void 0;
1839
1834
  }
1840
- function buildSlackRenderOptions() {
1841
- return {
1842
- annotationMarkers: { assistant_transcript_role: {
1843
- open: "`",
1844
- close: "`",
1845
- suppressNestedFormatting: true
1846
- } },
1847
- styleMarkers: {
1848
- bold: {
1849
- open: "*",
1850
- close: "*"
1851
- },
1852
- italic: {
1853
- open: "_",
1854
- close: "_"
1855
- },
1856
- strikethrough: {
1857
- open: "~",
1858
- close: "~"
1859
- },
1860
- code: {
1861
- open: "`",
1862
- close: "`"
1863
- },
1864
- code_block: {
1865
- open: "```\n",
1866
- close: "```"
1867
- }
1868
- },
1869
- escapeText: escapeSlackMrkdwnText,
1870
- buildLink: buildSlackLink
1871
- };
1835
+ function readSectionText(block, options = {}) {
1836
+ const parts = [readTextObject(block.text, options)];
1837
+ if (Array.isArray(block.fields)) parts.push(...block.fields.map((field) => readTextObject(field, options)));
1838
+ parts.push(readControlElementText(block.accessory, options));
1839
+ const visibleParts = parts.filter((part) => Boolean(part));
1840
+ return visibleParts.length > 0 ? visibleParts.join("\n") : void 0;
1872
1841
  }
1873
- function markdownToSlackMrkdwn(markdown, options = {}) {
1874
- return renderMarkdownWithMarkers(makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
1875
- assistantTranscriptRoleHeaders: true,
1876
- linkify: false,
1877
- autolink: false,
1878
- headingStyle: "rich",
1879
- blockquotePrefix: "> ",
1880
- tableMode: options.tableMode
1881
- })), buildSlackRenderOptions(), SLACK_FORMAT_PROFILE);
1842
+ function readActionsText(block, options = {}) {
1843
+ return Array.isArray(block.elements) ? readControlElementsText(block.elements, options) : void 0;
1882
1844
  }
1883
- function normalizeSlackOutboundText(markdown) {
1884
- return protectSlackAssistantTranscriptRoleHeaders(markdownToSlackMrkdwn(markdown ?? ""));
1845
+ /** Read only user-visible text from one Slack block. */
1846
+ function renderSlackBlockFallbackText(raw, options = {}) {
1847
+ const block = asOptionalRecord(raw);
1848
+ if (!block) return;
1849
+ switch (block.type) {
1850
+ case "rich_text": return normalizeOptionalString(renderSlackRichTextElements(block.elements, "\n", options.nativeReferenceFormat === "plain" ? (text) => text : escapeSlackMrkdwn));
1851
+ case "header": return readTextObject(block.text, options);
1852
+ case "section": return readSectionText(block, options);
1853
+ case "image": return readImageText(block) ?? "Shared an image";
1854
+ case "video": return readVideoText(block, options) ?? "Shared a video";
1855
+ case "file": return "Shared a file";
1856
+ case "context": return readContextText(block, options);
1857
+ case "actions": return readActionsText(block, options);
1858
+ case "data_visualization": return options.nativeDataFormat === "plain" ? renderSlackDataVisualizationFallbackText(block) : renderSlackDataVisualizationMrkdwnFallbackText(block);
1859
+ case "data_table": return options.nativeDataFormat === "plain" ? renderSlackDataTableFallbackText(block) : renderSlackDataTableMrkdwnFallbackText(block);
1860
+ case "table": return options.nativeDataFormat === "plain" ? renderSlackTableFallbackText(block) : renderSlackTableMrkdwnFallbackText(block);
1861
+ default: return;
1862
+ }
1885
1863
  }
1886
- /** Chunk already-rendered Slack mrkdwn without splitting entities or code markers. */
1887
- function chunkSlackMrkdwnText(text, limit) {
1888
- if (text.length <= limit) return [text];
1889
- if (!(text.includes("`") || text.includes("&amp;") || text.includes("&lt;") || text.includes("&gt;") || (text.match(/<[^>\n]+>/gu)?.some(isAllowedSlackAngleToken) ?? false) || /\\[\s\S]/u.test(text))) return chunkTextForOutbound(text, limit);
1890
- const chunks = [];
1891
- let activeMarker;
1892
- let content = "";
1893
- const wrapper = () => activeMarker && limit > activeMarker.length * 2 ? activeMarker : void 0;
1894
- const capacity = () => limit - (wrapper()?.length ?? 0) * 2;
1895
- const flush = () => {
1896
- if (!content) return;
1897
- const marker = wrapper();
1898
- chunks.push(marker ? `${marker}${content}${marker}` : content);
1899
- content = "";
1900
- };
1901
- for (const token of tokenizeSlackMrkdwn(text)) {
1902
- const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
1903
- if (transition !== null) {
1904
- flush();
1905
- activeMarker = transition;
1906
- continue;
1907
- }
1908
- const contentLimit = capacity();
1909
- if (token.length > contentLimit) {
1910
- flush();
1911
- const marker = wrapper();
1912
- if (activeMarker && isAllowedSlackAngleToken(token)) {
1913
- if (marker) chunks.push(...chunkTextForOutbound(token, Math.max(1, Math.floor(contentLimit)), { preserveWhitespace: true }).map((fragment) => `${marker}${fragment}${marker}`));
1914
- else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwnSegment(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
1915
- continue;
1916
- }
1917
- chunks.push(...token.length <= limit ? [token] : chunkTextForOutbound(token, limit));
1918
- continue;
1919
- }
1920
- if (content && content.length + token.length > contentLimit) flush();
1921
- content += token;
1864
+ function buildSlackBlocksFallbackText(blocks) {
1865
+ for (const block of blocks) {
1866
+ const text = renderSlackBlockFallbackText(block);
1867
+ if (text) return text;
1922
1868
  }
1923
- flush();
1924
- return chunks;
1869
+ return "Shared a Block Kit message";
1925
1870
  }
1926
- function markdownToSlackMrkdwnChunks(markdown, limit, options = {}) {
1927
- const ir = makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
1928
- assistantTranscriptRoleHeaders: true,
1929
- linkify: false,
1930
- autolink: false,
1931
- headingStyle: "rich",
1932
- blockquotePrefix: "> ",
1933
- tableMode: options.tableMode
1934
- }));
1935
- const renderOptions = buildSlackRenderOptions();
1936
- return renderMarkdownIRChunksWithinLimit({
1937
- ir,
1938
- limit,
1939
- renderChunk: (chunk) => protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(chunk, renderOptions, SLACK_FORMAT_PROFILE)),
1940
- measureRendered: (rendered) => rendered.length
1941
- }).map(({ rendered }) => rendered);
1871
+ function buildSlackCompleteBlocksFallbackText(blocks) {
1872
+ return blocks.map((block) => renderSlackBlockFallbackText(block)).filter(Boolean).join("\n\n").trim() || buildSlackBlocksFallbackText(blocks);
1942
1873
  }
1943
1874
  //#endregion
1944
1875
  //#region extensions/slack/src/native-data-blocks.ts
@@ -2108,7 +2039,10 @@ function resolveSlackReplyDeliveryMessages(params) {
2108
2039
  ...baseText ? { nativeDataFallbackBaseText: baseText } : {}
2109
2040
  });
2110
2041
  }
2111
- if (outsideText) messages.push({ text: outsideText });
2042
+ if (outsideText) messages.push({
2043
+ text: outsideText,
2044
+ authoredTextPlacement: "outside-blocks"
2045
+ });
2112
2046
  return messages;
2113
2047
  }
2114
2048
  function resolveSlackReplyText(payload, text = payload.text) {
@@ -2247,14 +2181,20 @@ function renderNativePresentation(presentation, options) {
2247
2181
  const blocks = buildSlackPresentationBlocks(presentation, options);
2248
2182
  return blocks.length > 0 ? blocks : void 0;
2249
2183
  }
2250
- function appendPresentationPart(segments, presentation) {
2184
+ function appendPresentationPart(segments, presentation, questionOptionIndices) {
2251
2185
  const currentBlocks = readLastBlockSegment(segments);
2252
- const currentRendered = renderNativePresentation(presentation, resolvePresentationRenderOptions(segments, "current"));
2186
+ const currentRendered = renderNativePresentation(presentation, {
2187
+ ...resolvePresentationRenderOptions(segments, "current"),
2188
+ questionOptionIndices
2189
+ });
2253
2190
  if (currentRendered && currentBlocks.length + currentRendered.length <= 50) {
2254
2191
  appendBlockSegment(segments, currentRendered);
2255
2192
  return;
2256
2193
  }
2257
- const freshRendered = renderNativePresentation(presentation, resolvePresentationRenderOptions(segments, "new-message"));
2194
+ const freshRendered = renderNativePresentation(presentation, {
2195
+ ...resolvePresentationRenderOptions(segments, "new-message"),
2196
+ questionOptionIndices
2197
+ });
2258
2198
  if (freshRendered) {
2259
2199
  appendBlockSegment(segments, freshRendered, true);
2260
2200
  return;
@@ -2264,6 +2204,7 @@ function appendPresentationPart(segments, presentation) {
2264
2204
  const SLACK_BUTTON_CONTROL_ACTION_IDS = [
2265
2205
  SLACK_APPROVAL_BUTTON_ACTION_ID,
2266
2206
  SLACK_CALLBACK_BUTTON_ACTION_ID,
2207
+ SLACK_QUESTION_BUTTON_ACTION_ID,
2267
2208
  SLACK_REPLY_BUTTON_ACTION_ID,
2268
2209
  SLACK_REPLY_LINK_ACTION_ID
2269
2210
  ];
@@ -2329,15 +2270,19 @@ function resolveSlackReplyBlockResolution(payload, options = {}) {
2329
2270
  }
2330
2271
  if (compiledChannelBlocks.length > 0) appendBlockSegment(segments, compiledChannelBlocks);
2331
2272
  const presentation = normalizeMessagePresentation(payload.presentation);
2273
+ const questionOptionIndices = resolveAskUserQuestionOptionIndices(payload);
2332
2274
  const presentationBlockOffset = readAllNativeBlocks(segments).length;
2333
2275
  if (presentation?.title) appendPresentationPart(segments, {
2334
2276
  title: presentation.title,
2335
2277
  blocks: []
2336
- });
2337
- for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] });
2278
+ }, questionOptionIndices);
2279
+ for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] }, questionOptionIndices);
2338
2280
  const renderedPresentationBlocks = readAllNativeBlocks(segments).slice(presentationBlockOffset);
2339
2281
  appendBlockSegment(segments, subtractMirroredSlackControlRows({
2340
- interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive, resolveSlackBlockOffsets(readAllNativeBlocks(segments))),
2282
+ interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive, {
2283
+ ...resolveSlackBlockOffsets(readAllNativeBlocks(segments)),
2284
+ questionOptionIndices
2285
+ }),
2341
2286
  presentationBlocks: renderedPresentationBlocks
2342
2287
  }));
2343
2288
  const renderedTextFragments = segments.flatMap((segment) => {
@@ -2366,113 +2311,6 @@ function assertSlackDetachedTargetAllowed(accountId, teamId) {
2366
2311
  if (installationKind && installationKind !== "workspace" && !teamId) throw new Error("unsupported_enterprise_slack_delivery: detached Slack operations require team:<team-id>:channel:<channel-id> or team:<team-id>:user:<user-id> until a workspace install is authenticated");
2367
2312
  }
2368
2313
  //#endregion
2369
- //#region extensions/slack/src/monitor/allow-list.ts
2370
- const SLACK_SLUG_CACHE_MAX = 512;
2371
- const SLACK_STABLE_USER_ID_RE = /^[ubw][a-z0-9]+$/;
2372
- const slackSlugCache = /* @__PURE__ */ new Map();
2373
- function normalizeSlackSlug(raw) {
2374
- const key = raw ?? "";
2375
- const cached = slackSlugCache.get(key);
2376
- if (cached !== void 0) return cached;
2377
- const normalized = normalizeHyphenSlug(raw);
2378
- slackSlugCache.set(key, normalized);
2379
- if (slackSlugCache.size > SLACK_SLUG_CACHE_MAX) {
2380
- const oldest = slackSlugCache.keys().next();
2381
- if (!oldest.done) slackSlugCache.delete(oldest.value);
2382
- }
2383
- return normalized;
2384
- }
2385
- function normalizeAllowList(list) {
2386
- return normalizeStringEntries$1(list);
2387
- }
2388
- function normalizeAllowListLower(list) {
2389
- return normalizeStringEntriesLower(list);
2390
- }
2391
- function normalizeSlackAllowOwnerEntry(entry) {
2392
- const trimmed = normalizeOptionalLowercaseString(entry);
2393
- if (!trimmed || trimmed === "*") return;
2394
- try {
2395
- const target = parseSlackTarget(trimmed);
2396
- if (target?.kind === "user" && target.teamId) return target.id.toLowerCase();
2397
- } catch {
2398
- return;
2399
- }
2400
- const withoutPrefix = trimmed.replace(/^(slack:|user:)/, "");
2401
- return SLACK_STABLE_USER_ID_RE.test(withoutPrefix) ? withoutPrefix : void 0;
2402
- }
2403
- function resolveSlackAllowListMatch(params) {
2404
- const compiledAllowList = compileAllowlist(params.allowList);
2405
- const teamId = normalizeOptionalLowercaseString(params.teamId);
2406
- const id = normalizeOptionalLowercaseString(params.id);
2407
- const name = normalizeOptionalLowercaseString(params.name);
2408
- const slug = normalizeSlackSlug(name);
2409
- const scopedCandidates = [{
2410
- value: teamId && id ? `team:${teamId}:user:${id}` : void 0,
2411
- source: "workspace-id"
2412
- }];
2413
- const unscopedCandidates = [
2414
- {
2415
- value: id,
2416
- source: "id"
2417
- },
2418
- {
2419
- value: id ? `slack:${id}` : void 0,
2420
- source: "prefixed-id"
2421
- },
2422
- {
2423
- value: id ? `user:${id}` : void 0,
2424
- source: "prefixed-user"
2425
- },
2426
- ...params.allowNameMatching === true ? [
2427
- {
2428
- value: name,
2429
- source: "name"
2430
- },
2431
- {
2432
- value: name ? `slack:${name}` : void 0,
2433
- source: "prefixed-name"
2434
- },
2435
- {
2436
- value: slug,
2437
- source: "slug"
2438
- }
2439
- ] : []
2440
- ];
2441
- return resolveCompiledAllowlistMatch({
2442
- compiledAllowlist: compiledAllowList,
2443
- candidates: [...scopedCandidates, ...unscopedCandidates]
2444
- });
2445
- }
2446
- function allowListMatches(params) {
2447
- return resolveSlackAllowListMatch(params).allowed;
2448
- }
2449
- function resolveSlackUserAllowed(params) {
2450
- const allowList = normalizeAllowListLower(params.allowList);
2451
- if (allowList.length === 0) return true;
2452
- return allowListMatches({
2453
- allowList,
2454
- teamId: params.teamId,
2455
- id: params.userId,
2456
- name: params.userName,
2457
- allowNameMatching: params.allowNameMatching
2458
- });
2459
- }
2460
- function resolveSlackUserAllowListForTeam(params) {
2461
- const allowList = normalizeAllowListLower(params.allowList);
2462
- const teamId = normalizeOptionalLowercaseString(params.teamId);
2463
- return allowList.flatMap((entry) => {
2464
- if (entry === "*") return [entry];
2465
- if (!entry.startsWith("team:")) return [entry];
2466
- try {
2467
- const target = parseSlackTarget(entry);
2468
- if (target?.kind === "user" && target.teamId?.toLowerCase() === teamId) return [entry];
2469
- return params.preserveUnmatchedScopedEntries ? [entry] : [];
2470
- } catch {
2471
- return params.preserveUnmatchedScopedEntries ? [entry] : [];
2472
- }
2473
- });
2474
- }
2475
- //#endregion
2476
2314
  //#region extensions/slack/src/monitor/workspace-routing.ts
2477
2315
  function resolveSlackEnterpriseMainDmSessionKey(params) {
2478
2316
  const accountId = encodeURIComponent(params.accountId).toLowerCase();
@@ -2538,4 +2376,4 @@ function resolveSlackGroupToolPolicy(params) {
2538
2376
  });
2539
2377
  }
2540
2378
  //#endregion
2541
- export { SLACK_REPLY_SELECT_ACTION_ID as $, isSlackInvalidBlocksResponse as A, isSlackApprovalAuthorizedSender as At, SLACK_EDIT_TEXT_MAX_BYTES as B, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as C, shouldHandleSlackNativeApprovalRequest as Ct, createSlackNativeDataBaseTextConsumer as D, isSlackWorkspaceInstallation as Dt, buildSlackNativeDataAccessibilityText as E, getSlackInstallationKind as Et, normalizeSlackOutboundText as F, resolveSlackExecApprovalTarget as Ft, buildSlackPresentationBlocks as G, SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT as H, buildSlackBlocksFallbackText as I, shouldSuppressLocalSlackExecApprovalPrompt as It, truncateSlackText as J, canRenderSlackPresentation as K, buildSlackCompleteBlocksFallbackText as L, SLACK_PRIVATE_ACTION_DELIVERY_RESULT as Lt, stripSlackNativeDataBlocks as M, isSlackExecApprovalAuthorizedSender as Mt, chunkSlackMrkdwnText as N, isSlackExecApprovalClientEnabled as Nt, hasSlackNativeDataBlock as O, registerSlackInstallationState as Ot, markdownToSlackMrkdwnChunks as P, normalizeSlackApproverId as Pt, SLACK_REPLY_LINK_ACTION_ID as Q, renderSlackBlockFallbackText as R, resolveSlackAutoThreadId as Rt, resolveSlackReplyRenderPlan as S, resolveTurnSourceSlackOriginTarget as St, appendSlackNativeDataPlainTextFallback as T, slackTargetsMatch as Tt, SLACK_TEXT_LIMIT as U, SLACK_MESSAGE_TEXT_HARD_LIMIT as V, buildSlackInteractiveBlocks as W, SLACK_QUESTION_FINALIZATION_BLOCKS as X, truncateSlackTextByUtf8Bytes as Y, SLACK_REPLY_BUTTON_ACTION_ID as Z, hasSlackReplyStructuredContent as _, normalizeSlackForwardTarget as _t, qualifySlackConversationId as a, decodeSlackQuestionAction as at, resolveSlackReplyBlocks as b, resolveSessionSlackOriginTarget as bt, allowListMatches as c, escapeSlackMrkdwn as ct, normalizeSlackAllowOwnerEntry as d, SLACK_PRESENTATION_CAPABILITIES as dt, SLACK_SESSION_LINK_ACTION_ID as et, normalizeSlackSlug as f, SLACK_MAX_BLOCKS as ft, assertSlackDetachedTargetAllowed as g, isSlackAnyNativeApprovalClientEnabled as gt, resolveSlackUserAllowed as h, hasSlackPluginApprovers as ht, resolveSlackGroupToolPolicy as i, resolveSlackQuestionActionIds as it, isSlackNativeResponseUrlRejection as j, getSlackExecApprovalApprovers as jt, isSlackInvalidBlocksError as k, getSlackApprovalApprovers as kt, normalizeAllowList as l, SLACK_APPROVAL_HEADER_BLOCK_ID as lt, resolveSlackUserAllowListForTeam as m, validateSlackBlocksArray as mt, buildSlackChannelPolicyScope as n, isSlackCallbackActionId as nt, qualifySlackRoutePeerId as o, resolveSlackQuestionAction as ot, resolveSlackAllowListMatch as p, parseSlackBlocksInput as pt, countSlackTextUtf8Bytes as q, resolveSlackGroupRequireMention as r, isSlackQuestionActionId as rt, resolveSlackEnterpriseMainDmSessionKey as s, renderSlackMessagePresentationFallbackText as st, buildSlackChannelIdCandidates as t, isSlackApprovalActionId as tt, normalizeAllowListLower as u, decodeSlackApprovalAction as ut, parseSlackReplyBlockSegments as v, normalizeSlackOriginTarget as vt, appendSlackNativeDataFallbackText as w, shouldHandleSlackPluginViaForwardingSession as wt, resolveSlackReplyDeliveryMessages as x, resolveSlackFallbackOriginTarget as xt, resolveSlackReplyBlockResolution as y, resolveEnterpriseApprovalTeamId as yt, resolveSlackAuthoredTextPlacement as z };
2379
+ export { renderSlackMessagePresentationFallbackText as $, SLACK_MESSAGE_TEXT_HARD_LIMIT as A, SLACK_PRIVATE_ACTION_DELIVERY_RESULT as At, SLACK_REPLY_BUTTON_ACTION_ID as B, isSlackNativeResponseUrlRejection as C, isSlackApprovalAuthorizedSender as Ct, renderSlackBlockFallbackText as D, normalizeSlackApproverId as Dt, buildSlackCompleteBlocksFallbackText as E, isSlackExecApprovalClientEnabled as Et, canRenderSlackPresentation as F, isSlackCallbackActionId as G, SLACK_REPLY_SELECT_ACTION_ID as H, countSlackTextUtf8Bytes as I, decodeSlackQuestionAction as J, isSlackQuestionActionId as K, truncateSlackText as L, SLACK_TEXT_LIMIT as M, buildSlackInteractiveBlocks as N, resolveSlackAuthoredTextPlacement as O, resolveSlackExecApprovalTarget as Ot, buildSlackPresentationBlocks as P, normalizeSlackOutboundText as Q, truncateSlackTextByUtf8Bytes as R, isSlackInvalidBlocksResponse as S, getSlackApprovalApprovers as St, buildSlackBlocksFallbackText as T, isSlackExecApprovalAuthorizedSender as Tt, SLACK_SESSION_LINK_ACTION_ID as U, SLACK_REPLY_LINK_ACTION_ID as V, isSlackApprovalActionId as W, chunkSlackMrkdwnText as X, resolveSlackQuestionAction as Y, markdownToSlackMrkdwnChunks as Z, appendSlackNativeDataPlainTextFallback as _, shouldHandleSlackPluginViaForwardingSession as _t, qualifySlackConversationId as a, SLACK_MAX_BLOCKS as at, hasSlackNativeDataBlock as b, isSlackWorkspaceInstallation as bt, assertSlackDetachedTargetAllowed as c, hasSlackPluginApprovers as ct, resolveSlackReplyBlockResolution as d, normalizeSlackOriginTarget as dt, escapeSlackMrkdwn as et, resolveSlackReplyBlocks as f, resolveEnterpriseApprovalTeamId as ft, appendSlackNativeDataFallbackText as g, shouldHandleSlackNativeApprovalRequest as gt, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as h, resolveTurnSourceSlackOriginTarget as ht, resolveSlackGroupToolPolicy as i, SLACK_SECTION_TEXT_MAX as it, SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT as j, resolveSlackAutoThreadId as jt, SLACK_EDIT_TEXT_MAX_BYTES as k, shouldSuppressLocalSlackExecApprovalPrompt as kt, hasSlackReplyStructuredContent as l, isSlackAnyNativeApprovalClientEnabled as lt, resolveSlackReplyRenderPlan as m, resolveSlackFallbackOriginTarget as mt, buildSlackChannelPolicyScope as n, decodeSlackApprovalAction as nt, qualifySlackRoutePeerId as o, parseSlackBlocksInput as ot, resolveSlackReplyDeliveryMessages as p, resolveSessionSlackOriginTarget as pt, resolveSlackQuestionActionIds as q, resolveSlackGroupRequireMention as r, SLACK_PRESENTATION_CAPABILITIES as rt, resolveSlackEnterpriseMainDmSessionKey as s, validateSlackBlocksArray as st, buildSlackChannelIdCandidates as t, SLACK_APPROVAL_HEADER_BLOCK_ID as tt, parseSlackReplyBlockSegments as u, normalizeSlackForwardTarget as ut, buildSlackNativeDataAccessibilityText as v, slackTargetsMatch as vt, stripSlackNativeDataBlocks as w, getSlackExecApprovalApprovers as wt, isSlackInvalidBlocksError as x, registerSlackInstallationState as xt, createSlackNativeDataBaseTextConsumer as y, getSlackInstallationKind as yt, SLACK_QUESTION_FINALIZATION_BLOCKS as z };