@spacebar_ai/moldclaw-core 2026.3.41 → 2026.3.44

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 (1144) hide show
  1. package/dist/accounts-5qY-dKca.d.ts +103 -0
  2. package/dist/accounts-SqdHz2ZP.js +114 -0
  3. package/dist/acp-cli-E6bcNqiE.js +2093 -0
  4. package/dist/actions.runtime-BU_XMuLk.js +119 -0
  5. package/dist/actions.runtime-CY5h8lqH.js +133 -0
  6. package/dist/agent-scope-lZlwP1At.js +208 -0
  7. package/dist/agents-C4SkadR1.js +853 -0
  8. package/dist/agents-RfwqGCzE.js +222 -0
  9. package/dist/agents.config-CX9CPNfP.js +17 -0
  10. package/dist/agents.config-DF9Zwn9n.js +121 -0
  11. package/dist/allow-list-3WSjz1zl.js +81 -0
  12. package/dist/allowlist-DNbDjFjw.js +142 -0
  13. package/dist/api-BEOpJ7dR.js +117 -0
  14. package/dist/audit-CpJz_eu6.js +787 -0
  15. package/dist/audit-CpfSjvyo.js +54 -0
  16. package/dist/audit-channel.collect.runtime-BeGotloZ.js +605 -0
  17. package/dist/audit-channel.runtime-BJDZ7ETt.js +121 -0
  18. package/dist/audit-extra.async-C2G0mqmk.js +813 -0
  19. package/dist/audit-membership-runtime-B1FqJsPV.js +162 -0
  20. package/dist/audit.deep.runtime-DyL9O_sU.js +25 -0
  21. package/dist/audit.nondeep.runtime-C6jFgJfH.js +832 -0
  22. package/dist/audit.runtime-Dnlsn23e.js +118 -0
  23. package/dist/auth-Ch3Rchm4.js +101 -0
  24. package/dist/auth-choice-CEFSlnLT.js +122 -0
  25. package/dist/auth-choice-CVCef-eU.js +268 -0
  26. package/dist/auth-choice-Cez-pXrg.js +507 -0
  27. package/dist/auth-choice-options-DO78mvPe.js +123 -0
  28. package/dist/auth-choice-prompt-CUkC7Mmb.js +36 -0
  29. package/dist/auth-choice-prompt-DCuQRiVl.js +115 -0
  30. package/dist/auth-choice.apply-helpers-BhbNIV8X.js +66 -0
  31. package/dist/auth-choice.plugin-providers.runtime-4BhqvEw_.js +119 -0
  32. package/dist/auth-profiles-smABVXzp.js +128040 -0
  33. package/dist/auth-profiles.runtime-Cr-ojtTc.js +116 -0
  34. package/dist/banner-CojBHPWr.js +342 -0
  35. package/dist/bluebubbles-BnLsj2Fy.d.ts +6 -0
  36. package/dist/bluebubbles-CVk7M3Bl.js +64 -0
  37. package/dist/bot-DdyrB2z9.d.ts +478 -0
  38. package/dist/brave-w4Fo8WZ3.js +24 -0
  39. package/dist/browser-cli-DWFs3P_i.js +1494 -0
  40. package/dist/build-info.json +3 -3
  41. package/dist/bundled/boot-md/handler.d.ts +1 -1
  42. package/dist/bundled/boot-md/handler.js +35 -35
  43. package/dist/bundled/bootstrap-extra-files/handler.d.ts +1 -1
  44. package/dist/bundled/bootstrap-extra-files/handler.js +1 -1
  45. package/dist/bundled/command-logger/handler.d.ts +1 -1
  46. package/dist/bundled/session-memory/handler.d.ts +1 -1
  47. package/dist/bundled/session-memory/handler.js +36 -36
  48. package/dist/call-Do7wTSr7.js +39 -0
  49. package/dist/call-gdDAt07d.js +640 -0
  50. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  51. package/dist/channel-B26pkce0.js +214 -0
  52. package/dist/channel-BJHp0AQC.js +352 -0
  53. package/dist/channel-BKFOv51P.js +4681 -0
  54. package/dist/channel-BNgpOY8v.js +538 -0
  55. package/dist/channel-BcQAAo2P.js +226 -0
  56. package/dist/channel-BvNdnhbx.js +1598 -0
  57. package/dist/channel-C1Rda3Jd.js +306 -0
  58. package/dist/channel-C87DG-F7.js +803 -0
  59. package/dist/channel-CIip0kvZ.js +619 -0
  60. package/dist/channel-CTPxoT_E2.js +316 -0
  61. package/dist/channel-CklaCzUG.js +562 -0
  62. package/dist/channel-CoJnAdLs.js +920 -0
  63. package/dist/channel-D3tafL1_.js +949 -0
  64. package/dist/channel-DFMrP2uu.js +542 -0
  65. package/dist/channel-DMd5cJQe.js +397 -0
  66. package/dist/channel-Dm34kxAJ.js +207 -0
  67. package/dist/channel-DmwF9udn.js +1321 -0
  68. package/dist/channel-account-context-Bjur9nlh.js +103 -0
  69. package/dist/channel-bGnST659.js +943 -0
  70. package/dist/channel-hIgbkTZf.js +575 -0
  71. package/dist/channel-m_TGrDKo.js +497 -0
  72. package/dist/channel-options-DoUPBMa8.js +50 -0
  73. package/dist/channel-plugin-ids-TZIY4hFs.js +26 -0
  74. package/dist/channel-summary-qD54bOBO.js +111 -0
  75. package/dist/channel.runtime-B0H04Dkk.js +199 -0
  76. package/dist/channel.runtime-BU1f3NkV.js +418 -0
  77. package/dist/channel.runtime-Bj1sfLep.js +4011 -0
  78. package/dist/channel.runtime-BtPAAJc3.js +870 -0
  79. package/dist/channel.runtime-Bx-10m_j.js +171 -0
  80. package/dist/channel.runtime-CI_TBywQ.js +179 -0
  81. package/dist/channel.runtime-CSLj14-Z.js +182 -0
  82. package/dist/channel.runtime-D-lTSYAd.js +404 -0
  83. package/dist/channel.runtime-DJqIOSji.js +127 -0
  84. package/dist/channel.runtime-Ec8aQ9V2.js +241 -0
  85. package/dist/channel.runtime-ax5a1jBm.js +218 -0
  86. package/dist/channel.setup-B-ncdYLT.js +9 -0
  87. package/dist/channel.setup-BY4bh5dm.js +9 -0
  88. package/dist/channel.setup-BovsdMnL.js +57 -0
  89. package/dist/channel.setup-CXzXA25h.js +6 -0
  90. package/dist/channel.setup-DcZUEufN.js +8 -0
  91. package/dist/channel.setup-E6zceRsE.js +8 -0
  92. package/dist/channel.setup-Pc7nGbdX.js +11 -0
  93. package/dist/channels/plugins/actions/discord.d.ts +2 -2
  94. package/dist/channels/plugins/actions/discord.js +35 -35
  95. package/dist/channels/plugins/actions/signal.d.ts +1 -1
  96. package/dist/channels/plugins/actions/signal.js +35 -35
  97. package/dist/channels/plugins/actions/telegram.d.ts +2 -2
  98. package/dist/channels/plugins/actions/telegram.js +35 -35
  99. package/dist/channels/plugins/agent-tools/whatsapp-login.d.ts +3 -3
  100. package/dist/channels/plugins/agent-tools/whatsapp-login.js +35 -35
  101. package/dist/channels-CPtE5ND6.js +404 -0
  102. package/dist/channels-Cj8ZolHI.js +1118 -0
  103. package/dist/channels-cli-D2sKrntt.js +291 -0
  104. package/dist/channels-status-issues-CzIHODg2.js +16 -0
  105. package/dist/clawbot-cli-BcwEDmUn.js +118 -0
  106. package/dist/cleanup-utils-D0L17RsX.js +96 -0
  107. package/dist/cli/daemon-cli.js +1 -1
  108. package/dist/cli-BvGVPKnD.js +154 -0
  109. package/dist/command-registry-CADQzTAg.js +14 -0
  110. package/dist/command-registry-ktiJNAJd.js +242 -0
  111. package/dist/command-secret-gateway-CXp10RTM.js +111 -0
  112. package/dist/compact.runtime-DyKL-Iar.js +116 -0
  113. package/dist/completion-cli-Bz4STrpt.js +17 -0
  114. package/dist/completion-cli-pVda2OFb.js +445 -0
  115. package/dist/config-BbvDRSYp.js +31 -0
  116. package/dist/config-CwBv71QC.js +44 -0
  117. package/dist/config-cli-Y0uXHbOw.js +678 -0
  118. package/dist/config-guard-BpW5g7JE.js +118 -0
  119. package/dist/config-validation-B-vLIsbo.js +262 -0
  120. package/dist/config-value-DT3-5958.js +132 -0
  121. package/dist/configure-B9U-jCqP.js +1100 -0
  122. package/dist/configure-BJ3Wrs5b.js +243 -0
  123. package/dist/control-ui-assets-C1YDYi82.js +232 -0
  124. package/dist/control-ui-shared-Dm5Dh0Lo.js +29 -0
  125. package/dist/core-BwKq3krw.js +150 -0
  126. package/dist/core-hjBwfDsW.d.ts +87 -0
  127. package/dist/cron-cli-DTDgfoMh.js +639 -0
  128. package/dist/daemon-cli-C-dkAXR1.js +339 -0
  129. package/dist/daemon-install-Oy0Q5pMF.js +180 -0
  130. package/dist/deliver-DNGnDqF9.js +111 -0
  131. package/dist/deliver-runtime-CCNZIhET.js +111 -0
  132. package/dist/device-id-cli-XvwZbIyC.js +52 -0
  133. package/dist/device-identity-IG5DngWM.js +365 -0
  134. package/dist/devices-cli-DIsxj4xp.js +342 -0
  135. package/dist/diagnostic-DTPopFvh.js +310 -0
  136. package/dist/directory-cli-DTSY3Ktr.js +311 -0
  137. package/dist/directory-config-helpers-DpFcAbmo.d.ts +38 -0
  138. package/dist/directory.static-CBRAUwUW.js +44 -0
  139. package/dist/discord-CrgxhEWw.js +114 -0
  140. package/dist/discovery-DrG7wmAR.js +48 -0
  141. package/dist/dm-policy-shared-DKoGdUpY.d.ts +95 -0
  142. package/dist/dns-cli-BJiz6CLK.js +217 -0
  143. package/dist/docs-cli-Dq2Yi5qO.js +174 -0
  144. package/dist/doctor-completion-D3GeVcFP.js +90 -0
  145. package/dist/doctor-config-flow-B1cMjr8h.js +112 -0
  146. package/dist/doctor-config-flow-BUe7JpV3.js +2437 -0
  147. package/dist/enable-Bc8bCuVe.js +24 -0
  148. package/dist/entry.js +4 -4
  149. package/dist/exec-approvals-cli-kLAev6bP.js +421 -0
  150. package/dist/extensions/acpx/index.d.ts +1 -1
  151. package/dist/extensions/amazon-bedrock/index.d.ts +1 -1
  152. package/dist/extensions/amazon-bedrock/index.js +4 -4
  153. package/dist/extensions/anthropic/index.d.ts +1 -1
  154. package/dist/extensions/anthropic/index.js +35 -35
  155. package/dist/extensions/bluebubbles/index.d.ts +1 -1
  156. package/dist/extensions/bluebubbles/index.js +39 -39
  157. package/dist/extensions/bluebubbles/setup-entry.d.ts +2 -2
  158. package/dist/extensions/bluebubbles/setup-entry.js +39 -39
  159. package/dist/extensions/brave/index.d.ts +1 -1
  160. package/dist/extensions/brave/index.js +5 -5
  161. package/dist/extensions/byteplus/index.d.ts +1 -1
  162. package/dist/extensions/byteplus/index.js +35 -35
  163. package/dist/extensions/cloudflare-ai-gateway/index.d.ts +1 -1
  164. package/dist/extensions/cloudflare-ai-gateway/index.js +36 -36
  165. package/dist/extensions/copilot-proxy/index.d.ts +1 -1
  166. package/dist/extensions/copilot-proxy/index.js +4 -4
  167. package/dist/extensions/device-pair/index.d.ts +1 -1
  168. package/dist/extensions/device-pair/index.js +4 -4
  169. package/dist/extensions/diagnostics-otel/index.d.ts +1 -1
  170. package/dist/extensions/diagnostics-otel/index.js +4 -4
  171. package/dist/extensions/diffs/index.d.ts +1 -1
  172. package/dist/extensions/discord/index.d.ts +1 -1
  173. package/dist/extensions/discord/index.js +40 -40
  174. package/dist/extensions/discord/setup-entry.d.ts +1 -1
  175. package/dist/extensions/discord/setup-entry.js +38 -38
  176. package/dist/extensions/elevenlabs/index.d.ts +1 -1
  177. package/dist/extensions/elevenlabs/index.js +35 -35
  178. package/dist/extensions/feishu/index.d.ts +2 -2
  179. package/dist/extensions/feishu/index.js +40 -40
  180. package/dist/extensions/feishu/setup-entry.d.ts +2 -2
  181. package/dist/extensions/feishu/setup-entry.js +37 -37
  182. package/dist/extensions/firecrawl/index.d.ts +1 -1
  183. package/dist/extensions/firecrawl/index.js +35 -35
  184. package/dist/extensions/github-copilot/index.d.ts +1 -1
  185. package/dist/extensions/github-copilot/index.js +35 -35
  186. package/dist/extensions/google/index.d.ts +1 -1
  187. package/dist/extensions/google/index.js +35 -35
  188. package/dist/extensions/googlechat/index.d.ts +1 -1
  189. package/dist/extensions/googlechat/index.js +38 -38
  190. package/dist/extensions/googlechat/setup-entry.d.ts +1 -1
  191. package/dist/extensions/googlechat/setup-entry.js +38 -38
  192. package/dist/extensions/huggingface/index.d.ts +1 -1
  193. package/dist/extensions/huggingface/index.js +35 -35
  194. package/dist/extensions/imessage/index.d.ts +1 -1
  195. package/dist/extensions/imessage/index.js +39 -39
  196. package/dist/extensions/imessage/setup-entry.d.ts +1 -1
  197. package/dist/extensions/imessage/setup-entry.js +39 -39
  198. package/dist/extensions/irc/index.d.ts +1 -1
  199. package/dist/extensions/irc/index.js +38 -38
  200. package/dist/extensions/irc/setup-entry.d.ts +2 -2
  201. package/dist/extensions/irc/setup-entry.js +38 -38
  202. package/dist/extensions/kakao-talkchannel/index.d.ts +1 -1
  203. package/dist/extensions/kakao-talkchannel/index.js +4 -4
  204. package/dist/extensions/kilocode/index.d.ts +1 -1
  205. package/dist/extensions/kilocode/index.js +35 -35
  206. package/dist/extensions/kimi-coding/index.d.ts +1 -1
  207. package/dist/extensions/kimi-coding/index.js +35 -35
  208. package/dist/extensions/line/index.d.ts +1 -1
  209. package/dist/extensions/line/index.js +37 -37
  210. package/dist/extensions/line/setup-entry.d.ts +1 -1
  211. package/dist/extensions/line/setup-entry.js +37 -37
  212. package/dist/extensions/llm-task/index.d.ts +1 -1
  213. package/dist/extensions/llm-task/index.js +35 -35
  214. package/dist/extensions/lobster/index.d.ts +1 -1
  215. package/dist/extensions/lobster/index.js +4 -4
  216. package/dist/extensions/matrix/index.d.ts +1 -1
  217. package/dist/extensions/matrix/index.js +40 -40
  218. package/dist/extensions/matrix/setup-entry.d.ts +2 -2
  219. package/dist/extensions/matrix/setup-entry.js +40 -40
  220. package/dist/extensions/mattermost/index.d.ts +1 -1
  221. package/dist/extensions/mattermost/index.js +37 -37
  222. package/dist/extensions/mattermost/setup-entry.d.ts +2 -2
  223. package/dist/extensions/mattermost/setup-entry.js +37 -37
  224. package/dist/extensions/memory-core/index.d.ts +1 -1
  225. package/dist/extensions/memory-core/index.js +4 -4
  226. package/dist/extensions/memory-lancedb/index.d.ts +1 -1
  227. package/dist/extensions/memory-lancedb/index.js +4 -4
  228. package/dist/extensions/microsoft/index.d.ts +1 -1
  229. package/dist/extensions/microsoft/index.js +35 -35
  230. package/dist/extensions/minimax/index.d.ts +1 -1
  231. package/dist/extensions/minimax/index.js +35 -35
  232. package/dist/extensions/mistral/index.d.ts +1 -1
  233. package/dist/extensions/mistral/index.js +35 -35
  234. package/dist/extensions/modelstudio/index.d.ts +1 -1
  235. package/dist/extensions/modelstudio/index.js +35 -35
  236. package/dist/extensions/moonshot/index.d.ts +1 -1
  237. package/dist/extensions/moonshot/index.js +35 -35
  238. package/dist/extensions/msteams/index.d.ts +1 -1
  239. package/dist/extensions/msteams/index.js +40 -40
  240. package/dist/extensions/msteams/setup-entry.d.ts +1 -1
  241. package/dist/extensions/msteams/setup-entry.js +40 -40
  242. package/dist/extensions/nextcloud-talk/index.d.ts +1 -1
  243. package/dist/extensions/nextcloud-talk/index.js +37 -37
  244. package/dist/extensions/nextcloud-talk/setup-entry.d.ts +2 -2
  245. package/dist/extensions/nextcloud-talk/setup-entry.js +37 -37
  246. package/dist/extensions/nostr/index.d.ts +1 -1
  247. package/dist/extensions/nostr/index.js +37 -37
  248. package/dist/extensions/nostr/setup-entry.d.ts +1 -1
  249. package/dist/extensions/nostr/setup-entry.js +37 -37
  250. package/dist/extensions/nvidia/index.d.ts +1 -1
  251. package/dist/extensions/nvidia/index.js +4 -4
  252. package/dist/extensions/ollama/index.d.ts +1 -1
  253. package/dist/extensions/ollama/index.js +7 -7
  254. package/dist/extensions/open-prose/index.d.ts +1 -1
  255. package/dist/extensions/open-prose/index.js +4 -4
  256. package/dist/extensions/openai/index.d.ts +1 -1
  257. package/dist/extensions/openai/index.js +35 -35
  258. package/dist/extensions/opencode/index.d.ts +1 -1
  259. package/dist/extensions/opencode/index.js +35 -35
  260. package/dist/extensions/opencode-go/index.d.ts +1 -1
  261. package/dist/extensions/opencode-go/index.js +35 -35
  262. package/dist/extensions/openrouter/index.d.ts +1 -1
  263. package/dist/extensions/openrouter/index.js +35 -35
  264. package/dist/extensions/openshell/index.d.ts +1 -1
  265. package/dist/extensions/openshell/index.js +35 -35
  266. package/dist/extensions/perplexity/index.d.ts +1 -1
  267. package/dist/extensions/perplexity/index.js +5 -5
  268. package/dist/extensions/phone-control/index.d.ts +1 -1
  269. package/dist/extensions/phone-control/index.js +4 -4
  270. package/dist/extensions/qianfan/index.d.ts +1 -1
  271. package/dist/extensions/qianfan/index.js +35 -35
  272. package/dist/extensions/qwen-portal-auth/index.d.ts +1 -1
  273. package/dist/extensions/qwen-portal-auth/index.js +35 -35
  274. package/dist/extensions/sglang/index.d.ts +1 -1
  275. package/dist/extensions/sglang/index.js +35 -35
  276. package/dist/extensions/signal/index.d.ts +1 -1
  277. package/dist/extensions/signal/index.js +38 -38
  278. package/dist/extensions/signal/setup-entry.d.ts +1 -1
  279. package/dist/extensions/signal/setup-entry.js +38 -38
  280. package/dist/extensions/slack/index.d.ts +1 -1
  281. package/dist/extensions/slack/index.js +39 -39
  282. package/dist/extensions/slack/setup-entry.d.ts +1 -1
  283. package/dist/extensions/slack/setup-entry.js +38 -38
  284. package/dist/extensions/synology-chat/index.d.ts +1 -1
  285. package/dist/extensions/synology-chat/index.js +37 -37
  286. package/dist/extensions/synology-chat/setup-entry.d.ts +1 -1
  287. package/dist/extensions/synology-chat/setup-entry.js +37 -37
  288. package/dist/extensions/synthetic/index.d.ts +1 -1
  289. package/dist/extensions/synthetic/index.js +35 -35
  290. package/dist/extensions/talk-voice/index.d.ts +1 -1
  291. package/dist/extensions/talk-voice/index.js +35 -35
  292. package/dist/extensions/telegram/index.d.ts +1 -1
  293. package/dist/extensions/telegram/index.js +38 -38
  294. package/dist/extensions/telegram/setup-entry.d.ts +1 -1
  295. package/dist/extensions/telegram/setup-entry.js +37 -37
  296. package/dist/extensions/thread-ownership/index.d.ts +1 -1
  297. package/dist/extensions/thread-ownership/index.js +4 -4
  298. package/dist/extensions/tlon/index.d.ts +1 -1
  299. package/dist/extensions/tlon/index.js +37 -37
  300. package/dist/extensions/tlon/setup-entry.d.ts +1 -1
  301. package/dist/extensions/tlon/setup-entry.js +37 -37
  302. package/dist/extensions/together/index.d.ts +1 -1
  303. package/dist/extensions/together/index.js +35 -35
  304. package/dist/extensions/twitch/index.d.ts +2 -2
  305. package/dist/extensions/twitch/index.js +37 -37
  306. package/dist/extensions/venice/index.d.ts +1 -1
  307. package/dist/extensions/venice/index.js +35 -35
  308. package/dist/extensions/vercel-ai-gateway/index.d.ts +1 -1
  309. package/dist/extensions/vercel-ai-gateway/index.js +36 -36
  310. package/dist/extensions/vllm/index.d.ts +1 -1
  311. package/dist/extensions/vllm/index.js +35 -35
  312. package/dist/extensions/voice-call/index.d.ts +1 -1
  313. package/dist/extensions/voice-call/index.js +35 -35
  314. package/dist/extensions/volcengine/index.d.ts +1 -1
  315. package/dist/extensions/volcengine/index.js +35 -35
  316. package/dist/extensions/whatsapp/index.d.ts +1 -1
  317. package/dist/extensions/whatsapp/index.js +38 -38
  318. package/dist/extensions/whatsapp/setup-entry.d.ts +1 -1
  319. package/dist/extensions/whatsapp/setup-entry.js +38 -38
  320. package/dist/extensions/xai/index.d.ts +1 -1
  321. package/dist/extensions/xai/index.js +35 -35
  322. package/dist/extensions/xiaomi/index.d.ts +1 -1
  323. package/dist/extensions/xiaomi/index.js +35 -35
  324. package/dist/extensions/zai/index.d.ts +1 -1
  325. package/dist/extensions/zai/index.js +35 -35
  326. package/dist/extensions/zalo/index.d.ts +1 -1
  327. package/dist/extensions/zalo/index.js +39 -39
  328. package/dist/extensions/zalo/setup-entry.d.ts +1 -1
  329. package/dist/extensions/zalo/setup-entry.js +39 -39
  330. package/dist/extensions/zalouser/index.d.ts +1 -1
  331. package/dist/extensions/zalouser/index.js +40 -40
  332. package/dist/extensions/zalouser/setup-entry.d.ts +1 -1
  333. package/dist/extensions/zalouser/setup-entry.js +40 -40
  334. package/dist/feishu-fIcnHDTd.d.ts +36 -0
  335. package/dist/gateway-cli-0c-8h93_.js +26437 -0
  336. package/dist/gateway-install-token-1PwJvrBY.js +163 -0
  337. package/dist/gateway-rpc-C0Vk51W7.js +26 -0
  338. package/dist/gateway-runtime-CBm3CCoA.js +69 -0
  339. package/dist/git-commit-BTWXFY41.js +177 -0
  340. package/dist/git-commit-D6GTN5Yt.js +2 -0
  341. package/dist/googlechat-BQr4xgoZ.js +307 -0
  342. package/dist/googlechat-BvwsCVKl.d.ts +12 -0
  343. package/dist/group-access-DpiQnd-G.d.ts +61 -0
  344. package/dist/health-6yZQGADY.js +113 -0
  345. package/dist/health-C9DYGyRe.js +570 -0
  346. package/dist/heartbeat-summary-Dct2lqJj.js +57 -0
  347. package/dist/help-CtwSApfq.js +81 -0
  348. package/dist/hooks-9gokOxZ5.d.ts +6 -0
  349. package/dist/hooks-cli-BegKzHZT.js +1000 -0
  350. package/dist/hooks-status-Bm_pGORf.js +78 -0
  351. package/dist/http-registry-D-S6a1Na.d.ts +20 -0
  352. package/dist/identity-file-Diub2a0t.js +60 -0
  353. package/dist/image-generation-CbIVzmAR.d.ts +9 -0
  354. package/dist/imessage-Bgok9kfl.js +31 -0
  355. package/dist/imessage-VIHePprL.js +115 -0
  356. package/dist/inbound-reply-dispatch-B53GAGWq.js +71 -0
  357. package/dist/inbound-reply-dispatch-n7U3qg15.d.ts +72 -0
  358. package/dist/index.js +2 -2
  359. package/dist/install-target-oz1pjfHH.js +574 -0
  360. package/dist/installs-CUFm5V8a.js +532 -0
  361. package/dist/io-BaBxjB1v.js +9739 -0
  362. package/dist/io-CgHb1Jld.js +29 -0
  363. package/dist/irc-CaRKzGvW.js +672 -0
  364. package/dist/library-C5SNBCMb.js +112 -0
  365. package/dist/lifecycle-core-Dn8PK6nk.js +382 -0
  366. package/dist/line/accounts.d.ts +2 -2
  367. package/dist/line/send.d.ts +1 -1
  368. package/dist/line/send.js +7 -7
  369. package/dist/line/template-messages.d.ts +1 -1
  370. package/dist/line-B5QFpgN_.d.ts +75 -0
  371. package/dist/line-fePrrQOD.js +530 -0
  372. package/dist/llm-slug-generator-hKae3XDA.js +67 -0
  373. package/dist/llm-slug-generator.d.ts +1 -1
  374. package/dist/llm-slug-generator.js +36 -36
  375. package/dist/logging-CdisccbY.js +13 -0
  376. package/dist/logging-LKQSgX1d.js +30 -0
  377. package/dist/login-qr-C1YWh4nE.js +233 -0
  378. package/dist/login-qr-WFluMDMb.js +112 -0
  379. package/dist/logs-cli-CNzOvZ2d.js +256 -0
  380. package/dist/manager-runtime-DgMhLTkR.js +111 -0
  381. package/dist/manager.runtime-hUWgpPt2.js +715 -0
  382. package/dist/manifest-registry-CS_p1OBQ.js +1329 -0
  383. package/dist/matrix-43_RGLZN.d.ts +68 -0
  384. package/dist/matrix-CCFxHfxa.js +1269 -0
  385. package/dist/matrix-DWs_qIkJ.js +1495 -0
  386. package/dist/mcp-cli-Ci2jvv3s.js +87 -0
  387. package/dist/media-understanding.runtime-Cdr6iTW6.js +116 -0
  388. package/dist/memory-cli-LZbyF0Iu.js +111 -0
  389. package/dist/memory-search-BHhETk6u.js +17 -0
  390. package/dist/memory-search-tTD5o_rU.js +204 -0
  391. package/dist/method-scopes-B2ZKSsxQ.js +2452 -0
  392. package/dist/model-auth-markers-LqZ4qhrZ.d.ts +20 -0
  393. package/dist/model-picker-CTR5mo4v.js +112 -0
  394. package/dist/model-picker-DG4z_dBs.js +390 -0
  395. package/dist/model-picker.runtime-DMQ9Pj9_.js +125 -0
  396. package/dist/model-selection-bBBxfXdb.js +653 -0
  397. package/dist/model-suppression.runtime-BVG75tZ7.js +116 -0
  398. package/dist/models-BjkVLfgw.js +2514 -0
  399. package/dist/models-ZO01Q4cx.js +118 -0
  400. package/dist/models-cli-DemdF-bm.js +309 -0
  401. package/dist/models-config-B2Jja8ua.js +111 -0
  402. package/dist/models-config.providers.discovery-puxTsH39.d.ts +18 -0
  403. package/dist/moldclaw-root-Cb6HRlUO.js +92 -0
  404. package/dist/monitor-BP4idxJD.js +782 -0
  405. package/dist/monitor-B_eP8Eim.js +772 -0
  406. package/dist/monitor-CRHYNl5J.js +3468 -0
  407. package/dist/monitor-Ci1Xg4g3.js +113 -0
  408. package/dist/monitor-DEodDl3z.js +6823 -0
  409. package/dist/monitor-DJlNKuMz.js +115 -0
  410. package/dist/monitor-DvFwDS9w.js +3076 -0
  411. package/dist/monitor-shared--cEjSf8s.js +444 -0
  412. package/dist/msteams-CV2a8uE8.js +852 -0
  413. package/dist/node-cli-Of2g7DSd.js +2503 -0
  414. package/dist/node-resolve-BYC2FbO2.js +835 -0
  415. package/dist/nodes-cli-CPHM6Upj.js +1380 -0
  416. package/dist/nostr-BFKRoOlz.d.ts +7 -0
  417. package/dist/nostr-lHpcBzz4.js +8744 -0
  418. package/dist/npm-resolution-kqHN85wB.js +60 -0
  419. package/dist/oauth-env-CLG8KOrz.js +10 -0
  420. package/dist/onboard-BON0C360.js +48 -0
  421. package/dist/onboard-CRkIBgOI.js +589 -0
  422. package/dist/onboard-DsKI17iq.js +25 -0
  423. package/dist/onboard-channels-BY3IbBBf.js +1241 -0
  424. package/dist/onboard-channels-CLKdRxvW.js +205 -0
  425. package/dist/onboard-custom-BjPrMo_R.js +571 -0
  426. package/dist/onboard-custom-DqcPiZBN.js +114 -0
  427. package/dist/onboard-helpers-BkrOY5OE.js +113 -0
  428. package/dist/onboard-helpers-DiSRTpZC.js +335 -0
  429. package/dist/onboard-hooks-pzEPZAvl.js +72 -0
  430. package/dist/onboard-remote-ChyLC6Dk.js +181 -0
  431. package/dist/onboard-remote-DHmK9ntl.js +117 -0
  432. package/dist/onboard-search-BgA3jEMW.js +302 -0
  433. package/dist/onboard-skills-BMo_NvnW.js +133 -0
  434. package/dist/onboard-skills-Bba-Z2p8.js +117 -0
  435. package/dist/outbound-media-BHD4aJEX.d.ts +11 -0
  436. package/dist/outbound-media-DSno0N82.js +11 -0
  437. package/dist/pairing-access-CzHpaM0R.d.ts +21 -0
  438. package/dist/pairing-cli-CmklqK0q.js +217 -0
  439. package/dist/perplexity-CXwMDD3u.js +24 -0
  440. package/dist/persistent-dedupe-B9vrAf8t.d.ts +26 -0
  441. package/dist/pi-model-discovery-runtime-BrK7tcaO.js +111 -0
  442. package/dist/pi-tools.before-tool-call.runtime-C5yLUogH.js +381 -0
  443. package/dist/plugin-install-C4AWJIFP.js +117 -0
  444. package/dist/plugin-install-CB3J1hfV.js +184 -0
  445. package/dist/plugin-install-plan-7itZiegi.js +49 -0
  446. package/dist/plugin-registry-DX_GFoiz.js +113 -0
  447. package/dist/plugin-registry-e3cxTtvb.js +49 -0
  448. package/dist/plugin-sdk/account-resolution.js +35 -35
  449. package/dist/plugin-sdk/acp-runtime.js +35 -35
  450. package/dist/plugin-sdk/agent-runtime.js +35 -35
  451. package/dist/plugin-sdk/bluebubbles.js +37 -37
  452. package/dist/plugin-sdk/channel-config-helpers.js +35 -35
  453. package/dist/plugin-sdk/channel-policy.js +35 -35
  454. package/dist/plugin-sdk/channel-runtime.js +35 -35
  455. package/dist/plugin-sdk/compat.js +36 -36
  456. package/dist/plugin-sdk/config-runtime.js +35 -35
  457. package/dist/plugin-sdk/conversation-runtime.js +35 -35
  458. package/dist/plugin-sdk/copilot-proxy.js +4 -4
  459. package/dist/plugin-sdk/core.js +4 -4
  460. package/dist/plugin-sdk/device-pair.js +4 -4
  461. package/dist/plugin-sdk/discord.js +35 -35
  462. package/dist/plugin-sdk/feishu.js +35 -35
  463. package/dist/plugin-sdk/gateway-runtime.js +10 -10
  464. package/dist/plugin-sdk/googlechat.js +37 -37
  465. package/dist/plugin-sdk/image-generation-runtime.js +35 -35
  466. package/dist/plugin-sdk/image-generation.js +35 -35
  467. package/dist/plugin-sdk/imessage.js +36 -36
  468. package/dist/plugin-sdk/index.js +35 -35
  469. package/dist/plugin-sdk/infra-runtime.js +35 -35
  470. package/dist/plugin-sdk/irc.js +37 -37
  471. package/dist/plugin-sdk/line.js +36 -36
  472. package/dist/plugin-sdk/llm-task.js +35 -35
  473. package/dist/plugin-sdk/lobster.js +4 -4
  474. package/dist/plugin-sdk/matrix.js +37 -37
  475. package/dist/plugin-sdk/mattermost.js +36 -36
  476. package/dist/plugin-sdk/media-runtime.js +35 -35
  477. package/dist/plugin-sdk/media-understanding-runtime.js +35 -35
  478. package/dist/plugin-sdk/media-understanding.js +35 -35
  479. package/dist/plugin-sdk/memory-lancedb.js +4 -4
  480. package/dist/plugin-sdk/minimax-portal-auth.js +4 -4
  481. package/dist/plugin-sdk/msteams.js +38 -38
  482. package/dist/plugin-sdk/nextcloud-talk.js +36 -36
  483. package/dist/plugin-sdk/nostr.js +36 -36
  484. package/dist/plugin-sdk/ollama-setup.js +9 -9
  485. package/dist/plugin-sdk/open-prose.js +4 -4
  486. package/dist/plugin-sdk/phone-control.js +4 -4
  487. package/dist/plugin-sdk/plugin-runtime.js +35 -35
  488. package/dist/plugin-sdk/provider-auth.js +35 -35
  489. package/dist/plugin-sdk/provider-models.js +5 -5
  490. package/dist/plugin-sdk/provider-onboard.js +4 -4
  491. package/dist/plugin-sdk/provider-setup.js +39 -39
  492. package/dist/plugin-sdk/provider-stream.js +4 -4
  493. package/dist/plugin-sdk/provider-usage.js +4 -4
  494. package/dist/plugin-sdk/qwen-portal-auth.js +35 -35
  495. package/dist/plugin-sdk/reply-history.js +35 -35
  496. package/dist/plugin-sdk/reply-runtime.js +35 -35
  497. package/dist/plugin-sdk/routing.js +3 -3
  498. package/dist/plugin-sdk/sandbox.js +35 -35
  499. package/dist/plugin-sdk/security-runtime.js +35 -35
  500. package/dist/plugin-sdk/self-hosted-provider-setup.js +37 -37
  501. package/dist/plugin-sdk/setup.js +35 -35
  502. package/dist/plugin-sdk/signal.js +35 -35
  503. package/dist/plugin-sdk/slack.js +35 -35
  504. package/dist/plugin-sdk/speech-runtime.js +35 -35
  505. package/dist/plugin-sdk/speech.js +35 -35
  506. package/dist/plugin-sdk/src/secrets/secure-file-store.d.ts +26 -0
  507. package/dist/plugin-sdk/src/subscription/provider.d.ts +5 -3
  508. package/dist/plugin-sdk/synology-chat.js +36 -36
  509. package/dist/plugin-sdk/talk-voice.js +4 -4
  510. package/dist/plugin-sdk/telegram.js +35 -35
  511. package/dist/plugin-sdk/text-runtime.js +7 -7
  512. package/dist/plugin-sdk/thread-ownership.js +4 -4
  513. package/dist/plugin-sdk/tlon.js +36 -36
  514. package/dist/plugin-sdk/twitch.js +35 -35
  515. package/dist/plugin-sdk/voice-call.js +35 -35
  516. package/dist/plugin-sdk/whatsapp.js +35 -35
  517. package/dist/plugin-sdk/zalo.js +38 -38
  518. package/dist/plugin-sdk/zalouser.js +38 -38
  519. package/dist/plugins/runtime/index.d.ts +1 -1
  520. package/dist/plugins/runtime/index.js +35 -35
  521. package/dist/plugins-DF5FaTO0.js +111 -0
  522. package/dist/plugins-cli-CvTJemqC.js +917 -0
  523. package/dist/policy-CNXISK_a.js +143 -0
  524. package/dist/preflight-audio.runtime-RP000oxo.js +116 -0
  525. package/dist/probe-BkM5pykD.js +21 -0
  526. package/dist/probe-DKbRTJv5.js +1793 -0
  527. package/dist/probe-DkrfRsjU.js +47 -0
  528. package/dist/probe-DpcJ0WeP.js +129 -0
  529. package/dist/probe-auth-BcNjX8hy.js +40 -0
  530. package/dist/probe-auth-DhuAb8ls.js +48 -0
  531. package/dist/probe-wciBj-aL.js +6329 -0
  532. package/dist/program-C8-p0mW5.js +253 -0
  533. package/dist/prompt-select-styled-DH0pVoc0.js +2673 -0
  534. package/dist/provider-api-key-auth.runtime-CAFeIQ1u.js +121 -0
  535. package/dist/provider-auth-choice-CB_HzdTl.js +126 -0
  536. package/dist/provider-auth-choice-helpers-hzDkh3f1.js +48 -0
  537. package/dist/provider-auth-choice-preference-BHCXvNSE.js +189 -0
  538. package/dist/provider-auth-choice.runtime-Dx4ms2C5.js +123 -0
  539. package/dist/provider-auth-choices-0KaDNPBQ.js +57 -0
  540. package/dist/provider-auth-guidance-BaAUiNr_.js +34 -0
  541. package/dist/provider-auth-result-Bto1bYtS.d.ts +18 -0
  542. package/dist/provider-models-DxOmeToO.d.ts +867 -0
  543. package/dist/provider-models-xnyxy6mO.js +2113 -0
  544. package/dist/provider-ollama-setup-DBYK__ov.d.ts +32 -0
  545. package/dist/provider-ollama-setup-QzgCxj44.js +314 -0
  546. package/dist/provider-onboard-B9ionepI.js +139 -0
  547. package/dist/provider-onboard-CURxJ_UX.d.ts +40 -0
  548. package/dist/provider-runtime.runtime-4xwmsl5L.js +111 -0
  549. package/dist/provider-self-hosted-setup-BHd24EDG.js +182 -0
  550. package/dist/provider-self-hosted-setup-qeY8BYSy.d.ts +61 -0
  551. package/dist/provider-stream-Chz_EFw3.js +512 -0
  552. package/dist/provider-usage-C11Q7UwS.js +111 -0
  553. package/dist/provider-usage-kxemdMp2.js +633 -0
  554. package/dist/provider-wizard-CanJoxNC.js +152 -0
  555. package/dist/push-apns-Dsajnm8C.js +1038 -0
  556. package/dist/pw-ai-DUe4BbH2.js +1867 -0
  557. package/dist/qmd-manager-CAAFp7qK.js +1570 -0
  558. package/dist/qr-cli-Bu2jqTPY.js +113 -0
  559. package/dist/qr-cli-Bu9Z-X48.js +369 -0
  560. package/dist/reactions-Cpfum4iU.js +281 -0
  561. package/dist/read-only-account-inspect.discord.runtime-BK0LaMgC.js +116 -0
  562. package/dist/read-only-account-inspect.slack.runtime-DgKiC5wT.js +116 -0
  563. package/dist/read-only-account-inspect.telegram.runtime-mxfgFVOU.js +116 -0
  564. package/dist/redact-snapshot-DD8A4tdd.js +2663 -0
  565. package/dist/register.agent-DU4FtrU2.js +439 -0
  566. package/dist/register.backup-8nOYtJqg.js +625 -0
  567. package/dist/register.configure-DmtecqIH.js +252 -0
  568. package/dist/register.maintenance-Dir3ulKP.js +574 -0
  569. package/dist/register.message-Cfl-f3Ju.js +709 -0
  570. package/dist/register.onboard-Bv7WVzEi.js +192 -0
  571. package/dist/register.setup-BIyeI8RY.js +212 -0
  572. package/dist/register.status-health-sessions-C69WQcF4.js +498 -0
  573. package/dist/register.subclis-B_4KCgTd.js +315 -0
  574. package/dist/register.subclis-BeXsmgBL.js +13 -0
  575. package/dist/replies-DdcFUmki.js +110 -0
  576. package/dist/resolve-channels-DRZqPV5o.js +226 -0
  577. package/dist/resolve-channels-DxW1kqxA.js +262 -0
  578. package/dist/resolve-route-DdX-HBVt.js +538 -0
  579. package/dist/resolve-users-rgCQvkLs.js +143 -0
  580. package/dist/root-help-QAkoA7GD.js +32 -0
  581. package/dist/routes-CcJNnwTF.js +7097 -0
  582. package/dist/rpc-DDUAlBbH.js +67 -0
  583. package/dist/run-main-D9ci5pn7.js +424 -0
  584. package/dist/runtime-Bitmi8Er.d.ts +26 -0
  585. package/dist/runtime-discord-ops.runtime-T4sf7aRB.js +9078 -0
  586. package/dist/runtime-slack-ops.runtime-BQpP48mC.js +4556 -0
  587. package/dist/runtime-telegram-ops.runtime-cVO5dqOp.js +133 -0
  588. package/dist/runtime-whatsapp-login.runtime-DtNx0dSY.js +114 -0
  589. package/dist/runtime-whatsapp-outbound.runtime-Bw47QbFK.js +117 -0
  590. package/dist/sandbox-cli-DsFwjbjC.js +535 -0
  591. package/dist/search-manager-BRAK8fEe.js +16 -0
  592. package/dist/search-manager-BS5Db0A6.js +386 -0
  593. package/dist/secrets-cli-D3J46TJp.js +2070 -0
  594. package/dist/security-cli-B866M9cB.js +575 -0
  595. package/dist/send-B1pX9_Oc.js +283 -0
  596. package/dist/send-B2RrLg83.js +100 -0
  597. package/dist/send-DFnV__Aq.js +1025 -0
  598. package/dist/send-DZIH6CJt.js +629 -0
  599. package/dist/send-sl9WnKbW.js +631 -0
  600. package/dist/server-node-events-BT6egg20.js +506 -0
  601. package/dist/server-zI_K-D05.js +107 -0
  602. package/dist/sessions-C8kiAcoJ.js +112 -0
  603. package/dist/sessions-DLBpp52_.js +218 -0
  604. package/dist/setup-C7eOzMiC.js +387 -0
  605. package/dist/setup-CFIMq-Pz.d.ts +37 -0
  606. package/dist/setup-binary-CcAv8NXz.js +406 -0
  607. package/dist/setup-browser-C4eRV3h6.js +70 -0
  608. package/dist/setup-core-BnR486P-.js +143 -0
  609. package/dist/setup-core-CIswIiu5.js +166 -0
  610. package/dist/setup-core-CcbcrXXg.js +47 -0
  611. package/dist/setup-core-nZSw5BSv.js +205 -0
  612. package/dist/setup-surface-C5iSpT4M.js +490 -0
  613. package/dist/setup-wizard-helpers-r0J6l8ST.d.ts +203 -0
  614. package/dist/setup.finalize-adiRfo0U.js +522 -0
  615. package/dist/setup.gateway-config-BwFWKDfT.js +343 -0
  616. package/dist/shared-12TimyeF.js +182 -0
  617. package/dist/shared-9EWO34-k.js +298 -0
  618. package/dist/shared-B4vUbaRR.js +75 -0
  619. package/dist/shared-bNWpW3Dd.js +96 -0
  620. package/dist/shared-lU1y5dvS.js +102 -0
  621. package/dist/signal-DBlETRu9.js +114 -0
  622. package/dist/skills-Bio8GwTE.js +20 -0
  623. package/dist/skills-DE_MXFSN.js +853 -0
  624. package/dist/skills-cli-BGuW-tKw.js +292 -0
  625. package/dist/skills-install--rnorIoJ.js +763 -0
  626. package/dist/skills-status-B08PtBc_.js +21 -0
  627. package/dist/skills-status-CzM008aB.js +169 -0
  628. package/dist/slack-C4T53Nc-.js +114 -0
  629. package/dist/slash-commands.runtime-B7fsD8Be.js +128 -0
  630. package/dist/slash-dispatch.runtime-t0PAX4vQ.js +141 -0
  631. package/dist/slash-skill-commands.runtime-DIhPnEfR.js +116 -0
  632. package/dist/src-DrDirlvw.js +1701 -0
  633. package/dist/status-Bld14WSA.js +131 -0
  634. package/dist/status-CgeO4RuH.js +43 -0
  635. package/dist/status-HlvixAOq.js +606 -0
  636. package/dist/status-Rom_Lf3c.js +1599 -0
  637. package/dist/status-TwbMH6Am.js +126 -0
  638. package/dist/status-json-DMW7cmuK.js +288 -0
  639. package/dist/status.link-channel-V4LkB6Gq.js +143 -0
  640. package/dist/status.scan.deps.runtime-BE3X-dcP.js +126 -0
  641. package/dist/status.scan.runtime-BxVY4mty.js +119 -0
  642. package/dist/status.summary-CzLM0vVr.js +592 -0
  643. package/dist/status.summary.runtime-BSBnHZ1Q.js +118 -0
  644. package/dist/status.update-BxblMS7P.js +77 -0
  645. package/dist/subagent-orphan-recovery-BpRPryEj.js +307 -0
  646. package/dist/subagent-registry-runtime-DYYU5p3X.js +111 -0
  647. package/dist/subscription-CpFdxuFS.js +33 -0
  648. package/dist/subscription-DaA1urx-.js +102 -0
  649. package/dist/subscription-cli-Bvto9EmO.js +134 -0
  650. package/dist/synology-chat-3nwk-Nj0.js +297 -0
  651. package/dist/system-cli-BvNps8sl.js +94 -0
  652. package/dist/telegram/audit.d.ts +1 -1
  653. package/dist/telegram/audit.js +1 -1
  654. package/dist/telegram/token.d.ts +1 -1
  655. package/dist/telegram/token.js +35 -35
  656. package/dist/telegram-RtKXoEsF.js +114 -0
  657. package/dist/text-chunking-BD5mQe2R.js +84 -0
  658. package/dist/text-chunking-DDUU_vAF.d.ts +79 -0
  659. package/dist/tlon-z-kYmJE-.js +433 -0
  660. package/dist/tui-cli-CzSK08Rh.js +137 -0
  661. package/dist/tui-wV7R1Tlc.js +3834 -0
  662. package/dist/types-2H_e7eWT.d.ts +45 -0
  663. package/dist/types-ZKnGUchG.d.ts +22692 -0
  664. package/dist/types.base-BFiQZ4J9.d.ts +188 -0
  665. package/dist/ui-BWVHreeR.js +31 -0
  666. package/dist/update-D1Wgh1Tj.js +1036 -0
  667. package/dist/update-cli-CZh99uyY.js +1503 -0
  668. package/dist/update-offset-store-D5xTdUr0.js +112 -0
  669. package/dist/update-runner-GbKfoCHs.js +1496 -0
  670. package/dist/upsert-with-lock-BZU7Le8n.js +33 -0
  671. package/dist/usage-Czgwvg0h.js +115 -0
  672. package/dist/web-CMczmL90.js +112 -0
  673. package/dist/web-shared-B5Q0mIJq.d.ts +45 -0
  674. package/dist/webhook-request-guards-CsKDhZJr.d.ts +76 -0
  675. package/dist/webhook-targets-BSmFtesN.js +181 -0
  676. package/dist/webhook-targets-CjxuEE9C.d.ts +106 -0
  677. package/dist/webhooks-cli-Wl9y6AWW.js +350 -0
  678. package/dist/whatsapp-VzRW8MdR.js +114 -0
  679. package/dist/whatsapp-actions-Cg1Wxv8W.js +167 -0
  680. package/dist/workspace-DJ_S272u.js +484 -0
  681. package/dist/workspace-DbZSqjw0.js +289 -0
  682. package/dist/workspace-cli-D93DLmAh.js +154 -0
  683. package/dist/workspace-dirs-CGeIPpGN.js +2003 -0
  684. package/dist/zalo-CK2dlGmu.d.ts +9 -0
  685. package/dist/zalo-Db7s2boL.js +415 -0
  686. package/dist/zalouser-Jh5YTJX3.js +30911 -0
  687. package/docs/reference/templates/AGENTS.dev.md +83 -0
  688. package/docs/reference/templates/AGENTS.md +219 -0
  689. package/docs/reference/templates/BOOT.md +11 -0
  690. package/docs/reference/templates/BOOTSTRAP.md +62 -0
  691. package/docs/reference/templates/HEARTBEAT.md +12 -0
  692. package/docs/reference/templates/IDENTITY.dev.md +47 -0
  693. package/docs/reference/templates/IDENTITY.md +29 -0
  694. package/docs/reference/templates/SOUL.dev.md +76 -0
  695. package/docs/reference/templates/SOUL.md +43 -0
  696. package/docs/reference/templates/TOOLS.dev.md +24 -0
  697. package/docs/reference/templates/TOOLS.md +47 -0
  698. package/docs/reference/templates/USER.dev.md +18 -0
  699. package/docs/reference/templates/USER.md +23 -0
  700. package/extensions/discord/src/monitor/allow-list.ts +8 -1
  701. package/extensions/discord/src/monitor/message-handler.preflight.ts +4 -1
  702. package/package.json +2 -1
  703. package/dist/accounts-CDr-lDaV.d.ts +0 -103
  704. package/dist/accounts-CS8U4v8C.js +0 -114
  705. package/dist/acp-cli-BGT0jXcC.js +0 -2093
  706. package/dist/actions.runtime-BfckTw6c.js +0 -119
  707. package/dist/actions.runtime-Cl9mBfqH.js +0 -133
  708. package/dist/agent-scope-C-YmLnnb.js +0 -208
  709. package/dist/agents-CydD54p8.js +0 -222
  710. package/dist/agents-DpQsZO6O.js +0 -853
  711. package/dist/agents.config-XU7IsYE-.js +0 -121
  712. package/dist/agents.config-ssoQXuvF.js +0 -17
  713. package/dist/allow-list-Cfn6lmMK.js +0 -81
  714. package/dist/allowlist-CCYXVpM9.js +0 -142
  715. package/dist/api-BoXoFKxy.js +0 -117
  716. package/dist/audit-Bv05N5o9.js +0 -787
  717. package/dist/audit-CIWW1Aqm.js +0 -54
  718. package/dist/audit-channel.collect.runtime-Bi7yrdcO.js +0 -605
  719. package/dist/audit-channel.runtime-C_NDweiW.js +0 -121
  720. package/dist/audit-extra.async-Dp7OKSXg.js +0 -813
  721. package/dist/audit-membership-runtime-B8FQ6VtN.js +0 -162
  722. package/dist/audit.deep.runtime-CXhobL6b.js +0 -25
  723. package/dist/audit.nondeep.runtime-CrEm3T16.js +0 -832
  724. package/dist/audit.runtime-CJPKj1Zg.js +0 -118
  725. package/dist/auth-Byfp0flq.js +0 -101
  726. package/dist/auth-choice-BgOjdeXN.js +0 -507
  727. package/dist/auth-choice-CD1Heq0M.js +0 -122
  728. package/dist/auth-choice-ePNfg0iQ.js +0 -268
  729. package/dist/auth-choice-options-BlewQWI0.js +0 -123
  730. package/dist/auth-choice-prompt-BP2b6aXz.js +0 -36
  731. package/dist/auth-choice-prompt-Cmwl4n97.js +0 -115
  732. package/dist/auth-choice.apply-helpers-Dq-nxuuX.js +0 -66
  733. package/dist/auth-choice.plugin-providers.runtime-B23kOUzQ.js +0 -119
  734. package/dist/auth-profiles-1kPLbBwI.js +0 -127823
  735. package/dist/auth-profiles.runtime-DAfSjku1.js +0 -116
  736. package/dist/banner-DeOsobLO.js +0 -342
  737. package/dist/bluebubbles-BsLGedBM.js +0 -64
  738. package/dist/bluebubbles-CnT9wiS4.d.ts +0 -6
  739. package/dist/bot-CuzVYwa_.d.ts +0 -478
  740. package/dist/brave-BoWimrLe.js +0 -24
  741. package/dist/browser-cli-D_S3wEYE.js +0 -1494
  742. package/dist/call-ByEzDJ1_.js +0 -640
  743. package/dist/call-CHCWVg-O.js +0 -39
  744. package/dist/channel-3VC0oOMu.js +0 -214
  745. package/dist/channel-B9fCBPiS.js +0 -207
  746. package/dist/channel-B9q775cM.js +0 -562
  747. package/dist/channel-BG3UK54j.js +0 -803
  748. package/dist/channel-BRQAdMML.js +0 -352
  749. package/dist/channel-BmlLp933.js +0 -1321
  750. package/dist/channel-By6KvdTG.js +0 -920
  751. package/dist/channel-C8rRsdf6.js +0 -226
  752. package/dist/channel-CLEDBbXE.js +0 -943
  753. package/dist/channel-CMvBAG7o.js +0 -306
  754. package/dist/channel-CmlxxjHY.js +0 -1598
  755. package/dist/channel-CqG6_xN0.js +0 -949
  756. package/dist/channel-DNueHKs92.js +0 -316
  757. package/dist/channel-DUtyN7BX.js +0 -4681
  758. package/dist/channel-DWD6GrfZ.js +0 -538
  759. package/dist/channel-DaRYMYzj.js +0 -619
  760. package/dist/channel-Dj6BgLp8.js +0 -575
  761. package/dist/channel-account-context-Ba3u5D21.js +0 -103
  762. package/dist/channel-crabk6Em.js +0 -542
  763. package/dist/channel-i8uqQaK2.js +0 -497
  764. package/dist/channel-options-xljvwHS2.js +0 -50
  765. package/dist/channel-plugin-ids-DAgknSG4.js +0 -26
  766. package/dist/channel-summary-dHTMCG75.js +0 -111
  767. package/dist/channel-xVWQ96Ni.js +0 -397
  768. package/dist/channel.runtime-B6PoZ4BV.js +0 -182
  769. package/dist/channel.runtime-BPZmo57e.js +0 -404
  770. package/dist/channel.runtime-B_1uGR-U.js +0 -199
  771. package/dist/channel.runtime-BiXnPU0d.js +0 -218
  772. package/dist/channel.runtime-BpvDc9sv.js +0 -870
  773. package/dist/channel.runtime-CUua3W80.js +0 -418
  774. package/dist/channel.runtime-CaCBTd0A.js +0 -179
  775. package/dist/channel.runtime-D0FfYvUj.js +0 -4011
  776. package/dist/channel.runtime-DhoJtpvJ.js +0 -241
  777. package/dist/channel.runtime-Kj9EXNE0.js +0 -127
  778. package/dist/channel.runtime-r4tPuPyh.js +0 -171
  779. package/dist/channel.setup-B7d_grfe.js +0 -6
  780. package/dist/channel.setup-C0vu1fhi.js +0 -9
  781. package/dist/channel.setup-CAI0FNHj.js +0 -11
  782. package/dist/channel.setup-CkDVwv5R.js +0 -57
  783. package/dist/channel.setup-Cpd00YqQ.js +0 -8
  784. package/dist/channel.setup-DbBz1-WT.js +0 -9
  785. package/dist/channel.setup-GZnAvD9g.js +0 -8
  786. package/dist/channels-5H484RSw.js +0 -1118
  787. package/dist/channels-BnPudfyx.js +0 -404
  788. package/dist/channels-cli-WIC-QeH_.js +0 -291
  789. package/dist/channels-status-issues-RDmzovJU.js +0 -16
  790. package/dist/clawbot-cli-BgutNwf8.js +0 -118
  791. package/dist/cleanup-utils-DBl1Aij1.js +0 -96
  792. package/dist/cli-1P7u6zqu.js +0 -154
  793. package/dist/command-registry-B8jovrws.js +0 -232
  794. package/dist/command-registry-DtDl1FVm.js +0 -14
  795. package/dist/command-secret-gateway-BgUo3FxJ.js +0 -111
  796. package/dist/compact.runtime-CXbXM0AU.js +0 -116
  797. package/dist/completion-cli-Cik_owAE.js +0 -17
  798. package/dist/completion-cli-RU3P2RSl.js +0 -445
  799. package/dist/config-5HUpB1L1.js +0 -31
  800. package/dist/config-cli-QHaUHoZI.js +0 -433
  801. package/dist/config-guard-C9Sn3pE-.js +0 -118
  802. package/dist/config-sW57gztj.js +0 -44
  803. package/dist/config-validation-5LkjIKNt.js +0 -262
  804. package/dist/config-value-CtTWALxG.js +0 -132
  805. package/dist/configure-BmR2TPLf.js +0 -243
  806. package/dist/configure-DaLN-5xM.js +0 -1100
  807. package/dist/control-ui-assets-CH3MYmAo.js +0 -232
  808. package/dist/control-ui-shared-CA77PTml.js +0 -29
  809. package/dist/core-CvDzLs7B.js +0 -150
  810. package/dist/core-jm751KJ9.d.ts +0 -87
  811. package/dist/cron-cli-tguLpzyq.js +0 -639
  812. package/dist/daemon-cli-ptosOkL8.js +0 -339
  813. package/dist/daemon-install-DzU4EnVa.js +0 -180
  814. package/dist/deliver-DwxFoHM3.js +0 -111
  815. package/dist/deliver-runtime-DOdDyaPI.js +0 -111
  816. package/dist/device-id-cli-GopvlxxZ.js +0 -52
  817. package/dist/device-identity-CRfhC3_s.js +0 -365
  818. package/dist/devices-cli-ain7ESqU.js +0 -342
  819. package/dist/diagnostic-D96Xaqrj.js +0 -310
  820. package/dist/directory-cli-fh1UxGgY.js +0 -311
  821. package/dist/directory-config-helpers-Coivm0Mt.d.ts +0 -38
  822. package/dist/directory.static-CKjJUNGl.js +0 -44
  823. package/dist/discord-CflhwDEM.js +0 -114
  824. package/dist/discovery-x0ZqY4AB.js +0 -48
  825. package/dist/dm-policy-shared-DKzsSLlO.d.ts +0 -95
  826. package/dist/dns-cli-DCHyKjGf.js +0 -217
  827. package/dist/docs-cli-D3OoqYSP.js +0 -174
  828. package/dist/doctor-completion-Bq2eP87s.js +0 -90
  829. package/dist/doctor-config-flow-D8XRG9Ku.js +0 -2437
  830. package/dist/doctor-config-flow-DGiF1HGc.js +0 -112
  831. package/dist/enable-0QSF4YGH.js +0 -24
  832. package/dist/exec-approvals-cli-Bncym0Gd.js +0 -421
  833. package/dist/feishu-C1dM8pl2.d.ts +0 -36
  834. package/dist/gateway-cli-DYscsmA-.js +0 -26437
  835. package/dist/gateway-install-token-CNv17ac9.js +0 -163
  836. package/dist/gateway-rpc-BGC1Rxvg.js +0 -26
  837. package/dist/gateway-runtime-D89mSQPB.js +0 -69
  838. package/dist/git-commit-CeLH5Ozm.js +0 -2
  839. package/dist/git-commit-DUKRiCP-.js +0 -177
  840. package/dist/googlechat-BgXeXjd1.js +0 -307
  841. package/dist/googlechat-CNZQb1jd.d.ts +0 -12
  842. package/dist/group-access-Deh1tVNr.d.ts +0 -61
  843. package/dist/health-BEjzWwaB.js +0 -570
  844. package/dist/health-FjqrWQL6.js +0 -113
  845. package/dist/heartbeat-summary-CfdSA9M1.js +0 -57
  846. package/dist/help-BZeVprq1.js +0 -81
  847. package/dist/hooks-06OUQvAV.d.ts +0 -6
  848. package/dist/hooks-cli-B7uGJs2O.js +0 -1000
  849. package/dist/hooks-status-CfceaUSg.js +0 -78
  850. package/dist/http-registry-DYskWhOr.d.ts +0 -20
  851. package/dist/identity-file-sshkKKIr.js +0 -60
  852. package/dist/image-generation-D4o3j8o6.d.ts +0 -9
  853. package/dist/imessage-BcV3WGx_.js +0 -31
  854. package/dist/imessage-Dhje7Ty-.js +0 -115
  855. package/dist/inbound-reply-dispatch-C73_7SOl.js +0 -71
  856. package/dist/inbound-reply-dispatch-D6_HNqH8.d.ts +0 -72
  857. package/dist/install-target-D7NRhfzc.js +0 -574
  858. package/dist/installs-Bj6jblqc.js +0 -532
  859. package/dist/io-CMfWWPXQ.js +0 -9738
  860. package/dist/io-CV844hAM.js +0 -29
  861. package/dist/irc-DKi1fDYI.js +0 -672
  862. package/dist/library-rygTG3oA.js +0 -112
  863. package/dist/lifecycle-core-BPlvShWY.js +0 -382
  864. package/dist/line-B8gTtl3Y.d.ts +0 -75
  865. package/dist/line-CGsemKWJ.js +0 -530
  866. package/dist/llm-slug-generator-DlhVyMqT.js +0 -67
  867. package/dist/logging-5wu9k6w4.js +0 -30
  868. package/dist/logging-CxP9suT8.js +0 -13
  869. package/dist/login-qr-BcDsiwHs.js +0 -233
  870. package/dist/login-qr-Y8pJ5yV4.js +0 -112
  871. package/dist/logs-cli-XI9oVXpH.js +0 -256
  872. package/dist/manager-runtime-DkIlXBhD.js +0 -111
  873. package/dist/manager.runtime-Q0q2rJCC.js +0 -715
  874. package/dist/manifest-registry-DAd0SRAP.js +0 -1329
  875. package/dist/matrix-BI0DBBrG.js +0 -1495
  876. package/dist/matrix-D2JoHzb4.d.ts +0 -68
  877. package/dist/matrix-DiABGjJR.js +0 -1269
  878. package/dist/mcp-cli-BOyn_DLL.js +0 -87
  879. package/dist/media-understanding.runtime-DjUa7Dka.js +0 -116
  880. package/dist/memory-cli-CJd_vl-Y.js +0 -111
  881. package/dist/memory-search-CEEItIFR.js +0 -17
  882. package/dist/memory-search-Cv1SBrn7.js +0 -204
  883. package/dist/method-scopes-CQE7-bZ-.js +0 -2452
  884. package/dist/model-auth-markers-BFoM4IPf.d.ts +0 -20
  885. package/dist/model-picker-D6_89XHg.js +0 -112
  886. package/dist/model-picker-Svaw-APs.js +0 -390
  887. package/dist/model-picker.runtime-Chi9nV7A.js +0 -125
  888. package/dist/model-selection-hL8i1Jbs.js +0 -653
  889. package/dist/model-suppression.runtime-DjWJZ0X-.js +0 -116
  890. package/dist/models-7qj1dG_W.js +0 -118
  891. package/dist/models-BPOB_xJF.js +0 -2514
  892. package/dist/models-cli-DdlOVUjS.js +0 -309
  893. package/dist/models-config-CBqUS-jX.js +0 -111
  894. package/dist/models-config.providers.discovery-Dc905FWG.d.ts +0 -18
  895. package/dist/moldclaw-root-D6PbhbZk.js +0 -88
  896. package/dist/monitor-BPYhkEqF.js +0 -782
  897. package/dist/monitor-BuTcQ24j.js +0 -3468
  898. package/dist/monitor-CuXvNhFh.js +0 -113
  899. package/dist/monitor-D-TqSIHF.js +0 -6823
  900. package/dist/monitor-DRSgo9u2.js +0 -3076
  901. package/dist/monitor-DcHch39z.js +0 -772
  902. package/dist/monitor-DsHBMrXp.js +0 -115
  903. package/dist/monitor-shared-CL8T4gt1.js +0 -444
  904. package/dist/msteams-7FMwTvQG.js +0 -852
  905. package/dist/node-cli-BCjaSCZM.js +0 -2503
  906. package/dist/node-resolve-D5Hvcgyx.js +0 -835
  907. package/dist/nodes-cli-Dd_SNbkt.js +0 -1380
  908. package/dist/nostr-DBTFTxKs.js +0 -8744
  909. package/dist/nostr-DLqaIuZx.d.ts +0 -7
  910. package/dist/npm-resolution-CYfb3MHG.js +0 -60
  911. package/dist/oauth-env-zPt5RywA.js +0 -10
  912. package/dist/onboard-BEFQQeig.js +0 -25
  913. package/dist/onboard-CJHNyxJh.js +0 -48
  914. package/dist/onboard-D_3UeLEN.js +0 -589
  915. package/dist/onboard-channels-B_JL0Djc.js +0 -1241
  916. package/dist/onboard-channels-CqZzHt2C.js +0 -205
  917. package/dist/onboard-custom-CER3Ggbq.js +0 -571
  918. package/dist/onboard-custom-bNRdGECb.js +0 -114
  919. package/dist/onboard-helpers-BK0Hsb7Y.js +0 -335
  920. package/dist/onboard-helpers-CXZ5RPoR.js +0 -113
  921. package/dist/onboard-hooks-1NsxEDjH.js +0 -72
  922. package/dist/onboard-remote-DuKhC_7W.js +0 -117
  923. package/dist/onboard-remote-OwRcDuB3.js +0 -181
  924. package/dist/onboard-search-Cy8dOq2W.js +0 -302
  925. package/dist/onboard-skills-D5phRa6r.js +0 -117
  926. package/dist/onboard-skills-c9qWCNe9.js +0 -133
  927. package/dist/outbound-media-CXKqTh2X.d.ts +0 -11
  928. package/dist/outbound-media-DYRO2vTD.js +0 -11
  929. package/dist/pairing-access-BwJu1mkk.d.ts +0 -21
  930. package/dist/pairing-cli-BOnv0TYn.js +0 -217
  931. package/dist/perplexity-EZwC3y2b.js +0 -24
  932. package/dist/persistent-dedupe-hNES5tS1.d.ts +0 -26
  933. package/dist/pi-model-discovery-runtime-BToY3A6K.js +0 -111
  934. package/dist/pi-tools.before-tool-call.runtime-D_acPtld.js +0 -381
  935. package/dist/plugin-install-CgJpSjYd.js +0 -184
  936. package/dist/plugin-install-Cl1A4EF6.js +0 -117
  937. package/dist/plugin-install-plan-Dc2Z4DeU.js +0 -49
  938. package/dist/plugin-registry-B1UaWrQD.js +0 -49
  939. package/dist/plugin-registry-Cy8biwnn.js +0 -113
  940. package/dist/plugins-CXwvg50F.js +0 -111
  941. package/dist/plugins-cli-Uvzp2aYV.js +0 -917
  942. package/dist/policy-DsMBbEe7.js +0 -143
  943. package/dist/preflight-audio.runtime-hWsZIYvc.js +0 -116
  944. package/dist/probe-CNsSf1Uf.js +0 -6329
  945. package/dist/probe-CqOIrPhb.js +0 -47
  946. package/dist/probe-DH6gDw-h.js +0 -129
  947. package/dist/probe-DM16PLf4.js +0 -21
  948. package/dist/probe-DvAEEWYr.js +0 -1793
  949. package/dist/probe-auth-COfgCble.js +0 -48
  950. package/dist/probe-auth-I_5TX1Eh.js +0 -40
  951. package/dist/program-Dz80sgTU.js +0 -253
  952. package/dist/prompt-select-styled-wQehwFxK.js +0 -2673
  953. package/dist/provider-api-key-auth.runtime-BR9GU4ya.js +0 -121
  954. package/dist/provider-auth-choice-CdhA84kr.js +0 -126
  955. package/dist/provider-auth-choice-helpers-kabp_0zA.js +0 -48
  956. package/dist/provider-auth-choice-preference-se3zAM_2.js +0 -189
  957. package/dist/provider-auth-choice.runtime-BMc8-xNQ.js +0 -123
  958. package/dist/provider-auth-choices-CYsCViGi.js +0 -57
  959. package/dist/provider-auth-guidance-CMjUWlNf.js +0 -34
  960. package/dist/provider-auth-result-5xgWoVGi.d.ts +0 -18
  961. package/dist/provider-models-BCId_Lfu.js +0 -2113
  962. package/dist/provider-models-D-eFl9oH.d.ts +0 -867
  963. package/dist/provider-ollama-setup-B6XJZ0So.js +0 -314
  964. package/dist/provider-ollama-setup-BF1vhob8.d.ts +0 -32
  965. package/dist/provider-onboard-BjXHP3IZ.d.ts +0 -40
  966. package/dist/provider-onboard-Ca0TaNud.js +0 -139
  967. package/dist/provider-runtime.runtime-DwwkHw_7.js +0 -111
  968. package/dist/provider-self-hosted-setup-BEKLVGpj.js +0 -182
  969. package/dist/provider-self-hosted-setup-BQ5BIlpi.d.ts +0 -61
  970. package/dist/provider-stream-DrUD69ai.js +0 -512
  971. package/dist/provider-usage-BgKHCnjr.js +0 -111
  972. package/dist/provider-usage-D8EZpFz9.js +0 -633
  973. package/dist/provider-wizard-DMdb-zj_.js +0 -152
  974. package/dist/push-apns-BPH6d4VV.js +0 -1038
  975. package/dist/pw-ai-DttfldtL.js +0 -1867
  976. package/dist/qmd-manager-CybcDUfk.js +0 -1570
  977. package/dist/qr-cli-8NcmJ8Ft.js +0 -369
  978. package/dist/qr-cli-DWe0Our3.js +0 -113
  979. package/dist/reactions-D6N0LR16.js +0 -281
  980. package/dist/read-only-account-inspect.discord.runtime-CqUWTRfl.js +0 -116
  981. package/dist/read-only-account-inspect.slack.runtime-9-jpln3q.js +0 -116
  982. package/dist/read-only-account-inspect.telegram.runtime-EKPI1D7n.js +0 -116
  983. package/dist/redact-snapshot-DwJEIVk9.js +0 -2663
  984. package/dist/register.agent-D3YdDirP.js +0 -439
  985. package/dist/register.backup-dR27qCuo.js +0 -625
  986. package/dist/register.configure-BjFhkkka.js +0 -252
  987. package/dist/register.maintenance-DiMQJIOa.js +0 -574
  988. package/dist/register.message-CdZsKYH1.js +0 -709
  989. package/dist/register.onboard-B0rV1eaO.js +0 -192
  990. package/dist/register.setup-wKMvohzo.js +0 -212
  991. package/dist/register.status-health-sessions-BJ68m6pt.js +0 -498
  992. package/dist/register.subclis-CnnrWt2a.js +0 -315
  993. package/dist/register.subclis-lSvTkC6z.js +0 -13
  994. package/dist/replies-BABt9b48.js +0 -110
  995. package/dist/resolve-channels-BqZFl2Ux.js +0 -262
  996. package/dist/resolve-channels-DjQLXb7B.js +0 -226
  997. package/dist/resolve-route-CSHDsa_m.js +0 -538
  998. package/dist/resolve-users-BG6HaSR5.js +0 -143
  999. package/dist/root-help-ohmaCyC_.js +0 -32
  1000. package/dist/routes-4k2kpvoT.js +0 -7097
  1001. package/dist/rpc-Cnwn4Q6L.js +0 -67
  1002. package/dist/run-main-VYlacKA0.js +0 -424
  1003. package/dist/runtime-Cy8pqYUB.d.ts +0 -26
  1004. package/dist/runtime-discord-ops.runtime-DafrU-rI.js +0 -9078
  1005. package/dist/runtime-slack-ops.runtime-CdXBKXwd.js +0 -4556
  1006. package/dist/runtime-telegram-ops.runtime-B12sF7gE.js +0 -133
  1007. package/dist/runtime-whatsapp-login.runtime-CqEudH37.js +0 -114
  1008. package/dist/runtime-whatsapp-outbound.runtime-D5m2qyn-.js +0 -117
  1009. package/dist/sandbox-cli-CHJiEWXB.js +0 -535
  1010. package/dist/search-manager-BtNC3-i_.js +0 -16
  1011. package/dist/search-manager-C7J7B3_a.js +0 -386
  1012. package/dist/secrets-cli-C6yIWBbN.js +0 -2070
  1013. package/dist/security-cli-BVu9BkjD.js +0 -575
  1014. package/dist/send-BSreC7rr.js +0 -631
  1015. package/dist/send-BsLHQG_B.js +0 -1025
  1016. package/dist/send-BuNhp8PH.js +0 -283
  1017. package/dist/send-DOCswVar.js +0 -100
  1018. package/dist/send-Dl0LLErk.js +0 -629
  1019. package/dist/server-node-events-Bq2067EG.js +0 -506
  1020. package/dist/server-y38L7N5H.js +0 -107
  1021. package/dist/sessions-BV8gXURR.js +0 -112
  1022. package/dist/sessions-dl1Kc-Ci.js +0 -218
  1023. package/dist/setup-DGszQH0_.js +0 -387
  1024. package/dist/setup-DR5rRw9y.d.ts +0 -37
  1025. package/dist/setup-binary-C17YnmA8.js +0 -406
  1026. package/dist/setup-browser-CPx-nEsr.js +0 -70
  1027. package/dist/setup-core-BByHN1ME.js +0 -143
  1028. package/dist/setup-core-C0KPlBmL.js +0 -47
  1029. package/dist/setup-core-Cq37G6of.js +0 -166
  1030. package/dist/setup-core-uO84_Y75.js +0 -205
  1031. package/dist/setup-surface-BEMi7Rmb.js +0 -490
  1032. package/dist/setup-wizard-helpers-BtuGx_gN.d.ts +0 -203
  1033. package/dist/setup.finalize-BzPBa8zW.js +0 -522
  1034. package/dist/setup.gateway-config-DdwkF-8e.js +0 -343
  1035. package/dist/shared-BCw4SKjB.js +0 -96
  1036. package/dist/shared-CjNzsULP.js +0 -75
  1037. package/dist/shared-Cu1BE7ZE.js +0 -298
  1038. package/dist/shared-DSClmyUn.js +0 -182
  1039. package/dist/shared-DyJdGH6y.js +0 -102
  1040. package/dist/signal-Dyv4NZsB.js +0 -114
  1041. package/dist/skills-CbB5b27M.js +0 -853
  1042. package/dist/skills-CnfI7Szw.js +0 -20
  1043. package/dist/skills-cli-CavB1f_3.js +0 -292
  1044. package/dist/skills-install-B1OBdgd0.js +0 -763
  1045. package/dist/skills-status-B3gAmIbW.js +0 -169
  1046. package/dist/skills-status-DrHhFgU9.js +0 -21
  1047. package/dist/slack-BRzqnoAz.js +0 -114
  1048. package/dist/slash-commands.runtime-BK88kgds.js +0 -128
  1049. package/dist/slash-dispatch.runtime-COGywwJE.js +0 -141
  1050. package/dist/slash-skill-commands.runtime-Ti4brxgh.js +0 -116
  1051. package/dist/src-DUR6OQxI.js +0 -1701
  1052. package/dist/status-C6dgQY9a.js +0 -131
  1053. package/dist/status-CNK0Q7QH.js +0 -606
  1054. package/dist/status-DBcX0DSC.js +0 -43
  1055. package/dist/status-DKgFgbwv.js +0 -1599
  1056. package/dist/status-Wn5lhNAc.js +0 -126
  1057. package/dist/status-json-D2EkWqAl.js +0 -288
  1058. package/dist/status.link-channel-D3ULIdEa.js +0 -143
  1059. package/dist/status.scan.deps.runtime-BsjWTAm4.js +0 -126
  1060. package/dist/status.scan.runtime-D4HbzROD.js +0 -119
  1061. package/dist/status.summary-C3YxPrDK.js +0 -592
  1062. package/dist/status.summary.runtime-DAkXPSaK.js +0 -118
  1063. package/dist/status.update-B4NnN9P1.js +0 -77
  1064. package/dist/subagent-orphan-recovery-QiQEBv36.js +0 -307
  1065. package/dist/subagent-registry-runtime-BJatPQFK.js +0 -111
  1066. package/dist/subscription-BhZORXN9.js +0 -100
  1067. package/dist/subscription-QEUjQRMv.js +0 -33
  1068. package/dist/subscription-cli-HrULlAgc.js +0 -134
  1069. package/dist/synology-chat-DB76GWMN.js +0 -297
  1070. package/dist/system-cli-D8jDwWuL.js +0 -94
  1071. package/dist/telegram-BHiiqKkQ.js +0 -114
  1072. package/dist/text-chunking-Baonm9Lu.js +0 -84
  1073. package/dist/text-chunking-Y3dPBOuZ.d.ts +0 -79
  1074. package/dist/tlon-DLESxNgD.js +0 -433
  1075. package/dist/tui-C75zi2Cl.js +0 -3834
  1076. package/dist/tui-cli-DFwx5e6i.js +0 -137
  1077. package/dist/types-BBJ3Qz7j.d.ts +0 -45
  1078. package/dist/types-Ckufs_BY.d.ts +0 -22692
  1079. package/dist/types.base-Cw0-zIvE.d.ts +0 -188
  1080. package/dist/ui-B55NOIB6.js +0 -31
  1081. package/dist/update--ojavYQ4.js +0 -1036
  1082. package/dist/update-cli-Cvj5aWYM.js +0 -1503
  1083. package/dist/update-offset-store-upatuWwX.js +0 -112
  1084. package/dist/update-runner-DHkY_-76.js +0 -1496
  1085. package/dist/upsert-with-lock-C171GLaR.js +0 -33
  1086. package/dist/usage-N3bxnbmt.js +0 -115
  1087. package/dist/web-RdvT7gKa.js +0 -112
  1088. package/dist/web-shared-HSGD3yGt.d.ts +0 -45
  1089. package/dist/webhook-request-guards-CosLyl01.d.ts +0 -76
  1090. package/dist/webhook-targets-Bfnag-du.js +0 -181
  1091. package/dist/webhook-targets-Di17rt8e.d.ts +0 -106
  1092. package/dist/webhooks-cli-ZpnXrq7G.js +0 -350
  1093. package/dist/whatsapp-DNTAyZHt.js +0 -114
  1094. package/dist/whatsapp-actions-o1zKQzKZ.js +0 -167
  1095. package/dist/workspace-CpWi5wPr.js +0 -479
  1096. package/dist/workspace-Ii7aRS7c.js +0 -289
  1097. package/dist/workspace-dirs-x10McA9t.js +0 -2003
  1098. package/dist/zalo-BN3VCrRY.d.ts +0 -9
  1099. package/dist/zalo-zm_bYCKg.js +0 -415
  1100. package/dist/zalouser-CvVEUvc5.js +0 -30911
  1101. /package/dist/{account-id-B3YSn4hl.d.ts → account-id-B8ce6G_4.d.ts} +0 -0
  1102. /package/dist/{acpx-CnNv70m2.d.ts → acpx-Ci50I9T2.d.ts} +0 -0
  1103. /package/dist/{agent-media-payload-DE2pEcsz.d.ts → agent-media-payload-en-gS5p6.d.ts} +0 -0
  1104. /package/dist/{allow-from-DPpHnT2A.d.ts → allow-from-cMeQ47Ot.d.ts} +0 -0
  1105. /package/dist/{allowlist-resolution-CLFiZ6nE.d.ts → allowlist-resolution-DoAWbfXV.d.ts} +0 -0
  1106. /package/dist/{bluebubbles-Duhu-Jer.d.ts → bluebubbles-C6yYmUl0.d.ts} +0 -0
  1107. /package/dist/{boolean-param-BhFjB3gp.d.ts → boolean-param-CdO2TFTk.d.ts} +0 -0
  1108. /package/dist/{channel-config-schema-DnnVMdjR.d.ts → channel-config-schema-Chp38wel.d.ts} +0 -0
  1109. /package/dist/{channel-policy-Baq-Z06b.d.ts → channel-policy-g2h6AbYQ.d.ts} +0 -0
  1110. /package/dist/{chat-type-DpiBgwuG.d.ts → chat-type-BLt59pPT.d.ts} +0 -0
  1111. /package/dist/{command-format-vi4xq8e8.d.ts → command-format-BDJC05Jp.d.ts} +0 -0
  1112. /package/dist/{diffs-DK7fVSDo.d.ts → diffs-D_iNKCyn.d.ts} +0 -0
  1113. /package/dist/{directory-runtime-BTLPaysA.d.ts → directory-runtime-DhMex6HY.d.ts} +0 -0
  1114. /package/dist/{exec-C01wtBHu.d.ts → exec-pjfUY4KM.d.ts} +0 -0
  1115. /package/dist/{gaxios-fetch-compat-wZ38b3w3.js → gaxios-fetch-compat-B_vtINdV.js} +0 -0
  1116. /package/dist/{history-CwXuP2TW.d.ts → history-aqSS5VGQ.d.ts} +0 -0
  1117. /package/dist/{inbound-envelope-SggrBs9m.d.ts → inbound-envelope-C5hWuZod.d.ts} +0 -0
  1118. /package/dist/{index-apAZHsDo.d.ts → index-DXVQFYGX.d.ts} +0 -0
  1119. /package/dist/{json-store-r75IZGk9.d.ts → json-store-UnqQ5aV3.d.ts} +0 -0
  1120. /package/dist/{keyed-async-queue-DHIr7yNe.d.ts → keyed-async-queue-guucpLw3.d.ts} +0 -0
  1121. /package/dist/{links-HeQ3r_L0.d.ts → links-Bar0meEK.d.ts} +0 -0
  1122. /package/dist/{markdown-to-line-CDb4Jy3V.d.ts → markdown-to-line-D8uH_KOj.d.ts} +0 -0
  1123. /package/dist/{mattermost-DtCsxpgg.d.ts → mattermost-xl7jAFJL.d.ts} +0 -0
  1124. /package/dist/{net-BATPDwdQ.d.ts → net-rGOKGds6.d.ts} +0 -0
  1125. /package/dist/{nextcloud-talk-Bb2wHOwp.d.ts → nextcloud-talk-De2CZ9dV.d.ts} +0 -0
  1126. /package/dist/{oauth-utils-u567CLT0.d.ts → oauth-utils-DzN1AlEH.d.ts} +0 -0
  1127. /package/dist/{parse-finite-number-l3tNlrZh.d.ts → parse-finite-number-odgyqhi0.d.ts} +0 -0
  1128. /package/dist/{provider-usage.types-C6061OVN.d.ts → provider-usage.types-EDE9o-H_.d.ts} +0 -0
  1129. /package/dist/{reply-history-BDsFnZFl.d.ts → reply-history-CVuU31xe.d.ts} +0 -0
  1130. /package/dist/{reply-payload-CCvM4W9u.d.ts → reply-payload-CHkpBYwL.d.ts} +0 -0
  1131. /package/dist/{request-url-C54l4-xC.d.ts → request-url-DHisbiHY.d.ts} +0 -0
  1132. /package/dist/{run-command-D3RqWcHu.d.ts → run-command-y0Cndsb1.d.ts} +0 -0
  1133. /package/dist/{secret-input-schema-BLBt-NAP.d.ts → secret-input-schema-b1vpYDQN.d.ts} +0 -0
  1134. /package/dist/{session-key-BQ2-bR-9.d.ts → session-key-DTHQl57f.d.ts} +0 -0
  1135. /package/dist/{ssh-config-C4mcH9Ly.js → ssh-config-hEHBfU2_.js} +0 -0
  1136. /package/dist/{testing-DLkhGsoz.d.ts → testing-DszuZXgK.d.ts} +0 -0
  1137. /package/dist/{thinking-DRkjX18p.d.ts → thinking-IwXTGSeT.d.ts} +0 -0
  1138. /package/dist/{tool-send-CMMD1uDu.d.ts → tool-send-DWHRmKpz.d.ts} +0 -0
  1139. /package/dist/{vllm-defaults-CcGuf4hL.d.ts → vllm-defaults-CrxZgE6-.d.ts} +0 -0
  1140. /package/dist/{wait-Daog8bxM.d.ts → wait-wDWw_MTI.d.ts} +0 -0
  1141. /package/dist/{webhook-memory-guards-C5MrExwT.d.ts → webhook-memory-guards-DreORuJy.d.ts} +0 -0
  1142. /package/dist/{windows-spawn-j2l-dqu8.d.ts → windows-spawn-BIzH92x2.d.ts} +0 -0
  1143. /package/dist/{zod-schema.agent-runtime-krMrBnIn.d.ts → zod-schema.agent-runtime-CP2rmis3.d.ts} +0 -0
  1144. /package/dist/{zod-schema.core-BNDieZDZ.d.ts → zod-schema.core-Foi1tYwi.d.ts} +0 -0
@@ -0,0 +1,4556 @@
1
+ import "./redact-fatrROh9.js";
2
+ import "./errors-DOJWZqNo.js";
3
+ import "./unhandled-rejections-CTvNvnT0.js";
4
+ import { i as getChildLogger } from "./logger-BFfIIIKH.js";
5
+ import "./paths-D6AgsMTU.js";
6
+ import "./tmp-moldclaw-dir-DWF-d8qD.js";
7
+ import "./theme-BSXzMzAA.js";
8
+ import { a as logVerbose, d as warn, l as shouldLogVerbose, t as danger } from "./globals-DESrFYmC.js";
9
+ import { t as createNonExitingRuntime } from "./runtime-_tQz41uA.js";
10
+ import "./ansi-BPhP6LBZ.js";
11
+ import "./subsystem-CPmDTJ2P.js";
12
+ import "./boolean-B6zcAynR.js";
13
+ import "./env-D42cffog.js";
14
+ import "./warning-filter-B1UOeM0G.js";
15
+ import "./utils-C7ykRPCQ.js";
16
+ import "./links-BcahUP5U.js";
17
+ import "./setup-binary-CcAv8NXz.js";
18
+ import { $r as resolveSlackThreadStarter, $t as createChannelInboundDebouncer, $w as formatAllowlistMatchMeta, A_ as finalizeInboundContext, Cn as shouldHandleTextCommands, Es as recordInboundSession, Fa as dispatchInboundMessage, Fd as resolvePinnedMainDmOwnerFromAllowlist, Fr as recordSlackThreadParticipation, Fs as formatInboundEnvelope, Fx as resolveSlackAppToken, GS as pruneMapToMaxSize, Gw as applyChannelMatchMeta, Hg as logAckFailure, Hw as resolveCommandAuthorizedFromAuthorizers, Id as buildUntrustedChannelMetadata, Ir as deleteSlackMessage, Ix as resolveSlackBotToken, Jv as resolvePluginConversationBindingApproval, KS as computeBackoff, Kv as parsePluginBindingApprovalCustomId, Kw as buildChannelKeyCandidates, Nr as truncateSlackText, Nx as resolveSlackAccount, Oh as issuePairingChallenge, Os as createReplyDispatcherWithTyping, Pr as hasSlackThreadParticipation, Px as resolveSlackReplyToMode, Qg as buildPendingHistoryContextFromMap, Qr as resolveSlackThreadHistory, Qt as resolveNativeCommandSessionTargets, Rn as dispatchPluginInteractiveHandler, Rr as editSlackMessage, Rs as resolveEnvelopeFormatOptions, Rv as buildPluginBindingResolvedText, Ug as logInboundDrop, Uw as resolveControlCommandGate, Vw as createDraftStreamLoop, WS as createDedupeCache, Wg as logTypingFailure, Wr as reactSlackMessage, XT as resolveConversationLabel, Xr as resolveSlackAttachmentContent, Yw as resolveChannelEntryMatchWithFallback, Zr as resolveSlackMedia, _S as installRequestBodyLimitGuard, aT as buildAllowlistResolutionSummary, a_ as buildMentionRegexes, ag as createTypingCallbacks, bs as resolveMentionGatingWithBypass, cC as updateLastRoute, cT as patchAllowlistUsersInConfigEntries, e_ as clearHistoryEntriesIfEnabled, ei as sendMessageSlack, en as shouldDebounceTextInbound, iC as readSessionUpdatedAt, iS as resolveAgentOutboundIdentity, iT as addAllowlistUserEntriesFromConfigEntry, ii as resolveSlackWebClientOptions, jc as resolveChannelConfigWrites, kd as readStoreAllowFromForDmPolicy, kr as handleSlackAction, lS as resolveHumanDelayConfig, lm as upsertChannelPairingRequest, ni as normalizeSlackOutboundText, oS as resolveAckReaction, oi as normalizeSlackWebhookPath, qS as sleepWithAbort, qr as removeSlackReaction, r_ as recordPendingHistoryEntryIfEnabled, ri as createSlackWebClient, sT as mergeAllowlist, s_ as matchesMentionWithExplicit, sg as createReplyPrefixOptions, si as registerSlackHttpHandler, tC as isDangerousNameMatchingEnabled, tn as hasControlCommand, uT as summarizeMapping, x as resolveSessionKey } from "./auth-profiles-smABVXzp.js";
19
+ import "./model-selection-bBBxfXdb.js";
20
+ import "./agent-scope-lZlwP1At.js";
21
+ import { d as resolveThreadSessionKeys, l as normalizeMainKey } from "./session-key-UoG7Kfw5.js";
22
+ import { n as normalizeAccountId } from "./account-id-BuyZMNja.js";
23
+ import { r as normalizeStringEntries } from "./string-normalization-28MhO2sd.js";
24
+ import "./boundary-file-read-tPYh_8fH.js";
25
+ import "./logger-BGzLUitz.js";
26
+ import "./exec-CvEtXqTZ.js";
27
+ import "./workspace-DJ_S272u.js";
28
+ import { c as loadConfig, cn as mapStreamingModeToSlackLegacyDraftStreamMode, mn as resolveSlackStreamingMode, pn as resolveSlackNativeStreaming, y as writeConfigFile } from "./io-BaBxjB1v.js";
29
+ import "./host-env-security-DQ2i_W12.js";
30
+ import "./safe-text-Cnulee_z.js";
31
+ import "./version-T8nMYUnU.js";
32
+ import { c as normalizeResolvedSecretInputString } from "./types.secrets-Ca-9L8vU.js";
33
+ import "./env-substitution-68cyvF5h.js";
34
+ import "./config-state-h5jUoHya.js";
35
+ import "./network-mode-BtWXzwYn.js";
36
+ import "./registry-C1pRrsQl.js";
37
+ import "./manifest-registry-CS_p1OBQ.js";
38
+ import "./ip-C4YAIpr4.js";
39
+ import "./zod-schema.core-DvwgNmpd.js";
40
+ import "./config-CwBv71QC.js";
41
+ import "./audit-fs-CMb-YUHX.js";
42
+ import "./resolve-PSlwZjg3.js";
43
+ import "./provider-web-search-CcUC9ktE.js";
44
+ import { b as resolveTextChunkLimit, r as chunkItems, t as withTimeout } from "./text-runtime-Cfq-Uyx0.js";
45
+ import { c as resolveNativeCommandsEnabled, l as resolveNativeSkillsEnabled } from "./workspace-dirs-CGeIPpGN.js";
46
+ import "./config-BwkGZjD5.js";
47
+ import "./tailnet-fFTz5Twr.js";
48
+ import "./net-K181nxTH.js";
49
+ import "./credentials-D-5Pb-aZ.js";
50
+ import "./routes-CcJNnwTF.js";
51
+ import "./frontmatter-Cgg0ICvh.js";
52
+ import "./env-overrides-DBQl3LRc.js";
53
+ import "./path-alias-guards-BtSO7sk7.js";
54
+ import "./skills-DE_MXFSN.js";
55
+ import "./ports-Ca74cFb2.js";
56
+ import "./ports-lsof-CoiADo0p.js";
57
+ import "./ssh-tunnel-DsY-9yao.js";
58
+ import "./image-ops-Ck_D_vpe.js";
59
+ import "./fs-safe-CRXFoBmh.js";
60
+ import "./mime-DGFQe4XX.js";
61
+ import { t as generateSecureToken } from "./secure-random-DCbze_y8.js";
62
+ import "./server-middleware-Djfoa1s0.js";
63
+ import "./message-channel-DFE4FuE_.js";
64
+ import { i as resolveAgentRoute } from "./resolve-route-DdX-HBVt.js";
65
+ import "./internal-hooks-83AcmxP3.js";
66
+ import { n as shouldAckReaction, t as removeAckReactionAfterReply } from "./ack-reactions-DCQB2y3w.js";
67
+ import { f as warnMissingProviderGroupPolicyFallbackOnce, l as resolveDefaultGroupPolicy, t as evaluateGroupRouteAccessForPolicy, u as resolveOpenProviderRuntimeGroupPolicy } from "./group-access-UAqUyJod.js";
68
+ import { b as enqueueSystemEvent } from "./lazy-runtime-BoGB4usD.js";
69
+ import "./config-schema-BNU4GQh_.js";
70
+ import "./method-scopes-B2ZKSsxQ.js";
71
+ import "./session-cost-usage-DWgQk6XT.js";
72
+ import { l as resolveStorePath } from "./paths-ApLcu1Uu.js";
73
+ import "./routing-DQ-fpTaA.js";
74
+ import "./send-B1pX9_Oc.js";
75
+ import "./node-resolve-BYC2FbO2.js";
76
+ import "./provider-stream-Chz_EFw3.js";
77
+ import "./identity-file-Diub2a0t.js";
78
+ import "./provider-models-xnyxy6mO.js";
79
+ import "./secret-file-p1IhQzwJ.js";
80
+ import "./logging-Dy7UYzIN.js";
81
+ import "./runtime-env-BlEtPF6b.js";
82
+ import "./registry-BFMbkmgR.js";
83
+ import "./provider-onboard-B9ionepI.js";
84
+ import "./model-definitions-Cyyzm6Kr.js";
85
+ import "./usage-Czgwvg0h.js";
86
+ import "./device-identity-IG5DngWM.js";
87
+ import "./auth-Ch3Rchm4.js";
88
+ import "./subscription-DaA1urx-.js";
89
+ import "./diagnostic-DTPopFvh.js";
90
+ import "./message-hook-mappers-CeiHXgSQ.js";
91
+ import "./json-store--7cBPxTG.js";
92
+ import "./call-gdDAt07d.js";
93
+ import "./multimodal-BJBBn_4F.js";
94
+ import "./memory-search-tTD5o_rU.js";
95
+ import "./query-expansion-D_Mm5Hhi.js";
96
+ import "./search-manager-BS5Db0A6.js";
97
+ import "./core-BwKq3krw.js";
98
+ import "./issue-format-B0SI57Es.js";
99
+ import "./logging-CdisccbY.js";
100
+ import "./note-dOl5kPAy.js";
101
+ import "./state-paths-DsMoTg25.js";
102
+ import "./config-value-DT3-5958.js";
103
+ import "./command-secret-targets-BFF4x_RB.js";
104
+ import "./brave-w4Fo8WZ3.js";
105
+ import "./provider-usage-kxemdMp2.js";
106
+ import "./perplexity-CXwMDD3u.js";
107
+ import "./restart-stale-pids-CPF1_61W.js";
108
+ import "./delivery-queue-BOf5wYIc.js";
109
+ import "./pairing-token-bu1e6z6X.js";
110
+ import "./accounts-J2OhhhQi.js";
111
+ import "./process-runtime-D27SftX_.js";
112
+ import "./audit-CpfSjvyo.js";
113
+ import "./cli-runtime-DTCHPjCi.js";
114
+ import "./cli-utils-BCuSS4l6.js";
115
+ import "./help-format-BFzPm_8V.js";
116
+ import "./progress-Cwq59vgZ.js";
117
+ import { r as createConnectedChannelStatusPatch } from "./gateway-runtime-CBm3CCoA.js";
118
+ import "./plugin-runtime-CUDsBEl9.js";
119
+ import { a as normalizeSlackSlug, i as normalizeSlackAllowOwnerEntry, n as normalizeAllowList, o as resolveSlackAllowListMatch, r as normalizeAllowListLower, s as resolveSlackUserAllowed, t as allowListMatches } from "./allow-list-3WSjz1zl.js";
120
+ import { n as resolveSlackUserAllowlist, t as resolveSlackChannelAllowlist } from "./resolve-channels-DRZqPV5o.js";
121
+ import { a as resolveSlackThreadTs, i as readSlackReplyBlocks, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-DdcFUmki.js";
122
+ import * as SlackBoltNamespace from "@slack/bolt";
123
+ import SlackBolt from "@slack/bolt";
124
+ //#region extensions/slack/src/directory-live.ts
125
+ function resolveReadToken(params) {
126
+ const account = resolveSlackAccount({
127
+ cfg: params.cfg,
128
+ accountId: params.accountId
129
+ });
130
+ return account.userToken ?? account.botToken?.trim();
131
+ }
132
+ function normalizeQuery(value) {
133
+ return value?.trim().toLowerCase() ?? "";
134
+ }
135
+ function buildUserRank(user) {
136
+ let rank = 0;
137
+ if (!user.deleted) rank += 2;
138
+ if (!user.is_bot && !user.is_app_user) rank += 1;
139
+ return rank;
140
+ }
141
+ function buildChannelRank(channel) {
142
+ return channel.is_archived ? 0 : 1;
143
+ }
144
+ async function listSlackDirectoryPeersLive(params) {
145
+ const token = resolveReadToken(params);
146
+ if (!token) return [];
147
+ const client = createSlackWebClient(token);
148
+ const query = normalizeQuery(params.query);
149
+ const members = [];
150
+ let cursor;
151
+ do {
152
+ const res = await client.users.list({
153
+ limit: 200,
154
+ cursor
155
+ });
156
+ if (Array.isArray(res.members)) members.push(...res.members);
157
+ const next = res.response_metadata?.next_cursor?.trim();
158
+ cursor = next ? next : void 0;
159
+ } while (cursor);
160
+ const rows = members.filter((member) => {
161
+ const candidates = [
162
+ member.profile?.display_name || member.profile?.real_name || member.real_name,
163
+ member.name,
164
+ member.profile?.email
165
+ ].map((item) => item?.trim().toLowerCase()).filter(Boolean);
166
+ if (!query) return true;
167
+ return candidates.some((candidate) => candidate?.includes(query));
168
+ }).map((member) => {
169
+ const id = member.id?.trim();
170
+ if (!id) return null;
171
+ const handle = member.name?.trim();
172
+ const display = member.profile?.display_name?.trim() || member.profile?.real_name?.trim() || member.real_name?.trim() || handle;
173
+ return {
174
+ kind: "user",
175
+ id: `user:${id}`,
176
+ name: display || void 0,
177
+ handle: handle ? `@${handle}` : void 0,
178
+ rank: buildUserRank(member),
179
+ raw: member
180
+ };
181
+ }).filter(Boolean);
182
+ if (typeof params.limit === "number" && params.limit > 0) return rows.slice(0, params.limit);
183
+ return rows;
184
+ }
185
+ async function listSlackDirectoryGroupsLive(params) {
186
+ const token = resolveReadToken(params);
187
+ if (!token) return [];
188
+ const client = createSlackWebClient(token);
189
+ const query = normalizeQuery(params.query);
190
+ const channels = [];
191
+ let cursor;
192
+ do {
193
+ const res = await client.conversations.list({
194
+ types: "public_channel,private_channel",
195
+ exclude_archived: false,
196
+ limit: 1e3,
197
+ cursor
198
+ });
199
+ if (Array.isArray(res.channels)) channels.push(...res.channels);
200
+ const next = res.response_metadata?.next_cursor?.trim();
201
+ cursor = next ? next : void 0;
202
+ } while (cursor);
203
+ const rows = channels.filter((channel) => {
204
+ const name = channel.name?.trim().toLowerCase();
205
+ if (!query) return true;
206
+ return Boolean(name && name.includes(query));
207
+ }).map((channel) => {
208
+ const id = channel.id?.trim();
209
+ const name = channel.name?.trim();
210
+ if (!id || !name) return null;
211
+ return {
212
+ kind: "group",
213
+ id: `channel:${id}`,
214
+ name,
215
+ handle: `#${name}`,
216
+ rank: buildChannelRank(channel),
217
+ raw: channel
218
+ };
219
+ }).filter(Boolean);
220
+ if (typeof params.limit === "number" && params.limit > 0) return rows.slice(0, params.limit);
221
+ return rows;
222
+ }
223
+ //#endregion
224
+ //#region extensions/slack/src/monitor/commands.ts
225
+ /**
226
+ * Strip Slack mentions (<@U123>, <@U123|name>) so command detection works on
227
+ * normalized text. Use in both prepare and debounce gate for consistency.
228
+ */
229
+ function stripSlackMentionsForCommandDetection(text) {
230
+ return (text ?? "").replace(/<@[^>]+>/g, " ").replace(/\s+/g, " ").trim();
231
+ }
232
+ function normalizeSlackSlashCommandName(raw) {
233
+ return raw.replace(/^\/+/, "");
234
+ }
235
+ function resolveSlackSlashCommandConfig(raw) {
236
+ const name = normalizeSlackSlashCommandName(raw?.name?.trim() || "moldclaw") || "moldclaw";
237
+ return {
238
+ enabled: raw?.enabled === true,
239
+ name,
240
+ sessionPrefix: raw?.sessionPrefix?.trim() || "slack:slash",
241
+ ephemeral: raw?.ephemeral !== false
242
+ };
243
+ }
244
+ function buildSlackSlashCommandMatcher(name) {
245
+ const escaped = normalizeSlackSlashCommandName(name).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
246
+ return new RegExp(`^/?${escaped}$`);
247
+ }
248
+ //#endregion
249
+ //#region extensions/slack/src/monitor/policy.ts
250
+ function isSlackChannelAllowedByPolicy(params) {
251
+ return evaluateGroupRouteAccessForPolicy({
252
+ groupPolicy: params.groupPolicy,
253
+ routeAllowlistConfigured: params.channelAllowlistConfigured,
254
+ routeMatched: params.channelAllowed
255
+ }).allowed;
256
+ }
257
+ //#endregion
258
+ //#region extensions/slack/src/monitor/channel-config.ts
259
+ function firstDefined(...values) {
260
+ for (const value of values) if (typeof value !== "undefined") return value;
261
+ }
262
+ function resolveSlackChannelLabel(params) {
263
+ const channelName = params.channelName?.trim();
264
+ if (channelName) return `#${normalizeSlackSlug(channelName) || channelName}`;
265
+ const channelId = params.channelId?.trim();
266
+ return channelId ? `#${channelId}` : "unknown channel";
267
+ }
268
+ function resolveSlackChannelConfig(params) {
269
+ const { channelId, channelName, channels, channelKeys, defaultRequireMention, allowNameMatching } = params;
270
+ const entries = channels ?? {};
271
+ const keys = channelKeys ?? Object.keys(entries);
272
+ const normalizedName = channelName ? normalizeSlackSlug(channelName) : "";
273
+ const directName = channelName ? channelName.trim() : "";
274
+ const channelIdLower = channelId.toLowerCase();
275
+ const channelIdUpper = channelId.toUpperCase();
276
+ const match = resolveChannelEntryMatchWithFallback({
277
+ entries,
278
+ keys: buildChannelKeyCandidates(channelId, channelIdLower !== channelId ? channelIdLower : void 0, channelIdUpper !== channelId ? channelIdUpper : void 0, allowNameMatching ? channelName ? `#${directName}` : void 0 : void 0, allowNameMatching ? directName : void 0, allowNameMatching ? normalizedName : void 0),
279
+ wildcardKey: "*"
280
+ });
281
+ const { entry: matched, wildcardEntry: fallback } = match;
282
+ const requireMentionDefault = defaultRequireMention ?? true;
283
+ if (keys.length === 0) return {
284
+ allowed: true,
285
+ requireMention: requireMentionDefault
286
+ };
287
+ if (!matched && !fallback) return {
288
+ allowed: false,
289
+ requireMention: requireMentionDefault
290
+ };
291
+ const resolved = matched ?? fallback ?? {};
292
+ return applyChannelMatchMeta({
293
+ allowed: firstDefined(resolved.enabled, resolved.allow, fallback?.enabled, fallback?.allow, true) ?? true,
294
+ requireMention: firstDefined(resolved.requireMention, fallback?.requireMention, requireMentionDefault) ?? requireMentionDefault,
295
+ allowBots: firstDefined(resolved.allowBots, fallback?.allowBots),
296
+ users: firstDefined(resolved.users, fallback?.users),
297
+ skills: firstDefined(resolved.skills, fallback?.skills),
298
+ systemPrompt: firstDefined(resolved.systemPrompt, fallback?.systemPrompt)
299
+ }, match);
300
+ }
301
+ //#endregion
302
+ //#region extensions/slack/src/monitor/channel-type.ts
303
+ function inferSlackChannelType(channelId) {
304
+ const trimmed = channelId?.trim();
305
+ if (!trimmed) return;
306
+ if (trimmed.startsWith("D")) return "im";
307
+ if (trimmed.startsWith("C")) return "channel";
308
+ if (trimmed.startsWith("G")) return "group";
309
+ }
310
+ function normalizeSlackChannelType(channelType, channelId) {
311
+ const normalized = channelType?.trim().toLowerCase();
312
+ const inferred = inferSlackChannelType(channelId);
313
+ if (normalized === "im" || normalized === "mpim" || normalized === "channel" || normalized === "group") {
314
+ if (inferred === "im" && normalized !== "im") return "im";
315
+ return normalized;
316
+ }
317
+ return inferred ?? "channel";
318
+ }
319
+ //#endregion
320
+ //#region extensions/slack/src/monitor/context.ts
321
+ function createSlackMonitorContext(params) {
322
+ const channelHistories = /* @__PURE__ */ new Map();
323
+ const logger = getChildLogger({ module: "slack-auto-reply" });
324
+ const channelCache = /* @__PURE__ */ new Map();
325
+ const userCache = /* @__PURE__ */ new Map();
326
+ const seenMessages = createDedupeCache({
327
+ ttlMs: 6e4,
328
+ maxSize: 500
329
+ });
330
+ const allowFrom = normalizeAllowList(params.allowFrom);
331
+ const groupDmChannels = normalizeAllowList(params.groupDmChannels);
332
+ const groupDmChannelsLower = normalizeAllowListLower(groupDmChannels);
333
+ const defaultRequireMention = params.defaultRequireMention ?? true;
334
+ const hasChannelAllowlistConfig = Object.keys(params.channelsConfig ?? {}).length > 0;
335
+ const channelsConfigKeys = Object.keys(params.channelsConfig ?? {});
336
+ const markMessageSeen = (channelId, ts) => {
337
+ if (!channelId || !ts) return false;
338
+ return seenMessages.check(`${channelId}:${ts}`);
339
+ };
340
+ const resolveSlackSystemEventSessionKey = (p) => {
341
+ const channelId = p.channelId?.trim() ?? "";
342
+ if (!channelId) return params.mainKey;
343
+ const channelType = normalizeSlackChannelType(p.channelType, channelId);
344
+ const isDirectMessage = channelType === "im";
345
+ const isGroup = channelType === "mpim";
346
+ const from = isDirectMessage ? `slack:${channelId}` : isGroup ? `slack:group:${channelId}` : `slack:channel:${channelId}`;
347
+ const chatType = isDirectMessage ? "direct" : isGroup ? "group" : "channel";
348
+ const senderId = p.senderId?.trim() ?? "";
349
+ try {
350
+ const peerKind = isDirectMessage ? "direct" : isGroup ? "group" : "channel";
351
+ const peerId = isDirectMessage ? senderId : channelId;
352
+ if (peerId) return resolveAgentRoute({
353
+ cfg: params.cfg,
354
+ channel: "slack",
355
+ accountId: params.accountId,
356
+ teamId: params.teamId,
357
+ peer: {
358
+ kind: peerKind,
359
+ id: peerId
360
+ }
361
+ }).sessionKey;
362
+ } catch {}
363
+ return resolveSessionKey(params.sessionScope, {
364
+ From: from,
365
+ ChatType: chatType,
366
+ Provider: "slack"
367
+ }, params.mainKey);
368
+ };
369
+ const resolveChannelName = async (channelId) => {
370
+ const cached = channelCache.get(channelId);
371
+ if (cached) return cached;
372
+ try {
373
+ const info = await params.app.client.conversations.info({
374
+ token: params.botToken,
375
+ channel: channelId
376
+ });
377
+ const name = info.channel && "name" in info.channel ? info.channel.name : void 0;
378
+ const channel = info.channel ?? void 0;
379
+ const entry = {
380
+ name,
381
+ type: channel?.is_im ? "im" : channel?.is_mpim ? "mpim" : channel?.is_channel ? "channel" : channel?.is_group ? "group" : void 0,
382
+ topic: channel && "topic" in channel ? channel.topic?.value ?? void 0 : void 0,
383
+ purpose: channel && "purpose" in channel ? channel.purpose?.value ?? void 0 : void 0
384
+ };
385
+ channelCache.set(channelId, entry);
386
+ return entry;
387
+ } catch {
388
+ return {};
389
+ }
390
+ };
391
+ const resolveUserName = async (userId) => {
392
+ const cached = userCache.get(userId);
393
+ if (cached) return cached;
394
+ try {
395
+ const info = await params.app.client.users.info({
396
+ token: params.botToken,
397
+ user: userId
398
+ });
399
+ const profile = info.user?.profile;
400
+ const entry = { name: profile?.display_name || profile?.real_name || info.user?.name || void 0 };
401
+ userCache.set(userId, entry);
402
+ return entry;
403
+ } catch {
404
+ return {};
405
+ }
406
+ };
407
+ const setSlackThreadStatus = async (p) => {
408
+ if (!p.threadTs) return;
409
+ const payload = {
410
+ token: params.botToken,
411
+ channel_id: p.channelId,
412
+ thread_ts: p.threadTs,
413
+ status: p.status
414
+ };
415
+ const client = params.app.client;
416
+ try {
417
+ if (client.assistant?.threads?.setStatus) {
418
+ await client.assistant.threads.setStatus(payload);
419
+ return;
420
+ }
421
+ if (typeof client.apiCall === "function") await client.apiCall("assistant.threads.setStatus", payload);
422
+ } catch (err) {
423
+ logVerbose(`slack status update failed for channel ${p.channelId}: ${String(err)}`);
424
+ }
425
+ };
426
+ const isChannelAllowed = (p) => {
427
+ const channelType = normalizeSlackChannelType(p.channelType, p.channelId);
428
+ const isDirectMessage = channelType === "im";
429
+ const isGroupDm = channelType === "mpim";
430
+ const isRoom = channelType === "channel" || channelType === "group";
431
+ if (isDirectMessage && !params.dmEnabled) return false;
432
+ if (isGroupDm && !params.groupDmEnabled) return false;
433
+ if (isGroupDm && groupDmChannels.length > 0) {
434
+ const candidates = [
435
+ p.channelId,
436
+ p.channelName ? `#${p.channelName}` : void 0,
437
+ p.channelName,
438
+ p.channelName ? normalizeSlackSlug(p.channelName) : void 0
439
+ ].filter((value) => Boolean(value)).map((value) => value.toLowerCase());
440
+ if (!(groupDmChannelsLower.includes("*") || candidates.some((candidate) => groupDmChannelsLower.includes(candidate)))) return false;
441
+ }
442
+ if (isRoom && p.channelId) {
443
+ const channelConfig = resolveSlackChannelConfig({
444
+ channelId: p.channelId,
445
+ channelName: p.channelName,
446
+ channels: params.channelsConfig,
447
+ channelKeys: channelsConfigKeys,
448
+ defaultRequireMention,
449
+ allowNameMatching: params.allowNameMatching
450
+ });
451
+ const channelMatchMeta = formatAllowlistMatchMeta(channelConfig);
452
+ const channelAllowed = channelConfig?.allowed !== false;
453
+ const channelAllowlistConfigured = hasChannelAllowlistConfig;
454
+ if (!isSlackChannelAllowedByPolicy({
455
+ groupPolicy: params.groupPolicy,
456
+ channelAllowlistConfigured,
457
+ channelAllowed
458
+ })) {
459
+ logVerbose(`slack: drop channel ${p.channelId} (groupPolicy=${params.groupPolicy}, ${channelMatchMeta})`);
460
+ return false;
461
+ }
462
+ const hasExplicitConfig = Boolean(channelConfig?.matchSource);
463
+ if (!channelAllowed && (params.groupPolicy !== "open" || hasExplicitConfig)) {
464
+ logVerbose(`slack: drop channel ${p.channelId} (${channelMatchMeta})`);
465
+ return false;
466
+ }
467
+ logVerbose(`slack: allow channel ${p.channelId} (${channelMatchMeta})`);
468
+ }
469
+ return true;
470
+ };
471
+ const shouldDropMismatchedSlackEvent = (body) => {
472
+ if (!body || typeof body !== "object") return false;
473
+ const raw = body;
474
+ const incomingApiAppId = typeof raw.api_app_id === "string" ? raw.api_app_id : "";
475
+ const incomingTeamId = typeof raw.team_id === "string" ? raw.team_id : typeof raw.team?.id === "string" ? raw.team.id : "";
476
+ if (params.apiAppId && incomingApiAppId && incomingApiAppId !== params.apiAppId) {
477
+ logVerbose(`slack: drop event with api_app_id=${incomingApiAppId} (expected ${params.apiAppId})`);
478
+ return true;
479
+ }
480
+ if (params.teamId && incomingTeamId && incomingTeamId !== params.teamId) {
481
+ logVerbose(`slack: drop event with team_id=${incomingTeamId} (expected ${params.teamId})`);
482
+ return true;
483
+ }
484
+ return false;
485
+ };
486
+ return {
487
+ cfg: params.cfg,
488
+ accountId: params.accountId,
489
+ botToken: params.botToken,
490
+ app: params.app,
491
+ runtime: params.runtime,
492
+ botUserId: params.botUserId,
493
+ teamId: params.teamId,
494
+ apiAppId: params.apiAppId,
495
+ historyLimit: params.historyLimit,
496
+ channelHistories,
497
+ sessionScope: params.sessionScope,
498
+ mainKey: params.mainKey,
499
+ dmEnabled: params.dmEnabled,
500
+ dmPolicy: params.dmPolicy,
501
+ allowFrom,
502
+ allowNameMatching: params.allowNameMatching,
503
+ groupDmEnabled: params.groupDmEnabled,
504
+ groupDmChannels,
505
+ defaultRequireMention,
506
+ channelsConfig: params.channelsConfig,
507
+ channelsConfigKeys,
508
+ groupPolicy: params.groupPolicy,
509
+ useAccessGroups: params.useAccessGroups,
510
+ reactionMode: params.reactionMode,
511
+ reactionAllowlist: params.reactionAllowlist,
512
+ replyToMode: params.replyToMode,
513
+ threadHistoryScope: params.threadHistoryScope,
514
+ threadInheritParent: params.threadInheritParent,
515
+ slashCommand: params.slashCommand,
516
+ textLimit: params.textLimit,
517
+ ackReactionScope: params.ackReactionScope,
518
+ typingReaction: params.typingReaction,
519
+ mediaMaxBytes: params.mediaMaxBytes,
520
+ removeAckAfterReply: params.removeAckAfterReply,
521
+ logger,
522
+ markMessageSeen,
523
+ shouldDropMismatchedSlackEvent,
524
+ resolveSlackSystemEventSessionKey,
525
+ isChannelAllowed,
526
+ resolveChannelName,
527
+ resolveUserName,
528
+ setSlackThreadStatus
529
+ };
530
+ }
531
+ //#endregion
532
+ //#region extensions/slack/src/channel-migration.ts
533
+ function resolveAccountChannels(cfg, accountId) {
534
+ if (!accountId) return {};
535
+ const normalized = normalizeAccountId(accountId);
536
+ const accounts = cfg.channels?.slack?.accounts;
537
+ if (!accounts || typeof accounts !== "object") return {};
538
+ const exact = accounts[normalized];
539
+ if (exact?.channels) return { channels: exact.channels };
540
+ const matchKey = Object.keys(accounts).find((key) => key.toLowerCase() === normalized.toLowerCase());
541
+ return { channels: matchKey ? accounts[matchKey]?.channels : void 0 };
542
+ }
543
+ function migrateSlackChannelsInPlace(channels, oldChannelId, newChannelId) {
544
+ if (!channels) return {
545
+ migrated: false,
546
+ skippedExisting: false
547
+ };
548
+ if (oldChannelId === newChannelId) return {
549
+ migrated: false,
550
+ skippedExisting: false
551
+ };
552
+ if (!Object.hasOwn(channels, oldChannelId)) return {
553
+ migrated: false,
554
+ skippedExisting: false
555
+ };
556
+ if (Object.hasOwn(channels, newChannelId)) return {
557
+ migrated: false,
558
+ skippedExisting: true
559
+ };
560
+ channels[newChannelId] = channels[oldChannelId];
561
+ delete channels[oldChannelId];
562
+ return {
563
+ migrated: true,
564
+ skippedExisting: false
565
+ };
566
+ }
567
+ function migrateSlackChannelConfig(params) {
568
+ const scopes = [];
569
+ let migrated = false;
570
+ let skippedExisting = false;
571
+ const accountChannels = resolveAccountChannels(params.cfg, params.accountId).channels;
572
+ if (accountChannels) {
573
+ const result = migrateSlackChannelsInPlace(accountChannels, params.oldChannelId, params.newChannelId);
574
+ if (result.migrated) {
575
+ migrated = true;
576
+ scopes.push("account");
577
+ }
578
+ if (result.skippedExisting) skippedExisting = true;
579
+ }
580
+ const globalChannels = params.cfg.channels?.slack?.channels;
581
+ if (globalChannels) {
582
+ const result = migrateSlackChannelsInPlace(globalChannels, params.oldChannelId, params.newChannelId);
583
+ if (result.migrated) {
584
+ migrated = true;
585
+ scopes.push("global");
586
+ }
587
+ if (result.skippedExisting) skippedExisting = true;
588
+ }
589
+ return {
590
+ migrated,
591
+ skippedExisting,
592
+ scopes
593
+ };
594
+ }
595
+ //#endregion
596
+ //#region extensions/slack/src/monitor/events/channels.ts
597
+ function registerSlackChannelEvents(params) {
598
+ const { ctx, trackEvent } = params;
599
+ const enqueueChannelSystemEvent = (params) => {
600
+ if (!ctx.isChannelAllowed({
601
+ channelId: params.channelId,
602
+ channelName: params.channelName,
603
+ channelType: "channel"
604
+ })) return;
605
+ const label = resolveSlackChannelLabel({
606
+ channelId: params.channelId,
607
+ channelName: params.channelName
608
+ });
609
+ const sessionKey = ctx.resolveSlackSystemEventSessionKey({
610
+ channelId: params.channelId,
611
+ channelType: "channel"
612
+ });
613
+ enqueueSystemEvent(`Slack channel ${params.kind}: ${label}.`, {
614
+ sessionKey,
615
+ contextKey: `slack:channel:${params.kind}:${params.channelId ?? params.channelName ?? "unknown"}`
616
+ });
617
+ };
618
+ ctx.app.event("channel_created", async ({ event, body }) => {
619
+ try {
620
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
621
+ trackEvent?.();
622
+ const payload = event;
623
+ const channelId = payload.channel?.id;
624
+ const channelName = payload.channel?.name;
625
+ enqueueChannelSystemEvent({
626
+ kind: "created",
627
+ channelId,
628
+ channelName
629
+ });
630
+ } catch (err) {
631
+ ctx.runtime.error?.(danger(`slack channel created handler failed: ${String(err)}`));
632
+ }
633
+ });
634
+ ctx.app.event("channel_rename", async ({ event, body }) => {
635
+ try {
636
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
637
+ trackEvent?.();
638
+ const payload = event;
639
+ const channelId = payload.channel?.id;
640
+ enqueueChannelSystemEvent({
641
+ kind: "renamed",
642
+ channelId,
643
+ channelName: payload.channel?.name_normalized ?? payload.channel?.name
644
+ });
645
+ } catch (err) {
646
+ ctx.runtime.error?.(danger(`slack channel rename handler failed: ${String(err)}`));
647
+ }
648
+ });
649
+ ctx.app.event("channel_id_changed", async ({ event, body }) => {
650
+ try {
651
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
652
+ trackEvent?.();
653
+ const payload = event;
654
+ const oldChannelId = payload.old_channel_id;
655
+ const newChannelId = payload.new_channel_id;
656
+ if (!oldChannelId || !newChannelId) return;
657
+ const label = resolveSlackChannelLabel({
658
+ channelId: newChannelId,
659
+ channelName: (await ctx.resolveChannelName(newChannelId))?.name
660
+ });
661
+ ctx.runtime.log?.(warn(`[slack] Channel ID changed: ${oldChannelId} → ${newChannelId} (${label})`));
662
+ if (!resolveChannelConfigWrites({
663
+ cfg: ctx.cfg,
664
+ channelId: "slack",
665
+ accountId: ctx.accountId
666
+ })) {
667
+ ctx.runtime.log?.(warn("[slack] Config writes disabled; skipping channel config migration."));
668
+ return;
669
+ }
670
+ const currentConfig = loadConfig();
671
+ const migration = migrateSlackChannelConfig({
672
+ cfg: currentConfig,
673
+ accountId: ctx.accountId,
674
+ oldChannelId,
675
+ newChannelId
676
+ });
677
+ if (migration.migrated) {
678
+ migrateSlackChannelConfig({
679
+ cfg: ctx.cfg,
680
+ accountId: ctx.accountId,
681
+ oldChannelId,
682
+ newChannelId
683
+ });
684
+ await writeConfigFile(currentConfig);
685
+ ctx.runtime.log?.(warn("[slack] Channel config migrated and saved successfully."));
686
+ } else if (migration.skippedExisting) ctx.runtime.log?.(warn(`[slack] Channel config already exists for ${newChannelId}; leaving ${oldChannelId} unchanged`));
687
+ else ctx.runtime.log?.(warn(`[slack] No config found for old channel ID ${oldChannelId}; migration logged only`));
688
+ } catch (err) {
689
+ ctx.runtime.error?.(danger(`slack channel_id_changed handler failed: ${String(err)}`));
690
+ }
691
+ });
692
+ }
693
+ //#endregion
694
+ //#region extensions/slack/src/monitor/auth.ts
695
+ let slackAllowFromCache = /* @__PURE__ */ new WeakMap();
696
+ const DEFAULT_PAIRING_ALLOW_FROM_CACHE_TTL_MS = 5e3;
697
+ function getPairingAllowFromCacheTtlMs() {
698
+ const raw = process.env.MOLDCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS?.trim();
699
+ if (!raw) return DEFAULT_PAIRING_ALLOW_FROM_CACHE_TTL_MS;
700
+ const parsed = Number(raw);
701
+ if (!Number.isFinite(parsed)) return DEFAULT_PAIRING_ALLOW_FROM_CACHE_TTL_MS;
702
+ return Math.max(0, Math.floor(parsed));
703
+ }
704
+ function getAllowFromCacheState(ctx) {
705
+ const existing = slackAllowFromCache.get(ctx);
706
+ if (existing) return existing;
707
+ const next = {};
708
+ slackAllowFromCache.set(ctx, next);
709
+ return next;
710
+ }
711
+ function buildBaseAllowFrom(ctx) {
712
+ const allowFrom = normalizeAllowList(ctx.allowFrom);
713
+ return {
714
+ allowFrom,
715
+ allowFromLower: normalizeAllowListLower(allowFrom)
716
+ };
717
+ }
718
+ async function resolveSlackEffectiveAllowFrom(ctx, options) {
719
+ const includePairingStore = options?.includePairingStore === true;
720
+ const cache = getAllowFromCacheState(ctx);
721
+ const baseSignature = JSON.stringify(ctx.allowFrom);
722
+ if (cache.baseSignature !== baseSignature || !cache.base) {
723
+ cache.baseSignature = baseSignature;
724
+ cache.base = buildBaseAllowFrom(ctx);
725
+ cache.pairing = void 0;
726
+ cache.pairingKey = void 0;
727
+ cache.pairingExpiresAtMs = void 0;
728
+ cache.pairingPending = void 0;
729
+ }
730
+ if (!includePairingStore) return cache.base;
731
+ const ttlMs = getPairingAllowFromCacheTtlMs();
732
+ const nowMs = Date.now();
733
+ const pairingKey = `${ctx.accountId}:${ctx.dmPolicy}`;
734
+ if (ttlMs > 0 && cache.pairing && cache.pairingKey === pairingKey && (cache.pairingExpiresAtMs ?? 0) >= nowMs) return cache.pairing;
735
+ if (cache.pairingPending && cache.pairingKey === pairingKey) return await cache.pairingPending;
736
+ const pairingPending = (async () => {
737
+ let storeAllowFrom = [];
738
+ try {
739
+ const resolved = await readStoreAllowFromForDmPolicy({
740
+ provider: "slack",
741
+ accountId: ctx.accountId,
742
+ dmPolicy: ctx.dmPolicy
743
+ });
744
+ storeAllowFrom = Array.isArray(resolved) ? resolved : [];
745
+ } catch {
746
+ storeAllowFrom = [];
747
+ }
748
+ const allowFrom = normalizeAllowList([...cache.base?.allowFrom ?? [], ...storeAllowFrom]);
749
+ return {
750
+ allowFrom,
751
+ allowFromLower: normalizeAllowListLower(allowFrom)
752
+ };
753
+ })();
754
+ cache.pairingKey = pairingKey;
755
+ cache.pairingPending = pairingPending;
756
+ try {
757
+ const resolved = await pairingPending;
758
+ if (ttlMs > 0) {
759
+ cache.pairing = resolved;
760
+ cache.pairingExpiresAtMs = nowMs + ttlMs;
761
+ } else {
762
+ cache.pairing = void 0;
763
+ cache.pairingExpiresAtMs = void 0;
764
+ }
765
+ return resolved;
766
+ } finally {
767
+ if (cache.pairingPending === pairingPending) cache.pairingPending = void 0;
768
+ }
769
+ }
770
+ function isSlackSenderAllowListed(params) {
771
+ const { allowListLower, senderId, senderName, allowNameMatching } = params;
772
+ return allowListLower.length === 0 || allowListMatches({
773
+ allowList: allowListLower,
774
+ id: senderId,
775
+ name: senderName,
776
+ allowNameMatching
777
+ });
778
+ }
779
+ async function authorizeSlackSystemEventSender(params) {
780
+ const senderId = params.senderId?.trim();
781
+ if (!senderId) return {
782
+ allowed: false,
783
+ reason: "missing-sender"
784
+ };
785
+ const expectedSenderId = params.expectedSenderId?.trim();
786
+ if (expectedSenderId && expectedSenderId !== senderId) return {
787
+ allowed: false,
788
+ reason: "sender-mismatch"
789
+ };
790
+ const channelId = params.channelId?.trim();
791
+ let channelType = normalizeSlackChannelType(params.channelType, channelId);
792
+ let channelName;
793
+ if (channelId) {
794
+ const info = await params.ctx.resolveChannelName(channelId).catch(() => ({}));
795
+ channelName = info.name;
796
+ channelType = normalizeSlackChannelType(params.channelType ?? info.type, channelId);
797
+ if (!params.ctx.isChannelAllowed({
798
+ channelId,
799
+ channelName,
800
+ channelType
801
+ })) return {
802
+ allowed: false,
803
+ reason: "channel-not-allowed",
804
+ channelType,
805
+ channelName
806
+ };
807
+ }
808
+ const senderName = (await params.ctx.resolveUserName(senderId).catch(() => ({}))).name;
809
+ const resolveAllowFromLower = async (includePairingStore = false) => (await resolveSlackEffectiveAllowFrom(params.ctx, { includePairingStore })).allowFromLower;
810
+ if (channelType === "im") {
811
+ if (!params.ctx.dmEnabled || params.ctx.dmPolicy === "disabled") return {
812
+ allowed: false,
813
+ reason: "dm-disabled",
814
+ channelType,
815
+ channelName
816
+ };
817
+ if (params.ctx.dmPolicy !== "open") {
818
+ if (!isSlackSenderAllowListed({
819
+ allowListLower: await resolveAllowFromLower(true),
820
+ senderId,
821
+ senderName,
822
+ allowNameMatching: params.ctx.allowNameMatching
823
+ })) return {
824
+ allowed: false,
825
+ reason: "sender-not-allowlisted",
826
+ channelType,
827
+ channelName
828
+ };
829
+ }
830
+ } else if (!channelId) {
831
+ const allowFromLower = await resolveAllowFromLower(false);
832
+ if (allowFromLower.length > 0) {
833
+ if (!isSlackSenderAllowListed({
834
+ allowListLower: allowFromLower,
835
+ senderId,
836
+ senderName,
837
+ allowNameMatching: params.ctx.allowNameMatching
838
+ })) return {
839
+ allowed: false,
840
+ reason: "sender-not-allowlisted"
841
+ };
842
+ }
843
+ } else {
844
+ const channelConfig = resolveSlackChannelConfig({
845
+ channelId,
846
+ channelName,
847
+ channels: params.ctx.channelsConfig,
848
+ channelKeys: params.ctx.channelsConfigKeys,
849
+ defaultRequireMention: params.ctx.defaultRequireMention,
850
+ allowNameMatching: params.ctx.allowNameMatching
851
+ });
852
+ if (Array.isArray(channelConfig?.users) && channelConfig.users.length > 0) {
853
+ if (!resolveSlackUserAllowed({
854
+ allowList: channelConfig?.users,
855
+ userId: senderId,
856
+ userName: senderName,
857
+ allowNameMatching: params.ctx.allowNameMatching
858
+ })) return {
859
+ allowed: false,
860
+ reason: "sender-not-channel-allowed",
861
+ channelType,
862
+ channelName
863
+ };
864
+ }
865
+ }
866
+ return {
867
+ allowed: true,
868
+ channelType,
869
+ channelName
870
+ };
871
+ }
872
+ //#endregion
873
+ //#region extensions/slack/src/monitor/mrkdwn.ts
874
+ function escapeSlackMrkdwn(value) {
875
+ return value.replaceAll("\\", "\\\\").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replace(/([*_`~])/g, "\\$1");
876
+ }
877
+ //#endregion
878
+ //#region extensions/slack/src/monitor/events/interactions.block-actions.ts
879
+ function readOptionValues(options) {
880
+ if (!Array.isArray(options)) return;
881
+ const values = options.map((option) => option && typeof option === "object" ? option.value : null).filter((value) => typeof value === "string" && value.trim().length > 0);
882
+ return values.length > 0 ? values : void 0;
883
+ }
884
+ function readOptionLabels(options) {
885
+ if (!Array.isArray(options)) return;
886
+ const labels = options.map((option) => option && typeof option === "object" ? option.text?.text ?? null : null).filter((label) => typeof label === "string" && label.trim().length > 0);
887
+ return labels.length > 0 ? labels : void 0;
888
+ }
889
+ function uniqueNonEmptyStrings(values) {
890
+ const unique = [];
891
+ const seen = /* @__PURE__ */ new Set();
892
+ for (const entry of values) {
893
+ if (typeof entry !== "string") continue;
894
+ const trimmed = entry.trim();
895
+ if (!trimmed || seen.has(trimmed)) continue;
896
+ seen.add(trimmed);
897
+ unique.push(trimmed);
898
+ }
899
+ return unique;
900
+ }
901
+ function collectRichTextFragments(value, out) {
902
+ if (!value || typeof value !== "object") return;
903
+ const typed = value;
904
+ if (typeof typed.text === "string" && typed.text.trim().length > 0) out.push(typed.text.trim());
905
+ if (Array.isArray(typed.elements)) for (const child of typed.elements) collectRichTextFragments(child, out);
906
+ }
907
+ function summarizeRichTextPreview(value) {
908
+ const fragments = [];
909
+ collectRichTextFragments(value, fragments);
910
+ if (fragments.length === 0) return;
911
+ const joined = fragments.join(" ").replace(/\s+/g, " ").trim();
912
+ if (!joined) return;
913
+ const max = 120;
914
+ return joined.length <= max ? joined : `${joined.slice(0, max - 1)}…`;
915
+ }
916
+ function readInteractionAction(raw) {
917
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
918
+ return raw;
919
+ }
920
+ function summarizeAction(action) {
921
+ const typed = action;
922
+ const actionType = typed.type;
923
+ const selectedUsers = uniqueNonEmptyStrings([...typed.selected_user ? [typed.selected_user] : [], ...Array.isArray(typed.selected_users) ? typed.selected_users : []]);
924
+ const selectedChannels = uniqueNonEmptyStrings([...typed.selected_channel ? [typed.selected_channel] : [], ...Array.isArray(typed.selected_channels) ? typed.selected_channels : []]);
925
+ const selectedConversations = uniqueNonEmptyStrings([...typed.selected_conversation ? [typed.selected_conversation] : [], ...Array.isArray(typed.selected_conversations) ? typed.selected_conversations : []]);
926
+ const selectedValues = uniqueNonEmptyStrings([
927
+ ...typed.selected_option?.value ? [typed.selected_option.value] : [],
928
+ ...readOptionValues(typed.selected_options) ?? [],
929
+ ...selectedUsers,
930
+ ...selectedChannels,
931
+ ...selectedConversations
932
+ ]);
933
+ const selectedLabels = uniqueNonEmptyStrings([...typed.selected_option?.text?.text ? [typed.selected_option.text.text] : [], ...readOptionLabels(typed.selected_options) ?? []]);
934
+ const inputValue = typeof typed.value === "string" ? typed.value : void 0;
935
+ const inputNumber = actionType === "number_input" && inputValue != null ? Number.parseFloat(inputValue) : void 0;
936
+ const parsedNumber = Number.isFinite(inputNumber) ? inputNumber : void 0;
937
+ const inputEmail = actionType === "email_text_input" && inputValue?.includes("@") ? inputValue : void 0;
938
+ let inputUrl;
939
+ if (actionType === "url_text_input" && inputValue) try {
940
+ inputUrl = new URL(inputValue).toString();
941
+ } catch {
942
+ inputUrl = void 0;
943
+ }
944
+ const richTextValue = actionType === "rich_text_input" ? typed.rich_text_value : void 0;
945
+ const richTextPreview = summarizeRichTextPreview(richTextValue);
946
+ return {
947
+ actionType,
948
+ inputKind: actionType === "number_input" ? "number" : actionType === "email_text_input" ? "email" : actionType === "url_text_input" ? "url" : actionType === "rich_text_input" ? "rich_text" : inputValue != null ? "text" : void 0,
949
+ value: typed.value,
950
+ selectedValues: selectedValues.length > 0 ? selectedValues : void 0,
951
+ selectedUsers: selectedUsers.length > 0 ? selectedUsers : void 0,
952
+ selectedChannels: selectedChannels.length > 0 ? selectedChannels : void 0,
953
+ selectedConversations: selectedConversations.length > 0 ? selectedConversations : void 0,
954
+ selectedLabels: selectedLabels.length > 0 ? selectedLabels : void 0,
955
+ selectedDate: typed.selected_date,
956
+ selectedTime: typed.selected_time,
957
+ selectedDateTime: typeof typed.selected_date_time === "number" ? typed.selected_date_time : void 0,
958
+ inputValue,
959
+ inputNumber: parsedNumber,
960
+ inputEmail,
961
+ inputUrl,
962
+ richTextValue,
963
+ richTextPreview,
964
+ workflowTriggerUrl: typed.workflow?.trigger_url,
965
+ workflowId: typed.workflow?.workflow_id
966
+ };
967
+ }
968
+ function isBulkActionsBlock(block) {
969
+ return block.type === "actions" && Array.isArray(block.elements) && block.elements.length > 0 && block.elements.every((el) => typeof el.action_id === "string" && el.action_id.includes("_all_"));
970
+ }
971
+ function formatInteractionSelectionLabel(params) {
972
+ if (params.summary.actionType === "button" && params.buttonText?.trim()) return params.buttonText.trim();
973
+ if (params.summary.selectedLabels?.length) {
974
+ if (params.summary.selectedLabels.length <= 3) return params.summary.selectedLabels.join(", ");
975
+ return `${params.summary.selectedLabels.slice(0, 3).join(", ")} +${params.summary.selectedLabels.length - 3}`;
976
+ }
977
+ if (params.summary.selectedValues?.length) {
978
+ if (params.summary.selectedValues.length <= 3) return params.summary.selectedValues.join(", ");
979
+ return `${params.summary.selectedValues.slice(0, 3).join(", ")} +${params.summary.selectedValues.length - 3}`;
980
+ }
981
+ if (params.summary.selectedDate) return params.summary.selectedDate;
982
+ if (params.summary.selectedTime) return params.summary.selectedTime;
983
+ if (typeof params.summary.selectedDateTime === "number") return (/* @__PURE__ */ new Date(params.summary.selectedDateTime * 1e3)).toISOString();
984
+ if (params.summary.richTextPreview) return params.summary.richTextPreview;
985
+ if (params.summary.value?.trim()) return params.summary.value.trim();
986
+ return params.actionId;
987
+ }
988
+ function formatInteractionConfirmationText(params) {
989
+ const actor = params.userId?.trim() ? ` by <@${params.userId.trim()}>` : "";
990
+ return `:white_check_mark: *${escapeSlackMrkdwn(params.selectedLabel)}* selected${actor}`;
991
+ }
992
+ function buildSlackPluginInteractionData(params) {
993
+ const actionId = params.actionId.trim();
994
+ if (!actionId) return null;
995
+ const payload = params.summary.value?.trim() || params.summary.selectedValues?.map((value) => value.trim()).find(Boolean) || "";
996
+ if (actionId === "moldclaw:reply_button" || actionId === "moldclaw:reply_select") return payload || null;
997
+ return payload ? `${actionId}:${payload}` : actionId;
998
+ }
999
+ function buildSlackPluginInteractionId(params) {
1000
+ const primaryValue = params.summary.value?.trim() || params.summary.selectedValues?.map((value) => value.trim()).find(Boolean) || "";
1001
+ return [
1002
+ params.userId?.trim() || "",
1003
+ params.channelId?.trim() || "",
1004
+ params.messageTs?.trim() || "",
1005
+ params.triggerId?.trim() || "",
1006
+ params.actionId.trim(),
1007
+ primaryValue
1008
+ ].join(":");
1009
+ }
1010
+ function parseSlackBlockAction(params) {
1011
+ const typedBody = params.body;
1012
+ const typedAction = readInteractionAction(params.action);
1013
+ if (!typedAction) {
1014
+ params.log?.(`slack:interaction malformed action payload channel=${typedBody.channel?.id ?? typedBody.container?.channel_id ?? "unknown"} user=${typedBody.user?.id ?? "unknown"}`);
1015
+ return null;
1016
+ }
1017
+ const typedActionWithText = typedAction;
1018
+ return {
1019
+ typedBody,
1020
+ typedAction,
1021
+ typedActionWithText,
1022
+ actionId: typeof typedActionWithText.action_id === "string" ? typedActionWithText.action_id : "unknown",
1023
+ blockId: typedActionWithText.block_id,
1024
+ userId: typedBody.user?.id ?? "unknown",
1025
+ channelId: typedBody.channel?.id ?? typedBody.container?.channel_id,
1026
+ messageTs: typedBody.message?.ts ?? typedBody.container?.message_ts,
1027
+ threadTs: typedBody.container?.thread_ts,
1028
+ actionSummary: summarizeAction(typedAction)
1029
+ };
1030
+ }
1031
+ async function respondEphemeral(respond, text) {
1032
+ if (!respond) return;
1033
+ try {
1034
+ await respond({
1035
+ text,
1036
+ response_type: "ephemeral"
1037
+ });
1038
+ } catch {}
1039
+ }
1040
+ async function updateSlackInteractionMessage(params) {
1041
+ if (!params.channelId || !params.messageTs) return;
1042
+ await params.ctx.app.client.chat.update({
1043
+ channel: params.channelId,
1044
+ ts: params.messageTs,
1045
+ text: params.text,
1046
+ ...params.blocks ? { blocks: params.blocks } : {}
1047
+ });
1048
+ }
1049
+ async function authorizeSlackBlockAction(params) {
1050
+ const auth = await authorizeSlackSystemEventSender({
1051
+ ctx: params.ctx,
1052
+ senderId: params.parsed.userId,
1053
+ channelId: params.parsed.channelId
1054
+ });
1055
+ if (auth.allowed) return auth;
1056
+ params.ctx.runtime.log?.(`slack:interaction drop action=${params.parsed.actionId} user=${params.parsed.userId} channel=${params.parsed.channelId ?? "unknown"} reason=${auth.reason ?? "unauthorized"}`);
1057
+ await respondEphemeral(params.respond, "You are not authorized to use this control.");
1058
+ return { allowed: false };
1059
+ }
1060
+ async function handleSlackPluginBindingApproval(params) {
1061
+ const pluginBindingApproval = parsePluginBindingApprovalCustomId(params.pluginInteractionData);
1062
+ if (!pluginBindingApproval) return false;
1063
+ const resolved = await resolvePluginConversationBindingApproval({
1064
+ approvalId: pluginBindingApproval.approvalId,
1065
+ decision: pluginBindingApproval.decision,
1066
+ senderId: params.parsed.userId
1067
+ });
1068
+ try {
1069
+ await updateSlackInteractionMessage({
1070
+ ctx: params.ctx,
1071
+ channelId: params.parsed.channelId,
1072
+ messageTs: params.parsed.messageTs,
1073
+ text: params.parsed.typedBody.message?.text ?? "",
1074
+ blocks: []
1075
+ });
1076
+ } catch {}
1077
+ await respondEphemeral(params.respond, buildPluginBindingResolvedText(resolved));
1078
+ return true;
1079
+ }
1080
+ async function dispatchSlackPluginInteraction(params) {
1081
+ const pluginInteractionId = buildSlackPluginInteractionId({
1082
+ userId: params.parsed.userId,
1083
+ channelId: params.parsed.channelId,
1084
+ messageTs: params.parsed.messageTs,
1085
+ triggerId: params.parsed.typedBody.trigger_id,
1086
+ actionId: params.parsed.actionId,
1087
+ summary: params.parsed.actionSummary
1088
+ });
1089
+ if (await handleSlackPluginBindingApproval({
1090
+ ctx: params.ctx,
1091
+ parsed: params.parsed,
1092
+ pluginInteractionData: params.pluginInteractionData,
1093
+ respond: params.respond
1094
+ })) return true;
1095
+ const pluginResult = await dispatchPluginInteractiveHandler({
1096
+ channel: "slack",
1097
+ data: params.pluginInteractionData,
1098
+ interactionId: pluginInteractionId,
1099
+ ctx: {
1100
+ accountId: params.ctx.accountId,
1101
+ interactionId: pluginInteractionId,
1102
+ conversationId: params.parsed.channelId ?? "",
1103
+ parentConversationId: void 0,
1104
+ threadId: params.parsed.threadTs,
1105
+ senderId: params.parsed.userId,
1106
+ senderUsername: void 0,
1107
+ auth: params.auth,
1108
+ interaction: {
1109
+ kind: params.parsed.actionSummary.actionType === "button" ? "button" : "select",
1110
+ actionId: params.parsed.actionId,
1111
+ blockId: params.parsed.blockId,
1112
+ messageTs: params.parsed.messageTs,
1113
+ threadTs: params.parsed.threadTs,
1114
+ value: params.parsed.actionSummary.value,
1115
+ selectedValues: params.parsed.actionSummary.selectedValues,
1116
+ selectedLabels: params.parsed.actionSummary.selectedLabels,
1117
+ triggerId: params.parsed.typedBody.trigger_id,
1118
+ responseUrl: params.parsed.typedBody.response_url
1119
+ }
1120
+ },
1121
+ respond: {
1122
+ acknowledge: async () => {},
1123
+ reply: async ({ text, responseType }) => {
1124
+ if (!text) return;
1125
+ await params.respond?.({
1126
+ text,
1127
+ response_type: responseType ?? "ephemeral"
1128
+ });
1129
+ },
1130
+ followUp: async ({ text, responseType }) => {
1131
+ if (!text) return;
1132
+ await params.respond?.({
1133
+ text,
1134
+ response_type: responseType ?? "ephemeral"
1135
+ });
1136
+ },
1137
+ editMessage: async ({ text, blocks }) => {
1138
+ await updateSlackInteractionMessage({
1139
+ ctx: params.ctx,
1140
+ channelId: params.parsed.channelId,
1141
+ messageTs: params.parsed.messageTs,
1142
+ text: text ?? params.parsed.typedBody.message?.text ?? "",
1143
+ blocks: Array.isArray(blocks) ? blocks : void 0
1144
+ });
1145
+ }
1146
+ }
1147
+ });
1148
+ return pluginResult.matched && pluginResult.handled;
1149
+ }
1150
+ function enqueueSlackBlockActionEvent(params) {
1151
+ const eventPayload = {
1152
+ interactionType: "block_action",
1153
+ actionId: params.parsed.actionId,
1154
+ blockId: params.parsed.blockId,
1155
+ ...params.parsed.actionSummary,
1156
+ userId: params.parsed.userId,
1157
+ teamId: params.parsed.typedBody.team?.id,
1158
+ triggerId: params.parsed.typedBody.trigger_id,
1159
+ responseUrl: params.parsed.typedBody.response_url,
1160
+ channelId: params.parsed.channelId,
1161
+ messageTs: params.parsed.messageTs,
1162
+ threadTs: params.parsed.threadTs
1163
+ };
1164
+ params.ctx.runtime.log?.(`slack:interaction action=${params.parsed.actionId} type=${params.parsed.actionSummary.actionType ?? "unknown"} user=${params.parsed.userId} channel=${params.parsed.channelId}`);
1165
+ const sessionKey = params.ctx.resolveSlackSystemEventSessionKey({
1166
+ channelId: params.parsed.channelId,
1167
+ channelType: params.auth.channelType,
1168
+ senderId: params.parsed.userId
1169
+ });
1170
+ const contextParts = [
1171
+ "slack:interaction",
1172
+ params.parsed.channelId,
1173
+ params.parsed.messageTs,
1174
+ params.parsed.actionId
1175
+ ].filter(Boolean);
1176
+ enqueueSystemEvent(params.formatSystemEvent(eventPayload), {
1177
+ sessionKey,
1178
+ contextKey: contextParts.join(":")
1179
+ });
1180
+ }
1181
+ function buildSlackConfirmationBlocks(params) {
1182
+ const selectedLabel = formatInteractionSelectionLabel({
1183
+ actionId: params.parsed.actionId,
1184
+ summary: params.parsed.actionSummary,
1185
+ buttonText: params.parsed.typedActionWithText.text?.text
1186
+ });
1187
+ let updatedBlocks = params.originalBlocks.map((block) => {
1188
+ const typedBlock = block;
1189
+ if (typedBlock.type === "actions" && typedBlock.block_id === params.parsed.blockId) return {
1190
+ type: "context",
1191
+ elements: [{
1192
+ type: "mrkdwn",
1193
+ text: formatInteractionConfirmationText({
1194
+ selectedLabel,
1195
+ userId: params.parsed.userId
1196
+ })
1197
+ }]
1198
+ };
1199
+ return block;
1200
+ });
1201
+ if (!updatedBlocks.some((block) => {
1202
+ const typedBlock = block;
1203
+ return typedBlock.type === "actions" && !isBulkActionsBlock(typedBlock);
1204
+ })) updatedBlocks = updatedBlocks.filter((block, index) => {
1205
+ const typedBlock = block;
1206
+ if (isBulkActionsBlock(typedBlock)) return false;
1207
+ if (typedBlock.type !== "divider") return true;
1208
+ const next = updatedBlocks[index + 1];
1209
+ return !next || !isBulkActionsBlock(next);
1210
+ });
1211
+ return updatedBlocks;
1212
+ }
1213
+ async function updateSlackLegacyBlockAction(params) {
1214
+ const originalBlocks = params.parsed.typedBody.message?.blocks;
1215
+ if (!Array.isArray(originalBlocks) || !params.parsed.channelId || !params.parsed.messageTs || !params.parsed.blockId) return;
1216
+ try {
1217
+ await updateSlackInteractionMessage({
1218
+ ctx: params.ctx,
1219
+ channelId: params.parsed.channelId,
1220
+ messageTs: params.parsed.messageTs,
1221
+ text: params.parsed.typedBody.message?.text ?? "",
1222
+ blocks: buildSlackConfirmationBlocks({
1223
+ parsed: params.parsed,
1224
+ originalBlocks
1225
+ })
1226
+ });
1227
+ } catch {
1228
+ await respondEphemeral(params.respond, `Button "${params.parsed.actionId}" clicked!`);
1229
+ }
1230
+ }
1231
+ async function handleSlackBlockAction(params) {
1232
+ const { ack, body, action, respond } = params.args;
1233
+ await ack();
1234
+ if (params.ctx.shouldDropMismatchedSlackEvent?.(body)) {
1235
+ params.ctx.runtime.log?.("slack:interaction drop block action payload (mismatched app/team)");
1236
+ return;
1237
+ }
1238
+ const parsed = parseSlackBlockAction({
1239
+ body,
1240
+ action,
1241
+ log: params.ctx.runtime.log
1242
+ });
1243
+ if (!parsed) return;
1244
+ const auth = await authorizeSlackBlockAction({
1245
+ ctx: params.ctx,
1246
+ parsed,
1247
+ respond
1248
+ });
1249
+ if (!auth.allowed) return;
1250
+ const pluginInteractionData = buildSlackPluginInteractionData({
1251
+ actionId: parsed.actionId,
1252
+ summary: parsed.actionSummary
1253
+ });
1254
+ if (pluginInteractionData) {
1255
+ if (await dispatchSlackPluginInteraction({
1256
+ ctx: params.ctx,
1257
+ parsed,
1258
+ pluginInteractionData,
1259
+ auth: { isAuthorizedSender: true },
1260
+ respond
1261
+ })) return;
1262
+ }
1263
+ enqueueSlackBlockActionEvent({
1264
+ ctx: params.ctx,
1265
+ parsed,
1266
+ auth,
1267
+ formatSystemEvent: params.formatSystemEvent
1268
+ });
1269
+ await updateSlackLegacyBlockAction({
1270
+ ctx: params.ctx,
1271
+ parsed,
1272
+ respond
1273
+ });
1274
+ }
1275
+ function registerSlackBlockActionHandler(params) {
1276
+ if (typeof params.ctx.app.action !== "function") return;
1277
+ params.ctx.app.action(/.+/, async (args) => {
1278
+ await handleSlackBlockAction({
1279
+ ctx: params.ctx,
1280
+ args,
1281
+ formatSystemEvent: params.formatSystemEvent
1282
+ });
1283
+ });
1284
+ }
1285
+ //#endregion
1286
+ //#region extensions/slack/src/modal-metadata.ts
1287
+ function normalizeString(value) {
1288
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
1289
+ }
1290
+ function parseSlackModalPrivateMetadata(raw) {
1291
+ if (typeof raw !== "string" || raw.trim().length === 0) return {};
1292
+ try {
1293
+ const parsed = JSON.parse(raw);
1294
+ return {
1295
+ sessionKey: normalizeString(parsed.sessionKey),
1296
+ channelId: normalizeString(parsed.channelId),
1297
+ channelType: normalizeString(parsed.channelType),
1298
+ userId: normalizeString(parsed.userId)
1299
+ };
1300
+ } catch {
1301
+ return {};
1302
+ }
1303
+ }
1304
+ //#endregion
1305
+ //#region extensions/slack/src/monitor/events/interactions.modal.ts
1306
+ function resolveModalSessionRouting(params) {
1307
+ const metadata = params.metadata;
1308
+ if (metadata.sessionKey) return {
1309
+ sessionKey: metadata.sessionKey,
1310
+ channelId: metadata.channelId,
1311
+ channelType: metadata.channelType
1312
+ };
1313
+ if (metadata.channelId) return {
1314
+ sessionKey: params.ctx.resolveSlackSystemEventSessionKey({
1315
+ channelId: metadata.channelId,
1316
+ channelType: metadata.channelType,
1317
+ senderId: params.userId
1318
+ }),
1319
+ channelId: metadata.channelId,
1320
+ channelType: metadata.channelType
1321
+ };
1322
+ return { sessionKey: params.ctx.resolveSlackSystemEventSessionKey({}) };
1323
+ }
1324
+ function summarizeSlackViewLifecycleContext(view) {
1325
+ const rootViewId = view.root_view_id;
1326
+ const previousViewId = view.previous_view_id;
1327
+ return {
1328
+ rootViewId,
1329
+ previousViewId,
1330
+ externalId: view.external_id,
1331
+ viewHash: view.hash,
1332
+ isStackedView: Boolean(previousViewId)
1333
+ };
1334
+ }
1335
+ function resolveSlackModalEventBase(params) {
1336
+ const metadata = parseSlackModalPrivateMetadata(params.body.view?.private_metadata);
1337
+ const callbackId = params.body.view?.callback_id ?? "unknown";
1338
+ const userId = params.body.user?.id ?? "unknown";
1339
+ const viewId = params.body.view?.id;
1340
+ const inputs = params.summarizeViewState(params.body.view?.state?.values);
1341
+ const sessionRouting = resolveModalSessionRouting({
1342
+ ctx: params.ctx,
1343
+ metadata,
1344
+ userId
1345
+ });
1346
+ return {
1347
+ callbackId,
1348
+ userId,
1349
+ expectedUserId: metadata.userId,
1350
+ viewId,
1351
+ sessionRouting,
1352
+ payload: {
1353
+ actionId: `view:${callbackId}`,
1354
+ callbackId,
1355
+ viewId,
1356
+ userId,
1357
+ teamId: params.body.team?.id,
1358
+ ...summarizeSlackViewLifecycleContext({
1359
+ root_view_id: params.body.view?.root_view_id,
1360
+ previous_view_id: params.body.view?.previous_view_id,
1361
+ external_id: params.body.view?.external_id,
1362
+ hash: params.body.view?.hash
1363
+ }),
1364
+ privateMetadata: params.body.view?.private_metadata,
1365
+ routedChannelId: sessionRouting.channelId,
1366
+ routedChannelType: sessionRouting.channelType,
1367
+ inputs
1368
+ }
1369
+ };
1370
+ }
1371
+ async function emitSlackModalLifecycleEvent(params) {
1372
+ const { callbackId, userId, expectedUserId, viewId, sessionRouting, payload } = resolveSlackModalEventBase({
1373
+ ctx: params.ctx,
1374
+ body: params.body,
1375
+ summarizeViewState: params.summarizeViewState
1376
+ });
1377
+ const isViewClosed = params.interactionType === "view_closed";
1378
+ const isCleared = params.body.is_cleared === true;
1379
+ const eventPayload = isViewClosed ? {
1380
+ interactionType: params.interactionType,
1381
+ ...payload,
1382
+ isCleared
1383
+ } : {
1384
+ interactionType: params.interactionType,
1385
+ ...payload
1386
+ };
1387
+ if (isViewClosed) params.ctx.runtime.log?.(`slack:interaction view_closed callback=${callbackId} user=${userId} cleared=${isCleared}`);
1388
+ else params.ctx.runtime.log?.(`slack:interaction view_submission callback=${callbackId} user=${userId} inputs=${payload.inputs.length}`);
1389
+ if (!expectedUserId) {
1390
+ params.ctx.runtime.log?.(`slack:interaction drop modal callback=${callbackId} user=${userId} reason=missing-expected-user`);
1391
+ return;
1392
+ }
1393
+ const auth = await authorizeSlackSystemEventSender({
1394
+ ctx: params.ctx,
1395
+ senderId: userId,
1396
+ channelId: sessionRouting.channelId,
1397
+ channelType: sessionRouting.channelType,
1398
+ expectedSenderId: expectedUserId
1399
+ });
1400
+ if (!auth.allowed) {
1401
+ params.ctx.runtime.log?.(`slack:interaction drop modal callback=${callbackId} user=${userId} reason=${auth.reason ?? "unauthorized"}`);
1402
+ return;
1403
+ }
1404
+ enqueueSystemEvent(params.formatSystemEvent(eventPayload), {
1405
+ sessionKey: sessionRouting.sessionKey,
1406
+ contextKey: [
1407
+ params.contextPrefix,
1408
+ callbackId,
1409
+ viewId,
1410
+ userId
1411
+ ].filter(Boolean).join(":")
1412
+ });
1413
+ }
1414
+ function registerModalLifecycleHandler(params) {
1415
+ params.register(params.matcher, async ({ ack, body }) => {
1416
+ await ack();
1417
+ if (params.ctx.shouldDropMismatchedSlackEvent?.(body)) {
1418
+ params.ctx.runtime.log?.(`slack:interaction drop ${params.interactionType} payload (mismatched app/team)`);
1419
+ return;
1420
+ }
1421
+ await emitSlackModalLifecycleEvent({
1422
+ ctx: params.ctx,
1423
+ body,
1424
+ interactionType: params.interactionType,
1425
+ contextPrefix: params.contextPrefix,
1426
+ summarizeViewState: params.summarizeViewState,
1427
+ formatSystemEvent: params.formatSystemEvent
1428
+ });
1429
+ });
1430
+ }
1431
+ //#endregion
1432
+ //#region extensions/slack/src/monitor/events/interactions.ts
1433
+ const MOLDCLAW_ACTION_PREFIX = "moldclaw:";
1434
+ const SLACK_INTERACTION_EVENT_PREFIX = "Slack interaction: ";
1435
+ const REDACTED_INTERACTION_VALUE = "[redacted]";
1436
+ const SLACK_INTERACTION_EVENT_MAX_CHARS = 2400;
1437
+ const SLACK_INTERACTION_STRING_MAX_CHARS = 160;
1438
+ const SLACK_INTERACTION_ARRAY_MAX_ITEMS = 64;
1439
+ const SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS = 3;
1440
+ const SLACK_INTERACTION_REDACTED_KEYS = new Set([
1441
+ "triggerId",
1442
+ "responseUrl",
1443
+ "workflowTriggerUrl",
1444
+ "privateMetadata",
1445
+ "viewHash"
1446
+ ]);
1447
+ function sanitizeSlackInteractionPayloadValue(value, key) {
1448
+ if (value === void 0) return;
1449
+ if (key && SLACK_INTERACTION_REDACTED_KEYS.has(key)) {
1450
+ if (typeof value !== "string" || value.trim().length === 0) return;
1451
+ return REDACTED_INTERACTION_VALUE;
1452
+ }
1453
+ if (typeof value === "string") return truncateSlackText(value, SLACK_INTERACTION_STRING_MAX_CHARS);
1454
+ if (Array.isArray(value)) {
1455
+ const sanitized = value.slice(0, SLACK_INTERACTION_ARRAY_MAX_ITEMS).map((entry) => sanitizeSlackInteractionPayloadValue(entry)).filter((entry) => entry !== void 0);
1456
+ if (value.length > SLACK_INTERACTION_ARRAY_MAX_ITEMS) sanitized.push(`…+${value.length - SLACK_INTERACTION_ARRAY_MAX_ITEMS} more`);
1457
+ return sanitized;
1458
+ }
1459
+ if (!value || typeof value !== "object") return value;
1460
+ const output = {};
1461
+ for (const [entryKey, entryValue] of Object.entries(value)) {
1462
+ const sanitized = sanitizeSlackInteractionPayloadValue(entryValue, entryKey);
1463
+ if (sanitized === void 0) continue;
1464
+ if (typeof sanitized === "string" && sanitized.length === 0) continue;
1465
+ if (Array.isArray(sanitized) && sanitized.length === 0) continue;
1466
+ output[entryKey] = sanitized;
1467
+ }
1468
+ return output;
1469
+ }
1470
+ function buildCompactSlackInteractionPayload(payload) {
1471
+ const rawInputs = Array.isArray(payload.inputs) ? payload.inputs : [];
1472
+ const compactInputs = rawInputs.slice(0, SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS).flatMap((entry) => {
1473
+ if (!entry || typeof entry !== "object") return [];
1474
+ const typed = entry;
1475
+ return [{
1476
+ actionId: typed.actionId,
1477
+ blockId: typed.blockId,
1478
+ actionType: typed.actionType,
1479
+ inputKind: typed.inputKind,
1480
+ selectedValues: typed.selectedValues,
1481
+ selectedLabels: typed.selectedLabels,
1482
+ inputValue: typed.inputValue,
1483
+ inputNumber: typed.inputNumber,
1484
+ selectedDate: typed.selectedDate,
1485
+ selectedTime: typed.selectedTime,
1486
+ selectedDateTime: typed.selectedDateTime,
1487
+ richTextPreview: typed.richTextPreview
1488
+ }];
1489
+ });
1490
+ return {
1491
+ interactionType: payload.interactionType,
1492
+ actionId: payload.actionId,
1493
+ callbackId: payload.callbackId,
1494
+ actionType: payload.actionType,
1495
+ userId: payload.userId,
1496
+ teamId: payload.teamId,
1497
+ channelId: payload.channelId ?? payload.routedChannelId,
1498
+ messageTs: payload.messageTs,
1499
+ threadTs: payload.threadTs,
1500
+ viewId: payload.viewId,
1501
+ isCleared: payload.isCleared,
1502
+ selectedValues: payload.selectedValues,
1503
+ selectedLabels: payload.selectedLabels,
1504
+ selectedDate: payload.selectedDate,
1505
+ selectedTime: payload.selectedTime,
1506
+ selectedDateTime: payload.selectedDateTime,
1507
+ workflowId: payload.workflowId,
1508
+ routedChannelType: payload.routedChannelType,
1509
+ inputs: compactInputs.length > 0 ? compactInputs : void 0,
1510
+ inputsOmitted: rawInputs.length > SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS ? rawInputs.length - SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS : void 0,
1511
+ payloadTruncated: true
1512
+ };
1513
+ }
1514
+ function formatSlackInteractionSystemEvent(payload) {
1515
+ const toEventText = (value) => `${SLACK_INTERACTION_EVENT_PREFIX}${JSON.stringify(value)}`;
1516
+ const sanitizedPayload = sanitizeSlackInteractionPayloadValue(payload) ?? {};
1517
+ let eventText = toEventText(sanitizedPayload);
1518
+ if (eventText.length <= SLACK_INTERACTION_EVENT_MAX_CHARS) return eventText;
1519
+ eventText = toEventText(sanitizeSlackInteractionPayloadValue(buildCompactSlackInteractionPayload(sanitizedPayload)));
1520
+ if (eventText.length <= SLACK_INTERACTION_EVENT_MAX_CHARS) return eventText;
1521
+ return toEventText({
1522
+ interactionType: sanitizedPayload.interactionType,
1523
+ actionId: sanitizedPayload.actionId ?? "unknown",
1524
+ userId: sanitizedPayload.userId,
1525
+ channelId: sanitizedPayload.channelId ?? sanitizedPayload.routedChannelId,
1526
+ payloadTruncated: true
1527
+ });
1528
+ }
1529
+ function summarizeViewState(values) {
1530
+ if (!values || typeof values !== "object") return [];
1531
+ const entries = [];
1532
+ for (const [blockId, blockValue] of Object.entries(values)) {
1533
+ if (!blockValue || typeof blockValue !== "object") continue;
1534
+ for (const [actionId, rawAction] of Object.entries(blockValue)) {
1535
+ if (!rawAction || typeof rawAction !== "object") continue;
1536
+ const actionSummary = summarizeAction(rawAction);
1537
+ entries.push({
1538
+ blockId,
1539
+ actionId,
1540
+ ...actionSummary
1541
+ });
1542
+ }
1543
+ }
1544
+ return entries;
1545
+ }
1546
+ function registerSlackInteractionEvents(params) {
1547
+ const { ctx } = params;
1548
+ registerSlackBlockActionHandler({
1549
+ ctx,
1550
+ formatSystemEvent: formatSlackInteractionSystemEvent
1551
+ });
1552
+ if (typeof ctx.app.view !== "function") return;
1553
+ const modalMatcher = new RegExp(`^${MOLDCLAW_ACTION_PREFIX}`);
1554
+ registerModalLifecycleHandler({
1555
+ register: (matcher, handler) => ctx.app.view(matcher, handler),
1556
+ matcher: modalMatcher,
1557
+ ctx,
1558
+ interactionType: "view_submission",
1559
+ contextPrefix: "slack:interaction:view",
1560
+ summarizeViewState,
1561
+ formatSystemEvent: formatSlackInteractionSystemEvent
1562
+ });
1563
+ const viewClosed = ctx.app.viewClosed;
1564
+ if (typeof viewClosed !== "function") return;
1565
+ registerModalLifecycleHandler({
1566
+ register: viewClosed,
1567
+ matcher: modalMatcher,
1568
+ ctx,
1569
+ interactionType: "view_closed",
1570
+ contextPrefix: "slack:interaction:view-closed",
1571
+ summarizeViewState,
1572
+ formatSystemEvent: formatSlackInteractionSystemEvent
1573
+ });
1574
+ }
1575
+ //#endregion
1576
+ //#region extensions/slack/src/monitor/events/system-event-context.ts
1577
+ async function authorizeAndResolveSlackSystemEventContext(params) {
1578
+ const { ctx, senderId, channelId, channelType, eventKind } = params;
1579
+ const auth = await authorizeSlackSystemEventSender({
1580
+ ctx,
1581
+ senderId,
1582
+ channelId,
1583
+ channelType
1584
+ });
1585
+ if (!auth.allowed) {
1586
+ logVerbose(`slack: drop ${eventKind} sender ${senderId ?? "unknown"} channel=${channelId ?? "unknown"} reason=${auth.reason ?? "unauthorized"}`);
1587
+ return;
1588
+ }
1589
+ return {
1590
+ channelLabel: resolveSlackChannelLabel({
1591
+ channelId,
1592
+ channelName: auth.channelName
1593
+ }),
1594
+ sessionKey: ctx.resolveSlackSystemEventSessionKey({
1595
+ channelId,
1596
+ channelType: auth.channelType,
1597
+ senderId
1598
+ })
1599
+ };
1600
+ }
1601
+ //#endregion
1602
+ //#region extensions/slack/src/monitor/events/members.ts
1603
+ function registerSlackMemberEvents(params) {
1604
+ const { ctx, trackEvent } = params;
1605
+ const handleMemberChannelEvent = async (params) => {
1606
+ try {
1607
+ if (ctx.shouldDropMismatchedSlackEvent(params.body)) return;
1608
+ trackEvent?.();
1609
+ const payload = params.event;
1610
+ const channelId = payload.channel;
1611
+ const channelInfo = channelId ? await ctx.resolveChannelName(channelId) : {};
1612
+ const channelType = payload.channel_type ?? channelInfo?.type;
1613
+ const ingressContext = await authorizeAndResolveSlackSystemEventContext({
1614
+ ctx,
1615
+ senderId: payload.user,
1616
+ channelId,
1617
+ channelType,
1618
+ eventKind: `member-${params.verb}`
1619
+ });
1620
+ if (!ingressContext) return;
1621
+ enqueueSystemEvent(`Slack: ${(payload.user ? await ctx.resolveUserName(payload.user) : {})?.name ?? payload.user ?? "someone"} ${params.verb} ${ingressContext.channelLabel}.`, {
1622
+ sessionKey: ingressContext.sessionKey,
1623
+ contextKey: `slack:member:${params.verb}:${channelId ?? "unknown"}:${payload.user ?? "unknown"}`
1624
+ });
1625
+ } catch (err) {
1626
+ ctx.runtime.error?.(danger(`slack ${params.verb} handler failed: ${String(err)}`));
1627
+ }
1628
+ };
1629
+ ctx.app.event("member_joined_channel", async ({ event, body }) => {
1630
+ await handleMemberChannelEvent({
1631
+ verb: "joined",
1632
+ event,
1633
+ body
1634
+ });
1635
+ });
1636
+ ctx.app.event("member_left_channel", async ({ event, body }) => {
1637
+ await handleMemberChannelEvent({
1638
+ verb: "left",
1639
+ event,
1640
+ body
1641
+ });
1642
+ });
1643
+ }
1644
+ //#endregion
1645
+ //#region extensions/slack/src/monitor/events/message-subtype-handlers.ts
1646
+ const SUBTYPE_HANDLER_REGISTRY = {
1647
+ message_changed: {
1648
+ subtype: "message_changed",
1649
+ eventKind: "message_changed",
1650
+ describe: (channelLabel) => `Slack message edited in ${channelLabel}.`,
1651
+ contextKey: (event) => {
1652
+ const changed = event;
1653
+ return `slack:message:changed:${changed.channel ?? "unknown"}:${changed.message?.ts ?? changed.previous_message?.ts ?? changed.event_ts ?? "unknown"}`;
1654
+ },
1655
+ resolveSenderId: (event) => {
1656
+ const changed = event;
1657
+ return changed.message?.user ?? changed.previous_message?.user ?? changed.message?.bot_id ?? changed.previous_message?.bot_id;
1658
+ },
1659
+ resolveChannelId: (event) => event.channel,
1660
+ resolveChannelType: () => void 0
1661
+ },
1662
+ message_deleted: {
1663
+ subtype: "message_deleted",
1664
+ eventKind: "message_deleted",
1665
+ describe: (channelLabel) => `Slack message deleted in ${channelLabel}.`,
1666
+ contextKey: (event) => {
1667
+ const deleted = event;
1668
+ return `slack:message:deleted:${deleted.channel ?? "unknown"}:${deleted.deleted_ts ?? deleted.event_ts ?? "unknown"}`;
1669
+ },
1670
+ resolveSenderId: (event) => {
1671
+ const deleted = event;
1672
+ return deleted.previous_message?.user ?? deleted.previous_message?.bot_id;
1673
+ },
1674
+ resolveChannelId: (event) => event.channel,
1675
+ resolveChannelType: () => void 0
1676
+ },
1677
+ thread_broadcast: {
1678
+ subtype: "thread_broadcast",
1679
+ eventKind: "thread_broadcast",
1680
+ describe: (channelLabel) => `Slack thread reply broadcast in ${channelLabel}.`,
1681
+ contextKey: (event) => {
1682
+ const thread = event;
1683
+ return `slack:thread:broadcast:${thread.channel ?? "unknown"}:${thread.message?.ts ?? thread.event_ts ?? "unknown"}`;
1684
+ },
1685
+ resolveSenderId: (event) => {
1686
+ const thread = event;
1687
+ return thread.user ?? thread.message?.user ?? thread.message?.bot_id;
1688
+ },
1689
+ resolveChannelId: (event) => event.channel,
1690
+ resolveChannelType: () => void 0
1691
+ }
1692
+ };
1693
+ function resolveSlackMessageSubtypeHandler(event) {
1694
+ const subtype = event.subtype;
1695
+ if (subtype !== "message_changed" && subtype !== "message_deleted" && subtype !== "thread_broadcast") return;
1696
+ return SUBTYPE_HANDLER_REGISTRY[subtype];
1697
+ }
1698
+ //#endregion
1699
+ //#region extensions/slack/src/monitor/events/messages.ts
1700
+ function registerSlackMessageEvents(params) {
1701
+ const { ctx, handleSlackMessage } = params;
1702
+ const handleIncomingMessageEvent = async ({ event, body }) => {
1703
+ try {
1704
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
1705
+ const message = event;
1706
+ const subtypeHandler = resolveSlackMessageSubtypeHandler(message);
1707
+ if (subtypeHandler) {
1708
+ const channelId = subtypeHandler.resolveChannelId(message);
1709
+ const ingressContext = await authorizeAndResolveSlackSystemEventContext({
1710
+ ctx,
1711
+ senderId: subtypeHandler.resolveSenderId(message),
1712
+ channelId,
1713
+ channelType: subtypeHandler.resolveChannelType(message),
1714
+ eventKind: subtypeHandler.eventKind
1715
+ });
1716
+ if (!ingressContext) return;
1717
+ enqueueSystemEvent(subtypeHandler.describe(ingressContext.channelLabel), {
1718
+ sessionKey: ingressContext.sessionKey,
1719
+ contextKey: subtypeHandler.contextKey(message)
1720
+ });
1721
+ return;
1722
+ }
1723
+ await handleSlackMessage(message, { source: "message" });
1724
+ } catch (err) {
1725
+ ctx.runtime.error?.(danger(`slack handler failed: ${String(err)}`));
1726
+ }
1727
+ };
1728
+ ctx.app.event("message", async ({ event, body }) => {
1729
+ await handleIncomingMessageEvent({
1730
+ event,
1731
+ body
1732
+ });
1733
+ });
1734
+ ctx.app.event("app_mention", async ({ event, body }) => {
1735
+ try {
1736
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
1737
+ const mention = event;
1738
+ const channelType = normalizeSlackChannelType(mention.channel_type, mention.channel);
1739
+ if (channelType === "im" || channelType === "mpim") return;
1740
+ await handleSlackMessage(mention, {
1741
+ source: "app_mention",
1742
+ wasMentioned: true
1743
+ });
1744
+ } catch (err) {
1745
+ ctx.runtime.error?.(danger(`slack mention handler failed: ${String(err)}`));
1746
+ }
1747
+ });
1748
+ }
1749
+ //#endregion
1750
+ //#region extensions/slack/src/monitor/events/pins.ts
1751
+ async function handleSlackPinEvent(params) {
1752
+ const { ctx, trackEvent, body, event, action, contextKeySuffix, errorLabel } = params;
1753
+ try {
1754
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
1755
+ trackEvent?.();
1756
+ const payload = event;
1757
+ const channelId = payload.channel_id;
1758
+ const ingressContext = await authorizeAndResolveSlackSystemEventContext({
1759
+ ctx,
1760
+ senderId: payload.user,
1761
+ channelId,
1762
+ eventKind: "pin"
1763
+ });
1764
+ if (!ingressContext) return;
1765
+ const userLabel = (payload.user ? await ctx.resolveUserName(payload.user) : {})?.name ?? payload.user ?? "someone";
1766
+ const itemType = payload.item?.type ?? "item";
1767
+ const messageId = payload.item?.message?.ts ?? payload.event_ts;
1768
+ enqueueSystemEvent(`Slack: ${userLabel} ${action} a ${itemType} in ${ingressContext.channelLabel}.`, {
1769
+ sessionKey: ingressContext.sessionKey,
1770
+ contextKey: `slack:pin:${contextKeySuffix}:${channelId ?? "unknown"}:${messageId ?? "unknown"}`
1771
+ });
1772
+ } catch (err) {
1773
+ ctx.runtime.error?.(danger(`slack ${errorLabel} handler failed: ${String(err)}`));
1774
+ }
1775
+ }
1776
+ function registerSlackPinEvents(params) {
1777
+ const { ctx, trackEvent } = params;
1778
+ ctx.app.event("pin_added", async ({ event, body }) => {
1779
+ await handleSlackPinEvent({
1780
+ ctx,
1781
+ trackEvent,
1782
+ body,
1783
+ event,
1784
+ action: "pinned",
1785
+ contextKeySuffix: "added",
1786
+ errorLabel: "pin added"
1787
+ });
1788
+ });
1789
+ ctx.app.event("pin_removed", async ({ event, body }) => {
1790
+ await handleSlackPinEvent({
1791
+ ctx,
1792
+ trackEvent,
1793
+ body,
1794
+ event,
1795
+ action: "unpinned",
1796
+ contextKeySuffix: "removed",
1797
+ errorLabel: "pin removed"
1798
+ });
1799
+ });
1800
+ }
1801
+ //#endregion
1802
+ //#region extensions/slack/src/monitor/events/reactions.ts
1803
+ function registerSlackReactionEvents(params) {
1804
+ const { ctx, trackEvent } = params;
1805
+ const handleReactionEvent = async (event, action) => {
1806
+ try {
1807
+ const item = event.item;
1808
+ if (!item || item.type !== "message") return;
1809
+ trackEvent?.();
1810
+ const ingressContext = await authorizeAndResolveSlackSystemEventContext({
1811
+ ctx,
1812
+ senderId: event.user,
1813
+ channelId: item.channel,
1814
+ eventKind: "reaction"
1815
+ });
1816
+ if (!ingressContext) return;
1817
+ const actorInfoPromise = event.user ? ctx.resolveUserName(event.user) : Promise.resolve(void 0);
1818
+ const authorInfoPromise = event.item_user ? ctx.resolveUserName(event.item_user) : Promise.resolve(void 0);
1819
+ const [actorInfo, authorInfo] = await Promise.all([actorInfoPromise, authorInfoPromise]);
1820
+ const actorLabel = actorInfo?.name ?? event.user;
1821
+ const emojiLabel = event.reaction ?? "emoji";
1822
+ const authorLabel = authorInfo?.name ?? event.item_user;
1823
+ const baseText = `Slack reaction ${action}: :${emojiLabel}: by ${actorLabel} in ${ingressContext.channelLabel} msg ${item.ts}`;
1824
+ enqueueSystemEvent(authorLabel ? `${baseText} from ${authorLabel}` : baseText, {
1825
+ sessionKey: ingressContext.sessionKey,
1826
+ contextKey: `slack:reaction:${action}:${item.channel}:${item.ts}:${event.user}:${emojiLabel}`
1827
+ });
1828
+ } catch (err) {
1829
+ ctx.runtime.error?.(danger(`slack reaction handler failed: ${String(err)}`));
1830
+ }
1831
+ };
1832
+ ctx.app.event("reaction_added", async ({ event, body }) => {
1833
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
1834
+ await handleReactionEvent(event, "added");
1835
+ });
1836
+ ctx.app.event("reaction_removed", async ({ event, body }) => {
1837
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
1838
+ await handleReactionEvent(event, "removed");
1839
+ });
1840
+ }
1841
+ //#endregion
1842
+ //#region extensions/slack/src/monitor/events.ts
1843
+ function registerSlackMonitorEvents(params) {
1844
+ registerSlackMessageEvents({
1845
+ ctx: params.ctx,
1846
+ handleSlackMessage: params.handleSlackMessage
1847
+ });
1848
+ registerSlackReactionEvents({
1849
+ ctx: params.ctx,
1850
+ trackEvent: params.trackEvent
1851
+ });
1852
+ registerSlackMemberEvents({
1853
+ ctx: params.ctx,
1854
+ trackEvent: params.trackEvent
1855
+ });
1856
+ registerSlackChannelEvents({
1857
+ ctx: params.ctx,
1858
+ trackEvent: params.trackEvent
1859
+ });
1860
+ registerSlackPinEvents({
1861
+ ctx: params.ctx,
1862
+ trackEvent: params.trackEvent
1863
+ });
1864
+ registerSlackInteractionEvents({ ctx: params.ctx });
1865
+ }
1866
+ //#endregion
1867
+ //#region extensions/slack/src/draft-stream.ts
1868
+ const SLACK_STREAM_MAX_CHARS = 4e3;
1869
+ const DEFAULT_THROTTLE_MS = 1e3;
1870
+ function createSlackDraftStream(params) {
1871
+ const maxChars = Math.min(params.maxChars ?? SLACK_STREAM_MAX_CHARS, SLACK_STREAM_MAX_CHARS);
1872
+ const throttleMs = Math.max(250, params.throttleMs ?? DEFAULT_THROTTLE_MS);
1873
+ const send = params.send ?? sendMessageSlack;
1874
+ const edit = params.edit ?? editSlackMessage;
1875
+ const remove = params.remove ?? deleteSlackMessage;
1876
+ let streamMessageId;
1877
+ let streamChannelId;
1878
+ let lastSentText = "";
1879
+ let stopped = false;
1880
+ const sendOrEditStreamMessage = async (text) => {
1881
+ if (stopped) return;
1882
+ const trimmed = text.trimEnd();
1883
+ if (!trimmed) return;
1884
+ if (trimmed.length > maxChars) {
1885
+ stopped = true;
1886
+ params.warn?.(`slack stream preview stopped (text length ${trimmed.length} > ${maxChars})`);
1887
+ return;
1888
+ }
1889
+ if (trimmed === lastSentText) return;
1890
+ lastSentText = trimmed;
1891
+ try {
1892
+ if (streamChannelId && streamMessageId) {
1893
+ await edit(streamChannelId, streamMessageId, trimmed, {
1894
+ token: params.token,
1895
+ accountId: params.accountId
1896
+ });
1897
+ return;
1898
+ }
1899
+ const sent = await send(params.target, trimmed, {
1900
+ token: params.token,
1901
+ accountId: params.accountId,
1902
+ threadTs: params.resolveThreadTs?.()
1903
+ });
1904
+ streamChannelId = sent.channelId || streamChannelId;
1905
+ streamMessageId = sent.messageId || streamMessageId;
1906
+ if (!streamChannelId || !streamMessageId) {
1907
+ stopped = true;
1908
+ params.warn?.("slack stream preview stopped (missing identifiers from sendMessage)");
1909
+ return;
1910
+ }
1911
+ params.onMessageSent?.();
1912
+ } catch (err) {
1913
+ stopped = true;
1914
+ params.warn?.(`slack stream preview failed: ${err instanceof Error ? err.message : String(err)}`);
1915
+ }
1916
+ };
1917
+ const loop = createDraftStreamLoop({
1918
+ throttleMs,
1919
+ isStopped: () => stopped,
1920
+ sendOrEditStreamMessage
1921
+ });
1922
+ const stop = () => {
1923
+ stopped = true;
1924
+ loop.stop();
1925
+ };
1926
+ const clear = async () => {
1927
+ stop();
1928
+ await loop.waitForInFlight();
1929
+ const channelId = streamChannelId;
1930
+ const messageId = streamMessageId;
1931
+ streamChannelId = void 0;
1932
+ streamMessageId = void 0;
1933
+ lastSentText = "";
1934
+ if (!channelId || !messageId) return;
1935
+ try {
1936
+ await remove(channelId, messageId, {
1937
+ token: params.token,
1938
+ accountId: params.accountId
1939
+ });
1940
+ } catch (err) {
1941
+ params.warn?.(`slack stream preview cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
1942
+ }
1943
+ };
1944
+ const forceNewMessage = () => {
1945
+ streamMessageId = void 0;
1946
+ streamChannelId = void 0;
1947
+ lastSentText = "";
1948
+ loop.resetPending();
1949
+ };
1950
+ params.log?.(`slack stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
1951
+ return {
1952
+ update: loop.update,
1953
+ flush: loop.flush,
1954
+ clear,
1955
+ stop,
1956
+ forceNewMessage,
1957
+ messageId: () => streamMessageId,
1958
+ channelId: () => streamChannelId
1959
+ };
1960
+ }
1961
+ //#endregion
1962
+ //#region extensions/slack/src/stream-mode.ts
1963
+ function resolveSlackStreamingConfig(params) {
1964
+ const mode = resolveSlackStreamingMode(params);
1965
+ return {
1966
+ mode,
1967
+ nativeStreaming: resolveSlackNativeStreaming(params),
1968
+ draftMode: mapStreamingModeToSlackLegacyDraftStreamMode(mode)
1969
+ };
1970
+ }
1971
+ function applyAppendOnlyStreamUpdate(params) {
1972
+ const incoming = params.incoming.trimEnd();
1973
+ if (!incoming) return {
1974
+ rendered: params.rendered,
1975
+ source: params.source,
1976
+ changed: false
1977
+ };
1978
+ if (!params.rendered) return {
1979
+ rendered: incoming,
1980
+ source: incoming,
1981
+ changed: true
1982
+ };
1983
+ if (incoming === params.source) return {
1984
+ rendered: params.rendered,
1985
+ source: params.source,
1986
+ changed: false
1987
+ };
1988
+ if (incoming.startsWith(params.source) || incoming.startsWith(params.rendered)) return {
1989
+ rendered: incoming,
1990
+ source: incoming,
1991
+ changed: incoming !== params.rendered
1992
+ };
1993
+ if (params.source.startsWith(incoming)) return {
1994
+ rendered: params.rendered,
1995
+ source: params.source,
1996
+ changed: false
1997
+ };
1998
+ const separator = params.rendered.endsWith("\n") ? "" : "\n";
1999
+ return {
2000
+ rendered: `${params.rendered}${separator}${incoming}`,
2001
+ source: incoming,
2002
+ changed: true
2003
+ };
2004
+ }
2005
+ function buildStatusFinalPreviewText(updateCount) {
2006
+ return `Status: thinking${".".repeat(Math.max(1, updateCount) % 3 + 1)}`;
2007
+ }
2008
+ //#endregion
2009
+ //#region extensions/slack/src/streaming.ts
2010
+ /**
2011
+ * Start a new Slack text stream.
2012
+ *
2013
+ * Returns a {@link SlackStreamSession} that should be passed to
2014
+ * {@link appendSlackStream} and {@link stopSlackStream}.
2015
+ *
2016
+ * The first chunk of text can optionally be included via `text`.
2017
+ */
2018
+ async function startSlackStream(params) {
2019
+ const { client, channel, threadTs, text, teamId, userId } = params;
2020
+ logVerbose(`slack-stream: starting stream in ${channel} thread=${threadTs}${teamId ? ` team=${teamId}` : ""}${userId ? ` user=${userId}` : ""}`);
2021
+ const streamer = client.chatStream({
2022
+ channel,
2023
+ thread_ts: threadTs,
2024
+ ...teamId ? { recipient_team_id: teamId } : {},
2025
+ ...userId ? { recipient_user_id: userId } : {}
2026
+ });
2027
+ const session = {
2028
+ streamer,
2029
+ channel,
2030
+ threadTs,
2031
+ stopped: false
2032
+ };
2033
+ if (text) {
2034
+ await streamer.append({ markdown_text: text });
2035
+ logVerbose(`slack-stream: appended initial text (${text.length} chars)`);
2036
+ }
2037
+ return session;
2038
+ }
2039
+ /**
2040
+ * Append markdown text to an active Slack stream.
2041
+ */
2042
+ async function appendSlackStream(params) {
2043
+ const { session, text } = params;
2044
+ if (session.stopped) {
2045
+ logVerbose("slack-stream: attempted to append to a stopped stream, ignoring");
2046
+ return;
2047
+ }
2048
+ if (!text) return;
2049
+ await session.streamer.append({ markdown_text: text });
2050
+ logVerbose(`slack-stream: appended ${text.length} chars`);
2051
+ }
2052
+ /**
2053
+ * Stop (finalize) a Slack stream.
2054
+ *
2055
+ * After calling this the stream message becomes a normal Slack message.
2056
+ * Optionally include final text to append before stopping.
2057
+ */
2058
+ async function stopSlackStream(params) {
2059
+ const { session, text } = params;
2060
+ if (session.stopped) {
2061
+ logVerbose("slack-stream: stream already stopped, ignoring duplicate stop");
2062
+ return;
2063
+ }
2064
+ session.stopped = true;
2065
+ logVerbose(`slack-stream: stopping stream in ${session.channel} thread=${session.threadTs}${text ? ` (final text: ${text.length} chars)` : ""}`);
2066
+ await session.streamer.stop(text ? { markdown_text: text } : void 0);
2067
+ logVerbose("slack-stream: stream stopped");
2068
+ }
2069
+ //#endregion
2070
+ //#region extensions/slack/src/threading.ts
2071
+ function resolveSlackThreadContext(params) {
2072
+ const incomingThreadTs = params.message.thread_ts;
2073
+ const eventTs = params.message.event_ts;
2074
+ const messageTs = params.message.ts ?? eventTs;
2075
+ const isThreadReply = typeof incomingThreadTs === "string" && incomingThreadTs.length > 0 && (incomingThreadTs !== messageTs || Boolean(params.message.parent_user_id));
2076
+ return {
2077
+ incomingThreadTs,
2078
+ messageTs,
2079
+ isThreadReply,
2080
+ replyToId: incomingThreadTs ?? messageTs,
2081
+ messageThreadId: isThreadReply ? incomingThreadTs : params.replyToMode === "all" ? messageTs : void 0
2082
+ };
2083
+ }
2084
+ /**
2085
+ * Resolves Slack thread targeting for replies and status indicators.
2086
+ *
2087
+ * @returns replyThreadTs - Thread timestamp for reply messages
2088
+ * @returns statusThreadTs - Thread timestamp for status indicators (typing, etc.)
2089
+ * @returns isThreadReply - true if this is a genuine user reply in a thread,
2090
+ * false if thread_ts comes from a bot status message (e.g. typing indicator)
2091
+ */
2092
+ function resolveSlackThreadTargets(params) {
2093
+ const { incomingThreadTs, messageTs, isThreadReply } = resolveSlackThreadContext(params);
2094
+ const replyThreadTs = isThreadReply ? incomingThreadTs : params.replyToMode === "all" ? messageTs : void 0;
2095
+ return {
2096
+ replyThreadTs,
2097
+ statusThreadTs: replyThreadTs,
2098
+ isThreadReply
2099
+ };
2100
+ }
2101
+ //#endregion
2102
+ //#region extensions/slack/src/monitor/message-handler/dispatch.ts
2103
+ function hasMedia(payload) {
2104
+ return Boolean(payload.mediaUrl) || (payload.mediaUrls?.length ?? 0) > 0;
2105
+ }
2106
+ function isSlackStreamingEnabled(params) {
2107
+ if (params.mode !== "partial") return false;
2108
+ return params.nativeStreaming;
2109
+ }
2110
+ function resolveSlackStreamingThreadHint(params) {
2111
+ return resolveSlackThreadTs({
2112
+ replyToMode: params.replyToMode,
2113
+ incomingThreadTs: params.incomingThreadTs,
2114
+ messageTs: params.messageTs,
2115
+ hasReplied: false,
2116
+ isThreadReply: params.isThreadReply
2117
+ });
2118
+ }
2119
+ function shouldUseStreaming(params) {
2120
+ if (!params.streamingEnabled) return false;
2121
+ if (!params.threadTs) {
2122
+ logVerbose("slack-stream: streaming disabled — no reply thread target available");
2123
+ return false;
2124
+ }
2125
+ return true;
2126
+ }
2127
+ async function dispatchPreparedSlackMessage(prepared) {
2128
+ const { ctx, account, message, route } = prepared;
2129
+ const cfg = ctx.cfg;
2130
+ const runtime = ctx.runtime;
2131
+ const outboundIdentity = resolveAgentOutboundIdentity(cfg, route.agentId);
2132
+ const slackIdentity = outboundIdentity ? {
2133
+ username: outboundIdentity.name,
2134
+ iconUrl: outboundIdentity.avatarUrl,
2135
+ iconEmoji: outboundIdentity.emoji
2136
+ } : void 0;
2137
+ if (prepared.isDirectMessage) {
2138
+ const sessionCfg = cfg.session;
2139
+ const storePath = resolveStorePath(sessionCfg?.store, { agentId: route.agentId });
2140
+ const pinnedMainDmOwner = resolvePinnedMainDmOwnerFromAllowlist({
2141
+ dmScope: cfg.session?.dmScope,
2142
+ allowFrom: ctx.allowFrom,
2143
+ normalizeEntry: normalizeSlackAllowOwnerEntry
2144
+ });
2145
+ const senderRecipient = message.user?.trim().toLowerCase();
2146
+ if (pinnedMainDmOwner && senderRecipient && pinnedMainDmOwner.trim().toLowerCase() !== senderRecipient) logVerbose(`slack: skip main-session last route for ${senderRecipient} (pinned owner ${pinnedMainDmOwner})`);
2147
+ else await updateLastRoute({
2148
+ storePath,
2149
+ sessionKey: route.mainSessionKey,
2150
+ deliveryContext: {
2151
+ channel: "slack",
2152
+ to: `user:${message.user}`,
2153
+ accountId: route.accountId,
2154
+ threadId: prepared.ctxPayload.MessageThreadId
2155
+ },
2156
+ ctx: prepared.ctxPayload
2157
+ });
2158
+ }
2159
+ const { statusThreadTs, isThreadReply } = resolveSlackThreadTargets({
2160
+ message,
2161
+ replyToMode: prepared.replyToMode
2162
+ });
2163
+ const messageTs = message.ts ?? message.event_ts;
2164
+ const incomingThreadTs = message.thread_ts;
2165
+ let didSetStatus = false;
2166
+ const hasRepliedRef = { value: false };
2167
+ const replyPlan = createSlackReplyDeliveryPlan({
2168
+ replyToMode: prepared.replyToMode,
2169
+ incomingThreadTs,
2170
+ messageTs,
2171
+ hasRepliedRef,
2172
+ isThreadReply
2173
+ });
2174
+ const typingTarget = statusThreadTs ? `${message.channel}/${statusThreadTs}` : message.channel;
2175
+ const typingReaction = ctx.typingReaction;
2176
+ const typingCallbacks = createTypingCallbacks({
2177
+ start: async () => {
2178
+ didSetStatus = true;
2179
+ await ctx.setSlackThreadStatus({
2180
+ channelId: message.channel,
2181
+ threadTs: statusThreadTs,
2182
+ status: "is typing..."
2183
+ });
2184
+ if (typingReaction && message.ts) await reactSlackMessage(message.channel, message.ts, typingReaction, {
2185
+ token: ctx.botToken,
2186
+ client: ctx.app.client
2187
+ }).catch(() => {});
2188
+ },
2189
+ stop: async () => {
2190
+ if (!didSetStatus) return;
2191
+ didSetStatus = false;
2192
+ await ctx.setSlackThreadStatus({
2193
+ channelId: message.channel,
2194
+ threadTs: statusThreadTs,
2195
+ status: ""
2196
+ });
2197
+ if (typingReaction && message.ts) await removeSlackReaction(message.channel, message.ts, typingReaction, {
2198
+ token: ctx.botToken,
2199
+ client: ctx.app.client
2200
+ }).catch(() => {});
2201
+ },
2202
+ onStartError: (err) => {
2203
+ logTypingFailure({
2204
+ log: (message) => runtime.error?.(danger(message)),
2205
+ channel: "slack",
2206
+ action: "start",
2207
+ target: typingTarget,
2208
+ error: err
2209
+ });
2210
+ },
2211
+ onStopError: (err) => {
2212
+ logTypingFailure({
2213
+ log: (message) => runtime.error?.(danger(message)),
2214
+ channel: "slack",
2215
+ action: "stop",
2216
+ target: typingTarget,
2217
+ error: err
2218
+ });
2219
+ }
2220
+ });
2221
+ const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
2222
+ cfg,
2223
+ agentId: route.agentId,
2224
+ channel: "slack",
2225
+ accountId: route.accountId
2226
+ });
2227
+ const slackStreaming = resolveSlackStreamingConfig({
2228
+ streaming: account.config.streaming,
2229
+ streamMode: account.config.streamMode,
2230
+ nativeStreaming: account.config.nativeStreaming
2231
+ });
2232
+ const previewStreamingEnabled = slackStreaming.mode !== "off";
2233
+ const useStreaming = shouldUseStreaming({
2234
+ streamingEnabled: isSlackStreamingEnabled({
2235
+ mode: slackStreaming.mode,
2236
+ nativeStreaming: slackStreaming.nativeStreaming
2237
+ }),
2238
+ threadTs: resolveSlackStreamingThreadHint({
2239
+ replyToMode: prepared.replyToMode,
2240
+ incomingThreadTs,
2241
+ messageTs,
2242
+ isThreadReply
2243
+ })
2244
+ });
2245
+ let streamSession = null;
2246
+ let streamFailed = false;
2247
+ let usedReplyThreadTs;
2248
+ const deliverNormally = async (payload, forcedThreadTs) => {
2249
+ const replyThreadTs = forcedThreadTs ?? replyPlan.nextThreadTs();
2250
+ await deliverReplies({
2251
+ replies: [payload],
2252
+ target: prepared.replyTarget,
2253
+ token: ctx.botToken,
2254
+ accountId: account.accountId,
2255
+ runtime,
2256
+ textLimit: ctx.textLimit,
2257
+ replyThreadTs,
2258
+ replyToMode: prepared.replyToMode,
2259
+ ...slackIdentity ? { identity: slackIdentity } : {}
2260
+ });
2261
+ if (replyThreadTs) usedReplyThreadTs ??= replyThreadTs;
2262
+ replyPlan.markSent();
2263
+ };
2264
+ const deliverWithStreaming = async (payload) => {
2265
+ if (streamFailed || hasMedia(payload) || readSlackReplyBlocks(payload)?.length || !payload.text?.trim()) {
2266
+ await deliverNormally(payload, streamSession?.threadTs);
2267
+ return;
2268
+ }
2269
+ const text = payload.text.trim();
2270
+ let plannedThreadTs;
2271
+ try {
2272
+ if (!streamSession) {
2273
+ const streamThreadTs = replyPlan.nextThreadTs();
2274
+ plannedThreadTs = streamThreadTs;
2275
+ if (!streamThreadTs) {
2276
+ logVerbose("slack-stream: no reply thread target for stream start, falling back to normal delivery");
2277
+ streamFailed = true;
2278
+ await deliverNormally(payload);
2279
+ return;
2280
+ }
2281
+ streamSession = await startSlackStream({
2282
+ client: ctx.app.client,
2283
+ channel: message.channel,
2284
+ threadTs: streamThreadTs,
2285
+ text,
2286
+ teamId: ctx.teamId,
2287
+ userId: message.user
2288
+ });
2289
+ usedReplyThreadTs ??= streamThreadTs;
2290
+ replyPlan.markSent();
2291
+ return;
2292
+ }
2293
+ await appendSlackStream({
2294
+ session: streamSession,
2295
+ text: "\n" + text
2296
+ });
2297
+ } catch (err) {
2298
+ runtime.error?.(danger(`slack-stream: streaming API call failed: ${String(err)}, falling back`));
2299
+ streamFailed = true;
2300
+ await deliverNormally(payload, streamSession?.threadTs ?? plannedThreadTs);
2301
+ }
2302
+ };
2303
+ const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
2304
+ ...prefixOptions,
2305
+ humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
2306
+ typingCallbacks,
2307
+ deliver: async (payload) => {
2308
+ if (useStreaming) {
2309
+ await deliverWithStreaming(payload);
2310
+ return;
2311
+ }
2312
+ const mediaCount = payload.mediaUrls?.length ?? (payload.mediaUrl ? 1 : 0);
2313
+ const slackBlocks = readSlackReplyBlocks(payload);
2314
+ const draftMessageId = draftStream?.messageId();
2315
+ const draftChannelId = draftStream?.channelId();
2316
+ const trimmedFinalText = (payload.text ?? "").trim();
2317
+ if (previewStreamingEnabled && streamMode !== "status_final" && mediaCount === 0 && !payload.isError && (trimmedFinalText.length > 0 || Boolean(slackBlocks?.length)) && typeof draftMessageId === "string" && typeof draftChannelId === "string") {
2318
+ draftStream?.stop();
2319
+ try {
2320
+ await editSlackMessage(draftChannelId, draftMessageId, normalizeSlackOutboundText(trimmedFinalText), {
2321
+ token: ctx.botToken,
2322
+ accountId: account.accountId,
2323
+ client: ctx.app.client,
2324
+ ...slackBlocks?.length ? { blocks: slackBlocks } : {}
2325
+ });
2326
+ return;
2327
+ } catch (err) {
2328
+ logVerbose(`slack: preview final edit failed; falling back to standard send (${String(err)})`);
2329
+ }
2330
+ } else if (previewStreamingEnabled && streamMode === "status_final" && hasStreamedMessage) try {
2331
+ const statusChannelId = draftStream?.channelId();
2332
+ const statusMessageId = draftStream?.messageId();
2333
+ if (statusChannelId && statusMessageId) await ctx.app.client.chat.update({
2334
+ token: ctx.botToken,
2335
+ channel: statusChannelId,
2336
+ ts: statusMessageId,
2337
+ text: "Status: complete. Final answer posted below."
2338
+ });
2339
+ } catch (err) {
2340
+ logVerbose(`slack: status_final completion update failed (${String(err)})`);
2341
+ }
2342
+ else if (mediaCount > 0) {
2343
+ await draftStream?.clear();
2344
+ hasStreamedMessage = false;
2345
+ }
2346
+ await deliverNormally(payload);
2347
+ },
2348
+ onError: (err, info) => {
2349
+ runtime.error?.(danger(`slack ${info.kind} reply failed: ${String(err)}`));
2350
+ typingCallbacks.onIdle?.();
2351
+ }
2352
+ });
2353
+ const draftStream = createSlackDraftStream({
2354
+ target: prepared.replyTarget,
2355
+ token: ctx.botToken,
2356
+ accountId: account.accountId,
2357
+ maxChars: Math.min(ctx.textLimit, 4e3),
2358
+ resolveThreadTs: () => {
2359
+ const ts = replyPlan.nextThreadTs();
2360
+ if (ts) usedReplyThreadTs ??= ts;
2361
+ return ts;
2362
+ },
2363
+ onMessageSent: () => replyPlan.markSent(),
2364
+ log: logVerbose,
2365
+ warn: logVerbose
2366
+ });
2367
+ let hasStreamedMessage = false;
2368
+ const streamMode = slackStreaming.draftMode;
2369
+ let appendRenderedText = "";
2370
+ let appendSourceText = "";
2371
+ let statusUpdateCount = 0;
2372
+ const updateDraftFromPartial = (text) => {
2373
+ const trimmed = text?.trimEnd();
2374
+ if (!trimmed) return;
2375
+ if (streamMode === "append") {
2376
+ const next = applyAppendOnlyStreamUpdate({
2377
+ incoming: trimmed,
2378
+ rendered: appendRenderedText,
2379
+ source: appendSourceText
2380
+ });
2381
+ appendRenderedText = next.rendered;
2382
+ appendSourceText = next.source;
2383
+ if (!next.changed) return;
2384
+ draftStream.update(next.rendered);
2385
+ hasStreamedMessage = true;
2386
+ return;
2387
+ }
2388
+ if (streamMode === "status_final") {
2389
+ statusUpdateCount += 1;
2390
+ if (statusUpdateCount > 1 && statusUpdateCount % 4 !== 0) return;
2391
+ draftStream.update(buildStatusFinalPreviewText(statusUpdateCount));
2392
+ hasStreamedMessage = true;
2393
+ return;
2394
+ }
2395
+ draftStream.update(trimmed);
2396
+ hasStreamedMessage = true;
2397
+ };
2398
+ const onDraftBoundary = useStreaming || !previewStreamingEnabled ? void 0 : async () => {
2399
+ if (hasStreamedMessage) {
2400
+ draftStream.forceNewMessage();
2401
+ hasStreamedMessage = false;
2402
+ appendRenderedText = "";
2403
+ appendSourceText = "";
2404
+ statusUpdateCount = 0;
2405
+ }
2406
+ };
2407
+ const { queuedFinal, counts } = await dispatchInboundMessage({
2408
+ ctx: prepared.ctxPayload,
2409
+ cfg,
2410
+ dispatcher,
2411
+ replyOptions: {
2412
+ ...replyOptions,
2413
+ skillFilter: prepared.channelConfig?.skills,
2414
+ hasRepliedRef,
2415
+ disableBlockStreaming: useStreaming ? true : typeof account.config.blockStreaming === "boolean" ? !account.config.blockStreaming : void 0,
2416
+ onModelSelected,
2417
+ onPartialReply: useStreaming ? void 0 : !previewStreamingEnabled ? void 0 : async (payload) => {
2418
+ updateDraftFromPartial(payload.text);
2419
+ },
2420
+ onAssistantMessageStart: onDraftBoundary,
2421
+ onReasoningEnd: onDraftBoundary
2422
+ }
2423
+ });
2424
+ await draftStream.flush();
2425
+ draftStream.stop();
2426
+ markDispatchIdle();
2427
+ const finalStream = streamSession;
2428
+ if (finalStream && !finalStream.stopped) try {
2429
+ await stopSlackStream({ session: finalStream });
2430
+ } catch (err) {
2431
+ runtime.error?.(danger(`slack-stream: failed to stop stream: ${String(err)}`));
2432
+ }
2433
+ const anyReplyDelivered = queuedFinal || (counts.block ?? 0) > 0 || (counts.final ?? 0) > 0;
2434
+ const participationThreadTs = usedReplyThreadTs ?? statusThreadTs;
2435
+ if (anyReplyDelivered && participationThreadTs) recordSlackThreadParticipation(account.accountId, message.channel, participationThreadTs);
2436
+ if (!anyReplyDelivered) {
2437
+ await draftStream.clear();
2438
+ if (prepared.isRoomish) clearHistoryEntriesIfEnabled({
2439
+ historyMap: ctx.channelHistories,
2440
+ historyKey: prepared.historyKey,
2441
+ limit: ctx.historyLimit
2442
+ });
2443
+ return;
2444
+ }
2445
+ if (shouldLogVerbose()) {
2446
+ const finalCount = counts.final;
2447
+ logVerbose(`slack: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${prepared.replyTarget}`);
2448
+ }
2449
+ removeAckReactionAfterReply({
2450
+ removeAfterReply: ctx.removeAckAfterReply,
2451
+ ackReactionPromise: prepared.ackReactionPromise,
2452
+ ackReactionValue: prepared.ackReactionValue,
2453
+ remove: () => removeSlackReaction(message.channel, prepared.ackReactionMessageTs ?? "", prepared.ackReactionValue, {
2454
+ token: ctx.botToken,
2455
+ client: ctx.app.client
2456
+ }),
2457
+ onError: (err) => {
2458
+ logAckFailure({
2459
+ log: logVerbose,
2460
+ channel: "slack",
2461
+ target: `${message.channel}/${message.ts}`,
2462
+ error: err
2463
+ });
2464
+ }
2465
+ });
2466
+ if (prepared.isRoomish) clearHistoryEntriesIfEnabled({
2467
+ historyMap: ctx.channelHistories,
2468
+ historyKey: prepared.historyKey,
2469
+ limit: ctx.historyLimit
2470
+ });
2471
+ }
2472
+ //#endregion
2473
+ //#region extensions/slack/src/monitor/dm-auth.ts
2474
+ async function authorizeSlackDirectMessage(params) {
2475
+ if (!params.ctx.dmEnabled || params.ctx.dmPolicy === "disabled") {
2476
+ await params.onDisabled();
2477
+ return false;
2478
+ }
2479
+ if (params.ctx.dmPolicy === "open") return true;
2480
+ const senderName = (await params.resolveSenderName(params.senderId))?.name ?? void 0;
2481
+ const allowMatch = resolveSlackAllowListMatch({
2482
+ allowList: params.allowFromLower,
2483
+ id: params.senderId,
2484
+ name: senderName,
2485
+ allowNameMatching: params.ctx.allowNameMatching
2486
+ });
2487
+ const allowMatchMeta = formatAllowlistMatchMeta(allowMatch);
2488
+ if (allowMatch.allowed) return true;
2489
+ if (params.ctx.dmPolicy === "pairing") {
2490
+ await issuePairingChallenge({
2491
+ channel: "slack",
2492
+ senderId: params.senderId,
2493
+ senderIdLine: `Your Slack user id: ${params.senderId}`,
2494
+ meta: { name: senderName },
2495
+ upsertPairingRequest: async ({ id, meta }) => await upsertChannelPairingRequest({
2496
+ channel: "slack",
2497
+ id,
2498
+ accountId: params.accountId,
2499
+ meta
2500
+ }),
2501
+ sendPairingReply: params.sendPairingReply,
2502
+ onCreated: () => {
2503
+ params.log(`slack pairing request sender=${params.senderId} name=${senderName ?? "unknown"} (${allowMatchMeta})`);
2504
+ },
2505
+ onReplyError: (err) => {
2506
+ params.log(`slack pairing reply failed for ${params.senderId}: ${String(err)}`);
2507
+ }
2508
+ });
2509
+ return false;
2510
+ }
2511
+ await params.onUnauthorized({
2512
+ allowMatchMeta,
2513
+ senderName
2514
+ });
2515
+ return false;
2516
+ }
2517
+ //#endregion
2518
+ //#region extensions/slack/src/monitor/room-context.ts
2519
+ function resolveSlackRoomContextHints(params) {
2520
+ if (!params.isRoomish) return {};
2521
+ const untrustedChannelMetadata = buildUntrustedChannelMetadata({
2522
+ source: "slack",
2523
+ label: "Slack channel description",
2524
+ entries: [params.channelInfo?.topic, params.channelInfo?.purpose]
2525
+ });
2526
+ const systemPromptParts = [params.channelConfig?.systemPrompt?.trim() || null].filter((entry) => Boolean(entry));
2527
+ return {
2528
+ untrustedChannelMetadata,
2529
+ groupSystemPrompt: systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : void 0
2530
+ };
2531
+ }
2532
+ //#endregion
2533
+ //#region extensions/slack/src/monitor/message-handler/prepare-content.ts
2534
+ function filterInheritedParentFiles(params) {
2535
+ const { files, isThreadReply, threadStarter } = params;
2536
+ if (!isThreadReply || !files?.length) return files;
2537
+ if (!threadStarter?.files?.length) return files;
2538
+ const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
2539
+ const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
2540
+ if (filtered.length < files.length) logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
2541
+ return filtered.length > 0 ? filtered : void 0;
2542
+ }
2543
+ async function resolveSlackMessageContent(params) {
2544
+ const ownFiles = filterInheritedParentFiles({
2545
+ files: params.message.files,
2546
+ isThreadReply: params.isThreadReply,
2547
+ threadStarter: params.threadStarter
2548
+ });
2549
+ const media = await resolveSlackMedia({
2550
+ files: ownFiles,
2551
+ token: params.botToken,
2552
+ maxBytes: params.mediaMaxBytes
2553
+ });
2554
+ const attachmentContent = await resolveSlackAttachmentContent({
2555
+ attachments: params.message.attachments,
2556
+ token: params.botToken,
2557
+ maxBytes: params.mediaMaxBytes
2558
+ });
2559
+ const mergedMedia = [...media ?? [], ...attachmentContent?.media ?? []];
2560
+ const effectiveDirectMedia = mergedMedia.length > 0 ? mergedMedia : null;
2561
+ const mediaPlaceholder = effectiveDirectMedia ? effectiveDirectMedia.map((item) => item.placeholder).join(" ") : void 0;
2562
+ const fallbackFiles = ownFiles ?? [];
2563
+ const fileOnlyFallback = !mediaPlaceholder && fallbackFiles.length > 0 ? fallbackFiles.slice(0, 8).map((file) => file.name?.trim() || "file").join(", ") : void 0;
2564
+ const fileOnlyPlaceholder = fileOnlyFallback ? `[Slack file: ${fileOnlyFallback}]` : void 0;
2565
+ const botAttachmentText = params.isBotMessage && !attachmentContent?.text ? (params.message.attachments ?? []).map((attachment) => attachment.text?.trim() || attachment.fallback?.trim()).filter(Boolean).join("\n") : void 0;
2566
+ const rawBody = [
2567
+ (params.message.text ?? "").trim(),
2568
+ attachmentContent?.text,
2569
+ botAttachmentText,
2570
+ mediaPlaceholder,
2571
+ fileOnlyPlaceholder
2572
+ ].filter(Boolean).join("\n") || "";
2573
+ if (!rawBody) return null;
2574
+ return {
2575
+ rawBody,
2576
+ effectiveDirectMedia
2577
+ };
2578
+ }
2579
+ //#endregion
2580
+ //#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
2581
+ async function resolveSlackThreadContextData(params) {
2582
+ let threadStarterBody;
2583
+ let threadHistoryBody;
2584
+ let threadSessionPreviousTimestamp;
2585
+ let threadLabel;
2586
+ let threadStarterMedia = null;
2587
+ if (!params.isThreadReply || !params.threadTs) return {
2588
+ threadStarterBody,
2589
+ threadHistoryBody,
2590
+ threadSessionPreviousTimestamp,
2591
+ threadLabel,
2592
+ threadStarterMedia
2593
+ };
2594
+ const starter = params.threadStarter;
2595
+ if (starter?.text) {
2596
+ threadStarterBody = starter.text;
2597
+ const snippet = starter.text.replace(/\s+/g, " ").slice(0, 80);
2598
+ threadLabel = `Slack thread ${params.roomLabel}${snippet ? `: ${snippet}` : ""}`;
2599
+ if (!params.effectiveDirectMedia && starter.files && starter.files.length > 0) {
2600
+ threadStarterMedia = await resolveSlackMedia({
2601
+ files: starter.files,
2602
+ token: params.ctx.botToken,
2603
+ maxBytes: params.ctx.mediaMaxBytes
2604
+ });
2605
+ if (threadStarterMedia) logVerbose(`slack: hydrated thread starter file ${threadStarterMedia.map((item) => item.placeholder).join(", ")} from root message`);
2606
+ }
2607
+ } else threadLabel = `Slack thread ${params.roomLabel}`;
2608
+ const threadInitialHistoryLimit = params.account.config?.thread?.initialHistoryLimit ?? 20;
2609
+ threadSessionPreviousTimestamp = readSessionUpdatedAt({
2610
+ storePath: params.storePath,
2611
+ sessionKey: params.sessionKey
2612
+ });
2613
+ if (threadInitialHistoryLimit > 0 && !threadSessionPreviousTimestamp) {
2614
+ const threadHistory = await resolveSlackThreadHistory({
2615
+ channelId: params.message.channel,
2616
+ threadTs: params.threadTs,
2617
+ client: params.ctx.app.client,
2618
+ currentMessageTs: params.message.ts,
2619
+ limit: threadInitialHistoryLimit
2620
+ });
2621
+ if (threadHistory.length > 0) {
2622
+ const uniqueUserIds = [...new Set(threadHistory.map((item) => item.userId).filter((id) => Boolean(id)))];
2623
+ const userMap = /* @__PURE__ */ new Map();
2624
+ await Promise.all(uniqueUserIds.map(async (id) => {
2625
+ const user = await params.ctx.resolveUserName(id);
2626
+ if (user) userMap.set(id, user);
2627
+ }));
2628
+ const historyParts = [];
2629
+ for (const historyMsg of threadHistory) {
2630
+ const msgSenderName = (historyMsg.userId ? userMap.get(historyMsg.userId) : null)?.name ?? (historyMsg.botId ? `Bot (${historyMsg.botId})` : "Unknown");
2631
+ const role = Boolean(historyMsg.botId) ? "assistant" : "user";
2632
+ const msgWithId = `${historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
2633
+ historyParts.push(formatInboundEnvelope({
2634
+ channel: "Slack",
2635
+ from: `${msgSenderName} (${role})`,
2636
+ timestamp: historyMsg.ts ? Math.round(Number(historyMsg.ts) * 1e3) : void 0,
2637
+ body: msgWithId,
2638
+ chatType: "channel",
2639
+ envelope: params.envelopeOptions
2640
+ }));
2641
+ }
2642
+ threadHistoryBody = historyParts.join("\n\n");
2643
+ logVerbose(`slack: populated thread history with ${threadHistory.length} messages for new session`);
2644
+ }
2645
+ }
2646
+ return {
2647
+ threadStarterBody,
2648
+ threadHistoryBody,
2649
+ threadSessionPreviousTimestamp,
2650
+ threadLabel,
2651
+ threadStarterMedia
2652
+ };
2653
+ }
2654
+ //#endregion
2655
+ //#region extensions/slack/src/monitor/message-handler/prepare.ts
2656
+ const mentionRegexCache = /* @__PURE__ */ new WeakMap();
2657
+ function resolveCachedMentionRegexes(ctx, agentId) {
2658
+ const key = agentId?.trim() || "__default__";
2659
+ let byAgent = mentionRegexCache.get(ctx);
2660
+ if (!byAgent) {
2661
+ byAgent = /* @__PURE__ */ new Map();
2662
+ mentionRegexCache.set(ctx, byAgent);
2663
+ }
2664
+ const cached = byAgent.get(key);
2665
+ if (cached) return cached;
2666
+ const built = buildMentionRegexes(ctx.cfg, agentId);
2667
+ byAgent.set(key, built);
2668
+ return built;
2669
+ }
2670
+ async function resolveSlackConversationContext(params) {
2671
+ const { ctx, account, message } = params;
2672
+ const cfg = ctx.cfg;
2673
+ let channelInfo = {};
2674
+ let resolvedChannelType = normalizeSlackChannelType(message.channel_type, message.channel);
2675
+ if (resolvedChannelType !== "im" && (!message.channel_type || message.channel_type !== "im")) {
2676
+ channelInfo = await ctx.resolveChannelName(message.channel);
2677
+ resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type, message.channel);
2678
+ }
2679
+ const channelName = channelInfo?.name;
2680
+ const isDirectMessage = resolvedChannelType === "im";
2681
+ const isGroupDm = resolvedChannelType === "mpim";
2682
+ const isRoom = resolvedChannelType === "channel" || resolvedChannelType === "group";
2683
+ const isRoomish = isRoom || isGroupDm;
2684
+ const channelConfig = isRoom ? resolveSlackChannelConfig({
2685
+ channelId: message.channel,
2686
+ channelName,
2687
+ channels: ctx.channelsConfig,
2688
+ channelKeys: ctx.channelsConfigKeys,
2689
+ defaultRequireMention: ctx.defaultRequireMention,
2690
+ allowNameMatching: ctx.allowNameMatching
2691
+ }) : null;
2692
+ const allowBots = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ?? false;
2693
+ return {
2694
+ channelInfo,
2695
+ channelName,
2696
+ resolvedChannelType,
2697
+ isDirectMessage,
2698
+ isGroupDm,
2699
+ isRoom,
2700
+ isRoomish,
2701
+ channelConfig,
2702
+ allowBots,
2703
+ isBotMessage: Boolean(message.bot_id)
2704
+ };
2705
+ }
2706
+ async function authorizeSlackInboundMessage(params) {
2707
+ const { ctx, account, message, conversation } = params;
2708
+ const { isDirectMessage, channelName, resolvedChannelType, isBotMessage, allowBots } = conversation;
2709
+ if (isBotMessage) {
2710
+ if (message.user && ctx.botUserId && message.user === ctx.botUserId) return null;
2711
+ if (!allowBots) {
2712
+ logVerbose(`slack: drop bot message ${message.bot_id ?? "unknown"} (allowBots=false)`);
2713
+ return null;
2714
+ }
2715
+ }
2716
+ if (isDirectMessage && !message.user) {
2717
+ logVerbose("slack: drop dm message (missing user id)");
2718
+ return null;
2719
+ }
2720
+ const senderId = message.user ?? (isBotMessage ? message.bot_id : void 0);
2721
+ if (!senderId) {
2722
+ logVerbose("slack: drop message (missing sender id)");
2723
+ return null;
2724
+ }
2725
+ if (!ctx.isChannelAllowed({
2726
+ channelId: message.channel,
2727
+ channelName,
2728
+ channelType: resolvedChannelType
2729
+ })) {
2730
+ logVerbose("slack: drop message (channel not allowed)");
2731
+ return null;
2732
+ }
2733
+ const { allowFromLower } = await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: isDirectMessage });
2734
+ if (isDirectMessage) {
2735
+ const directUserId = message.user;
2736
+ if (!directUserId) {
2737
+ logVerbose("slack: drop dm message (missing user id)");
2738
+ return null;
2739
+ }
2740
+ if (!await authorizeSlackDirectMessage({
2741
+ ctx,
2742
+ accountId: account.accountId,
2743
+ senderId: directUserId,
2744
+ allowFromLower,
2745
+ resolveSenderName: ctx.resolveUserName,
2746
+ sendPairingReply: async (text) => {
2747
+ await sendMessageSlack(message.channel, text, {
2748
+ token: ctx.botToken,
2749
+ client: ctx.app.client,
2750
+ accountId: account.accountId
2751
+ });
2752
+ },
2753
+ onDisabled: () => {
2754
+ logVerbose("slack: drop dm (dms disabled)");
2755
+ },
2756
+ onUnauthorized: ({ allowMatchMeta }) => {
2757
+ logVerbose(`Blocked unauthorized slack sender ${message.user} (dmPolicy=${ctx.dmPolicy}, ${allowMatchMeta})`);
2758
+ },
2759
+ log: logVerbose
2760
+ })) return null;
2761
+ }
2762
+ return {
2763
+ senderId,
2764
+ allowFromLower
2765
+ };
2766
+ }
2767
+ function resolveSlackRoutingContext(params) {
2768
+ const { ctx, account, message, isDirectMessage, isGroupDm, isRoom, isRoomish } = params;
2769
+ const route = resolveAgentRoute({
2770
+ cfg: ctx.cfg,
2771
+ channel: "slack",
2772
+ accountId: account.accountId,
2773
+ teamId: ctx.teamId || void 0,
2774
+ peer: {
2775
+ kind: isDirectMessage ? "direct" : isRoom ? "channel" : "group",
2776
+ id: isDirectMessage ? message.user ?? "unknown" : message.channel
2777
+ }
2778
+ });
2779
+ const chatType = isDirectMessage ? "direct" : isGroupDm ? "group" : "channel";
2780
+ const replyToMode = resolveSlackReplyToMode(account, chatType);
2781
+ const threadContext = resolveSlackThreadContext({
2782
+ message,
2783
+ replyToMode
2784
+ });
2785
+ const threadTs = threadContext.incomingThreadTs;
2786
+ const isThreadReply = threadContext.isThreadReply;
2787
+ const autoThreadId = !isThreadReply && replyToMode === "all" && threadContext.messageTs ? threadContext.messageTs : void 0;
2788
+ const canonicalThreadId = isRoomish ? isThreadReply && threadTs ? threadTs : void 0 : isThreadReply ? threadTs : autoThreadId;
2789
+ const threadKeys = resolveThreadSessionKeys({
2790
+ baseSessionKey: route.sessionKey,
2791
+ threadId: canonicalThreadId,
2792
+ parentSessionKey: canonicalThreadId && ctx.threadInheritParent ? route.sessionKey : void 0
2793
+ });
2794
+ const sessionKey = threadKeys.sessionKey;
2795
+ return {
2796
+ route,
2797
+ chatType,
2798
+ replyToMode,
2799
+ threadContext,
2800
+ threadTs,
2801
+ isThreadReply,
2802
+ threadKeys,
2803
+ sessionKey,
2804
+ historyKey: isThreadReply && ctx.threadHistoryScope === "thread" ? sessionKey : message.channel
2805
+ };
2806
+ }
2807
+ async function prepareSlackMessage(params) {
2808
+ const { ctx, account, message, opts } = params;
2809
+ const cfg = ctx.cfg;
2810
+ const conversation = await resolveSlackConversationContext({
2811
+ ctx,
2812
+ account,
2813
+ message
2814
+ });
2815
+ const { channelInfo, channelName, isDirectMessage, isGroupDm, isRoom, isRoomish, channelConfig, isBotMessage } = conversation;
2816
+ const authorization = await authorizeSlackInboundMessage({
2817
+ ctx,
2818
+ account,
2819
+ message,
2820
+ conversation
2821
+ });
2822
+ if (!authorization) return null;
2823
+ const { senderId, allowFromLower } = authorization;
2824
+ const { route, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey, historyKey } = resolveSlackRoutingContext({
2825
+ ctx,
2826
+ account,
2827
+ message,
2828
+ isDirectMessage,
2829
+ isGroupDm,
2830
+ isRoom,
2831
+ isRoomish
2832
+ });
2833
+ const mentionRegexes = resolveCachedMentionRegexes(ctx, route.agentId);
2834
+ const hasAnyMention = /<@[^>]+>/.test(message.text ?? "");
2835
+ const explicitlyMentioned = Boolean(ctx.botUserId && message.text?.includes(`<@${ctx.botUserId}>`));
2836
+ const wasMentioned = opts.wasMentioned ?? (!isDirectMessage && matchesMentionWithExplicit({
2837
+ text: message.text ?? "",
2838
+ mentionRegexes,
2839
+ explicit: {
2840
+ hasAnyMention,
2841
+ isExplicitlyMentioned: explicitlyMentioned,
2842
+ canResolveExplicit: Boolean(ctx.botUserId)
2843
+ }
2844
+ }));
2845
+ const implicitMention = Boolean(!isDirectMessage && ctx.botUserId && message.thread_ts && (message.parent_user_id === ctx.botUserId || hasSlackThreadParticipation(account.accountId, message.channel, message.thread_ts)));
2846
+ let resolvedSenderName = message.username?.trim() || void 0;
2847
+ const resolveSenderName = async () => {
2848
+ if (resolvedSenderName) return resolvedSenderName;
2849
+ if (message.user) {
2850
+ const normalized = (await ctx.resolveUserName(message.user))?.name?.trim();
2851
+ if (normalized) {
2852
+ resolvedSenderName = normalized;
2853
+ return resolvedSenderName;
2854
+ }
2855
+ }
2856
+ resolvedSenderName = message.user ?? message.bot_id ?? "unknown";
2857
+ return resolvedSenderName;
2858
+ };
2859
+ const senderNameForAuth = ctx.allowNameMatching ? await resolveSenderName() : void 0;
2860
+ const channelUserAuthorized = isRoom ? resolveSlackUserAllowed({
2861
+ allowList: channelConfig?.users,
2862
+ userId: senderId,
2863
+ userName: senderNameForAuth,
2864
+ allowNameMatching: ctx.allowNameMatching
2865
+ }) : true;
2866
+ if (isRoom && !channelUserAuthorized) {
2867
+ logVerbose(`Blocked unauthorized slack sender ${senderId} (not in channel users)`);
2868
+ return null;
2869
+ }
2870
+ const allowTextCommands = shouldHandleTextCommands({
2871
+ cfg,
2872
+ surface: "slack"
2873
+ });
2874
+ const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
2875
+ const hasControlCommandInMessage = hasControlCommand(textForCommandDetection, cfg);
2876
+ const ownerAuthorized = resolveSlackAllowListMatch({
2877
+ allowList: allowFromLower,
2878
+ id: senderId,
2879
+ name: senderNameForAuth,
2880
+ allowNameMatching: ctx.allowNameMatching
2881
+ }).allowed;
2882
+ const channelUsersAllowlistConfigured = isRoom && Array.isArray(channelConfig?.users) && channelConfig.users.length > 0;
2883
+ const channelCommandAuthorized = isRoom && channelUsersAllowlistConfigured ? resolveSlackUserAllowed({
2884
+ allowList: channelConfig?.users,
2885
+ userId: senderId,
2886
+ userName: senderNameForAuth,
2887
+ allowNameMatching: ctx.allowNameMatching
2888
+ }) : false;
2889
+ const commandGate = resolveControlCommandGate({
2890
+ useAccessGroups: ctx.useAccessGroups,
2891
+ authorizers: [{
2892
+ configured: allowFromLower.length > 0,
2893
+ allowed: ownerAuthorized
2894
+ }, {
2895
+ configured: channelUsersAllowlistConfigured,
2896
+ allowed: channelCommandAuthorized
2897
+ }],
2898
+ allowTextCommands,
2899
+ hasControlCommand: hasControlCommandInMessage
2900
+ });
2901
+ const commandAuthorized = commandGate.commandAuthorized;
2902
+ if (isRoomish && commandGate.shouldBlock) {
2903
+ logInboundDrop({
2904
+ log: logVerbose,
2905
+ channel: "slack",
2906
+ reason: "control command (unauthorized)",
2907
+ target: senderId
2908
+ });
2909
+ return null;
2910
+ }
2911
+ const shouldRequireMention = isRoom ? channelConfig?.requireMention ?? ctx.defaultRequireMention : false;
2912
+ const canDetectMention = Boolean(ctx.botUserId) || mentionRegexes.length > 0;
2913
+ const mentionGate = resolveMentionGatingWithBypass({
2914
+ isGroup: isRoom,
2915
+ requireMention: Boolean(shouldRequireMention),
2916
+ canDetectMention,
2917
+ wasMentioned,
2918
+ implicitMention,
2919
+ hasAnyMention,
2920
+ allowTextCommands,
2921
+ hasControlCommand: hasControlCommandInMessage,
2922
+ commandAuthorized
2923
+ });
2924
+ const effectiveWasMentioned = mentionGate.effectiveWasMentioned;
2925
+ if (isRoom && shouldRequireMention && mentionGate.shouldSkip) {
2926
+ ctx.logger.info({
2927
+ channel: message.channel,
2928
+ reason: "no-mention"
2929
+ }, "skipping channel message");
2930
+ const pendingText = (message.text ?? "").trim();
2931
+ const fallbackFile = message.files?.[0]?.name ? `[Slack file: ${message.files[0].name}]` : message.files?.length ? "[Slack file]" : "";
2932
+ const pendingBody = pendingText || fallbackFile;
2933
+ recordPendingHistoryEntryIfEnabled({
2934
+ historyMap: ctx.channelHistories,
2935
+ historyKey,
2936
+ limit: ctx.historyLimit,
2937
+ entry: pendingBody ? {
2938
+ sender: await resolveSenderName(),
2939
+ body: pendingBody,
2940
+ timestamp: message.ts ? Math.round(Number(message.ts) * 1e3) : void 0,
2941
+ messageId: message.ts
2942
+ } : null
2943
+ });
2944
+ return null;
2945
+ }
2946
+ const threadStarter = isThreadReply && threadTs ? await resolveSlackThreadStarter({
2947
+ channelId: message.channel,
2948
+ threadTs,
2949
+ client: ctx.app.client
2950
+ }) : null;
2951
+ const resolvedMessageContent = await resolveSlackMessageContent({
2952
+ message,
2953
+ isThreadReply,
2954
+ threadStarter,
2955
+ isBotMessage,
2956
+ botToken: ctx.botToken,
2957
+ mediaMaxBytes: ctx.mediaMaxBytes
2958
+ });
2959
+ if (!resolvedMessageContent) return null;
2960
+ const { rawBody, effectiveDirectMedia } = resolvedMessageContent;
2961
+ const ackReaction = resolveAckReaction(cfg, route.agentId, {
2962
+ channel: "slack",
2963
+ accountId: account.accountId
2964
+ });
2965
+ const ackReactionValue = ackReaction ?? "";
2966
+ const shouldAckReaction$1 = () => Boolean(ackReaction && shouldAckReaction({
2967
+ scope: ctx.ackReactionScope,
2968
+ isDirect: isDirectMessage,
2969
+ isGroup: isRoomish,
2970
+ isMentionableGroup: isRoom,
2971
+ requireMention: Boolean(shouldRequireMention),
2972
+ canDetectMention,
2973
+ effectiveWasMentioned,
2974
+ shouldBypassMention: mentionGate.shouldBypassMention
2975
+ }));
2976
+ const ackReactionMessageTs = message.ts;
2977
+ const ackReactionPromise = shouldAckReaction$1() && ackReactionMessageTs && ackReactionValue ? reactSlackMessage(message.channel, ackReactionMessageTs, ackReactionValue, {
2978
+ token: ctx.botToken,
2979
+ client: ctx.app.client
2980
+ }).then(() => true, (err) => {
2981
+ logVerbose(`slack react failed for channel ${message.channel}: ${String(err)}`);
2982
+ return false;
2983
+ }) : null;
2984
+ const roomLabel = channelName ? `#${channelName}` : `#${message.channel}`;
2985
+ const senderName = await resolveSenderName();
2986
+ const preview = rawBody.replace(/\s+/g, " ").slice(0, 160);
2987
+ const inboundLabel = isDirectMessage ? `Slack DM from ${senderName}` : `Slack message in ${roomLabel} from ${senderName}`;
2988
+ const slackFrom = isDirectMessage ? `slack:${message.user}` : isRoom ? `slack:channel:${message.channel}` : `slack:group:${message.channel}`;
2989
+ enqueueSystemEvent(`${inboundLabel}: ${preview}`, {
2990
+ sessionKey,
2991
+ contextKey: `slack:message:${message.channel}:${message.ts ?? "unknown"}`
2992
+ });
2993
+ const envelopeFrom = resolveConversationLabel({
2994
+ ChatType: isDirectMessage ? "direct" : "channel",
2995
+ SenderName: senderName,
2996
+ GroupSubject: isRoomish ? roomLabel : void 0,
2997
+ From: slackFrom
2998
+ }) ?? (isDirectMessage ? senderName : roomLabel);
2999
+ const threadInfo = isThreadReply && threadTs ? ` thread_ts: ${threadTs}${message.parent_user_id ? ` parent_user_id: ${message.parent_user_id}` : ""}` : "";
3000
+ const textWithId = `${rawBody}\n[slack message id: ${message.ts} channel: ${message.channel}${threadInfo}]`;
3001
+ const storePath = resolveStorePath(ctx.cfg.session?.store, { agentId: route.agentId });
3002
+ const envelopeOptions = resolveEnvelopeFormatOptions(ctx.cfg);
3003
+ const previousTimestamp = readSessionUpdatedAt({
3004
+ storePath,
3005
+ sessionKey
3006
+ });
3007
+ let combinedBody = formatInboundEnvelope({
3008
+ channel: "Slack",
3009
+ from: envelopeFrom,
3010
+ timestamp: message.ts ? Math.round(Number(message.ts) * 1e3) : void 0,
3011
+ body: textWithId,
3012
+ chatType: isDirectMessage ? "direct" : "channel",
3013
+ sender: {
3014
+ name: senderName,
3015
+ id: senderId
3016
+ },
3017
+ previousTimestamp,
3018
+ envelope: envelopeOptions
3019
+ });
3020
+ if (isRoomish && ctx.historyLimit > 0) combinedBody = buildPendingHistoryContextFromMap({
3021
+ historyMap: ctx.channelHistories,
3022
+ historyKey,
3023
+ limit: ctx.historyLimit,
3024
+ currentMessage: combinedBody,
3025
+ formatEntry: (entry) => formatInboundEnvelope({
3026
+ channel: "Slack",
3027
+ from: roomLabel,
3028
+ timestamp: entry.timestamp,
3029
+ body: `${entry.body}${entry.messageId ? ` [id:${entry.messageId} channel:${message.channel}]` : ""}`,
3030
+ chatType: "channel",
3031
+ senderLabel: entry.sender,
3032
+ envelope: envelopeOptions
3033
+ })
3034
+ });
3035
+ const slackTo = isDirectMessage ? `user:${message.user}` : `channel:${message.channel}`;
3036
+ const { untrustedChannelMetadata, groupSystemPrompt } = resolveSlackRoomContextHints({
3037
+ isRoomish,
3038
+ channelInfo,
3039
+ channelConfig
3040
+ });
3041
+ const { threadStarterBody, threadHistoryBody, threadSessionPreviousTimestamp, threadLabel, threadStarterMedia } = await resolveSlackThreadContextData({
3042
+ ctx,
3043
+ account,
3044
+ message,
3045
+ isThreadReply,
3046
+ threadTs,
3047
+ threadStarter,
3048
+ roomLabel,
3049
+ storePath,
3050
+ sessionKey,
3051
+ envelopeOptions,
3052
+ effectiveDirectMedia
3053
+ });
3054
+ const effectiveMedia = effectiveDirectMedia ?? threadStarterMedia;
3055
+ const firstMedia = effectiveMedia?.[0];
3056
+ const inboundHistory = isRoomish && ctx.historyLimit > 0 ? (ctx.channelHistories.get(historyKey) ?? []).map((entry) => ({
3057
+ sender: entry.sender,
3058
+ body: entry.body,
3059
+ timestamp: entry.timestamp
3060
+ })) : void 0;
3061
+ const commandBody = textForCommandDetection.trim();
3062
+ const ctxPayload = finalizeInboundContext({
3063
+ Body: combinedBody,
3064
+ BodyForAgent: rawBody,
3065
+ InboundHistory: inboundHistory,
3066
+ RawBody: rawBody,
3067
+ CommandBody: commandBody,
3068
+ BodyForCommands: commandBody,
3069
+ From: slackFrom,
3070
+ To: slackTo,
3071
+ SessionKey: sessionKey,
3072
+ AccountId: route.accountId,
3073
+ ChatType: isDirectMessage ? "direct" : "channel",
3074
+ ConversationLabel: envelopeFrom,
3075
+ GroupSubject: isRoomish ? roomLabel : void 0,
3076
+ GroupSystemPrompt: isRoomish ? groupSystemPrompt : void 0,
3077
+ UntrustedContext: untrustedChannelMetadata ? [untrustedChannelMetadata] : void 0,
3078
+ SenderName: senderName,
3079
+ SenderId: senderId,
3080
+ Provider: "slack",
3081
+ Surface: "slack",
3082
+ MessageSid: message.ts,
3083
+ ReplyToId: threadContext.replyToId,
3084
+ MessageThreadId: threadContext.messageThreadId,
3085
+ ParentSessionKey: threadKeys.parentSessionKey,
3086
+ ThreadStarterBody: !threadSessionPreviousTimestamp ? threadStarterBody : void 0,
3087
+ ThreadHistoryBody: threadHistoryBody,
3088
+ IsFirstThreadTurn: isThreadReply && threadTs && !threadSessionPreviousTimestamp ? true : void 0,
3089
+ ThreadLabel: threadLabel,
3090
+ Timestamp: message.ts ? Math.round(Number(message.ts) * 1e3) : void 0,
3091
+ WasMentioned: isRoomish ? effectiveWasMentioned : void 0,
3092
+ MediaPath: firstMedia?.path,
3093
+ MediaType: firstMedia?.contentType,
3094
+ MediaUrl: firstMedia?.path,
3095
+ MediaPaths: effectiveMedia && effectiveMedia.length > 0 ? effectiveMedia.map((m) => m.path) : void 0,
3096
+ MediaUrls: effectiveMedia && effectiveMedia.length > 0 ? effectiveMedia.map((m) => m.path) : void 0,
3097
+ MediaTypes: effectiveMedia && effectiveMedia.length > 0 ? effectiveMedia.map((m) => m.contentType ?? "") : void 0,
3098
+ CommandAuthorized: commandAuthorized,
3099
+ OriginatingChannel: "slack",
3100
+ OriginatingTo: slackTo,
3101
+ NativeChannelId: message.channel
3102
+ });
3103
+ const pinnedMainDmOwner = isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
3104
+ dmScope: cfg.session?.dmScope,
3105
+ allowFrom: ctx.allowFrom,
3106
+ normalizeEntry: normalizeSlackAllowOwnerEntry
3107
+ }) : null;
3108
+ await recordInboundSession({
3109
+ storePath,
3110
+ sessionKey,
3111
+ ctx: ctxPayload,
3112
+ updateLastRoute: isDirectMessage ? {
3113
+ sessionKey: route.mainSessionKey,
3114
+ channel: "slack",
3115
+ to: `user:${message.user}`,
3116
+ accountId: route.accountId,
3117
+ threadId: threadContext.messageThreadId,
3118
+ mainDmOwnerPin: pinnedMainDmOwner && message.user ? {
3119
+ ownerRecipient: pinnedMainDmOwner,
3120
+ senderRecipient: message.user.toLowerCase(),
3121
+ onSkip: ({ ownerRecipient, senderRecipient }) => {
3122
+ logVerbose(`slack: skip main-session last route for ${senderRecipient} (pinned owner ${ownerRecipient})`);
3123
+ }
3124
+ } : void 0
3125
+ } : void 0,
3126
+ onRecordError: (err) => {
3127
+ ctx.logger.warn({
3128
+ error: String(err),
3129
+ storePath,
3130
+ sessionKey
3131
+ }, "failed updating session meta");
3132
+ }
3133
+ });
3134
+ const replyTarget = ctxPayload.To ?? void 0;
3135
+ if (!replyTarget) return null;
3136
+ if (shouldLogVerbose()) logVerbose(`slack inbound: channel=${message.channel} from=${slackFrom} preview="${preview}"`);
3137
+ return {
3138
+ ctx,
3139
+ account,
3140
+ message,
3141
+ route,
3142
+ channelConfig,
3143
+ replyTarget,
3144
+ ctxPayload,
3145
+ replyToMode,
3146
+ isDirectMessage,
3147
+ isRoomish,
3148
+ historyKey,
3149
+ preview,
3150
+ ackReactionMessageTs,
3151
+ ackReactionValue,
3152
+ ackReactionPromise
3153
+ };
3154
+ }
3155
+ //#endregion
3156
+ //#region extensions/slack/src/monitor/thread-resolution.ts
3157
+ const DEFAULT_THREAD_TS_CACHE_TTL_MS = 6e4;
3158
+ const DEFAULT_THREAD_TS_CACHE_MAX = 500;
3159
+ const normalizeThreadTs = (threadTs) => {
3160
+ const trimmed = threadTs?.trim();
3161
+ return trimmed ? trimmed : void 0;
3162
+ };
3163
+ async function resolveThreadTsFromHistory(params) {
3164
+ try {
3165
+ const response = await params.client.conversations.history({
3166
+ channel: params.channelId,
3167
+ latest: params.messageTs,
3168
+ oldest: params.messageTs,
3169
+ inclusive: true,
3170
+ limit: 1
3171
+ });
3172
+ return normalizeThreadTs((response.messages?.find((entry) => entry.ts === params.messageTs) ?? response.messages?.[0])?.thread_ts);
3173
+ } catch (err) {
3174
+ if (shouldLogVerbose()) logVerbose(`slack inbound: failed to resolve thread_ts via conversations.history for channel=${params.channelId} ts=${params.messageTs}: ${String(err)}`);
3175
+ return;
3176
+ }
3177
+ }
3178
+ function createSlackThreadTsResolver(params) {
3179
+ const ttlMs = Math.max(0, params.cacheTtlMs ?? DEFAULT_THREAD_TS_CACHE_TTL_MS);
3180
+ const maxSize = Math.max(0, params.maxSize ?? DEFAULT_THREAD_TS_CACHE_MAX);
3181
+ const cache = /* @__PURE__ */ new Map();
3182
+ const inflight = /* @__PURE__ */ new Map();
3183
+ const getCached = (key, now) => {
3184
+ const entry = cache.get(key);
3185
+ if (!entry) return;
3186
+ if (ttlMs > 0 && now - entry.updatedAt > ttlMs) {
3187
+ cache.delete(key);
3188
+ return;
3189
+ }
3190
+ cache.delete(key);
3191
+ cache.set(key, {
3192
+ ...entry,
3193
+ updatedAt: now
3194
+ });
3195
+ return entry.threadTs;
3196
+ };
3197
+ const setCached = (key, threadTs, now) => {
3198
+ cache.delete(key);
3199
+ cache.set(key, {
3200
+ threadTs,
3201
+ updatedAt: now
3202
+ });
3203
+ pruneMapToMaxSize(cache, maxSize);
3204
+ };
3205
+ return { resolve: async (request) => {
3206
+ const { message } = request;
3207
+ if (!message.parent_user_id || message.thread_ts || !message.ts) return message;
3208
+ const cacheKey = `${message.channel}:${message.ts}`;
3209
+ const cached = getCached(cacheKey, Date.now());
3210
+ if (cached !== void 0) return cached ? {
3211
+ ...message,
3212
+ thread_ts: cached
3213
+ } : message;
3214
+ if (shouldLogVerbose()) logVerbose(`slack inbound: missing thread_ts for thread reply channel=${message.channel} ts=${message.ts} source=${request.source}`);
3215
+ let pending = inflight.get(cacheKey);
3216
+ if (!pending) {
3217
+ pending = resolveThreadTsFromHistory({
3218
+ client: params.client,
3219
+ channelId: message.channel,
3220
+ messageTs: message.ts
3221
+ });
3222
+ inflight.set(cacheKey, pending);
3223
+ }
3224
+ let resolved;
3225
+ try {
3226
+ resolved = await pending;
3227
+ } finally {
3228
+ inflight.delete(cacheKey);
3229
+ }
3230
+ setCached(cacheKey, resolved ?? null, Date.now());
3231
+ if (resolved) {
3232
+ if (shouldLogVerbose()) logVerbose(`slack inbound: resolved missing thread_ts channel=${message.channel} ts=${message.ts} -> thread_ts=${resolved}`);
3233
+ return {
3234
+ ...message,
3235
+ thread_ts: resolved
3236
+ };
3237
+ }
3238
+ if (shouldLogVerbose()) logVerbose(`slack inbound: could not resolve missing thread_ts channel=${message.channel} ts=${message.ts}`);
3239
+ return message;
3240
+ } };
3241
+ }
3242
+ //#endregion
3243
+ //#region extensions/slack/src/monitor/message-handler.ts
3244
+ const APP_MENTION_RETRY_TTL_MS = 6e4;
3245
+ function resolveSlackSenderId(message) {
3246
+ return message.user ?? message.bot_id ?? null;
3247
+ }
3248
+ function isSlackDirectMessageChannel(channelId) {
3249
+ return channelId.startsWith("D");
3250
+ }
3251
+ function isTopLevelSlackMessage(message) {
3252
+ return !message.thread_ts && !message.parent_user_id;
3253
+ }
3254
+ function buildTopLevelSlackConversationKey(message, accountId) {
3255
+ if (!isTopLevelSlackMessage(message)) return null;
3256
+ const senderId = resolveSlackSenderId(message);
3257
+ if (!senderId) return null;
3258
+ return `slack:${accountId}:${message.channel}:${senderId}`;
3259
+ }
3260
+ function shouldDebounceSlackMessage(message, cfg) {
3261
+ return shouldDebounceTextInbound({
3262
+ text: stripSlackMentionsForCommandDetection(message.text ?? ""),
3263
+ cfg,
3264
+ hasMedia: Boolean(message.files && message.files.length > 0)
3265
+ });
3266
+ }
3267
+ function buildSeenMessageKey(channelId, ts) {
3268
+ if (!channelId || !ts) return null;
3269
+ return `${channelId}:${ts}`;
3270
+ }
3271
+ /**
3272
+ * Build a debounce key that isolates messages by thread (or by message timestamp
3273
+ * for top-level non-DM channel messages). Without per-message scoping, concurrent
3274
+ * top-level messages from the same sender can share a key and get merged
3275
+ * into a single reply on the wrong thread.
3276
+ *
3277
+ * DMs intentionally stay channel-scoped to preserve short-message batching.
3278
+ */
3279
+ function buildSlackDebounceKey(message, accountId) {
3280
+ const senderId = resolveSlackSenderId(message);
3281
+ if (!senderId) return null;
3282
+ const messageTs = message.ts ?? message.event_ts;
3283
+ return `slack:${accountId}:${message.thread_ts ? `${message.channel}:${message.thread_ts}` : message.parent_user_id && messageTs ? `${message.channel}:maybe-thread:${messageTs}` : messageTs && !isSlackDirectMessageChannel(message.channel) ? `${message.channel}:${messageTs}` : message.channel}:${senderId}`;
3284
+ }
3285
+ function createSlackMessageHandler(params) {
3286
+ const { ctx, account, trackEvent } = params;
3287
+ const { debounceMs, debouncer } = createChannelInboundDebouncer({
3288
+ cfg: ctx.cfg,
3289
+ channel: "slack",
3290
+ buildKey: (entry) => buildSlackDebounceKey(entry.message, ctx.accountId),
3291
+ shouldDebounce: (entry) => shouldDebounceSlackMessage(entry.message, ctx.cfg),
3292
+ onFlush: async (entries) => {
3293
+ const last = entries.at(-1);
3294
+ if (!last) return;
3295
+ const flushedKey = buildSlackDebounceKey(last.message, ctx.accountId);
3296
+ const topLevelConversationKey = buildTopLevelSlackConversationKey(last.message, ctx.accountId);
3297
+ if (flushedKey && topLevelConversationKey) {
3298
+ const pendingKeys = pendingTopLevelDebounceKeys.get(topLevelConversationKey);
3299
+ if (pendingKeys) {
3300
+ pendingKeys.delete(flushedKey);
3301
+ if (pendingKeys.size === 0) pendingTopLevelDebounceKeys.delete(topLevelConversationKey);
3302
+ }
3303
+ }
3304
+ const combinedText = entries.length === 1 ? last.message.text ?? "" : entries.map((entry) => entry.message.text ?? "").filter(Boolean).join("\n");
3305
+ const combinedMentioned = entries.some((entry) => Boolean(entry.opts.wasMentioned));
3306
+ const prepared = await prepareSlackMessage({
3307
+ ctx,
3308
+ account,
3309
+ message: {
3310
+ ...last.message,
3311
+ text: combinedText
3312
+ },
3313
+ opts: {
3314
+ ...last.opts,
3315
+ wasMentioned: combinedMentioned || last.opts.wasMentioned
3316
+ }
3317
+ });
3318
+ const seenMessageKey = buildSeenMessageKey(last.message.channel, last.message.ts);
3319
+ if (!prepared) return;
3320
+ if (seenMessageKey) {
3321
+ pruneAppMentionRetryKeys(Date.now());
3322
+ if (last.opts.source === "app_mention") appMentionDispatchedKeys.set(seenMessageKey, Date.now() + APP_MENTION_RETRY_TTL_MS);
3323
+ else if (last.opts.source === "message" && appMentionDispatchedKeys.has(seenMessageKey)) {
3324
+ appMentionDispatchedKeys.delete(seenMessageKey);
3325
+ appMentionRetryKeys.delete(seenMessageKey);
3326
+ return;
3327
+ }
3328
+ appMentionRetryKeys.delete(seenMessageKey);
3329
+ }
3330
+ if (entries.length > 1) {
3331
+ const ids = entries.map((entry) => entry.message.ts).filter(Boolean);
3332
+ if (ids.length > 0) {
3333
+ prepared.ctxPayload.MessageSids = ids;
3334
+ prepared.ctxPayload.MessageSidFirst = ids[0];
3335
+ prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
3336
+ }
3337
+ }
3338
+ await dispatchPreparedSlackMessage(prepared);
3339
+ },
3340
+ onError: (err) => {
3341
+ ctx.runtime.error?.(`slack inbound debounce flush failed: ${String(err)}`);
3342
+ }
3343
+ });
3344
+ const threadTsResolver = createSlackThreadTsResolver({ client: ctx.app.client });
3345
+ const pendingTopLevelDebounceKeys = /* @__PURE__ */ new Map();
3346
+ const appMentionRetryKeys = /* @__PURE__ */ new Map();
3347
+ const appMentionDispatchedKeys = /* @__PURE__ */ new Map();
3348
+ const pruneAppMentionRetryKeys = (now) => {
3349
+ for (const [key, expiresAt] of appMentionRetryKeys) if (expiresAt <= now) appMentionRetryKeys.delete(key);
3350
+ for (const [key, expiresAt] of appMentionDispatchedKeys) if (expiresAt <= now) appMentionDispatchedKeys.delete(key);
3351
+ };
3352
+ const rememberAppMentionRetryKey = (key) => {
3353
+ const now = Date.now();
3354
+ pruneAppMentionRetryKeys(now);
3355
+ appMentionRetryKeys.set(key, now + APP_MENTION_RETRY_TTL_MS);
3356
+ };
3357
+ const consumeAppMentionRetryKey = (key) => {
3358
+ pruneAppMentionRetryKeys(Date.now());
3359
+ if (!appMentionRetryKeys.has(key)) return false;
3360
+ appMentionRetryKeys.delete(key);
3361
+ return true;
3362
+ };
3363
+ return async (message, opts) => {
3364
+ if (opts.source === "message" && message.type !== "message") return;
3365
+ if (opts.source === "message" && message.subtype && message.subtype !== "file_share" && message.subtype !== "bot_message") return;
3366
+ const seenMessageKey = buildSeenMessageKey(message.channel, message.ts);
3367
+ const wasSeen = seenMessageKey ? ctx.markMessageSeen(message.channel, message.ts) : false;
3368
+ if (seenMessageKey && opts.source === "message" && !wasSeen) rememberAppMentionRetryKey(seenMessageKey);
3369
+ if (seenMessageKey && wasSeen) {
3370
+ if (opts.source !== "app_mention" || !consumeAppMentionRetryKey(seenMessageKey)) return;
3371
+ }
3372
+ trackEvent?.();
3373
+ const resolvedMessage = await threadTsResolver.resolve({
3374
+ message,
3375
+ source: opts.source
3376
+ });
3377
+ const debounceKey = buildSlackDebounceKey(resolvedMessage, ctx.accountId);
3378
+ const conversationKey = buildTopLevelSlackConversationKey(resolvedMessage, ctx.accountId);
3379
+ const canDebounce = debounceMs > 0 && shouldDebounceSlackMessage(resolvedMessage, ctx.cfg);
3380
+ if (!canDebounce && conversationKey) {
3381
+ const pendingKeys = pendingTopLevelDebounceKeys.get(conversationKey);
3382
+ if (pendingKeys && pendingKeys.size > 0) {
3383
+ const keysToFlush = Array.from(pendingKeys);
3384
+ for (const pendingKey of keysToFlush) await debouncer.flushKey(pendingKey);
3385
+ }
3386
+ }
3387
+ if (canDebounce && debounceKey && conversationKey) {
3388
+ const pendingKeys = pendingTopLevelDebounceKeys.get(conversationKey) ?? /* @__PURE__ */ new Set();
3389
+ pendingKeys.add(debounceKey);
3390
+ pendingTopLevelDebounceKeys.set(conversationKey, pendingKeys);
3391
+ }
3392
+ await debouncer.enqueue({
3393
+ message: resolvedMessage,
3394
+ opts
3395
+ });
3396
+ };
3397
+ }
3398
+ //#endregion
3399
+ //#region extensions/slack/src/monitor/reconnect-policy.ts
3400
+ const SLACK_AUTH_ERROR_RE = /account_inactive|invalid_auth|token_revoked|token_expired|not_authed|org_login_required|team_access_not_granted|missing_scope|cannot_find_service|invalid_token/i;
3401
+ const SLACK_SOCKET_RECONNECT_POLICY = {
3402
+ initialMs: 2e3,
3403
+ maxMs: 3e4,
3404
+ factor: 1.8,
3405
+ jitter: .25,
3406
+ maxAttempts: 12
3407
+ };
3408
+ function getSocketEmitter(app) {
3409
+ const receiver = app.receiver;
3410
+ const client = receiver && typeof receiver === "object" ? receiver.client : void 0;
3411
+ if (!client || typeof client !== "object") return null;
3412
+ const on = client.on;
3413
+ const off = client.off;
3414
+ if (typeof on !== "function" || typeof off !== "function") return null;
3415
+ return {
3416
+ on: (event, listener) => on.call(client, event, listener),
3417
+ off: (event, listener) => off.call(client, event, listener)
3418
+ };
3419
+ }
3420
+ function waitForSlackSocketDisconnect(app, abortSignal) {
3421
+ return new Promise((resolve) => {
3422
+ const emitter = getSocketEmitter(app);
3423
+ if (!emitter) {
3424
+ abortSignal?.addEventListener("abort", () => resolve({ event: "disconnect" }), { once: true });
3425
+ return;
3426
+ }
3427
+ const disconnectListener = () => resolveOnce({ event: "disconnect" });
3428
+ const startFailListener = (error) => resolveOnce({
3429
+ event: "unable_to_socket_mode_start",
3430
+ error
3431
+ });
3432
+ const errorListener = (error) => resolveOnce({
3433
+ event: "error",
3434
+ error
3435
+ });
3436
+ const abortListener = () => resolveOnce({ event: "disconnect" });
3437
+ const cleanup = () => {
3438
+ emitter.off("disconnected", disconnectListener);
3439
+ emitter.off("unable_to_socket_mode_start", startFailListener);
3440
+ emitter.off("error", errorListener);
3441
+ abortSignal?.removeEventListener("abort", abortListener);
3442
+ };
3443
+ const resolveOnce = (value) => {
3444
+ cleanup();
3445
+ resolve(value);
3446
+ };
3447
+ emitter.on("disconnected", disconnectListener);
3448
+ emitter.on("unable_to_socket_mode_start", startFailListener);
3449
+ emitter.on("error", errorListener);
3450
+ abortSignal?.addEventListener("abort", abortListener, { once: true });
3451
+ });
3452
+ }
3453
+ /**
3454
+ * Detect non-recoverable Slack API / auth errors that should NOT be retried.
3455
+ * These indicate permanent credential problems (revoked bot, deactivated account, etc.)
3456
+ * and retrying will never succeed — continuing to retry blocks the entire gateway.
3457
+ */
3458
+ function isNonRecoverableSlackAuthError(error) {
3459
+ const msg = error instanceof Error ? error.message : typeof error === "string" ? error : "";
3460
+ return SLACK_AUTH_ERROR_RE.test(msg);
3461
+ }
3462
+ function formatUnknownError(error) {
3463
+ if (error instanceof Error) return error.message;
3464
+ if (typeof error === "string") return error;
3465
+ try {
3466
+ return JSON.stringify(error);
3467
+ } catch {
3468
+ return "unknown error";
3469
+ }
3470
+ }
3471
+ //#endregion
3472
+ //#region extensions/slack/src/monitor/external-arg-menu-store.ts
3473
+ const SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES = 18;
3474
+ const SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH = Math.ceil(SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES * 8 / 6);
3475
+ const SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH}}$`);
3476
+ const SLACK_EXTERNAL_ARG_MENU_TTL_MS = 600 * 1e3;
3477
+ const SLACK_EXTERNAL_ARG_MENU_PREFIX = "moldclaw_cmdarg_ext:";
3478
+ function pruneSlackExternalArgMenuStore(store, now) {
3479
+ for (const [token, entry] of store.entries()) if (entry.expiresAt <= now) store.delete(token);
3480
+ }
3481
+ function createSlackExternalArgMenuToken(store) {
3482
+ let token = "";
3483
+ do
3484
+ token = generateSecureToken(SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES);
3485
+ while (store.has(token));
3486
+ return token;
3487
+ }
3488
+ function createSlackExternalArgMenuStore() {
3489
+ const store = /* @__PURE__ */ new Map();
3490
+ return {
3491
+ create(params, now = Date.now()) {
3492
+ pruneSlackExternalArgMenuStore(store, now);
3493
+ const token = createSlackExternalArgMenuToken(store);
3494
+ store.set(token, {
3495
+ choices: params.choices,
3496
+ userId: params.userId,
3497
+ expiresAt: now + SLACK_EXTERNAL_ARG_MENU_TTL_MS
3498
+ });
3499
+ return token;
3500
+ },
3501
+ readToken(raw) {
3502
+ if (typeof raw !== "string" || !raw.startsWith("moldclaw_cmdarg_ext:")) return;
3503
+ const token = raw.slice(20).trim();
3504
+ return SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN.test(token) ? token : void 0;
3505
+ },
3506
+ get(token, now = Date.now()) {
3507
+ pruneSlackExternalArgMenuStore(store, now);
3508
+ return store.get(token);
3509
+ }
3510
+ };
3511
+ }
3512
+ //#endregion
3513
+ //#region extensions/slack/src/monitor/slash.ts
3514
+ const SLACK_COMMAND_ARG_ACTION_ID = "moldclaw_cmdarg";
3515
+ const SLACK_COMMAND_ARG_VALUE_PREFIX = "cmdarg";
3516
+ const SLACK_COMMAND_ARG_BUTTON_ROW_SIZE = 5;
3517
+ const SLACK_COMMAND_ARG_OVERFLOW_MIN = 3;
3518
+ const SLACK_COMMAND_ARG_OVERFLOW_MAX = 5;
3519
+ const SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX = 100;
3520
+ const SLACK_COMMAND_ARG_SELECT_OPTION_VALUE_MAX = 75;
3521
+ const SLACK_HEADER_TEXT_MAX = 150;
3522
+ let slashCommandsRuntimePromise = null;
3523
+ let slashDispatchRuntimePromise = null;
3524
+ let slashSkillCommandsRuntimePromise = null;
3525
+ function loadSlashCommandsRuntime() {
3526
+ slashCommandsRuntimePromise ??= import("./slash-commands.runtime-B7fsD8Be.js");
3527
+ return slashCommandsRuntimePromise;
3528
+ }
3529
+ function loadSlashDispatchRuntime() {
3530
+ slashDispatchRuntimePromise ??= import("./slash-dispatch.runtime-t0PAX4vQ.js");
3531
+ return slashDispatchRuntimePromise;
3532
+ }
3533
+ function loadSlashSkillCommandsRuntime() {
3534
+ slashSkillCommandsRuntimePromise ??= import("./slash-skill-commands.runtime-DIhPnEfR.js");
3535
+ return slashSkillCommandsRuntimePromise;
3536
+ }
3537
+ const slackExternalArgMenuStore = createSlackExternalArgMenuStore();
3538
+ function buildSlackArgMenuConfirm(params) {
3539
+ return {
3540
+ title: {
3541
+ type: "plain_text",
3542
+ text: "Confirm selection"
3543
+ },
3544
+ text: {
3545
+ type: "mrkdwn",
3546
+ text: `Run */${escapeSlackMrkdwn(params.command)}* with *${escapeSlackMrkdwn(params.arg)}* set to this value?`
3547
+ },
3548
+ confirm: {
3549
+ type: "plain_text",
3550
+ text: "Run command"
3551
+ },
3552
+ deny: {
3553
+ type: "plain_text",
3554
+ text: "Cancel"
3555
+ }
3556
+ };
3557
+ }
3558
+ function storeSlackExternalArgMenu(params) {
3559
+ return slackExternalArgMenuStore.create({
3560
+ choices: params.choices,
3561
+ userId: params.userId
3562
+ });
3563
+ }
3564
+ function readSlackExternalArgMenuToken(raw) {
3565
+ return slackExternalArgMenuStore.readToken(raw);
3566
+ }
3567
+ function encodeSlackCommandArgValue(parts) {
3568
+ return [
3569
+ SLACK_COMMAND_ARG_VALUE_PREFIX,
3570
+ encodeURIComponent(parts.command),
3571
+ encodeURIComponent(parts.arg),
3572
+ encodeURIComponent(parts.value),
3573
+ encodeURIComponent(parts.userId)
3574
+ ].join("|");
3575
+ }
3576
+ function parseSlackCommandArgValue(raw) {
3577
+ if (!raw) return null;
3578
+ const parts = raw.split("|");
3579
+ if (parts.length !== 5 || parts[0] !== SLACK_COMMAND_ARG_VALUE_PREFIX) return null;
3580
+ const [, command, arg, value, userId] = parts;
3581
+ if (!command || !arg || !value || !userId) return null;
3582
+ const decode = (text) => {
3583
+ try {
3584
+ return decodeURIComponent(text);
3585
+ } catch {
3586
+ return null;
3587
+ }
3588
+ };
3589
+ const decodedCommand = decode(command);
3590
+ const decodedArg = decode(arg);
3591
+ const decodedValue = decode(value);
3592
+ const decodedUserId = decode(userId);
3593
+ if (!decodedCommand || !decodedArg || !decodedValue || !decodedUserId) return null;
3594
+ return {
3595
+ command: decodedCommand,
3596
+ arg: decodedArg,
3597
+ value: decodedValue,
3598
+ userId: decodedUserId
3599
+ };
3600
+ }
3601
+ function buildSlackArgMenuOptions(choices) {
3602
+ return choices.map((choice) => ({
3603
+ text: {
3604
+ type: "plain_text",
3605
+ text: choice.label.slice(0, 75)
3606
+ },
3607
+ value: choice.value
3608
+ }));
3609
+ }
3610
+ function buildSlackCommandArgMenuBlocks(params) {
3611
+ const encodedChoices = params.choices.map((choice) => ({
3612
+ label: choice.label,
3613
+ value: encodeSlackCommandArgValue({
3614
+ command: params.command,
3615
+ arg: params.arg,
3616
+ value: choice.value,
3617
+ userId: params.userId
3618
+ })
3619
+ }));
3620
+ const canUseStaticSelect = encodedChoices.every((choice) => choice.value.length <= SLACK_COMMAND_ARG_SELECT_OPTION_VALUE_MAX);
3621
+ const canUseOverflow = canUseStaticSelect && encodedChoices.length >= SLACK_COMMAND_ARG_OVERFLOW_MIN && encodedChoices.length <= SLACK_COMMAND_ARG_OVERFLOW_MAX;
3622
+ const canUseExternalSelect = params.supportsExternalSelect && canUseStaticSelect && encodedChoices.length > SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX;
3623
+ const rows = canUseOverflow ? [{
3624
+ type: "actions",
3625
+ elements: [{
3626
+ type: "overflow",
3627
+ action_id: SLACK_COMMAND_ARG_ACTION_ID,
3628
+ confirm: buildSlackArgMenuConfirm({
3629
+ command: params.command,
3630
+ arg: params.arg
3631
+ }),
3632
+ options: buildSlackArgMenuOptions(encodedChoices)
3633
+ }]
3634
+ }] : canUseExternalSelect ? [{
3635
+ type: "actions",
3636
+ block_id: `${SLACK_EXTERNAL_ARG_MENU_PREFIX}${params.createExternalMenuToken(encodedChoices)}`,
3637
+ elements: [{
3638
+ type: "external_select",
3639
+ action_id: SLACK_COMMAND_ARG_ACTION_ID,
3640
+ confirm: buildSlackArgMenuConfirm({
3641
+ command: params.command,
3642
+ arg: params.arg
3643
+ }),
3644
+ min_query_length: 0,
3645
+ placeholder: {
3646
+ type: "plain_text",
3647
+ text: `Search ${params.arg}`
3648
+ }
3649
+ }]
3650
+ }] : encodedChoices.length <= SLACK_COMMAND_ARG_BUTTON_ROW_SIZE || !canUseStaticSelect ? chunkItems(encodedChoices, SLACK_COMMAND_ARG_BUTTON_ROW_SIZE).map((choices) => ({
3651
+ type: "actions",
3652
+ elements: choices.map((choice) => ({
3653
+ type: "button",
3654
+ action_id: SLACK_COMMAND_ARG_ACTION_ID,
3655
+ text: {
3656
+ type: "plain_text",
3657
+ text: choice.label
3658
+ },
3659
+ value: choice.value,
3660
+ confirm: buildSlackArgMenuConfirm({
3661
+ command: params.command,
3662
+ arg: params.arg
3663
+ })
3664
+ }))
3665
+ })) : chunkItems(encodedChoices, SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX).map((choices, index) => ({
3666
+ type: "actions",
3667
+ elements: [{
3668
+ type: "static_select",
3669
+ action_id: SLACK_COMMAND_ARG_ACTION_ID,
3670
+ confirm: buildSlackArgMenuConfirm({
3671
+ command: params.command,
3672
+ arg: params.arg
3673
+ }),
3674
+ placeholder: {
3675
+ type: "plain_text",
3676
+ text: index === 0 ? `Choose ${params.arg}` : `Choose ${params.arg} (${index + 1})`
3677
+ },
3678
+ options: buildSlackArgMenuOptions(choices)
3679
+ }]
3680
+ }));
3681
+ const headerText = truncateSlackText(`/${params.command}: choose ${params.arg}`, SLACK_HEADER_TEXT_MAX);
3682
+ const sectionText = truncateSlackText(params.title, 3e3);
3683
+ const contextText = truncateSlackText(`Select one option to continue /${params.command} (${params.arg})`, 3e3);
3684
+ return [
3685
+ {
3686
+ type: "header",
3687
+ text: {
3688
+ type: "plain_text",
3689
+ text: headerText
3690
+ }
3691
+ },
3692
+ {
3693
+ type: "section",
3694
+ text: {
3695
+ type: "mrkdwn",
3696
+ text: sectionText
3697
+ }
3698
+ },
3699
+ {
3700
+ type: "context",
3701
+ elements: [{
3702
+ type: "mrkdwn",
3703
+ text: contextText
3704
+ }]
3705
+ },
3706
+ ...rows
3707
+ ];
3708
+ }
3709
+ async function registerSlackMonitorSlashCommands(params) {
3710
+ const { ctx, account } = params;
3711
+ const cfg = ctx.cfg;
3712
+ const runtime = ctx.runtime;
3713
+ const supportsInteractiveArgMenus = typeof ctx.app.action === "function";
3714
+ let supportsExternalArgMenus = typeof ctx.app.options === "function";
3715
+ const slashCommand = resolveSlackSlashCommandConfig(ctx.slashCommand ?? account.config.slashCommand);
3716
+ const handleSlashCommand = async (p) => {
3717
+ const { command, ack, respond, body, prompt, commandArgs, commandDefinition } = p;
3718
+ try {
3719
+ if (ctx.shouldDropMismatchedSlackEvent?.(body)) {
3720
+ await ack();
3721
+ runtime.log?.(`slack: drop slash command from user=${command.user_id ?? "unknown"} channel=${command.channel_id ?? "unknown"} (mismatched app/team)`);
3722
+ return;
3723
+ }
3724
+ if (!prompt.trim()) {
3725
+ await ack({
3726
+ text: "Message required.",
3727
+ response_type: "ephemeral"
3728
+ });
3729
+ return;
3730
+ }
3731
+ await ack();
3732
+ if (ctx.botUserId && command.user_id === ctx.botUserId) return;
3733
+ const channelInfo = await ctx.resolveChannelName(command.channel_id);
3734
+ const channelType = normalizeSlackChannelType(channelInfo?.type ?? (command.channel_name === "directmessage" ? "im" : void 0), command.channel_id);
3735
+ const isDirectMessage = channelType === "im";
3736
+ const isGroupDm = channelType === "mpim";
3737
+ const isRoom = channelType === "channel" || channelType === "group";
3738
+ const isRoomish = isRoom || isGroupDm;
3739
+ if (!ctx.isChannelAllowed({
3740
+ channelId: command.channel_id,
3741
+ channelName: channelInfo?.name,
3742
+ channelType
3743
+ })) {
3744
+ await respond({
3745
+ text: "This channel is not allowed.",
3746
+ response_type: "ephemeral"
3747
+ });
3748
+ return;
3749
+ }
3750
+ const { allowFromLower: effectiveAllowFromLower } = await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: isDirectMessage });
3751
+ let commandAuthorized = false;
3752
+ let channelConfig = null;
3753
+ if (isDirectMessage) {
3754
+ if (!await authorizeSlackDirectMessage({
3755
+ ctx,
3756
+ accountId: ctx.accountId,
3757
+ senderId: command.user_id,
3758
+ allowFromLower: effectiveAllowFromLower,
3759
+ resolveSenderName: ctx.resolveUserName,
3760
+ sendPairingReply: async (text) => {
3761
+ await respond({
3762
+ text,
3763
+ response_type: "ephemeral"
3764
+ });
3765
+ },
3766
+ onDisabled: async () => {
3767
+ await respond({
3768
+ text: "Slack DMs are disabled.",
3769
+ response_type: "ephemeral"
3770
+ });
3771
+ },
3772
+ onUnauthorized: async ({ allowMatchMeta }) => {
3773
+ logVerbose(`slack: blocked slash sender ${command.user_id} (dmPolicy=${ctx.dmPolicy}, ${allowMatchMeta})`);
3774
+ await respond({
3775
+ text: "You are not authorized to use this command.",
3776
+ response_type: "ephemeral"
3777
+ });
3778
+ },
3779
+ log: logVerbose
3780
+ })) return;
3781
+ }
3782
+ if (isRoom) {
3783
+ channelConfig = resolveSlackChannelConfig({
3784
+ channelId: command.channel_id,
3785
+ channelName: channelInfo?.name,
3786
+ channels: ctx.channelsConfig,
3787
+ channelKeys: ctx.channelsConfigKeys,
3788
+ defaultRequireMention: ctx.defaultRequireMention,
3789
+ allowNameMatching: ctx.allowNameMatching
3790
+ });
3791
+ if (ctx.useAccessGroups) {
3792
+ const channelAllowlistConfigured = (ctx.channelsConfigKeys?.length ?? 0) > 0;
3793
+ const channelAllowed = channelConfig?.allowed !== false;
3794
+ if (!isSlackChannelAllowedByPolicy({
3795
+ groupPolicy: ctx.groupPolicy,
3796
+ channelAllowlistConfigured,
3797
+ channelAllowed
3798
+ })) {
3799
+ await respond({
3800
+ text: "This channel is not allowed.",
3801
+ response_type: "ephemeral"
3802
+ });
3803
+ return;
3804
+ }
3805
+ const hasExplicitConfig = Boolean(channelConfig?.matchSource);
3806
+ if (!channelAllowed && (ctx.groupPolicy !== "open" || hasExplicitConfig)) {
3807
+ await respond({
3808
+ text: "This channel is not allowed.",
3809
+ response_type: "ephemeral"
3810
+ });
3811
+ return;
3812
+ }
3813
+ }
3814
+ }
3815
+ const senderName = (await ctx.resolveUserName(command.user_id))?.name ?? command.user_name ?? command.user_id;
3816
+ const channelUsersAllowlistConfigured = isRoom && Array.isArray(channelConfig?.users) && channelConfig.users.length > 0;
3817
+ const channelUserAllowed = channelUsersAllowlistConfigured ? resolveSlackUserAllowed({
3818
+ allowList: channelConfig?.users,
3819
+ userId: command.user_id,
3820
+ userName: senderName,
3821
+ allowNameMatching: ctx.allowNameMatching
3822
+ }) : false;
3823
+ if (channelUsersAllowlistConfigured && !channelUserAllowed) {
3824
+ await respond({
3825
+ text: "You are not authorized to use this command here.",
3826
+ response_type: "ephemeral"
3827
+ });
3828
+ return;
3829
+ }
3830
+ const ownerAllowed = resolveSlackAllowListMatch({
3831
+ allowList: effectiveAllowFromLower,
3832
+ id: command.user_id,
3833
+ name: senderName,
3834
+ allowNameMatching: ctx.allowNameMatching
3835
+ }).allowed;
3836
+ commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
3837
+ useAccessGroups: ctx.useAccessGroups,
3838
+ authorizers: [{
3839
+ configured: effectiveAllowFromLower.length > 0,
3840
+ allowed: ownerAllowed
3841
+ }],
3842
+ modeWhenAccessGroupsOff: "configured"
3843
+ });
3844
+ if (isRoomish) {
3845
+ commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
3846
+ useAccessGroups: ctx.useAccessGroups,
3847
+ authorizers: [{
3848
+ configured: effectiveAllowFromLower.length > 0,
3849
+ allowed: ownerAllowed
3850
+ }, {
3851
+ configured: channelUsersAllowlistConfigured,
3852
+ allowed: channelUserAllowed
3853
+ }],
3854
+ modeWhenAccessGroupsOff: "configured"
3855
+ });
3856
+ if (ctx.useAccessGroups && !commandAuthorized) {
3857
+ await respond({
3858
+ text: "You are not authorized to use this command.",
3859
+ response_type: "ephemeral"
3860
+ });
3861
+ return;
3862
+ }
3863
+ }
3864
+ if (commandDefinition && supportsInteractiveArgMenus) {
3865
+ const { resolveCommandArgMenu } = await loadSlashCommandsRuntime();
3866
+ const menu = resolveCommandArgMenu({
3867
+ command: commandDefinition,
3868
+ args: commandArgs,
3869
+ cfg
3870
+ });
3871
+ if (menu) {
3872
+ const commandLabel = commandDefinition.nativeName ?? commandDefinition.key;
3873
+ const title = menu.title ?? `Choose ${menu.arg.description || menu.arg.name} for /${commandLabel}.`;
3874
+ await respond({
3875
+ text: title,
3876
+ blocks: buildSlackCommandArgMenuBlocks({
3877
+ title,
3878
+ command: commandLabel,
3879
+ arg: menu.arg.name,
3880
+ choices: menu.choices,
3881
+ userId: command.user_id,
3882
+ supportsExternalSelect: supportsExternalArgMenus,
3883
+ createExternalMenuToken: (choices) => storeSlackExternalArgMenu({
3884
+ choices,
3885
+ userId: command.user_id
3886
+ })
3887
+ }),
3888
+ response_type: "ephemeral"
3889
+ });
3890
+ return;
3891
+ }
3892
+ }
3893
+ const channelName = channelInfo?.name;
3894
+ const roomLabel = channelName ? `#${channelName}` : `#${command.channel_id}`;
3895
+ const { createReplyPrefixOptions, deliverSlackSlashReplies, dispatchReplyWithDispatcher, finalizeInboundContext, recordInboundSessionMetaSafe, resolveAgentRoute, resolveChunkMode, resolveConversationLabel, resolveMarkdownTableMode } = await loadSlashDispatchRuntime();
3896
+ const route = resolveAgentRoute({
3897
+ cfg,
3898
+ channel: "slack",
3899
+ accountId: account.accountId,
3900
+ teamId: ctx.teamId || void 0,
3901
+ peer: {
3902
+ kind: isDirectMessage ? "direct" : isRoom ? "channel" : "group",
3903
+ id: isDirectMessage ? command.user_id : command.channel_id
3904
+ }
3905
+ });
3906
+ const { untrustedChannelMetadata, groupSystemPrompt } = resolveSlackRoomContextHints({
3907
+ isRoomish,
3908
+ channelInfo,
3909
+ channelConfig
3910
+ });
3911
+ const { sessionKey, commandTargetSessionKey } = resolveNativeCommandSessionTargets({
3912
+ agentId: route.agentId,
3913
+ sessionPrefix: slashCommand.sessionPrefix,
3914
+ userId: command.user_id,
3915
+ targetSessionKey: route.sessionKey,
3916
+ lowercaseSessionKey: true
3917
+ });
3918
+ const ctxPayload = finalizeInboundContext({
3919
+ Body: prompt,
3920
+ BodyForAgent: prompt,
3921
+ RawBody: prompt,
3922
+ CommandBody: prompt,
3923
+ CommandArgs: commandArgs,
3924
+ From: isDirectMessage ? `slack:${command.user_id}` : isRoom ? `slack:channel:${command.channel_id}` : `slack:group:${command.channel_id}`,
3925
+ To: `slash:${command.user_id}`,
3926
+ ChatType: isDirectMessage ? "direct" : "channel",
3927
+ ConversationLabel: resolveConversationLabel({
3928
+ ChatType: isDirectMessage ? "direct" : "channel",
3929
+ SenderName: senderName,
3930
+ GroupSubject: isRoomish ? roomLabel : void 0,
3931
+ From: isDirectMessage ? `slack:${command.user_id}` : isRoom ? `slack:channel:${command.channel_id}` : `slack:group:${command.channel_id}`
3932
+ }) ?? (isDirectMessage ? senderName : roomLabel),
3933
+ GroupSubject: isRoomish ? roomLabel : void 0,
3934
+ GroupSystemPrompt: isRoomish ? groupSystemPrompt : void 0,
3935
+ UntrustedContext: untrustedChannelMetadata ? [untrustedChannelMetadata] : void 0,
3936
+ SenderName: senderName,
3937
+ SenderId: command.user_id,
3938
+ Provider: "slack",
3939
+ Surface: "slack",
3940
+ WasMentioned: true,
3941
+ MessageSid: command.trigger_id,
3942
+ Timestamp: Date.now(),
3943
+ SessionKey: sessionKey,
3944
+ CommandTargetSessionKey: commandTargetSessionKey,
3945
+ AccountId: route.accountId,
3946
+ CommandSource: "native",
3947
+ CommandAuthorized: commandAuthorized,
3948
+ OriginatingChannel: "slack",
3949
+ OriginatingTo: `user:${command.user_id}`
3950
+ });
3951
+ await recordInboundSessionMetaSafe({
3952
+ cfg,
3953
+ agentId: route.agentId,
3954
+ sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
3955
+ ctx: ctxPayload,
3956
+ onError: (err) => runtime.error?.(danger(`slack slash: failed updating session meta: ${String(err)}`))
3957
+ });
3958
+ const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
3959
+ cfg,
3960
+ agentId: route.agentId,
3961
+ channel: "slack",
3962
+ accountId: route.accountId
3963
+ });
3964
+ const deliverSlashPayloads = async (replies) => {
3965
+ await deliverSlackSlashReplies({
3966
+ replies,
3967
+ respond,
3968
+ ephemeral: slashCommand.ephemeral,
3969
+ textLimit: ctx.textLimit,
3970
+ chunkMode: resolveChunkMode(cfg, "slack", route.accountId),
3971
+ tableMode: resolveMarkdownTableMode({
3972
+ cfg,
3973
+ channel: "slack",
3974
+ accountId: route.accountId
3975
+ })
3976
+ });
3977
+ };
3978
+ const { counts } = await dispatchReplyWithDispatcher({
3979
+ ctx: ctxPayload,
3980
+ cfg,
3981
+ dispatcherOptions: {
3982
+ ...prefixOptions,
3983
+ deliver: async (payload) => deliverSlashPayloads([payload]),
3984
+ onError: (err, info) => {
3985
+ runtime.error?.(danger(`slack slash ${info.kind} reply failed: ${String(err)}`));
3986
+ }
3987
+ },
3988
+ replyOptions: {
3989
+ skillFilter: channelConfig?.skills,
3990
+ onModelSelected
3991
+ }
3992
+ });
3993
+ if (counts.final + counts.tool + counts.block === 0) await deliverSlashPayloads([]);
3994
+ } catch (err) {
3995
+ runtime.error?.(danger(`slack slash handler failed: ${String(err)}`));
3996
+ await respond({
3997
+ text: "Sorry, something went wrong handling that command.",
3998
+ response_type: "ephemeral"
3999
+ });
4000
+ }
4001
+ };
4002
+ const nativeEnabled = resolveNativeCommandsEnabled({
4003
+ providerId: "slack",
4004
+ providerSetting: account.config.commands?.native,
4005
+ globalSetting: cfg.commands?.native
4006
+ });
4007
+ const nativeSkillsEnabled = resolveNativeSkillsEnabled({
4008
+ providerId: "slack",
4009
+ providerSetting: account.config.commands?.nativeSkills,
4010
+ globalSetting: cfg.commands?.nativeSkills
4011
+ });
4012
+ let nativeCommands = [];
4013
+ let slashCommandsRuntime = null;
4014
+ if (nativeEnabled) {
4015
+ slashCommandsRuntime = await loadSlashCommandsRuntime();
4016
+ const skillCommands = nativeSkillsEnabled ? (await loadSlashSkillCommandsRuntime()).listSkillCommandsForAgents({ cfg }) : [];
4017
+ nativeCommands = slashCommandsRuntime.listNativeCommandSpecsForConfig(cfg, {
4018
+ skillCommands,
4019
+ provider: "slack"
4020
+ });
4021
+ }
4022
+ if (nativeCommands.length > 0) {
4023
+ if (!slashCommandsRuntime) throw new Error("Missing commands runtime for native Slack commands.");
4024
+ for (const command of nativeCommands) ctx.app.command(`/${command.name}`, async ({ command: cmd, ack, respond, body }) => {
4025
+ const commandDefinition = slashCommandsRuntime.findCommandByNativeName(command.name, "slack");
4026
+ const rawText = cmd.text?.trim() ?? "";
4027
+ const commandArgs = commandDefinition ? slashCommandsRuntime.parseCommandArgs(commandDefinition, rawText) : rawText ? { raw: rawText } : void 0;
4028
+ await handleSlashCommand({
4029
+ command: cmd,
4030
+ ack,
4031
+ respond,
4032
+ body,
4033
+ prompt: commandDefinition ? slashCommandsRuntime.buildCommandTextFromArgs(commandDefinition, commandArgs) : rawText ? `/${command.name} ${rawText}` : `/${command.name}`,
4034
+ commandArgs,
4035
+ commandDefinition: commandDefinition ?? void 0
4036
+ });
4037
+ });
4038
+ } else if (slashCommand.enabled) ctx.app.command(buildSlackSlashCommandMatcher(slashCommand.name), async ({ command, ack, respond, body }) => {
4039
+ await handleSlashCommand({
4040
+ command,
4041
+ ack,
4042
+ respond,
4043
+ body,
4044
+ prompt: command.text?.trim() ?? ""
4045
+ });
4046
+ });
4047
+ else logVerbose("slack: slash commands disabled");
4048
+ if (nativeCommands.length === 0 || !supportsInteractiveArgMenus) return;
4049
+ const registerArgOptions = () => {
4050
+ const appWithOptions = ctx.app;
4051
+ if (typeof appWithOptions.options !== "function") return;
4052
+ appWithOptions.options(SLACK_COMMAND_ARG_ACTION_ID, async ({ ack, body }) => {
4053
+ if (ctx.shouldDropMismatchedSlackEvent?.(body)) {
4054
+ await ack({ options: [] });
4055
+ runtime.log?.("slack: drop slash arg options payload (mismatched app/team)");
4056
+ return;
4057
+ }
4058
+ const typedBody = body;
4059
+ const token = readSlackExternalArgMenuToken(typedBody.actions?.[0]?.block_id ?? typedBody.block_id);
4060
+ if (!token) {
4061
+ await ack({ options: [] });
4062
+ return;
4063
+ }
4064
+ const entry = slackExternalArgMenuStore.get(token);
4065
+ if (!entry) {
4066
+ await ack({ options: [] });
4067
+ return;
4068
+ }
4069
+ const requesterUserId = typedBody.user?.id?.trim();
4070
+ if (!requesterUserId || requesterUserId !== entry.userId) {
4071
+ await ack({ options: [] });
4072
+ return;
4073
+ }
4074
+ const query = typedBody.value?.trim().toLowerCase() ?? "";
4075
+ await ack({ options: entry.choices.filter((choice) => !query || choice.label.toLowerCase().includes(query)).slice(0, SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX).map((choice) => ({
4076
+ text: {
4077
+ type: "plain_text",
4078
+ text: choice.label.slice(0, 75)
4079
+ },
4080
+ value: choice.value
4081
+ })) });
4082
+ });
4083
+ };
4084
+ try {
4085
+ registerArgOptions();
4086
+ } catch (err) {
4087
+ supportsExternalArgMenus = false;
4088
+ logVerbose(`slack: external arg-menu registration failed, falling back to static menus: ${String(err)}`);
4089
+ }
4090
+ const registerArgAction = (actionId) => {
4091
+ ctx.app.action(actionId, async (args) => {
4092
+ const { ack, body, respond } = args;
4093
+ const action = args.action;
4094
+ await ack();
4095
+ if (ctx.shouldDropMismatchedSlackEvent?.(body)) {
4096
+ runtime.log?.("slack: drop slash arg action payload (mismatched app/team)");
4097
+ return;
4098
+ }
4099
+ const respondFn = respond ?? (async (payload) => {
4100
+ if (!body.channel?.id || !body.user?.id) return;
4101
+ await ctx.app.client.chat.postEphemeral({
4102
+ token: ctx.botToken,
4103
+ channel: body.channel.id,
4104
+ user: body.user.id,
4105
+ text: payload.text,
4106
+ blocks: payload.blocks
4107
+ });
4108
+ });
4109
+ const parsed = parseSlackCommandArgValue(action?.value ?? action?.selected_option?.value);
4110
+ if (!parsed) {
4111
+ await respondFn({
4112
+ text: "Sorry, that button is no longer valid.",
4113
+ response_type: "ephemeral"
4114
+ });
4115
+ return;
4116
+ }
4117
+ if (body.user?.id && parsed.userId !== body.user.id) {
4118
+ await respondFn({
4119
+ text: "That menu is for another user.",
4120
+ response_type: "ephemeral"
4121
+ });
4122
+ return;
4123
+ }
4124
+ const { buildCommandTextFromArgs, findCommandByNativeName } = await loadSlashCommandsRuntime();
4125
+ const commandDefinition = findCommandByNativeName(parsed.command, "slack");
4126
+ const commandArgs = { values: { [parsed.arg]: parsed.value } };
4127
+ const prompt = commandDefinition ? buildCommandTextFromArgs(commandDefinition, commandArgs) : `/${parsed.command} ${parsed.value}`;
4128
+ const user = body.user;
4129
+ const userName = user && "name" in user && user.name ? user.name : user && "username" in user && user.username ? user.username : user?.id ?? "";
4130
+ const triggerId = "trigger_id" in body ? body.trigger_id : void 0;
4131
+ await handleSlashCommand({
4132
+ command: {
4133
+ user_id: user?.id ?? "",
4134
+ user_name: userName,
4135
+ channel_id: body.channel?.id ?? "",
4136
+ channel_name: body.channel?.name ?? body.channel?.id ?? "",
4137
+ trigger_id: triggerId
4138
+ },
4139
+ ack: async () => {},
4140
+ respond: respondFn,
4141
+ body,
4142
+ prompt,
4143
+ commandArgs,
4144
+ commandDefinition: commandDefinition ?? void 0
4145
+ });
4146
+ });
4147
+ };
4148
+ registerArgAction(SLACK_COMMAND_ARG_ACTION_ID);
4149
+ }
4150
+ //#endregion
4151
+ //#region extensions/slack/src/monitor/provider.ts
4152
+ function isConstructorFunction(value) {
4153
+ return typeof value === "function";
4154
+ }
4155
+ function resolveSlackBoltModule(value) {
4156
+ if (!value || typeof value !== "object") return null;
4157
+ const app = Reflect.get(value, "App");
4158
+ const httpReceiver = Reflect.get(value, "HTTPReceiver");
4159
+ if (!isConstructorFunction(app) || !isConstructorFunction(httpReceiver)) return null;
4160
+ return {
4161
+ App: app,
4162
+ HTTPReceiver: httpReceiver
4163
+ };
4164
+ }
4165
+ function resolveSlackBoltInterop(params) {
4166
+ const { defaultImport, namespaceImport } = params;
4167
+ const nestedDefault = defaultImport && typeof defaultImport === "object" ? Reflect.get(defaultImport, "default") : void 0;
4168
+ const namespaceDefault = namespaceImport && typeof namespaceImport === "object" ? Reflect.get(namespaceImport, "default") : void 0;
4169
+ const namespaceReceiver = namespaceImport && typeof namespaceImport === "object" ? Reflect.get(namespaceImport, "HTTPReceiver") : void 0;
4170
+ const directModule = resolveSlackBoltModule(defaultImport) ?? resolveSlackBoltModule(nestedDefault) ?? resolveSlackBoltModule(namespaceDefault) ?? resolveSlackBoltModule(namespaceImport);
4171
+ if (directModule) return directModule;
4172
+ if (isConstructorFunction(defaultImport) && isConstructorFunction(namespaceReceiver)) return {
4173
+ App: defaultImport,
4174
+ HTTPReceiver: namespaceReceiver
4175
+ };
4176
+ throw new TypeError("Unable to resolve @slack/bolt App/HTTPReceiver exports");
4177
+ }
4178
+ const { App, HTTPReceiver } = resolveSlackBoltInterop({
4179
+ defaultImport: SlackBolt,
4180
+ namespaceImport: SlackBoltNamespace
4181
+ });
4182
+ const SLACK_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
4183
+ const SLACK_WEBHOOK_BODY_TIMEOUT_MS = 3e4;
4184
+ function parseApiAppIdFromAppToken(raw) {
4185
+ const token = raw?.trim();
4186
+ if (!token) return;
4187
+ return /^xapp-\d-([a-z0-9]+)-/i.exec(token)?.[1]?.toUpperCase();
4188
+ }
4189
+ function publishSlackConnectedStatus(setStatus) {
4190
+ if (!setStatus) return;
4191
+ setStatus({
4192
+ ...createConnectedChannelStatusPatch(Date.now()),
4193
+ lastError: null
4194
+ });
4195
+ }
4196
+ function publishSlackDisconnectedStatus(setStatus, error) {
4197
+ if (!setStatus) return;
4198
+ const at = Date.now();
4199
+ const message = error ? formatUnknownError(error) : void 0;
4200
+ setStatus({
4201
+ connected: false,
4202
+ lastDisconnect: message ? {
4203
+ at,
4204
+ error: message
4205
+ } : { at },
4206
+ lastError: message ?? null
4207
+ });
4208
+ }
4209
+ async function monitorSlackProvider(opts = {}) {
4210
+ const cfg = opts.config ?? loadConfig();
4211
+ const runtime = opts.runtime ?? createNonExitingRuntime();
4212
+ let account = resolveSlackAccount({
4213
+ cfg,
4214
+ accountId: opts.accountId
4215
+ });
4216
+ if (!account.enabled) {
4217
+ runtime.log?.(`[${account.accountId}] slack account disabled; monitor startup skipped`);
4218
+ if (opts.abortSignal?.aborted) return;
4219
+ await new Promise((resolve) => {
4220
+ opts.abortSignal?.addEventListener("abort", () => resolve(), { once: true });
4221
+ });
4222
+ return;
4223
+ }
4224
+ const historyLimit = Math.max(0, account.config.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? 50);
4225
+ const sessionCfg = cfg.session;
4226
+ const sessionScope = sessionCfg?.scope ?? "per-sender";
4227
+ const mainKey = normalizeMainKey(sessionCfg?.mainKey);
4228
+ const slackMode = opts.mode ?? account.config.mode ?? "socket";
4229
+ const slackWebhookPath = normalizeSlackWebhookPath(account.config.webhookPath);
4230
+ const signingSecret = normalizeResolvedSecretInputString({
4231
+ value: account.config.signingSecret,
4232
+ path: `channels.slack.accounts.${account.accountId}.signingSecret`
4233
+ });
4234
+ const botToken = resolveSlackBotToken(opts.botToken ?? account.botToken);
4235
+ const appToken = resolveSlackAppToken(opts.appToken ?? account.appToken);
4236
+ if (!botToken || slackMode !== "http" && !appToken) {
4237
+ const missing = slackMode === "http" ? `Slack bot token missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken or SLACK_BOT_TOKEN for default).` : `Slack bot + app tokens missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken/appToken or SLACK_BOT_TOKEN/SLACK_APP_TOKEN for default).`;
4238
+ throw new Error(missing);
4239
+ }
4240
+ if (slackMode === "http" && !signingSecret) throw new Error(`Slack signing secret missing for account "${account.accountId}" (set channels.slack.signingSecret or channels.slack.accounts.${account.accountId}.signingSecret).`);
4241
+ const slackCfg = account.config;
4242
+ const dmConfig = slackCfg.dm;
4243
+ const dmEnabled = dmConfig?.enabled ?? true;
4244
+ const dmPolicy = slackCfg.dmPolicy ?? dmConfig?.policy ?? "pairing";
4245
+ let allowFrom = slackCfg.allowFrom ?? dmConfig?.allowFrom;
4246
+ const groupDmEnabled = dmConfig?.groupEnabled ?? false;
4247
+ const groupDmChannels = dmConfig?.groupChannels;
4248
+ let channelsConfig = slackCfg.channels;
4249
+ const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
4250
+ const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy({
4251
+ providerConfigPresent: cfg.channels?.slack !== void 0,
4252
+ groupPolicy: slackCfg.groupPolicy,
4253
+ defaultGroupPolicy
4254
+ });
4255
+ warnMissingProviderGroupPolicyFallbackOnce({
4256
+ providerMissingFallbackApplied,
4257
+ providerKey: "slack",
4258
+ accountId: account.accountId,
4259
+ log: (message) => runtime.log?.(warn(message))
4260
+ });
4261
+ const resolveToken = account.userToken || botToken;
4262
+ const useAccessGroups = cfg.commands?.useAccessGroups !== false;
4263
+ const reactionMode = slackCfg.reactionNotifications ?? "own";
4264
+ const reactionAllowlist = slackCfg.reactionAllowlist ?? [];
4265
+ const replyToMode = slackCfg.replyToMode ?? "off";
4266
+ const threadHistoryScope = slackCfg.thread?.historyScope ?? "thread";
4267
+ const threadInheritParent = slackCfg.thread?.inheritParent ?? false;
4268
+ const slashCommand = resolveSlackSlashCommandConfig(opts.slashCommand ?? slackCfg.slashCommand);
4269
+ const textLimit = resolveTextChunkLimit(cfg, "slack", account.accountId);
4270
+ const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
4271
+ const typingReaction = slackCfg.typingReaction?.trim() ?? "";
4272
+ const mediaMaxBytes = (opts.mediaMaxMb ?? slackCfg.mediaMaxMb ?? 20) * 1024 * 1024;
4273
+ const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
4274
+ const receiver = slackMode === "http" ? new HTTPReceiver({
4275
+ signingSecret: signingSecret ?? "",
4276
+ endpoints: slackWebhookPath
4277
+ }) : null;
4278
+ const clientOptions = resolveSlackWebClientOptions();
4279
+ const app = new App(slackMode === "socket" ? {
4280
+ token: botToken,
4281
+ appToken,
4282
+ socketMode: true,
4283
+ clientOptions
4284
+ } : {
4285
+ token: botToken,
4286
+ receiver: receiver ?? void 0,
4287
+ clientOptions
4288
+ });
4289
+ const slackHttpHandler = slackMode === "http" && receiver ? async (req, res) => {
4290
+ const guard = installRequestBodyLimitGuard(req, res, {
4291
+ maxBytes: SLACK_WEBHOOK_MAX_BODY_BYTES,
4292
+ timeoutMs: SLACK_WEBHOOK_BODY_TIMEOUT_MS,
4293
+ responseFormat: "text"
4294
+ });
4295
+ if (guard.isTripped()) return;
4296
+ try {
4297
+ await Promise.resolve(receiver.requestListener(req, res));
4298
+ } catch (err) {
4299
+ if (!guard.isTripped()) throw err;
4300
+ } finally {
4301
+ guard.dispose();
4302
+ }
4303
+ } : null;
4304
+ let unregisterHttpHandler = null;
4305
+ let botUserId = "";
4306
+ let teamId = "";
4307
+ let apiAppId = "";
4308
+ const expectedApiAppIdFromAppToken = parseApiAppIdFromAppToken(appToken);
4309
+ try {
4310
+ const auth = await app.client.auth.test({ token: botToken });
4311
+ botUserId = auth.user_id ?? "";
4312
+ teamId = auth.team_id ?? "";
4313
+ apiAppId = auth.api_app_id ?? "";
4314
+ } catch {}
4315
+ if (apiAppId && expectedApiAppIdFromAppToken && apiAppId !== expectedApiAppIdFromAppToken) runtime.error?.(`slack token mismatch: bot token api_app_id=${apiAppId} but app token looks like api_app_id=${expectedApiAppIdFromAppToken}`);
4316
+ const ctx = createSlackMonitorContext({
4317
+ cfg,
4318
+ accountId: account.accountId,
4319
+ botToken,
4320
+ app,
4321
+ runtime,
4322
+ botUserId,
4323
+ teamId,
4324
+ apiAppId,
4325
+ historyLimit,
4326
+ sessionScope,
4327
+ mainKey,
4328
+ dmEnabled,
4329
+ dmPolicy,
4330
+ allowFrom,
4331
+ allowNameMatching: isDangerousNameMatchingEnabled(slackCfg),
4332
+ groupDmEnabled,
4333
+ groupDmChannels,
4334
+ defaultRequireMention: slackCfg.requireMention,
4335
+ channelsConfig,
4336
+ groupPolicy,
4337
+ useAccessGroups,
4338
+ reactionMode,
4339
+ reactionAllowlist,
4340
+ replyToMode,
4341
+ threadHistoryScope,
4342
+ threadInheritParent,
4343
+ slashCommand,
4344
+ textLimit,
4345
+ ackReactionScope,
4346
+ typingReaction,
4347
+ mediaMaxBytes,
4348
+ removeAckAfterReply
4349
+ });
4350
+ const trackEvent = opts.setStatus ? () => {
4351
+ opts.setStatus({
4352
+ lastEventAt: Date.now(),
4353
+ lastInboundAt: Date.now()
4354
+ });
4355
+ } : void 0;
4356
+ registerSlackMonitorEvents({
4357
+ ctx,
4358
+ account,
4359
+ handleSlackMessage: createSlackMessageHandler({
4360
+ ctx,
4361
+ account,
4362
+ trackEvent
4363
+ }),
4364
+ trackEvent
4365
+ });
4366
+ await registerSlackMonitorSlashCommands({
4367
+ ctx,
4368
+ account
4369
+ });
4370
+ if (slackMode === "http" && slackHttpHandler) unregisterHttpHandler = registerSlackHttpHandler({
4371
+ path: slackWebhookPath,
4372
+ handler: slackHttpHandler,
4373
+ log: runtime.log,
4374
+ accountId: account.accountId
4375
+ });
4376
+ if (resolveToken) (async () => {
4377
+ if (opts.abortSignal?.aborted) return;
4378
+ if (channelsConfig && Object.keys(channelsConfig).length > 0) try {
4379
+ const entries = Object.keys(channelsConfig).filter((key) => key !== "*");
4380
+ if (entries.length > 0) {
4381
+ const resolved = await resolveSlackChannelAllowlist({
4382
+ token: resolveToken,
4383
+ entries
4384
+ });
4385
+ const nextChannels = { ...channelsConfig };
4386
+ const mapping = [];
4387
+ const unresolved = [];
4388
+ for (const entry of resolved) {
4389
+ const source = channelsConfig?.[entry.input];
4390
+ if (!source) continue;
4391
+ if (!entry.resolved || !entry.id) {
4392
+ unresolved.push(entry.input);
4393
+ continue;
4394
+ }
4395
+ mapping.push(`${entry.input}→${entry.id}${entry.archived ? " (archived)" : ""}`);
4396
+ const existing = nextChannels[entry.id] ?? {};
4397
+ nextChannels[entry.id] = {
4398
+ ...source,
4399
+ ...existing
4400
+ };
4401
+ }
4402
+ channelsConfig = nextChannels;
4403
+ ctx.channelsConfig = nextChannels;
4404
+ summarizeMapping("slack channels", mapping, unresolved, runtime);
4405
+ }
4406
+ } catch (err) {
4407
+ runtime.log?.(`slack channel resolve failed; using config entries. ${String(err)}`);
4408
+ }
4409
+ const allowEntries = normalizeStringEntries(allowFrom).filter((entry) => entry !== "*");
4410
+ if (allowEntries.length > 0) try {
4411
+ const { mapping, unresolved, additions } = buildAllowlistResolutionSummary(await resolveSlackUserAllowlist({
4412
+ token: resolveToken,
4413
+ entries: allowEntries
4414
+ }), { formatResolved: (entry) => {
4415
+ const note = entry.note ? ` (${entry.note})` : "";
4416
+ return `${entry.input}→${entry.id}${note}`;
4417
+ } });
4418
+ allowFrom = mergeAllowlist({
4419
+ existing: allowFrom,
4420
+ additions
4421
+ });
4422
+ ctx.allowFrom = normalizeAllowList(allowFrom);
4423
+ summarizeMapping("slack users", mapping, unresolved, runtime);
4424
+ } catch (err) {
4425
+ runtime.log?.(`slack user resolve failed; using config entries. ${String(err)}`);
4426
+ }
4427
+ if (channelsConfig && Object.keys(channelsConfig).length > 0) {
4428
+ const userEntries = /* @__PURE__ */ new Set();
4429
+ for (const channel of Object.values(channelsConfig)) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
4430
+ if (userEntries.size > 0) try {
4431
+ const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(await resolveSlackUserAllowlist({
4432
+ token: resolveToken,
4433
+ entries: Array.from(userEntries)
4434
+ }));
4435
+ const nextChannels = patchAllowlistUsersInConfigEntries({
4436
+ entries: channelsConfig,
4437
+ resolvedMap
4438
+ });
4439
+ channelsConfig = nextChannels;
4440
+ ctx.channelsConfig = nextChannels;
4441
+ summarizeMapping("slack channel users", mapping, unresolved, runtime);
4442
+ } catch (err) {
4443
+ runtime.log?.(`slack channel user resolve failed; using config entries. ${String(err)}`);
4444
+ }
4445
+ }
4446
+ })();
4447
+ const stopOnAbort = () => {
4448
+ if (opts.abortSignal?.aborted && slackMode === "socket") app.stop();
4449
+ };
4450
+ opts.abortSignal?.addEventListener("abort", stopOnAbort, { once: true });
4451
+ try {
4452
+ if (slackMode === "socket") {
4453
+ let reconnectAttempts = 0;
4454
+ while (!opts.abortSignal?.aborted) {
4455
+ try {
4456
+ await app.start();
4457
+ reconnectAttempts = 0;
4458
+ publishSlackConnectedStatus(opts.setStatus);
4459
+ runtime.log?.("slack socket mode connected");
4460
+ } catch (err) {
4461
+ if (isNonRecoverableSlackAuthError(err)) {
4462
+ runtime.error?.(`slack socket mode failed to start due to non-recoverable auth error — skipping channel (${formatUnknownError(err)})`);
4463
+ throw err;
4464
+ }
4465
+ reconnectAttempts += 1;
4466
+ if (SLACK_SOCKET_RECONNECT_POLICY.maxAttempts > 0 && reconnectAttempts >= SLACK_SOCKET_RECONNECT_POLICY.maxAttempts) throw err;
4467
+ const delayMs = computeBackoff(SLACK_SOCKET_RECONNECT_POLICY, reconnectAttempts);
4468
+ runtime.error?.(`slack socket mode failed to start. retry ${reconnectAttempts}/${SLACK_SOCKET_RECONNECT_POLICY.maxAttempts || "∞"} in ${Math.round(delayMs / 1e3)}s (${formatUnknownError(err)})`);
4469
+ try {
4470
+ await sleepWithAbort(delayMs, opts.abortSignal);
4471
+ } catch {
4472
+ break;
4473
+ }
4474
+ continue;
4475
+ }
4476
+ if (opts.abortSignal?.aborted) break;
4477
+ const disconnect = await waitForSlackSocketDisconnect(app, opts.abortSignal);
4478
+ if (opts.abortSignal?.aborted) break;
4479
+ publishSlackDisconnectedStatus(opts.setStatus, disconnect.error);
4480
+ if (disconnect.error && isNonRecoverableSlackAuthError(disconnect.error)) {
4481
+ runtime.error?.(`slack socket mode disconnected due to non-recoverable auth error — skipping channel (${formatUnknownError(disconnect.error)})`);
4482
+ throw disconnect.error instanceof Error ? disconnect.error : new Error(formatUnknownError(disconnect.error));
4483
+ }
4484
+ reconnectAttempts += 1;
4485
+ if (SLACK_SOCKET_RECONNECT_POLICY.maxAttempts > 0 && reconnectAttempts >= SLACK_SOCKET_RECONNECT_POLICY.maxAttempts) throw new Error(`Slack socket mode reconnect max attempts reached (${reconnectAttempts}/${SLACK_SOCKET_RECONNECT_POLICY.maxAttempts}) after ${disconnect.event}`);
4486
+ const delayMs = computeBackoff(SLACK_SOCKET_RECONNECT_POLICY, reconnectAttempts);
4487
+ runtime.error?.(`slack socket disconnected (${disconnect.event}). retry ${reconnectAttempts}/${SLACK_SOCKET_RECONNECT_POLICY.maxAttempts || "∞"} in ${Math.round(delayMs / 1e3)}s${disconnect.error ? ` (${formatUnknownError(disconnect.error)})` : ""}`);
4488
+ await app.stop().catch(() => void 0);
4489
+ try {
4490
+ await sleepWithAbort(delayMs, opts.abortSignal);
4491
+ } catch {
4492
+ break;
4493
+ }
4494
+ }
4495
+ } else {
4496
+ runtime.log?.(`slack http mode listening at ${slackWebhookPath}`);
4497
+ if (!opts.abortSignal?.aborted) await new Promise((resolve) => {
4498
+ opts.abortSignal?.addEventListener("abort", () => resolve(), { once: true });
4499
+ });
4500
+ }
4501
+ } finally {
4502
+ opts.abortSignal?.removeEventListener("abort", stopOnAbort);
4503
+ unregisterHttpHandler?.();
4504
+ await app.stop().catch(() => void 0);
4505
+ }
4506
+ }
4507
+ //#endregion
4508
+ //#region extensions/slack/src/probe.ts
4509
+ async function probeSlack(token, timeoutMs = 2500) {
4510
+ const client = createSlackWebClient(token);
4511
+ const start = Date.now();
4512
+ try {
4513
+ const result = await withTimeout(client.auth.test(), timeoutMs);
4514
+ if (!result.ok) return {
4515
+ ok: false,
4516
+ status: 200,
4517
+ error: result.error ?? "unknown",
4518
+ elapsedMs: Date.now() - start
4519
+ };
4520
+ return {
4521
+ ok: true,
4522
+ status: 200,
4523
+ elapsedMs: Date.now() - start,
4524
+ bot: {
4525
+ id: result.user_id,
4526
+ name: result.user
4527
+ },
4528
+ team: {
4529
+ id: result.team_id,
4530
+ name: result.team
4531
+ }
4532
+ };
4533
+ } catch (err) {
4534
+ const message = err instanceof Error ? err.message : String(err);
4535
+ return {
4536
+ ok: false,
4537
+ status: typeof err.status === "number" ? err.status : null,
4538
+ error: message,
4539
+ elapsedMs: Date.now() - start
4540
+ };
4541
+ }
4542
+ }
4543
+ //#endregion
4544
+ //#region src/plugins/runtime/runtime-slack-ops.runtime.ts
4545
+ const runtimeSlackOps = {
4546
+ listDirectoryGroupsLive: listSlackDirectoryGroupsLive,
4547
+ listDirectoryPeersLive: listSlackDirectoryPeersLive,
4548
+ probeSlack,
4549
+ resolveChannelAllowlist: resolveSlackChannelAllowlist,
4550
+ resolveUserAllowlist: resolveSlackUserAllowlist,
4551
+ sendMessageSlack,
4552
+ monitorSlackProvider,
4553
+ handleSlackAction
4554
+ };
4555
+ //#endregion
4556
+ export { runtimeSlackOps };