@openclaw/slack 2026.10.10-beta.5 → 2026.11.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/dist/.setup/{account-configured-zcR9TJJN.mjs → account-configured-35y0-Hso.mjs} +1 -2
  2. package/dist/.setup/{account-inspect-CmkKiSb9.mjs → account-inspect-DgQgj0wk.mjs} +13 -11
  3. package/dist/.setup/{accounts-msihSF3-.mjs → accounts-EaPP0fFY.mjs} +16 -11
  4. package/dist/.setup/{action-runtime-ChRfnnBu.mjs → action-runtime-CK9QZgQl.mjs} +39 -47
  5. package/dist/.setup/action-runtime.runtime-CpZktret.mjs +1 -0
  6. package/dist/.setup/{actions-By7tvpvv.mjs → actions-s3CcFO45.mjs} +98 -93
  7. package/dist/.setup/{approval-handler.runtime-D8ArtDQt.mjs → approval-handler.runtime-Ch7BecYK.mjs} +27 -32
  8. package/dist/.setup/{approval-message-updates-DT7XBPbV.mjs → approval-message-updates-CqcRoa28.mjs} +2 -3
  9. package/dist/.setup/{channel-6YzXl_63.mjs → channel-CAvo_WNZ.mjs} +573 -352
  10. package/dist/.setup/{channel-meta-C443t-lI.mjs → channel-meta-C5vsCo3a.mjs} +1 -2
  11. package/dist/.setup/{channel-type-BEFP2ORi.mjs → channel-type-9Lw6yLf2.mjs} +6 -11
  12. package/dist/.setup/{channel.setup-u6QQdbTa.mjs → channel.setup-BlgXNuCJ.mjs} +19 -23
  13. package/dist/.setup/{config-schema-DNnh6bWU.mjs → config-schema-Bx1tCZB0.mjs} +5 -11
  14. package/dist/.setup/cursor-pages-jVn3Vkfi.mjs +309 -0
  15. package/dist/.setup/{directory-config-Cjj0N8R0.mjs → directory-config-CGvKYg9F.mjs} +5 -6
  16. package/dist/.setup/{directory-live-BIKD-5B_.mjs → directory-live-DNdw97LA.mjs} +6 -7
  17. package/dist/.setup/{doctor-contract-Cd4-VzIM.mjs → doctor-contract-BB2KJ9Ni.mjs} +44 -58
  18. package/dist/.setup/{message-tool-api-BS5ekEA_.mjs → message-tool-api-B38BpEaE.mjs} +7 -8
  19. package/dist/.setup/{monitor-BFilOuM_.mjs → monitor-BD86SotB.mjs} +3416 -3750
  20. package/dist/.setup/{outbound-adapter-9dbnYtL1.mjs → outbound-adapter-BH6iPWBj.mjs} +32 -39
  21. package/dist/.setup/paths-CQZI_5WY.mjs +7 -0
  22. package/dist/.setup/{pipeline.runtime-BG5swHnj.mjs → pipeline.runtime-C4ELxaRU.mjs} +444 -590
  23. package/dist/.setup/{policy-yhn48xf5.mjs → policy-C6_DdlSf.mjs} +3 -6
  24. package/dist/.setup/{session-status-Dv8wNBEt.mjs → probe-B_Ax1vS1.mjs} +1015 -678
  25. package/dist/.setup/question-delivery-D3qAIwuv.mjs +38 -0
  26. package/dist/.setup/{relay-source-oY9SbDiX.mjs → relay-source-a8jodKuO.mjs} +12 -6
  27. package/dist/.setup/{replies-CJwjTqDr.mjs → replies-Bq7n0gfM.mjs} +37 -24
  28. package/dist/.setup/{reply-blocks-Ca-raz2z.mjs → reply-blocks-DyYYRrP_.mjs} +202 -210
  29. package/dist/.setup/{resolve-channels-DRRhElwz.mjs → resolve-channels-CF2JME9q.mjs} +6 -10
  30. package/dist/.setup/{resolve-users-Cz8e17ky.mjs → resolve-users-DDcCAjH1.mjs} +10 -19
  31. package/dist/.setup/{rolldown-runtime-B4FMCO8f.mjs → rolldown-runtime-nwUcYXjP.mjs} +1 -2
  32. package/dist/.setup/{runtime-JSVZSWAj.mjs → runtime-C6HKn7Av.mjs} +1 -2
  33. package/dist/.setup/runtime-setter-api-DrXr965r.mjs +2 -0
  34. package/dist/.setup/{scopes-DfQVi8Jw.mjs → scopes-CzHC_dwV.mjs} +3 -3
  35. package/dist/.setup/{secret-contract-B-Qm6aQQ.mjs → secret-contract-CqVqR7MP.mjs} +5 -4
  36. package/dist/.setup/{secret-contract-api-DB6CMdgc.mjs → secret-contract-api-DaCXZ47j.mjs} +1 -1
  37. package/dist/.setup/{security-audit-DFGiFLqd.mjs → security-audit-C3hXCfDt.mjs} +2 -3
  38. package/dist/.setup/{send-C-8wY0lK.mjs → send-WJZ73VSf.mjs} +306 -349
  39. package/dist/.setup/{send-results-eeOu_HYm.mjs → send-results-Bm6V1ekL.mjs} +4 -6
  40. package/dist/.setup/setup-plugin-api-DJXIB8CF.mjs +2 -0
  41. package/dist/.setup/{setup-surface-9WVQgYCT.mjs → setup-surface-uIqP2B0Y.mjs} +6 -8
  42. package/dist/.setup/{slash-dispatch.runtime-v5kQqJPh.mjs → slash-dispatch.runtime-Cwuwv7FL.mjs} +2 -2
  43. package/dist/.setup/{target-parsing-FFE26kOV.mjs → target-parsing-DwYAP3ts.mjs} +2 -4
  44. package/dist/.setup/{targets-C6LZQL1Q.mjs → targets-eeOxA_b_.mjs} +2 -3
  45. package/dist/.setup/{thread-ts-Cvt7WD6B.mjs → thread-ts-47Au2-Yn.mjs} +1 -2
  46. package/dist/.source-module-urls/c5ffd0957b234c7c12090e7de4eca2482ef339b8561e078da55b734211b0ba58.json +1 -0
  47. package/dist/account-inspect-api.js +2 -3
  48. package/dist/api.js +17 -18
  49. package/dist/channel-config-api.js +1 -1
  50. package/dist/channel-entry.js +1 -2
  51. package/dist/channel-plugin-api.js +1 -1
  52. package/dist/configured-state.js +2 -3
  53. package/dist/directory-contract-api.js +1 -1
  54. package/dist/doctor-contract-api.js +1 -1
  55. package/dist/index.js +1 -8
  56. package/dist/message-tool-api.js +1 -1
  57. package/dist/runtime-api.js +11 -13
  58. package/dist/runtime-setter-api.js +1 -1
  59. package/dist/secret-contract-api.js +1 -1
  60. package/dist/security-contract-api.js +1 -1
  61. package/dist/setup-entry.js +4 -5
  62. package/dist/setup-plugin-api.js +1 -1
  63. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  64. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  65. package/node_modules/@slack/bolt/node_modules/@types/node/util.d.ts +6 -3
  66. package/node_modules/@slack/bolt/node_modules/content-disposition/README.md +105 -35
  67. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.d.ts +72 -0
  68. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js +388 -0
  69. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js.map +1 -0
  70. package/node_modules/@slack/bolt/node_modules/content-disposition/package.json +31 -19
  71. package/node_modules/@slack/bolt/node_modules/content-type/README.md +34 -57
  72. package/node_modules/@slack/bolt/node_modules/content-type/package.json +35 -25
  73. package/node_modules/@slack/bolt/node_modules/express/Readme.md +15 -9
  74. package/node_modules/@slack/bolt/node_modules/express/lib/application.js +2 -2
  75. package/node_modules/@slack/bolt/node_modules/express/lib/request.js +32 -19
  76. package/node_modules/@slack/bolt/node_modules/express/lib/response.js +27 -30
  77. package/node_modules/@slack/bolt/node_modules/express/package.json +10 -10
  78. package/node_modules/@slack/bolt/node_modules/qs/.github/THREAT_MODEL.md +4 -2
  79. package/node_modules/@slack/bolt/node_modules/qs/CHANGELOG.md +38 -14
  80. package/node_modules/@slack/bolt/node_modules/qs/README.md +31 -3
  81. package/node_modules/@slack/bolt/node_modules/qs/dist/qs.js +20 -20
  82. package/node_modules/@slack/bolt/node_modules/qs/lib/parse.js +94 -4
  83. package/node_modules/@slack/bolt/node_modules/qs/lib/stringify.js +4 -4
  84. package/node_modules/@slack/bolt/node_modules/qs/lib/utils.js +130 -6
  85. package/node_modules/@slack/bolt/node_modules/qs/package.json +4 -4
  86. package/node_modules/@slack/bolt/node_modules/qs/test/parse.js +174 -0
  87. package/node_modules/@slack/bolt/node_modules/qs/test/stringify.js +263 -33
  88. package/node_modules/@slack/bolt/node_modules/qs/test/utils.js +184 -0
  89. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  90. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  91. package/node_modules/@slack/web-api/node_modules/@types/node/util.d.ts +6 -3
  92. package/node_modules/typebox/build/format/duration.d.mts +2 -2
  93. package/node_modules/typebox/build/format/duration.mjs +2 -2
  94. package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
  95. package/node_modules/typebox/build/format/idn_email.mjs +1 -0
  96. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
  97. package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
  98. package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
  99. package/node_modules/typebox/build/format/ipv4.mjs +2 -2
  100. package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
  101. package/node_modules/typebox/build/format/ipv6.mjs +1 -1
  102. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  103. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  104. package/node_modules/typebox/build/schema/build.mjs +1 -0
  105. package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
  106. package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
  107. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
  108. package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
  109. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
  110. package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
  111. package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
  112. package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
  113. package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
  114. package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
  115. package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
  116. package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
  117. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
  118. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
  119. package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
  120. package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
  121. package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
  122. package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
  123. package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
  124. package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
  125. package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
  126. package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
  127. package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
  128. package/node_modules/typebox/build/system/memory/create.mjs +18 -13
  129. package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
  130. package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
  131. package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
  132. package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
  133. package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
  134. package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
  135. package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
  136. package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
  137. package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
  138. package/node_modules/typebox/build/system/memory/update.mjs +43 -16
  139. package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
  140. package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
  141. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
  142. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
  143. package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
  144. package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
  145. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
  146. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
  147. package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
  148. package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
  149. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
  150. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
  151. package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
  152. package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
  153. package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
  154. package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
  155. package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
  156. package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
  157. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
  158. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
  159. package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
  160. package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
  161. package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
  162. package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
  163. package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
  164. package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
  165. package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
  166. package/node_modules/typebox/package.json +1 -1
  167. package/node_modules/typebox/readme.md +1 -1
  168. package/node_modules/undici/README.md +25 -3
  169. package/node_modules/undici/docs/docs/api/CacheStore.md +24 -9
  170. package/node_modules/undici/docs/docs/api/Client.md +11 -6
  171. package/node_modules/undici/docs/docs/api/Dispatcher.md +3 -0
  172. package/node_modules/undici/docs/docs/api/Errors.md +76 -1
  173. package/node_modules/undici/docs/docs/api/H2CClient.md +3 -2
  174. package/node_modules/undici/docs/docs/api/Interceptors.md +28 -8
  175. package/node_modules/undici/docs/docs/api/RedirectHandler.md +13 -10
  176. package/node_modules/undici/docs/docs/index.md +12 -12
  177. package/node_modules/undici/docs/docs/type-map.json +66 -66
  178. package/node_modules/undici/lib/cache/memory-cache-store.js +48 -13
  179. package/node_modules/undici/lib/cache/sqlite-cache-store.js +83 -5
  180. package/node_modules/undici/lib/core/connect.js +10 -4
  181. package/node_modules/undici/lib/core/constants.js +12 -1
  182. package/node_modules/undici/lib/core/errors.js +38 -1
  183. package/node_modules/undici/lib/core/request.js +16 -1
  184. package/node_modules/undici/lib/core/symbols.js +2 -0
  185. package/node_modules/undici/lib/core/util.js +26 -1
  186. package/node_modules/undici/lib/dispatcher/agent.js +6 -2
  187. package/node_modules/undici/lib/dispatcher/client-h1.js +116 -80
  188. package/node_modules/undici/lib/dispatcher/client-h2.js +124 -17
  189. package/node_modules/undici/lib/dispatcher/client.js +4 -1
  190. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +3 -2
  191. package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +20 -3
  192. package/node_modules/undici/lib/dispatcher/parser-h1.js +1064 -0
  193. package/node_modules/undici/lib/dispatcher/pool-base.js +85 -31
  194. package/node_modules/undici/lib/dispatcher/pool.js +11 -8
  195. package/node_modules/undici/lib/dispatcher/proxy-agent.js +18 -8
  196. package/node_modules/undici/lib/dispatcher/retry-agent.js +10 -0
  197. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +15 -5
  198. package/node_modules/undici/lib/handler/cache-handler.js +153 -15
  199. package/node_modules/undici/lib/handler/deduplication-handler.js +112 -51
  200. package/node_modules/undici/lib/handler/redirect-handler.js +28 -8
  201. package/node_modules/undici/lib/handler/retry-handler.js +44 -11
  202. package/node_modules/undici/lib/interceptor/cache.js +11 -3
  203. package/node_modules/undici/lib/interceptor/decompress.js +22 -9
  204. package/node_modules/undici/lib/interceptor/dns.js +11 -0
  205. package/node_modules/undici/lib/interceptor/response-error.js +72 -28
  206. package/node_modules/undici/lib/milo/LICENSE.md +7 -0
  207. package/node_modules/undici/lib/milo/no-simd.js +1002 -0
  208. package/node_modules/undici/lib/milo/simd.js +1002 -0
  209. package/node_modules/undici/lib/mock/mock-agent.js +11 -0
  210. package/node_modules/undici/lib/mock/snapshot-recorder.js +3 -2
  211. package/node_modules/undici/lib/mock/snapshot-utils.js +3 -2
  212. package/node_modules/undici/lib/util/cache.js +11 -5
  213. package/node_modules/undici/lib/web/cookies/util.js +19 -2
  214. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +69 -15
  215. package/node_modules/undici/lib/web/eventsource/eventsource.js +25 -2
  216. package/node_modules/undici/lib/web/fetch/body.js +47 -38
  217. package/node_modules/undici/lib/web/fetch/formdata-parser.js +12 -4
  218. package/node_modules/undici/lib/web/fetch/headers.js +2 -2
  219. package/node_modules/undici/lib/web/fetch/index.js +8 -4
  220. package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +5 -5
  221. package/node_modules/undici/lib/web/websocket/receiver.js +25 -4
  222. package/node_modules/undici/package.json +9 -7
  223. package/node_modules/undici/types/api.d.ts +1 -1
  224. package/node_modules/undici/types/cache-interceptor.d.ts +10 -0
  225. package/node_modules/undici/types/client.d.ts +10 -4
  226. package/node_modules/undici/types/errors.d.ts +16 -1
  227. package/node_modules/undici/types/h2c-client.d.ts +1 -1
  228. package/node_modules/undici/types/interceptors.d.ts +6 -1
  229. package/node_modules/undici/types/utility.d.ts +4 -4
  230. package/node_modules/zod/package.json +1 -1
  231. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  232. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  233. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  234. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  235. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  236. package/node_modules/zod/src/v4/core/util.ts +13 -0
  237. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  238. package/node_modules/zod/v4/core/compile.cjs +8 -0
  239. package/node_modules/zod/v4/core/compile.js +8 -0
  240. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  241. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  242. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  243. package/node_modules/zod/v4/core/schemas.js +30 -0
  244. package/node_modules/zod/v4/core/util.cjs +15 -0
  245. package/node_modules/zod/v4/core/util.d.cts +2 -0
  246. package/node_modules/zod/v4/core/util.d.ts +2 -0
  247. package/node_modules/zod/v4/core/util.js +14 -0
  248. package/node_modules/zod/v4/core/versions.cjs +1 -1
  249. package/node_modules/zod/v4/core/versions.js +1 -1
  250. package/openclaw.plugin.json +6 -30
  251. package/package.json +7 -7
  252. package/dist/.setup/action-runtime.runtime-Ck_j1YTn.mjs +0 -1
  253. package/dist/.setup/http-C9sM-FXe.mjs +0 -2
  254. package/dist/.setup/plugin-routes-D4qozHVn.mjs +0 -22
  255. package/dist/.setup/probe-IiHogLQN.mjs +0 -694
  256. package/dist/.setup/registry-DizWcnNp.mjs +0 -36
  257. package/dist/.setup/runtime-setter-api-Cx_PV-xu.mjs +0 -2
  258. package/dist/.setup/setup-plugin-api-B18kDKtr.mjs +0 -2
  259. package/dist/.setup/shared-DpHCoKy2.mjs +0 -259
  260. package/dist/.source-module-urls/562d694877afe9d9dcbb3b32a8883c16974738f2aa892c48d45572cdc9a62529.json +0 -1
  261. package/dist/http-routes-api.js +0 -1
  262. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/LICENSE +0 -22
  263. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +0 -71
  264. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +0 -52
  265. package/node_modules/@slack/bolt/node_modules/content-disposition/index.js +0 -536
  266. package/node_modules/@slack/bolt/node_modules/content-type/HISTORY.md +0 -29
  267. package/node_modules/@slack/bolt/node_modules/content-type/index.js +0 -225
  268. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +0 -22
  269. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +0 -71
  270. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +0 -46
  271. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +0 -176
  272. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +0 -1
  273. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +0 -52
  274. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/LICENSE +0 -22
  275. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +0 -71
  276. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +0 -46
  277. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +0 -176
  278. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +0 -1
  279. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +0 -52
  280. package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
  281. package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
  282. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.d.ts +0 -0
  283. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js +0 -0
  284. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js.map +0 -0
@@ -1,16 +1,17 @@
1
- import { n as __reExport, t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
2
- import { f as resolveSlackReplyToMode, o as resolveDefaultSlackAccountId } from "./accounts-msihSF3-.mjs";
3
- import { n as formatSlackTarget } from "./target-parsing-FFE26kOV.mjs";
4
- import { D as buildSlackCompleteBlocksFallbackText, E as buildSlackBlocksFallbackText, F as truncateSlackTextByUtf8Bytes, H as SLACK_SESSION_LINK_ACTION_ID, M as SLACK_TEXT_LIMIT, N as countSlackTextUtf8Bytes, P as truncateSlackText, Q as normalizeSlackOutboundText, b as hasSlackNativeDataBlock, k as SLACK_EDIT_TEXT_MAX_BYTES, l as qualifySlackRoutePeerId, st as escapeSlackMrkdwn } from "./session-status-Dv8wNBEt.mjs";
5
- import { M as resolveSlackUserAllowed, O as normalizeSlackAllowOwnerEntry, b as writeLruMapEntry, o as formatSlackError, v as pruneExpiredMapEntries, y as readLruMapEntry } from "./probe-IiHogLQN.mjs";
6
- import { a as prepareSlackReply, l as resolveSlackReplyRenderPlan, s as resolveSlackReplyBlocks } from "./reply-blocks-Ca-raz2z.mjs";
7
- import { n as resolveSlackReplyThreadTs } from "./thread-ts-Cvt7WD6B.mjs";
8
- import { C as hasSlackTableBlock, D as buildSlackEditTextPayload, E as resolveSlackMessageText$1, T as resolveSlackBlocksText, a as editSlackRenderedMessage, b as formatSlackFileReference, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, w as isSlackUnfurlAttachment, x as formatSlackFileReferenceList } from "./actions-By7tvpvv.mjs";
9
- import { c as hasSlackThreadParticipationWithPersistence, i as clearSlackThreadFailureNotice, l as recordSlackThreadFailureNotice, m as buildSlackNativeDataDeliveryPlan, o as hasSlackThreadFailureNotice, p as hasSlackMessageIdentity, s as hasSlackThreadParticipation, t as sendMessageSlack, u as recordSlackThreadParticipation } from "./send-C-8wY0lK.mjs";
10
- import { n as resolveSlackChannelConfig } from "./policy-yhn48xf5.mjs";
11
- import { C as resolveSlackChatType, E as stripSlackMentionsForCommandDetection, S as normalizeSlackChannelType, T as readSlackAssistantThreadContext, _ as appendSlackStream, b as stopSlackStream, c as resolveSlackRoutingContext, g as SlackStreamNotDeliveredError, h as resolveSlackEffectiveAllowFrom, i as resolveSlackRoomContextHints, l as registerSlackSessionRun, m as resolveSlackCommandIngress, p as authorizeSlackBotRoomMessage, r as trackSlackDraftMessage, s as authorizeSlackDirectMessage, u as resolveSlackThreadContext, v as markSlackStreamFallbackDelivered, w as buildSlackAssistantThreadMetadata, y as startSlackStream } from "./monitor-BFilOuM_.mjs";
12
- import { a as emitSlackMessageSentHooks, i as sanitizeSlackMonitorReplyPayload, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-CJwjTqDr.mjs";
1
+ import { n as __reExport, t as __exportAll } from "./rolldown-runtime-nwUcYXjP.mjs";
2
+ import { d as resolveSlackMarkdownOptions, o as resolveDefaultSlackAccountId, p as resolveSlackReplyToMode } from "./accounts-EaPP0fFY.mjs";
3
+ import { n as formatSlackTarget } from "./target-parsing-DwYAP3ts.mjs";
4
+ import { F as truncateSlackText, Gt as resolveSlackUserAllowed, I as truncateSlackTextByUtf8Bytes, O as hasSlackNativeDataBlock, P as countSlackTextUtf8Bytes, Tt as escapeSlackMrkdwn, U as SLACK_SESSION_LINK_ACTION_ID, Vt as normalizeSlackAllowOwnerEntry, _ as qualifySlackRoutePeerId, at as buildSlackCompleteBlocksFallbackText, it as buildSlackBlocksFallbackText, m as formatSlackError, vt as SLACK_EDIT_TEXT_MAX_BYTES, wt as normalizeSlackOutboundText, xt as SLACK_TEXT_LIMIT } from "./probe-B_Ax1vS1.mjs";
5
+ import { n as resolveSlackReplyThreadTs } from "./thread-ts-47Au2-Yn.mjs";
6
+ import { c as resolveSlackReplyRenderPlan, i as prepareSlackReply, o as resolveSlackReplyBlocks } from "./reply-blocks-DyYYRrP_.mjs";
7
+ import { d as getOrCreateWeakOwnerMap, m as writeLruMapEntry, p as readLruMapEntry } from "./cursor-pages-jVn3Vkfi.mjs";
8
+ import { C as hasSlackTableBlock, D as buildSlackEditTextPayload, E as resolveSlackMessageText$1, T as resolveSlackBlocksText, a as editSlackRenderedMessage, b as formatSlackFileReference, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, w as isSlackUnfurlAttachment, x as formatSlackFileReferenceList } from "./actions-s3CcFO45.mjs";
9
+ import { a as clearSlackThreadFailureNotice, c as hasSlackThreadParticipation, d as recordSlackThreadParticipation, h as buildSlackNativeDataDeliveryPlan, l as hasSlackThreadParticipationWithPersistence, m as hasSlackMessageIdentity, s as hasSlackThreadFailureNotice, t as sendMessageSlack, u as recordSlackThreadFailureNotice } from "./send-WJZ73VSf.mjs";
10
+ import { n as resolveSlackChannelConfig } from "./policy-C6_DdlSf.mjs";
11
+ import { C as resolveSlackChatType, E as stripSlackMentionsForCommandDetection, S as normalizeSlackChannelType, T as readSlackAssistantThreadContext, _ as appendSlackStream, b as stopSlackStream, c as registerSlackSessionRun, g as SlackStreamNotDeliveredError, h as resolveSlackEffectiveAllowFrom, l as resolveSlackThreadContext, m as resolveSlackCommandIngress, o as authorizeSlackDirectMessage, p as authorizeSlackBotRoomMessage, r as resolveSlackRoomContextHints, s as resolveSlackRoutingContext, u as trackSlackDraftMessage, v as markSlackStreamFallbackDelivered, w as buildSlackAssistantThreadMetadata, y as startSlackStream } from "./monitor-BD86SotB.mjs";
12
+ import { a as emitSlackMessageSentHooks, i as sanitizeSlackMonitorReplyPayload, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-Bq7n0gfM.mjs";
13
13
  import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
14
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
14
15
  import { resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
15
16
  import { buildChannelProgressDraftLine, compactChannelProgressDraftLine, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createDraftStreamLoop, createFinalizableDraftLifecycle, createLivePreviewLifecycle, createMessageReceiptFromOutboundResults, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages, selectPlanChecklistSteps } from "openclaw/plugin-sdk/channel-outbound";
16
17
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
@@ -18,10 +19,9 @@ import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtim
18
19
  import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
19
20
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
20
21
  import { normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-normalization-runtime";
21
- import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
22
- import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
22
+ import { createStaleWhileRevalidateCache } from "openclaw/plugin-sdk/collection-runtime";
23
+ import { asFiniteNumberInRange, parseStrictFiniteNumber, resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
23
24
  import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
24
- import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
25
25
  import { hash } from "node:crypto";
26
26
  import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
27
27
  import fs from "node:fs/promises";
@@ -32,10 +32,10 @@ import { mimeTypeFromFilePath, normalizeMimeType } from "openclaw/plugin-sdk/med
32
32
  import { ensureConfiguredBindingRouteReady, resolveConversationLabel } from "openclaw/plugin-sdk/conversation-runtime";
33
33
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
34
34
  import { getSessionEntryAsync, readSessionUpdatedAtAsync, resolveChannelResetConfig, resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
35
- import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
36
35
  import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
37
36
  import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
38
- import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, isGroupThreadRouteExclusive, matchesMentionWithExplicit, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, resolveGroupThreadConfig, resolveGroupThreadMentionFacts, resolveInboundMentionDecision, resolveInboundReplyDispatchCounts, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
37
+ import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
38
+ import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, isGroupThreadRouteExclusive, matchesMentionWithExplicit, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, resolveGroupThreadConfig, resolveGroupThreadMentionFacts, resolveInboundMentionDecision, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
39
39
  import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
40
40
  import { buildControlUiSessionPath } from "openclaw/plugin-sdk/session-discussion";
41
41
  import { createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
@@ -45,7 +45,7 @@ import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
45
45
  import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
46
46
  import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
47
47
  import { createChannelPreflightAudio, formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
48
- //#region extensions/slack/src/monitor/message-handler/timestamp.ts
48
+ // extensions/slack/src/monitor/message-handler/timestamp.ts
49
49
  const SLACK_TIMESTAMP_RE = /^\d+(?:\.\d+)?$/;
50
50
  const MAX_SAFE_SLACK_TIMESTAMP_SECONDS = Number.MAX_SAFE_INTEGER / 1e3;
51
51
  function resolveSlackTimestampMs(ts) {
@@ -57,8 +57,7 @@ function resolveSlackTimestampMs(ts) {
57
57
  });
58
58
  return seconds === void 0 ? void 0 : Math.round(seconds * 1e3);
59
59
  }
60
- //#endregion
61
- //#region extensions/slack/src/monitor/message-handler/dispatch-helpers.ts
60
+ // extensions/slack/src/monitor/message-handler/dispatch-helpers.ts
62
61
  function resolveSlackBotLoopProtection(prepared) {
63
62
  const senderBotId = prepared.message.bot_id;
64
63
  if (!senderBotId) return;
@@ -97,13 +96,6 @@ function resolveSlackNativeProgressTaskCards(entry, style) {
97
96
  }
98
97
  const SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX = 2e3;
99
98
  const slackStreamRecipientTeamCaches = /* @__PURE__ */ new WeakMap();
100
- function getSlackStreamRecipientTeamCache(client) {
101
- const existing = slackStreamRecipientTeamCaches.get(client);
102
- if (existing) return existing;
103
- const cache = /* @__PURE__ */ new Map();
104
- slackStreamRecipientTeamCaches.set(client, cache);
105
- return cache;
106
- }
107
99
  function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(params.payload)) {
108
100
  const reply = resolveSendableOutboundReplyParts(params.payload, { text: params.textOverride });
109
101
  const renderPlan = preparedReply.resolvePreview(params.textOverride);
@@ -122,7 +114,7 @@ function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(pa
122
114
  }
123
115
  async function resolveSlackStreamRecipientTeamId(params) {
124
116
  const cacheKey = params.fallbackTeamId && params.userId ? `${params.fallbackTeamId}:${params.userId}` : void 0;
125
- const cache = cacheKey ? getSlackStreamRecipientTeamCache(params.client) : void 0;
117
+ const cache = cacheKey ? getOrCreateWeakOwnerMap(slackStreamRecipientTeamCaches, params.client) : void 0;
126
118
  const cachedTeamId = cache && cacheKey ? readLruMapEntry(cache, cacheKey) : void 0;
127
119
  if (cachedTeamId) return cachedTeamId;
128
120
  if (params.userId) try {
@@ -140,14 +132,11 @@ async function resolveSlackStreamRecipientTeamId(params) {
140
132
  }
141
133
  return params.fallbackTeamId;
142
134
  }
143
- //#endregion
144
- //#region extensions/slack/src/draft-stream.ts
135
+ // extensions/slack/src/draft-stream.ts
145
136
  const DEFAULT_THROTTLE_MS = 1e3;
146
137
  function createSlackDraftStream(params) {
147
138
  const maxChars = Math.min(params.maxChars ?? 8e3, SLACK_TEXT_LIMIT);
148
139
  const throttleMs = Math.max(250, params.throttleMs ?? DEFAULT_THROTTLE_MS);
149
- const send = params.send ?? sendMessageSlack;
150
- const remove = params.remove ?? deleteSlackMessage;
151
140
  let streamMessage;
152
141
  let untrackConversationBoundary;
153
142
  let lastSentKey = "";
@@ -161,7 +150,7 @@ function createSlackDraftStream(params) {
161
150
  streamMessage = void 0;
162
151
  lastSentKey = "";
163
152
  };
164
- const editPreview = (message, update) => (params.edit ?? (update.textIsSlackMrkdwn ? editSlackRenderedMessage : editSlackMessage))(message.channelId, message.messageId, update.text, {
153
+ const editPreview = (message, update) => (update.textIsSlackMrkdwn ? editSlackRenderedMessage : editSlackMessage)(message.channelId, message.messageId, update.text, {
165
154
  cfg: params.cfg,
166
155
  token: params.token,
167
156
  accountId: params.accountId,
@@ -208,7 +197,7 @@ function createSlackDraftStream(params) {
208
197
  onInterveningMessage: () => forceNewMessage("human")
209
198
  });
210
199
  await lifecycle.createMessage(async () => {
211
- const sent = await send(params.target, visibleUpdate.text, {
200
+ const sent = await sendMessageSlack(params.target, visibleUpdate.text, {
212
201
  cfg: params.cfg,
213
202
  token: params.token,
214
203
  accountId: params.accountId,
@@ -253,7 +242,7 @@ function createSlackDraftStream(params) {
253
242
  clearMessageId,
254
243
  isValidMessageId: (value) => typeof value === "object" && value !== null,
255
244
  deleteMessage: async (message) => {
256
- if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await remove(message.channelId, message.messageId, {
245
+ if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await deleteSlackMessage(message.channelId, message.messageId, {
257
246
  token: params.token,
258
247
  accountId: params.accountId,
259
248
  ...params.eventScope ? { client: params.eventScope.client } : {}
@@ -301,7 +290,6 @@ function createSlackDraftStream(params) {
301
290
  stopTrackingConversationBoundary();
302
291
  return true;
303
292
  };
304
- params.log?.(`slack stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
305
293
  return {
306
294
  update,
307
295
  flush: loop.flush,
@@ -315,8 +303,7 @@ function createSlackDraftStream(params) {
315
303
  channelId: () => streamMessage?.channelId
316
304
  };
317
305
  }
318
- //#endregion
319
- //#region extensions/slack/src/stream-mode.ts
306
+ // extensions/slack/src/stream-mode.ts
320
307
  function resolveSlackStreamingConfig(params) {
321
308
  return {
322
309
  mode: params.streaming?.mode ?? "progress",
@@ -365,8 +352,7 @@ function applyAppendOnlyStreamUpdate(params) {
365
352
  changed: true
366
353
  };
367
354
  }
368
- //#endregion
369
- //#region extensions/slack/src/progress-blocks.ts
355
+ // extensions/slack/src/progress-blocks.ts
370
356
  const SLACK_PROGRESS_FIELD_MAX = 1800;
371
357
  const DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS = 120;
372
358
  const DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS = 48;
@@ -375,12 +361,6 @@ const SLACK_PROGRESS_TASK_TITLE_MAX = 120;
375
361
  const SLACK_PROGRESS_PLAN_FALLBACK_TITLE = "Thinking";
376
362
  const SLACK_PROGRESS_LINE_DELTA_RE = /(?:^|\s)\+(\d+)\s+[−-](\d+)(?=\s|$)/u;
377
363
  const SLACK_ATTENTION_TASK_PREFIX = "openclaw-attention-";
378
- function buildSessionSources(links) {
379
- return links.map((link) => ({
380
- type: "url_source",
381
- ...link
382
- }));
383
- }
384
364
  function field(text) {
385
365
  return {
386
366
  type: "mrkdwn",
@@ -439,10 +419,6 @@ function lineTaskTitle(line) {
439
419
  if (fallback && fallback !== label) return compactTitle(lineDetailParts(line).length > 0 || line.status ? label : fallback);
440
420
  return compactTitle(label);
441
421
  }
442
- function lineTaskDetails(line, maxLineChars) {
443
- const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
444
- return detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
445
- }
446
422
  function lineTaskOutput(line) {
447
423
  const match = line.detail ? SLACK_PROGRESS_LINE_DELTA_RE.exec(line.detail) : null;
448
424
  if (match) return `+${match[1]} −${match[2]}`;
@@ -473,48 +449,39 @@ function resolveLineTaskIdentity(line, contentIdOccurrences) {
473
449
  contentIdOccurrences.set(id, occurrence);
474
450
  return `${id}_${occurrence}`;
475
451
  }
476
- function buildNativeTasks(params) {
452
+ function formatProgressAttentionTitle(line, finalStatus) {
453
+ if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
454
+ if (lineTaskStatus(line) !== "error") return;
455
+ const title = [...new Set([
456
+ line.label,
457
+ line.detail,
458
+ line.status
459
+ ].filter(Boolean))].join(" — ");
460
+ return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
461
+ }
462
+ function buildSlackProgressStreamChunks(params) {
463
+ const approvals = params.lines.filter((line) => line.kind === "approval");
464
+ const taskLines = params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval");
477
465
  const tasks = (params.plan ?? []).map((entry, index) => ({
478
466
  id: `plan_step_${index + 1}`,
479
467
  title: compactTitle(entry.step),
480
468
  status: entry.status === "completed" ? "complete" : entry.status
481
469
  }));
482
470
  const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS);
483
- const contentIdOccurrences = /* @__PURE__ */ new Map();
484
- for (const line of params.lines) {
471
+ const taskContentIdOccurrences = /* @__PURE__ */ new Map();
472
+ for (const line of taskLines) {
485
473
  const task = {
486
- id: resolveLineTaskIdentity(line, contentIdOccurrences),
474
+ id: resolveLineTaskIdentity(line, taskContentIdOccurrences),
487
475
  title: lineTaskTitle(line),
488
476
  status: lineTaskStatus(line)
489
477
  };
490
- const details = lineTaskDetails(line, maxLineChars);
478
+ const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
479
+ const details = detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
491
480
  const output = lineTaskOutput(line);
492
481
  if (details) task.details = details;
493
482
  if (output) task.output = output;
494
483
  tasks.push(task);
495
484
  }
496
- return tasks;
497
- }
498
- function formatProgressAttentionTitle(line, finalStatus) {
499
- if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
500
- if (lineTaskStatus(line) !== "error") return;
501
- const title = [...new Set([
502
- line.label,
503
- line.detail,
504
- line.status
505
- ].filter(Boolean))].join(" — ");
506
- return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
507
- }
508
- function formatTaskDiffOutput(diffStat) {
509
- return diffStat && (diffStat.added > 0 || diffStat.removed > 0) ? `+${diffStat.added} −${diffStat.removed}` : void 0;
510
- }
511
- function buildSlackProgressStreamChunks(params) {
512
- const approvals = params.lines.filter((line) => line.kind === "approval");
513
- const tasks = buildNativeTasks({
514
- lines: params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval"),
515
- plan: params.plan,
516
- maxLineChars: params.maxLineChars
517
- });
518
485
  const contentIdOccurrences = /* @__PURE__ */ new Map();
519
486
  const attention = [];
520
487
  for (const line of approvals) {
@@ -525,11 +492,11 @@ function buildSlackProgressStreamChunks(params) {
525
492
  status: "pending"
526
493
  });
527
494
  }
528
- const headline = params.title?.trim() || params.label?.trim();
495
+ const headline = params.title?.trim();
529
496
  const summaryTitle = params.finalInProgressStatus === "error" ? "Failed" : params.finalInProgressStatus === "complete" || !params.summaryRow ? "Completed" : "Working";
530
497
  const newest = tasks.at(-1);
531
498
  const title = compactTitle(headline || (newest?.details ? `${newest.title} — ${newest.details}` : newest?.title) || (params.summaryRow ? summaryTitle : attention.at(-1)?.title) || SLACK_PROGRESS_PLAN_FALLBACK_TITLE, SLACK_PROGRESS_CHUNK_TEXT_MAX);
532
- const diffOutput = formatTaskDiffOutput(params.diffStat);
499
+ const diffOutput = params.diffStat && (params.diffStat.added > 0 || params.diffStat.removed > 0) ? `+${params.diffStat.added} −${params.diffStat.removed}` : void 0;
533
500
  if (tasks.length === 0 && (params.summaryRow || params.sessionLinks?.length || diffOutput)) tasks.push({
534
501
  id: "openclaw_summary",
535
502
  title: params.summaryRow ? compactTitle(title) : summaryTitle,
@@ -549,7 +516,10 @@ function buildSlackProgressStreamChunks(params) {
549
516
  chunk.title = recovered ? compactTitle(`Recovered: ${task.title}`) : task.title;
550
517
  chunk.status = recovered ? "complete" : task.status === "in_progress" ? params.finalInProgressStatus ?? task.status : task.status;
551
518
  if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
552
- if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources = buildSessionSources(params.sessionLinks);
519
+ if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources = params.sessionLinks.map((link) => ({
520
+ type: "url_source",
521
+ ...link
522
+ }));
553
523
  return chunk;
554
524
  });
555
525
  return [{
@@ -568,13 +538,6 @@ function joinRecentProgressRows(rows) {
568
538
  }
569
539
  return rendered.toReversed().join("\n");
570
540
  }
571
- function buildActivityText(lines, maxLineChars) {
572
- return joinRecentProgressRows(lines.slice(-50).map((line) => {
573
- if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
574
- const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
575
- return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
576
- }));
577
- }
578
541
  function buildSlackProgressCardBlocks(params) {
579
542
  const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS);
580
543
  const selected = selectPlanChecklistSteps(params.detailed ? params.plan ?? [] : [], { maxLines: 50 });
@@ -604,7 +567,11 @@ function buildSlackProgressCardBlocks(params) {
604
567
  });
605
568
  const sections = [
606
569
  planLines.map((line) => renderProgressCardText(line)).join("\n"),
607
- buildActivityText(lines.filter((line) => line.kind !== "approval" && lineTaskStatus(line) !== "error"), maxLineChars),
570
+ joinRecentProgressRows(lines.filter((line) => line.kind !== "approval" && lineTaskStatus(line) !== "error").slice(-50).map((line) => {
571
+ if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
572
+ const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
573
+ return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
574
+ })),
608
575
  joinRecentProgressRows(attention)
609
576
  ];
610
577
  const title = params.title?.trim();
@@ -684,6 +651,13 @@ function reconcileSlackNativeTaskChunks(params) {
684
651
  const nextTasks = /* @__PURE__ */ new Map();
685
652
  let planTitle = params.previous.planTitle;
686
653
  const emitted = [];
654
+ if (!params.chunks?.length && planTitle && planTitle !== SLACK_PROGRESS_PLAN_FALLBACK_TITLE) {
655
+ planTitle = SLACK_PROGRESS_PLAN_FALLBACK_TITLE;
656
+ emitted.push({
657
+ type: "plan_update",
658
+ title: planTitle
659
+ });
660
+ }
687
661
  for (const chunk of params.chunks ?? []) {
688
662
  if (chunk.type === "plan_update") {
689
663
  if (chunk.title !== planTitle) {
@@ -751,8 +725,7 @@ function reconcileSlackNativeTaskChunks(params) {
751
725
  }
752
726
  };
753
727
  }
754
- //#endregion
755
- //#region extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
728
+ // extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
756
729
  function resolveStructuredProgressLines(lines) {
757
730
  return lines.map((line) => {
758
731
  if (typeof line !== "string") return line;
@@ -793,14 +766,7 @@ function isSlackProgressTitleText(text, snapshot, explicitTitle) {
793
766
  const title = normalizeProgressText(combineProgressHeadlineAndExplanation(explicitTitle ?? (snapshot.statusHeadlineFormat === "plain" ? void 0 : snapshot.statusHeadline), snapshot.planExplanationFormat === "plain" ? void 0 : snapshot.planExplanation));
794
767
  return title.length > 0 && title.includes(candidate);
795
768
  }
796
- //#endregion
797
- //#region extensions/slack/src/monitor/message-handler/preview-finalize.ts
798
- function buildExpectedSlackEditText(params) {
799
- const trimmedText = params.text.trim();
800
- if (trimmedText) return normalizeSlackOutboundText(trimmedText);
801
- if (params.blocks?.length) return normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks));
802
- return " ";
803
- }
769
+ // extensions/slack/src/monitor/message-handler/preview-finalize.ts
804
770
  function blocksMatch(expected, actual) {
805
771
  if (!expected?.length) return !actual?.length;
806
772
  if (!actual?.length) {
@@ -820,45 +786,6 @@ function blocksMatch(expected, actual) {
820
786
  return false;
821
787
  }
822
788
  }
823
- async function readSlackMessageAfterEditError(params) {
824
- const query = {
825
- token: params.token,
826
- channel: params.channelId,
827
- latest: params.messageId,
828
- oldest: params.messageId,
829
- inclusive: true,
830
- limit: 1
831
- };
832
- const result = params.threadTs ? await params.client.conversations.replies({
833
- ...query,
834
- ts: params.threadTs
835
- }) : await params.client.conversations.history(query);
836
- const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
837
- return message?.ts && message.ts === params.messageId ? message : null;
838
- }
839
- async function didSlackPreviewEditApplyAfterError(params) {
840
- const readback = await readSlackMessageAfterEditError(params);
841
- if (!readback) return false;
842
- const expectedText = buildExpectedSlackEditText({
843
- text: params.text,
844
- blocks: params.blocks
845
- });
846
- const acceptedTexts = /* @__PURE__ */ new Set([
847
- expectedText,
848
- normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
849
- normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
850
- ]);
851
- if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
852
- const fallbackPlan = buildSlackNativeDataDeliveryPlan({
853
- baseText: params.text,
854
- blocks: params.blocks
855
- });
856
- for (const message of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(message.text));
857
- }
858
- const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
859
- if (params.blocks?.length) return acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks);
860
- return actualText === expectedText;
861
- }
862
789
  async function finalizeSlackPreviewEdit(params) {
863
790
  try {
864
791
  await editSlackRenderedMessage(params.channelId, params.messageId, params.text, {
@@ -869,9 +796,40 @@ async function finalizeSlackPreviewEdit(params) {
869
796
  });
870
797
  } catch (err) {
871
798
  try {
872
- if (await didSlackPreviewEditApplyAfterError(params)) {
873
- logVerbose(`slack: preview final edit response failed but readback matched message ${params.channelId}/${params.messageId}; suppressing duplicate fallback send`);
874
- return;
799
+ const query = {
800
+ token: params.token,
801
+ channel: params.channelId,
802
+ latest: params.messageId,
803
+ oldest: params.messageId,
804
+ inclusive: true,
805
+ limit: 1
806
+ };
807
+ const result = params.threadTs ? await params.client.conversations.replies({
808
+ ...query,
809
+ ts: params.threadTs
810
+ }) : await params.client.conversations.history(query);
811
+ const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
812
+ const readback = message?.ts && message.ts === params.messageId ? message : null;
813
+ if (readback) {
814
+ const trimmedText = params.text.trim();
815
+ const expectedText = trimmedText ? normalizeSlackOutboundText(trimmedText) : params.blocks?.length ? normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks)) : " ";
816
+ const acceptedTexts = /* @__PURE__ */ new Set([
817
+ expectedText,
818
+ normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
819
+ normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
820
+ ]);
821
+ if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
822
+ const fallbackPlan = buildSlackNativeDataDeliveryPlan({
823
+ baseText: params.text,
824
+ blocks: params.blocks
825
+ });
826
+ for (const fallbackMessage of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(fallbackMessage.text));
827
+ }
828
+ const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
829
+ if (params.blocks?.length ? acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks) : actualText === expectedText) {
830
+ logVerbose(`slack: preview final edit response failed but readback matched message ${params.channelId}/${params.messageId}; suppressing duplicate fallback send`);
831
+ return;
832
+ }
875
833
  }
876
834
  } catch (readbackErr) {
877
835
  logVerbose(`slack: preview final edit readback failed (${String(readbackErr)})`);
@@ -879,8 +837,7 @@ async function finalizeSlackPreviewEdit(params) {
879
837
  throw err;
880
838
  }
881
839
  }
882
- //#endregion
883
- //#region extensions/slack/src/monitor/message-handler/dispatch-progress-card.ts
840
+ // extensions/slack/src/monitor/message-handler/dispatch-progress-card.ts
884
841
  const MAX_VISIBLE_WORK_LINKS = 5;
885
842
  function createSlackDraftProgressCardRuntime(params) {
886
843
  const { cfg, prepared, slackClient } = params.setup;
@@ -1008,8 +965,7 @@ function formatSlackProgressDraftLine(line) {
1008
965
  enclosingStyle: "italic"
1009
966
  })}_`;
1010
967
  }
1011
- //#endregion
1012
- //#region extensions/slack/src/monitor/message-handler/dispatch-progress-native.ts
968
+ // extensions/slack/src/monitor/message-handler/dispatch-progress-native.ts
1013
969
  function createSlackNativeProgressTransport(params) {
1014
970
  const { replyPlan } = params.setup;
1015
971
  const { delivery } = params;
@@ -1049,7 +1005,7 @@ function createSlackNativeProgressTransport(params) {
1049
1005
  const delivered = markDelivered(streamThreadTs);
1050
1006
  return update.chunks?.length ? delivered : true;
1051
1007
  } finally {
1052
- if (delivery.nativeProgressStreamStartPromise === startPromise) delivery.nativeProgressStreamStartPromise = null;
1008
+ delivery.nativeProgressStreamStartPromise = null;
1053
1009
  }
1054
1010
  };
1055
1011
  const append = async (update) => {
@@ -1070,8 +1026,7 @@ function createSlackNativeProgressTransport(params) {
1070
1026
  waitForStart
1071
1027
  };
1072
1028
  }
1073
- //#endregion
1074
- //#region extensions/slack/src/monitor/message-handler/dispatch-progress.ts
1029
+ // extensions/slack/src/monitor/message-handler/dispatch-progress.ts
1075
1030
  function createSlackProgressRuntime(runtimeParams) {
1076
1031
  const { setup, delivery } = runtimeParams;
1077
1032
  const { cfg, hasSlackCustomIdentity, prepared, replyPlan, runtime, slackIdentity, slackStreaming, slackProgressStyle, quietProgress, shouldUseDraftStream, useStreaming, previewStreamingEnabled } = setup;
@@ -1081,7 +1036,6 @@ function createSlackProgressRuntime(runtimeParams) {
1081
1036
  cfg,
1082
1037
  token: ctx.botToken,
1083
1038
  accountId: account.accountId,
1084
- conversationChannelId: message.channel,
1085
1039
  eventScope: prepared.eventScope,
1086
1040
  ...!hasSlackCustomIdentity && slackIdentity ? { identity: slackIdentity } : {},
1087
1041
  ...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
@@ -1091,7 +1045,6 @@ function createSlackProgressRuntime(runtimeParams) {
1091
1045
  if (ts) delivery.usedReplyThreadTs ??= ts;
1092
1046
  return ts;
1093
1047
  },
1094
- log: logVerbose,
1095
1048
  warn: logVerbose
1096
1049
  }) : void 0;
1097
1050
  const isProgressMode = slackStreaming.mode === "progress";
@@ -1510,7 +1463,6 @@ function createSlackProgressRuntime(runtimeParams) {
1510
1463
  return {
1511
1464
  draftStream,
1512
1465
  previewLifecycle,
1513
- isProgressMode,
1514
1466
  useDraftProgressCard,
1515
1467
  useNativeProgressStreaming,
1516
1468
  progressDraftActive,
@@ -1546,8 +1498,7 @@ function createSlackProgressRuntime(runtimeParams) {
1546
1498
  updateDraftFromPartial
1547
1499
  };
1548
1500
  }
1549
- //#endregion
1550
- //#region extensions/slack/src/monitor/message-handler/dispatch-setup.ts
1501
+ // extensions/slack/src/monitor/message-handler/dispatch-setup.ts
1551
1502
  async function createSlackDispatchSetup(prepared) {
1552
1503
  const { ctx, account, message, route } = prepared;
1553
1504
  const slackClient = prepared.eventScope?.client ?? ctx.app.client;
@@ -1703,9 +1654,7 @@ async function createSlackDispatchSetup(prepared) {
1703
1654
  status: "active",
1704
1655
  eventScope: prepared.eventScope
1705
1656
  });
1706
- if (reportFailure && !restored) try {
1707
- runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
1708
- } catch {}
1657
+ if (reportFailure && !restored) runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
1709
1658
  }
1710
1659
  if (didAddTypingReaction && typingReaction && message.ts) {
1711
1660
  didAddTypingReaction = false;
@@ -1765,11 +1714,14 @@ async function createSlackDispatchSetup(prepared) {
1765
1714
  useStreaming
1766
1715
  };
1767
1716
  }
1768
- //#endregion
1769
- //#region extensions/slack/src/monitor/message-handler/dispatch-streaming.ts
1717
+ // extensions/slack/src/monitor/message-handler/dispatch-streaming.ts
1770
1718
  function createSlackStreamingDeliveryRuntime(setup) {
1771
1719
  const { isThreadReply, messageSentHookContext, messageSentHookTarget, prepared, replyDeliveryMode, replyPlan, runtime, slackClient, slackClientOptions, slackIdentity, slackStreamFallbackTeamId } = setup;
1772
1720
  const { account, ctx, forcedReplyThreadTs, message, slackMessageMetadata } = prepared;
1721
+ const markdownOptions = resolveSlackMarkdownOptions({
1722
+ cfg: ctx.cfg,
1723
+ accountId: account.accountId
1724
+ });
1773
1725
  const state = {
1774
1726
  streamSession: null,
1775
1727
  streamBoundary: null,
@@ -1850,7 +1802,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
1850
1802
  if (key) deliveredKeys.add(key);
1851
1803
  };
1852
1804
  const markPreviewPayloadDelivered = (params) => {
1853
- const preparedReply = prepareSlackReply(params.payload);
1805
+ const preparedReply = prepareSlackReply(params.payload, markdownOptions);
1854
1806
  markDelivered(buildSlackEventDeliveryKey(params, preparedReply));
1855
1807
  const nextThreadTs = replyPlan.peekThreadTs();
1856
1808
  if (nextThreadTs !== params.threadTs) markDelivered(buildSlackEventDeliveryKey({
@@ -1891,7 +1843,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
1891
1843
  }
1892
1844
  const fallbackText = fallbackError.pendingText.trim();
1893
1845
  if (!fallbackText) return;
1894
- const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }), session.threadTs, true);
1846
+ const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }, markdownOptions), session.threadTs, true);
1895
1847
  if (!sent?.receipt.platformMessageIds.length) return;
1896
1848
  markSlackStreamFallbackDelivered(session);
1897
1849
  if (!session.stopped) try {
@@ -1949,16 +1901,13 @@ function createSlackStreamingDeliveryRuntime(setup) {
1949
1901
  if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
1950
1902
  const replyThreadTs = params.forcedThreadTs ?? state.interruptedThreadTs ?? resolveDeliveryThreadTs(params);
1951
1903
  const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
1952
- const preparedReply = prepareSlackReply(params.payload);
1904
+ const preparedReply = prepareSlackReply(params.payload, markdownOptions);
1953
1905
  const deliveryKey = buildSlackEventDeliveryKey({
1954
1906
  kind: params.kind,
1955
1907
  payload: params.payload,
1956
1908
  threadTs: deliveryReplyThreadTs
1957
1909
  }, preparedReply);
1958
- if (deliveryKey && deliveredKeys.has(deliveryKey)) {
1959
- logVerbose("slack: suppressed duplicate normal delivery within the same turn");
1960
- return { visibleReplySent: false };
1961
- }
1910
+ if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
1962
1911
  const sent = await deliverPreparedReply(preparedReply, deliveryReplyThreadTs);
1963
1912
  if (!sent?.receipt.platformMessageIds.length) return { visibleReplySent: false };
1964
1913
  state.observedReplyDelivery = true;
@@ -1980,9 +1929,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
1980
1929
  };
1981
1930
  const isStreamingEligible = (payload, options) => {
1982
1931
  const reply = resolveSendableOutboundReplyParts(payload);
1983
- const renderPlan = resolveSlackReplyRenderPlan(payload);
1932
+ const renderPlan = resolveSlackReplyRenderPlan(payload, payload.text, markdownOptions);
1984
1933
  const plannedBlocks = renderPlan.mode === "single" ? renderPlan.blocks : renderPlan.blockPart?.blocks;
1985
- return !state.streamFailed && !reply.hasMedia && renderPlan.mode !== "split" && !renderPlan.textIsSlackPlainText && !plannedBlocks?.length && !resolveSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
1934
+ const previewThreadTs = state.streamSession?.threadTs ?? state.interruptedThreadTs ?? state.nativeProgressStreamThreadTs;
1935
+ const finalThreadTs = resolveSlackReplyThreadTs({
1936
+ replyToMode: replyDeliveryMode,
1937
+ replyToId: payload.replyToId,
1938
+ threadId: previewThreadTs,
1939
+ replyToCurrent: payload.replyToCurrent
1940
+ });
1941
+ return !state.streamFailed && (!previewThreadTs || finalThreadTs === previewThreadTs) && !reply.hasMedia && renderPlan.mode !== "split" && !renderPlan.textIsSlackPlainText && !plannedBlocks?.length && !resolveSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
1986
1942
  };
1987
1943
  const deliverWithStreaming = async (params) => {
1988
1944
  if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
@@ -1995,7 +1951,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
1995
1951
  await rotateInterruptedStream();
1996
1952
  if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
1997
1953
  let session = state.streamSession;
1998
- const threadTs = session?.threadTs ?? state.interruptedThreadTs ?? replyPlan.nextThreadTs();
1954
+ const threadTs = resolveSlackReplyThreadTs({
1955
+ replyToMode: replyDeliveryMode,
1956
+ replyToId: params.payload.replyToId,
1957
+ threadId: session?.threadTs ?? state.interruptedThreadTs ?? replyPlan.nextThreadTs(),
1958
+ replyToCurrent: params.payload.replyToCurrent
1959
+ });
1999
1960
  if (state.streamFailed || !threadTs) {
2000
1961
  state.streamFailed = true;
2001
1962
  return await deliverNormally({
@@ -2010,11 +1971,8 @@ function createSlackStreamingDeliveryRuntime(setup) {
2010
1971
  ...params,
2011
1972
  threadTs,
2012
1973
  textOverride: text
2013
- });
2014
- if (deliveryKey && deliveredKeys.has(deliveryKey)) {
2015
- logVerbose("slack-stream: suppressed duplicate reply payload");
2016
- return { visibleReplySent: false };
2017
- }
1974
+ }, prepareSlackReply(params.payload, markdownOptions));
1975
+ if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
2018
1976
  let messageId;
2019
1977
  let fallbackDelivery;
2020
1978
  try {
@@ -2095,8 +2053,75 @@ function createSlackStreamingDeliveryRuntime(setup) {
2095
2053
  resetDeliveryTracker: () => deliveredKeys.clear()
2096
2054
  });
2097
2055
  }
2098
- //#endregion
2099
- //#region extensions/slack/src/monitor/message-handler/dispatch.ts
2056
+ // extensions/slack/src/monitor/message-handler/failure-notice.ts
2057
+ /** One outage policy for immediate replies and later origin-routed queue drains. */
2058
+ function createSlackFailureNoticePolicy(params, hasVisibleReply) {
2059
+ const { context, accountId, channelId, failureNoticeThreadTs, failureNoticeTeamId, statusThreadTs } = params;
2060
+ let sawTerminalFailurePayload = false;
2061
+ let pendingFailureNotice;
2062
+ const filterPassiveThreadFailure = (payload) => {
2063
+ if (payload.isError !== true || context.ChatType !== "channel" || isReplyPayloadNonTerminalToolErrorWarning(payload)) return payload;
2064
+ sawTerminalFailurePayload = true;
2065
+ if (hasVisibleReply()) return payload;
2066
+ const explicitlyAddressed = context.ExplicitlyMentionedBot === true || context.MentionSource === "explicit_bot" || context.MentionSource === "subteam" || context.MentionSource === "mention_pattern" || context.MentionSource === "command_bypass" || context.CommandTurn?.kind !== void 0 && context.CommandTurn.kind !== "normal" && context.CommandTurn.authorized;
2067
+ const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
2068
+ const notice = {
2069
+ accountId,
2070
+ channelId,
2071
+ ...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
2072
+ failureText: payload.text ?? "",
2073
+ ...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
2074
+ };
2075
+ if (failureNoticeThreadTs && !explicitlyAddressed && context.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
2076
+ logVerbose("slack: suppressed passive failure before thread participation");
2077
+ return null;
2078
+ }
2079
+ if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
2080
+ logVerbose("slack: suppressed repeated passive channel or thread failure");
2081
+ return null;
2082
+ }
2083
+ pendingFailureNotice = notice;
2084
+ return payload;
2085
+ };
2086
+ return {
2087
+ filter: filterPassiveThreadFailure,
2088
+ recordDelivered(payload) {
2089
+ if (pendingFailureNotice && (!payload || payload.isError === true && !isReplyPayloadNonTerminalToolErrorWarning(payload) && (payload.text ?? "") === pendingFailureNotice.failureText)) {
2090
+ recordSlackThreadFailureNotice(pendingFailureNotice);
2091
+ pendingFailureNotice = void 0;
2092
+ }
2093
+ },
2094
+ complete() {
2095
+ if (!sawTerminalFailurePayload && context.ChatType === "channel") clearSlackThreadFailureNotice({
2096
+ accountId,
2097
+ channelId,
2098
+ ...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
2099
+ ...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
2100
+ });
2101
+ }
2102
+ };
2103
+ }
2104
+ function createSlackQueuedFailureNoticePolicy(params, beginSessionRun) {
2105
+ let visibleReplySent = false;
2106
+ let policy = createSlackFailureNoticePolicy(params, () => visibleReplySent);
2107
+ return {
2108
+ begin() {
2109
+ visibleReplySent = false;
2110
+ policy = createSlackFailureNoticePolicy(params, () => visibleReplySent);
2111
+ const release = beginSessionRun();
2112
+ return (settlement) => {
2113
+ if (settlement?.completed && !settlement.failed && !settlement.transportPending) policy.complete();
2114
+ release();
2115
+ };
2116
+ },
2117
+ shouldSuppressReply: (payload) => policy.filter(payload) === null,
2118
+ onReplyDelivered(payload) {
2119
+ policy.recordDelivered(payload);
2120
+ visibleReplySent = true;
2121
+ }
2122
+ };
2123
+ }
2124
+ // extensions/slack/src/monitor/message-handler/dispatch.ts
2100
2125
  function formatSlackGroupThreadReply(text, participant) {
2101
2126
  return `**${participant.name.replace(/[\\`*_{}[\]()<>#!|]/g, "\\$&").replace(/\s+/g, " ")}**\n${text}`;
2102
2127
  }
@@ -2121,7 +2146,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2121
2146
  },
2122
2147
  onSettled: () => {
2123
2148
  releaseDeferred?.();
2124
- upstreamLifecycle.onSettled?.();
2149
+ return upstreamLifecycle.onSettled?.();
2125
2150
  }
2126
2151
  };
2127
2152
  const release = beginSessionRun();
@@ -2130,6 +2155,10 @@ async function dispatchPreparedSlackMessage(prepared) {
2130
2155
  async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptionLifecycle) {
2131
2156
  const { prepared } = setup;
2132
2157
  const { account, ctx, message, route } = prepared;
2158
+ const markdownOptions = resolveSlackMarkdownOptions({
2159
+ cfg: ctx.cfg,
2160
+ accountId: account.accountId
2161
+ });
2133
2162
  const { cfg, disableBlockStreaming, hasSlackCustomIdentity, hasRepliedRef, messageSentHookContext, messageSentHookTarget, onModelSelected, previewStreamingEnabled, replyPipeline, replyPlan, runtime, slackClient, slackStreaming, sourceReplyDeliveryMode, statusReactions, statusReactionsEnabled, statusThreadTs, suppressRoomEventTyping, useStreaming } = setup;
2134
2163
  let dispatchError;
2135
2164
  const delivery = createSlackStreamingDeliveryRuntime(setup);
@@ -2141,41 +2170,22 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2141
2170
  let turnCommentaryVisible = false;
2142
2171
  const { draftStream, previewLifecycle } = progress;
2143
2172
  setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized || Boolean(draftStream?.messageId());
2144
- const failureNoticeThreadTs = message.thread_ts;
2145
- const failureNoticeTeamId = prepared.eventScope?.teamId;
2146
- let sawTerminalFailurePayload = false;
2147
- let pendingFailureNotice;
2148
- const filterPassiveThreadFailure = (payload) => {
2149
- if (payload.isError !== true || prepared.ctxPayload.ChatType !== "channel" || isReplyPayloadNonTerminalToolErrorWarning(payload)) return payload;
2150
- sawTerminalFailurePayload = true;
2151
- if (delivery.observedReplyDelivery || previewLifecycle.previewFinalized) return payload;
2152
- const explicitlyAddressed = prepared.ctxPayload.ExplicitlyMentionedBot === true || prepared.ctxPayload.MentionSource === "explicit_bot" || prepared.ctxPayload.MentionSource === "subteam" || prepared.ctxPayload.MentionSource === "mention_pattern" || prepared.ctxPayload.MentionSource === "command_bypass" || prepared.ctxPayload.CommandTurn?.kind !== void 0 && prepared.ctxPayload.CommandTurn.kind !== "normal" && prepared.ctxPayload.CommandTurn.authorized;
2153
- const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
2154
- const notice = {
2155
- accountId: account.accountId,
2156
- channelId: message.channel,
2157
- ...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
2158
- failureText: payload.text ?? "",
2159
- ...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
2160
- };
2161
- if (failureNoticeThreadTs && !explicitlyAddressed && prepared.ctxPayload.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
2162
- logVerbose("slack: suppressed passive failure before thread participation");
2163
- return null;
2164
- }
2165
- if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
2166
- logVerbose("slack: suppressed repeated passive channel or thread failure");
2167
- return null;
2168
- }
2169
- pendingFailureNotice = notice;
2170
- return payload;
2173
+ const failurePolicyParams = {
2174
+ context: prepared.ctxPayload,
2175
+ accountId: account.accountId,
2176
+ channelId: message.channel,
2177
+ failureNoticeThreadTs: message.thread_ts,
2178
+ failureNoticeTeamId: prepared.eventScope?.teamId,
2179
+ statusThreadTs
2171
2180
  };
2181
+ const failurePolicy = createSlackFailureNoticePolicy(failurePolicyParams, () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized);
2172
2182
  const deliverSlackPayload = async (incomingPayload, info) => {
2173
2183
  let payload = incomingPayload;
2174
2184
  if (info.participant && (payload.text || payload.mediaUrl || payload.mediaUrls?.length)) payload = {
2175
2185
  ...payload,
2176
2186
  text: formatSlackGroupThreadReply(payload.text ?? "", info.participant)
2177
2187
  };
2178
- if (info.kind === "final" && slackStreaming.mode === "progress" && progress.isProgressMode) {
2188
+ if (info.kind === "final" && slackStreaming.mode === "progress") {
2179
2189
  const supplement = getReplyPayloadTtsSupplement(payload);
2180
2190
  const finalPayload = !progress.useDraftProgressCard && !progress.useNativeProgressStreaming && supplement && !supplement.visibleTextAlreadyDelivered && !payload.text?.trim() ? {
2181
2191
  ...payload,
@@ -2215,15 +2225,11 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2215
2225
  const reply = resolveSendableOutboundReplyParts(payload);
2216
2226
  const ttsSupplement = getReplyPayloadTtsSupplement(payload);
2217
2227
  const replySourceText = payload.text ?? ttsSupplement?.spokenText;
2218
- const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText);
2228
+ const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText, markdownOptions);
2219
2229
  const slackBlocks = replyRenderPlan.mode === "single" ? replyRenderPlan.blocks : replyRenderPlan.blockPart?.blocks;
2220
2230
  const requiresSeparateFallbackDelivery = replyRenderPlan.mode === "split" || replyRenderPlan.textIsSlackPlainText === true;
2221
2231
  const trimmedFinalText = replyRenderPlan.mode === "single" ? replyRenderPlan.text.trim() : replyRenderPlan.fallbackText.trim();
2222
- const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), { tableMode: resolveMarkdownTableMode({
2223
- cfg,
2224
- channel: "slack",
2225
- accountId: account.accountId
2226
- }) });
2232
+ const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), markdownOptions);
2227
2233
  const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
2228
2234
  const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !previewLifecycle.previewFinalized && !previewLifecycle.finalDelivered && previewStreamingEnabled && !payload.text?.trim();
2229
2235
  let ttsPreviewFinalization;
@@ -2233,11 +2239,18 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2233
2239
  isError: payload.isError === true,
2234
2240
  adapter: {
2235
2241
  buildFinalEdit: () => {
2236
- if (hasSlackCustomIdentity || !previewStreamingEnabled || reply.hasMedia && !ttsSupplement || payload.isError || requiresSeparateFallbackDelivery || !previewFinalTextFitsEdit || trimmedFinalText.length === 0 && !slackBlocks?.length) return;
2242
+ const threadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
2243
+ const finalThreadTs = resolveSlackReplyThreadTs({
2244
+ replyToMode: setup.replyDeliveryMode,
2245
+ replyToId: payload.replyToId,
2246
+ threadId: threadTs,
2247
+ replyToCurrent: payload.replyToCurrent
2248
+ });
2249
+ if (hasSlackCustomIdentity || finalThreadTs !== threadTs || !previewStreamingEnabled || reply.hasMedia && !ttsSupplement || payload.isError || requiresSeparateFallbackDelivery || !previewFinalTextFitsEdit || trimmedFinalText.length === 0 && !slackBlocks?.length) return;
2237
2250
  return {
2238
2251
  text: previewFinalText,
2239
2252
  blocks: slackBlocks,
2240
- threadTs: delivery.usedReplyThreadTs ?? statusThreadTs
2253
+ threadTs
2241
2254
  };
2242
2255
  },
2243
2256
  editFinal: async (preview, edit) => {
@@ -2332,7 +2345,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2332
2345
  ...replyPipeline,
2333
2346
  transformReplyPayload: (payload) => {
2334
2347
  const transformed = replyPipeline.transformReplyPayload ? replyPipeline.transformReplyPayload(payload) : payload;
2335
- return transformed ? filterPassiveThreadFailure(transformed) : null;
2348
+ return transformed ? failurePolicy.filter(transformed) : null;
2336
2349
  },
2337
2350
  humanDelay: resolveHumanDelayConfig(cfg, route.agentId)
2338
2351
  },
@@ -2349,7 +2362,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2349
2362
  replyOptions: {
2350
2363
  onVisibleWorkSessions: progress.onVisibleWorkSessions,
2351
2364
  groupThreadReplyFormatter: formatSlackGroupThreadReply,
2352
- queuedDeliveryCorrelations: [{ begin: beginSessionRun }],
2365
+ queuedDeliveryCorrelations: [createSlackQueuedFailureNoticePolicy(failurePolicyParams, beginSessionRun)],
2353
2366
  ...turnAdoptionLifecycle ? { turnAdoptionLifecycle } : {},
2354
2367
  skillFilter: prepared.channelConfig?.skills,
2355
2368
  sourceReplyDeliveryMode,
@@ -2393,7 +2406,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2393
2406
  if (payload.kind === "preamble" && await shouldYieldDraftProgress()) return false;
2394
2407
  if (prepared.turnAdoptionLifecycle?.abortSignal?.aborted) return false;
2395
2408
  progress.progressWorkCounter.noteItem(payload);
2396
- return progress.preambleOnlyProgress && payload.kind !== "preamble" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
2409
+ return progress.preambleOnlyProgress && payload.kind !== "preamble" && payload.kind !== "model-wait" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
2397
2410
  },
2398
2411
  onPlanUpdate: async (payload) => {
2399
2412
  if (payload.phase !== "update") return false;
@@ -2407,12 +2420,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2407
2420
  settledDispatchResult = result;
2408
2421
  const agentRunOutcome = readAgentRunTerminalOutcome(result);
2409
2422
  agentRunFailed = agentRunOutcome === "failed";
2410
- if (agentRunOutcome === "completed" && !sawTerminalFailurePayload && prepared.ctxPayload.ChatType === "channel") clearSlackThreadFailureNotice({
2411
- accountId: account.accountId,
2412
- channelId: message.channel,
2413
- ...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
2414
- ...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
2415
- });
2423
+ if (agentRunOutcome === "completed") failurePolicy.complete();
2416
2424
  }
2417
2425
  } catch (err) {
2418
2426
  dispatchError ??= err;
@@ -2428,7 +2436,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2428
2436
  if (hasVisibleInboundReplyDispatch(settledDispatchResult)) await previewLifecycle.observeDelivery({ visibleReplySent: true });
2429
2437
  }
2430
2438
  await previewLifecycle.cleanup({ failed: Boolean(dispatchError || agentRunFailed) });
2431
- if (pendingFailureNotice && anyReplyDelivered) recordSlackThreadFailureNotice(pendingFailureNotice);
2439
+ if (anyReplyDelivered) failurePolicy.recordDelivered();
2432
2440
  if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error", { postIfMissing: !anyReplyDelivered });
2433
2441
  await progress.dropDetachedProgressCards();
2434
2442
  if (statusReactionsEnabled) {
@@ -2448,15 +2456,9 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
2448
2456
  if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
2449
2457
  if (!anyReplyDelivered && !previewLifecycle.previewFinalized && !(agentRunFailed && progress.useDraftProgressCard)) {
2450
2458
  if (progress.useDraftProgressCard) await draftStream?.clear();
2451
- return;
2452
- }
2453
- if (shouldLogVerbose()) {
2454
- const finalCount = resolveInboundReplyDispatchCounts(settledDispatchResult).final;
2455
- logVerbose(`slack: delivered ${finalCount} repl${finalCount === 1 ? "y" : "ies"} to ${prepared.replyTarget}`);
2456
2459
  }
2457
2460
  }
2458
- //#endregion
2459
- //#region extensions/slack/src/agent-context.ts
2461
+ // extensions/slack/src/agent-context.ts
2460
2462
  function normalizeEntity(value) {
2461
2463
  const entity = asOptionalRecord(value);
2462
2464
  const type = normalizeOptionalString(entity?.type);
@@ -2494,15 +2496,13 @@ function normalizeSlackAppContextEntities(value) {
2494
2496
  return normalized ? [normalized] : [];
2495
2497
  });
2496
2498
  }
2497
- //#endregion
2498
- //#region extensions/slack/src/monitor/thread.ts
2499
- const THREAD_STARTER_CACHE = /* @__PURE__ */ new Map();
2500
- const THREAD_STARTER_CACHE_TTL_MS = 216e5;
2501
- const THREAD_STARTER_CACHE_MAX = 2e3;
2502
- function evictThreadStarterCache() {
2503
- pruneExpiredMapEntries(THREAD_STARTER_CACHE, Date.now());
2504
- pruneMapToMaxSize(THREAD_STARTER_CACHE, THREAD_STARTER_CACHE_MAX);
2505
- }
2499
+ // extensions/slack/src/monitor/thread.ts
2500
+ const threadStarterCache = createStaleWhileRevalidateCache({
2501
+ maxEntries: 2e3,
2502
+ maxPending: Number.POSITIVE_INFINITY,
2503
+ ttlMs: 216e5,
2504
+ cacheable: (starter) => starter !== null
2505
+ });
2506
2506
  function formatSlackFilePlaceholder(files) {
2507
2507
  return `[attached: ${formatSlackFileReferenceList(files)}]`;
2508
2508
  }
@@ -2537,40 +2537,35 @@ function resolveSlackMessageText(message) {
2537
2537
  }, { preserveMessageTextWhitespace: true });
2538
2538
  }
2539
2539
  async function resolveSlackThreadStarter(params) {
2540
- evictThreadStarterCache();
2541
2540
  const cacheKey = JSON.stringify([
2542
2541
  params.workspaceScope.accountId,
2543
2542
  params.workspaceScope.teamId,
2544
2543
  params.channelId,
2545
2544
  params.threadTs
2546
2545
  ]);
2547
- const cached = THREAD_STARTER_CACHE.get(cacheKey);
2548
- if (cached && !params.refresh) return cached.value;
2549
- if (params.refresh) THREAD_STARTER_CACHE.delete(cacheKey);
2550
2546
  try {
2551
- const message = (await params.client.conversations.replies({
2552
- channel: params.channelId,
2553
- ts: params.threadTs,
2554
- limit: 1,
2555
- inclusive: true
2556
- }))?.messages?.[0];
2557
- const text = message ? resolveSlackMessageText(message) : void 0;
2558
- const files = message?.files?.length ? message.files : void 0;
2559
- if (!message || !text && !files) return null;
2560
- const starter = {
2561
- text: text || formatSlackFilePlaceholder(files),
2562
- userId: message.user,
2563
- botId: message.bot_id,
2564
- ts: message.ts,
2565
- files
2566
- };
2567
- THREAD_STARTER_CACHE.delete(cacheKey);
2568
- THREAD_STARTER_CACHE.set(cacheKey, {
2569
- value: starter,
2570
- expiresAt: Date.now() + THREAD_STARTER_CACHE_TTL_MS
2547
+ const { value } = await threadStarterCache.read(cacheKey, async () => {
2548
+ const message = (await params.client.conversations.replies({
2549
+ channel: params.channelId,
2550
+ ts: params.threadTs,
2551
+ limit: 1,
2552
+ inclusive: true
2553
+ }))?.messages?.[0];
2554
+ const text = message ? resolveSlackMessageText(message) : void 0;
2555
+ const files = message?.files?.length ? message.files : void 0;
2556
+ if (!message || !text && !files) return null;
2557
+ return {
2558
+ text: text || formatSlackFilePlaceholder(files),
2559
+ userId: message.user,
2560
+ botId: message.bot_id,
2561
+ ts: message.ts,
2562
+ files
2563
+ };
2564
+ }, {
2565
+ allowStale: false,
2566
+ refresh: params.refresh
2571
2567
  });
2572
- evictThreadStarterCache();
2573
- return starter;
2568
+ return value;
2574
2569
  } catch (err) {
2575
2570
  logVerbose(`slack thread starter fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
2576
2571
  return null;
@@ -2624,8 +2619,7 @@ async function resolveSlackThreadHistory(params) {
2624
2619
  retained.push([msg, text]);
2625
2620
  }
2626
2621
  if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
2627
- const next = response.response_metadata?.next_cursor;
2628
- cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
2622
+ cursor = normalizeOptionalString(response.response_metadata?.next_cursor);
2629
2623
  if (response.has_more && !cursor) {
2630
2624
  params.onOmission?.("Slack returned an incomplete thread page without a cursor");
2631
2625
  return [];
@@ -2674,10 +2668,9 @@ async function resolveSlackChannelHistory(params) {
2674
2668
  cursor = response.response_metadata?.next_cursor?.trim() || void 0;
2675
2669
  if (!cursor || scanned >= params.limit) break;
2676
2670
  }
2677
- return messages.slice(0, params.limit).toReversed();
2671
+ return messages.slice(0, params.limit).reverse();
2678
2672
  }
2679
- //#endregion
2680
- //#region extensions/slack/src/monitor/message-handler/preflight-audio.ts
2673
+ // extensions/slack/src/monitor/message-handler/preflight-audio.ts
2681
2674
  function isSlackAudioFile(file) {
2682
2675
  if (file.subtype === "slack_audio") return true;
2683
2676
  if ((file.mimetype?.split(";")[0]?.trim().toLowerCase())?.startsWith("audio/")) return true;
@@ -2720,13 +2713,12 @@ const sendSlackPreflightAudioTranscriptEcho = slackPreflightAudio.send.bind(slac
2720
2713
  async function discardSlackPreflightMedia(media) {
2721
2714
  await Promise.allSettled((media ?? []).map((entry) => fs.rm(entry.path, { force: true })));
2722
2715
  }
2723
- //#endregion
2724
- //#region extensions/slack/src/monitor/message-handler/prepare-content.ts
2716
+ // extensions/slack/src/monitor/message-handler/prepare-content.ts
2725
2717
  const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
2726
2718
  const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
2727
2719
  const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
2728
2720
  const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
2729
- const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-By7tvpvv.mjs").then((n) => n._));
2721
+ const loadSlackMediaModule$2 = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
2730
2722
  function formatSlackUnavailableMedia(params) {
2731
2723
  let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
2732
2724
  if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
@@ -2747,7 +2739,6 @@ function collectUniqueSlackMentionIds(texts) {
2747
2739
  const seen = /* @__PURE__ */ new Set();
2748
2740
  for (const text of texts) {
2749
2741
  if (!text) continue;
2750
- SLACK_USER_MENTION_RE$1.lastIndex = 0;
2751
2742
  for (const match of text.matchAll(SLACK_USER_MENTION_RE$1)) {
2752
2743
  const userId = match[1];
2753
2744
  if (userId) seen.add(userId);
@@ -2757,35 +2748,24 @@ function collectUniqueSlackMentionIds(texts) {
2757
2748
  }
2758
2749
  function renderSlackUserMentions(text, renderedMentions) {
2759
2750
  if (!text || renderedMentions.size === 0) return text;
2760
- SLACK_USER_MENTION_RE$1.lastIndex = 0;
2761
2751
  return text.replace(SLACK_USER_MENTION_RE$1, (full, userId) => {
2762
2752
  return renderedMentions.get(userId) ?? full;
2763
2753
  });
2764
2754
  }
2765
- function filterInheritedParentFiles(params) {
2766
- const { files, isThreadReply, threadStarter } = params;
2767
- if (!isThreadReply || !files?.length || !threadStarter?.files?.length) return files;
2768
- const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
2769
- const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
2770
- if (filtered.length < files.length) logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
2771
- return filtered.length > 0 ? filtered : void 0;
2772
- }
2773
2755
  async function resolveSlackMessageContent(params) {
2774
- const ownFiles = filterInheritedParentFiles({
2775
- files: params.message.files,
2776
- isThreadReply: params.isThreadReply,
2777
- threadStarter: params.threadStarter
2778
- });
2779
- const attachmentContent = ownFiles?.length || params.message.attachments?.length ? await loadSlackMediaModule$1().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
2756
+ let ownFiles = params.message.files;
2757
+ const { isThreadReply, threadStarter } = params;
2758
+ if (isThreadReply && ownFiles?.length && threadStarter?.files?.length) {
2759
+ const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
2760
+ const filtered = ownFiles.filter((file) => !file.id || !starterFileIds.has(file.id));
2761
+ ownFiles = filtered.length > 0 ? filtered : void 0;
2762
+ }
2763
+ const attachmentContent = ownFiles?.length || params.message.attachments?.length ? await loadSlackMediaModule$2().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
2780
2764
  files: ownFiles,
2781
2765
  attachments: params.message.attachments,
2782
2766
  client: params.client,
2783
2767
  token: params.botToken,
2784
2768
  maxBytes: params.mediaMaxBytes,
2785
- readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
2786
- totalTimeoutMs: params.mediaTotalTimeoutMs,
2787
- abortSignal: params.abortSignal,
2788
- assertCurrent: params.assertCurrent,
2789
2769
  preloadedMedia: params.preloadedMedia
2790
2770
  })) : null;
2791
2771
  const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
@@ -2834,14 +2814,13 @@ async function resolveSlackMessageContent(params) {
2834
2814
  mentionStripPatterns
2835
2815
  } : null;
2836
2816
  }
2837
- //#endregion
2838
- //#region extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
2817
+ // extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
2839
2818
  function resolveSlackDmHistoryLimit(params) {
2840
2819
  const override = params.userId ? params.account.config.dms?.[params.userId]?.historyLimit : void 0;
2841
2820
  return resolvePromptHistoryLimit(override ?? params.defaultLimit, 0);
2842
2821
  }
2843
2822
  async function resolveSlackDmHistoryContext(params) {
2844
- const maxMessages = Math.max(0, Math.floor(params.limit));
2823
+ const maxMessages = params.limit;
2845
2824
  if (maxMessages <= 0) return {
2846
2825
  body: void 0,
2847
2826
  inboundHistory: void 0
@@ -2862,7 +2841,7 @@ async function resolveSlackDmHistoryContext(params) {
2862
2841
  message,
2863
2842
  body
2864
2843
  }] : [];
2865
- }).slice(0, maxMessages).toReversed();
2844
+ }).slice(0, maxMessages).reverse();
2866
2845
  if (messages.length === 0) return {
2867
2846
  body: void 0,
2868
2847
  inboundHistory: void 0
@@ -2908,20 +2887,19 @@ async function resolveSlackDmHistoryContext(params) {
2908
2887
  };
2909
2888
  }
2910
2889
  }
2911
- //#endregion
2912
- //#region extensions/slack/src/monitor/message-handler/prepare-thread-context-root.ts
2890
+ // extensions/slack/src/monitor/message-handler/prepare-thread-context-root.ts
2913
2891
  function isSlackThreadAuthorCurrentBot(params) {
2914
2892
  const { identity, author } = params;
2915
2893
  if (identity.botUserId && author.userId && author.userId === identity.botUserId) return true;
2916
2894
  if (identity.botId && author.botId && author.botId === identity.botId) return true;
2917
2895
  return false;
2918
2896
  }
2919
- //#endregion
2920
- //#region extensions/slack/src/monitor/message-handler/prepare-room-history.ts
2897
+ // extensions/slack/src/monitor/message-handler/prepare-room-history.ts
2921
2898
  const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
2922
2899
  const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
2923
2900
  const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
2924
2901
  const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
2902
+ const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
2925
2903
  async function resolveSlackRoomHistory(params) {
2926
2904
  if (params.ctx.historyLimit <= 0 || !params.message.ts) return [];
2927
2905
  const warnOmission = (reason) => {
@@ -2975,26 +2953,51 @@ async function resolveSlackRoomHistory(params) {
2975
2953
  sender: user?.name ?? message.userId ?? `Bot (${message.botId ?? "unknown"})`
2976
2954
  });
2977
2955
  }
2956
+ async function resolveSlackHistoryMedia(message, maxAttachments) {
2957
+ const { ctx, eventScope, assertCurrent, abortSignal } = params;
2958
+ const files = sliceSlackImageFileCandidates(message.files, maxAttachments);
2959
+ const attachments = [];
2960
+ let remaining = Math.max(0, maxAttachments - files.length);
2961
+ if (remaining > 0 && message.attachments?.length) for (const attachment of message.attachments) {
2962
+ if (attachment.is_share !== true) continue;
2963
+ const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
2964
+ const attachmentFiles = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
2965
+ if (!hasImageUrl && attachmentFiles.length === 0) continue;
2966
+ attachments.push({
2967
+ ...attachment,
2968
+ files: attachmentFiles
2969
+ });
2970
+ remaining -= (hasImageUrl ? 1 : 0) + attachmentFiles.length;
2971
+ if (remaining <= 0) break;
2972
+ }
2973
+ if (files.length === 0 && attachments.length === 0) return {
2974
+ media: [],
2975
+ attempted: 0
2976
+ };
2977
+ const { resolveSlackAttachmentContent } = await loadSlackMediaModule$1();
2978
+ const content = await resolveSlackAttachmentContent({
2979
+ files,
2980
+ attachments,
2981
+ client: eventScope?.client ?? ctx.app.client,
2982
+ token: ctx.botToken,
2983
+ maxBytes: Math.min(ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
2984
+ readIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
2985
+ totalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
2986
+ assertCurrent,
2987
+ abortSignal
2988
+ });
2989
+ return {
2990
+ media: await toInboundMediaFactsWithMetadata(content?.media, {
2991
+ kind: "image",
2992
+ messageId: message.ts
2993
+ }),
2994
+ attempted: maxAttachments - remaining
2995
+ };
2996
+ }
2978
2997
  const entries = [];
2979
2998
  let mediaRemaining = SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS;
2980
2999
  for (const { message, sender } of permitted.slice(-params.ctx.historyLimit)) {
2981
- const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia({
2982
- ctx: params.ctx,
2983
- eventScope: params.eventScope,
2984
- maxAttachments: mediaRemaining,
2985
- assertCurrent: params.assertCurrent,
2986
- abortSignal: params.abortSignal,
2987
- message: {
2988
- type: "message",
2989
- channel: params.message.channel,
2990
- ts: message.ts,
2991
- user: message.userId,
2992
- bot_id: message.botId,
2993
- text: message.text,
2994
- files: message.files,
2995
- attachments: message.attachments
2996
- }
2997
- }) : {
3000
+ const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia(message, mediaRemaining) : {
2998
3001
  media: [],
2999
3002
  attempted: 0
3000
3003
  };
@@ -3021,68 +3024,15 @@ function sliceSlackImageFileCandidates(files, limit) {
3021
3024
  if (limit <= 0 || !files?.length) return [];
3022
3025
  return files.filter(isSlackImageFileCandidate).slice(0, limit);
3023
3026
  }
3024
- function sliceSlackHistoryAttachmentCandidates(attachments, limit) {
3025
- if (limit <= 0 || !attachments?.length) return [];
3026
- const out = [];
3027
- let remaining = limit;
3028
- for (const attachment of attachments) {
3029
- if (attachment.is_share !== true) continue;
3030
- const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
3031
- const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
3032
- if (!hasImageUrl && files.length === 0) continue;
3033
- out.push({
3034
- ...attachment,
3035
- files
3036
- });
3037
- remaining -= (hasImageUrl ? 1 : 0) + files.length;
3038
- if (remaining <= 0) break;
3039
- }
3040
- return out;
3041
- }
3042
- async function resolveSlackHistoryMedia(params) {
3043
- const files = sliceSlackImageFileCandidates(params.message.files, params.maxAttachments);
3044
- const attachments = sliceSlackHistoryAttachmentCandidates(params.message.attachments, Math.max(0, params.maxAttachments - files.length));
3045
- if (files.length === 0 && attachments.length === 0) return {
3046
- media: [],
3047
- attempted: 0
3048
- };
3049
- const attempted = files.length + attachments.reduce((count, attachment) => count + (normalizeOptionalString(attachment.image_url) ? 1 : 0) + (attachment.files?.length ?? 0), 0);
3050
- const content = await resolveSlackMessageContent({
3051
- message: {
3052
- ...params.message,
3053
- files,
3054
- attachments
3055
- },
3056
- isThreadReply: false,
3057
- threadStarter: null,
3058
- isBotMessage: Boolean(params.message.bot_id),
3059
- client: params.eventScope?.client ?? params.ctx.app.client,
3060
- botToken: params.ctx.botToken,
3061
- mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
3062
- mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
3063
- mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
3064
- assertCurrent: params.assertCurrent,
3065
- abortSignal: params.abortSignal
3066
- });
3067
- return {
3068
- media: await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
3069
- kind: "image",
3070
- messageId: params.message.ts
3071
- }),
3072
- attempted
3073
- };
3074
- }
3075
- //#endregion
3076
- //#region extensions/slack/src/monitor/message-handler/prepare-session-presentation.ts
3027
+ // extensions/slack/src/monitor/message-handler/prepare-session-presentation.ts
3077
3028
  function resolveSlackGroupSessionSubject(params) {
3078
3029
  const channelName = normalizeOptionalString(params.channelName);
3079
3030
  const workspaceName = normalizeOptionalString(params.installationIdentity?.kind === "workspace" && params.installationIdentity.teamId === params.workspaceId ? params.installationIdentity.teamName : void 0);
3080
3031
  if (channelName && workspaceName) return `${workspaceName} #${channelName}`;
3081
3032
  return `Slack Channel (Workspace ID: ${params.workspaceId}, Channel ID: ${params.channelId})`;
3082
3033
  }
3083
- //#endregion
3084
- //#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
3085
- const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-By7tvpvv.mjs").then((n) => n._));
3034
+ // extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
3035
+ const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
3086
3036
  const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
3087
3037
  function formatSlackThreadLabelSnippet(text) {
3088
3038
  return truncateUtf16Safe(text.replace(/\s+/g, " "), 80);
@@ -3131,13 +3081,14 @@ async function resolveSlackThreadContextData(params) {
3131
3081
  const isOutboundOnlyThreadSession = threadSessionFreshness !== void 0 && threadSessionFreshness.state !== "missing" && threadSessionFreshness.entry.lastInteractionAt === void 0 && threadSessionFreshness.entry.updatedAt !== 0;
3132
3082
  const shouldSeedInitialThreadContext = Boolean(params.isThreadReply && params.threadTs && (threadSessionFreshness ? threadSessionFreshness.state !== "fresh" || isOutboundOnlyThreadSession : threadSessionPreviousTimestamp === void 0));
3133
3083
  const shouldLoadInitialThreadHistory = shouldSeedInitialThreadContext || params.forceInitialHistory === true;
3134
- if (!params.isThreadReply || !params.threadTs) return {
3084
+ const readThreadContextData = () => ({
3135
3085
  threadStarterBody,
3136
3086
  threadHistoryBody,
3137
3087
  shouldSeedInitialThreadContext,
3138
3088
  threadLabel,
3139
3089
  threadStarterMedia
3140
- };
3090
+ });
3091
+ if (!params.isThreadReply || !params.threadTs) return readThreadContextData();
3141
3092
  const starter = params.threadStarter;
3142
3093
  const starterSenderName = params.allowNameMatching && params.allowFromLower.length > 0 && starter?.userId ? (await params.ctx.resolveUserName(starter.userId, params.eventScope))?.name : void 0;
3143
3094
  params.assertHistoryCurrent?.();
@@ -3177,10 +3128,6 @@ async function resolveSlackThreadContextData(params) {
3177
3128
  unavailableMediaCount: attachmentContent.unavailableMediaCount,
3178
3129
  prependUnavailable: true
3179
3130
  });
3180
- if (threadStarterMedia) {
3181
- const starterPlaceholders = threadStarterMedia.map((item) => item.placeholder).join(", ");
3182
- logVerbose(`slack: hydrated thread starter file ${starterPlaceholders} from root message`);
3183
- }
3184
3131
  }
3185
3132
  } else threadLabel = `Slack thread ${params.roomLabel}`;
3186
3133
  const includeBotStarterAsRootContext = Boolean(starter?.text && starterIsCurrentBot && shouldSeedInitialThreadContext);
@@ -3189,7 +3136,6 @@ async function resolveSlackThreadContextData(params) {
3189
3136
  else if (includeBotStarterAsRootContext) {
3190
3137
  const snippet = formatSlackThreadLabelSnippet(starter?.text ?? "").trim();
3191
3138
  threadLabel = `Slack thread ${params.roomLabel}${snippet ? ` (assistant root): ${snippet}` : ""}`;
3192
- logVerbose("slack: retained current-bot thread starter as assistant root context");
3193
3139
  }
3194
3140
  const threadInitialHistoryLimit = Math.min(params.account.config?.thread?.initialHistoryLimit ?? 20, params.historyLimit ?? Number.POSITIVE_INFINITY);
3195
3141
  if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
@@ -3214,28 +3160,22 @@ async function resolveSlackThreadContextData(params) {
3214
3160
  }, "Slack automatic thread history omitted");
3215
3161
  }
3216
3162
  });
3217
- if (historyOmitted) return {
3218
- threadStarterBody,
3219
- threadHistoryBody,
3220
- shouldSeedInitialThreadContext,
3221
- threadLabel,
3222
- threadStarterMedia
3223
- };
3163
+ if (historyOmitted) return readThreadContextData();
3224
3164
  const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
3225
3165
  ...starter,
3226
3166
  text: threadStarterBody,
3227
3167
  ts: currentBotRootTs
3228
3168
  } : null;
3229
- const threadHistoryWithEnrichedRoot = enrichedStarter && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [enrichedStarter, ...threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory;
3230
- const threadHistoryWithBotRoot = includeBotStarterAsRootContext && starter && !threadHistoryWithEnrichedRoot.some((entry) => entry.ts === currentBotRootTs) ? [{
3169
+ const rootContext = enrichedStarter ?? (includeBotStarterAsRootContext && starter ? {
3231
3170
  ...starter,
3232
3171
  ts: currentBotRootTs
3233
- }, ...threadHistoryWithEnrichedRoot] : threadHistoryWithEnrichedRoot;
3234
- if (threadHistoryWithBotRoot.length > 0) {
3172
+ } : null);
3173
+ const threadHistoryWithRoot = rootContext && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [rootContext, ...enrichedStarter && threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory;
3174
+ if (threadHistoryWithRoot.length > 0) {
3235
3175
  const retainCurrentBotHistory = params.isGroupDm && (isMissingThreadSession || isOutboundOnlyThreadSession);
3236
- const threadHistoryWithoutCurrentBot = threadHistoryWithBotRoot.filter((entry) => !isCurrentBotAuthor(entry) || retainCurrentBotHistory || includeBotStarterAsRootContext && entry.ts === currentBotRootTs);
3237
- const omittedCurrentBotHistoryCount = threadHistoryWithBotRoot.length - threadHistoryWithoutCurrentBot.length;
3238
- const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) : /* @__PURE__ */ new Map();
3176
+ const threadHistoryWithoutCurrentBot = threadHistoryWithRoot.filter((entry) => !isCurrentBotAuthor(entry) || retainCurrentBotHistory || includeBotStarterAsRootContext && entry.ts === currentBotRootTs);
3177
+ const omittedCurrentBotHistoryCount = threadHistoryWithRoot.length - threadHistoryWithoutCurrentBot.length;
3178
+ const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) : void 0;
3239
3179
  params.assertHistoryCurrent?.();
3240
3180
  const { items: filteredThreadHistory, omitted: omittedHistoryCount } = params.contextVisibilityMode === "all" ? {
3241
3181
  items: threadHistoryWithoutCurrentBot,
@@ -3246,7 +3186,7 @@ async function resolveSlackThreadContextData(params) {
3246
3186
  kind: "thread",
3247
3187
  isSenderAllowed: (historyMsg) => {
3248
3188
  if (isCurrentBotAuthor(historyMsg)) return true;
3249
- const msgUser = historyMsg.userId ? userMapForFilter.get(historyMsg.userId) : null;
3189
+ const msgUser = historyMsg.userId ? userMapForFilter?.get(historyMsg.userId) : null;
3250
3190
  return resolveSlackUserAllowed({
3251
3191
  allowList: params.allowFromLower,
3252
3192
  teamId: params.eventScope?.teamId ?? params.ctx.teamId,
@@ -3256,7 +3196,7 @@ async function resolveSlackThreadContextData(params) {
3256
3196
  });
3257
3197
  }
3258
3198
  });
3259
- const userMap = await resolveThreadUserMap(filteredThreadHistory);
3199
+ const userMap = userMapForFilter ?? await resolveThreadUserMap(filteredThreadHistory);
3260
3200
  params.assertHistoryCurrent?.();
3261
3201
  if (omittedHistoryCount > 0 || omittedCurrentBotHistoryCount > 0) logVerbose(`slack: omitted ${omittedHistoryCount + omittedCurrentBotHistoryCount} thread message(s) from context (mode=${params.contextVisibilityMode})`);
3262
3202
  const historyParts = [];
@@ -3275,22 +3215,12 @@ async function resolveSlackThreadContextData(params) {
3275
3215
  envelope: params.envelopeOptions
3276
3216
  }));
3277
3217
  }
3278
- if (historyParts.length > 0) {
3279
- threadHistoryBody = historyParts.join("\n\n");
3280
- logVerbose(`slack: populated thread history with ${filteredThreadHistory.length} messages for new session`);
3281
- }
3218
+ if (historyParts.length > 0) threadHistoryBody = historyParts.join("\n\n");
3282
3219
  }
3283
3220
  }
3284
- return {
3285
- threadStarterBody,
3286
- threadHistoryBody,
3287
- shouldSeedInitialThreadContext,
3288
- threadLabel,
3289
- threadStarterMedia
3290
- };
3221
+ return readThreadContextData();
3291
3222
  }
3292
- //#endregion
3293
- //#region src/channels/mention-gating.ts
3223
+ // src/channels/mention-gating.ts
3294
3224
  function resolveBotThreadMentionPolicy(params) {
3295
3225
  if (!params.isBotOwnedThread || params.requireMentionInBotThreads === void 0) return {
3296
3226
  requireMention: params.requireMention,
@@ -3301,13 +3231,11 @@ function resolveBotThreadMentionPolicy(params) {
3301
3231
  implicitMentionKinds: params.requireMentionInBotThreads ? params.implicitMentionKinds?.filter((kind) => kind === "native") : params.implicitMentionKinds
3302
3232
  };
3303
3233
  }
3304
- //#endregion
3305
- //#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/channel-mention-gating
3234
+ // \0openclaw:bundled-sdk:openclaw/plugin-sdk/channel-mention-gating
3306
3235
  var channel_mention_gating_exports = /* @__PURE__ */ __exportAll({ resolveBotThreadMentionPolicy: () => resolveBotThreadMentionPolicy });
3307
3236
  import * as import_openclaw_plugin_sdk_channel_mention_gating from "openclaw/plugin-sdk/channel-mention-gating";
3308
3237
  __reExport(channel_mention_gating_exports, import_openclaw_plugin_sdk_channel_mention_gating);
3309
- //#endregion
3310
- //#region extensions/slack/src/monitor/message-handler/prepare-thread-mentions.ts
3238
+ // extensions/slack/src/monitor/message-handler/prepare-thread-mentions.ts
3311
3239
  async function resolveSlackThreadMentionPolicy(params) {
3312
3240
  const { ctx, account, message, conversation, thread } = params;
3313
3241
  const { isRoom, isDirectMessage, channelConfig } = conversation;
@@ -3341,8 +3269,7 @@ async function resolveSlackThreadMentionPolicy(params) {
3341
3269
  implicitMentionKinds
3342
3270
  });
3343
3271
  }
3344
- //#endregion
3345
- //#region extensions/slack/src/monitor/message-handler/subteam-mentions.ts
3272
+ // extensions/slack/src/monitor/message-handler/subteam-mentions.ts
3346
3273
  const SUBTEAM_MENTION_RE = /<!subteam\^([A-Z0-9]+)(?:\|[^>]*)?>/gi;
3347
3274
  const SUBTEAM_MEMBER_CACHE_TTL_MS = 3e5;
3348
3275
  const subteamMemberCache = /* @__PURE__ */ new WeakMap();
@@ -3358,75 +3285,55 @@ function collectSlackMentionIds(text, regex) {
3358
3285
  }
3359
3286
  return [...ids];
3360
3287
  }
3361
- async function readSlackSubteamUsers(params) {
3362
- let bySubteam = subteamMemberCache.get(params.client);
3363
- if (!bySubteam) {
3364
- bySubteam = /* @__PURE__ */ new Map();
3365
- subteamMemberCache.set(params.client, bySubteam);
3366
- }
3367
- const cacheKey = `${normalizeSlackId(params.teamId) ?? ""}:${params.subteamId}`;
3368
- const cached = bySubteam.get(cacheKey);
3369
- const now = asDateTimestampMs(params.now);
3370
- if (cached) {
3371
- if (now !== void 0 && asDateTimestampMs(cached.expiresAt) !== void 0 && cached.expiresAt > now) return cached.users;
3372
- bySubteam.delete(cacheKey);
3373
- }
3374
- try {
3375
- const response = await params.client.usergroups.users.list({
3376
- usergroup: params.subteamId,
3377
- ...params.teamId ? { team_id: params.teamId } : {}
3378
- });
3379
- if (!response.ok) {
3380
- params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${response.error ?? "unknown_error"}`);
3381
- return /* @__PURE__ */ new Set();
3382
- }
3383
- const users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
3384
- const expiresAt = resolveExpiresAtMsFromDurationMs(SUBTEAM_MEMBER_CACHE_TTL_MS, { nowMs: params.now });
3385
- if (expiresAt !== void 0) bySubteam.set(cacheKey, {
3386
- expiresAt,
3387
- users
3388
- });
3389
- return users;
3390
- } catch (err) {
3391
- params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${formatErrorMessage(err)}`);
3392
- return /* @__PURE__ */ new Set();
3393
- }
3394
- }
3395
3288
  async function isSlackSubteamMentionForBot(params) {
3396
3289
  const botUserId = normalizeSlackId(params.botUserId);
3397
3290
  if (!botUserId) return false;
3398
3291
  const subteamIds = collectSlackMentionIds(params.text, SUBTEAM_MENTION_RE);
3399
3292
  if (subteamIds.length === 0) return false;
3400
- const now = params.now ?? Date.now();
3401
- for (const subteamId of subteamIds) if ((await readSlackSubteamUsers({
3402
- client: params.client,
3403
- subteamId,
3404
- teamId: normalizeOptionalString(params.teamId),
3405
- now,
3406
- log: params.log
3407
- })).has(botUserId)) return true;
3293
+ const now = Date.now();
3294
+ for (const subteamId of subteamIds) {
3295
+ const { client, log } = params;
3296
+ const teamId = normalizeOptionalString(params.teamId);
3297
+ const bySubteam = getOrCreateWeakOwnerMap(subteamMemberCache, client);
3298
+ const cacheKey = `${normalizeSlackId(teamId) ?? ""}:${subteamId}`;
3299
+ const cached = bySubteam.get(cacheKey);
3300
+ if (cached) {
3301
+ if (cached.expiresAt > now) {
3302
+ if (cached.users.has(botUserId)) return true;
3303
+ continue;
3304
+ }
3305
+ bySubteam.delete(cacheKey);
3306
+ }
3307
+ let users;
3308
+ try {
3309
+ const response = await client.usergroups.users.list({
3310
+ usergroup: subteamId,
3311
+ ...teamId ? { team_id: teamId } : {}
3312
+ });
3313
+ if (!response.ok) {
3314
+ log?.(`slack: failed to resolve user-group mention ${subteamId}: ${response.error ?? "unknown_error"}`);
3315
+ continue;
3316
+ }
3317
+ users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
3318
+ bySubteam.set(cacheKey, {
3319
+ expiresAt: now + SUBTEAM_MEMBER_CACHE_TTL_MS,
3320
+ users
3321
+ });
3322
+ } catch (err) {
3323
+ log?.(`slack: failed to resolve user-group mention ${subteamId}: ${formatErrorMessage(err)}`);
3324
+ continue;
3325
+ }
3326
+ if (users.has(botUserId)) return true;
3327
+ }
3408
3328
  return false;
3409
3329
  }
3410
- //#endregion
3411
- //#region extensions/slack/src/monitor/message-handler/prepare.ts
3330
+ // extensions/slack/src/monitor/message-handler/prepare.ts
3412
3331
  const mentionRegexCache = /* @__PURE__ */ new WeakMap();
3413
3332
  const SLACK_ANY_MENTION_RE = /<@[^>]+>|<!subteam\^[^>]+>/;
3414
3333
  const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
3415
3334
  const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
3416
3335
  const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
3417
3336
  const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
3418
- function mergeSlackAssistantThreadContext(primary, fallback) {
3419
- if (!primary) return fallback;
3420
- if (!fallback) return primary;
3421
- return {
3422
- assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
3423
- threadTs: primary.threadTs || fallback.threadTs,
3424
- userId: primary.userId ?? fallback.userId,
3425
- channelId: primary.channelId ?? fallback.channelId,
3426
- teamId: primary.teamId ?? fallback.teamId,
3427
- enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
3428
- };
3429
- }
3430
3337
  function hasSlackAssistantThreadMetadata(context) {
3431
3338
  return Boolean(context?.channelId || context?.teamId || context?.enterpriseId !== void 0);
3432
3339
  }
@@ -3440,7 +3347,6 @@ function resolveSlackMessageAssistantThreadContext(message) {
3440
3347
  return {
3441
3348
  assistantChannelId,
3442
3349
  threadTs,
3443
- userId: normalizeOptionalString(thread.user_id) ?? message.user,
3444
3350
  channelId: normalizeOptionalString(context?.channel_id),
3445
3351
  teamId: normalizeOptionalString(context?.team_id),
3446
3352
  enterpriseId: context?.enterprise_id === null ? null : normalizeOptionalString(context?.enterprise_id)
@@ -3454,8 +3360,7 @@ async function restoreSlackAssistantThreadContextFromMetadata(params) {
3454
3360
  return await readSlackAssistantThreadContext({
3455
3361
  client: params.eventScope?.client ?? params.ctx.app.client,
3456
3362
  channelId: params.message.channel,
3457
- threadTs,
3458
- userId: params.message.user
3363
+ threadTs
3459
3364
  });
3460
3365
  } catch (err) {
3461
3366
  logVerbose(`slack assistant context restore failed channel=${params.message.channel} ts=${threadTs}: ${formatErrorMessage(err)}`);
@@ -3468,41 +3373,40 @@ function resolveCachedMentionRegexes(ctx, agentId, options) {
3468
3373
  normalizeOptionalString(options?.conversationId ?? void 0),
3469
3374
  options?.providerPolicy ? JSON.stringify(options.providerPolicy) : ""
3470
3375
  ].join("");
3471
- let byAgent = mentionRegexCache.get(ctx);
3472
- if (!byAgent) {
3473
- byAgent = /* @__PURE__ */ new Map();
3474
- mentionRegexCache.set(ctx, byAgent);
3475
- }
3376
+ const byAgent = getOrCreateWeakOwnerMap(mentionRegexCache, ctx);
3476
3377
  const cached = byAgent.get(key);
3477
3378
  if (cached) return cached;
3478
3379
  const built = buildMentionRegexes(ctx.cfg, agentId, options);
3479
3380
  byAgent.set(key, built);
3480
3381
  return built;
3481
3382
  }
3482
- function collectSlackMentionMetadata(text) {
3483
- return {
3484
- mentionedUserIds: collectSlackMentionIds(text, SLACK_USER_MENTION_RE),
3485
- mentionedSubteamIds: collectSlackMentionIds(text, SLACK_SUBTEAM_MENTION_RE),
3486
- hasAnyMention: SLACK_ANY_MENTION_RE.test(text),
3487
- hasSubteamMention: text.includes(SLACK_SUBTEAM_MENTION_MARKER)
3383
+ async function prepareSlackMessage(params) {
3384
+ const { ctx, account, message, opts } = params;
3385
+ const drop = (reason, parentUserId) => {
3386
+ ctx.logger.info({
3387
+ provider: "slack",
3388
+ accountId: account.accountId,
3389
+ teamId: opts.eventScope?.teamId ?? ctx.teamId,
3390
+ channelId: message.channel,
3391
+ messageTs: message.ts,
3392
+ source: opts.source,
3393
+ reason,
3394
+ ...parentUserId ? { parentUserId } : {}
3395
+ }, "Slack inbound event rejected during preparation");
3396
+ return null;
3397
+ };
3398
+ const slackClient = opts.eventScope?.client ?? ctx.app.client;
3399
+ const threadStarterWorkspaceScope = {
3400
+ accountId: account.accountId,
3401
+ teamId: opts.eventScope?.teamId ?? ctx.teamId
3488
3402
  };
3489
- }
3490
- function resolveSlackMentionSource(params) {
3491
- if (params.explicitBotMention) return "explicit_bot";
3492
- if (params.explicitSubteamMention) return "subteam";
3493
- if (params.shouldBypassMention) return "command_bypass";
3494
- if (params.wasMentioned) return "mention_pattern";
3495
- if (params.matchedImplicitMentionKinds.length > 0) return "implicit_thread";
3496
- return "none";
3497
- }
3498
- async function resolveSlackConversationContext(params) {
3499
- const { ctx, account, message } = params;
3500
3403
  const cfg = ctx.cfg;
3404
+ const conversationEventScope = opts.eventScope;
3501
3405
  let channelInfo = {};
3502
3406
  let resolvedChannelType = normalizeSlackChannelType(message.channel_type, message.channel);
3503
3407
  if (resolvedChannelType !== "im" && message.channel_type !== "im") {
3504
- channelInfo = await ctx.resolveChannelName(message.channel, params.eventScope);
3505
- resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel, params.eventScope), message.channel);
3408
+ channelInfo = await ctx.resolveChannelName(message.channel, conversationEventScope);
3409
+ resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel, conversationEventScope), message.channel);
3506
3410
  }
3507
3411
  const channelName = channelInfo.name;
3508
3412
  const isDirectMessage = resolvedChannelType === "im";
@@ -3510,7 +3414,7 @@ async function resolveSlackConversationContext(params) {
3510
3414
  const isRoom = resolvedChannelType === "channel" || resolvedChannelType === "group";
3511
3415
  const isRoomish = isRoom || isGroupDm;
3512
3416
  const channelConfig = isRoom ? resolveSlackChannelConfig({
3513
- teamId: params.eventScope?.teamId ?? ctx.teamId,
3417
+ teamId: conversationEventScope?.teamId ?? ctx.teamId,
3514
3418
  allowUnscoped: ctx.installationIdentity?.kind !== "enterprise",
3515
3419
  channelId: message.channel,
3516
3420
  channelName,
@@ -3520,22 +3424,19 @@ async function resolveSlackConversationContext(params) {
3520
3424
  allowNameMatching: ctx.allowNameMatching
3521
3425
  }) : null;
3522
3426
  const allowBotsSetting = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ?? true;
3523
- return {
3524
- channelInfo,
3525
- channelName,
3526
- resolvedChannelType,
3527
- isDirectMessage,
3528
- isGroupDm,
3529
- isRoom,
3530
- isRoomish,
3531
- channelConfig,
3532
- allowBotsMode: allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off",
3533
- isBotMessage: Boolean(message.bot_id)
3427
+ const allowBotsMode = allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off";
3428
+ const isBotMessage = Boolean(message.bot_id);
3429
+ const messageText = message.text ?? "";
3430
+ const mentionMetadata = {
3431
+ mentionedUserIds: collectSlackMentionIds(messageText, SLACK_USER_MENTION_RE),
3432
+ mentionedSubteamIds: collectSlackMentionIds(messageText, SLACK_SUBTEAM_MENTION_RE),
3433
+ hasAnyMention: SLACK_ANY_MENTION_RE.test(messageText),
3434
+ hasSubteamMention: messageText.includes(SLACK_SUBTEAM_MENTION_MARKER)
3534
3435
  };
3535
- }
3536
- async function authorizeSlackInboundMessage(params) {
3537
- const { ctx, account, message, conversation, drop } = params;
3538
- const { isDirectMessage, channelName, resolvedChannelType, isBotMessage, allowBotsMode } = conversation;
3436
+ const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
3437
+ const explicitBotMention = opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId));
3438
+ const authorizationEventScope = opts.eventScope;
3439
+ const onVisibleDrop = opts.onVisibleDrop;
3539
3440
  if (isBotMessage) {
3540
3441
  if (ctx.botUserId && message.user === ctx.botUserId || ctx.botId && message.bot_id === ctx.botId) return null;
3541
3442
  if (allowBotsMode === "off") return drop("bot-disabled");
@@ -3544,28 +3445,28 @@ async function authorizeSlackInboundMessage(params) {
3544
3445
  const senderId = message.user ?? (isBotMessage ? message.bot_id : void 0);
3545
3446
  if (!senderId) return drop("missing-sender");
3546
3447
  if (!ctx.isChannelAllowed({
3547
- teamId: params.eventScope?.teamId ?? ctx.teamId,
3448
+ teamId: authorizationEventScope?.teamId ?? ctx.teamId,
3548
3449
  channelId: message.channel,
3549
3450
  channelName,
3550
3451
  channelType: resolvedChannelType
3551
3452
  })) {
3552
- if (conversation.isRoom && ctx.groupPolicy === "allowlist" && params.explicitBotMention && !isBotMessage && message.user) {
3453
+ if (isRoom && ctx.groupPolicy === "allowlist" && explicitBotMention && !isBotMessage && message.user) {
3553
3454
  let subject = "This OpenClaw bot";
3554
3455
  if (ctx.botUserId) try {
3555
- const botIdentity = await ctx.resolveUserName(ctx.botUserId, params.eventScope);
3456
+ const botIdentity = await ctx.resolveUserName(ctx.botUserId, authorizationEventScope);
3556
3457
  const botName = normalizeOptionalString(botIdentity?.name);
3557
3458
  if (botName) subject = escapeSlackMrkdwn(botName);
3558
3459
  } catch (error) {
3559
3460
  logVerbose(`slack allowlist denial bot-name lookup failed: ${formatSlackError(error)}`);
3560
3461
  }
3561
3462
  try {
3562
- await (params.eventScope?.client ?? ctx.app.client).chat.postEphemeral({
3463
+ await (authorizationEventScope?.client ?? ctx.app.client).chat.postEphemeral({
3563
3464
  token: ctx.botToken,
3564
3465
  channel: message.channel,
3565
3466
  user: message.user,
3566
3467
  text: `${subject} can’t reply here because this channel isn’t in its OpenClaw channel allowlist. Ask the OpenClaw owner to allow this channel. <${SLACK_CHANNEL_ACCESS_DOCS_URL}|Learn how to configure Slack channel access.>`
3567
3468
  });
3568
- params.onVisibleDrop?.();
3469
+ onVisibleDrop?.();
3569
3470
  } catch (error) {
3570
3471
  ctx.runtime.error?.(`slack allowlist denial notice failed for channel ${message.channel}: ${formatSlackError(error)}`);
3571
3472
  }
@@ -3574,7 +3475,7 @@ async function authorizeSlackInboundMessage(params) {
3574
3475
  }
3575
3476
  const allowFromLower = await resolveSlackEffectiveAllowFrom(ctx, {
3576
3477
  includePairingStore: isDirectMessage,
3577
- eventScope: params.eventScope
3478
+ eventScope: authorizationEventScope
3578
3479
  });
3579
3480
  if (isDirectMessage) {
3580
3481
  const directUserId = message.user;
@@ -3584,16 +3485,16 @@ async function authorizeSlackInboundMessage(params) {
3584
3485
  ctx,
3585
3486
  accountId: account.accountId,
3586
3487
  senderId: directUserId,
3587
- eventScope: params.eventScope,
3488
+ eventScope: authorizationEventScope,
3588
3489
  allowFromLower,
3589
- resolveSenderName: (userId) => ctx.resolveUserName(userId, params.eventScope),
3490
+ resolveSenderName: (userId) => ctx.resolveUserName(userId, authorizationEventScope),
3590
3491
  sendPairingReply: async (text) => {
3591
3492
  await sendMessageSlack(message.channel, text, {
3592
3493
  cfg: ctx.cfg,
3593
3494
  token: ctx.botToken,
3594
- client: params.eventScope?.client ?? ctx.app.client,
3495
+ client: authorizationEventScope?.client ?? ctx.app.client,
3595
3496
  accountId: account.accountId,
3596
- eventScope: params.eventScope
3497
+ eventScope: authorizationEventScope
3597
3498
  });
3598
3499
  },
3599
3500
  onDisabled: () => {
@@ -3605,54 +3506,6 @@ async function authorizeSlackInboundMessage(params) {
3605
3506
  log: logVerbose
3606
3507
  })) return drop(dropReason);
3607
3508
  }
3608
- return {
3609
- senderId,
3610
- allowFromLower
3611
- };
3612
- }
3613
- async function prepareSlackMessage(params) {
3614
- const { ctx, account, message, opts } = params;
3615
- const drop = (reason, parentUserId) => {
3616
- ctx.logger.info({
3617
- provider: "slack",
3618
- accountId: account.accountId,
3619
- teamId: opts.eventScope?.teamId ?? ctx.teamId,
3620
- channelId: message.channel,
3621
- messageTs: message.ts,
3622
- source: opts.source,
3623
- reason,
3624
- ...parentUserId ? { parentUserId } : {}
3625
- }, "Slack inbound event rejected during preparation");
3626
- return null;
3627
- };
3628
- const slackClient = opts.eventScope?.client ?? ctx.app.client;
3629
- const threadStarterWorkspaceScope = {
3630
- accountId: account.accountId,
3631
- teamId: opts.eventScope?.teamId ?? ctx.teamId
3632
- };
3633
- const cfg = ctx.cfg;
3634
- const conversation = await resolveSlackConversationContext({
3635
- ctx,
3636
- account,
3637
- message,
3638
- eventScope: opts.eventScope
3639
- });
3640
- const { channelInfo, channelName, isDirectMessage, isGroupDm, isRoom, isRoomish, channelConfig, allowBotsMode, isBotMessage } = conversation;
3641
- const messageText = message.text ?? "";
3642
- const mentionMetadata = collectSlackMentionMetadata(messageText);
3643
- const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
3644
- const authorization = await authorizeSlackInboundMessage({
3645
- ctx,
3646
- account,
3647
- message,
3648
- conversation,
3649
- explicitBotMention: opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId)),
3650
- eventScope: opts.eventScope,
3651
- onVisibleDrop: opts.onVisibleDrop,
3652
- drop
3653
- });
3654
- if (!authorization) return null;
3655
- const { senderId, allowFromLower } = authorization;
3656
3509
  let resolvedSenderName = normalizeOptionalString(message.username);
3657
3510
  const resolveSenderName = async () => {
3658
3511
  if (resolvedSenderName) return resolvedSenderName;
@@ -3688,9 +3541,17 @@ async function prepareSlackMessage(params) {
3688
3541
  });
3689
3542
  const explicitlyMentioned = explicitlyMentionedBotUser || explicitlyMentionedBotSubteam || opts.source === "app_mention";
3690
3543
  const channelRequireMention = channelConfig?.requireMention ?? ctx.defaultRequireMention ?? true;
3691
- const chatType = resolveSlackChatType(conversation.resolvedChannelType);
3544
+ const chatType = resolveSlackChatType(resolvedChannelType);
3692
3545
  const restoredAssistantThreadContext = await restoredAssistantThreadContextPromise;
3693
- const assistantThreadContext = mergeSlackAssistantThreadContext(messageAssistantThreadContext, cachedAssistantThreadContext ?? restoredAssistantThreadContext);
3546
+ const primary = messageAssistantThreadContext;
3547
+ const fallback = cachedAssistantThreadContext ?? restoredAssistantThreadContext;
3548
+ const assistantThreadContext = !primary ? fallback : !fallback ? primary : {
3549
+ assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
3550
+ threadTs: primary.threadTs || fallback.threadTs,
3551
+ channelId: primary.channelId ?? fallback.channelId,
3552
+ teamId: primary.teamId ?? fallback.teamId,
3553
+ enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
3554
+ };
3694
3555
  const assistantThreadContextToCache = messageAssistantThreadContext || restoredAssistantThreadContext ? assistantThreadContext : void 0;
3695
3556
  if (assistantThreadContextToCache) ctx.saveSlackAssistantThreadContext(assistantThreadContextToCache, opts.eventScope);
3696
3557
  const canUseManagedView = isDirectMessage && !opts.eventScope && !assistantThreadContext;
@@ -3754,19 +3615,16 @@ async function prepareSlackMessage(params) {
3754
3615
  let mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
3755
3616
  let wasMentioned = resolveWasMentioned(mentionRegexes);
3756
3617
  const hasBoundSession = Boolean(routing.runtimeBoundSessionKey || routing.configuredBindingSessionKey);
3757
- const { configuredBinding, configuredBindingSessionKey } = routing;
3618
+ const { configuredBinding } = routing;
3758
3619
  const isAssistantThreadMessage = Boolean(isDirectMessage && messageAssistantThreadContext);
3759
3620
  const forcedAssistantReplyThreadTs = Boolean(assistantThreadContext?.threadTs && (routing.isThreadReply || isAssistantThreadMessage || routing.replyToMode !== "off")) ? assistantThreadContext?.threadTs : void 0;
3760
3621
  const forcedReplyThreadTs = agentViewThreadTs ?? forcedAssistantReplyThreadTs;
3761
- if (routing.runtimeBinding && shouldLogVerbose()) logVerbose(`slack: routed via bound conversation ${routing.runtimeBinding.conversation.conversationId} -> ${routing.runtimeBinding.targetSessionKey}`);
3762
3622
  if (configuredBinding) {
3763
3623
  const ensured = await ensureConfiguredBindingRouteReady({
3764
3624
  cfg,
3765
3625
  bindingResolution: configuredBinding
3766
3626
  });
3767
- if (ensured.ok) {
3768
- if (shouldLogVerbose()) logVerbose(`slack: using configured ACP binding for ${configuredBinding.record.conversation.conversationId} -> ${configuredBindingSessionKey}`);
3769
- } else {
3627
+ if (!ensured.ok) {
3770
3628
  if (shouldLogVerbose()) logVerbose(`slack: configured ACP binding unavailable for ${configuredBinding.record.conversation.conversationId}: ${ensured.error}`);
3771
3629
  return drop("configured-binding-unavailable");
3772
3630
  }
@@ -3804,7 +3662,11 @@ async function prepareSlackMessage(params) {
3804
3662
  ctx,
3805
3663
  account,
3806
3664
  message,
3807
- conversation,
3665
+ conversation: {
3666
+ isRoom,
3667
+ isDirectMessage,
3668
+ channelConfig
3669
+ },
3808
3670
  thread: routing,
3809
3671
  wasMentioned,
3810
3672
  teamId: opts.eventScope?.teamId,
@@ -3822,14 +3684,14 @@ async function prepareSlackMessage(params) {
3822
3684
  const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
3823
3685
  const hasControlCommandInMessage = hasControlCommand(textForCommandDetection, cfg);
3824
3686
  const hasAbortRequest = isAbortRequestText(textForCommandDetection);
3825
- const channelUsersAllowlistConfigured = isRoom && Array.isArray(channelConfig?.users) && channelConfig.users.length > 0;
3687
+ const channelUsersAllowlistConfigured = isRoom && (channelConfig?.users?.length ?? 0) > 0;
3826
3688
  const resolveMessageIngress = async (contextBinding, threadId) => await resolveSlackCommandIngress({
3827
3689
  ctx,
3828
3690
  teamId: opts.eventScope?.teamId ?? ctx.teamId,
3829
3691
  senderId,
3830
3692
  senderAuthentication: message.user ? opts.senderAuthentication : void 0,
3831
3693
  senderName: senderNameForAuth,
3832
- channelType: conversation.resolvedChannelType ?? "channel",
3694
+ channelType: resolvedChannelType ?? "channel",
3833
3695
  channelId: message.channel,
3834
3696
  threadId,
3835
3697
  ownerAllowFromLower: allowFromLower,
@@ -3964,13 +3826,7 @@ async function prepareSlackMessage(params) {
3964
3826
  const effectiveWasMentioned = mentionDecision.effectiveWasMentioned;
3965
3827
  const shouldBypassMention = mentionDecision.shouldBypassMention;
3966
3828
  const matchedImplicitMentionKinds = mentionDecision.matchedImplicitMentionKinds;
3967
- const mentionSource = resolveSlackMentionSource({
3968
- explicitBotMention: explicitlyMentionedBotUser || opts.source === "app_mention",
3969
- explicitSubteamMention: explicitlyMentionedBotSubteam,
3970
- matchedImplicitMentionKinds,
3971
- shouldBypassMention,
3972
- wasMentioned
3973
- });
3829
+ const mentionSource = explicitlyMentionedBotUser || opts.source === "app_mention" ? "explicit_bot" : explicitlyMentionedBotSubteam ? "subteam" : shouldBypassMention ? "command_bypass" : wasMentioned ? "mention_pattern" : matchedImplicitMentionKinds.length > 0 ? "implicit_thread" : "none";
3974
3830
  if (isBotMessage && allowBotsMode === "mentions") {
3975
3831
  if (!(isDirectMessage || effectiveWasMentioned || shouldBypassMention)) return drop("bot-missing-mention");
3976
3832
  }
@@ -4301,7 +4157,6 @@ async function prepareSlackMessage(params) {
4301
4157
  originatingTo: preflightChannelTarget,
4302
4158
  messageThreadId: threadContext.messageThreadId
4303
4159
  });
4304
- if (shouldLogVerbose()) logVerbose(`slack inbound: account=${route.accountId} agent=${route.agentId} channel=${message.channel} message_ts=${message.ts ?? "unknown"} thread_ts=${effectiveMessageThreadId ?? "none"} from=${slackFrom} chat=${chatType} chars=${rawBody.length}`);
4305
4160
  const updateLastRouteSessionKey = resolveInboundLastRouteSessionKey({
4306
4161
  route,
4307
4162
  sessionKey
@@ -4350,5 +4205,4 @@ async function prepareSlackMessage(params) {
4350
4205
  ackReactionPromise
4351
4206
  };
4352
4207
  }
4353
- //#endregion
4354
4208
  export { dispatchPreparedSlackMessage, prepareSlackMessage };