@5ss/ai-tools 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +21 -0
  3. package/README.md +221 -0
  4. package/dist/ai-sdk/index.d.ts +15 -0
  5. package/dist/ai-sdk/index.d.ts.map +1 -0
  6. package/dist/ai-sdk/index.js +24 -0
  7. package/dist/ai-sdk/index.js.map +1 -0
  8. package/dist/artifact-D064mHfK.js +44 -0
  9. package/dist/artifact-D064mHfK.js.map +1 -0
  10. package/dist/artifacts-O8g-40Pw.js +404 -0
  11. package/dist/artifacts-O8g-40Pw.js.map +1 -0
  12. package/dist/aws-json-CecFqzqX.js +23 -0
  13. package/dist/aws-json-CecFqzqX.js.map +1 -0
  14. package/dist/aws-service-msttbPrz.js +58 -0
  15. package/dist/aws-service-msttbPrz.js.map +1 -0
  16. package/dist/batch-BMM5dXqL.d.ts +22 -0
  17. package/dist/batch-BMM5dXqL.d.ts.map +1 -0
  18. package/dist/batch-Co1ujeAW.js +67 -0
  19. package/dist/batch-Co1ujeAW.js.map +1 -0
  20. package/dist/bedrock-agentcore-browser-a_qOs-NR.js +182 -0
  21. package/dist/bedrock-agentcore-browser-a_qOs-NR.js.map +1 -0
  22. package/dist/bedrock-agentcore-code-interpreter-MWK-8RhA.js +357 -0
  23. package/dist/bedrock-agentcore-code-interpreter-MWK-8RhA.js.map +1 -0
  24. package/dist/bytes-BxpimpQx.js +45 -0
  25. package/dist/bytes-BxpimpQx.js.map +1 -0
  26. package/dist/client-CCKGsTeI.js +743 -0
  27. package/dist/client-CCKGsTeI.js.map +1 -0
  28. package/dist/cloudflare/index.d.ts +37 -0
  29. package/dist/cloudflare/index.d.ts.map +1 -0
  30. package/dist/cloudflare/index.js +41 -0
  31. package/dist/cloudflare/index.js.map +1 -0
  32. package/dist/cloudflare-browser-B6Yolpin.js +428 -0
  33. package/dist/cloudflare-browser-B6Yolpin.js.map +1 -0
  34. package/dist/cloudflare-email-Dy0KHeDf.js +197 -0
  35. package/dist/cloudflare-email-Dy0KHeDf.js.map +1 -0
  36. package/dist/cloudflare-sandbox-Dp_uNaqW.js +982 -0
  37. package/dist/cloudflare-sandbox-Dp_uNaqW.js.map +1 -0
  38. package/dist/content-type-CORxaxcv.js +49 -0
  39. package/dist/content-type-CORxaxcv.js.map +1 -0
  40. package/dist/core/index.d.ts +4 -0
  41. package/dist/core/index.js +204 -0
  42. package/dist/core/index.js.map +1 -0
  43. package/dist/define-CvpJ_pNP.js +115 -0
  44. package/dist/define-CvpJ_pNP.js.map +1 -0
  45. package/dist/errors-DoSpNHvs.js +20 -0
  46. package/dist/errors-DoSpNHvs.js.map +1 -0
  47. package/dist/errors-aKhko9T1.d.ts +18 -0
  48. package/dist/errors-aKhko9T1.d.ts.map +1 -0
  49. package/dist/eventbridge-scheduler-Bh6GqZY2.js +349 -0
  50. package/dist/eventbridge-scheduler-Bh6GqZY2.js.map +1 -0
  51. package/dist/framework-context-DVIIY8ZO.js +24 -0
  52. package/dist/framework-context-DVIIY8ZO.js.map +1 -0
  53. package/dist/gotenberg-NuJjxyln.js +291 -0
  54. package/dist/gotenberg-NuJjxyln.js.map +1 -0
  55. package/dist/http/index.d.ts +47 -0
  56. package/dist/http/index.d.ts.map +1 -0
  57. package/dist/http/index.js +3 -0
  58. package/dist/http-service-DDNCO1s4.js +254 -0
  59. package/dist/http-service-DDNCO1s4.js.map +1 -0
  60. package/dist/http-service-T7E5UjP8.d.ts +80 -0
  61. package/dist/http-service-T7E5UjP8.d.ts.map +1 -0
  62. package/dist/imessage-BSAFOI8Z.js +154 -0
  63. package/dist/imessage-BSAFOI8Z.js.map +1 -0
  64. package/dist/index-BU4gmYO8.d.ts +254 -0
  65. package/dist/index-BU4gmYO8.d.ts.map +1 -0
  66. package/dist/index-CCivzmxO.d.ts +188 -0
  67. package/dist/index-CCivzmxO.d.ts.map +1 -0
  68. package/dist/index-CLmTrcu5.d.ts +22 -0
  69. package/dist/index-CLmTrcu5.d.ts.map +1 -0
  70. package/dist/index-CZX5OeOF.d.ts +235 -0
  71. package/dist/index-CZX5OeOF.d.ts.map +1 -0
  72. package/dist/index-CdFmEfZO.d.ts +359 -0
  73. package/dist/index-CdFmEfZO.d.ts.map +1 -0
  74. package/dist/index-Cuh6eMWc.d.ts +285 -0
  75. package/dist/index-Cuh6eMWc.d.ts.map +1 -0
  76. package/dist/index-DuOGj7vc.d.ts +107 -0
  77. package/dist/index-DuOGj7vc.d.ts.map +1 -0
  78. package/dist/index-ccZ1XOHw.d.ts +69 -0
  79. package/dist/index-ccZ1XOHw.d.ts.map +1 -0
  80. package/dist/index-n8JTpNf1.d.ts +247 -0
  81. package/dist/index-n8JTpNf1.d.ts.map +1 -0
  82. package/dist/index-pwW1OsOx.d.ts +134 -0
  83. package/dist/index-pwW1OsOx.d.ts.map +1 -0
  84. package/dist/index-zK1ZwS4m.d.ts +347 -0
  85. package/dist/index-zK1ZwS4m.d.ts.map +1 -0
  86. package/dist/limits-hjrO8zUG.js +80 -0
  87. package/dist/limits-hjrO8zUG.js.map +1 -0
  88. package/dist/mastra/index.d.ts +14 -0
  89. package/dist/mastra/index.d.ts.map +1 -0
  90. package/dist/mastra/index.js +26 -0
  91. package/dist/mastra/index.js.map +1 -0
  92. package/dist/mastra-vector-Dhc6XZ8l.js +234 -0
  93. package/dist/mastra-vector-Dhc6XZ8l.js.map +1 -0
  94. package/dist/mcp/index.d.ts +80 -0
  95. package/dist/mcp/index.d.ts.map +1 -0
  96. package/dist/mcp/index.js +97 -0
  97. package/dist/mcp/index.js.map +1 -0
  98. package/dist/modules/artifacts/index.d.ts +337 -0
  99. package/dist/modules/artifacts/index.d.ts.map +1 -0
  100. package/dist/modules/artifacts/index.js +348 -0
  101. package/dist/modules/artifacts/index.js.map +1 -0
  102. package/dist/modules/browser/index.d.ts +516 -0
  103. package/dist/modules/browser/index.d.ts.map +1 -0
  104. package/dist/modules/browser/index.js +475 -0
  105. package/dist/modules/browser/index.js.map +1 -0
  106. package/dist/modules/calendar/index.d.ts +93 -0
  107. package/dist/modules/calendar/index.d.ts.map +1 -0
  108. package/dist/modules/calendar/index.js +131 -0
  109. package/dist/modules/calendar/index.js.map +1 -0
  110. package/dist/modules/code-sandbox/index.d.ts +317 -0
  111. package/dist/modules/code-sandbox/index.d.ts.map +1 -0
  112. package/dist/modules/code-sandbox/index.js +537 -0
  113. package/dist/modules/code-sandbox/index.js.map +1 -0
  114. package/dist/modules/content-type/index.d.ts +22 -0
  115. package/dist/modules/content-type/index.d.ts.map +1 -0
  116. package/dist/modules/content-type/index.js +66 -0
  117. package/dist/modules/content-type/index.js.map +1 -0
  118. package/dist/modules/crypto/index.d.ts +115 -0
  119. package/dist/modules/crypto/index.d.ts.map +1 -0
  120. package/dist/modules/crypto/index.js +139 -0
  121. package/dist/modules/crypto/index.js.map +1 -0
  122. package/dist/modules/document/index.d.ts +575 -0
  123. package/dist/modules/document/index.d.ts.map +1 -0
  124. package/dist/modules/document/index.js +444 -0
  125. package/dist/modules/document/index.js.map +1 -0
  126. package/dist/modules/document-extract/index.d.ts +438 -0
  127. package/dist/modules/document-extract/index.d.ts.map +1 -0
  128. package/dist/modules/document-extract/index.js +127 -0
  129. package/dist/modules/document-extract/index.js.map +1 -0
  130. package/dist/modules/document-render/index.d.ts +336 -0
  131. package/dist/modules/document-render/index.d.ts.map +1 -0
  132. package/dist/modules/document-render/index.js +155 -0
  133. package/dist/modules/document-render/index.js.map +1 -0
  134. package/dist/modules/email/index.d.ts +311 -0
  135. package/dist/modules/email/index.d.ts.map +1 -0
  136. package/dist/modules/email/index.js +167 -0
  137. package/dist/modules/email/index.js.map +1 -0
  138. package/dist/modules/email-message/index.d.ts +95 -0
  139. package/dist/modules/email-message/index.d.ts.map +1 -0
  140. package/dist/modules/email-message/index.js +264 -0
  141. package/dist/modules/email-message/index.js.map +1 -0
  142. package/dist/modules/file-convert/index.d.ts +273 -0
  143. package/dist/modules/file-convert/index.d.ts.map +1 -0
  144. package/dist/modules/file-convert/index.js +103 -0
  145. package/dist/modules/file-convert/index.js.map +1 -0
  146. package/dist/modules/files/index.d.ts +452 -0
  147. package/dist/modules/files/index.d.ts.map +1 -0
  148. package/dist/modules/files/index.js +733 -0
  149. package/dist/modules/files/index.js.map +1 -0
  150. package/dist/modules/image/index.d.ts +342 -0
  151. package/dist/modules/image/index.d.ts.map +1 -0
  152. package/dist/modules/image/index.js +281 -0
  153. package/dist/modules/image/index.js.map +1 -0
  154. package/dist/modules/messaging/index.d.ts +608 -0
  155. package/dist/modules/messaging/index.d.ts.map +1 -0
  156. package/dist/modules/messaging/index.js +1067 -0
  157. package/dist/modules/messaging/index.js.map +1 -0
  158. package/dist/modules/pdf/index.d.ts +287 -0
  159. package/dist/modules/pdf/index.d.ts.map +1 -0
  160. package/dist/modules/pdf/index.js +259 -0
  161. package/dist/modules/pdf/index.js.map +1 -0
  162. package/dist/modules/presentation/index.d.ts +247 -0
  163. package/dist/modules/presentation/index.d.ts.map +1 -0
  164. package/dist/modules/presentation/index.js +12657 -0
  165. package/dist/modules/presentation/index.js.map +1 -0
  166. package/dist/modules/queue/index.d.ts +129 -0
  167. package/dist/modules/queue/index.d.ts.map +1 -0
  168. package/dist/modules/queue/index.js +131 -0
  169. package/dist/modules/queue/index.js.map +1 -0
  170. package/dist/modules/rag/index.d.ts +250 -0
  171. package/dist/modules/rag/index.d.ts.map +1 -0
  172. package/dist/modules/rag/index.js +366 -0
  173. package/dist/modules/rag/index.js.map +1 -0
  174. package/dist/modules/scheduler/index.d.ts +216 -0
  175. package/dist/modules/scheduler/index.d.ts.map +1 -0
  176. package/dist/modules/scheduler/index.js +153 -0
  177. package/dist/modules/scheduler/index.js.map +1 -0
  178. package/dist/modules/skills/index.d.ts +205 -0
  179. package/dist/modules/skills/index.d.ts.map +1 -0
  180. package/dist/modules/skills/index.js +203 -0
  181. package/dist/modules/skills/index.js.map +1 -0
  182. package/dist/modules/tasks/index.d.ts +287 -0
  183. package/dist/modules/tasks/index.d.ts.map +1 -0
  184. package/dist/modules/tasks/index.js +207 -0
  185. package/dist/modules/tasks/index.js.map +1 -0
  186. package/dist/modules/vector-store/index.d.ts +3 -0
  187. package/dist/modules/vector-store/index.js +3 -0
  188. package/dist/modules/web-fetch/index.d.ts +99 -0
  189. package/dist/modules/web-fetch/index.d.ts.map +1 -0
  190. package/dist/modules/web-fetch/index.js +242 -0
  191. package/dist/modules/web-fetch/index.js.map +1 -0
  192. package/dist/object-artifact-store-CMTzCm_G.d.ts +7 -0
  193. package/dist/object-artifact-store-CMTzCm_G.d.ts.map +1 -0
  194. package/dist/object-artifact-store-wZ2j9cto.js +28 -0
  195. package/dist/object-artifact-store-wZ2j9cto.js.map +1 -0
  196. package/dist/pinecone-umY4t6OF.js +190 -0
  197. package/dist/pinecone-umY4t6OF.js.map +1 -0
  198. package/dist/provider-CgDAlg6K.js +34 -0
  199. package/dist/provider-CgDAlg6K.js.map +1 -0
  200. package/dist/qdrant-DMp4NhKR.js +253 -0
  201. package/dist/qdrant-DMp4NhKR.js.map +1 -0
  202. package/dist/resend-BAC38_dA.js +155 -0
  203. package/dist/resend-BAC38_dA.js.map +1 -0
  204. package/dist/s3-CsOaPWMP.js +955 -0
  205. package/dist/s3-CsOaPWMP.js.map +1 -0
  206. package/dist/schemas-ChOAhdo9.js +192 -0
  207. package/dist/schemas-ChOAhdo9.js.map +1 -0
  208. package/dist/slack-Di5BBNpt.js +1455 -0
  209. package/dist/slack-Di5BBNpt.js.map +1 -0
  210. package/dist/sqs-DCwS1i2N.js +225 -0
  211. package/dist/sqs-DCwS1i2N.js.map +1 -0
  212. package/dist/supabase-vector-Dpp9mmJR.js +218 -0
  213. package/dist/supabase-vector-Dpp9mmJR.js.map +1 -0
  214. package/dist/tanstack/index.d.ts +15 -0
  215. package/dist/tanstack/index.d.ts.map +1 -0
  216. package/dist/tanstack/index.js +28 -0
  217. package/dist/tanstack/index.js.map +1 -0
  218. package/dist/teams-DYAHNb39.js +835 -0
  219. package/dist/teams-DYAHNb39.js.map +1 -0
  220. package/dist/telegram-DDXWzkfL.js +734 -0
  221. package/dist/telegram-DDXWzkfL.js.map +1 -0
  222. package/dist/textract-CPLiB22H.js +554 -0
  223. package/dist/textract-CPLiB22H.js.map +1 -0
  224. package/dist/transport-B4vn-XiQ.js +157 -0
  225. package/dist/transport-B4vn-XiQ.js.map +1 -0
  226. package/dist/transport-i96ACAI_.d.ts +46 -0
  227. package/dist/transport-i96ACAI_.d.ts.map +1 -0
  228. package/dist/types-Ccb0DXY9.d.ts +150 -0
  229. package/dist/types-Ccb0DXY9.d.ts.map +1 -0
  230. package/dist/unique-EwBH1JPB.js +19 -0
  231. package/dist/unique-EwBH1JPB.js.map +1 -0
  232. package/dist/vector-store-C3nEO80e.js +193 -0
  233. package/dist/vector-store-C3nEO80e.js.map +1 -0
  234. package/dist/vendors/amazon-sp-api/index.d.ts +526 -0
  235. package/dist/vendors/amazon-sp-api/index.d.ts.map +1 -0
  236. package/dist/vendors/amazon-sp-api/index.js +975 -0
  237. package/dist/vendors/amazon-sp-api/index.js.map +1 -0
  238. package/dist/vendors/bedrock-agentcore-browser/index.d.ts +2 -0
  239. package/dist/vendors/bedrock-agentcore-browser/index.js +2 -0
  240. package/dist/vendors/bedrock-agentcore-code-interpreter/index.d.ts +228 -0
  241. package/dist/vendors/bedrock-agentcore-code-interpreter/index.d.ts.map +1 -0
  242. package/dist/vendors/bedrock-agentcore-code-interpreter/index.js +2 -0
  243. package/dist/vendors/cloudflare-browser/index.d.ts +2 -0
  244. package/dist/vendors/cloudflare-browser/index.js +2 -0
  245. package/dist/vendors/cloudflare-email/index.d.ts +260 -0
  246. package/dist/vendors/cloudflare-email/index.d.ts.map +1 -0
  247. package/dist/vendors/cloudflare-email/index.js +3 -0
  248. package/dist/vendors/cloudflare-sandbox/index.d.ts +565 -0
  249. package/dist/vendors/cloudflare-sandbox/index.d.ts.map +1 -0
  250. package/dist/vendors/cloudflare-sandbox/index.js +2 -0
  251. package/dist/vendors/eventbridge-scheduler/index.d.ts +2 -0
  252. package/dist/vendors/eventbridge-scheduler/index.js +2 -0
  253. package/dist/vendors/gotenberg/index.d.ts +306 -0
  254. package/dist/vendors/gotenberg/index.d.ts.map +1 -0
  255. package/dist/vendors/gotenberg/index.js +2 -0
  256. package/dist/vendors/imessage/index.d.ts +420 -0
  257. package/dist/vendors/imessage/index.d.ts.map +1 -0
  258. package/dist/vendors/imessage/index.js +4 -0
  259. package/dist/vendors/katana/index.d.ts +1570 -0
  260. package/dist/vendors/katana/index.d.ts.map +1 -0
  261. package/dist/vendors/katana/index.js +1639 -0
  262. package/dist/vendors/katana/index.js.map +1 -0
  263. package/dist/vendors/mastra-vector/index.d.ts +120 -0
  264. package/dist/vendors/mastra-vector/index.d.ts.map +1 -0
  265. package/dist/vendors/mastra-vector/index.js +3 -0
  266. package/dist/vendors/pinecone/index.d.ts +75 -0
  267. package/dist/vendors/pinecone/index.d.ts.map +1 -0
  268. package/dist/vendors/pinecone/index.js +3 -0
  269. package/dist/vendors/qdrant/index.d.ts +75 -0
  270. package/dist/vendors/qdrant/index.d.ts.map +1 -0
  271. package/dist/vendors/qdrant/index.js +3 -0
  272. package/dist/vendors/resend/index.d.ts +3 -0
  273. package/dist/vendors/resend/index.js +3 -0
  274. package/dist/vendors/s3/index.d.ts +2 -0
  275. package/dist/vendors/s3/index.js +2 -0
  276. package/dist/vendors/slack/index.d.ts +576 -0
  277. package/dist/vendors/slack/index.d.ts.map +1 -0
  278. package/dist/vendors/slack/index.js +3 -0
  279. package/dist/vendors/sqs/index.d.ts +2 -0
  280. package/dist/vendors/sqs/index.js +2 -0
  281. package/dist/vendors/supabase-vector/index.d.ts +89 -0
  282. package/dist/vendors/supabase-vector/index.d.ts.map +1 -0
  283. package/dist/vendors/supabase-vector/index.js +3 -0
  284. package/dist/vendors/teams/index.d.ts +303 -0
  285. package/dist/vendors/teams/index.d.ts.map +1 -0
  286. package/dist/vendors/teams/index.js +3 -0
  287. package/dist/vendors/telegram/index.d.ts +319 -0
  288. package/dist/vendors/telegram/index.d.ts.map +1 -0
  289. package/dist/vendors/telegram/index.js +3 -0
  290. package/dist/vendors/textract/index.d.ts +2 -0
  291. package/dist/vendors/textract/index.js +2 -0
  292. package/dist/vendors/woocommerce/index.d.ts +1700 -0
  293. package/dist/vendors/woocommerce/index.d.ts.map +1 -0
  294. package/dist/vendors/woocommerce/index.js +1427 -0
  295. package/dist/vendors/woocommerce/index.js.map +1 -0
  296. package/dist/with-auth-CpKqTrGK.js +240 -0
  297. package/dist/with-auth-CpKqTrGK.js.map +1 -0
  298. package/logos/LUCIDE-ATTRIBUTION.txt +4 -0
  299. package/logos/README.md +89 -0
  300. package/logos/amazon.svg +6 -0
  301. package/logos/artifacts.svg +9 -0
  302. package/logos/browser.svg +9 -0
  303. package/logos/calendar.svg +15 -0
  304. package/logos/cloudflare-browser.svg +5 -0
  305. package/logos/cloudflare-email.svg +5 -0
  306. package/logos/cloudflare.svg +4 -0
  307. package/logos/code-sandbox.svg +8 -0
  308. package/logos/content-type.svg +10 -0
  309. package/logos/crypto.svg +7 -0
  310. package/logos/document-extract.svg +12 -0
  311. package/logos/document-render.svg +8 -0
  312. package/logos/document.svg +10 -0
  313. package/logos/email-message.svg +8 -0
  314. package/logos/email.svg +7 -0
  315. package/logos/file-convert.svg +9 -0
  316. package/logos/files.svg +6 -0
  317. package/logos/gotenberg.svg +340 -0
  318. package/logos/image.svg +8 -0
  319. package/logos/imessage.svg +7 -0
  320. package/logos/katana.svg +13 -0
  321. package/logos/mastra.svg +7 -0
  322. package/logos/messaging.svg +7 -0
  323. package/logos/pack-logos.json +48 -0
  324. package/logos/pdf.svg +10 -0
  325. package/logos/pinecone.svg +25 -0
  326. package/logos/presentation.svg +8 -0
  327. package/logos/qdrant.svg +4 -0
  328. package/logos/queue.svg +11 -0
  329. package/logos/rag.svg +18 -0
  330. package/logos/resend.svg +5 -0
  331. package/logos/scheduler.svg +7 -0
  332. package/logos/skills.svg +10 -0
  333. package/logos/slack.svg +14 -0
  334. package/logos/supabase.svg +4 -0
  335. package/logos/tasks.svg +10 -0
  336. package/logos/teams.svg +6 -0
  337. package/logos/telegram.svg +10 -0
  338. package/logos/textract.svg +5 -0
  339. package/logos/vector-store.svg +8 -0
  340. package/logos/web-fetch.svg +8 -0
  341. package/logos/woocommerce.svg +4 -0
  342. package/package.json +373 -0
@@ -0,0 +1,1455 @@
1
+ import { t as ToolError } from "./errors-DoSpNHvs.js";
2
+ import { n as defineModule, r as defineTool } from "./define-CvpJ_pNP.js";
3
+ import { n as requireAuth } from "./provider-CgDAlg6K.js";
4
+ import { t as HttpService } from "./http-service-DDNCO1s4.js";
5
+ import { a as toArrayBuffer, n as bytesToBase64, t as base64ToBytes } from "./bytes-BxpimpQx.js";
6
+ import { isPlainObject, isString } from "es-toolkit";
7
+ import { z } from "zod";
8
+ import { createHmac, timingSafeEqual } from "node:crypto";
9
+ //#region src/vendors/slack/contracts.ts
10
+ const MAX_MEDIA_BYTES = 100 * 1024 * 1024;
11
+ const slackChatActionSchema = z.enum([
12
+ "typing",
13
+ "upload_photo",
14
+ "record_video",
15
+ "upload_video",
16
+ "record_voice",
17
+ "upload_voice",
18
+ "upload_document",
19
+ "choose_sticker",
20
+ "find_location",
21
+ "record_video_note",
22
+ "upload_video_note"
23
+ ]);
24
+ const slackAuthSchema = z.object({ bot_token: z.string().min(1).describe("Slack bot token (xoxb-…)") });
25
+ const slackSendTextInputSchema = z.object({
26
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
27
+ text: z.string().min(1).max(4e4).describe("Message text (max 40000 characters)"),
28
+ reply_to_message_id: z.string().min(1).optional().describe("Optional thread_ts to reply in a thread"),
29
+ reply_markup: z.unknown().optional().describe("Optional Slack blocks array (Block Kit)")
30
+ });
31
+ const slackMessageOutputSchema = z.object({
32
+ message_id: z.string().describe("Slack message timestamp (ts) as string"),
33
+ file_id: z.string().min(1).optional().describe("Slack file id when the message carries an uploaded file (sendMedia)")
34
+ });
35
+ const slackEditTextInputSchema = z.object({
36
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
37
+ message_id: z.string().min(1).describe("Message ts to edit"),
38
+ text: z.string().min(1).max(4e4).describe("Replacement text (max 40000 characters)"),
39
+ reply_markup: z.unknown().optional().describe("Optional Slack blocks array (Block Kit)")
40
+ });
41
+ const slackSendChatActionInputSchema = z.object({
42
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
43
+ action: slackChatActionSchema.describe("Chat action. With reply_to_message_id (thread_ts), maps to assistant.threads.setStatus loading text."),
44
+ reply_to_message_id: z.string().min(1).optional().describe("Thread root ts (thread_ts). Required for assistant status; without it sendChatAction is a no-op on Slack.")
45
+ });
46
+ /** Clear assistant thread status (empty status). Needs the same thread_ts as set. */
47
+ const slackStopTypingInputSchema = z.object({
48
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
49
+ reply_to_message_id: z.string().min(1).optional().describe("Thread root ts (thread_ts). Required to clear assistant status; without it stop is a no-op.")
50
+ });
51
+ const slackSetReactionInputSchema = z.object({
52
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
53
+ message_id: z.string().min(1).describe("Message ts to react to"),
54
+ emoji: z.string().min(1).max(64).describe("Emoji name (with or without colons), e.g. thumbsup or :thumbsup:")
55
+ });
56
+ const slackClearReactionInputSchema = z.object({
57
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
58
+ message_id: z.string().min(1).describe("Message ts to clear a reaction on"),
59
+ emoji: z.string().min(1).max(64).describe("Emoji name to remove (with or without colons); required on Slack")
60
+ });
61
+ const slackSendMediaInputSchema = z.object({
62
+ chat_id: z.string().min(1).describe("Slack channel or conversation id"),
63
+ kind: z.enum(["photo", "document"]).describe("Media kind"),
64
+ body_base64: z.string().min(1).describe("File body as base64"),
65
+ file_name: z.string().min(1).describe("File name including extension"),
66
+ caption: z.string().max(3e3).optional().describe("Optional initial comment / caption"),
67
+ reply_to_message_id: z.string().min(1).optional().describe("Optional thread_ts for the upload"),
68
+ content_type: z.string().optional().describe("Optional content type for the upload")
69
+ });
70
+ const slackDownloadFileInputSchema = z.object({
71
+ file_id: z.string().min(1).describe("Slack file id from an inbound attachment"),
72
+ file_name: z.string().min(1).optional().describe("Preferred file name for the download result")
73
+ });
74
+ const slackDownloadFileOutputSchema = z.object({
75
+ file_name: z.string(),
76
+ file_size: z.number().optional(),
77
+ body_base64: z.string().describe("Downloaded file body as base64")
78
+ });
79
+ const slackAnswerCallbackInputSchema = z.object({
80
+ callback_query_id: z.string().min(1).describe("Slack response_url from an interactive payload, or opaque callback id"),
81
+ text: z.string().max(3e3).optional().describe("Optional ephemeral response text"),
82
+ show_alert: z.boolean().optional().describe("Ignored on Slack; reserved for channel seam parity")
83
+ });
84
+ const slackGetBotOutputSchema = z.object({
85
+ bot_id: z.string(),
86
+ username: z.string(),
87
+ display_name: z.string()
88
+ });
89
+ const slackOkOutputSchema = z.object({ ok: z.boolean() });
90
+ const slackPostEphemeralInputSchema = z.object({
91
+ chat_id: z.string().min(1).describe("Slack channel id"),
92
+ user_id: z.string().min(1).describe("User id who should see the ephemeral message"),
93
+ text: z.string().min(1).max(4e4).describe("Ephemeral message text"),
94
+ reply_markup: z.unknown().optional().describe("Optional Slack blocks array (Block Kit)")
95
+ });
96
+ const slackListConversationsInputSchema = z.object({
97
+ limit: z.number().int().min(1).max(1e3).optional().describe("Page size (default Slack limit)"),
98
+ cursor: z.string().min(1).optional().describe("Pagination cursor from a previous page"),
99
+ types: z.string().min(1).optional().describe("Comma-separated conversation types, e.g. public_channel,private_channel,im,mpim")
100
+ });
101
+ const slackListConversationsOutputSchema = z.object({
102
+ channels: z.array(z.object({
103
+ id: z.string(),
104
+ name: z.string().optional(),
105
+ is_channel: z.boolean().optional(),
106
+ is_im: z.boolean().optional(),
107
+ is_mpim: z.boolean().optional(),
108
+ is_private: z.boolean().optional()
109
+ })),
110
+ next_cursor: z.string().optional()
111
+ });
112
+ const MAX_SLACK_MEDIA_BATCH = 10;
113
+ /** Host-only: full assistant.threads.setStatus (custom status + loading_messages). */
114
+ const slackSetAssistantStatusInputSchema = z.object({
115
+ chat_id: z.string().min(1).describe("Channel or DM id containing the assistant thread"),
116
+ thread_ts: z.string().min(1).describe("Thread root message ts"),
117
+ status: z.string().describe("Status text Slack shows after the app name (empty string clears)"),
118
+ loading_messages: z.array(z.string().min(1)).max(10).optional().describe("Up to 10 rotating loading messages")
119
+ });
120
+ const slackSetSuggestedPromptsInputSchema = z.object({
121
+ chat_id: z.string().min(1).describe("Channel or DM id"),
122
+ thread_ts: z.string().min(1).optional().describe("Thread ts; optional in agent Messages-tab experience"),
123
+ title: z.string().min(1).optional().describe("Title above the prompt list"),
124
+ prompts: z.array(z.object({
125
+ title: z.string().min(1),
126
+ message: z.string().min(1)
127
+ })).min(1).max(4).describe("Up to four suggested prompts")
128
+ });
129
+ const slackPublishHomeInputSchema = z.object({
130
+ user_id: z.string().min(1).describe("User id to publish the Home tab view for"),
131
+ view: z.unknown().describe("Slack home view payload (type home + blocks)"),
132
+ hash: z.string().min(1).optional().describe("Optional view hash for race protection")
133
+ });
134
+ const slackStartStreamInputSchema = z.object({
135
+ chat_id: z.string().min(1).describe("Channel or DM id"),
136
+ thread_ts: z.string().min(1).describe("Parent message ts (streamed messages are thread replies)"),
137
+ markdown_text: z.string().max(12e3).optional().describe("Optional initial markdown chunk"),
138
+ recipient_user_id: z.string().min(1).optional().describe("Required when streaming into channels"),
139
+ recipient_team_id: z.string().min(1).optional().describe("Required when streaming into channels"),
140
+ task_display_mode: z.enum([
141
+ "timeline",
142
+ "plan",
143
+ "dense"
144
+ ]).optional()
145
+ });
146
+ const slackAppendStreamInputSchema = z.object({
147
+ chat_id: z.string().min(1).describe("Channel or DM id"),
148
+ message_id: z.string().min(1).describe("Streaming message ts from startStream"),
149
+ markdown_text: z.string().min(1).max(12e3).describe("Markdown text to append")
150
+ });
151
+ const slackStopStreamInputSchema = z.object({
152
+ chat_id: z.string().min(1).describe("Channel or DM id"),
153
+ message_id: z.string().min(1).describe("Streaming message ts"),
154
+ markdown_text: z.string().max(12e3).optional().describe("Optional final markdown append"),
155
+ blocks: z.unknown().optional().describe("Optional Block Kit blocks on finalize")
156
+ });
157
+ const slackAuthRevokeInputSchema = z.object({ test: z.boolean().optional().describe("When true, tests revoke without revoking (Slack auth.revoke test flag)") });
158
+ const slackAuthRevokeOutputSchema = z.object({ revoked: z.boolean() });
159
+ const slackUsersInfoInputSchema = z.object({
160
+ user_id: z.string().min(1).describe("Slack user id"),
161
+ include_locale: z.boolean().optional()
162
+ });
163
+ const slackUsersInfoOutputSchema = z.object({
164
+ user_id: z.string(),
165
+ name: z.string().optional(),
166
+ real_name: z.string().optional(),
167
+ display_name: z.string().optional(),
168
+ is_bot: z.boolean().optional(),
169
+ tz: z.string().optional(),
170
+ profile: z.record(z.string(), z.unknown()).optional()
171
+ });
172
+ const slackUsersConversationsInputSchema = z.object({
173
+ user_id: z.string().min(1).optional().describe("User id; omit for the authed user"),
174
+ limit: z.number().int().min(1).max(1e3).optional(),
175
+ cursor: z.string().min(1).optional(),
176
+ types: z.string().min(1).optional().describe("e.g. public_channel,private_channel,im,mpim"),
177
+ exclude_archived: z.boolean().optional()
178
+ });
179
+ const slackConversationInfoInputSchema = z.object({
180
+ chat_id: z.string().min(1).describe("Channel, group, or DM id"),
181
+ include_locale: z.boolean().optional(),
182
+ include_num_members: z.boolean().optional()
183
+ });
184
+ const slackConversationInfoOutputSchema = z.object({
185
+ id: z.string(),
186
+ name: z.string().optional(),
187
+ is_channel: z.boolean().optional(),
188
+ is_im: z.boolean().optional(),
189
+ is_mpim: z.boolean().optional(),
190
+ is_private: z.boolean().optional(),
191
+ is_archived: z.boolean().optional(),
192
+ num_members: z.number().optional(),
193
+ raw: z.record(z.string(), z.unknown()).optional()
194
+ });
195
+ const slackConversationHistoryInputSchema = z.object({
196
+ chat_id: z.string().min(1),
197
+ limit: z.number().int().min(1).max(1e3).optional(),
198
+ cursor: z.string().min(1).optional(),
199
+ oldest: z.string().min(1).optional(),
200
+ latest: z.string().min(1).optional(),
201
+ inclusive: z.boolean().optional()
202
+ });
203
+ const slackConversationRepliesInputSchema = z.object({
204
+ chat_id: z.string().min(1),
205
+ message_id: z.string().min(1).describe("Parent message ts"),
206
+ limit: z.number().int().min(1).max(1e3).optional(),
207
+ cursor: z.string().min(1).optional(),
208
+ oldest: z.string().min(1).optional(),
209
+ latest: z.string().min(1).optional(),
210
+ inclusive: z.boolean().optional()
211
+ });
212
+ const slackConversationMessagesOutputSchema = z.object({
213
+ messages: z.array(z.record(z.string(), z.unknown())),
214
+ next_cursor: z.string().optional(),
215
+ has_more: z.boolean().optional()
216
+ });
217
+ /** Host batch upload: many files, one completeUploadExternal share. */
218
+ const slackSendMediaBatchItemSchema = z.object({
219
+ file_name: z.string().min(1),
220
+ body_base64: z.string().min(1).optional().describe("File body as base64 (tool/host JSON path)"),
221
+ content_type: z.string().optional(),
222
+ title: z.string().min(1).optional()
223
+ });
224
+ const slackSendMediaBatchInputSchema = z.object({
225
+ chat_id: z.string().min(1),
226
+ files: z.array(slackSendMediaBatchItemSchema).min(1).max(10),
227
+ caption: z.string().max(3e3).optional(),
228
+ reply_to_message_id: z.string().min(1).optional()
229
+ });
230
+ const slackSendMediaBatchOutputSchema = z.object({
231
+ message_id: z.string(),
232
+ file_ids: z.array(z.string().min(1)).min(1)
233
+ });
234
+ //#endregion
235
+ //#region src/vendors/slack/domain.ts
236
+ /**
237
+ * Slack payload shaping + envelope/result parse.
238
+ * No HTTP — client owns transport.
239
+ */
240
+ var SlackClientError = class extends ToolError {
241
+ failureKind;
242
+ constructor(input) {
243
+ super(input.message, {
244
+ code: "upstream",
245
+ retryable: input.failureKind === "outcome_unknown",
246
+ cause: input.cause,
247
+ details: {
248
+ method: input.method,
249
+ failure_kind: input.failureKind,
250
+ status: input.status,
251
+ slack_error: input.slackError,
252
+ retry_after_seconds: input.retryAfterSeconds
253
+ }
254
+ });
255
+ this.name = "SlackClientError";
256
+ this.failureKind = input.failureKind;
257
+ }
258
+ };
259
+ function isSlackDefiniteRejection(error) {
260
+ return error instanceof SlackClientError && error.failureKind === "definite_rejection";
261
+ }
262
+ function isSlackOutcomeUnknown(error) {
263
+ return error instanceof SlackClientError && error.failureKind === "outcome_unknown";
264
+ }
265
+ /** Network / abort / transport failures before a parseable Slack envelope. */
266
+ function throwSlackTransportError(method, error) {
267
+ if (error instanceof SlackClientError) throw error;
268
+ throw new SlackClientError({
269
+ message: error instanceof Error ? error.message : `${method} request failed`,
270
+ failureKind: "outcome_unknown",
271
+ method,
272
+ cause: error
273
+ });
274
+ }
275
+ /** Client/auth/validation errors that should not be retried as if delivery might have succeeded. */
276
+ const DEFINITE_SLACK_ERRORS = /* @__PURE__ */ new Set([
277
+ "invalid_auth",
278
+ "not_authed",
279
+ "account_inactive",
280
+ "token_revoked",
281
+ "token_expired",
282
+ "invalid_token",
283
+ "missing_scope",
284
+ "not_allowed_token_type",
285
+ "ekm_access_denied",
286
+ "access_denied",
287
+ "org_login_required",
288
+ "team_access_not_granted",
289
+ "channel_not_found",
290
+ "is_archived",
291
+ "not_in_channel",
292
+ "is_inactive",
293
+ "method_not_supported_for_channel_type",
294
+ "msg_too_long",
295
+ "no_text",
296
+ "invalid_arguments",
297
+ "invalid_blocks",
298
+ "invalid_blocks_format",
299
+ "cant_update_message",
300
+ "message_not_found",
301
+ "cant_delete_message",
302
+ "already_reacted",
303
+ "no_reaction",
304
+ "invalid_name",
305
+ "too_many_emoji",
306
+ "file_not_found",
307
+ "file_deleted",
308
+ "cant_find_user",
309
+ "user_not_found",
310
+ "user_not_visible",
311
+ "invalid_channel",
312
+ "name_taken",
313
+ "restricted_action",
314
+ "as_user_not_supported",
315
+ "cannot_reply_to_message",
316
+ "thread_not_found"
317
+ ]);
318
+ const RETRYABLE_SLACK_ERRORS = /* @__PURE__ */ new Set([
319
+ "rate_limited",
320
+ "ratelimited",
321
+ "internal_error",
322
+ "fatal_error",
323
+ "service_unavailable",
324
+ "request_timeout"
325
+ ]);
326
+ function isDefiniteStatus(status) {
327
+ return status === 400 || status === 401 || status === 403 || status === 404;
328
+ }
329
+ function classifySlackFailure(status, errorCode) {
330
+ if (status === 429 || status >= 500) return "outcome_unknown";
331
+ if (errorCode && RETRYABLE_SLACK_ERRORS.has(errorCode)) return "outcome_unknown";
332
+ if (errorCode && DEFINITE_SLACK_ERRORS.has(errorCode)) return "definite_rejection";
333
+ if (isDefiniteStatus(status)) return "definite_rejection";
334
+ return "outcome_unknown";
335
+ }
336
+ /** Map Slack `{ ok, error?, … }` (HTTP may be non-2xx). Returns the full envelope object when ok. */
337
+ function parseSlackResult(label, status, data) {
338
+ if (!isPlainObject(data) || typeof data["ok"] !== "boolean") throw new SlackClientError({
339
+ message: `${label} returned an invalid envelope`,
340
+ failureKind: status === 429 || status >= 500 || status === 0 ? "outcome_unknown" : classifySlackFailure(status, void 0),
341
+ method: label,
342
+ status
343
+ });
344
+ if (data["ok"] === true) return data;
345
+ const errorCode = isString(data["error"]) ? data["error"] : void 0;
346
+ const retryAfter = typeof data["retry_after"] === "number" ? data["retry_after"] : typeof data["Retry-After"] === "number" ? data["Retry-After"] : void 0;
347
+ throw new SlackClientError({
348
+ message: errorCode ? `${label} failed: ${errorCode}` : `${label} failed`,
349
+ failureKind: classifySlackFailure(status, errorCode),
350
+ method: label,
351
+ status,
352
+ ...errorCode && { slackError: errorCode },
353
+ ...retryAfter !== void 0 && { retryAfterSeconds: retryAfter }
354
+ });
355
+ }
356
+ /** Strip surrounding colons from emoji names (`:thumbsup:` → `thumbsup`). */
357
+ function normalizeEmojiName(emoji) {
358
+ return emoji.replace(/^:+/, "").replace(/:+$/, "");
359
+ }
360
+ function parseMessageTs(value) {
361
+ const ts = value["ts"];
362
+ if (!isString(ts) || ts.length === 0) throw new ToolError("Slack returned an invalid message ts", { code: "upstream" });
363
+ return { message_id: ts };
364
+ }
365
+ function parseOk(value) {
366
+ if (value["ok"] !== true) throw new ToolError("Slack returned unexpected result", { code: "upstream" });
367
+ }
368
+ function parseBot(value) {
369
+ const botId = firstString$1(value["bot_id"], value["user_id"]);
370
+ const username = firstString$1(value["user"], value["team"]);
371
+ const displayName = firstString$1(value["user"], value["team"]);
372
+ if (!botId || !username || !displayName) throw new ToolError("Slack auth.test returned invalid bot identity", { code: "upstream" });
373
+ return {
374
+ bot_id: botId,
375
+ username,
376
+ display_name: displayName
377
+ };
378
+ }
379
+ function parseFileInfo(value) {
380
+ const file = value["file"];
381
+ if (!isPlainObject(file) || !isString(file["id"])) throw new ToolError("Slack files.info returned invalid payload", { code: "upstream" });
382
+ const downloadUrl = file["url_private_download"];
383
+ if (!isString(downloadUrl) || downloadUrl.length === 0) throw new ToolError("Slack files.info missing url_private_download", { code: "upstream" });
384
+ return {
385
+ file_id: file["id"],
386
+ url_private_download: downloadUrl,
387
+ ...isString(file["name"]) && { file_name: file["name"] },
388
+ ...typeof file["size"] === "number" && { file_size: file["size"] }
389
+ };
390
+ }
391
+ function parseDownload(input, file, bytes) {
392
+ return {
393
+ file_name: input.file_name ?? file.file_name ?? file.file_id,
394
+ ...file.file_size !== void 0 && { file_size: file.file_size },
395
+ body_base64: bytesToBase64(bytes)
396
+ };
397
+ }
398
+ function parseUploadUrl(value) {
399
+ const uploadUrl = value["upload_url"];
400
+ const fileId = value["file_id"];
401
+ if (!isString(uploadUrl) || uploadUrl.length === 0 || !isString(fileId) || fileId.length === 0) throw new ToolError("Slack files.getUploadURLExternal returned invalid payload", { code: "upstream" });
402
+ return {
403
+ upload_url: uploadUrl,
404
+ file_id: fileId
405
+ };
406
+ }
407
+ /**
408
+ * Prefer message ts from shares; fall back to uploaded file id.
409
+ * Always surface `file_id` when known so hosts can download the just-uploaded file.
410
+ */
411
+ function parseUploadComplete(value, knownFileId) {
412
+ const files = value["files"];
413
+ if (Array.isArray(files) && files.length > 0) {
414
+ const first = files[0];
415
+ if (isPlainObject(first)) {
416
+ const fileId = (isString(first["id"]) && first["id"].length > 0 ? first["id"] : void 0) ?? knownFileId;
417
+ const fromShares = extractTsFromShares(first["shares"]);
418
+ if (fromShares) return {
419
+ message_id: fromShares,
420
+ ...fileId && { file_id: fileId }
421
+ };
422
+ if (fileId) return {
423
+ message_id: fileId,
424
+ file_id: fileId
425
+ };
426
+ }
427
+ }
428
+ if (knownFileId) return {
429
+ message_id: knownFileId,
430
+ file_id: knownFileId
431
+ };
432
+ throw new ToolError("Slack files.completeUploadExternal returned invalid payload", { code: "upstream" });
433
+ }
434
+ function extractTsFromShares(shares) {
435
+ if (!isPlainObject(shares)) return void 0;
436
+ for (const bucket of Object.values(shares)) {
437
+ if (!isPlainObject(bucket)) continue;
438
+ for (const entries of Object.values(bucket)) {
439
+ if (!Array.isArray(entries)) continue;
440
+ for (const entry of entries) if (isPlainObject(entry) && isString(entry["ts"]) && entry["ts"].length > 0) return entry["ts"];
441
+ }
442
+ }
443
+ }
444
+ function parseConversationsList(value) {
445
+ const channelsRaw = value["channels"];
446
+ if (!Array.isArray(channelsRaw)) throw new ToolError("Slack conversations.list returned invalid payload", { code: "upstream" });
447
+ const channels = [];
448
+ for (const row of channelsRaw) {
449
+ if (!isPlainObject(row) || !isString(row["id"])) continue;
450
+ channels.push({
451
+ id: row["id"],
452
+ ...isString(row["name"]) && { name: row["name"] },
453
+ ...typeof row["is_channel"] === "boolean" && { is_channel: row["is_channel"] },
454
+ ...typeof row["is_im"] === "boolean" && { is_im: row["is_im"] },
455
+ ...typeof row["is_mpim"] === "boolean" && { is_mpim: row["is_mpim"] },
456
+ ...typeof row["is_private"] === "boolean" && { is_private: row["is_private"] }
457
+ });
458
+ }
459
+ const nextCursor = nextCursorFrom(value);
460
+ return {
461
+ channels,
462
+ ...nextCursor && { next_cursor: nextCursor }
463
+ };
464
+ }
465
+ /** Empty + size checks shared by base64 and raw-byte media paths. */
466
+ function assertMediaBytes(bytes) {
467
+ if (bytes.byteLength === 0) throw new ToolError("Media body must not be empty", { code: "bad_input" });
468
+ if (bytes.byteLength > 104857600) throw new ToolError("Media exceeds 100 MiB limit", {
469
+ code: "too_large",
470
+ details: {
471
+ max_bytes: MAX_MEDIA_BYTES,
472
+ content_length: bytes.byteLength
473
+ }
474
+ });
475
+ return bytes;
476
+ }
477
+ function decodeMediaBytes(bodyBase64) {
478
+ let bytes;
479
+ try {
480
+ bytes = base64ToBytes(bodyBase64);
481
+ } catch (error) {
482
+ throw new ToolError("Invalid base64 body", {
483
+ code: "bad_input",
484
+ cause: error
485
+ });
486
+ }
487
+ return assertMediaBytes(bytes);
488
+ }
489
+ /** Host may pass raw bytes instead of base64 (client path only). */
490
+ function resolveMediaBytes(input) {
491
+ const bytes = input.body !== void 0 ? assertMediaBytes(input.body) : input.body_base64 ? decodeMediaBytes(input.body_base64) : void 0;
492
+ if (!bytes) throw new ToolError("Media requires body_base64 or body (Uint8Array)", { code: "bad_input" });
493
+ return {
494
+ bytes,
495
+ body: toArrayBuffer(bytes)
496
+ };
497
+ }
498
+ function nextCursorFrom(value) {
499
+ const metadata = value["response_metadata"];
500
+ return isPlainObject(metadata) ? firstString$1(metadata["next_cursor"]) : void 0;
501
+ }
502
+ function parseUsersInfo(value) {
503
+ const user = value["user"];
504
+ if (!isPlainObject(user) || !isString(user["id"])) throw new ToolError("Slack users.info returned invalid payload", { code: "upstream" });
505
+ const profile = isPlainObject(user["profile"]) ? user["profile"] : void 0;
506
+ const out = { user_id: user["id"] };
507
+ const name = firstString$1(user["name"]);
508
+ if (name) out.name = name;
509
+ const realName = firstString$1(user["real_name"]);
510
+ if (realName) out.real_name = realName;
511
+ const displayName = firstString$1(profile?.["display_name"], profile?.["real_name"], user["real_name"]);
512
+ if (displayName) out.display_name = displayName;
513
+ if (typeof user["is_bot"] === "boolean") out.is_bot = user["is_bot"];
514
+ const tz = firstString$1(user["tz"]);
515
+ if (tz) out.tz = tz;
516
+ if (profile) out.profile = profile;
517
+ return out;
518
+ }
519
+ function parseConversationInfo(value) {
520
+ const channel = value["channel"];
521
+ if (!isPlainObject(channel) || !isString(channel["id"])) throw new ToolError("Slack conversations.info returned invalid payload", { code: "upstream" });
522
+ const out = {
523
+ id: channel["id"],
524
+ raw: channel
525
+ };
526
+ const name = firstString$1(channel["name"]);
527
+ if (name) out.name = name;
528
+ if (typeof channel["is_channel"] === "boolean") out.is_channel = channel["is_channel"];
529
+ if (typeof channel["is_im"] === "boolean") out.is_im = channel["is_im"];
530
+ if (typeof channel["is_mpim"] === "boolean") out.is_mpim = channel["is_mpim"];
531
+ if (typeof channel["is_private"] === "boolean") out.is_private = channel["is_private"];
532
+ if (typeof channel["is_archived"] === "boolean") out.is_archived = channel["is_archived"];
533
+ if (typeof channel["num_members"] === "number") out.num_members = channel["num_members"];
534
+ return out;
535
+ }
536
+ function parseConversationMessages(value) {
537
+ const messagesRaw = value["messages"];
538
+ if (!Array.isArray(messagesRaw)) throw new ToolError("Slack conversation messages payload invalid", { code: "upstream" });
539
+ const out = { messages: messagesRaw.filter(isPlainObject) };
540
+ const nextCursor = nextCursorFrom(value);
541
+ if (nextCursor) out.next_cursor = nextCursor;
542
+ if (typeof value["has_more"] === "boolean") out.has_more = value["has_more"];
543
+ return out;
544
+ }
545
+ function parseAuthRevoke(value) {
546
+ return { revoked: value["revoked"] === true };
547
+ }
548
+ function parseStreamTs(value) {
549
+ const ts = firstString$1(value["ts"]);
550
+ if (!ts) throw new ToolError("Slack stream API returned invalid payload (missing ts)", { code: "upstream" });
551
+ return { message_id: ts };
552
+ }
553
+ function parseUploadBatchComplete(value, knownFileIds) {
554
+ const files = Array.isArray(value["files"]) ? value["files"] : [];
555
+ const fromResponse = [];
556
+ for (const file of files) if (isPlainObject(file)) {
557
+ const id = firstString$1(file["id"]);
558
+ if (id) fromResponse.push(id);
559
+ }
560
+ const fileIds = fromResponse.length > 0 ? fromResponse : knownFileIds;
561
+ const first = isPlainObject(files[0]) ? files[0] : void 0;
562
+ const messageId = (first ? extractTsFromShares(first["shares"]) : void 0) ?? fileIds[0];
563
+ if (!messageId || fileIds.length === 0) throw new ToolError("Slack files.completeUploadExternal returned no file ids", { code: "upstream" });
564
+ return {
565
+ message_id: messageId,
566
+ file_ids: fileIds
567
+ };
568
+ }
569
+ function isHttpsUrl(value) {
570
+ return value.startsWith("https://") || value.startsWith("http://");
571
+ }
572
+ /**
573
+ * Map shared chat-action enum → assistant.threads.setStatus status text.
574
+ * Slack renders as "{App Name} {status}" (do not include the app name).
575
+ */
576
+ function assistantStatusFromChatAction(action) {
577
+ switch (action) {
578
+ case "upload_photo":
579
+ case "upload_video":
580
+ case "upload_voice":
581
+ case "upload_document":
582
+ case "upload_video_note": return "is uploading a file…";
583
+ case "record_video":
584
+ case "record_voice":
585
+ case "record_video_note": return "is recording…";
586
+ case "choose_sticker":
587
+ case "find_location": return "is working on your request…";
588
+ default: return "is checking the request…";
589
+ }
590
+ }
591
+ function firstString$1(...values) {
592
+ for (const value of values) if (isString(value) && value.length > 0) return value;
593
+ }
594
+ //#endregion
595
+ //#region src/vendors/slack/client.ts
596
+ /**
597
+ * Slack Web API vendor client.
598
+ * Host: `new SlackClient(auth)`. Agent tools: `fromContext(ctx)`.
599
+ */
600
+ var SlackClient = class SlackClient {
601
+ #token;
602
+ /** Authenticated Slack Web API (`https://slack.com/api`). */
603
+ #http;
604
+ /** Bare HTTP for pre-signed upload URLs and interactive response_url (no bot Authorization). */
605
+ #external;
606
+ constructor(auth, options = {}) {
607
+ const parsed = slackAuthSchema.safeParse(auth);
608
+ if (!parsed.success) throw new ToolError("Invalid Slack auth credentials", {
609
+ code: "bad_auth",
610
+ details: { issues: parsed.error.issues.map((issue) => issue.message) }
611
+ });
612
+ this.#token = parsed.data.bot_token;
613
+ this.#http = new HttpService({
614
+ ...options,
615
+ baseURL: "https://slack.com/api",
616
+ headers: {
617
+ Authorization: `Bearer ${parsed.data.bot_token}`,
618
+ "Content-Type": "application/json"
619
+ },
620
+ label: "Slack"
621
+ });
622
+ this.#external = new HttpService({
623
+ ...options,
624
+ label: "Slack"
625
+ });
626
+ }
627
+ static fromContext(ctx) {
628
+ const auth = requireAuth(ctx, slackAuthSchema);
629
+ return new SlackClient(auth, {
630
+ ...ctx.fetch && { fetch: ctx.fetch },
631
+ ...ctx.signal && { signal: ctx.signal }
632
+ });
633
+ }
634
+ async #api(method, body, label) {
635
+ try {
636
+ const res = await this.#http.post(`/${method}`, body, {
637
+ label,
638
+ noThrow: true
639
+ });
640
+ return parseSlackResult(label, res.status, res.data);
641
+ } catch (error) {
642
+ throwSlackTransportError(label, error);
643
+ }
644
+ }
645
+ /** Form-urlencoded Web API call (used where Slack documents form as primary, e.g. getUploadURLExternal). */
646
+ async #apiForm(method, body, label) {
647
+ try {
648
+ const res = await this.#http.post(`/${method}`, body, {
649
+ label,
650
+ noThrow: true,
651
+ headers: {
652
+ Authorization: `Bearer ${this.#token}`,
653
+ "Content-Type": "application/x-www-form-urlencoded"
654
+ }
655
+ });
656
+ return parseSlackResult(label, res.status, res.data);
657
+ } catch (error) {
658
+ throwSlackTransportError(label, error);
659
+ }
660
+ }
661
+ /** POST chat.postMessage */
662
+ async sendText(input) {
663
+ const body = {
664
+ channel: input.chat_id,
665
+ text: input.text,
666
+ ...input.reply_to_message_id && { thread_ts: input.reply_to_message_id },
667
+ ...input.reply_markup !== void 0 && { blocks: input.reply_markup }
668
+ };
669
+ return parseMessageTs(await this.#api("chat.postMessage", body, "Slack chat.postMessage"));
670
+ }
671
+ /** POST chat.update */
672
+ async editText(input) {
673
+ const body = {
674
+ channel: input.chat_id,
675
+ ts: input.message_id,
676
+ text: input.text,
677
+ ...input.reply_markup !== void 0 && { blocks: input.reply_markup }
678
+ };
679
+ return parseMessageTs(await this.#api("chat.update", body, "Slack chat.update"));
680
+ }
681
+ /**
682
+ * Chat action (typing / upload_*).
683
+ * With `reply_to_message_id` (thread_ts): `assistant.threads.setStatus` loading line.
684
+ * Without thread_ts: no-op (Slack has no channel-level typing API).
685
+ * @see https://docs.slack.dev/reference/methods/assistant.threads.setStatus
686
+ */
687
+ async sendChatAction(input) {
688
+ const threadTs = input.reply_to_message_id;
689
+ if (!threadTs) return;
690
+ parseOk(await this.#api("assistant.threads.setStatus", {
691
+ channel_id: input.chat_id,
692
+ thread_ts: threadTs,
693
+ status: assistantStatusFromChatAction(input.action)
694
+ }, "Slack assistant.threads.setStatus"));
695
+ }
696
+ /**
697
+ * Clear assistant thread status (`status: ""`).
698
+ * Requires `reply_to_message_id` (thread_ts); otherwise no-op.
699
+ */
700
+ async stopTyping(input) {
701
+ const threadTs = input.reply_to_message_id;
702
+ if (!threadTs) return;
703
+ parseOk(await this.#api("assistant.threads.setStatus", {
704
+ channel_id: input.chat_id,
705
+ thread_ts: threadTs,
706
+ status: ""
707
+ }, "Slack assistant.threads.setStatus clear"));
708
+ }
709
+ /** POST reactions.add */
710
+ async setReaction(input) {
711
+ parseOk(await this.#api("reactions.add", {
712
+ channel: input.chat_id,
713
+ timestamp: input.message_id,
714
+ name: normalizeEmojiName(input.emoji)
715
+ }, "Slack reactions.add"));
716
+ }
717
+ /** POST reactions.remove — emoji required on Slack. */
718
+ async clearReaction(input) {
719
+ parseOk(await this.#api("reactions.remove", {
720
+ channel: input.chat_id,
721
+ timestamp: input.message_id,
722
+ name: normalizeEmojiName(input.emoji)
723
+ }, "Slack reactions.remove"));
724
+ }
725
+ /**
726
+ * External upload flow:
727
+ * files.getUploadURLExternal → POST bytes to upload_url → files.completeUploadExternal
728
+ * @see https://docs.slack.dev/reference/methods/files.getUploadURLExternal
729
+ */
730
+ async sendMedia(input) {
731
+ const { bytes, body } = resolveMediaBytes(input);
732
+ const form = new URLSearchParams();
733
+ form.set("filename", input.file_name);
734
+ form.set("length", String(bytes.byteLength));
735
+ const upload = parseUploadUrl(await this.#apiForm("files.getUploadURLExternal", form, "Slack files.getUploadURLExternal"));
736
+ const putHeaders = { "Content-Type": input.content_type ?? "application/octet-stream" };
737
+ let put;
738
+ try {
739
+ put = await this.#external.post(upload.upload_url, body, {
740
+ label: "Slack file upload POST",
741
+ noThrow: true,
742
+ headers: putHeaders
743
+ });
744
+ } catch (error) {
745
+ throwSlackTransportError("Slack file upload POST", error);
746
+ }
747
+ if (!put.ok) throw new SlackClientError({
748
+ message: `Slack file upload POST failed with HTTP ${put.status}`,
749
+ failureKind: put.status === 400 || put.status === 401 || put.status === 403 || put.status === 404 ? "definite_rejection" : "outcome_unknown",
750
+ method: "Slack file upload POST",
751
+ status: put.status
752
+ });
753
+ return parseUploadComplete(await this.#api("files.completeUploadExternal", {
754
+ files: [{
755
+ id: upload.file_id,
756
+ title: input.file_name
757
+ }],
758
+ channel_id: input.chat_id,
759
+ ...input.reply_to_message_id && { thread_ts: input.reply_to_message_id },
760
+ ...input.caption && { initial_comment: input.caption }
761
+ }, "Slack files.completeUploadExternal"), upload.file_id);
762
+ }
763
+ /** POST files.info + GET url_private_download (Bearer). */
764
+ async downloadFile(input) {
765
+ const file = parseFileInfo(await this.#api("files.info", { file: input.file_id }, "Slack files.info"));
766
+ let res;
767
+ try {
768
+ res = await this.#http.bytes("GET", file.url_private_download, {
769
+ label: "Slack downloadFile",
770
+ noThrow: true,
771
+ headers: { Authorization: `Bearer ${this.#token}` }
772
+ });
773
+ } catch (error) {
774
+ throwSlackTransportError("Slack downloadFile", error);
775
+ }
776
+ if (!res.ok) throw new SlackClientError({
777
+ message: `Slack downloadFile failed with HTTP ${res.status}`,
778
+ failureKind: res.status === 400 || res.status === 401 || res.status === 403 || res.status === 404 ? "definite_rejection" : "outcome_unknown",
779
+ method: "Slack downloadFile",
780
+ status: res.status
781
+ });
782
+ return parseDownload(input, file, res.bytes);
783
+ }
784
+ /**
785
+ * Answer an interactive payload.
786
+ * When callback_query_id is an http(s) response_url, POST ephemeral JSON to it.
787
+ * Otherwise no-op success (Slack has no Telegram-style answerCallbackQuery id).
788
+ */
789
+ async answerCallback(input) {
790
+ if (!isHttpsUrl(input.callback_query_id)) return;
791
+ const body = {
792
+ replace_original: false,
793
+ response_type: "ephemeral",
794
+ ...input.text && { text: input.text }
795
+ };
796
+ let res;
797
+ try {
798
+ res = await this.#external.post(input.callback_query_id, body, {
799
+ label: "Slack response_url",
800
+ noThrow: true,
801
+ headers: { "Content-Type": "application/json" }
802
+ });
803
+ } catch (error) {
804
+ throwSlackTransportError("Slack response_url", error);
805
+ }
806
+ if (!res.ok) throw new SlackClientError({
807
+ message: `Slack response_url failed with HTTP ${res.status}`,
808
+ failureKind: res.status === 400 || res.status === 401 || res.status === 403 || res.status === 404 ? "definite_rejection" : "outcome_unknown",
809
+ method: "Slack response_url",
810
+ status: res.status
811
+ });
812
+ }
813
+ /** POST auth.test */
814
+ async getBot() {
815
+ return parseBot(await this.#api("auth.test", {}, "Slack auth.test"));
816
+ }
817
+ /** POST chat.postEphemeral */
818
+ async postEphemeral(input) {
819
+ const body = {
820
+ channel: input.chat_id,
821
+ user: input.user_id,
822
+ text: input.text,
823
+ ...input.reply_markup !== void 0 && { blocks: input.reply_markup }
824
+ };
825
+ const messageTs = (await this.#api("chat.postEphemeral", body, "Slack chat.postEphemeral"))["message_ts"];
826
+ if (typeof messageTs === "string" && messageTs.length > 0) return { message_id: messageTs };
827
+ return { message_id: "ephemeral" };
828
+ }
829
+ /** POST conversations.list */
830
+ async listConversations(input = {}) {
831
+ const body = {
832
+ ...input.limit !== void 0 && { limit: input.limit },
833
+ ...input.cursor && { cursor: input.cursor },
834
+ ...input.types && { types: input.types }
835
+ };
836
+ return parseConversationsList(await this.#api("conversations.list", body, "Slack conversations.list"));
837
+ }
838
+ /**
839
+ * Full assistant.threads.setStatus (custom status + optional loading_messages).
840
+ * Prefer this over sendChatAction when the host already has status copy.
841
+ * @see https://docs.slack.dev/reference/methods/assistant.threads.setStatus
842
+ */
843
+ async setAssistantStatus(input) {
844
+ parseOk(await this.#api("assistant.threads.setStatus", {
845
+ channel_id: input.chat_id,
846
+ thread_ts: input.thread_ts,
847
+ status: input.status,
848
+ ...input.loading_messages && input.loading_messages.length > 0 && { loading_messages: input.loading_messages }
849
+ }, "Slack assistant.threads.setStatus"));
850
+ }
851
+ /** POST assistant.threads.setSuggestedPrompts (max 4). */
852
+ async setSuggestedPrompts(input) {
853
+ parseOk(await this.#api("assistant.threads.setSuggestedPrompts", {
854
+ channel_id: input.chat_id,
855
+ prompts: input.prompts,
856
+ ...input.thread_ts && { thread_ts: input.thread_ts },
857
+ ...input.title && { title: input.title }
858
+ }, "Slack assistant.threads.setSuggestedPrompts"));
859
+ }
860
+ /** POST views.publish — App Home for a user. */
861
+ async publishHome(input) {
862
+ parseOk(await this.#api("views.publish", {
863
+ user_id: input.user_id,
864
+ view: input.view,
865
+ ...input.hash && { hash: input.hash }
866
+ }, "Slack views.publish"));
867
+ }
868
+ /** POST chat.startStream — begins a streaming thread reply. */
869
+ async startStream(input) {
870
+ const body = {
871
+ channel: input.chat_id,
872
+ thread_ts: input.thread_ts,
873
+ ...input.markdown_text && { markdown_text: input.markdown_text },
874
+ ...input.recipient_user_id && { recipient_user_id: input.recipient_user_id },
875
+ ...input.recipient_team_id && { recipient_team_id: input.recipient_team_id },
876
+ ...input.task_display_mode && { task_display_mode: input.task_display_mode }
877
+ };
878
+ return parseStreamTs(await this.#api("chat.startStream", body, "Slack chat.startStream"));
879
+ }
880
+ /** POST chat.appendStream */
881
+ async appendStream(input) {
882
+ return parseStreamTs(await this.#api("chat.appendStream", {
883
+ channel: input.chat_id,
884
+ ts: input.message_id,
885
+ markdown_text: input.markdown_text
886
+ }, "Slack chat.appendStream"));
887
+ }
888
+ /** POST chat.stopStream */
889
+ async stopStream(input) {
890
+ const body = {
891
+ channel: input.chat_id,
892
+ ts: input.message_id,
893
+ ...input.markdown_text && { markdown_text: input.markdown_text },
894
+ ...input.blocks !== void 0 && { blocks: input.blocks }
895
+ };
896
+ return parseStreamTs(await this.#api("chat.stopStream", body, "Slack chat.stopStream"));
897
+ }
898
+ /** POST auth.revoke — disconnect installation (host-only). */
899
+ async authRevoke(input = {}) {
900
+ const body = { ...input.test !== void 0 && { test: input.test } };
901
+ return parseAuthRevoke(await this.#api("auth.revoke", body, "Slack auth.revoke"));
902
+ }
903
+ /** POST users.info */
904
+ async usersInfo(input) {
905
+ return parseUsersInfo(await this.#api("users.info", {
906
+ user: input.user_id,
907
+ ...input.include_locale !== void 0 && { include_locale: input.include_locale }
908
+ }, "Slack users.info"));
909
+ }
910
+ /** POST users.conversations */
911
+ async usersConversations(input = {}) {
912
+ const body = {
913
+ ...input.user_id && { user: input.user_id },
914
+ ...input.limit !== void 0 && { limit: input.limit },
915
+ ...input.cursor && { cursor: input.cursor },
916
+ ...input.types && { types: input.types },
917
+ ...input.exclude_archived !== void 0 && { exclude_archived: input.exclude_archived }
918
+ };
919
+ return parseConversationsList(await this.#api("users.conversations", body, "Slack users.conversations"));
920
+ }
921
+ /** POST conversations.info */
922
+ async conversationsInfo(input) {
923
+ return parseConversationInfo(await this.#api("conversations.info", {
924
+ channel: input.chat_id,
925
+ ...input.include_locale !== void 0 && { include_locale: input.include_locale },
926
+ ...input.include_num_members !== void 0 && { include_num_members: input.include_num_members }
927
+ }, "Slack conversations.info"));
928
+ }
929
+ /** POST conversations.history */
930
+ async conversationsHistory(input) {
931
+ const body = {
932
+ channel: input.chat_id,
933
+ ...input.limit !== void 0 && { limit: input.limit },
934
+ ...input.cursor && { cursor: input.cursor },
935
+ ...input.oldest && { oldest: input.oldest },
936
+ ...input.latest && { latest: input.latest },
937
+ ...input.inclusive !== void 0 && { inclusive: input.inclusive }
938
+ };
939
+ return parseConversationMessages(await this.#api("conversations.history", body, "Slack conversations.history"));
940
+ }
941
+ /** POST conversations.replies */
942
+ async conversationsReplies(input) {
943
+ const body = {
944
+ channel: input.chat_id,
945
+ ts: input.message_id,
946
+ ...input.limit !== void 0 && { limit: input.limit },
947
+ ...input.cursor && { cursor: input.cursor },
948
+ ...input.oldest && { oldest: input.oldest },
949
+ ...input.latest && { latest: input.latest },
950
+ ...input.inclusive !== void 0 && { inclusive: input.inclusive }
951
+ };
952
+ return parseConversationMessages(await this.#api("conversations.replies", body, "Slack conversations.replies"));
953
+ }
954
+ /**
955
+ * Multi-file external upload: get URL + PUT each file, then one completeUploadExternal.
956
+ * Host may pass `body` (Uint8Array) on each item instead of body_base64.
957
+ */
958
+ async sendMediaBatch(input) {
959
+ const completed = [];
960
+ for (const file of input.files) {
961
+ const { bytes, body } = resolveMediaBytes(file);
962
+ const form = new URLSearchParams();
963
+ form.set("filename", file.file_name);
964
+ form.set("length", String(bytes.byteLength));
965
+ const upload = parseUploadUrl(await this.#apiForm("files.getUploadURLExternal", form, "Slack files.getUploadURLExternal"));
966
+ let put;
967
+ try {
968
+ put = await this.#external.post(upload.upload_url, body, {
969
+ label: "Slack file upload POST",
970
+ noThrow: true,
971
+ headers: { "Content-Type": file.content_type ?? "application/octet-stream" }
972
+ });
973
+ } catch (error) {
974
+ throwSlackTransportError("Slack file upload POST", error);
975
+ }
976
+ if (!put.ok) throw new SlackClientError({
977
+ message: `Slack file upload POST failed with HTTP ${put.status}`,
978
+ failureKind: put.status === 400 || put.status === 401 || put.status === 403 || put.status === 404 ? "definite_rejection" : "outcome_unknown",
979
+ method: "Slack file upload POST",
980
+ status: put.status
981
+ });
982
+ completed.push({
983
+ id: upload.file_id,
984
+ ...file.title || file.file_name ? { title: file.title ?? file.file_name } : {}
985
+ });
986
+ }
987
+ return parseUploadBatchComplete(await this.#api("files.completeUploadExternal", {
988
+ files: completed,
989
+ channel_id: input.chat_id,
990
+ ...input.reply_to_message_id && { thread_ts: input.reply_to_message_id },
991
+ ...input.caption && { initial_comment: input.caption }
992
+ }, "Slack files.completeUploadExternal"), completed.map((f) => f.id));
993
+ }
994
+ /**
995
+ * Download file bytes for host (no base64). Tool path still uses downloadFile → body_base64.
996
+ */
997
+ async downloadFileBytes(input) {
998
+ const file = parseFileInfo(await this.#api("files.info", { file: input.file_id }, "Slack files.info"));
999
+ let res;
1000
+ try {
1001
+ res = await this.#http.bytes("GET", file.url_private_download, {
1002
+ label: "Slack downloadFileBytes",
1003
+ noThrow: true,
1004
+ headers: { Authorization: `Bearer ${this.#token}` }
1005
+ });
1006
+ } catch (error) {
1007
+ throwSlackTransportError("Slack downloadFileBytes", error);
1008
+ }
1009
+ if (!res.ok) throw new SlackClientError({
1010
+ message: `Slack downloadFileBytes failed with HTTP ${res.status}`,
1011
+ failureKind: res.status === 400 || res.status === 401 || res.status === 403 || res.status === 404 ? "definite_rejection" : "outcome_unknown",
1012
+ method: "Slack downloadFileBytes",
1013
+ status: res.status
1014
+ });
1015
+ const out = {
1016
+ file_name: input.file_name ?? file.file_name ?? file.file_id,
1017
+ body: res.bytes
1018
+ };
1019
+ if (file.file_size !== void 0) out.file_size = file.file_size;
1020
+ return out;
1021
+ }
1022
+ };
1023
+ //#endregion
1024
+ //#region src/vendors/slack/module.ts
1025
+ const emptyInputSchema = z.object({}).describe("No input fields");
1026
+ const slackSendTextTool = defineTool({
1027
+ id: "slack-send-text",
1028
+ name: "slackSendText",
1029
+ description: "Send a text message to a Slack channel or DM. Optional reply_to_message_id anchors a thread reply. Optional reply_markup is a Block Kit blocks array. Returns the new message_id (ts).",
1030
+ inputSchema: slackSendTextInputSchema,
1031
+ outputSchema: slackMessageOutputSchema,
1032
+ sideEffect: "send",
1033
+ runtime: "node",
1034
+ execute: async (input, ctx) => SlackClient.fromContext(ctx).sendText(input)
1035
+ });
1036
+ const slackEditTextTool = defineTool({
1037
+ id: "slack-edit-text",
1038
+ name: "slackEditText",
1039
+ description: "Edit the text of an existing Slack message. Used for progressive live updates and corrections.",
1040
+ inputSchema: slackEditTextInputSchema,
1041
+ outputSchema: slackMessageOutputSchema,
1042
+ sideEffect: "write",
1043
+ runtime: "node",
1044
+ execute: async (input, ctx) => SlackClient.fromContext(ctx).editText(input)
1045
+ });
1046
+ const slackSendChatActionTool = defineTool({
1047
+ id: "slack-send-chat-action",
1048
+ name: "slackSendChatAction",
1049
+ description: "Show busy status on a Slack assistant thread. Pass reply_to_message_id as the thread root ts (thread_ts) to call assistant.threads.setStatus (e.g. “is checking the request…”). Without reply_to_message_id this is a no-op (no channel-level typing API).",
1050
+ inputSchema: slackSendChatActionInputSchema,
1051
+ outputSchema: slackOkOutputSchema,
1052
+ sideEffect: "none",
1053
+ runtime: "node",
1054
+ execute: async (input, ctx) => {
1055
+ await SlackClient.fromContext(ctx).sendChatAction(input);
1056
+ return { ok: true };
1057
+ }
1058
+ });
1059
+ const slackSetReactionTool = defineTool({
1060
+ id: "slack-set-reaction",
1061
+ name: "slackSetReaction",
1062
+ description: "Add an emoji reaction on a Slack message. Pass the emoji name with or without colons (e.g. thumbsup or :thumbsup:).",
1063
+ inputSchema: slackSetReactionInputSchema,
1064
+ outputSchema: slackOkOutputSchema,
1065
+ sideEffect: "write",
1066
+ runtime: "node",
1067
+ execute: async (input, ctx) => {
1068
+ await SlackClient.fromContext(ctx).setReaction(input);
1069
+ return { ok: true };
1070
+ }
1071
+ });
1072
+ const slackClearReactionTool = defineTool({
1073
+ id: "slack-clear-reaction",
1074
+ name: "slackClearReaction",
1075
+ description: "Remove one emoji reaction the bot added on a Slack message. emoji is required (Slack cannot clear all reactions in one call).",
1076
+ inputSchema: slackClearReactionInputSchema,
1077
+ outputSchema: slackOkOutputSchema,
1078
+ sideEffect: "write",
1079
+ runtime: "node",
1080
+ execute: async (input, ctx) => {
1081
+ await SlackClient.fromContext(ctx).clearReaction(input);
1082
+ return { ok: true };
1083
+ }
1084
+ });
1085
+ const slackSendMediaTool = defineTool({
1086
+ id: "slack-send-media",
1087
+ name: "slackSendMedia",
1088
+ description: "Upload one photo or document to a Slack channel from a base64 body (external upload flow). Optional caption becomes the initial comment.",
1089
+ inputSchema: slackSendMediaInputSchema,
1090
+ outputSchema: slackMessageOutputSchema,
1091
+ sideEffect: "send",
1092
+ runtime: "node",
1093
+ execute: async (input, ctx) => SlackClient.fromContext(ctx).sendMedia(input)
1094
+ });
1095
+ const slackDownloadFileTool = defineTool({
1096
+ id: "slack-download-file",
1097
+ name: "slackDownloadFile",
1098
+ description: "Download a Slack file by file_id and return the body as base64 with optional size and name.",
1099
+ inputSchema: slackDownloadFileInputSchema,
1100
+ outputSchema: slackDownloadFileOutputSchema,
1101
+ sideEffect: "read",
1102
+ runtime: "node",
1103
+ execute: async (input, ctx) => SlackClient.fromContext(ctx).downloadFile(input)
1104
+ });
1105
+ const slackAnswerCallbackTool = defineTool({
1106
+ id: "slack-answer-callback",
1107
+ name: "slackAnswerCallback",
1108
+ description: "Acknowledge a Slack interactive payload. When callback_query_id is a response_url, posts an ephemeral reply. Otherwise succeeds without a network call.",
1109
+ inputSchema: slackAnswerCallbackInputSchema,
1110
+ outputSchema: slackOkOutputSchema,
1111
+ sideEffect: "write",
1112
+ runtime: "node",
1113
+ execute: async (input, ctx) => {
1114
+ await SlackClient.fromContext(ctx).answerCallback(input);
1115
+ return { ok: true };
1116
+ }
1117
+ });
1118
+ const slackGetBotTool = defineTool({
1119
+ id: "slack-get-bot",
1120
+ name: "slackGetBot",
1121
+ description: "Return the current Slack bot identity, including bot_id, username, and display_name.",
1122
+ inputSchema: emptyInputSchema,
1123
+ outputSchema: slackGetBotOutputSchema,
1124
+ sideEffect: "read",
1125
+ runtime: "node",
1126
+ execute: async (_input, ctx) => SlackClient.fromContext(ctx).getBot()
1127
+ });
1128
+ const slackModule = defineModule({
1129
+ id: "slack",
1130
+ title: "Slack",
1131
+ description: "Slack Web API vendor pack: text, media upload, chat-action parity, reactions, file download, interactive callbacks, bot identity. Expand with more Web API methods over time. Not a multi-provider messaging seam.",
1132
+ runtime: "node",
1133
+ auth: {
1134
+ type: "custom",
1135
+ schema: slackAuthSchema
1136
+ },
1137
+ categories: ["messaging", "chat"],
1138
+ classification: "pii",
1139
+ tags: ["slack"],
1140
+ tools: [
1141
+ slackSendTextTool,
1142
+ slackEditTextTool,
1143
+ slackSendChatActionTool,
1144
+ slackSetReactionTool,
1145
+ slackClearReactionTool,
1146
+ slackSendMediaTool,
1147
+ slackDownloadFileTool,
1148
+ slackAnswerCallbackTool,
1149
+ slackGetBotTool
1150
+ ]
1151
+ });
1152
+ //#endregion
1153
+ //#region src/vendors/slack/reference.ts
1154
+ /**
1155
+ * Pure Slack mrkdwn / reference helpers (no HTTP).
1156
+ * Host uses these when resolving mentions, channel refs, and permalinks for tools.
1157
+ */
1158
+ /** User mention: `<@U123>` or `<@U123|label>` → user id. */
1159
+ const USER_MENTION = /<@([UW][A-Z0-9]+)(?:\|[^>]*)?>/g;
1160
+ /** Channel reference: `<#C123>` or `<#C123|name>` → channel id. */
1161
+ const CHANNEL_REF = /<#([CGD][A-Z0-9]+)(?:\|[^>]*)?>/g;
1162
+ /** Special commands / mailto / bare links in angle brackets. */
1163
+ const SPECIAL_CMD = /<!([^>|]+)(?:\|[^>]*)?>/g;
1164
+ /**
1165
+ * Extract Slack user ids mentioned in message text (`<@U…>`).
1166
+ */
1167
+ function extractSlackUserMentions(text) {
1168
+ const ids = [];
1169
+ const seen = /* @__PURE__ */ new Set();
1170
+ USER_MENTION.lastIndex = 0;
1171
+ let match;
1172
+ while ((match = USER_MENTION.exec(text)) !== null) {
1173
+ const id = match[1];
1174
+ if (id && !seen.has(id)) {
1175
+ seen.add(id);
1176
+ ids.push(id);
1177
+ }
1178
+ }
1179
+ return ids;
1180
+ }
1181
+ /**
1182
+ * Extract channel ids from `<#C…>` references in text.
1183
+ */
1184
+ function extractSlackChannelRefs(text) {
1185
+ const ids = [];
1186
+ const seen = /* @__PURE__ */ new Set();
1187
+ CHANNEL_REF.lastIndex = 0;
1188
+ let match;
1189
+ while ((match = CHANNEL_REF.exec(text)) !== null) {
1190
+ const id = match[1];
1191
+ if (id && !seen.has(id)) {
1192
+ seen.add(id);
1193
+ ids.push(id);
1194
+ }
1195
+ }
1196
+ return ids;
1197
+ }
1198
+ /**
1199
+ * Format a user mention for outgoing mrkdwn.
1200
+ */
1201
+ function formatSlackUserMention(userId, label) {
1202
+ return label && label.length > 0 ? `<@${userId}|${label}>` : `<@${userId}>`;
1203
+ }
1204
+ /**
1205
+ * Format a channel reference for outgoing mrkdwn.
1206
+ */
1207
+ function formatSlackChannelRef(channelId, name) {
1208
+ return name && name.length > 0 ? `<#${channelId}|${name}>` : `<#${channelId}>`;
1209
+ }
1210
+ /**
1211
+ * Build an app message permalink.
1212
+ * @see https://api.slack.com/methods/chat.getPermalink (host may also call the API)
1213
+ */
1214
+ function formatSlackMessagePermalink(input) {
1215
+ const domain = input.team_domain.replace(/^https?:\/\//, "").replace(/\.slack\.com\/?$/, "");
1216
+ const ts = input.message_id.replace(".", "");
1217
+ return `https://${domain}.slack.com/archives/${input.chat_id}/p${ts}`;
1218
+ }
1219
+ /**
1220
+ * Strip a leading bot user mention from inbound text (common in channels with @bot).
1221
+ * Only removes a mention of `botUserId` at the start (optional surrounding whitespace).
1222
+ */
1223
+ function stripLeadingSlackBotMention(text, botUserId) {
1224
+ if (!botUserId) return text;
1225
+ const escaped = botUserId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1226
+ const re = new RegExp(`^\\s*<@${escaped}(?:\\|[^>]*)?>\\s*`);
1227
+ return text.replace(re, "");
1228
+ }
1229
+ /**
1230
+ * Lightweight mrkdwn → plain-ish text for logging / model context (not full Slack rendering).
1231
+ * Removes mention markup, channel refs, and special commands; keeps link labels when present.
1232
+ */
1233
+ function slackMrkdwnToPlainText(text) {
1234
+ let out = text;
1235
+ out = out.replace(USER_MENTION, (_m, id) => `@${id}`);
1236
+ out = out.replace(CHANNEL_REF, (_m, id) => `#${id}`);
1237
+ out = out.replace(SPECIAL_CMD, (_m, cmd) => `@${cmd}`);
1238
+ out = out.replace(/<([^|>]+)\|([^>]+)>/g, "$2");
1239
+ out = out.replace(/<([^>]+)>/g, "$1");
1240
+ return out;
1241
+ }
1242
+ //#endregion
1243
+ //#region src/vendors/slack/webhook.ts
1244
+ /**
1245
+ * Verify Slack request signature (X-Slack-Signature).
1246
+ * HMAC-SHA256 of `v0:{timestamp}:{raw_body}` compared to `v0={hex}`.
1247
+ * Rejects empty inputs and timestamps older/newer than maxAgeSeconds (default 5 minutes).
1248
+ */
1249
+ function verifySlackRequestSignature(input) {
1250
+ const { signing_secret, raw_body, timestamp, signature } = input;
1251
+ if (!signing_secret || !timestamp || !signature) return false;
1252
+ if (!/^\d+$/.test(timestamp)) return false;
1253
+ const maxAge = input.maxAgeSeconds ?? 300;
1254
+ const now = input.nowSeconds ?? Math.floor(Date.now() / 1e3);
1255
+ const ts = Number.parseInt(timestamp, 10);
1256
+ if (!Number.isFinite(ts) || Math.abs(now - ts) > maxAge) return false;
1257
+ const base = `v0:${timestamp}:${raw_body}`;
1258
+ const expected = `v0=${createHmac("sha256", signing_secret).update(base, "utf8").digest("hex")}`;
1259
+ const a = Buffer.from(expected, "utf8");
1260
+ const b = Buffer.from(signature, "utf8");
1261
+ if (a.byteLength !== b.byteLength) return false;
1262
+ return timingSafeEqual(a, b);
1263
+ }
1264
+ /**
1265
+ * Parse one raw Slack Events API / interactive body into a normalized inbound event.
1266
+ * Handles url_verification challenges, event_callback messages, and interactive payloads.
1267
+ */
1268
+ function parseSlackEvent(body, options) {
1269
+ if (isString(body)) return parseSlackEvent(tryParseJson(body) ?? tryParsePayloadForm(body) ?? body, options);
1270
+ if (!isPlainObject(body)) return {
1271
+ ok: false,
1272
+ reason: "body_not_object"
1273
+ };
1274
+ const receivedAt = options?.received_at ?? (/* @__PURE__ */ new Date()).toISOString();
1275
+ const allowGroups = options?.allow_group_chats ?? true;
1276
+ if (body["type"] === "url_verification" && isString(body["challenge"])) return {
1277
+ ok: true,
1278
+ challenge: body["challenge"]
1279
+ };
1280
+ if (body["type"] === "event_callback" && isPlainObject(body["event"])) return parseEventCallback(body, body["event"], receivedAt, allowGroups);
1281
+ if (isInteractionType(body["type"])) return parseInteraction(body, receivedAt);
1282
+ if (isString(body["type"]) && (body["type"] === "message" || body["type"] === "app_mention")) {
1283
+ const teamId = isString(body["team"]) ? body["team"] : void 0;
1284
+ return parseMessageEvent(body, {
1285
+ eventId: firstString(body["event_ts"], body["ts"]) ?? "unknown",
1286
+ receivedAt,
1287
+ allowGroups,
1288
+ rawType: body["type"],
1289
+ ...teamId && { teamId }
1290
+ });
1291
+ }
1292
+ return {
1293
+ ok: false,
1294
+ reason: "unsupported_event_type"
1295
+ };
1296
+ }
1297
+ function parseEventCallback(envelope, event, receivedAt, allowGroups) {
1298
+ const eventId = firstString(envelope["event_id"], event["event_ts"], event["ts"]);
1299
+ if (!eventId) return {
1300
+ ok: false,
1301
+ reason: "missing_event_id"
1302
+ };
1303
+ const teamId = isString(envelope["team_id"]) ? envelope["team_id"] : void 0;
1304
+ const type = isString(event["type"]) ? event["type"] : "unknown";
1305
+ if (type === "message" || type === "app_mention") return parseMessageEvent(event, {
1306
+ eventId,
1307
+ receivedAt,
1308
+ allowGroups,
1309
+ rawType: type,
1310
+ ...teamId && { teamId }
1311
+ });
1312
+ return {
1313
+ ok: false,
1314
+ reason: "unsupported_event_type"
1315
+ };
1316
+ }
1317
+ function parseMessageEvent(event, ctx) {
1318
+ const subtype = isString(event["subtype"]) ? event["subtype"] : void 0;
1319
+ if (subtype && subtype !== "file_share") return {
1320
+ ok: false,
1321
+ reason: "unsupported_message_subtype"
1322
+ };
1323
+ const chatId = firstString(event["channel"]);
1324
+ if (!chatId) return {
1325
+ ok: false,
1326
+ reason: "missing_channel"
1327
+ };
1328
+ const channelType = firstString(event["channel_type"]);
1329
+ if (!ctx.allowGroups && channelType && channelType !== "im" && channelType !== "mpim") return {
1330
+ ok: false,
1331
+ reason: "non_dm_chat"
1332
+ };
1333
+ const userId = firstString(event["user"]);
1334
+ const messageId = firstString(event["ts"]);
1335
+ const text = firstString(event["text"]);
1336
+ const media = collectMedia(event);
1337
+ const replyTo = firstString(event["thread_ts"]);
1338
+ const replyToParent = replyTo && messageId && replyTo !== messageId ? replyTo : void 0;
1339
+ if (!text && media.length === 0) return {
1340
+ ok: false,
1341
+ reason: "empty_message"
1342
+ };
1343
+ return {
1344
+ ok: true,
1345
+ event: {
1346
+ channel: "slack",
1347
+ event_id: ctx.eventId,
1348
+ chat_id: chatId,
1349
+ raw_type: ctx.rawType,
1350
+ received_at: ctx.receivedAt,
1351
+ ...userId && { user_id: userId },
1352
+ ...messageId && { message_id: messageId },
1353
+ ...text && { text },
1354
+ ...media.length > 0 && { media },
1355
+ ...replyToParent && { reply_to: replyToParent },
1356
+ ...channelType && { chat_type: channelType },
1357
+ ...ctx.teamId && { team_id: ctx.teamId }
1358
+ }
1359
+ };
1360
+ }
1361
+ function parseInteraction(body, receivedAt) {
1362
+ const type = isString(body["type"]) ? body["type"] : "interaction";
1363
+ const channel = body["channel"];
1364
+ const chatId = isPlainObject(channel) ? firstString(channel["id"]) : firstString(body["channel_id"], body["channel"]);
1365
+ if (!chatId) return {
1366
+ ok: false,
1367
+ reason: "interaction_missing_channel"
1368
+ };
1369
+ const user = body["user"];
1370
+ const userId = isPlainObject(user) ? firstString(user["id"]) : firstString(body["user_id"]);
1371
+ const username = isPlainObject(user) ? firstString(user["username"], user["name"]) : void 0;
1372
+ const message = body["message"];
1373
+ const messageId = isPlainObject(message) ? firstString(message["ts"]) : firstString(body["message_ts"]);
1374
+ const responseUrl = firstString(body["response_url"]);
1375
+ const callbackData = extractCallbackData(body);
1376
+ const team = body["team"];
1377
+ const teamId = isPlainObject(team) ? firstString(team["id"]) : firstString(body["team_id"]);
1378
+ return {
1379
+ ok: true,
1380
+ event: {
1381
+ channel: "slack",
1382
+ event_id: firstString(body["trigger_id"], responseUrl, messageId) ?? `${type}:${chatId}`,
1383
+ chat_id: chatId,
1384
+ raw_type: type,
1385
+ received_at: receivedAt,
1386
+ ...userId && { user_id: userId },
1387
+ ...username && { username },
1388
+ ...messageId && { message_id: messageId },
1389
+ ...responseUrl && { callback_query_id: responseUrl },
1390
+ ...callbackData && { callback_data: callbackData },
1391
+ ...teamId && { team_id: teamId }
1392
+ }
1393
+ };
1394
+ }
1395
+ function extractCallbackData(body) {
1396
+ const actions = body["actions"];
1397
+ if (Array.isArray(actions) && actions.length > 0) {
1398
+ const first = actions[0];
1399
+ if (isPlainObject(first)) {
1400
+ const selected = first["selected_option"];
1401
+ const selectedValue = isPlainObject(selected) ? selected["value"] : void 0;
1402
+ return firstString(first["value"], first["action_id"], selectedValue);
1403
+ }
1404
+ }
1405
+ const view = body["view"];
1406
+ if (isPlainObject(view) && isString(view["callback_id"])) return view["callback_id"];
1407
+ return firstString(body["callback_id"]);
1408
+ }
1409
+ function collectMedia(event) {
1410
+ const out = [];
1411
+ const files = event["files"];
1412
+ if (!Array.isArray(files)) return out;
1413
+ for (const file of files) {
1414
+ if (!isPlainObject(file) || !isString(file["id"])) continue;
1415
+ const mimetype = isString(file["mimetype"]) ? file["mimetype"] : void 0;
1416
+ const kind = mimetype?.startsWith("image/") ? "photo" : "document";
1417
+ out.push({
1418
+ kind,
1419
+ ref: file["id"],
1420
+ ...isString(file["name"]) && { file_name: file["name"] },
1421
+ ...typeof file["size"] === "number" && { file_size: file["size"] },
1422
+ ...mimetype && { media_type: mimetype },
1423
+ ...isString(file["file_access"]) && { unique_ref: file["file_access"] }
1424
+ });
1425
+ }
1426
+ return out;
1427
+ }
1428
+ function isInteractionType(type) {
1429
+ return type === "block_actions" || type === "interactive_message" || type === "shortcut" || type === "message_action" || type === "view_submission" || type === "view_closed" || type === "slash_command";
1430
+ }
1431
+ function tryParseJson(raw) {
1432
+ try {
1433
+ return JSON.parse(raw);
1434
+ } catch {
1435
+ return;
1436
+ }
1437
+ }
1438
+ /** Interactive endpoints often post `payload=<urlencoded json>`. */
1439
+ function tryParsePayloadForm(raw) {
1440
+ if (!raw.includes("payload=")) return void 0;
1441
+ try {
1442
+ const payload = new URLSearchParams(raw).get("payload");
1443
+ if (!payload) return void 0;
1444
+ return JSON.parse(payload);
1445
+ } catch {
1446
+ return;
1447
+ }
1448
+ }
1449
+ function firstString(...values) {
1450
+ for (const value of values) if (isString(value) && value.length > 0) return value;
1451
+ }
1452
+ //#endregion
1453
+ export { slackSetAssistantStatusInputSchema as $, slackAuthSchema as A, slackGetBotOutputSchema as B, isSlackOutcomeUnknown as C, slackAppendStreamInputSchema as D, slackAnswerCallbackInputSchema as E, slackConversationMessagesOutputSchema as F, slackPostEphemeralInputSchema as G, slackListConversationsOutputSchema as H, slackConversationRepliesInputSchema as I, slackSendMediaBatchInputSchema as J, slackPublishHomeInputSchema as K, slackDownloadFileInputSchema as L, slackConversationHistoryInputSchema as M, slackConversationInfoInputSchema as N, slackAuthRevokeInputSchema as O, slackConversationInfoOutputSchema as P, slackSendTextInputSchema as Q, slackDownloadFileOutputSchema as R, isSlackDefiniteRejection as S, MAX_SLACK_MEDIA_BATCH as T, slackMessageOutputSchema as U, slackListConversationsInputSchema as V, slackOkOutputSchema as W, slackSendMediaBatchOutputSchema as X, slackSendMediaBatchItemSchema as Y, slackSendMediaInputSchema as Z, slackSendMediaTool as _, formatSlackChannelRef as a, slackUsersConversationsInputSchema as at, SlackClient as b, slackMrkdwnToPlainText as c, slackClearReactionTool as d, slackSetReactionInputSchema as et, slackDownloadFileTool as f, slackSendChatActionTool as g, slackModule as h, extractSlackUserMentions as i, slackStopTypingInputSchema as it, slackClearReactionInputSchema as j, slackAuthRevokeOutputSchema as k, stripLeadingSlackBotMention as l, slackGetBotTool as m, verifySlackRequestSignature as n, slackStartStreamInputSchema as nt, formatSlackMessagePermalink as o, slackUsersInfoInputSchema as ot, slackEditTextTool as p, slackSendChatActionInputSchema as q, extractSlackChannelRefs as r, slackStopStreamInputSchema as rt, formatSlackUserMention as s, slackUsersInfoOutputSchema as st, parseSlackEvent as t, slackSetSuggestedPromptsInputSchema as tt, slackAnswerCallbackTool as u, slackSendTextTool as v, MAX_MEDIA_BYTES as w, SlackClientError as x, slackSetReactionTool as y, slackEditTextInputSchema as z };
1454
+
1455
+ //# sourceMappingURL=slack-Di5BBNpt.js.map