@openclaw/slack 2026.8.1-beta.3 → 2026.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/account-configured-sUohAxZr.js +33 -0
  2. package/dist/account-inspect-C3sePHWa.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-B0kRJ69h.js} +90 -75
  7. package/dist/action-runtime.runtime-IuA14rev.js +2 -0
  8. package/dist/{actions-DFk0ANVB.js → actions-BOxiu2Vy.js} +278 -102
  9. package/dist/api.js +15 -15
  10. package/dist/{approval-handler.runtime-BNvAoKdK.js → approval-handler.runtime-l5_2JLqi.js} +58 -180
  11. package/dist/{channel-CA5w7qDF.js → channel-BguxhhNG.js} +97 -154
  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-ChkODKBW.js} +3 -3
  15. package/dist/{channel.setup-CpyYsEXH.js → channel.setup-BJohRJha.js} +54 -68
  16. package/dist/{config-schema-CN3XZRX5.js → config-schema-B9GwoRlE.js} +24 -15
  17. package/dist/configured-state.js +34 -0
  18. package/dist/{conversation-binding-route-DFVLUdYF.js → conversation-binding-route-Vee8Dgbf.js} +2 -2
  19. package/dist/{directory-config-BGYyuzWh.js → directory-config-Bmw4ykSy.js} +5 -4
  20. package/dist/directory-contract-api.js +1 -1
  21. package/dist/{directory-live-DjUJQLbq.js → directory-live-BOILcXPo.js} +2 -2
  22. package/dist/{doctor-contract-BAy7-EUQ.js → doctor-contract-BNjw9bxb.js} +5 -4
  23. package/dist/doctor-contract-api.js +1 -1
  24. package/dist/{group-policy-DyfB_ZIE.js → group-policy-BYH74y50.js} +643 -774
  25. package/dist/{message-tool-api-CqMr5Rmc.js → message-tool-api-BsZbsulu.js} +23 -5
  26. package/dist/message-tool-api.js +1 -1
  27. package/dist/{monitor-Chrecrb9.js → monitor-B72wWXWg.js} +3 -3
  28. package/dist/{outbound-adapter-DuRqAQXK.js → outbound-adapter-CPgYQ-BM.js} +94 -69
  29. package/dist/{pipeline.runtime-Bbfd5VFW.js → pipeline.runtime-CcdujV99.js} +357 -544
  30. package/dist/{policy-BKXSxrIS.js → policy-CUpBeOt9.js} +7 -4
  31. package/dist/{probe-BVA65leh.js → probe-gj5yQgN2.js} +209 -21
  32. package/dist/{provider-CUUiwsg2.js → provider-DW9YC_no.js} +301 -179
  33. package/dist/{relay-source-mhpMMRG-.js → relay-source-BLMdBrAw.js} +6 -4
  34. package/dist/{replies-SnWyXcsL.js → replies-DLjQ8RYU.js} +25 -10
  35. package/dist/{resolve-channels-BSpqC8jU.js → resolve-channels-Bv6IiGZ4.js} +4 -3
  36. package/dist/{resolve-users-Dvz9pDe0.js → resolve-users-BXw2pA7y.js} +4 -3
  37. package/dist/runtime-api.js +11 -11
  38. package/dist/{scopes-BSk4GZvZ.js → scopes-B9HRguDe.js} +1 -1
  39. package/dist/{send-CtnOxKCc.js → send-GUz4_v2E.js} +58 -42
  40. package/dist/send-results-eeOu_HYm.js +23 -0
  41. package/dist/{send.runtime-kYctMHSd.js → send.runtime-rScD-UJi.js} +1 -1
  42. package/dist/setup-plugin-api.js +1 -1
  43. package/dist/{setup-surface-BPFfp6So.js → setup-surface-Cc3P-z35.js} +6 -6
  44. package/dist/{shared-DJBaslN7.js → shared-CQGVZ_8a.js} +28 -8
  45. package/dist/{slash-dispatch.runtime-Cf2FTrnf.js → slash-dispatch.runtime-C2015r6s.js} +3 -3
  46. package/dist/{target-parsing-BnMD2ZqZ.js → target-parsing-PbxGDbr9.js} +11 -6
  47. package/dist/{targets-Cx5W_n3W.js → targets-7FexXJ62.js} +1 -1
  48. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  49. package/node_modules/@slack/bolt/node_modules/@types/node/child_process.d.ts +0 -1
  50. package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +6 -6
  51. package/node_modules/@slack/bolt/node_modules/@types/node/dns/promises.d.ts +5 -5
  52. package/node_modules/@slack/bolt/node_modules/@types/node/dns.d.ts +5 -5
  53. package/node_modules/@slack/bolt/node_modules/@types/node/fs.d.ts +7 -0
  54. package/node_modules/@slack/bolt/node_modules/@types/node/http.d.ts +30 -0
  55. package/node_modules/@slack/bolt/node_modules/@types/node/http2.d.ts +4 -4
  56. package/node_modules/@slack/bolt/node_modules/@types/node/os.d.ts +30 -30
  57. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  58. package/node_modules/@slack/bolt/node_modules/@types/node/perf_hooks.d.ts +2 -1
  59. package/node_modules/@slack/bolt/node_modules/@types/node/process.d.ts +42 -43
  60. package/node_modules/@slack/bolt/node_modules/@types/node/quic.d.ts +1049 -84
  61. package/node_modules/@slack/bolt/node_modules/@types/node/sqlite.d.ts +14 -1
  62. package/node_modules/@slack/bolt/node_modules/@types/node/stream/iter.d.ts +3 -2
  63. package/node_modules/@slack/bolt/node_modules/@types/node/test.d.ts +61 -0
  64. package/node_modules/@slack/bolt/node_modules/@types/node/v8.d.ts +20 -23
  65. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  66. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  67. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  68. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  69. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  70. package/node_modules/@slack/bolt/node_modules/negotiator/lib/accept.js +54 -0
  71. package/node_modules/@slack/bolt/node_modules/negotiator/lib/charset.js +10 -34
  72. package/node_modules/@slack/bolt/node_modules/negotiator/lib/encoding.js +9 -30
  73. package/node_modules/@slack/bolt/node_modules/negotiator/lib/language.js +15 -36
  74. package/node_modules/@slack/bolt/node_modules/negotiator/lib/mediaType.js +16 -134
  75. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
  76. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +71 -0
  77. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
  78. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
  79. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
  80. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +52 -0
  81. package/node_modules/@slack/bolt/node_modules/negotiator/package.json +16 -10
  82. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +2 -0
  83. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  84. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  85. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  86. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +1 -1
  87. package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
  88. package/node_modules/@slack/socket-mode/node_modules/@types/node/child_process.d.ts +0 -1
  89. package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +6 -6
  90. package/node_modules/@slack/socket-mode/node_modules/@types/node/dns/promises.d.ts +5 -5
  91. package/node_modules/@slack/socket-mode/node_modules/@types/node/dns.d.ts +5 -5
  92. package/node_modules/@slack/socket-mode/node_modules/@types/node/fs.d.ts +7 -0
  93. package/node_modules/@slack/socket-mode/node_modules/@types/node/http.d.ts +30 -0
  94. package/node_modules/@slack/socket-mode/node_modules/@types/node/http2.d.ts +4 -4
  95. package/node_modules/@slack/socket-mode/node_modules/@types/node/os.d.ts +30 -30
  96. package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
  97. package/node_modules/@slack/socket-mode/node_modules/@types/node/perf_hooks.d.ts +2 -1
  98. package/node_modules/@slack/socket-mode/node_modules/@types/node/process.d.ts +42 -43
  99. package/node_modules/@slack/socket-mode/node_modules/@types/node/quic.d.ts +1049 -84
  100. package/node_modules/@slack/socket-mode/node_modules/@types/node/sqlite.d.ts +14 -1
  101. package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/iter.d.ts +3 -2
  102. package/node_modules/@slack/socket-mode/node_modules/@types/node/test.d.ts +61 -0
  103. package/node_modules/@slack/socket-mode/node_modules/@types/node/v8.d.ts +20 -23
  104. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  105. package/node_modules/@slack/web-api/node_modules/@types/node/child_process.d.ts +0 -1
  106. package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +6 -6
  107. package/node_modules/@slack/web-api/node_modules/@types/node/dns/promises.d.ts +5 -5
  108. package/node_modules/@slack/web-api/node_modules/@types/node/dns.d.ts +5 -5
  109. package/node_modules/@slack/web-api/node_modules/@types/node/fs.d.ts +7 -0
  110. package/node_modules/@slack/web-api/node_modules/@types/node/http.d.ts +30 -0
  111. package/node_modules/@slack/web-api/node_modules/@types/node/http2.d.ts +4 -4
  112. package/node_modules/@slack/web-api/node_modules/@types/node/os.d.ts +30 -30
  113. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  114. package/node_modules/@slack/web-api/node_modules/@types/node/perf_hooks.d.ts +2 -1
  115. package/node_modules/@slack/web-api/node_modules/@types/node/process.d.ts +42 -43
  116. package/node_modules/@slack/web-api/node_modules/@types/node/quic.d.ts +1049 -84
  117. package/node_modules/@slack/web-api/node_modules/@types/node/sqlite.d.ts +14 -1
  118. package/node_modules/@slack/web-api/node_modules/@types/node/stream/iter.d.ts +3 -2
  119. package/node_modules/@slack/web-api/node_modules/@types/node/test.d.ts +61 -0
  120. package/node_modules/@slack/web-api/node_modules/@types/node/v8.d.ts +20 -23
  121. package/node_modules/typebox/build/format/date.d.mts +1 -1
  122. package/node_modules/typebox/build/format/date.mjs +1 -1
  123. package/node_modules/typebox/build/format/date_time.d.mts +2 -2
  124. package/node_modules/typebox/build/format/date_time.mjs +3 -3
  125. package/node_modules/typebox/build/format/email.d.mts +1 -1
  126. package/node_modules/typebox/build/format/email.mjs +2 -2
  127. package/node_modules/typebox/build/format/hostname.mjs +2 -10
  128. package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
  129. package/node_modules/typebox/build/format/idn_email.mjs +3 -3
  130. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
  131. package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
  132. package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
  133. package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
  134. package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
  135. package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
  136. package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
  137. package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
  138. package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
  139. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +41 -0
  140. package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
  141. package/node_modules/typebox/build/format/idna/index.mjs +2 -0
  142. package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
  143. package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
  144. package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
  145. package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
  146. package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
  147. package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
  148. package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
  149. package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
  150. package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
  151. package/node_modules/typebox/build/format/ipv4.mjs +2 -32
  152. package/node_modules/typebox/build/format/ipv6.mjs +2 -61
  153. package/node_modules/typebox/build/format/iri.d.mts +2 -2
  154. package/node_modules/typebox/build/format/iri.mjs +26 -8
  155. package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
  156. package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
  157. package/node_modules/typebox/build/format/regex.d.mts +1 -2
  158. package/node_modules/typebox/build/format/regex.mjs +2 -6
  159. package/node_modules/typebox/build/format/time.d.mts +2 -2
  160. package/node_modules/typebox/build/format/time.mjs +19 -14
  161. package/node_modules/typebox/build/format/uri.d.mts +1 -1
  162. package/node_modules/typebox/build/format/uri.mjs +3 -130
  163. package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
  164. package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
  165. package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
  166. package/node_modules/typebox/build/format/uri_template.mjs +4 -5
  167. package/node_modules/typebox/build/format/url.d.mts +3 -3
  168. package/node_modules/typebox/build/format/url.mjs +4 -5
  169. package/node_modules/typebox/build/guard/emit.d.mts +3 -1
  170. package/node_modules/typebox/build/guard/emit.mjs +12 -5
  171. package/node_modules/typebox/build/guard/guard.d.mts +8 -2
  172. package/node_modules/typebox/build/guard/guard.mjs +25 -4
  173. package/node_modules/typebox/build/guard/string.d.mts +2 -2
  174. package/node_modules/typebox/build/guard/string.mjs +7 -7
  175. package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
  176. package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
  177. package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
  178. package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
  179. package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
  180. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
  181. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
  182. package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
  183. package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
  184. package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
  185. package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
  186. package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
  187. package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
  188. package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
  189. package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
  190. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
  191. package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
  192. package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
  193. package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
  194. package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
  195. package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
  196. package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
  197. package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
  198. package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
  199. package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
  200. package/node_modules/typebox/build/schema/types/index.mjs +0 -2
  201. package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
  202. package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
  203. package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
  204. package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
  205. package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
  206. package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
  207. package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
  208. package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
  209. package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
  210. package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
  211. package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
  212. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
  213. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
  214. package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
  215. package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
  216. package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
  217. package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
  218. package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
  219. package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
  220. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
  221. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
  222. package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
  223. package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
  224. package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
  225. package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
  226. package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
  227. package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
  228. package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
  229. package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
  230. package/node_modules/typebox/build/type/script/parser.mjs +27 -23
  231. package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
  232. package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
  233. package/node_modules/typebox/package.json +27 -27
  234. package/node_modules/typebox/readme.md +79 -82
  235. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  236. package/node_modules/ws/package.json +1 -1
  237. package/openclaw.plugin.json +14 -6
  238. package/package.json +9 -7
  239. package/dist/account-configured-BwfXBo_F.js +0 -14
  240. package/dist/account-inspect-YJvFBbCR.js +0 -89
  241. package/dist/action-runtime.runtime-JtoOK9l5.js +0 -2
  242. package/dist/actions.runtime-CYLsYRai.js +0 -2
  243. package/dist/runtime-api-DBi7xc_g.js +0 -10
  244. package/dist/slack-client-kind-BXyOOICI.js +0 -94
  245. package/node_modules/@slack/bolt/node_modules/negotiator/HISTORY.md +0 -114
  246. package/node_modules/typebox/build/format/_idna.d.mts +0 -2
  247. package/node_modules/typebox/build/format/_idna.mjs +0 -246
  248. package/node_modules/typebox/build/format/_puny.d.mts +0 -1
  249. package/node_modules/typebox/build/format/_puny.mjs +0 -77
  250. package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
  251. package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
  252. package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
  253. package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
  254. package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
  255. package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
@@ -1,40 +1,40 @@
1
- import { n as resolveSlackConversationBindingRoute, r as resolveSlackReplyToMode, t as normalizeSlackRouteBindingConfig } from "./conversation-binding-route-DFVLUdYF.js";
2
- import { n as formatSlackTarget } from "./target-parsing-BnMD2ZqZ.js";
3
- import { B as SLACK_EDIT_TEXT_MAX_BYTES, F as normalizeSlackOutboundText, I as buildSlackBlocksFallbackText, J as truncateSlackText, O as hasSlackNativeDataBlock, S as resolveSlackReplyRenderPlan, U as SLACK_TEXT_LIMIT, Y as truncateSlackTextByUtf8Bytes, a as qualifySlackConversationId, ct as escapeSlackMrkdwn, d as normalizeSlackAllowOwnerEntry, et as SLACK_SESSION_LINK_ACTION_ID, o as qualifySlackRoutePeerId, p as resolveSlackAllowListMatch, q as countSlackTextUtf8Bytes, s as resolveSlackEnterpriseMainDmSessionKey, u as normalizeAllowListLower } from "./group-policy-DyfB_ZIE.js";
4
- import { r as formatSlackError } from "./probe-BVA65leh.js";
1
+ import { n as resolveSlackConversationBindingRoute, r as resolveSlackReplyToMode, t as normalizeSlackRouteBindingConfig } from "./conversation-binding-route-Vee8Dgbf.js";
2
+ import { n as formatSlackTarget } from "./target-parsing-PbxGDbr9.js";
3
+ import { I as countSlackTextUtf8Bytes, L as truncateSlackText, M as SLACK_TEXT_LIMIT, Q as normalizeSlackOutboundText, R as truncateSlackTextByUtf8Bytes, T as buildSlackBlocksFallbackText, U as SLACK_SESSION_LINK_ACTION_ID, a as qualifySlackConversationId, b as hasSlackNativeDataBlock, et as escapeSlackMrkdwn, k as SLACK_EDIT_TEXT_MAX_BYTES, m as resolveSlackReplyRenderPlan, o as qualifySlackRoutePeerId, s as resolveSlackEnterpriseMainDmSessionKey } from "./group-policy-BYH74y50.js";
4
+ import { C as normalizeAllowListLower, E as resolveSlackAllowListMatch, o as formatSlackError, w as normalizeSlackAllowOwnerEntry } from "./probe-gj5yQgN2.js";
5
5
  import { n as resolveSlackStreamingMode, t as resolveSlackNativeStreaming } from "./streaming-compat-B-e0mqM0.js";
6
- import { b as formatSlackFileReferenceList, i as editSlackRenderedMessage, p as removeSlackReaction, r as editSlackMessage, t as deleteSlackMessage, u as reactSlackMessage, v as logVerbose$1, x as buildSlackEditTextPayload, y as formatSlackFileReference } from "./actions-DFk0ANVB.js";
7
- import { a as hasSlackTableBlock, c as resolveSlackMessageText$1, o as isSlackUnfurlAttachment, s as resolveSlackBlocksText } from "./slack-client-kind-BXyOOICI.js";
8
- import { c as hasSlackThreadFailureNotice, d as recordSlackThreadFailureNotice, f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, m as buildSlackNativeDataDeliveryPlan, o as clearSlackThreadFailureNotice, r as sendMessageSlack, u as hasSlackThreadParticipationWithPersistence } from "./send-CtnOxKCc.js";
9
- import { S as updateLastRoute, _ as parseSlackAssistantThreadMetadata, b as resolveChannelResetConfig, c as resolveConversationLabel$1, d as resolveSlackEffectiveAllowFrom, g as buildSlackAssistantThreadMetadata, h as resolveSlackChatType, l as authorizeSlackBotRoomMessage, m as normalizeSlackChannelType, o as authorizeSlackDirectMessage, r as resolveSlackRoomContextHints, s as trackSlackDraftMessage, u as resolveSlackCommandIngress, v as readSessionUpdatedAt, w as stripSlackMentionsForCommandDetection, x as resolveStorePath, y as resolveChannelContextVisibilityMode } from "./provider-CUUiwsg2.js";
10
- import { n as resolveSlackChannelConfig } from "./policy-BKXSxrIS.js";
11
- import { a as resolveDeliveredSlackReplyThreadTs, i as readSlackReplyBlocks, n as deliverReplies, o as resolveSlackThreadTs, s as emitSlackMessageSentHooks, t as createSlackReplyDeliveryPlan } from "./replies-SnWyXcsL.js";
6
+ import { D as resolveSlackMessageText$1, E as resolveSlackBlocksText, O as buildSlackEditTextPayload, S as formatSlackFileReferenceList, T as isSlackUnfurlAttachment, a as editSlackRenderedMessage, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, v as logVerbose$1, w as hasSlackTableBlock, x as formatSlackFileReference } from "./actions-BOxiu2Vy.js";
7
+ import { c as hasSlackThreadFailureNotice, d as recordSlackThreadFailureNotice, f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, m as buildSlackNativeDataDeliveryPlan, o as clearSlackThreadFailureNotice, r as sendMessageSlack, u as hasSlackThreadParticipationWithPersistence } from "./send-GUz4_v2E.js";
8
+ import { C as resolveStorePath, E as stripSlackMentionsForCommandDetection, S as resolveChannelResetConfig, _ as resolveSlackChatType, b as readSessionUpdatedAt, c as resolveSlackThreadTargets, d as authorizeSlackBotRoomMessage, f as resolveSlackCommandIngress, g as normalizeSlackChannelType, l as trackSlackDraftMessage, o as authorizeSlackDirectMessage, p as resolveSlackEffectiveAllowFrom, r as resolveSlackRoomContextHints, s as resolveSlackThreadContext, u as resolveConversationLabel$1, v as buildSlackAssistantThreadMetadata, w as updateLastRoute, x as resolveChannelContextVisibilityMode, y as parseSlackAssistantThreadMetadata } from "./provider-DW9YC_no.js";
9
+ import { n as resolveSlackChannelConfig } from "./policy-CUpBeOt9.js";
10
+ import { a as resolveDeliveredSlackReplyThreadTs, c as emitSlackMessageSentHooks, i as readSlackReplyBlocks, n as deliverReplies, o as resolveSlackThreadTs, s as sanitizeSlackMonitorReplyPayload, t as createSlackReplyDeliveryPlan } from "./replies-DLjQ8RYU.js";
12
11
  import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
12
  import { resolveAgentRoute, resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
14
- import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createFinalizableDraftStreamControlsForState, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftText, formatPlanChecklistLines, isChannelProgressDraftWorkToolName, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-outbound";
13
+ import { createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createDraftStreamLoop, createFinalizableDraftStreamControlsForState, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-outbound";
15
14
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
16
15
  import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
16
+ import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
17
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
18
+ import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
17
19
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
18
- import { createHash } from "node:crypto";
19
20
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
20
21
  import { ensureConfiguredBindingRouteReady } from "openclaw/plugin-sdk/conversation-runtime";
22
+ import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
21
23
  import fs from "node:fs/promises";
22
24
  import { runTasksWithConcurrency } from "openclaw/plugin-sdk/concurrency-runtime";
23
25
  import { formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
24
- import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
25
26
  import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist, shouldIncludeSupplementalContext } from "openclaw/plugin-sdk/security-runtime";
26
27
  import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
27
28
  import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
28
29
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
29
30
  import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
30
- import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
31
31
  import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
32
32
  import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
33
33
  import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, implicitMentionKindWhen, logInboundDrop, matchesMentionWithExplicit, readAgentRunTerminalOutcome, recordDroppedChannelInboundHistory, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, resolveInboundReplyDispatchCounts, resolveInboundSupplementalSenderAllowed, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
34
34
  import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
35
35
  import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
36
36
  import { buildControlUiSessionPath } from "openclaw/plugin-sdk/session-discussion";
37
- import { DEFAULT_TIMING, createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
37
+ import { createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
38
38
  import { hasControlCommand } from "openclaw/plugin-sdk/command-detection";
39
39
  import { isAbortRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
40
40
  import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
@@ -384,12 +384,12 @@ function createSlackDraftStream(params) {
384
384
  const send = params.send ?? sendMessageSlack;
385
385
  const edit = params.edit ?? editSlackMessage;
386
386
  const remove = params.remove ?? deleteSlackMessage;
387
- let streamMessageId;
388
- let streamChannelId;
387
+ let streamMessage;
389
388
  let untrackConversationBoundary;
390
389
  let lastVisibleUpdate;
391
390
  let lastSentKey = "";
392
- const detachedMessages = [];
391
+ const pendingCleanupMessages = [];
392
+ let cleanupTail = Promise.resolve();
393
393
  const finalizedMessageIds = /* @__PURE__ */ new Set();
394
394
  const streamState = {
395
395
  stopped: false,
@@ -411,8 +411,8 @@ function createSlackDraftStream(params) {
411
411
  if (sentKey === lastSentKey) return;
412
412
  lastSentKey = sentKey;
413
413
  try {
414
- if (streamChannelId && streamMessageId) {
415
- await edit(streamChannelId, streamMessageId, trimmed, {
414
+ if (streamMessage) {
415
+ await edit(streamMessage.channelId, streamMessage.messageId, trimmed, {
416
416
  cfg: params.cfg,
417
417
  token: params.token,
418
418
  accountId: params.accountId,
@@ -444,27 +444,29 @@ function createSlackDraftStream(params) {
444
444
  ...params.metadata ? { metadata: params.metadata } : {},
445
445
  ...blocks ? { blocks } : {}
446
446
  });
447
- streamChannelId = sent.channelId || streamChannelId;
448
- streamMessageId = sent.messageId || streamMessageId;
449
- if (!streamChannelId || !streamMessageId) {
447
+ if (!sent.channelId || !sent.messageId) {
450
448
  stopTrackingConversationBoundary();
451
449
  streamState.stopped = true;
452
450
  params.warn?.("slack stream preview stopped (missing identifiers from sendMessage)");
453
451
  return;
454
452
  }
453
+ streamMessage = {
454
+ channelId: sent.channelId,
455
+ messageId: sent.messageId
456
+ };
455
457
  lastVisibleUpdate = {
456
458
  text: trimmed,
457
459
  ...blocks ? { blocks } : {}
458
460
  };
459
- if (pendingBoundary && params.conversationChannelId === streamChannelId) pendingBoundary.setMessageTs(streamMessageId);
461
+ if (pendingBoundary && params.conversationChannelId === streamMessage.channelId) pendingBoundary.setMessageTs(streamMessage.messageId);
460
462
  else {
461
463
  stopTrackingConversationBoundary();
462
464
  untrackConversationBoundary = trackSlackDraftMessage({
463
465
  accountId: params.accountId,
464
466
  teamId: params.eventScope?.teamId,
465
- channelId: streamChannelId,
467
+ channelId: streamMessage.channelId,
466
468
  threadTs,
467
- messageTs: streamMessageId,
469
+ messageTs: streamMessage.messageId,
468
470
  onInterveningMessage: forceNewMessage
469
471
  }).stop;
470
472
  }
@@ -476,6 +478,7 @@ function createSlackDraftStream(params) {
476
478
  };
477
479
  const { loop, update, discardPending, seal } = createFinalizableDraftStreamControlsForState({
478
480
  throttleMs,
481
+ coalesceInFlight: true,
479
482
  state: streamState,
480
483
  sendOrEditStreamMessage,
481
484
  emptyValue: "",
@@ -485,60 +488,58 @@ function createSlackDraftStream(params) {
485
488
  untrackConversationBoundary?.();
486
489
  untrackConversationBoundary = void 0;
487
490
  };
488
- const removeMessage = async (channelId, messageId) => {
489
- try {
490
- await remove(channelId, messageId, {
491
- token: params.token,
492
- accountId: params.accountId,
493
- ...params.eventScope ? { client: params.eventScope.client } : {}
494
- });
495
- } catch (err) {
496
- params.warn?.(`slack stream preview cleanup failed: ${formatSlackError(err)}`);
497
- }
491
+ const dropDetachedMessages = () => {
492
+ cleanupTail = cleanupTail.then(async () => {
493
+ for (let index = 0; index < pendingCleanupMessages.length;) {
494
+ const message = pendingCleanupMessages[index];
495
+ if (!message) return;
496
+ try {
497
+ await remove(message.channelId, message.messageId, {
498
+ token: params.token,
499
+ accountId: params.accountId,
500
+ ...params.eventScope ? { client: params.eventScope.client } : {}
501
+ });
502
+ pendingCleanupMessages.splice(index, 1);
503
+ } catch (err) {
504
+ params.warn?.(`slack stream preview cleanup failed: ${formatSlackError(err)}`);
505
+ index += 1;
506
+ }
507
+ }
508
+ });
509
+ return cleanupTail;
498
510
  };
499
511
  const clear = async () => {
500
512
  stopTrackingConversationBoundary();
501
513
  await discardPending();
502
- const channelId = streamChannelId;
503
- const messageId = streamMessageId;
504
- streamChannelId = void 0;
505
- streamMessageId = void 0;
514
+ if (streamMessage) {
515
+ pendingCleanupMessages.push(streamMessage);
516
+ streamMessage = void 0;
517
+ }
506
518
  lastVisibleUpdate = void 0;
507
519
  lastSentKey = "";
508
- if (!channelId || !messageId) return;
509
- await removeMessage(channelId, messageId);
520
+ await dropDetachedMessages();
510
521
  };
511
522
  const forceNewMessage = () => {
512
523
  stopTrackingConversationBoundary();
513
524
  streamState.stopped = false;
514
525
  streamState.final = false;
515
- if (streamChannelId && streamMessageId && !finalizedMessageIds.has(streamMessageId)) detachedMessages.push({
516
- channelId: streamChannelId,
517
- messageId: streamMessageId
518
- });
519
- streamMessageId = void 0;
520
- streamChannelId = void 0;
526
+ if (streamMessage && !finalizedMessageIds.has(streamMessage.messageId)) pendingCleanupMessages.push(streamMessage);
527
+ streamMessage = void 0;
521
528
  lastVisibleUpdate = void 0;
522
529
  lastSentKey = "";
523
530
  loop.resetPending();
524
531
  };
525
- const dropDetachedMessages = async () => {
526
- let message;
527
- while ((message = detachedMessages.shift()) !== void 0) {
528
- const { channelId, messageId } = message;
529
- await removeMessage(channelId, messageId);
530
- }
531
- };
532
532
  const discardPendingAndStopTracking = async () => {
533
533
  stopTrackingConversationBoundary();
534
534
  await discardPending();
535
535
  };
536
536
  const finalizeMessage = async (messageId, editFinal) => {
537
- const channelId = streamChannelId;
537
+ const currentMessage = streamMessage;
538
538
  const previousUpdate = lastVisibleUpdate;
539
- if (!channelId || streamMessageId !== messageId || !previousUpdate) return false;
539
+ if (!currentMessage || currentMessage.messageId !== messageId || !previousUpdate) return false;
540
+ const { channelId } = currentMessage;
540
541
  await editFinal();
541
- if (streamChannelId === channelId && streamMessageId === messageId) {
542
+ if (streamMessage?.channelId === channelId && streamMessage.messageId === messageId) {
542
543
  finalizedMessageIds.add(messageId);
543
544
  stopTrackingConversationBoundary();
544
545
  return true;
@@ -566,69 +567,16 @@ function createSlackDraftStream(params) {
566
567
  forceNewMessage,
567
568
  dropDetachedMessages,
568
569
  finalizeMessage,
569
- messageId: () => streamMessageId,
570
- channelId: () => streamChannelId
571
- };
572
- }
573
- //#endregion
574
- //#region extensions/slack/src/stream-mode.ts
575
- function resolveSlackStreamingConfig(params) {
576
- return {
577
- mode: resolveSlackStreamingMode(params),
578
- nativeStreaming: resolveSlackNativeStreaming(params)
579
- };
580
- }
581
- function applyAppendOnlyStreamUpdate(params) {
582
- const incoming = params.incoming.trimEnd();
583
- if (!incoming) return {
584
- rendered: params.rendered,
585
- source: params.source,
586
- changed: false
587
- };
588
- if (!params.rendered) return {
589
- rendered: incoming,
590
- source: incoming,
591
- changed: true
592
- };
593
- if (incoming === params.source) return {
594
- rendered: params.rendered,
595
- source: params.source,
596
- changed: false
597
- };
598
- if (incoming.startsWith(params.rendered)) return {
599
- rendered: incoming,
600
- source: incoming,
601
- changed: incoming !== params.rendered
602
- };
603
- if (incoming.startsWith(params.source)) {
604
- const delta = incoming.slice(params.source.length);
605
- return {
606
- rendered: `${params.rendered}${delta}`,
607
- source: incoming,
608
- changed: delta.length > 0
609
- };
610
- }
611
- if (params.source.startsWith(incoming)) return {
612
- rendered: params.rendered,
613
- source: params.source,
614
- changed: false
615
- };
616
- const separator = params.separator ?? (params.rendered.endsWith("\n") ? "" : "\n");
617
- return {
618
- rendered: `${params.rendered}${separator}${incoming}`,
619
- source: incoming,
620
- changed: true
570
+ messageId: () => streamMessage?.messageId,
571
+ channelId: () => streamMessage?.channelId
621
572
  };
622
573
  }
623
574
  //#endregion
624
575
  //#region extensions/slack/src/progress-blocks.ts
625
576
  const SLACK_PROGRESS_FIELD_MAX = 1800;
626
577
  const DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS = 120;
627
- const DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS = 48;
628
578
  const SLACK_PROGRESS_CHUNK_TEXT_MAX = 256;
629
579
  const SLACK_PROGRESS_TASK_TITLE_MAX = 120;
630
- const SLACK_PROGRESS_PLAN_FALLBACK_TITLE = "Thinking";
631
- const SLACK_PROGRESS_LINE_DELTA_RE = /(?:^|\s)\+(\d+)\s+[−-](\d+)(?=\s|$)/u;
632
580
  function buildSessionSources(url) {
633
581
  return [{
634
582
  type: "url_source",
@@ -636,12 +584,6 @@ function buildSessionSources(url) {
636
584
  text: "Open in OpenClaw"
637
585
  }];
638
586
  }
639
- function field(text) {
640
- return {
641
- type: "mrkdwn",
642
- text: truncateSlackText(text, SLACK_PROGRESS_FIELD_MAX)
643
- };
644
- }
645
587
  function resolveMaxLineChars(value, fallback) {
646
588
  return value && value > 0 ? Math.floor(value) : fallback;
647
589
  }
@@ -660,141 +602,58 @@ function compactTitle(value) {
660
602
  function compactChunkText(value) {
661
603
  return truncateSlackText(value.replace(/\s+/g, " ").trim(), SLACK_PROGRESS_CHUNK_TEXT_MAX);
662
604
  }
663
- function lineDetailParts(line) {
664
- return [line.detail, line.status && line.status !== "completed" && !line.detail?.includes(line.status) ? line.status : void 0].map((part) => part?.trim()).filter((part) => Boolean(part));
665
- }
666
- function legacyLineTitle(line) {
667
- return `${line.icon ?? "•"} *${escapeSlackMrkdwn(line.label)}*`;
668
- }
669
605
  function isAuthoredProgressLine(line) {
670
606
  return line.id === "reasoning" || line.id?.startsWith("commentary:") === true;
671
607
  }
672
- function legacyLineDetail(line, maxChars) {
673
- const detail = lineDetailParts(line).join(" · ");
674
- if (detail) return escapeSlackMrkdwn(compactDetail(detail, maxChars));
675
- if (isAuthoredProgressLine(line)) return normalizeSlackOutboundText(compactDetail(line.text.replace(/^(?:🧠|💬)\s+/u, ""), maxChars));
676
- return "—";
677
- }
678
- function lineTaskTitle(line) {
679
- const label = (line.kind === "command-output" ? line.toolName : void 0) || line.label.replace(/\s+/g, " ").trim() || line.toolName || line.kind || "Update";
680
- const fallback = line.text.replace(/\s+/g, " ").trim();
681
- if (fallback && fallback !== label) return compactTitle(lineDetailParts(line).length > 0 || line.status ? label : fallback);
682
- return compactTitle(label);
683
- }
684
- function lineTaskDetails(line, maxLineChars) {
685
- const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
686
- return detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
687
- }
688
- function lineTaskOutput(line) {
689
- const match = line.detail ? SLACK_PROGRESS_LINE_DELTA_RE.exec(line.detail) : null;
690
- if (match) return `+${match[1]} −${match[2]}`;
691
- const status = line.status?.replace(/\s+/g, " ").trim();
692
- return status && lineTaskStatus(line) === "error" ? status : void 0;
693
- }
694
- function lineTaskStatus(line) {
695
- const normalized = line.status?.replace(/\s+/g, " ").trim().toLowerCase();
696
- if (!normalized) return "in_progress";
697
- if (normalized === "complete" || normalized === "completed" || normalized === "done" || normalized === "ok" || normalized === "success" || normalized === "succeeded" || normalized === "successful" || normalized === "exit 0") return "complete";
698
- if (normalized === "error" || normalized === "failed" || normalized === "failure" || normalized.startsWith("exit ")) return normalized === "exit 0" ? "complete" : "error";
699
- return "in_progress";
700
- }
701
- function slugTaskIdPart(value) {
702
- return value?.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "task";
703
- }
704
- function stableTaskIdPart(value, slugValue = value) {
705
- const suffix = createHash("sha256").update(value).digest("hex").slice(0, 8);
706
- return `${slugTaskIdPart(slugValue).slice(0, 48)}_${suffix}`;
707
- }
708
- function resolveLineTaskIdentity(line) {
709
- if (line.id?.trim()) return {
710
- id: stableTaskIdPart(line.id),
711
- contentDerived: false
608
+ function resolveProgressAttention(lines) {
609
+ const approval = lines.findLast((line) => line.kind === "approval" && line.status === "requested");
610
+ if (approval) return {
611
+ id: "openclaw_attention",
612
+ title: compactTitle(`Approval required: ${approval.detail || approval.label}`),
613
+ status: "pending"
712
614
  };
615
+ const failure = lines.findLast((line) => {
616
+ const status = line.status?.trim().toLowerCase();
617
+ return status === "error" || status === "failed" || status === "failure" || status?.startsWith("exit ") && status !== "exit 0";
618
+ });
619
+ if (!failure) return;
713
620
  return {
714
- id: stableTaskIdPart([
715
- line.kind,
716
- line.toolName,
717
- line.label,
718
- line.text
719
- ].join("\0"), line.toolName ?? line.kind ?? line.label),
720
- contentDerived: true
621
+ id: "openclaw_attention",
622
+ title: compactTitle([...new Set([
623
+ failure.label,
624
+ failure.detail,
625
+ failure.status
626
+ ].filter(Boolean))].join(" ")),
627
+ status: "error"
721
628
  };
722
629
  }
723
- function buildPlanTasks(params) {
724
- if (params.plan) return params.plan.slice(-50).map((entry, index) => ({
630
+ function buildSlackProgressStreamChunks(params) {
631
+ const title = compactChunkText(params.title?.trim() || params.label?.trim() || "Working");
632
+ if (!params.title && !params.label && !params.lines.length && !params.plan?.length && !params.sessionUrl) return;
633
+ const tasks = params.plan?.length ? params.plan.slice(-50).map((entry, index) => ({
725
634
  id: `plan_step_${index + 1}`,
726
635
  title: compactTitle(entry.step),
727
636
  status: entry.status === "completed" ? "complete" : entry.status
728
- }));
729
- const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS);
730
- const lines = params.lines.slice(-50);
731
- const identities = lines.map(resolveLineTaskIdentity);
732
- const contentIdOccurrences = /* @__PURE__ */ new Map();
733
- return lines.map((line, index) => {
734
- const identity = identities[index];
735
- let id = identity.id;
736
- if (identity.contentDerived) {
737
- const occurrence = (contentIdOccurrences.get(id) ?? 0) + 1;
738
- contentIdOccurrences.set(id, occurrence);
739
- id = `${id}_${occurrence}`;
740
- }
741
- const details = lineTaskDetails(line, maxLineChars);
742
- const output = lineTaskOutput(line);
743
- const task = {
744
- id,
745
- title: lineTaskTitle(line),
746
- status: lineTaskStatus(line)
747
- };
748
- if (details) task.details = details;
749
- if (output) task.output = output;
750
- return task;
751
- });
752
- }
753
- function resolvePlanTitle(params) {
754
- return compactChunkText(params.title?.trim() || params.label?.trim() || (params.tasks.at(-1)?.details ? `${params.tasks.at(-1)?.title} — ${params.tasks.at(-1)?.details}` : params.tasks.at(-1)?.title) || SLACK_PROGRESS_PLAN_FALLBACK_TITLE);
755
- }
756
- function buildSlackProgressStreamChunks(params) {
757
- const tasks = buildPlanTasks({
758
- lines: params.lines,
759
- plan: params.plan,
760
- maxLineChars: params.maxLineChars
761
- });
762
- if (tasks.length === 0) {
763
- const title = params.title?.trim() || params.label?.trim();
764
- if (!title) return;
765
- if (!params.sessionUrl && !params.diffStat) return [{
766
- type: "plan_update",
767
- title: compactChunkText(title)
768
- }];
769
- return [{
770
- type: "plan_update",
771
- title: compactChunkText(title)
772
- }, {
773
- type: "task_update",
774
- id: "openclaw_summary",
775
- title: "Completed",
776
- status: "complete",
777
- ...formatTaskDiffOutput(params.diffStat) ? { output: formatTaskDiffOutput(params.diffStat) } : {},
778
- ...params.sessionUrl ? { sources: buildSessionSources(params.sessionUrl) } : {}
779
- }];
780
- }
781
- const title = resolvePlanTitle({
782
- label: params.label,
783
- title: params.title,
784
- tasks
785
- });
637
+ })) : [{
638
+ id: "openclaw_summary",
639
+ title: compactTitle(title),
640
+ status: "in_progress"
641
+ }];
642
+ let attention = resolveProgressAttention(params.lines);
643
+ if (params.finalInProgressStatus === "error" && !tasks.some((task) => task.status === "in_progress")) attention = {
644
+ id: "openclaw_attention",
645
+ title: attention?.status === "error" ? attention.title : "Failed",
646
+ status: "error"
647
+ };
648
+ if (attention && !(params.finalInProgressStatus && attention.status === "pending")) tasks.push(attention);
786
649
  const finalTaskIndex = tasks.length - 1;
787
- const diffOutput = formatTaskDiffOutput(params.diffStat);
788
650
  const taskChunks = tasks.map((task, index) => {
789
651
  const chunk = {
790
652
  type: "task_update",
791
653
  id: task.id,
792
654
  title: task.title,
793
- status: task.status === "in_progress" ? params.finalInProgressStatus ?? (params.completeInProgress ? "complete" : task.status) : task.status
655
+ status: task.status === "in_progress" ? params.finalInProgressStatus ?? task.status : task.status
794
656
  };
795
- if (task.details) chunk.details = task.details;
796
- if (task.output) chunk.output = task.output;
797
- if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
798
657
  if (index === finalTaskIndex && params.sessionUrl) chunk.sources = buildSessionSources(params.sessionUrl);
799
658
  return chunk;
800
659
  });
@@ -803,113 +662,50 @@ function buildSlackProgressStreamChunks(params) {
803
662
  title
804
663
  }, ...taskChunks];
805
664
  }
806
- function formatDiffStat(diffStat) {
807
- if (!diffStat || diffStat.files === 0 && diffStat.added === 0 && diffStat.removed === 0) return;
808
- return [
809
- `📝 ${diffStat.files} files`,
810
- ...diffStat.added > 0 ? [`+${diffStat.added}`] : [],
811
- ...diffStat.removed > 0 ? [`−${diffStat.removed}`] : []
812
- ].join(" ");
813
- }
814
- function formatTaskDiffOutput(diffStat) {
815
- return diffStat && (diffStat.added > 0 || diffStat.removed > 0) ? `+${diffStat.added} −${diffStat.removed}` : void 0;
816
- }
817
- function buildActivityText(lines, maxLineChars) {
818
- const rendered = [];
819
- let length = 0;
820
- for (const line of lines.slice(-50).toReversed()) {
821
- const row = `${legacyLineTitle(line)} — ${legacyLineDetail(line, maxLineChars)}`;
822
- const nextLength = length + row.length + (rendered.length > 0 ? 1 : 0);
823
- if (nextLength > SLACK_PROGRESS_FIELD_MAX) break;
824
- rendered.push(row);
825
- length = nextLength;
826
- }
827
- return rendered.toReversed().join("\n");
828
- }
829
665
  function buildSlackProgressCardBlocks(params) {
830
666
  const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS);
831
- const planLines = formatPlanChecklistLines(params.plan ?? [], {
832
- maxLines: 50,
833
- maxLineChars
834
- });
835
- const narration = params.narration?.replace(/\s+/g, " ").trim();
836
- const activityText = buildActivityText(params.lines, maxLineChars);
837
- const diffStat = formatDiffStat(params.diffStat);
838
- const workingFooter = [
839
- ...params.toolCalls && params.toolCalls > 0 ? [`🛠️ ${params.toolCalls} tools`] : [],
840
- ...diffStat ? [diffStat] : [],
841
- ...params.elapsedSeconds && params.elapsedSeconds > 0 ? [`⏱ ${params.elapsedSeconds}s`] : []
842
- ].join(" · ");
843
- const footer = params.state === "working" ? workingFooter : diffStat;
844
- return [
845
- {
846
- type: "section",
847
- text: field(`${params.state === "working" ? "🔄" : params.state === "success" ? "✅" : "❌"} *${escapeSlackMrkdwn(params.title.trim() || "Working")}*`)
848
- },
849
- ...narration ? [{
850
- type: "section",
851
- text: field(`_${escapeSlackMrkdwn(narration)}_`)
852
- }] : [],
853
- ...planLines.length > 0 ? [{
854
- type: "section",
855
- text: field(planLines.map((line) => escapeSlackMrkdwn(line)).join("\n"))
856
- }] : [],
857
- ...activityText ? [{
858
- type: "section",
859
- text: field(activityText)
860
- }] : [],
861
- ...footer ? [{
862
- type: "context",
863
- elements: [field(footer)]
864
- }] : [],
865
- ...params.state !== "working" && params.sessionUrl ? [{
866
- type: "actions",
867
- elements: [{
868
- type: "button",
869
- action_id: SLACK_SESSION_LINK_ACTION_ID,
870
- text: {
871
- type: "plain_text",
872
- text: "Open in OpenClaw"
873
- },
874
- url: params.sessionUrl
875
- }]
876
- }] : []
877
- ].slice(0, 50);
878
- }
879
- const EMPTY_SLACK_NATIVE_STREAM_SNAPSHOT = { tasks: /* @__PURE__ */ new Map() };
880
- const SLACK_TASK_FIELD_SEPARATOR = " · ";
881
- function resolveTaskFieldDelta(previous, incoming) {
882
- if (!incoming) return {
883
- field: previous,
884
- delta: void 0
885
- };
886
- if (previous?.rendered.includes(incoming)) return {
887
- field: {
888
- rendered: previous.rendered,
889
- source: incoming
890
- },
891
- delta: void 0
667
+ const statusLabels = {
668
+ completed: "Completed",
669
+ in_progress: "In progress",
670
+ pending: "Pending"
892
671
  };
893
- const next = applyAppendOnlyStreamUpdate({
894
- incoming,
895
- rendered: previous?.rendered ?? "",
896
- source: previous?.source ?? "",
897
- separator: SLACK_TASK_FIELD_SEPARATOR
672
+ const planLines = (params.plan ?? []).slice(-50).map((entry) => `${statusLabels[entry.status]}: ${compactDetail(entry.step, maxLineChars)}`);
673
+ const narration = params.narration?.replace(/\s+/g, " ").trim();
674
+ const authoredText = params.lines.filter(isAuthoredProgressLine).map((line) => line.text.trim()).filter((text, index, values) => text && text !== narration && values.indexOf(text) === index).map((text) => normalizeSlackOutboundText(compactDetail(text, maxLineChars))).join("\n");
675
+ const attention = resolveProgressAttention(params.lines);
676
+ const blocks = [
677
+ `${params.state === "success" ? "Completed: " : params.state === "error" ? "Failed: " : ""}*${escapeSlackMrkdwn(params.title.trim() || "Working")}*`,
678
+ narration ? `_${escapeSlackMrkdwn(narration)}_` : "",
679
+ planLines.map((line) => escapeSlackMrkdwn(line)).join("\n"),
680
+ authoredText,
681
+ attention && !(params.state !== "working" && attention.status === "pending") ? escapeSlackMrkdwn(attention.title) : ""
682
+ ].filter(Boolean).map((text) => ({
683
+ type: "section",
684
+ text: {
685
+ type: "mrkdwn",
686
+ text: truncateSlackText(text, SLACK_PROGRESS_FIELD_MAX)
687
+ }
688
+ }));
689
+ if (params.state !== "working" && params.sessionUrl) blocks.push({
690
+ type: "actions",
691
+ elements: [{
692
+ type: "button",
693
+ action_id: SLACK_SESSION_LINK_ACTION_ID,
694
+ text: {
695
+ type: "plain_text",
696
+ text: "Open in OpenClaw"
697
+ },
698
+ url: params.sessionUrl
699
+ }]
898
700
  });
899
- const delta = next.changed ? next.rendered.slice(previous?.rendered.length ?? 0) : void 0;
900
- return {
901
- field: {
902
- rendered: next.rendered,
903
- source: next.source
904
- },
905
- delta
906
- };
701
+ return blocks.slice(0, 50);
907
702
  }
703
+ const EMPTY_SLACK_NATIVE_STREAM_SNAPSHOT = { tasks: /* @__PURE__ */ new Map() };
908
704
  /**
909
705
  * Turns a full task snapshot into the delta Slack must receive. Native streams
910
706
  * key rows by persistent id with no removal chunk: unchanged rows are omitted,
911
- * changed rows carry only their unsent field text, and rows that dropped out
912
- * (plan shrinks, tool-line <-> plan source switches) get a final complete
707
+ * changed titles/statuses replace in place, and rows that dropped out
708
+ * (plan shrinks, summary <-> plan source switches) get a final complete
913
709
  * update or they linger in_progress forever.
914
710
  */
915
711
  function reconcileSlackNativeTaskChunks(params) {
@@ -930,26 +726,20 @@ function reconcileSlackNativeTaskChunks(params) {
930
726
  }
931
727
  const previousRow = params.previous.tasks.get(chunk.id);
932
728
  const status = chunk.status;
933
- const details = resolveTaskFieldDelta(previousRow?.details, chunk.details);
934
- const output = resolveTaskFieldDelta(previousRow?.output, chunk.output);
935
729
  const sourcesChanged = Boolean(chunk.sources) && !previousRow?.sourcesSent;
936
730
  const row = {
937
731
  title: chunk.title,
938
732
  status
939
733
  };
940
- if (details.field) row.details = details.field;
941
- if (output.field) row.output = output.field;
942
734
  if (sourcesChanged || previousRow?.sourcesSent) row.sourcesSent = true;
943
735
  nextTasks.set(chunk.id, row);
944
- if (!(!previousRow || previousRow.title !== chunk.title || previousRow.status !== status || Boolean(details.delta) || Boolean(output.delta) || sourcesChanged)) continue;
736
+ if (!(!previousRow || previousRow.title !== chunk.title || previousRow.status !== status || sourcesChanged)) continue;
945
737
  const update = {
946
738
  type: "task_update",
947
739
  id: chunk.id,
948
740
  title: chunk.title,
949
741
  status
950
742
  };
951
- if (details.delta) update.details = details.delta;
952
- if (output.delta) update.output = output.delta;
953
743
  if (sourcesChanged) update.sources = chunk.sources;
954
744
  emitted.push(update);
955
745
  }
@@ -978,40 +768,63 @@ function reconcileSlackNativeTaskChunks(params) {
978
768
  }
979
769
  };
980
770
  }
981
- function buildSlackProgressStreamCompletionChunks(params) {
982
- return buildSlackProgressStreamChunks({
983
- ...params,
984
- completeInProgress: true
985
- });
986
- }
987
771
  //#endregion
988
- //#region extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
989
- function resolveStructuredProgressLines(lines) {
990
- return lines.map((line) => {
991
- if (typeof line !== "string") return line;
992
- const reasoning = line.startsWith("🧠 ");
993
- const text = line.replace(/^(?:🧠|💬)\s+/u, "").replace(/^_(.*)_$/su, "$1").trim();
772
+ //#region extensions/slack/src/stream-mode.ts
773
+ function resolveSlackStreamingConfig(params) {
774
+ return {
775
+ mode: resolveSlackStreamingMode(params),
776
+ nativeStreaming: resolveSlackNativeStreaming(params)
777
+ };
778
+ }
779
+ function applyAppendOnlyStreamUpdate(params) {
780
+ const incoming = params.incoming.trimEnd();
781
+ if (!incoming) return {
782
+ rendered: params.rendered,
783
+ source: params.source,
784
+ changed: false
785
+ };
786
+ if (!params.rendered) return {
787
+ rendered: incoming,
788
+ source: incoming,
789
+ changed: true
790
+ };
791
+ if (incoming === params.source) return {
792
+ rendered: params.rendered,
793
+ source: params.source,
794
+ changed: false
795
+ };
796
+ if (incoming.startsWith(params.rendered)) return {
797
+ rendered: incoming,
798
+ source: incoming,
799
+ changed: incoming !== params.rendered
800
+ };
801
+ if (incoming.startsWith(params.source)) {
802
+ const delta = incoming.slice(params.source.length);
994
803
  return {
995
- ...reasoning ? { id: "reasoning" } : {},
996
- kind: "item",
997
- text,
998
- label: reasoning ? "Reasoning" : "Update",
999
- prefix: false
804
+ rendered: `${params.rendered}${delta}`,
805
+ source: incoming,
806
+ changed: delta.length > 0
1000
807
  };
1001
- });
808
+ }
809
+ if (params.source.startsWith(incoming)) return {
810
+ rendered: params.rendered,
811
+ source: params.source,
812
+ changed: false
813
+ };
814
+ const separator = params.separator ?? (params.rendered.endsWith("\n") ? "" : "\n");
815
+ return {
816
+ rendered: `${params.rendered}${separator}${incoming}`,
817
+ source: incoming,
818
+ changed: true
819
+ };
1002
820
  }
1003
- function resolveNativeProgressPlan(snapshot) {
1004
- return snapshot.plan?.length ? snapshot.plan : void 0;
821
+ //#endregion
822
+ //#region extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
823
+ function resolveStructuredProgressLines(lines) {
824
+ return lines.filter((line) => typeof line !== "string");
1005
825
  }
1006
826
  function resolveNativeProgressLines(snapshot) {
1007
- const lines = resolveStructuredProgressLines(snapshot.lines).filter((line) => line.id !== "reasoning" && line.id?.startsWith("commentary:") !== true);
1008
- if (snapshot.plan?.length || !snapshot.planExplanation) return lines;
1009
- const explanationLine = buildChannelProgressDraftLine({
1010
- event: "plan",
1011
- phase: "update",
1012
- explanation: snapshot.planExplanation
1013
- });
1014
- return explanationLine ? [...lines, explanationLine] : lines;
827
+ return resolveStructuredProgressLines(snapshot.lines).filter((line) => line.id !== "reasoning" && line.id?.startsWith("commentary:") !== true);
1015
828
  }
1016
829
  function resolveNativeProgressNarration(snapshot) {
1017
830
  const paragraphs = resolveStructuredProgressLines(snapshot.lines).filter((line) => line.id === "reasoning" || line.id?.startsWith("commentary:") === true).map((line) => line.text.trim()).filter((text, index, values) => Boolean(text) && values.indexOf(text) === index);
@@ -1020,14 +833,6 @@ function resolveNativeProgressNarration(snapshot) {
1020
833
  function combineProgressHeadlineAndExplanation(headline, explanation) {
1021
834
  return headline && explanation && headline !== explanation ? `${headline} — ${explanation}` : headline ?? explanation;
1022
835
  }
1023
- function buildNativeProgressChunks(params) {
1024
- return buildSlackProgressStreamChunks({
1025
- title: params.title,
1026
- lines: resolveNativeProgressLines(params.snapshot),
1027
- plan: resolveNativeProgressPlan(params.snapshot),
1028
- maxLineChars: params.maxLineChars
1029
- });
1030
- }
1031
836
  //#endregion
1032
837
  //#region extensions/slack/src/monitor/message-handler/preview-finalize.ts
1033
838
  function buildExpectedSlackEditText(params) {
@@ -1065,7 +870,8 @@ function blocksMatch(expected, actual) {
1065
870
  const fallbackBlocks = fallbackPlan.fallbackMessages.flatMap((message) => message.blocks ?? []);
1066
871
  if (JSON.stringify(fallbackBlocks) === JSON.stringify(actual)) return true;
1067
872
  const fallbackText = fallbackPlan.fallbackMessages.map((message) => message.text).filter(Boolean).join("\n\n");
1068
- return normalizeSlackOutboundText(buildSlackBlocksFallbackText(actual)) === normalizeSlackOutboundText(fallbackText);
873
+ const actualText = buildSlackBlocksFallbackText(actual);
874
+ return normalizeSlackOutboundText(actualText) === normalizeSlackOutboundText(fallbackText);
1069
875
  } catch {
1070
876
  return false;
1071
877
  }
@@ -1156,6 +962,7 @@ function createSlackDraftProgressCardRuntime(params) {
1156
962
  return url.toString();
1157
963
  };
1158
964
  const resolveText = (snapshot) => latestFallbackText || formatChannelProgressDraftText({
965
+ presentation: "summary",
1159
966
  entry: account.config,
1160
967
  lines: [...snapshot.lines],
1161
968
  seed: params.progressSeed,
@@ -1172,11 +979,7 @@ function createSlackDraftProgressCardRuntime(params) {
1172
979
  plan: snapshot.plan,
1173
980
  lines: resolveStructuredProgressLines(snapshot.lines),
1174
981
  maxLineChars: params.maxLineChars,
1175
- diffStat: snapshot.diffStat,
1176
- ...state === "working" ? {
1177
- toolCalls: params.progressWorkCounter.toolCalls,
1178
- elapsedSeconds: params.progressWorkCounter.elapsedSeconds
1179
- } : { sessionUrl: resolveSessionUrl() }
982
+ ...state !== "working" ? { sessionUrl: resolveSessionUrl() } : {}
1180
983
  });
1181
984
  };
1182
985
  const finalize = async (status, snapshot = params.getSnapshot(), fallbackText = resolveText(snapshot)) => {
@@ -1336,7 +1139,7 @@ function createSlackProgressRuntime(runtimeParams) {
1336
1139
  log: logVerbose,
1337
1140
  warn: logVerbose
1338
1141
  }) : void 0;
1339
- let hasStreamedMessage = false;
1142
+ let hasStreamedAnswer = false;
1340
1143
  const isProgressMode = slackStreaming.mode === "progress";
1341
1144
  const useNativeProgressStreaming = useStreaming && slackStreaming.mode === "progress";
1342
1145
  const progressDraftActive = Boolean(draftStream) || useNativeProgressStreaming;
@@ -1362,7 +1165,6 @@ function createSlackProgressRuntime(runtimeParams) {
1362
1165
  nativeStreamOrder = run.catch(() => void 0);
1363
1166
  return run;
1364
1167
  };
1365
- const progressWorkCounter = createChannelProgressWorkCounter();
1366
1168
  const progressSeed = `${account.accountId}:${message.channel}`;
1367
1169
  const slackProgressStyle = resolveSlackProgressStyle(account.config);
1368
1170
  const useDraftProgressCard = Boolean(draftStream) && isProgressMode && slackProgressStyle === "card";
@@ -1378,7 +1180,6 @@ function createSlackProgressRuntime(runtimeParams) {
1378
1180
  },
1379
1181
  draftStream,
1380
1182
  enabled: useDraftProgressCard,
1381
- progressWorkCounter,
1382
1183
  progressSeed,
1383
1184
  explicitTitle: explicitProgressTitle,
1384
1185
  maxLineChars: progressDraftMaxLineChars,
@@ -1398,12 +1199,17 @@ function createSlackProgressRuntime(runtimeParams) {
1398
1199
  if (isError) nativeProgressTerminalStatus = "error";
1399
1200
  if (!session || nativeProgressCompletionSent) return;
1400
1201
  const chunks = buildNativeProgressCompletionChunks(isError ? "error" : "complete");
1401
- if (!chunks?.length) return;
1202
+ const narrationUpdate = resolveNarrationUpdate(resolveNativeProgressNarration(progressDraft.getSnapshot()));
1203
+ if (!chunks?.length && !narrationUpdate.delta) return;
1402
1204
  try {
1403
1205
  await appendSlackStream({
1404
1206
  session,
1405
1207
  chunks
1406
1208
  });
1209
+ if (narrationUpdate.next.changed) {
1210
+ nativeNarrationRenderedText = narrationUpdate.next.rendered;
1211
+ nativeNarrationSourceText = narrationUpdate.next.source;
1212
+ }
1407
1213
  nativeProgressCompletionSent = true;
1408
1214
  delivery.observedReplyDelivery ||= session.delivered;
1409
1215
  } catch (err) {
@@ -1412,11 +1218,6 @@ function createSlackProgressRuntime(runtimeParams) {
1412
1218
  }
1413
1219
  };
1414
1220
  const resolveNativeProgressTitle = (snapshot) => combineProgressHeadlineAndExplanation(explicitProgressTitle ?? snapshot.statusHeadline, snapshot.planExplanation);
1415
- const buildNativeProgressChunks$1 = (snapshot) => buildNativeProgressChunks({
1416
- snapshot,
1417
- title: resolveNativeProgressTitle(snapshot),
1418
- maxLineChars: progressDraftMaxLineChars
1419
- });
1420
1221
  const normalizeProgressText = (text) => text?.replace(/\s+/gu, " ").trim() ?? "";
1421
1222
  const isRenderedAsProgressTitle = (text) => {
1422
1223
  const candidate = normalizeProgressText(text);
@@ -1435,17 +1236,18 @@ function createSlackProgressRuntime(runtimeParams) {
1435
1236
  delta: next.changed ? next.rendered.slice(nativeNarrationRenderedText.length) : ""
1436
1237
  };
1437
1238
  };
1438
- const updateNativeProgressStream = () => withNativeStreamOrder(updateNativeProgressStreamNow);
1439
1239
  const updateNativeProgressStreamNow = async () => {
1440
1240
  const snapshot = progressDraft.getSnapshot();
1441
- const progressLines = resolveNativeProgressLines(snapshot);
1442
1241
  const narrationUpdate = resolveNarrationUpdate(resolveNativeProgressNarration(snapshot));
1443
- const hasRetirableNativeTasks = [...nativeStreamSnapshot.tasks.values()].some((task) => task.status !== "complete" && task.status !== "error");
1444
- if (!useNativeProgressStreaming || delivery.streamFailed || progressLines.length === 0 && !snapshot.plan?.length && !snapshot.statusHeadline && !explicitProgressTitle && !hasRetirableNativeTasks && !narrationUpdate.delta) return false;
1242
+ if (!useNativeProgressStreaming || delivery.streamFailed || nativeUpdatesStopped) return false;
1445
1243
  if (!await nativeTransport.waitForStart()) return false;
1446
1244
  const reconciled = reconcileSlackNativeTaskChunks({
1447
1245
  previous: nativeStreamSnapshot,
1448
- chunks: buildNativeProgressChunks$1(snapshot)
1246
+ chunks: buildSlackProgressStreamChunks({
1247
+ title: resolveNativeProgressTitle(snapshot) ?? "Working",
1248
+ lines: resolveNativeProgressLines(snapshot),
1249
+ plan: snapshot.plan
1250
+ })
1449
1251
  });
1450
1252
  const chunks = reconciled.chunks;
1451
1253
  if (!chunks?.length && !narrationUpdate.delta) return false;
@@ -1469,6 +1271,21 @@ function createSlackProgressRuntime(runtimeParams) {
1469
1271
  return false;
1470
1272
  }
1471
1273
  };
1274
+ let nativeUpdatesStopped = false;
1275
+ const nativeUpdates = createDraftStreamLoop({
1276
+ throttleMs: 1e3,
1277
+ coalesceInFlight: true,
1278
+ emptyValue: false,
1279
+ isEmpty: (pending) => !pending,
1280
+ isStopped: () => nativeUpdatesStopped,
1281
+ sendOrEditStreamMessage: () => withNativeStreamOrder(updateNativeProgressStreamNow),
1282
+ onBackgroundFlushError: (err) => runtime.error?.(danger(`slack-stream: progress update failed: ${formatSlackError(err)}`))
1283
+ });
1284
+ const cancelNativeUpdates = async () => {
1285
+ nativeUpdatesStopped = true;
1286
+ nativeUpdates.stop();
1287
+ await nativeUpdates.waitForInFlight();
1288
+ };
1472
1289
  const appendNativeNarration = (payload, kind) => withNativeStreamOrder(() => appendNativeNarrationNow(payload, kind));
1473
1290
  const appendNativeNarrationNow = async (payload, kind) => {
1474
1291
  if (isRenderedAsProgressTitle(payload.text)) return false;
@@ -1488,24 +1305,28 @@ function createSlackProgressRuntime(runtimeParams) {
1488
1305
  return true;
1489
1306
  };
1490
1307
  const resetProgressTurnState = () => {
1491
- progressWorkCounter.reset();
1492
1308
  nativeNarrationRenderedText = "";
1493
1309
  nativeNarrationSourceText = "";
1494
1310
  };
1495
1311
  const progressDraft = createChannelProgressDraftCompositor({
1312
+ presentation: isProgressMode ? "summary" : void 0,
1496
1313
  entry: account.config,
1497
1314
  mode: slackStreaming.mode,
1498
1315
  active: progressDraftActive,
1499
1316
  seed: progressSeed,
1500
1317
  formatLine: formatSlackProgressDraftLine,
1501
1318
  reasoningLinePrefix: "🧠 ",
1502
- commentaryLinePrefix: "",
1503
1319
  reasoningGate: previewToolProgressEnabled,
1504
- commentaryItalics: true,
1505
- buildProgressEventLine: (input, options) => input.event === "tool" || input.event === "item" || input.event === "command-output" ? buildChannelProgressDraftLineForEntry(account.config, input, options) : buildChannelProgressDraftLine(input, options),
1506
1320
  updateOnLineChange: useNativeProgressStreaming || useDraftProgressCard,
1507
1321
  update: async (previewText, options) => {
1508
- if (useNativeProgressStreaming) return await updateNativeProgressStream();
1322
+ if (useNativeProgressStreaming) {
1323
+ const priorSnapshot = nativeStreamSnapshot;
1324
+ const priorNarration = nativeNarrationRenderedText;
1325
+ nativeUpdates.update(true);
1326
+ if (options?.flush) await nativeUpdates.flush();
1327
+ else await nativeUpdates.waitForInFlight();
1328
+ return priorSnapshot !== nativeStreamSnapshot || priorNarration !== nativeNarrationRenderedText;
1329
+ }
1509
1330
  if (!draftStream) return false;
1510
1331
  const snapshot = progressDraft.getSnapshot();
1511
1332
  progressCard.setFallbackText(previewText);
@@ -1513,13 +1334,16 @@ function createSlackProgressRuntime(runtimeParams) {
1513
1334
  text: previewText,
1514
1335
  blocks: progressCard.resolvePresentation(snapshot, "working")
1515
1336
  } : previewText);
1516
- hasStreamedMessage = true;
1517
1337
  if (options?.flush) await draftStream.flush();
1518
1338
  return Boolean(draftStream.messageId() && draftStream.channelId());
1519
1339
  }
1520
1340
  });
1521
1341
  const commentaryProgressEnabled = progressDraft.commentaryProgressEnabled;
1522
- const deliverNativeFinal = (payload, kind) => withNativeStreamOrder(() => deliverNativeFinalNow(payload, kind));
1342
+ const deliverNativeFinal = async (payload, kind) => {
1343
+ progressDraft.markFinalReplyStarted();
1344
+ await cancelNativeUpdates();
1345
+ await withNativeStreamOrder(() => deliverNativeFinalNow(payload, kind));
1346
+ };
1523
1347
  const deliverNativeFinalNow = async (payload, kind) => {
1524
1348
  progressDraft.markFinalReplyStarted();
1525
1349
  const streamReady = await nativeTransport.waitForStart();
@@ -1544,20 +1368,23 @@ function createSlackProgressRuntime(runtimeParams) {
1544
1368
  const snapshot = progressDraft.getSnapshot();
1545
1369
  const lines = resolveNativeProgressLines(snapshot);
1546
1370
  const sessionUrl = progressCard.resolveSessionUrl();
1371
+ const narrationUpdate = resolveNarrationUpdate(resolveNativeProgressNarration(snapshot));
1547
1372
  const hasRetirableNativeTasks = [...nativeStreamSnapshot.tasks.values()].some((task) => task.status !== "complete" && task.status !== "error");
1548
- if (lines.length === 0 && !snapshot.plan?.length && !hasRetirableNativeTasks && !snapshot.diffStat && !sessionUrl) return;
1549
- return reconcileSlackNativeTaskChunks({
1373
+ if (lines.length === 0 && !snapshot.plan?.length && !hasRetirableNativeTasks && !narrationUpdate.delta && !sessionUrl) return;
1374
+ const completion = reconcileSlackNativeTaskChunks({
1550
1375
  previous: nativeStreamSnapshot,
1551
- chunks: buildSlackProgressStreamCompletionChunks({
1376
+ chunks: buildSlackProgressStreamChunks({
1552
1377
  title: resolveNativeProgressTitle(snapshot) ?? (lines.length === 0 && !snapshot.plan?.length ? "Working" : void 0),
1553
1378
  lines,
1554
- plan: resolveNativeProgressPlan(snapshot),
1555
- maxLineChars: progressDraftMaxLineChars,
1379
+ plan: snapshot.plan,
1556
1380
  finalInProgressStatus,
1557
- diffStat: snapshot.diffStat,
1558
1381
  sessionUrl
1559
1382
  })
1560
1383
  }).chunks;
1384
+ return narrationUpdate.delta ? [{
1385
+ type: "markdown_text",
1386
+ text: narrationUpdate.delta
1387
+ }, ...completion ?? []] : completion;
1561
1388
  };
1562
1389
  const finishNativeProgressTurn = async (completionChunks) => {
1563
1390
  if (delivery.nativeProgressStreamStartPromise) await delivery.nativeProgressStreamStartPromise.catch(() => null);
@@ -1595,10 +1422,7 @@ function createSlackProgressRuntime(runtimeParams) {
1595
1422
  narration: explanation,
1596
1423
  plan: steps
1597
1424
  });
1598
- if (text) {
1599
- draftStream.update(text);
1600
- hasStreamedMessage = true;
1601
- }
1425
+ if (text) draftStream.update(text);
1602
1426
  return false;
1603
1427
  };
1604
1428
  const pushPreviewProgress = async (line, options) => {
@@ -1613,7 +1437,7 @@ function createSlackProgressRuntime(runtimeParams) {
1613
1437
  return await progressDraft.pushToolProgress(line, options);
1614
1438
  };
1615
1439
  const updateDraftFromPartial = (text) => {
1616
- const trimmed = text?.trimEnd();
1440
+ const trimmed = text && sanitizeAssistantVisibleText(text).trimEnd();
1617
1441
  if (!trimmed) return false;
1618
1442
  if (slackStreaming.mode === "block") {
1619
1443
  previewToolProgressSuppressed = true;
@@ -1627,14 +1451,14 @@ function createSlackProgressRuntime(runtimeParams) {
1627
1451
  appendSourceText = next.source;
1628
1452
  if (!next.changed) return false;
1629
1453
  draftStream?.update(next.rendered);
1630
- hasStreamedMessage = true;
1454
+ hasStreamedAnswer = true;
1631
1455
  return false;
1632
1456
  }
1633
1457
  if (isProgressMode) return false;
1634
1458
  previewToolProgressSuppressed = true;
1635
1459
  progressDraft.suppress();
1636
1460
  draftStream?.update(trimmed);
1637
- hasStreamedMessage = true;
1461
+ hasStreamedAnswer = true;
1638
1462
  return false;
1639
1463
  };
1640
1464
  const pushReasoningProgress = async (payload) => {
@@ -1654,7 +1478,7 @@ function createSlackProgressRuntime(runtimeParams) {
1654
1478
  return await progressDraft.pushReasoningProgress(payload.text, { snapshot: payload.isReasoningSnapshot === true });
1655
1479
  };
1656
1480
  const resetDraftDeliveryState = () => {
1657
- hasStreamedMessage = false;
1481
+ hasStreamedAnswer = false;
1658
1482
  appendRenderedText = "";
1659
1483
  appendSourceText = "";
1660
1484
  };
@@ -1663,6 +1487,10 @@ function createSlackProgressRuntime(runtimeParams) {
1663
1487
  progressDraft.reset();
1664
1488
  };
1665
1489
  const beginNewProgressTurn = async (options) => {
1490
+ if (useNativeProgressStreaming) {
1491
+ if (!nativeUpdatesStopped && options?.force !== true) return false;
1492
+ await cancelNativeUpdates();
1493
+ }
1666
1494
  const priorSnapshot = progressDraft.getSnapshot();
1667
1495
  const priorFallbackText = progressCard.resolveText(priorSnapshot);
1668
1496
  const completionChunks = useNativeProgressStreaming && !nativeProgressCompletionSent ? buildNativeProgressCompletionChunks(nativeProgressTerminalStatus) : void 0;
@@ -1677,6 +1505,8 @@ function createSlackProgressRuntime(runtimeParams) {
1677
1505
  nativeStreamSnapshot = EMPTY_SLACK_NATIVE_STREAM_SNAPSHOT;
1678
1506
  nativeProgressCompletionSent = false;
1679
1507
  nativeProgressTerminalStatus = "complete";
1508
+ nativeUpdatesStopped = false;
1509
+ nativeUpdates.resetThrottleWindow();
1680
1510
  progressCard.reset();
1681
1511
  resetPreviewDeliveryState();
1682
1512
  delivery.resetDeliveryTracker();
@@ -1687,7 +1517,7 @@ function createSlackProgressRuntime(runtimeParams) {
1687
1517
  await beginNewProgressTurn();
1688
1518
  return;
1689
1519
  }
1690
- if (hasStreamedMessage) draftStream?.forceNewMessage();
1520
+ if (hasStreamedAnswer) draftStream?.forceNewMessage();
1691
1521
  resetDraftDeliveryState();
1692
1522
  resetDraftProgressState();
1693
1523
  };
@@ -1700,7 +1530,14 @@ function createSlackProgressRuntime(runtimeParams) {
1700
1530
  resetDraftDeliveryState();
1701
1531
  resetDraftProgressState();
1702
1532
  };
1703
- const onQueuedFollowupSettled = !useDraftProgressCard ? void 0 : async () => {
1533
+ const onQueuedFollowupSettled = !useDraftProgressCard && !useNativeProgressStreaming ? void 0 : async () => {
1534
+ if (useNativeProgressStreaming) {
1535
+ progressDraft.markFinalReplyStarted();
1536
+ await cancelNativeUpdates();
1537
+ await finishNativeProgressTurn(nativeProgressCompletionSent ? void 0 : buildNativeProgressCompletionChunks(nativeProgressTerminalStatus));
1538
+ progressDraft.markFinalReplyDelivered();
1539
+ return;
1540
+ }
1704
1541
  if (!progressCard.hasTerminalized) await draftStream?.clear();
1705
1542
  await dropDetachedProgressCards();
1706
1543
  };
@@ -1714,7 +1551,10 @@ function createSlackProgressRuntime(runtimeParams) {
1714
1551
  suppressDefaultToolProgressMessages,
1715
1552
  progressDraft,
1716
1553
  commentaryProgressEnabled,
1717
- progressWorkCounter,
1554
+ async cancel() {
1555
+ progressDraft.cancel();
1556
+ await cancelNativeUpdates();
1557
+ },
1718
1558
  get nativeProgressCompletionSent() {
1719
1559
  return nativeProgressCompletionSent;
1720
1560
  },
@@ -1742,41 +1582,6 @@ function createSlackProgressRuntime(runtimeParams) {
1742
1582
  };
1743
1583
  }
1744
1584
  //#endregion
1745
- //#region extensions/slack/src/threading.ts
1746
- function resolveSlackThreadContext(params) {
1747
- const incomingThreadTs = params.message.thread_ts;
1748
- const eventTs = params.message.event_ts;
1749
- const messageTs = params.message.ts ?? eventTs;
1750
- const hasThreadTs = typeof incomingThreadTs === "string" && incomingThreadTs.length > 0;
1751
- const isThreadReply = hasThreadTs && (incomingThreadTs !== messageTs || Boolean(params.message.parent_user_id));
1752
- const replyToId = isThreadReply ? incomingThreadTs : void 0;
1753
- const isAssistantDmThreadRoot = hasThreadTs && !isThreadReply && params.isDirectMessage === true;
1754
- return {
1755
- incomingThreadTs,
1756
- messageTs,
1757
- isThreadReply,
1758
- replyToId,
1759
- messageThreadId: isThreadReply || isAssistantDmThreadRoot ? incomingThreadTs : params.replyToMode === "all" ? messageTs : void 0
1760
- };
1761
- }
1762
- /**
1763
- * Resolves Slack thread targeting for replies and status indicators.
1764
- *
1765
- * @returns replyThreadTs - Thread timestamp for reply messages
1766
- * @returns statusThreadTs - Thread timestamp for status indicators (typing, etc.)
1767
- * @returns isThreadReply - true if this is a genuine user reply in a thread,
1768
- * false if thread_ts comes from a bot status message (e.g. typing indicator)
1769
- */
1770
- function resolveSlackThreadTargets(params) {
1771
- const { incomingThreadTs, messageTs, isThreadReply } = resolveSlackThreadContext(params);
1772
- const replyThreadTs = isThreadReply ? incomingThreadTs : params.replyToMode === "all" ? messageTs : void 0;
1773
- return {
1774
- replyThreadTs,
1775
- statusThreadTs: replyThreadTs,
1776
- isThreadReply
1777
- };
1778
- }
1779
- //#endregion
1780
1585
  //#region extensions/slack/src/monitor/message-handler/dispatch-setup.ts
1781
1586
  async function createSlackDispatchSetup(prepared) {
1782
1587
  const { ctx, account, message, route } = prepared;
@@ -1854,24 +1659,17 @@ async function createSlackDispatchSetup(prepared) {
1854
1659
  await reactSlackMessage(message.channel, reactionMessageTs ?? "", emoji, {
1855
1660
  token: ctx.botToken,
1856
1661
  client: slackClient
1857
- }).catch((err) => {
1858
- if (formatErrorMessage(err).includes("already_reacted")) return;
1859
- throw err;
1860
1662
  });
1861
1663
  },
1862
1664
  removeReaction: async (emoji) => {
1863
1665
  await removeSlackReaction(message.channel, reactionMessageTs ?? "", emoji, {
1864
1666
  token: ctx.botToken,
1865
1667
  client: slackClient
1866
- }).catch((err) => {
1867
- if (formatErrorMessage(err).includes("no_reaction")) return;
1868
- throw err;
1869
1668
  });
1870
1669
  }
1871
1670
  },
1872
1671
  initialEmoji: prepared.ackReactionValue || "eyes",
1873
- emojis: void 0,
1874
- timing: DEFAULT_TIMING,
1672
+ presentation: "acknowledgement",
1875
1673
  onError: (err) => {
1876
1674
  logAckFailure({
1877
1675
  log: logVerbose,
@@ -1898,10 +1696,7 @@ async function createSlackDispatchSetup(prepared) {
1898
1696
  agentId: route.agentId,
1899
1697
  channel: "slack",
1900
1698
  accountId: route.accountId,
1901
- transformReplyPayload: (payload) => {
1902
- if (payload.isReasoning === true) return null;
1903
- return payload;
1904
- },
1699
+ transformReplyPayload: sanitizeSlackMonitorReplyPayload,
1905
1700
  typing: {
1906
1701
  start: async () => {
1907
1702
  if (!threadStatusGate.hasVisibleOutput()) {
@@ -2187,7 +1982,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
2187
1982
  }
2188
1983
  };
2189
1984
  const deliverNormally = async (params) => {
2190
- if (params.payload.isReasoning === true) return;
2191
1985
  const replyThreadTs = resolveDeliveryThreadTs(params);
2192
1986
  const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
2193
1987
  if (deliveryTracker.hasDelivered({
@@ -2250,7 +2044,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
2250
2044
  return !state.streamFailed && !reply.hasMedia && renderPlan.mode !== "split" && !plannedBlocks?.length && !readSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
2251
2045
  };
2252
2046
  const deliverWithStreaming = async (params) => {
2253
- if (params.payload.isReasoning === true) return;
2254
2047
  const reply = resolveSendableOutboundReplyParts(params.payload);
2255
2048
  if (!isStreamingEligible(params.payload)) {
2256
2049
  await deliverNormally({
@@ -2452,7 +2245,6 @@ async function dispatchPreparedSlackMessage(prepared) {
2452
2245
  return payload;
2453
2246
  };
2454
2247
  const deliverSlackPayload = async (payload, info) => {
2455
- if (payload.isReasoning === true) return { visibleReplySent: false };
2456
2248
  if (info.kind === "final" && slackStreaming.mode === "progress" && progress.isProgressMode) {
2457
2249
  if (progress.useNativeProgressStreaming) {
2458
2250
  await progress.deliverNativeFinal(payload, info.kind);
@@ -2503,7 +2295,11 @@ async function dispatchPreparedSlackMessage(prepared) {
2503
2295
  const slackBlocks = replyRenderPlan.mode === "single" ? replyRenderPlan.blocks : replyRenderPlan.blockPart?.blocks;
2504
2296
  const requiresSeparateFallbackDelivery = replyRenderPlan.mode === "split";
2505
2297
  const trimmedFinalText = replyRenderPlan.mode === "single" ? replyRenderPlan.text.trim() : replyRenderPlan.fallbackText.trim();
2506
- const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim());
2298
+ const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), { tableMode: resolveMarkdownTableMode({
2299
+ cfg,
2300
+ channel: "slack",
2301
+ accountId: account.accountId
2302
+ }) });
2507
2303
  const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
2508
2304
  const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !draftPreviewCommitted.value && !delivery.observedFinalReplyDelivery && previewStreamingEnabled && !payload.text?.trim();
2509
2305
  let ttsPreviewFinalization;
@@ -2619,6 +2415,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2619
2415
  sessionKey: route.sessionKey
2620
2416
  },
2621
2417
  ctxPayload: prepared.ctxPayload,
2418
+ dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
2622
2419
  dispatcherOptions: {
2623
2420
  ...replyPipeline,
2624
2421
  transformReplyPayload: (payload) => {
@@ -2673,7 +2470,6 @@ async function dispatchPreparedSlackMessage(prepared) {
2673
2470
  } : void 0,
2674
2471
  onToolStart: async (payload) => {
2675
2472
  if (statusReactionsEnabled) await statusReactions.setTool(payload.name);
2676
- if (payload.phase === "start") progress.progressWorkCounter.noteToolCall(payload.name);
2677
2473
  return await progress.progressDraft.pushToolEvent(payload);
2678
2474
  },
2679
2475
  onItemEvent: async (payload) => {
@@ -2715,7 +2511,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2715
2511
  } catch (err) {
2716
2512
  dispatchError = err;
2717
2513
  } finally {
2718
- progress.progressDraft.cancel();
2514
+ await progress.cancel();
2719
2515
  if (!progress.useDraftProgressCard) await draftStream?.discardPending();
2720
2516
  }
2721
2517
  let streamFallbackDelivered = false;
@@ -2748,13 +2544,15 @@ async function dispatchPreparedSlackMessage(prepared) {
2748
2544
  if (pendingFailureNotice && anyReplyDelivered) recordSlackThreadFailureNotice(pendingFailureNotice);
2749
2545
  if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error");
2750
2546
  await progress.dropDetachedProgressCards();
2751
- if (statusReactionsEnabled) if (dispatchError || agentRunFailed) {
2752
- await statusReactions.setError();
2753
- statusReactions.restoreInitial();
2754
- } else if (anyReplyDelivered) {
2755
- await statusReactions.setDone();
2756
- statusReactions.restoreInitial();
2757
- } else await statusReactions.restoreInitial();
2547
+ if (statusReactionsEnabled) {
2548
+ if (dispatchError || agentRunFailed) {
2549
+ await statusReactions.setError();
2550
+ statusReactions.restoreInitial();
2551
+ } else if (anyReplyDelivered) {
2552
+ await statusReactions.setDone();
2553
+ statusReactions.restoreInitial();
2554
+ } else await statusReactions.restoreInitial();
2555
+ }
2758
2556
  const participationThreadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
2759
2557
  if (anyReplyDelivered && participationThreadTs) recordSlackThreadParticipation(account.accountId, message.channel, participationThreadTs, {
2760
2558
  agentId: route.agentId,
@@ -2813,7 +2611,7 @@ function normalizeSlackAppContextEntities(value) {
2813
2611
  //#endregion
2814
2612
  //#region extensions/slack/src/monitor/thread.ts
2815
2613
  const THREAD_STARTER_CACHE = /* @__PURE__ */ new Map();
2816
- const THREAD_STARTER_CACHE_TTL_MS = 360 * 6e4;
2614
+ const THREAD_STARTER_CACHE_TTL_MS = 216e5;
2817
2615
  const THREAD_STARTER_CACHE_MAX = 2e3;
2818
2616
  function evictThreadStarterCache() {
2819
2617
  const now = asDateTimestampMs(Date.now());
@@ -3008,7 +2806,24 @@ async function discardSlackPreflightMedia(media) {
3008
2806
  const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
3009
2807
  const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
3010
2808
  const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
3011
- const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-DFk0ANVB.js").then((n) => n._));
2809
+ const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
2810
+ const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-BOxiu2Vy.js").then((n) => n._));
2811
+ function formatSlackUnavailableMedia(params) {
2812
+ let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
2813
+ if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
2814
+ const fileBlock = fileReferences ? `[Slack file: ${fileReferences}]` : void 0;
2815
+ const body = [params.body, fileBlock].filter(Boolean).join("\n");
2816
+ if (params.unavailableMediaCount === 0) return body;
2817
+ const notice = `[slack ${params.unavailableMediaCount > 1 ? `${params.unavailableMediaCount} attachments` : "attachment"} unavailable]`;
2818
+ return params.prependUnavailable ? [
2819
+ notice,
2820
+ fileBlock,
2821
+ params.body
2822
+ ].filter(Boolean).join("\n") : formatInboundMediaUnavailableText({
2823
+ body,
2824
+ notice
2825
+ });
2826
+ }
3012
2827
  function collectUniqueSlackMentionIds$1(texts) {
3013
2828
  const seen = /* @__PURE__ */ new Set();
3014
2829
  const mentionIds = [];
@@ -3046,8 +2861,9 @@ async function resolveSlackMessageContent(params) {
3046
2861
  isThreadReply: params.isThreadReply,
3047
2862
  threadStarter: params.threadStarter
3048
2863
  });
3049
- const mediaPromise = ownFiles && ownFiles.length > 0 ? loadSlackMediaModule$1().then(({ resolveSlackMedia }) => resolveSlackMedia({
2864
+ const attachmentContent = ownFiles?.length || params.message.attachments?.length ? await loadSlackMediaModule$1().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
3050
2865
  files: ownFiles,
2866
+ attachments: params.message.attachments,
3051
2867
  client: params.client,
3052
2868
  token: params.botToken,
3053
2869
  maxBytes: params.mediaMaxBytes,
@@ -3055,30 +2871,9 @@ async function resolveSlackMessageContent(params) {
3055
2871
  totalTimeoutMs: params.mediaTotalTimeoutMs,
3056
2872
  abortSignal: params.abortSignal,
3057
2873
  preloadedMedia: params.preloadedMedia
3058
- })) : Promise.resolve(null);
3059
- const attachmentContentPromise = params.message.attachments && params.message.attachments.length > 0 ? loadSlackMediaModule$1().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
3060
- attachments: params.message.attachments,
3061
- client: params.client,
3062
- token: params.botToken,
3063
- maxBytes: params.mediaMaxBytes,
3064
- readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
3065
- totalTimeoutMs: params.mediaTotalTimeoutMs,
3066
- abortSignal: params.abortSignal
3067
- })) : Promise.resolve(null);
3068
- const [media, attachmentContent] = await Promise.all([mediaPromise, attachmentContentPromise]);
3069
- const mergedMedia = [...media ?? [], ...attachmentContent?.media ?? []];
3070
- const effectiveDirectMedia = mergedMedia.length > 0 ? mergedMedia : null;
3071
- const mediaPlaceholder = effectiveDirectMedia ? effectiveDirectMedia.map((item) => item.placeholder).join(" ") : void 0;
3072
- const fallbackFileIds = /* @__PURE__ */ new Set();
3073
- const fallbackFiles = [...ownFiles ?? [], ...attachmentContent?.files ?? []].filter((file) => {
3074
- const fileId = normalizeOptionalString(file.id);
3075
- if (!fileId) return true;
3076
- if (fallbackFileIds.has(fileId)) return false;
3077
- fallbackFileIds.add(fileId);
3078
- return true;
3079
- });
3080
- const fileOnlyFallback = !mediaPlaceholder && fallbackFiles.length > 0 ? fallbackFiles.slice(0, 8).map((file) => formatSlackFileReference(file)).join(", ") : void 0;
3081
- const fileOnlyPlaceholder = fileOnlyFallback ? `[Slack file: ${fileOnlyFallback}]` : void 0;
2874
+ })) : null;
2875
+ const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
2876
+ const mediaPlaceholder = effectiveDirectMedia?.map((item) => item.placeholder).join(" ");
3082
2877
  let botAttachmentText;
3083
2878
  if (params.isBotMessage && !attachmentContent?.text) {
3084
2879
  const botAttachmentTextParts = [];
@@ -3102,7 +2897,8 @@ async function resolveSlackMessageContent(params) {
3102
2897
  if (skippedLookups > 0) logVerbose(`slack: skipping ${skippedLookups} mention lookup(s) beyond per-message cap (${SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE})`);
3103
2898
  const { results } = await runTasksWithConcurrency({
3104
2899
  tasks: lookupIds.map((userId) => async () => {
3105
- const renderedName = normalizeOptionalString((await resolveUserName(userId))?.name);
2900
+ const user = await resolveUserName(userId);
2901
+ const renderedName = normalizeOptionalString(user?.name);
3106
2902
  return {
3107
2903
  userId,
3108
2904
  rendered: renderedName ? `<@${userId}> (${renderedName})` : null
@@ -3115,23 +2911,20 @@ async function resolveSlackMessageContent(params) {
3115
2911
  renderedMentions.set(result.userId, result.rendered);
3116
2912
  }
3117
2913
  }
3118
- let rawBody = [
3119
- renderSlackUserMentions(textParts[0], renderedMentions),
3120
- renderSlackUserMentions(textParts[1], renderedMentions),
3121
- renderSlackUserMentions(textParts[2], renderedMentions),
3122
- mediaPlaceholder,
3123
- fileOnlyPlaceholder
3124
- ].filter(Boolean).join("\n") || "";
3125
- const unavailableImageCount = attachmentContent?.unavailableImageCount ?? 0;
3126
- if (unavailableImageCount > 0) rawBody = formatInboundMediaUnavailableText({
3127
- body: rawBody,
3128
- notice: `[slack ${unavailableImageCount > 1 ? `${unavailableImageCount} forwarded images` : "forwarded image"} unavailable]`
2914
+ const rawBody = formatSlackUnavailableMedia({
2915
+ body: [
2916
+ renderSlackUserMentions(textParts[0], renderedMentions),
2917
+ renderSlackUserMentions(textParts[1], renderedMentions),
2918
+ renderSlackUserMentions(textParts[2], renderedMentions),
2919
+ mediaPlaceholder
2920
+ ].filter(Boolean).join("\n") || "",
2921
+ files: attachmentContent?.files,
2922
+ unavailableMediaCount: attachmentContent?.unavailableMediaCount ?? 0
3129
2923
  });
3130
- if (!rawBody) return null;
3131
- return {
2924
+ return rawBody ? {
3132
2925
  rawBody,
3133
2926
  effectiveDirectMedia
3134
- };
2927
+ } : null;
3135
2928
  }
3136
2929
  //#endregion
3137
2930
  //#region extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
@@ -3208,7 +3001,8 @@ async function resolveSlackDmHistoryContext(params) {
3208
3001
  //#endregion
3209
3002
  //#region extensions/slack/src/monitor/message-handler/prepare-routing.ts
3210
3003
  function resolveSlackBaseConversationId(params) {
3211
- return qualifySlackConversationId(params.isDirectMessage ? `user:${params.message.user ?? "unknown"}` : params.message.channel, params.eventScope);
3004
+ const raw = params.isDirectMessage ? `user:${params.message.user ?? "unknown"}` : params.message.channel;
3005
+ return qualifySlackConversationId(raw, params.eventScope);
3212
3006
  }
3213
3007
  function resolveSlackInitialAgentRoute(params) {
3214
3008
  const route = resolveAgentRoute({
@@ -3359,7 +3153,7 @@ function formatSlackThreadLabelSnippet(text) {
3359
3153
  }
3360
3154
  //#endregion
3361
3155
  //#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
3362
- const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-DFk0ANVB.js").then((n) => n._));
3156
+ const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-BOxiu2Vy.js").then((n) => n._));
3363
3157
  const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
3364
3158
  function resolveSlackThreadSessionFreshness(params) {
3365
3159
  return params.ctx.channelRuntime?.session?.resolveEntryResetFreshness?.({
@@ -3471,14 +3265,24 @@ async function resolveSlackThreadContextData(params) {
3471
3265
  const snippet = formatSlackThreadLabelSnippet(starter.text);
3472
3266
  threadLabel = `Slack thread ${params.roomLabel}${snippet ? `: ${snippet}` : ""}`;
3473
3267
  if (shouldSeedInitialThreadContext && !params.effectiveDirectMedia && starter.files && starter.files.length > 0) {
3474
- const { resolveSlackMedia } = await loadSlackMediaModule();
3475
- threadStarterMedia = await resolveSlackMedia({
3268
+ const { resolveSlackAttachmentContent } = await loadSlackMediaModule();
3269
+ const attachmentContent = await resolveSlackAttachmentContent({
3476
3270
  files: starter.files,
3477
3271
  client: params.eventScope?.client ?? params.ctx.app.client,
3478
3272
  token: params.ctx.botToken,
3479
3273
  maxBytes: params.ctx.mediaMaxBytes
3480
3274
  });
3481
- if (threadStarterMedia) logVerbose(`slack: hydrated thread starter file ${threadStarterMedia.map((item) => item.placeholder).join(", ")} from root message`);
3275
+ threadStarterMedia = attachmentContent?.media.length ? attachmentContent.media : null;
3276
+ if (attachmentContent) threadStarterBody = formatSlackUnavailableMedia({
3277
+ body: threadStarterBody,
3278
+ files: attachmentContent.files,
3279
+ unavailableMediaCount: attachmentContent.unavailableMediaCount,
3280
+ prependUnavailable: true
3281
+ });
3282
+ if (threadStarterMedia) {
3283
+ const starterPlaceholders = threadStarterMedia.map((item) => item.placeholder).join(", ");
3284
+ logVerbose(`slack: hydrated thread starter file ${starterPlaceholders} from root message`);
3285
+ }
3482
3286
  }
3483
3287
  } else threadLabel = `Slack thread ${params.roomLabel}`;
3484
3288
  const includeBotStarterAsRootContext = shouldIncludeBotThreadStarterContext({
@@ -3498,14 +3302,20 @@ async function resolveSlackThreadContextData(params) {
3498
3302
  const threadInitialHistoryLimit = params.account.config?.thread?.initialHistoryLimit ?? 20;
3499
3303
  if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
3500
3304
  const currentBotRootTs = starter?.ts ?? params.threadTs;
3305
+ const threadHistory = await resolveSlackThreadHistory({
3306
+ channelId: params.message.channel,
3307
+ threadTs: params.threadTs,
3308
+ client: params.eventScope?.client ?? params.ctx.app.client,
3309
+ currentMessageTs: params.message.ts,
3310
+ limit: threadInitialHistoryLimit
3311
+ });
3312
+ const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
3313
+ ...starter,
3314
+ text: threadStarterBody,
3315
+ ts: currentBotRootTs
3316
+ } : null;
3501
3317
  const threadHistoryWithBotRoot = ensureSlackThreadHistoryHasBotRoot({
3502
- history: await resolveSlackThreadHistory({
3503
- channelId: params.message.channel,
3504
- threadTs: params.threadTs,
3505
- client: params.eventScope?.client ?? params.ctx.app.client,
3506
- currentMessageTs: params.message.ts,
3507
- limit: threadInitialHistoryLimit
3508
- }),
3318
+ history: enrichedStarter && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [enrichedStarter, ...threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory,
3509
3319
  includeBotStarterAsRootContext,
3510
3320
  threadStarter: starter ? {
3511
3321
  ...starter,
@@ -3564,7 +3374,7 @@ async function resolveSlackThreadContextData(params) {
3564
3374
  });
3565
3375
  const role = isCurrentBot || isOtherBot || Boolean(historyMsg.botId) ? "assistant" : "user";
3566
3376
  const msgSenderName = isCurrentBot ? "Bot (this assistant)" : msgUser?.name ?? (historyMsg.botId ? `Bot (${historyMsg.botId})` : "Unknown");
3567
- const msgWithId = `${historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
3377
+ const msgWithId = `${historyMsg.ts === currentBotRootTs && threadStarterBody ? threadStarterBody : historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
3568
3378
  historyParts.push(formatInboundEnvelope({
3569
3379
  channel: "Slack",
3570
3380
  from: `${msgSenderName} (${role})`,
@@ -3591,7 +3401,7 @@ async function resolveSlackThreadContextData(params) {
3591
3401
  //#endregion
3592
3402
  //#region extensions/slack/src/monitor/message-handler/subteam-mentions.ts
3593
3403
  const SUBTEAM_MENTION_RE = /<!subteam\^([A-Z0-9]+)(?:\|[^>]*)?>/gi;
3594
- const SUBTEAM_MEMBER_CACHE_TTL_MS = 300 * 1e3;
3404
+ const SUBTEAM_MEMBER_CACHE_TTL_MS = 3e5;
3595
3405
  const subteamMemberCache = /* @__PURE__ */ new WeakMap();
3596
3406
  function normalizeSlackId(value) {
3597
3407
  return typeof value === "string" && value.trim() ? value.trim().toUpperCase() : void 0;
@@ -3662,7 +3472,7 @@ const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
3662
3472
  const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
3663
3473
  const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
3664
3474
  const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
3665
- const SLACK_HISTORY_MEDIA_MAX_BYTES = 10 * 1024 * 1024;
3475
+ const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
3666
3476
  const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
3667
3477
  const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
3668
3478
  const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
@@ -3796,7 +3606,7 @@ function buildSlackHistoryMediaCandidateMessage(message) {
3796
3606
  async function resolveSlackHistoryMediaForPendingRecord(params) {
3797
3607
  const mediaMessage = buildSlackHistoryMediaCandidateMessage(params.message);
3798
3608
  if (!mediaMessage) return [];
3799
- return await toInboundMediaFactsWithMetadata((await resolveSlackMessageContent({
3609
+ const content = await resolveSlackMessageContent({
3800
3610
  message: mediaMessage,
3801
3611
  isThreadReply: params.isThreadReply,
3802
3612
  threadStarter: params.threadStarter,
@@ -3806,7 +3616,8 @@ async function resolveSlackHistoryMediaForPendingRecord(params) {
3806
3616
  mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
3807
3617
  mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
3808
3618
  mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS
3809
- }))?.effectiveDirectMedia, {
3619
+ });
3620
+ return await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
3810
3621
  kind: "image",
3811
3622
  messageId: params.message.ts
3812
3623
  });
@@ -3929,7 +3740,8 @@ async function authorizeSlackInboundMessage(params) {
3929
3740
  if (conversation.isRoom && ctx.groupPolicy === "allowlist" && params.explicitBotMention && !isBotMessage && message.user) {
3930
3741
  let subject = "This OpenClaw bot";
3931
3742
  if (ctx.botUserId) try {
3932
- const botName = normalizeOptionalString((await ctx.resolveUserName(ctx.botUserId, params.eventScope))?.name);
3743
+ const botIdentity = await ctx.resolveUserName(ctx.botUserId, params.eventScope);
3744
+ const botName = normalizeOptionalString(botIdentity?.name);
3933
3745
  if (botName) subject = escapeSlackMrkdwn(botName);
3934
3746
  } catch (error) {
3935
3747
  logVerbose(`slack allowlist denial bot-name lookup failed: ${formatSlackError(error)}`);
@@ -4022,7 +3834,8 @@ async function prepareSlackMessage(params) {
4022
3834
  const resolveSenderName = async () => {
4023
3835
  if (resolvedSenderName) return resolvedSenderName;
4024
3836
  if (message.user) {
4025
- const normalized = normalizeOptionalString((await ctx.resolveUserName(message.user, opts.eventScope))?.name);
3837
+ const sender = await ctx.resolveUserName(message.user, opts.eventScope);
3838
+ const normalized = normalizeOptionalString(sender?.name);
4026
3839
  if (normalized) {
4027
3840
  resolvedSenderName = normalized;
4028
3841
  return resolvedSenderName;