agent-messenger 2.10.2 → 2.11.0

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 (330) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.env.template +4 -1
  3. package/README.md +77 -27
  4. package/bun.lock +26 -0
  5. package/dist/package.json +14 -1
  6. package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
  7. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  8. package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
  9. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
  11. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  12. package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
  13. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  14. package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
  15. package/dist/src/platforms/channeltalkbot/cli.js +11 -1
  16. package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
  17. package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
  18. package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
  19. package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
  20. package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
  21. package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
  22. package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
  23. package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
  24. package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
  25. package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
  26. package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
  27. package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
  28. package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
  29. package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
  30. package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
  31. package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
  32. package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
  33. package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
  34. package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
  35. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
  36. package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
  37. package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
  38. package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
  39. package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
  40. package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
  41. package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
  42. package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
  43. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  44. package/dist/src/platforms/discord/commands/auth.js +3 -1
  45. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  46. package/dist/src/platforms/discord/listener.d.ts +2 -0
  47. package/dist/src/platforms/discord/listener.d.ts.map +1 -1
  48. package/dist/src/platforms/discord/listener.js +51 -21
  49. package/dist/src/platforms/discord/listener.js.map +1 -1
  50. package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
  51. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  52. package/dist/src/platforms/discord/token-extractor.js +21 -6
  53. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  54. package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
  55. package/dist/src/platforms/discordbot/cli.js +12 -1
  56. package/dist/src/platforms/discordbot/cli.js.map +1 -1
  57. package/dist/src/platforms/discordbot/client.d.ts +3 -0
  58. package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
  59. package/dist/src/platforms/discordbot/client.js +3 -0
  60. package/dist/src/platforms/discordbot/client.js.map +1 -1
  61. package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
  62. package/dist/src/platforms/discordbot/commands/auth.js +1 -5
  63. package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
  64. package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
  65. package/dist/src/platforms/discordbot/commands/message.js +1 -6
  66. package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
  67. package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
  68. package/dist/src/platforms/discordbot/commands/server.js +1 -4
  69. package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
  70. package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
  71. package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
  72. package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
  73. package/dist/src/platforms/discordbot/index.d.ts +3 -1
  74. package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
  75. package/dist/src/platforms/discordbot/index.js +2 -1
  76. package/dist/src/platforms/discordbot/index.js.map +1 -1
  77. package/dist/src/platforms/discordbot/listener.d.ts +43 -0
  78. package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
  79. package/dist/src/platforms/discordbot/listener.js +292 -0
  80. package/dist/src/platforms/discordbot/listener.js.map +1 -0
  81. package/dist/src/platforms/discordbot/types.d.ts +161 -0
  82. package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
  83. package/dist/src/platforms/discordbot/types.js +34 -0
  84. package/dist/src/platforms/discordbot/types.js.map +1 -1
  85. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  86. package/dist/src/platforms/instagram/commands/auth.js +3 -1
  87. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  88. package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
  89. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
  90. package/dist/src/platforms/instagram/token-extractor.js +11 -2
  91. package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
  92. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  93. package/dist/src/platforms/slack/commands/auth.js +4 -2
  94. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  95. package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
  96. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  97. package/dist/src/platforms/slack/token-extractor.js +64 -15
  98. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  99. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  100. package/dist/src/platforms/slackbot/cli.js +15 -3
  101. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  102. package/dist/src/platforms/slackbot/client.d.ts +22 -1
  103. package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
  104. package/dist/src/platforms/slackbot/client.js +104 -1
  105. package/dist/src/platforms/slackbot/client.js.map +1 -1
  106. package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
  107. package/dist/src/platforms/slackbot/commands/auth.js +1 -5
  108. package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
  109. package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
  110. package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
  111. package/dist/src/platforms/slackbot/commands/file.js +164 -0
  112. package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
  113. package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
  114. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
  115. package/dist/src/platforms/slackbot/commands/index.js +1 -0
  116. package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
  117. package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
  118. package/dist/src/platforms/slackbot/commands/message.js +19 -0
  119. package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
  120. package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
  121. package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
  122. package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
  123. package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
  124. package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
  125. package/dist/src/platforms/slackbot/credential-manager.js +30 -2
  126. package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
  127. package/dist/src/platforms/slackbot/index.d.ts +4 -1
  128. package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
  129. package/dist/src/platforms/slackbot/index.js +1 -0
  130. package/dist/src/platforms/slackbot/index.js.map +1 -1
  131. package/dist/src/platforms/slackbot/listener.d.ts +44 -0
  132. package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
  133. package/dist/src/platforms/slackbot/listener.js +313 -0
  134. package/dist/src/platforms/slackbot/listener.js.map +1 -0
  135. package/dist/src/platforms/slackbot/types.d.ts +196 -1
  136. package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
  137. package/dist/src/platforms/slackbot/types.js +4 -1
  138. package/dist/src/platforms/slackbot/types.js.map +1 -1
  139. package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
  140. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  141. package/dist/src/platforms/teams/commands/auth.js +37 -6
  142. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  143. package/dist/src/platforms/teams/ensure-auth.js +31 -9
  144. package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
  145. package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
  146. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  147. package/dist/src/platforms/teams/token-extractor.js +71 -29
  148. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  149. package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
  150. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  151. package/dist/src/platforms/webex/commands/auth.js +3 -1
  152. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  153. package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
  154. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  155. package/dist/src/platforms/webex/token-extractor.js +16 -2
  156. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  157. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
  158. package/dist/src/platforms/wechatbot/cli.js +11 -1
  159. package/dist/src/platforms/wechatbot/cli.js.map +1 -1
  160. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
  161. package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
  162. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
  163. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
  164. package/dist/src/platforms/wechatbot/commands/message.js +1 -6
  165. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
  166. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
  167. package/dist/src/platforms/wechatbot/commands/template.js +1 -6
  168. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
  169. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
  170. package/dist/src/platforms/wechatbot/commands/user.js +1 -6
  171. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
  172. package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
  173. package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
  174. package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
  175. package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
  176. package/dist/src/platforms/whatsappbot/cli.js +11 -1
  177. package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
  178. package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
  179. package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
  180. package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
  181. package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
  182. package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
  183. package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
  184. package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
  185. package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
  186. package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
  187. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
  188. package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
  189. package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
  190. package/dist/src/shared/chromium/browsers.d.ts +8 -0
  191. package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
  192. package/dist/src/shared/chromium/browsers.js +58 -3
  193. package/dist/src/shared/chromium/browsers.js.map +1 -1
  194. package/dist/src/shared/chromium/cli-options.d.ts +5 -0
  195. package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
  196. package/dist/src/shared/chromium/cli-options.js +8 -0
  197. package/dist/src/shared/chromium/cli-options.js.map +1 -0
  198. package/dist/src/shared/chromium/index.d.ts +3 -1
  199. package/dist/src/shared/chromium/index.d.ts.map +1 -1
  200. package/dist/src/shared/chromium/index.js +2 -1
  201. package/dist/src/shared/chromium/index.js.map +1 -1
  202. package/dist/src/shared/utils/cli-output.d.ts +7 -0
  203. package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
  204. package/dist/src/shared/utils/cli-output.js +7 -0
  205. package/dist/src/shared/utils/cli-output.js.map +1 -0
  206. package/dist/src/tui/app.d.ts.map +1 -1
  207. package/dist/src/tui/app.js +73 -20
  208. package/dist/src/tui/app.js.map +1 -1
  209. package/docs/content/docs/cli/channeltalk.mdx +4 -0
  210. package/docs/content/docs/cli/discord.mdx +5 -0
  211. package/docs/content/docs/cli/instagram.mdx +3 -0
  212. package/docs/content/docs/cli/slack.mdx +5 -0
  213. package/docs/content/docs/cli/slackbot.mdx +60 -22
  214. package/docs/content/docs/cli/teams.mdx +5 -0
  215. package/docs/content/docs/cli/webex.mdx +3 -0
  216. package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
  217. package/docs/content/docs/sdk/discordbot.mdx +501 -0
  218. package/docs/content/docs/sdk/meta.json +2 -0
  219. package/docs/content/docs/sdk/slackbot.mdx +576 -0
  220. package/e2e/README.md +1 -1
  221. package/e2e/config.ts +9 -4
  222. package/examples/discordbot-listen.ts +65 -0
  223. package/examples/slackbot-listen.ts +65 -0
  224. package/package.json +14 -1
  225. package/skills/agent-channeltalk/SKILL.md +5 -1
  226. package/skills/agent-channeltalk/references/authentication.md +5 -1
  227. package/skills/agent-channeltalkbot/SKILL.md +17 -3
  228. package/skills/agent-channeltalkbot/references/authentication.md +7 -5
  229. package/skills/agent-discord/SKILL.md +5 -1
  230. package/skills/agent-discord/references/authentication.md +7 -1
  231. package/skills/agent-discordbot/SKILL.md +13 -2
  232. package/skills/agent-discordbot/references/common-patterns.md +1 -1
  233. package/skills/agent-instagram/SKILL.md +7 -1
  234. package/skills/agent-instagram/references/authentication.md +6 -0
  235. package/skills/agent-kakaotalk/SKILL.md +1 -1
  236. package/skills/agent-line/SKILL.md +1 -1
  237. package/skills/agent-slack/SKILL.md +5 -1
  238. package/skills/agent-slack/references/authentication.md +7 -1
  239. package/skills/agent-slackbot/SKILL.md +56 -4
  240. package/skills/agent-slackbot/references/authentication.md +4 -0
  241. package/skills/agent-teams/SKILL.md +5 -1
  242. package/skills/agent-teams/references/authentication.md +7 -1
  243. package/skills/agent-telegram/SKILL.md +1 -1
  244. package/skills/agent-webex/SKILL.md +7 -1
  245. package/skills/agent-webex/references/authentication.md +6 -0
  246. package/skills/agent-wechatbot/SKILL.md +16 -1
  247. package/skills/agent-wechatbot/references/authentication.md +219 -0
  248. package/skills/agent-wechatbot/references/common-patterns.md +358 -0
  249. package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
  250. package/skills/agent-wechatbot/templates/post-message.sh +122 -0
  251. package/skills/agent-wechatbot/templates/send-template.sh +152 -0
  252. package/skills/agent-whatsapp/SKILL.md +1 -1
  253. package/skills/agent-whatsappbot/SKILL.md +30 -1
  254. package/src/platforms/channeltalk/commands/auth.test.ts +15 -3
  255. package/src/platforms/channeltalk/commands/auth.ts +15 -5
  256. package/src/platforms/channeltalk/token-extractor.ts +24 -5
  257. package/src/platforms/channeltalkbot/cli.ts +9 -0
  258. package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
  259. package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
  260. package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
  261. package/src/platforms/channeltalkbot/commands/group.ts +1 -6
  262. package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
  263. package/src/platforms/channeltalkbot/commands/message.ts +1 -6
  264. package/src/platforms/channeltalkbot/commands/whoami.test.ts +2 -0
  265. package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
  266. package/src/platforms/channeltalkbot/credential-manager.test.ts +96 -2
  267. package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
  268. package/src/platforms/discord/commands/auth.ts +13 -2
  269. package/src/platforms/discord/listener.test.ts +59 -1
  270. package/src/platforms/discord/listener.ts +43 -19
  271. package/src/platforms/discord/token-extractor.ts +30 -6
  272. package/src/platforms/discordbot/cli.ts +10 -0
  273. package/src/platforms/discordbot/client.ts +4 -0
  274. package/src/platforms/discordbot/commands/auth.ts +1 -5
  275. package/src/platforms/discordbot/commands/message.ts +1 -6
  276. package/src/platforms/discordbot/commands/server.ts +1 -5
  277. package/src/platforms/discordbot/commands/whoami.ts +1 -6
  278. package/src/platforms/discordbot/index.test.ts +82 -0
  279. package/src/platforms/discordbot/index.ts +27 -9
  280. package/src/platforms/discordbot/listener.test.ts +1002 -0
  281. package/src/platforms/discordbot/listener.ts +321 -0
  282. package/src/platforms/discordbot/types.ts +163 -0
  283. package/src/platforms/instagram/commands/auth.ts +9 -1
  284. package/src/platforms/instagram/token-extractor.ts +13 -1
  285. package/src/platforms/slack/commands/auth.ts +11 -2
  286. package/src/platforms/slack/token-extractor.test.ts +96 -0
  287. package/src/platforms/slack/token-extractor.ts +76 -13
  288. package/src/platforms/slackbot/cli.ts +13 -1
  289. package/src/platforms/slackbot/client.test.ts +274 -0
  290. package/src/platforms/slackbot/client.ts +130 -2
  291. package/src/platforms/slackbot/commands/auth.ts +1 -5
  292. package/src/platforms/slackbot/commands/file.test.ts +201 -0
  293. package/src/platforms/slackbot/commands/file.ts +212 -0
  294. package/src/platforms/slackbot/commands/index.ts +1 -0
  295. package/src/platforms/slackbot/commands/message.ts +22 -0
  296. package/src/platforms/slackbot/commands/whoami.ts +1 -6
  297. package/src/platforms/slackbot/credential-manager.test.ts +62 -2
  298. package/src/platforms/slackbot/credential-manager.ts +32 -2
  299. package/src/platforms/slackbot/index.test.ts +59 -0
  300. package/src/platforms/slackbot/index.ts +31 -7
  301. package/src/platforms/slackbot/listener.test.ts +1012 -0
  302. package/src/platforms/slackbot/listener.ts +362 -0
  303. package/src/platforms/slackbot/types.ts +224 -1
  304. package/src/platforms/teams/commands/auth.test.ts +1 -1
  305. package/src/platforms/teams/commands/auth.ts +66 -7
  306. package/src/platforms/teams/ensure-auth.test.ts +56 -5
  307. package/src/platforms/teams/ensure-auth.ts +39 -11
  308. package/src/platforms/teams/token-extractor.test.ts +146 -24
  309. package/src/platforms/teams/token-extractor.ts +87 -29
  310. package/src/platforms/webex/commands/auth.ts +13 -2
  311. package/src/platforms/webex/token-extractor.ts +25 -3
  312. package/src/platforms/wechatbot/cli.ts +9 -0
  313. package/src/platforms/wechatbot/commands/auth.ts +1 -5
  314. package/src/platforms/wechatbot/commands/message.ts +1 -6
  315. package/src/platforms/wechatbot/commands/template.ts +1 -6
  316. package/src/platforms/wechatbot/commands/user.ts +1 -6
  317. package/src/platforms/wechatbot/commands/whoami.ts +1 -6
  318. package/src/platforms/whatsappbot/cli.ts +9 -0
  319. package/src/platforms/whatsappbot/commands/auth.ts +1 -5
  320. package/src/platforms/whatsappbot/commands/message.ts +1 -6
  321. package/src/platforms/whatsappbot/commands/template.ts +1 -6
  322. package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
  323. package/src/shared/chromium/browsers.test.ts +80 -0
  324. package/src/shared/chromium/browsers.ts +72 -3
  325. package/src/shared/chromium/cli-options.test.ts +22 -0
  326. package/src/shared/chromium/cli-options.ts +12 -0
  327. package/src/shared/chromium/index.ts +3 -0
  328. package/src/shared/utils/cli-output.test.ts +57 -0
  329. package/src/shared/utils/cli-output.ts +8 -0
  330. package/src/tui/app.ts +129 -20
@@ -0,0 +1,362 @@
1
+ import { EventEmitter } from 'events'
2
+
3
+ import WebSocket from 'ws'
4
+
5
+ import type { SlackBotClient } from './client'
6
+ import { SlackBotError } from './types'
7
+ import type {
8
+ SlackBotListenerEventMap,
9
+ SlackSocketModeAck,
10
+ SlackSocketModeEnvelope,
11
+ SlackSocketModeEventsApiArgs,
12
+ SlackSocketModeEventsApiEnvelope,
13
+ SlackSocketModeGenericEvent,
14
+ SlackSocketModeInteractiveArgs,
15
+ SlackSocketModeInteractiveEnvelope,
16
+ SlackSocketModeSlashCommandArgs,
17
+ SlackSocketModeSlashCommandEnvelope,
18
+ } from './types'
19
+
20
+ const RECONNECT_BASE_DELAY = 1_000
21
+ const RECONNECT_MAX_DELAY = 30_000
22
+ const PING_INTERVAL = 30_000
23
+ const PONG_TIMEOUT = 10_000
24
+ const HELLO_TIMEOUT = 10_000
25
+
26
+ const FATAL_ERROR_CODES = new Set([
27
+ 'not_authed',
28
+ 'invalid_auth',
29
+ 'account_inactive',
30
+ 'user_removed_from_team',
31
+ 'team_disabled',
32
+ 'not_allowed_token_type',
33
+ 'missing_app_token',
34
+ 'invalid_app_token_type',
35
+ ])
36
+
37
+ const TERMINAL_DISCONNECT_REASONS = new Set(['link_disabled'])
38
+
39
+ type EventKey = keyof SlackBotListenerEventMap
40
+
41
+ export interface SlackBotListenerOptions {
42
+ appToken: string
43
+ debugReconnects?: boolean
44
+ }
45
+
46
+ export class SlackBotListener {
47
+ private client: SlackBotClient
48
+ private appToken: string
49
+ private debugReconnects: boolean
50
+ private running = false
51
+ private ws: WebSocket | null = null
52
+ private emitter = new EventEmitter()
53
+ private pingTimer: ReturnType<typeof setInterval> | null = null
54
+ private pongTimer: ReturnType<typeof setTimeout> | null = null
55
+ private helloTimer: ReturnType<typeof setTimeout> | null = null
56
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null
57
+ private reconnectAttempts = 0
58
+ private nextReconnectFloorMs = 0
59
+ private generation = 0
60
+
61
+ constructor(client: SlackBotClient, options: SlackBotListenerOptions) {
62
+ if (!options?.appToken) {
63
+ throw new SlackBotError('App-level token (xapp-) is required for Socket Mode', 'missing_app_token')
64
+ }
65
+ this.client = client
66
+ this.appToken = options.appToken
67
+ this.debugReconnects = options.debugReconnects ?? false
68
+ }
69
+
70
+ async start(): Promise<void> {
71
+ if (this.running) return
72
+ this.running = true
73
+ this.reconnectAttempts = 0
74
+ this.nextReconnectFloorMs = 0
75
+ this.generation++
76
+ await this.connect(this.generation)
77
+ }
78
+
79
+ stop(): void {
80
+ this.running = false
81
+ this.generation++
82
+ this.clearTimers()
83
+ if (this.ws) {
84
+ this.ws.close()
85
+ this.ws = null
86
+ }
87
+ }
88
+
89
+ on<K extends EventKey>(event: K, listener: (...args: SlackBotListenerEventMap[K]) => void): this {
90
+ this.emitter.on(event, listener as (...args: any[]) => void)
91
+ return this
92
+ }
93
+
94
+ off<K extends EventKey>(event: K, listener: (...args: SlackBotListenerEventMap[K]) => void): this {
95
+ this.emitter.off(event, listener as (...args: any[]) => void)
96
+ return this
97
+ }
98
+
99
+ once<K extends EventKey>(event: K, listener: (...args: SlackBotListenerEventMap[K]) => void): this {
100
+ this.emitter.once(event, listener as (...args: any[]) => void)
101
+ return this
102
+ }
103
+
104
+ private isCurrent(generation: number, ws?: WebSocket): boolean {
105
+ if (generation !== this.generation || !this.running) return false
106
+ if (ws !== undefined && this.ws !== ws) return false
107
+ return true
108
+ }
109
+
110
+ private async connect(generation: number): Promise<void> {
111
+ if (!this.isCurrent(generation)) return
112
+
113
+ try {
114
+ const { url } = await this.client.appsConnectionsOpen(this.appToken)
115
+ if (!this.isCurrent(generation)) return
116
+
117
+ const wsUrl = this.debugReconnects ? `${url}${url.includes('?') ? '&' : '?'}debug_reconnects=true` : url
118
+ const ws = new WebSocket(wsUrl)
119
+ this.ws = ws
120
+
121
+ ws.on('open', () => {
122
+ if (!this.isCurrent(generation, ws)) {
123
+ ws.close()
124
+ return
125
+ }
126
+ this.startPing(generation, ws)
127
+ this.armHelloTimeout(generation, ws)
128
+ })
129
+
130
+ ws.on('message', (raw) => {
131
+ if (!this.isCurrent(generation, ws)) return
132
+ try {
133
+ const data = JSON.parse(raw.toString()) as SlackSocketModeEnvelope
134
+ this.handleEnvelope(data, generation, ws)
135
+ } catch {
136
+ // Malformed frame; ignore — ping/pong handles liveness.
137
+ }
138
+ })
139
+
140
+ ws.on('pong', () => {
141
+ if (!this.isCurrent(generation, ws)) return
142
+ this.clearPongTimer()
143
+ })
144
+
145
+ ws.on('close', () => {
146
+ if (!this.isCurrent(generation, ws)) return
147
+ this.clearTimers()
148
+ this.ws = null
149
+ if (this.running) {
150
+ this.emitter.emit('disconnected')
151
+ this.scheduleReconnect()
152
+ }
153
+ })
154
+
155
+ ws.on('error', (err) => {
156
+ if (!this.isCurrent(generation, ws)) return
157
+ this.emitter.emit('error', err instanceof Error ? err : new Error(String(err)))
158
+ })
159
+ } catch (error) {
160
+ if (!this.isCurrent(generation)) return
161
+ const wrapped = error instanceof Error ? error : new Error(String(error))
162
+ this.emitter.emit('error', wrapped)
163
+
164
+ const code = (error as { code?: string })?.code
165
+ if (code && FATAL_ERROR_CODES.has(code)) {
166
+ this.running = false
167
+ return
168
+ }
169
+
170
+ const retryAfter = (error as { retryAfter?: number })?.retryAfter
171
+ if (typeof retryAfter === 'number' && retryAfter > 0) {
172
+ this.nextReconnectFloorMs = retryAfter * 1000
173
+ }
174
+
175
+ if (this.running) {
176
+ this.scheduleReconnect()
177
+ }
178
+ }
179
+ }
180
+
181
+ private handleEnvelope(envelope: SlackSocketModeEnvelope, generation: number, ws: WebSocket): void {
182
+ if (!this.isCurrent(generation, ws)) return
183
+
184
+ switch (envelope.type) {
185
+ case 'hello': {
186
+ const hello = envelope as { connection_info?: { app_id?: string }; num_connections?: number }
187
+ this.clearHelloTimer()
188
+ this.reconnectAttempts = 0
189
+ this.emitter.emit('connected', {
190
+ app_id: hello.connection_info?.app_id,
191
+ num_connections: hello.num_connections,
192
+ })
193
+ return
194
+ }
195
+
196
+ case 'disconnect': {
197
+ // Server-requested reconnect (warning, refresh_requested) — analogous to
198
+ // Discord opcode 7, so reset backoff. `link_disabled` is terminal: the app
199
+ // was disabled, reconnecting would loop forever.
200
+ const reason = (envelope as { reason?: string }).reason
201
+ if (reason && TERMINAL_DISCONNECT_REASONS.has(reason)) {
202
+ this.emitter.emit(
203
+ 'error',
204
+ new SlackBotError(`Slack closed the Socket Mode session: ${reason}`, 'disconnect_terminal'),
205
+ )
206
+ this.running = false
207
+ ws.close()
208
+ return
209
+ }
210
+ this.reconnectAttempts = 0
211
+ ws.close()
212
+ return
213
+ }
214
+
215
+ case 'events_api': {
216
+ this.dispatchEventsApi(envelope as SlackSocketModeEventsApiEnvelope, generation, ws)
217
+ return
218
+ }
219
+
220
+ case 'slash_commands': {
221
+ this.dispatchSlashCommand(envelope as SlackSocketModeSlashCommandEnvelope, generation, ws)
222
+ return
223
+ }
224
+
225
+ case 'interactive': {
226
+ this.dispatchInteractive(envelope as SlackSocketModeInteractiveEnvelope, generation, ws)
227
+ return
228
+ }
229
+
230
+ default: {
231
+ this.emitter.emit('slack_event', envelope)
232
+ }
233
+ }
234
+ }
235
+
236
+ private dispatchEventsApi(envelope: SlackSocketModeEventsApiEnvelope, generation: number, ws: WebSocket): void {
237
+ const event = envelope.payload?.event as SlackSocketModeGenericEvent | undefined
238
+ if (!event?.type) return
239
+
240
+ const ack = this.makeAck(envelope.envelope_id, generation, ws)
241
+ const args: SlackSocketModeEventsApiArgs = {
242
+ ack,
243
+ envelope_id: envelope.envelope_id,
244
+ body: envelope.payload,
245
+ event,
246
+ retry_num: envelope.retry_attempt,
247
+ retry_reason: envelope.retry_reason,
248
+ accepts_response_payload: envelope.accepts_response_payload,
249
+ }
250
+
251
+ this.emitter.emit(event.type, args)
252
+ this.emitter.emit('slack_event', args)
253
+ }
254
+
255
+ private dispatchSlashCommand(envelope: SlackSocketModeSlashCommandEnvelope, generation: number, ws: WebSocket): void {
256
+ const ack = this.makeAck(envelope.envelope_id, generation, ws)
257
+ const args: SlackSocketModeSlashCommandArgs = {
258
+ ack,
259
+ envelope_id: envelope.envelope_id,
260
+ body: envelope.payload,
261
+ accepts_response_payload: envelope.accepts_response_payload,
262
+ }
263
+ this.emitter.emit('slash_commands', args)
264
+ }
265
+
266
+ private dispatchInteractive(envelope: SlackSocketModeInteractiveEnvelope, generation: number, ws: WebSocket): void {
267
+ const ack = this.makeAck(envelope.envelope_id, generation, ws)
268
+ const args: SlackSocketModeInteractiveArgs = {
269
+ ack,
270
+ envelope_id: envelope.envelope_id,
271
+ body: envelope.payload,
272
+ accepts_response_payload: envelope.accepts_response_payload,
273
+ }
274
+ this.emitter.emit('interactive', args)
275
+ }
276
+
277
+ private makeAck(envelopeId: string, generation: number, ws: WebSocket): SlackSocketModeAck {
278
+ let acked = false
279
+ return (responsePayload?: Record<string, unknown>) => {
280
+ if (acked) return
281
+ acked = true
282
+ if (!this.isCurrent(generation, ws)) return
283
+ if (ws.readyState !== WebSocket.OPEN) return
284
+ const message =
285
+ responsePayload === undefined
286
+ ? { envelope_id: envelopeId }
287
+ : { envelope_id: envelopeId, payload: responsePayload }
288
+ ws.send(JSON.stringify(message))
289
+ }
290
+ }
291
+
292
+ private armHelloTimeout(generation: number, ws: WebSocket): void {
293
+ this.clearHelloTimer()
294
+ this.helloTimer = setTimeout(() => {
295
+ this.helloTimer = null
296
+ if (!this.isCurrent(generation, ws)) return
297
+ ws.close()
298
+ }, HELLO_TIMEOUT)
299
+ }
300
+
301
+ private clearHelloTimer(): void {
302
+ if (this.helloTimer) {
303
+ clearTimeout(this.helloTimer)
304
+ this.helloTimer = null
305
+ }
306
+ }
307
+
308
+ private startPing(generation: number, ws: WebSocket): void {
309
+ this.clearPingTimers()
310
+ this.pingTimer = setInterval(() => {
311
+ if (!this.isCurrent(generation, ws)) {
312
+ this.clearPingTimers()
313
+ return
314
+ }
315
+ if (ws.readyState !== WebSocket.OPEN) return
316
+
317
+ ws.ping()
318
+
319
+ this.clearPongTimer()
320
+ this.pongTimer = setTimeout(() => {
321
+ if (!this.isCurrent(generation, ws)) return
322
+ ws.close()
323
+ }, PONG_TIMEOUT)
324
+ }, PING_INTERVAL)
325
+ }
326
+
327
+ private scheduleReconnect(): void {
328
+ const exponential = Math.min(RECONNECT_BASE_DELAY * 2 ** this.reconnectAttempts, RECONNECT_MAX_DELAY)
329
+ const delay = Math.max(exponential, this.nextReconnectFloorMs)
330
+ this.nextReconnectFloorMs = 0
331
+ this.reconnectAttempts++
332
+ const generation = this.generation
333
+ this.reconnectTimer = setTimeout(() => {
334
+ this.reconnectTimer = null
335
+ this.connect(generation)
336
+ }, delay)
337
+ }
338
+
339
+ private clearPongTimer(): void {
340
+ if (this.pongTimer) {
341
+ clearTimeout(this.pongTimer)
342
+ this.pongTimer = null
343
+ }
344
+ }
345
+
346
+ private clearPingTimers(): void {
347
+ if (this.pingTimer) {
348
+ clearInterval(this.pingTimer)
349
+ this.pingTimer = null
350
+ }
351
+ this.clearPongTimer()
352
+ }
353
+
354
+ private clearTimers(): void {
355
+ this.clearPingTimers()
356
+ this.clearHelloTimer()
357
+ if (this.reconnectTimer) {
358
+ clearTimeout(this.reconnectTimer)
359
+ this.reconnectTimer = null
360
+ }
361
+ }
362
+ }
@@ -30,11 +30,13 @@ export interface SlackBotConfig {
30
30
  // Error class for SlackBot operations
31
31
  export class SlackBotError extends Error {
32
32
  code: string
33
+ retryAfter?: number
33
34
 
34
- constructor(message: string, code: string) {
35
+ constructor(message: string, code: string, retryAfter?: number) {
35
36
  super(message)
36
37
  this.name = 'SlackBotError'
37
38
  this.code = code
39
+ if (retryAfter !== undefined) this.retryAfter = retryAfter
38
40
  }
39
41
  }
40
42
 
@@ -221,3 +223,224 @@ export const SlackFileSchema = z.object({
221
223
  user: z.string(),
222
224
  channels: z.array(z.string()).optional(),
223
225
  })
226
+
227
+ // Socket Mode envelope types — see https://api.slack.com/apis/socket-mode
228
+
229
+ export interface SlackSocketModeHelloEnvelope {
230
+ type: 'hello'
231
+ connection_info?: { app_id: string }
232
+ num_connections?: number
233
+ debug_info?: {
234
+ host?: string
235
+ started?: string
236
+ build_number?: number
237
+ approximate_connection_time?: number
238
+ }
239
+ }
240
+
241
+ export type SlackSocketModeDisconnectReason = 'warning' | 'refresh_requested' | 'link_disabled' | string
242
+
243
+ export interface SlackSocketModeDisconnectEnvelope {
244
+ type: 'disconnect'
245
+ reason: SlackSocketModeDisconnectReason
246
+ debug_info?: {
247
+ host?: string
248
+ }
249
+ }
250
+
251
+ export interface SlackSocketModeEventsApiEnvelope {
252
+ type: 'events_api'
253
+ envelope_id: string
254
+ payload: {
255
+ token?: string
256
+ team_id?: string
257
+ api_app_id?: string
258
+ event: SlackSocketModeEvent
259
+ type?: 'event_callback' | string
260
+ event_id?: string
261
+ event_time?: number
262
+ [key: string]: unknown
263
+ }
264
+ accepts_response_payload?: boolean
265
+ retry_attempt?: number
266
+ retry_reason?: string
267
+ }
268
+
269
+ export interface SlackSocketModeSlashCommandEnvelope {
270
+ type: 'slash_commands'
271
+ envelope_id: string
272
+ payload: {
273
+ command: string
274
+ text: string
275
+ user_id: string
276
+ user_name?: string
277
+ channel_id: string
278
+ channel_name?: string
279
+ team_id: string
280
+ team_domain?: string
281
+ api_app_id?: string
282
+ response_url?: string
283
+ trigger_id?: string
284
+ [key: string]: unknown
285
+ }
286
+ accepts_response_payload?: boolean
287
+ }
288
+
289
+ export interface SlackSocketModeInteractiveEnvelope {
290
+ type: 'interactive'
291
+ envelope_id: string
292
+ payload: {
293
+ type: string
294
+ user?: { id: string; username?: string; name?: string; team_id?: string }
295
+ api_app_id?: string
296
+ token?: string
297
+ trigger_id?: string
298
+ response_url?: string
299
+ actions?: Array<Record<string, unknown>>
300
+ view?: Record<string, unknown>
301
+ [key: string]: unknown
302
+ }
303
+ accepts_response_payload?: boolean
304
+ }
305
+
306
+ export interface SlackSocketModeGenericEnvelope {
307
+ type: string
308
+ envelope_id?: string
309
+ payload?: Record<string, unknown>
310
+ accepts_response_payload?: boolean
311
+ [key: string]: unknown
312
+ }
313
+
314
+ export type SlackSocketModeEnvelope =
315
+ | SlackSocketModeHelloEnvelope
316
+ | SlackSocketModeDisconnectEnvelope
317
+ | SlackSocketModeEventsApiEnvelope
318
+ | SlackSocketModeSlashCommandEnvelope
319
+ | SlackSocketModeInteractiveEnvelope
320
+ | SlackSocketModeGenericEnvelope
321
+
322
+ // Inner Events API event lives at `payload.event` — see SlackSocketModeEventsApiEnvelope.
323
+
324
+ export interface SlackSocketModeMessageEvent {
325
+ type: 'message'
326
+ subtype?: string
327
+ channel: string
328
+ channel_type?: string
329
+ user?: string
330
+ bot_id?: string
331
+ text?: string
332
+ ts: string
333
+ thread_ts?: string
334
+ event_ts?: string
335
+ edited?: { user: string; ts: string }
336
+ hidden?: boolean
337
+ [key: string]: unknown
338
+ }
339
+
340
+ export interface SlackSocketModeAppMentionEvent {
341
+ type: 'app_mention'
342
+ channel: string
343
+ user: string
344
+ text: string
345
+ ts: string
346
+ thread_ts?: string
347
+ event_ts?: string
348
+ [key: string]: unknown
349
+ }
350
+
351
+ export interface SlackSocketModeReactionEvent {
352
+ type: 'reaction_added' | 'reaction_removed'
353
+ user: string
354
+ reaction: string
355
+ item: { type: string; channel: string; ts: string }
356
+ item_user?: string
357
+ event_ts: string
358
+ [key: string]: unknown
359
+ }
360
+
361
+ export interface SlackSocketModeMemberChannelEvent {
362
+ type: 'member_joined_channel' | 'member_left_channel'
363
+ user: string
364
+ channel: string
365
+ channel_type?: string
366
+ team?: string
367
+ event_ts?: string
368
+ [key: string]: unknown
369
+ }
370
+
371
+ export interface SlackSocketModeChannelEvent {
372
+ type:
373
+ | 'channel_created'
374
+ | 'channel_deleted'
375
+ | 'channel_rename'
376
+ | 'channel_archive'
377
+ | 'channel_unarchive'
378
+ | 'channel_left'
379
+ channel: { id: string; name?: string } | string
380
+ event_ts?: string
381
+ [key: string]: unknown
382
+ }
383
+
384
+ export interface SlackSocketModeGenericEvent {
385
+ type: string
386
+ [key: string]: unknown
387
+ }
388
+
389
+ export type SlackSocketModeEvent =
390
+ | SlackSocketModeMessageEvent
391
+ | SlackSocketModeAppMentionEvent
392
+ | SlackSocketModeReactionEvent
393
+ | SlackSocketModeMemberChannelEvent
394
+ | SlackSocketModeChannelEvent
395
+ | SlackSocketModeGenericEvent
396
+
397
+ // Acknowledgment callback. Without args sends `{ envelope_id }`; with args sends
398
+ // `{ envelope_id, payload }` (for `accepts_response_payload: true` envelopes).
399
+ export type SlackSocketModeAck = (responsePayload?: Record<string, unknown>) => void
400
+
401
+ export interface SlackSocketModeEventsApiArgs<E extends SlackSocketModeEvent = SlackSocketModeEvent> {
402
+ ack: SlackSocketModeAck
403
+ envelope_id: string
404
+ body: SlackSocketModeEventsApiEnvelope['payload']
405
+ event: E
406
+ retry_num?: number
407
+ retry_reason?: string
408
+ accepts_response_payload?: boolean
409
+ }
410
+
411
+ export interface SlackSocketModeSlashCommandArgs {
412
+ ack: SlackSocketModeAck
413
+ envelope_id: string
414
+ body: SlackSocketModeSlashCommandEnvelope['payload']
415
+ accepts_response_payload?: boolean
416
+ }
417
+
418
+ export interface SlackSocketModeInteractiveArgs {
419
+ ack: SlackSocketModeAck
420
+ envelope_id: string
421
+ body: SlackSocketModeInteractiveEnvelope['payload']
422
+ accepts_response_payload?: boolean
423
+ }
424
+
425
+ export interface SlackBotListenerEventMap {
426
+ connected: [info: { app_id?: string; num_connections?: number }]
427
+ disconnected: []
428
+ error: [error: Error]
429
+
430
+ message: [args: SlackSocketModeEventsApiArgs<SlackSocketModeMessageEvent>]
431
+ app_mention: [args: SlackSocketModeEventsApiArgs<SlackSocketModeAppMentionEvent>]
432
+ reaction_added: [args: SlackSocketModeEventsApiArgs<SlackSocketModeReactionEvent>]
433
+ reaction_removed: [args: SlackSocketModeEventsApiArgs<SlackSocketModeReactionEvent>]
434
+ member_joined_channel: [args: SlackSocketModeEventsApiArgs<SlackSocketModeMemberChannelEvent>]
435
+ member_left_channel: [args: SlackSocketModeEventsApiArgs<SlackSocketModeMemberChannelEvent>]
436
+ channel_created: [args: SlackSocketModeEventsApiArgs<SlackSocketModeChannelEvent>]
437
+ channel_deleted: [args: SlackSocketModeEventsApiArgs<SlackSocketModeChannelEvent>]
438
+ channel_rename: [args: SlackSocketModeEventsApiArgs<SlackSocketModeChannelEvent>]
439
+ channel_archive: [args: SlackSocketModeEventsApiArgs<SlackSocketModeChannelEvent>]
440
+ channel_unarchive: [args: SlackSocketModeEventsApiArgs<SlackSocketModeChannelEvent>]
441
+
442
+ slash_commands: [args: SlackSocketModeSlashCommandArgs]
443
+ interactive: [args: SlackSocketModeInteractiveArgs]
444
+
445
+ slack_event: [args: SlackSocketModeEventsApiArgs<SlackSocketModeGenericEvent> | SlackSocketModeGenericEnvelope]
446
+ }
@@ -16,7 +16,7 @@ let clientGetRegionSpy: ReturnType<typeof spyOn>
16
16
 
17
17
  beforeEach(() => {
18
18
  extractorExtractSpy = spyOn(TeamsTokenExtractor.prototype, 'extract').mockResolvedValue([
19
- { token: 'test-skype-token-123', accountType: 'work' as const },
19
+ { token: 'test-skype-token-123', accountType: 'work' as const, accountTypeKnown: true },
20
20
  ])
21
21
 
22
22
  clientTestAuthSpy = spyOn(TeamsClient.prototype, 'testAuth').mockResolvedValue({