@spacebar_ai/moldclaw-core 2026.3.43 → 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 (1131) 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/extensions/discord/src/monitor/allow-list.ts +8 -1
  688. package/extensions/discord/src/monitor/message-handler.preflight.ts +4 -1
  689. package/package.json +1 -1
  690. package/dist/accounts-CS8U4v8C.js +0 -114
  691. package/dist/accounts-gLr-Udmt.d.ts +0 -103
  692. package/dist/acp-cli-BGT0jXcC.js +0 -2093
  693. package/dist/actions.runtime-BfckTw6c.js +0 -119
  694. package/dist/actions.runtime-Cl9mBfqH.js +0 -133
  695. package/dist/agent-scope-C-YmLnnb.js +0 -208
  696. package/dist/agents-CydD54p8.js +0 -222
  697. package/dist/agents-DpQsZO6O.js +0 -853
  698. package/dist/agents.config-XU7IsYE-.js +0 -121
  699. package/dist/agents.config-ssoQXuvF.js +0 -17
  700. package/dist/allow-list-Cfn6lmMK.js +0 -81
  701. package/dist/allowlist-CCYXVpM9.js +0 -142
  702. package/dist/api-BoXoFKxy.js +0 -117
  703. package/dist/audit-Bv05N5o9.js +0 -787
  704. package/dist/audit-CIWW1Aqm.js +0 -54
  705. package/dist/audit-channel.collect.runtime-Bi7yrdcO.js +0 -605
  706. package/dist/audit-channel.runtime-C_NDweiW.js +0 -121
  707. package/dist/audit-extra.async-Dp7OKSXg.js +0 -813
  708. package/dist/audit-membership-runtime-B8FQ6VtN.js +0 -162
  709. package/dist/audit.deep.runtime-CXhobL6b.js +0 -25
  710. package/dist/audit.nondeep.runtime-CrEm3T16.js +0 -832
  711. package/dist/audit.runtime-CJPKj1Zg.js +0 -118
  712. package/dist/auth-Byfp0flq.js +0 -101
  713. package/dist/auth-choice-BgOjdeXN.js +0 -507
  714. package/dist/auth-choice-CD1Heq0M.js +0 -122
  715. package/dist/auth-choice-ePNfg0iQ.js +0 -268
  716. package/dist/auth-choice-options-BlewQWI0.js +0 -123
  717. package/dist/auth-choice-prompt-BP2b6aXz.js +0 -36
  718. package/dist/auth-choice-prompt-Cmwl4n97.js +0 -115
  719. package/dist/auth-choice.apply-helpers-Dq-nxuuX.js +0 -66
  720. package/dist/auth-choice.plugin-providers.runtime-B23kOUzQ.js +0 -119
  721. package/dist/auth-profiles-1kPLbBwI.js +0 -127823
  722. package/dist/auth-profiles.runtime-DAfSjku1.js +0 -116
  723. package/dist/banner-DeOsobLO.js +0 -342
  724. package/dist/bluebubbles-BsLGedBM.js +0 -64
  725. package/dist/bluebubbles-U2sAfO4_.d.ts +0 -6
  726. package/dist/bot-DW12K3bO.d.ts +0 -478
  727. package/dist/brave-BoWimrLe.js +0 -24
  728. package/dist/browser-cli-D_S3wEYE.js +0 -1494
  729. package/dist/call-ByEzDJ1_.js +0 -640
  730. package/dist/call-CHCWVg-O.js +0 -39
  731. package/dist/channel-3VC0oOMu.js +0 -214
  732. package/dist/channel-B9fCBPiS.js +0 -207
  733. package/dist/channel-B9q775cM.js +0 -562
  734. package/dist/channel-BG3UK54j.js +0 -803
  735. package/dist/channel-BRQAdMML.js +0 -352
  736. package/dist/channel-BmlLp933.js +0 -1321
  737. package/dist/channel-By6KvdTG.js +0 -920
  738. package/dist/channel-C8rRsdf6.js +0 -226
  739. package/dist/channel-CLEDBbXE.js +0 -943
  740. package/dist/channel-CMvBAG7o.js +0 -306
  741. package/dist/channel-CmlxxjHY.js +0 -1598
  742. package/dist/channel-CqG6_xN0.js +0 -949
  743. package/dist/channel-DNueHKs92.js +0 -316
  744. package/dist/channel-DUtyN7BX.js +0 -4681
  745. package/dist/channel-DWD6GrfZ.js +0 -538
  746. package/dist/channel-DaRYMYzj.js +0 -619
  747. package/dist/channel-Dj6BgLp8.js +0 -575
  748. package/dist/channel-account-context-Ba3u5D21.js +0 -103
  749. package/dist/channel-crabk6Em.js +0 -542
  750. package/dist/channel-i8uqQaK2.js +0 -497
  751. package/dist/channel-options-xljvwHS2.js +0 -50
  752. package/dist/channel-plugin-ids-DAgknSG4.js +0 -26
  753. package/dist/channel-summary-dHTMCG75.js +0 -111
  754. package/dist/channel-xVWQ96Ni.js +0 -397
  755. package/dist/channel.runtime-B6PoZ4BV.js +0 -182
  756. package/dist/channel.runtime-BPZmo57e.js +0 -404
  757. package/dist/channel.runtime-B_1uGR-U.js +0 -199
  758. package/dist/channel.runtime-BiXnPU0d.js +0 -218
  759. package/dist/channel.runtime-BpvDc9sv.js +0 -870
  760. package/dist/channel.runtime-CUua3W80.js +0 -418
  761. package/dist/channel.runtime-CaCBTd0A.js +0 -179
  762. package/dist/channel.runtime-D0FfYvUj.js +0 -4011
  763. package/dist/channel.runtime-DhoJtpvJ.js +0 -241
  764. package/dist/channel.runtime-Kj9EXNE0.js +0 -127
  765. package/dist/channel.runtime-r4tPuPyh.js +0 -171
  766. package/dist/channel.setup-B7d_grfe.js +0 -6
  767. package/dist/channel.setup-C0vu1fhi.js +0 -9
  768. package/dist/channel.setup-CAI0FNHj.js +0 -11
  769. package/dist/channel.setup-CkDVwv5R.js +0 -57
  770. package/dist/channel.setup-Cpd00YqQ.js +0 -8
  771. package/dist/channel.setup-DbBz1-WT.js +0 -9
  772. package/dist/channel.setup-GZnAvD9g.js +0 -8
  773. package/dist/channels-5H484RSw.js +0 -1118
  774. package/dist/channels-BnPudfyx.js +0 -404
  775. package/dist/channels-cli-WIC-QeH_.js +0 -291
  776. package/dist/channels-status-issues-RDmzovJU.js +0 -16
  777. package/dist/clawbot-cli-BgutNwf8.js +0 -118
  778. package/dist/cleanup-utils-DBl1Aij1.js +0 -96
  779. package/dist/cli-1P7u6zqu.js +0 -154
  780. package/dist/command-registry-B8jovrws.js +0 -232
  781. package/dist/command-registry-DtDl1FVm.js +0 -14
  782. package/dist/command-secret-gateway-BgUo3FxJ.js +0 -111
  783. package/dist/compact.runtime-CXbXM0AU.js +0 -116
  784. package/dist/completion-cli-Cik_owAE.js +0 -17
  785. package/dist/completion-cli-RU3P2RSl.js +0 -445
  786. package/dist/config-5HUpB1L1.js +0 -31
  787. package/dist/config-cli-QHaUHoZI.js +0 -433
  788. package/dist/config-guard-C9Sn3pE-.js +0 -118
  789. package/dist/config-sW57gztj.js +0 -44
  790. package/dist/config-validation-5LkjIKNt.js +0 -262
  791. package/dist/config-value-CtTWALxG.js +0 -132
  792. package/dist/configure-BmR2TPLf.js +0 -243
  793. package/dist/configure-DaLN-5xM.js +0 -1100
  794. package/dist/control-ui-assets-CH3MYmAo.js +0 -232
  795. package/dist/control-ui-shared-CA77PTml.js +0 -29
  796. package/dist/core-CvDzLs7B.js +0 -150
  797. package/dist/core-dPA4nFkn.d.ts +0 -87
  798. package/dist/cron-cli-tguLpzyq.js +0 -639
  799. package/dist/daemon-cli-ptosOkL8.js +0 -339
  800. package/dist/daemon-install-DzU4EnVa.js +0 -180
  801. package/dist/deliver-DwxFoHM3.js +0 -111
  802. package/dist/deliver-runtime-DOdDyaPI.js +0 -111
  803. package/dist/device-id-cli-GopvlxxZ.js +0 -52
  804. package/dist/device-identity-CRfhC3_s.js +0 -365
  805. package/dist/devices-cli-ain7ESqU.js +0 -342
  806. package/dist/diagnostic-D96Xaqrj.js +0 -310
  807. package/dist/directory-cli-fh1UxGgY.js +0 -311
  808. package/dist/directory-config-helpers-CpU1oflo.d.ts +0 -38
  809. package/dist/directory.static-CKjJUNGl.js +0 -44
  810. package/dist/discord-CflhwDEM.js +0 -114
  811. package/dist/discovery-x0ZqY4AB.js +0 -48
  812. package/dist/dm-policy-shared-73A52W6E.d.ts +0 -95
  813. package/dist/dns-cli-DCHyKjGf.js +0 -217
  814. package/dist/docs-cli-D3OoqYSP.js +0 -174
  815. package/dist/doctor-completion-Bq2eP87s.js +0 -90
  816. package/dist/doctor-config-flow-D8XRG9Ku.js +0 -2437
  817. package/dist/doctor-config-flow-DGiF1HGc.js +0 -112
  818. package/dist/enable-0QSF4YGH.js +0 -24
  819. package/dist/exec-approvals-cli-Bncym0Gd.js +0 -421
  820. package/dist/feishu-B5JDcyF9.d.ts +0 -36
  821. package/dist/gateway-cli-DYscsmA-.js +0 -26437
  822. package/dist/gateway-install-token-CNv17ac9.js +0 -163
  823. package/dist/gateway-rpc-BGC1Rxvg.js +0 -26
  824. package/dist/gateway-runtime-D89mSQPB.js +0 -69
  825. package/dist/git-commit-CeLH5Ozm.js +0 -2
  826. package/dist/git-commit-DUKRiCP-.js +0 -177
  827. package/dist/googlechat-BgXeXjd1.js +0 -307
  828. package/dist/googlechat-De-T7C31.d.ts +0 -12
  829. package/dist/group-access-Deh1tVNr.d.ts +0 -61
  830. package/dist/health-BEjzWwaB.js +0 -570
  831. package/dist/health-FjqrWQL6.js +0 -113
  832. package/dist/heartbeat-summary-CfdSA9M1.js +0 -57
  833. package/dist/help-BZeVprq1.js +0 -81
  834. package/dist/hooks-B5pYs_d7.d.ts +0 -6
  835. package/dist/hooks-cli-B7uGJs2O.js +0 -1000
  836. package/dist/hooks-status-CfceaUSg.js +0 -78
  837. package/dist/http-registry-C-KXqwnj.d.ts +0 -20
  838. package/dist/identity-file-sshkKKIr.js +0 -60
  839. package/dist/image-generation-CafM5hZh.d.ts +0 -9
  840. package/dist/imessage-BcV3WGx_.js +0 -31
  841. package/dist/imessage-Dhje7Ty-.js +0 -115
  842. package/dist/inbound-reply-dispatch-C73_7SOl.js +0 -71
  843. package/dist/inbound-reply-dispatch-DmL0KWLe.d.ts +0 -72
  844. package/dist/install-target-D7NRhfzc.js +0 -574
  845. package/dist/installs-Bj6jblqc.js +0 -532
  846. package/dist/io-CMfWWPXQ.js +0 -9738
  847. package/dist/io-CV844hAM.js +0 -29
  848. package/dist/irc-DKi1fDYI.js +0 -672
  849. package/dist/library-rygTG3oA.js +0 -112
  850. package/dist/lifecycle-core-BPlvShWY.js +0 -382
  851. package/dist/line-CGsemKWJ.js +0 -530
  852. package/dist/line-CKU3ER-n.d.ts +0 -75
  853. package/dist/llm-slug-generator-DlhVyMqT.js +0 -67
  854. package/dist/logging-5wu9k6w4.js +0 -30
  855. package/dist/logging-CxP9suT8.js +0 -13
  856. package/dist/login-qr-BcDsiwHs.js +0 -233
  857. package/dist/login-qr-Y8pJ5yV4.js +0 -112
  858. package/dist/logs-cli-XI9oVXpH.js +0 -256
  859. package/dist/manager-runtime-DkIlXBhD.js +0 -111
  860. package/dist/manager.runtime-Q0q2rJCC.js +0 -715
  861. package/dist/manifest-registry-DAd0SRAP.js +0 -1329
  862. package/dist/matrix-BI0DBBrG.js +0 -1495
  863. package/dist/matrix-DiABGjJR.js +0 -1269
  864. package/dist/matrix-fC6NrFM5.d.ts +0 -68
  865. package/dist/mcp-cli-BOyn_DLL.js +0 -87
  866. package/dist/media-understanding.runtime-DjUa7Dka.js +0 -116
  867. package/dist/memory-cli-CJd_vl-Y.js +0 -111
  868. package/dist/memory-search-CEEItIFR.js +0 -17
  869. package/dist/memory-search-Cv1SBrn7.js +0 -204
  870. package/dist/method-scopes-CQE7-bZ-.js +0 -2452
  871. package/dist/model-auth-markers-B1bbs9Qd.d.ts +0 -20
  872. package/dist/model-picker-D6_89XHg.js +0 -112
  873. package/dist/model-picker-Svaw-APs.js +0 -390
  874. package/dist/model-picker.runtime-Chi9nV7A.js +0 -125
  875. package/dist/model-selection-hL8i1Jbs.js +0 -653
  876. package/dist/model-suppression.runtime-DjWJZ0X-.js +0 -116
  877. package/dist/models-7qj1dG_W.js +0 -118
  878. package/dist/models-BPOB_xJF.js +0 -2514
  879. package/dist/models-cli-DdlOVUjS.js +0 -309
  880. package/dist/models-config-CBqUS-jX.js +0 -111
  881. package/dist/models-config.providers.discovery-BKB5JH9M.d.ts +0 -18
  882. package/dist/moldclaw-root-D6PbhbZk.js +0 -88
  883. package/dist/monitor-BPYhkEqF.js +0 -782
  884. package/dist/monitor-BuTcQ24j.js +0 -3468
  885. package/dist/monitor-CuXvNhFh.js +0 -113
  886. package/dist/monitor-D-TqSIHF.js +0 -6823
  887. package/dist/monitor-DRSgo9u2.js +0 -3076
  888. package/dist/monitor-DcHch39z.js +0 -772
  889. package/dist/monitor-DsHBMrXp.js +0 -115
  890. package/dist/monitor-shared-CL8T4gt1.js +0 -444
  891. package/dist/msteams-7FMwTvQG.js +0 -852
  892. package/dist/node-cli-BCjaSCZM.js +0 -2503
  893. package/dist/node-resolve-D5Hvcgyx.js +0 -835
  894. package/dist/nodes-cli-Dd_SNbkt.js +0 -1380
  895. package/dist/nostr-D8scBiYq.d.ts +0 -7
  896. package/dist/nostr-DBTFTxKs.js +0 -8744
  897. package/dist/npm-resolution-CYfb3MHG.js +0 -60
  898. package/dist/oauth-env-zPt5RywA.js +0 -10
  899. package/dist/onboard-BEFQQeig.js +0 -25
  900. package/dist/onboard-CJHNyxJh.js +0 -48
  901. package/dist/onboard-D_3UeLEN.js +0 -589
  902. package/dist/onboard-channels-B_JL0Djc.js +0 -1241
  903. package/dist/onboard-channels-CqZzHt2C.js +0 -205
  904. package/dist/onboard-custom-CER3Ggbq.js +0 -571
  905. package/dist/onboard-custom-bNRdGECb.js +0 -114
  906. package/dist/onboard-helpers-BK0Hsb7Y.js +0 -335
  907. package/dist/onboard-helpers-CXZ5RPoR.js +0 -113
  908. package/dist/onboard-hooks-1NsxEDjH.js +0 -72
  909. package/dist/onboard-remote-DuKhC_7W.js +0 -117
  910. package/dist/onboard-remote-OwRcDuB3.js +0 -181
  911. package/dist/onboard-search-Cy8dOq2W.js +0 -302
  912. package/dist/onboard-skills-D5phRa6r.js +0 -117
  913. package/dist/onboard-skills-c9qWCNe9.js +0 -133
  914. package/dist/outbound-media-CgNYEQWb.d.ts +0 -11
  915. package/dist/outbound-media-DYRO2vTD.js +0 -11
  916. package/dist/pairing-access-Dsiu5Mvl.d.ts +0 -21
  917. package/dist/pairing-cli-BOnv0TYn.js +0 -217
  918. package/dist/perplexity-EZwC3y2b.js +0 -24
  919. package/dist/persistent-dedupe-DMLOqJ23.d.ts +0 -26
  920. package/dist/pi-model-discovery-runtime-BToY3A6K.js +0 -111
  921. package/dist/pi-tools.before-tool-call.runtime-D_acPtld.js +0 -381
  922. package/dist/plugin-install-CgJpSjYd.js +0 -184
  923. package/dist/plugin-install-Cl1A4EF6.js +0 -117
  924. package/dist/plugin-install-plan-Dc2Z4DeU.js +0 -49
  925. package/dist/plugin-registry-B1UaWrQD.js +0 -49
  926. package/dist/plugin-registry-Cy8biwnn.js +0 -113
  927. package/dist/plugins-CXwvg50F.js +0 -111
  928. package/dist/plugins-cli-Uvzp2aYV.js +0 -917
  929. package/dist/policy-DsMBbEe7.js +0 -143
  930. package/dist/preflight-audio.runtime-hWsZIYvc.js +0 -116
  931. package/dist/probe-CNsSf1Uf.js +0 -6329
  932. package/dist/probe-CqOIrPhb.js +0 -47
  933. package/dist/probe-DH6gDw-h.js +0 -129
  934. package/dist/probe-DM16PLf4.js +0 -21
  935. package/dist/probe-DvAEEWYr.js +0 -1793
  936. package/dist/probe-auth-COfgCble.js +0 -48
  937. package/dist/probe-auth-I_5TX1Eh.js +0 -40
  938. package/dist/program-Dz80sgTU.js +0 -253
  939. package/dist/prompt-select-styled-wQehwFxK.js +0 -2673
  940. package/dist/provider-api-key-auth.runtime-BR9GU4ya.js +0 -121
  941. package/dist/provider-auth-choice-CdhA84kr.js +0 -126
  942. package/dist/provider-auth-choice-helpers-kabp_0zA.js +0 -48
  943. package/dist/provider-auth-choice-preference-se3zAM_2.js +0 -189
  944. package/dist/provider-auth-choice.runtime-BMc8-xNQ.js +0 -123
  945. package/dist/provider-auth-choices-CYsCViGi.js +0 -57
  946. package/dist/provider-auth-guidance-CMjUWlNf.js +0 -34
  947. package/dist/provider-auth-result-Cw6qIhO-.d.ts +0 -18
  948. package/dist/provider-models-BCId_Lfu.js +0 -2113
  949. package/dist/provider-models-Ok-DrSiY.d.ts +0 -867
  950. package/dist/provider-ollama-setup-B6XJZ0So.js +0 -314
  951. package/dist/provider-ollama-setup-lGDdTl0b.d.ts +0 -32
  952. package/dist/provider-onboard-CSPi7jOK.d.ts +0 -40
  953. package/dist/provider-onboard-Ca0TaNud.js +0 -139
  954. package/dist/provider-runtime.runtime-DwwkHw_7.js +0 -111
  955. package/dist/provider-self-hosted-setup-BEKLVGpj.js +0 -182
  956. package/dist/provider-self-hosted-setup-Df91By-J.d.ts +0 -61
  957. package/dist/provider-stream-DrUD69ai.js +0 -512
  958. package/dist/provider-usage-BgKHCnjr.js +0 -111
  959. package/dist/provider-usage-D8EZpFz9.js +0 -633
  960. package/dist/provider-wizard-DMdb-zj_.js +0 -152
  961. package/dist/push-apns-BPH6d4VV.js +0 -1038
  962. package/dist/pw-ai-DttfldtL.js +0 -1867
  963. package/dist/qmd-manager-CybcDUfk.js +0 -1570
  964. package/dist/qr-cli-8NcmJ8Ft.js +0 -369
  965. package/dist/qr-cli-DWe0Our3.js +0 -113
  966. package/dist/reactions-D6N0LR16.js +0 -281
  967. package/dist/read-only-account-inspect.discord.runtime-CqUWTRfl.js +0 -116
  968. package/dist/read-only-account-inspect.slack.runtime-9-jpln3q.js +0 -116
  969. package/dist/read-only-account-inspect.telegram.runtime-EKPI1D7n.js +0 -116
  970. package/dist/redact-snapshot-DwJEIVk9.js +0 -2663
  971. package/dist/register.agent-D3YdDirP.js +0 -439
  972. package/dist/register.backup-dR27qCuo.js +0 -625
  973. package/dist/register.configure-BjFhkkka.js +0 -252
  974. package/dist/register.maintenance-DiMQJIOa.js +0 -574
  975. package/dist/register.message-CdZsKYH1.js +0 -709
  976. package/dist/register.onboard-B0rV1eaO.js +0 -192
  977. package/dist/register.setup-wKMvohzo.js +0 -212
  978. package/dist/register.status-health-sessions-BJ68m6pt.js +0 -498
  979. package/dist/register.subclis-CnnrWt2a.js +0 -315
  980. package/dist/register.subclis-lSvTkC6z.js +0 -13
  981. package/dist/replies-BABt9b48.js +0 -110
  982. package/dist/resolve-channels-BqZFl2Ux.js +0 -262
  983. package/dist/resolve-channels-DjQLXb7B.js +0 -226
  984. package/dist/resolve-route-CSHDsa_m.js +0 -538
  985. package/dist/resolve-users-BG6HaSR5.js +0 -143
  986. package/dist/root-help-ohmaCyC_.js +0 -32
  987. package/dist/routes-4k2kpvoT.js +0 -7097
  988. package/dist/rpc-Cnwn4Q6L.js +0 -67
  989. package/dist/run-main-VYlacKA0.js +0 -424
  990. package/dist/runtime-D61jzMiI.d.ts +0 -26
  991. package/dist/runtime-discord-ops.runtime-DafrU-rI.js +0 -9078
  992. package/dist/runtime-slack-ops.runtime-CdXBKXwd.js +0 -4556
  993. package/dist/runtime-telegram-ops.runtime-B12sF7gE.js +0 -133
  994. package/dist/runtime-whatsapp-login.runtime-CqEudH37.js +0 -114
  995. package/dist/runtime-whatsapp-outbound.runtime-D5m2qyn-.js +0 -117
  996. package/dist/sandbox-cli-CHJiEWXB.js +0 -535
  997. package/dist/search-manager-BtNC3-i_.js +0 -16
  998. package/dist/search-manager-C7J7B3_a.js +0 -386
  999. package/dist/secrets-cli-C6yIWBbN.js +0 -2070
  1000. package/dist/security-cli-BVu9BkjD.js +0 -575
  1001. package/dist/send-BSreC7rr.js +0 -631
  1002. package/dist/send-BsLHQG_B.js +0 -1025
  1003. package/dist/send-BuNhp8PH.js +0 -283
  1004. package/dist/send-DOCswVar.js +0 -100
  1005. package/dist/send-Dl0LLErk.js +0 -629
  1006. package/dist/server-node-events-Bq2067EG.js +0 -506
  1007. package/dist/server-y38L7N5H.js +0 -107
  1008. package/dist/sessions-BV8gXURR.js +0 -112
  1009. package/dist/sessions-dl1Kc-Ci.js +0 -218
  1010. package/dist/setup-BSPXdMuK.d.ts +0 -37
  1011. package/dist/setup-DGszQH0_.js +0 -387
  1012. package/dist/setup-binary-C17YnmA8.js +0 -406
  1013. package/dist/setup-browser-CPx-nEsr.js +0 -70
  1014. package/dist/setup-core-BByHN1ME.js +0 -143
  1015. package/dist/setup-core-C0KPlBmL.js +0 -47
  1016. package/dist/setup-core-Cq37G6of.js +0 -166
  1017. package/dist/setup-core-uO84_Y75.js +0 -205
  1018. package/dist/setup-surface-BEMi7Rmb.js +0 -490
  1019. package/dist/setup-wizard-helpers-Ck9wDR0b.d.ts +0 -203
  1020. package/dist/setup.finalize-BzPBa8zW.js +0 -522
  1021. package/dist/setup.gateway-config-DdwkF-8e.js +0 -343
  1022. package/dist/shared-BCw4SKjB.js +0 -96
  1023. package/dist/shared-CjNzsULP.js +0 -75
  1024. package/dist/shared-Cu1BE7ZE.js +0 -298
  1025. package/dist/shared-DSClmyUn.js +0 -182
  1026. package/dist/shared-DyJdGH6y.js +0 -102
  1027. package/dist/signal-Dyv4NZsB.js +0 -114
  1028. package/dist/skills-CbB5b27M.js +0 -853
  1029. package/dist/skills-CnfI7Szw.js +0 -20
  1030. package/dist/skills-cli-CavB1f_3.js +0 -292
  1031. package/dist/skills-install-B1OBdgd0.js +0 -763
  1032. package/dist/skills-status-B3gAmIbW.js +0 -169
  1033. package/dist/skills-status-DrHhFgU9.js +0 -21
  1034. package/dist/slack-BRzqnoAz.js +0 -114
  1035. package/dist/slash-commands.runtime-BK88kgds.js +0 -128
  1036. package/dist/slash-dispatch.runtime-COGywwJE.js +0 -141
  1037. package/dist/slash-skill-commands.runtime-Ti4brxgh.js +0 -116
  1038. package/dist/src-DUR6OQxI.js +0 -1701
  1039. package/dist/status-C6dgQY9a.js +0 -131
  1040. package/dist/status-CNK0Q7QH.js +0 -606
  1041. package/dist/status-DBcX0DSC.js +0 -43
  1042. package/dist/status-DKgFgbwv.js +0 -1599
  1043. package/dist/status-Wn5lhNAc.js +0 -126
  1044. package/dist/status-json-D2EkWqAl.js +0 -288
  1045. package/dist/status.link-channel-D3ULIdEa.js +0 -143
  1046. package/dist/status.scan.deps.runtime-BsjWTAm4.js +0 -126
  1047. package/dist/status.scan.runtime-D4HbzROD.js +0 -119
  1048. package/dist/status.summary-C3YxPrDK.js +0 -592
  1049. package/dist/status.summary.runtime-DAkXPSaK.js +0 -118
  1050. package/dist/status.update-B4NnN9P1.js +0 -77
  1051. package/dist/subagent-orphan-recovery-QiQEBv36.js +0 -307
  1052. package/dist/subagent-registry-runtime-BJatPQFK.js +0 -111
  1053. package/dist/subscription-BhZORXN9.js +0 -100
  1054. package/dist/subscription-QEUjQRMv.js +0 -33
  1055. package/dist/subscription-cli-HrULlAgc.js +0 -134
  1056. package/dist/synology-chat-DB76GWMN.js +0 -297
  1057. package/dist/system-cli-D8jDwWuL.js +0 -94
  1058. package/dist/telegram-BHiiqKkQ.js +0 -114
  1059. package/dist/text-chunking-Baonm9Lu.js +0 -84
  1060. package/dist/text-chunking-DzB11ONk.d.ts +0 -79
  1061. package/dist/tlon-DLESxNgD.js +0 -433
  1062. package/dist/tui-C75zi2Cl.js +0 -3834
  1063. package/dist/tui-cli-DFwx5e6i.js +0 -137
  1064. package/dist/types-BKldC9YN.d.ts +0 -22692
  1065. package/dist/types-MeyueBE0.d.ts +0 -45
  1066. package/dist/types.base-Cw0-zIvE.d.ts +0 -188
  1067. package/dist/ui-B55NOIB6.js +0 -31
  1068. package/dist/update--ojavYQ4.js +0 -1036
  1069. package/dist/update-cli-Cvj5aWYM.js +0 -1503
  1070. package/dist/update-offset-store-upatuWwX.js +0 -112
  1071. package/dist/update-runner-DHkY_-76.js +0 -1496
  1072. package/dist/upsert-with-lock-C171GLaR.js +0 -33
  1073. package/dist/usage-N3bxnbmt.js +0 -115
  1074. package/dist/web-RdvT7gKa.js +0 -112
  1075. package/dist/web-shared-C2qHVxw1.d.ts +0 -45
  1076. package/dist/webhook-request-guards-CosLyl01.d.ts +0 -76
  1077. package/dist/webhook-targets-Bfnag-du.js +0 -181
  1078. package/dist/webhook-targets-DP_EkQa4.d.ts +0 -106
  1079. package/dist/webhooks-cli-ZpnXrq7G.js +0 -350
  1080. package/dist/whatsapp-DNTAyZHt.js +0 -114
  1081. package/dist/whatsapp-actions-o1zKQzKZ.js +0 -167
  1082. package/dist/workspace-CpWi5wPr.js +0 -479
  1083. package/dist/workspace-Ii7aRS7c.js +0 -289
  1084. package/dist/workspace-dirs-x10McA9t.js +0 -2003
  1085. package/dist/zalo-C9OQRYRw.d.ts +0 -9
  1086. package/dist/zalo-zm_bYCKg.js +0 -415
  1087. package/dist/zalouser-CvVEUvc5.js +0 -30911
  1088. /package/dist/{account-id-B3YSn4hl.d.ts → account-id-B8ce6G_4.d.ts} +0 -0
  1089. /package/dist/{acpx-CnNv70m2.d.ts → acpx-Ci50I9T2.d.ts} +0 -0
  1090. /package/dist/{agent-media-payload-DE2pEcsz.d.ts → agent-media-payload-en-gS5p6.d.ts} +0 -0
  1091. /package/dist/{allow-from-DPpHnT2A.d.ts → allow-from-cMeQ47Ot.d.ts} +0 -0
  1092. /package/dist/{allowlist-resolution-CLFiZ6nE.d.ts → allowlist-resolution-DoAWbfXV.d.ts} +0 -0
  1093. /package/dist/{bluebubbles-Duhu-Jer.d.ts → bluebubbles-C6yYmUl0.d.ts} +0 -0
  1094. /package/dist/{boolean-param-BhFjB3gp.d.ts → boolean-param-CdO2TFTk.d.ts} +0 -0
  1095. /package/dist/{channel-config-schema-DnnVMdjR.d.ts → channel-config-schema-Chp38wel.d.ts} +0 -0
  1096. /package/dist/{channel-policy-Baq-Z06b.d.ts → channel-policy-g2h6AbYQ.d.ts} +0 -0
  1097. /package/dist/{chat-type-DpiBgwuG.d.ts → chat-type-BLt59pPT.d.ts} +0 -0
  1098. /package/dist/{command-format-vi4xq8e8.d.ts → command-format-BDJC05Jp.d.ts} +0 -0
  1099. /package/dist/{diffs-DK7fVSDo.d.ts → diffs-D_iNKCyn.d.ts} +0 -0
  1100. /package/dist/{directory-runtime-BTLPaysA.d.ts → directory-runtime-DhMex6HY.d.ts} +0 -0
  1101. /package/dist/{exec-C01wtBHu.d.ts → exec-pjfUY4KM.d.ts} +0 -0
  1102. /package/dist/{gaxios-fetch-compat-wZ38b3w3.js → gaxios-fetch-compat-B_vtINdV.js} +0 -0
  1103. /package/dist/{history-CwXuP2TW.d.ts → history-aqSS5VGQ.d.ts} +0 -0
  1104. /package/dist/{inbound-envelope-SggrBs9m.d.ts → inbound-envelope-C5hWuZod.d.ts} +0 -0
  1105. /package/dist/{index-apAZHsDo.d.ts → index-DXVQFYGX.d.ts} +0 -0
  1106. /package/dist/{json-store-r75IZGk9.d.ts → json-store-UnqQ5aV3.d.ts} +0 -0
  1107. /package/dist/{keyed-async-queue-DHIr7yNe.d.ts → keyed-async-queue-guucpLw3.d.ts} +0 -0
  1108. /package/dist/{links-HeQ3r_L0.d.ts → links-Bar0meEK.d.ts} +0 -0
  1109. /package/dist/{markdown-to-line-CDb4Jy3V.d.ts → markdown-to-line-D8uH_KOj.d.ts} +0 -0
  1110. /package/dist/{mattermost-DtCsxpgg.d.ts → mattermost-xl7jAFJL.d.ts} +0 -0
  1111. /package/dist/{net-BATPDwdQ.d.ts → net-rGOKGds6.d.ts} +0 -0
  1112. /package/dist/{nextcloud-talk-Bb2wHOwp.d.ts → nextcloud-talk-De2CZ9dV.d.ts} +0 -0
  1113. /package/dist/{oauth-utils-u567CLT0.d.ts → oauth-utils-DzN1AlEH.d.ts} +0 -0
  1114. /package/dist/{parse-finite-number-l3tNlrZh.d.ts → parse-finite-number-odgyqhi0.d.ts} +0 -0
  1115. /package/dist/{provider-usage.types-C6061OVN.d.ts → provider-usage.types-EDE9o-H_.d.ts} +0 -0
  1116. /package/dist/{reply-history-BDsFnZFl.d.ts → reply-history-CVuU31xe.d.ts} +0 -0
  1117. /package/dist/{reply-payload-CCvM4W9u.d.ts → reply-payload-CHkpBYwL.d.ts} +0 -0
  1118. /package/dist/{request-url-C54l4-xC.d.ts → request-url-DHisbiHY.d.ts} +0 -0
  1119. /package/dist/{run-command-D3RqWcHu.d.ts → run-command-y0Cndsb1.d.ts} +0 -0
  1120. /package/dist/{secret-input-schema-BLBt-NAP.d.ts → secret-input-schema-b1vpYDQN.d.ts} +0 -0
  1121. /package/dist/{session-key-BQ2-bR-9.d.ts → session-key-DTHQl57f.d.ts} +0 -0
  1122. /package/dist/{ssh-config-C4mcH9Ly.js → ssh-config-hEHBfU2_.js} +0 -0
  1123. /package/dist/{testing-DLkhGsoz.d.ts → testing-DszuZXgK.d.ts} +0 -0
  1124. /package/dist/{thinking-DRkjX18p.d.ts → thinking-IwXTGSeT.d.ts} +0 -0
  1125. /package/dist/{tool-send-CMMD1uDu.d.ts → tool-send-DWHRmKpz.d.ts} +0 -0
  1126. /package/dist/{vllm-defaults-CcGuf4hL.d.ts → vllm-defaults-CrxZgE6-.d.ts} +0 -0
  1127. /package/dist/{wait-Daog8bxM.d.ts → wait-wDWw_MTI.d.ts} +0 -0
  1128. /package/dist/{webhook-memory-guards-C5MrExwT.d.ts → webhook-memory-guards-DreORuJy.d.ts} +0 -0
  1129. /package/dist/{windows-spawn-j2l-dqu8.d.ts → windows-spawn-BIzH92x2.d.ts} +0 -0
  1130. /package/dist/{zod-schema.agent-runtime-krMrBnIn.d.ts → zod-schema.agent-runtime-CP2rmis3.d.ts} +0 -0
  1131. /package/dist/{zod-schema.core-BNDieZDZ.d.ts → zod-schema.core-Foi1tYwi.d.ts} +0 -0
@@ -1,4556 +0,0 @@
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-C17YnmA8.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-1kPLbBwI.js";
19
- import "./model-selection-hL8i1Jbs.js";
20
- import "./agent-scope-C-YmLnnb.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-CpWi5wPr.js";
28
- import { c as loadConfig, cn as mapStreamingModeToSlackLegacyDraftStreamMode, mn as resolveSlackStreamingMode, pn as resolveSlackNativeStreaming, y as writeConfigFile } from "./io-CMfWWPXQ.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-DAd0SRAP.js";
38
- import "./ip-C4YAIpr4.js";
39
- import "./zod-schema.core-DvwgNmpd.js";
40
- import "./config-sW57gztj.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-x10McA9t.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-4k2kpvoT.js";
51
- import "./frontmatter-Cgg0ICvh.js";
52
- import "./env-overrides-DBQl3LRc.js";
53
- import "./path-alias-guards-BtSO7sk7.js";
54
- import "./skills-CbB5b27M.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-CSHDsa_m.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-CQE7-bZ-.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-BuNhp8PH.js";
75
- import "./node-resolve-D5Hvcgyx.js";
76
- import "./provider-stream-DrUD69ai.js";
77
- import "./identity-file-sshkKKIr.js";
78
- import "./provider-models-BCId_Lfu.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-Ca0TaNud.js";
84
- import "./model-definitions-Cyyzm6Kr.js";
85
- import "./usage-N3bxnbmt.js";
86
- import "./device-identity-CRfhC3_s.js";
87
- import "./auth-Byfp0flq.js";
88
- import "./subscription-BhZORXN9.js";
89
- import "./diagnostic-D96Xaqrj.js";
90
- import "./message-hook-mappers-CeiHXgSQ.js";
91
- import "./json-store--7cBPxTG.js";
92
- import "./call-ByEzDJ1_.js";
93
- import "./multimodal-BJBBn_4F.js";
94
- import "./memory-search-Cv1SBrn7.js";
95
- import "./query-expansion-D_Mm5Hhi.js";
96
- import "./search-manager-C7J7B3_a.js";
97
- import "./core-CvDzLs7B.js";
98
- import "./issue-format-B0SI57Es.js";
99
- import "./logging-CxP9suT8.js";
100
- import "./note-dOl5kPAy.js";
101
- import "./state-paths-DsMoTg25.js";
102
- import "./config-value-CtTWALxG.js";
103
- import "./command-secret-targets-BFF4x_RB.js";
104
- import "./brave-BoWimrLe.js";
105
- import "./provider-usage-D8EZpFz9.js";
106
- import "./perplexity-EZwC3y2b.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-CIWW1Aqm.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-D89mSQPB.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-Cfn6lmMK.js";
120
- import { n as resolveSlackUserAllowlist, t as resolveSlackChannelAllowlist } from "./resolve-channels-DjQLXb7B.js";
121
- import { a as resolveSlackThreadTs, i as readSlackReplyBlocks, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-BABt9b48.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-BK88kgds.js");
3527
- return slashCommandsRuntimePromise;
3528
- }
3529
- function loadSlashDispatchRuntime() {
3530
- slashDispatchRuntimePromise ??= import("./slash-dispatch.runtime-COGywwJE.js");
3531
- return slashDispatchRuntimePromise;
3532
- }
3533
- function loadSlashSkillCommandsRuntime() {
3534
- slashSkillCommandsRuntimePromise ??= import("./slash-skill-commands.runtime-Ti4brxgh.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 };