agent-messenger 2.10.1 → 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 (536) 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 +80 -31
  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/decryptor.d.ts +6 -0
  199. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
  200. package/dist/src/shared/chromium/decryptor.js +26 -6
  201. package/dist/src/shared/chromium/decryptor.js.map +1 -1
  202. package/dist/src/shared/chromium/index.d.ts +3 -1
  203. package/dist/src/shared/chromium/index.d.ts.map +1 -1
  204. package/dist/src/shared/chromium/index.js +2 -1
  205. package/dist/src/shared/chromium/index.js.map +1 -1
  206. package/dist/src/shared/utils/cli-output.d.ts +7 -0
  207. package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
  208. package/dist/src/shared/utils/cli-output.js +7 -0
  209. package/dist/src/shared/utils/cli-output.js.map +1 -0
  210. package/dist/src/tui/app.d.ts.map +1 -1
  211. package/dist/src/tui/app.js +73 -20
  212. package/dist/src/tui/app.js.map +1 -1
  213. package/docs/content/docs/cli/channeltalk.mdx +4 -0
  214. package/docs/content/docs/cli/discord.mdx +5 -0
  215. package/docs/content/docs/cli/instagram.mdx +3 -0
  216. package/docs/content/docs/cli/slack.mdx +5 -0
  217. package/docs/content/docs/cli/slackbot.mdx +60 -22
  218. package/docs/content/docs/cli/teams.mdx +5 -0
  219. package/docs/content/docs/cli/webex.mdx +3 -0
  220. package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
  221. package/docs/content/docs/sdk/discordbot.mdx +501 -0
  222. package/docs/content/docs/sdk/meta.json +2 -0
  223. package/docs/content/docs/sdk/slackbot.mdx +576 -0
  224. package/e2e/README.md +1 -1
  225. package/e2e/channeltalk.e2e.test.ts +13 -13
  226. package/e2e/channeltalkbot.e2e.test.ts +13 -13
  227. package/e2e/config.ts +9 -4
  228. package/e2e/discord.e2e.test.ts +24 -24
  229. package/e2e/discordbot.e2e.test.ts +16 -16
  230. package/e2e/instagram.e2e.test.ts +10 -10
  231. package/e2e/kakaotalk.e2e.test.ts +7 -7
  232. package/e2e/line.e2e.test.ts +8 -8
  233. package/e2e/slack.e2e.test.ts +34 -34
  234. package/e2e/slackbot.e2e.test.ts +14 -14
  235. package/e2e/teams.e2e.test.ts +23 -23
  236. package/e2e/telegram.e2e.test.ts +8 -8
  237. package/e2e/webex.e2e.test.ts +14 -14
  238. package/e2e/whatsapp.e2e.test.ts +8 -8
  239. package/e2e/whatsappbot.e2e.test.ts +6 -6
  240. package/examples/discordbot-listen.ts +65 -0
  241. package/examples/slackbot-listen.ts +65 -0
  242. package/package.json +14 -1
  243. package/skills/agent-channeltalk/SKILL.md +5 -1
  244. package/skills/agent-channeltalk/references/authentication.md +5 -1
  245. package/skills/agent-channeltalkbot/SKILL.md +17 -3
  246. package/skills/agent-channeltalkbot/references/authentication.md +7 -5
  247. package/skills/agent-discord/SKILL.md +5 -1
  248. package/skills/agent-discord/references/authentication.md +7 -1
  249. package/skills/agent-discordbot/SKILL.md +13 -2
  250. package/skills/agent-discordbot/references/common-patterns.md +1 -1
  251. package/skills/agent-instagram/SKILL.md +7 -1
  252. package/skills/agent-instagram/references/authentication.md +6 -0
  253. package/skills/agent-kakaotalk/SKILL.md +1 -1
  254. package/skills/agent-line/SKILL.md +1 -1
  255. package/skills/agent-slack/SKILL.md +5 -1
  256. package/skills/agent-slack/references/authentication.md +7 -1
  257. package/skills/agent-slackbot/SKILL.md +56 -4
  258. package/skills/agent-slackbot/references/authentication.md +4 -0
  259. package/skills/agent-teams/SKILL.md +5 -1
  260. package/skills/agent-teams/references/authentication.md +7 -1
  261. package/skills/agent-telegram/SKILL.md +1 -1
  262. package/skills/agent-webex/SKILL.md +7 -1
  263. package/skills/agent-webex/references/authentication.md +6 -0
  264. package/skills/agent-wechatbot/SKILL.md +16 -1
  265. package/skills/agent-wechatbot/references/authentication.md +219 -0
  266. package/skills/agent-wechatbot/references/common-patterns.md +358 -0
  267. package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
  268. package/skills/agent-wechatbot/templates/post-message.sh +122 -0
  269. package/skills/agent-wechatbot/templates/send-template.sh +152 -0
  270. package/skills/agent-whatsapp/SKILL.md +1 -1
  271. package/skills/agent-whatsappbot/SKILL.md +30 -1
  272. package/src/platforms/channeltalk/client.test.ts +26 -26
  273. package/src/platforms/channeltalk/commands/auth.test.ts +31 -19
  274. package/src/platforms/channeltalk/commands/auth.ts +15 -5
  275. package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
  276. package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
  277. package/src/platforms/channeltalk/commands/group.test.ts +4 -4
  278. package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
  279. package/src/platforms/channeltalk/commands/message.test.ts +17 -17
  280. package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
  281. package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
  282. package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
  283. package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
  284. package/src/platforms/channeltalk/index.test.ts +23 -23
  285. package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
  286. package/src/platforms/channeltalk/token-extractor.ts +24 -5
  287. package/src/platforms/channeltalk/types.test.ts +12 -12
  288. package/src/platforms/channeltalkbot/cli.ts +9 -0
  289. package/src/platforms/channeltalkbot/client.test.ts +14 -14
  290. package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
  291. package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
  292. package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
  293. package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
  294. package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
  295. package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
  296. package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
  297. package/src/platforms/channeltalkbot/commands/group.ts +1 -6
  298. package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
  299. package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
  300. package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
  301. package/src/platforms/channeltalkbot/commands/message.ts +1 -6
  302. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
  303. package/src/platforms/channeltalkbot/commands/whoami.test.ts +6 -4
  304. package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
  305. package/src/platforms/channeltalkbot/credential-manager.test.ts +123 -29
  306. package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
  307. package/src/platforms/channeltalkbot/index.test.ts +15 -15
  308. package/src/platforms/discord/client.test.ts +28 -28
  309. package/src/platforms/discord/commands/auth.test.ts +7 -7
  310. package/src/platforms/discord/commands/auth.ts +13 -2
  311. package/src/platforms/discord/commands/channel.test.ts +7 -7
  312. package/src/platforms/discord/commands/dm.test.ts +4 -4
  313. package/src/platforms/discord/commands/file.test.ts +4 -4
  314. package/src/platforms/discord/commands/friend.test.ts +6 -6
  315. package/src/platforms/discord/commands/member.test.ts +5 -5
  316. package/src/platforms/discord/commands/mention.test.ts +5 -5
  317. package/src/platforms/discord/commands/message.test.ts +9 -9
  318. package/src/platforms/discord/commands/note.test.ts +6 -6
  319. package/src/platforms/discord/commands/profile.test.ts +4 -4
  320. package/src/platforms/discord/commands/reaction.test.ts +5 -5
  321. package/src/platforms/discord/commands/server.test.ts +7 -7
  322. package/src/platforms/discord/commands/snapshot.test.ts +6 -6
  323. package/src/platforms/discord/commands/thread.test.ts +6 -6
  324. package/src/platforms/discord/commands/user.test.ts +5 -5
  325. package/src/platforms/discord/commands/whoami.test.ts +6 -6
  326. package/src/platforms/discord/credential-manager.test.ts +16 -16
  327. package/src/platforms/discord/ensure-auth.test.ts +8 -8
  328. package/src/platforms/discord/index.test.ts +17 -17
  329. package/src/platforms/discord/listener.test.ts +92 -34
  330. package/src/platforms/discord/listener.ts +43 -19
  331. package/src/platforms/discord/token-extractor.test.ts +53 -53
  332. package/src/platforms/discord/token-extractor.ts +30 -6
  333. package/src/platforms/discord/types.test.ts +26 -26
  334. package/src/platforms/discordbot/cli.ts +10 -0
  335. package/src/platforms/discordbot/client.test.ts +31 -31
  336. package/src/platforms/discordbot/client.ts +4 -0
  337. package/src/platforms/discordbot/commands/auth.test.ts +18 -18
  338. package/src/platforms/discordbot/commands/auth.ts +1 -5
  339. package/src/platforms/discordbot/commands/channel.test.ts +11 -11
  340. package/src/platforms/discordbot/commands/file.test.ts +7 -7
  341. package/src/platforms/discordbot/commands/message.test.ts +25 -25
  342. package/src/platforms/discordbot/commands/message.ts +1 -6
  343. package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
  344. package/src/platforms/discordbot/commands/server.test.ts +12 -12
  345. package/src/platforms/discordbot/commands/server.ts +1 -5
  346. package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
  347. package/src/platforms/discordbot/commands/thread.test.ts +10 -10
  348. package/src/platforms/discordbot/commands/user.test.ts +9 -9
  349. package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
  350. package/src/platforms/discordbot/commands/whoami.ts +1 -6
  351. package/src/platforms/discordbot/credential-manager.test.ts +28 -28
  352. package/src/platforms/discordbot/index.test.ts +82 -0
  353. package/src/platforms/discordbot/index.ts +27 -9
  354. package/src/platforms/discordbot/listener.test.ts +1002 -0
  355. package/src/platforms/discordbot/listener.ts +321 -0
  356. package/src/platforms/discordbot/types.ts +163 -0
  357. package/src/platforms/instagram/client.test.ts +18 -18
  358. package/src/platforms/instagram/commands/auth.test.ts +11 -11
  359. package/src/platforms/instagram/commands/auth.ts +9 -1
  360. package/src/platforms/instagram/commands/chat.test.ts +6 -6
  361. package/src/platforms/instagram/commands/message.test.ts +11 -11
  362. package/src/platforms/instagram/commands/shared.test.ts +12 -12
  363. package/src/platforms/instagram/commands/whoami.test.ts +3 -3
  364. package/src/platforms/instagram/credential-manager.test.ts +21 -21
  365. package/src/platforms/instagram/ensure-auth.test.ts +4 -4
  366. package/src/platforms/instagram/index.test.ts +9 -9
  367. package/src/platforms/instagram/listener.test.ts +8 -8
  368. package/src/platforms/instagram/token-extractor.test.ts +35 -35
  369. package/src/platforms/instagram/token-extractor.ts +13 -1
  370. package/src/platforms/kakaotalk/client.test.ts +33 -33
  371. package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
  372. package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
  373. package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
  374. package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
  375. package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
  376. package/src/platforms/kakaotalk/index.test.ts +15 -15
  377. package/src/platforms/kakaotalk/listener.test.ts +17 -17
  378. package/src/platforms/line/client.test.ts +17 -17
  379. package/src/platforms/line/commands/auth.test.ts +8 -8
  380. package/src/platforms/line/commands/chat.test.ts +7 -7
  381. package/src/platforms/line/commands/friend.test.ts +6 -6
  382. package/src/platforms/line/commands/message.test.ts +7 -7
  383. package/src/platforms/line/commands/whoami.test.ts +6 -6
  384. package/src/platforms/line/credential-manager.test.ts +17 -17
  385. package/src/platforms/line/index.test.ts +10 -10
  386. package/src/platforms/line/listener.test.ts +15 -15
  387. package/src/platforms/line/types.test.ts +14 -14
  388. package/src/platforms/slack/cli.test.ts +8 -8
  389. package/src/platforms/slack/client.test.ts +151 -151
  390. package/src/platforms/slack/commands/activity.test.ts +13 -13
  391. package/src/platforms/slack/commands/auth.test.ts +34 -34
  392. package/src/platforms/slack/commands/auth.ts +11 -2
  393. package/src/platforms/slack/commands/bookmark.test.ts +9 -9
  394. package/src/platforms/slack/commands/channel.test.ts +17 -17
  395. package/src/platforms/slack/commands/drafts.test.ts +7 -7
  396. package/src/platforms/slack/commands/emoji.test.ts +3 -3
  397. package/src/platforms/slack/commands/file.test.ts +12 -12
  398. package/src/platforms/slack/commands/message.test.ts +19 -19
  399. package/src/platforms/slack/commands/pin.test.ts +7 -7
  400. package/src/platforms/slack/commands/reaction.test.ts +10 -10
  401. package/src/platforms/slack/commands/reminder.test.ts +9 -9
  402. package/src/platforms/slack/commands/saved.test.ts +7 -7
  403. package/src/platforms/slack/commands/sections.test.ts +5 -5
  404. package/src/platforms/slack/commands/snapshot.test.ts +13 -13
  405. package/src/platforms/slack/commands/unread.test.ts +6 -6
  406. package/src/platforms/slack/commands/user.test.ts +10 -10
  407. package/src/platforms/slack/commands/usergroup.test.ts +15 -15
  408. package/src/platforms/slack/commands/whoami.test.ts +6 -6
  409. package/src/platforms/slack/commands/workspace.test.ts +26 -26
  410. package/src/platforms/slack/credential-manager.test.ts +14 -14
  411. package/src/platforms/slack/ensure-auth.test.ts +21 -21
  412. package/src/platforms/slack/index.test.ts +12 -12
  413. package/src/platforms/slack/listener.test.ts +17 -17
  414. package/src/platforms/slack/token-extractor-node.test.ts +2 -2
  415. package/src/platforms/slack/token-extractor.test.ts +133 -37
  416. package/src/platforms/slack/token-extractor.ts +76 -13
  417. package/src/platforms/slack/types.test.ts +21 -21
  418. package/src/platforms/slackbot/cli.ts +13 -1
  419. package/src/platforms/slackbot/client.test.ts +296 -22
  420. package/src/platforms/slackbot/client.ts +130 -2
  421. package/src/platforms/slackbot/commands/auth.test.ts +14 -14
  422. package/src/platforms/slackbot/commands/auth.ts +1 -5
  423. package/src/platforms/slackbot/commands/channel.test.ts +7 -7
  424. package/src/platforms/slackbot/commands/file.test.ts +201 -0
  425. package/src/platforms/slackbot/commands/file.ts +212 -0
  426. package/src/platforms/slackbot/commands/index.ts +1 -0
  427. package/src/platforms/slackbot/commands/message.test.ts +13 -13
  428. package/src/platforms/slackbot/commands/message.ts +22 -0
  429. package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
  430. package/src/platforms/slackbot/commands/user.test.ts +7 -7
  431. package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
  432. package/src/platforms/slackbot/commands/whoami.ts +1 -6
  433. package/src/platforms/slackbot/credential-manager.test.ts +83 -23
  434. package/src/platforms/slackbot/credential-manager.ts +32 -2
  435. package/src/platforms/slackbot/index.test.ts +59 -0
  436. package/src/platforms/slackbot/index.ts +31 -7
  437. package/src/platforms/slackbot/listener.test.ts +1012 -0
  438. package/src/platforms/slackbot/listener.ts +362 -0
  439. package/src/platforms/slackbot/types.test.ts +7 -7
  440. package/src/platforms/slackbot/types.ts +224 -1
  441. package/src/platforms/teams/client.test.ts +30 -30
  442. package/src/platforms/teams/commands/auth.test.ts +9 -9
  443. package/src/platforms/teams/commands/auth.ts +66 -7
  444. package/src/platforms/teams/commands/channel.test.ts +7 -7
  445. package/src/platforms/teams/commands/file.test.ts +4 -4
  446. package/src/platforms/teams/commands/message.test.ts +5 -5
  447. package/src/platforms/teams/commands/reaction.test.ts +4 -4
  448. package/src/platforms/teams/commands/snapshot.test.ts +7 -7
  449. package/src/platforms/teams/commands/team.test.ts +8 -8
  450. package/src/platforms/teams/commands/user.test.ts +4 -4
  451. package/src/platforms/teams/commands/whoami.test.ts +6 -6
  452. package/src/platforms/teams/credential-manager.test.ts +17 -17
  453. package/src/platforms/teams/ensure-auth.test.ts +69 -18
  454. package/src/platforms/teams/ensure-auth.ts +39 -11
  455. package/src/platforms/teams/index.test.ts +15 -15
  456. package/src/platforms/teams/token-extractor.test.ts +251 -69
  457. package/src/platforms/teams/token-extractor.ts +94 -31
  458. package/src/platforms/teams/types.test.ts +26 -26
  459. package/src/platforms/telegram/app-config.test.ts +4 -4
  460. package/src/platforms/telegram/chat-utils.test.ts +12 -12
  461. package/src/platforms/telegram/client.test.ts +4 -4
  462. package/src/platforms/telegram/commands/auth.test.ts +16 -16
  463. package/src/platforms/telegram/commands/chat.test.ts +9 -9
  464. package/src/platforms/telegram/commands/message.test.ts +6 -6
  465. package/src/platforms/telegram/commands/shared.test.ts +3 -3
  466. package/src/platforms/telegram/commands/whoami.test.ts +3 -3
  467. package/src/platforms/telegram/credential-manager.test.ts +10 -10
  468. package/src/platforms/telegram/types.test.ts +6 -6
  469. package/src/platforms/webex/app-config.test.ts +8 -8
  470. package/src/platforms/webex/cli.test.ts +5 -5
  471. package/src/platforms/webex/client.test.ts +65 -65
  472. package/src/platforms/webex/commands/auth.test.ts +18 -18
  473. package/src/platforms/webex/commands/auth.ts +13 -2
  474. package/src/platforms/webex/commands/member.test.ts +5 -5
  475. package/src/platforms/webex/commands/message.test.ts +12 -12
  476. package/src/platforms/webex/commands/snapshot.test.ts +5 -5
  477. package/src/platforms/webex/commands/space.test.ts +10 -10
  478. package/src/platforms/webex/commands/whoami.test.ts +6 -6
  479. package/src/platforms/webex/credential-manager.test.ts +22 -22
  480. package/src/platforms/webex/encryption.test.ts +4 -4
  481. package/src/platforms/webex/ensure-auth.test.ts +5 -5
  482. package/src/platforms/webex/index.test.ts +5 -5
  483. package/src/platforms/webex/markdown-to-html.test.ts +33 -33
  484. package/src/platforms/webex/token-extractor.test.ts +23 -23
  485. package/src/platforms/webex/token-extractor.ts +25 -3
  486. package/src/platforms/webex/types.test.ts +27 -27
  487. package/src/platforms/wechatbot/cli.ts +9 -0
  488. package/src/platforms/wechatbot/client.test.ts +27 -27
  489. package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
  490. package/src/platforms/wechatbot/commands/auth.ts +1 -5
  491. package/src/platforms/wechatbot/commands/message.test.ts +8 -8
  492. package/src/platforms/wechatbot/commands/message.ts +1 -6
  493. package/src/platforms/wechatbot/commands/template.test.ts +9 -9
  494. package/src/platforms/wechatbot/commands/template.ts +1 -6
  495. package/src/platforms/wechatbot/commands/user.test.ts +7 -7
  496. package/src/platforms/wechatbot/commands/user.ts +1 -6
  497. package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
  498. package/src/platforms/wechatbot/commands/whoami.ts +1 -6
  499. package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
  500. package/src/platforms/wechatbot/index.test.ts +10 -10
  501. package/src/platforms/wechatbot/types.test.ts +25 -25
  502. package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
  503. package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
  504. package/src/platforms/whatsapp/commands/message.test.ts +10 -10
  505. package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
  506. package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
  507. package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
  508. package/src/platforms/whatsapp/index.test.ts +8 -8
  509. package/src/platforms/whatsapp/types.test.ts +42 -42
  510. package/src/platforms/whatsappbot/cli.ts +9 -0
  511. package/src/platforms/whatsappbot/client.test.ts +27 -27
  512. package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
  513. package/src/platforms/whatsappbot/commands/auth.ts +1 -5
  514. package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
  515. package/src/platforms/whatsappbot/commands/message.ts +1 -6
  516. package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
  517. package/src/platforms/whatsappbot/commands/template.ts +1 -6
  518. package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
  519. package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
  520. package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
  521. package/src/platforms/whatsappbot/index.test.ts +7 -7
  522. package/src/platforms/whatsappbot/types.test.ts +18 -18
  523. package/src/shared/chromium/browsers.test.ts +102 -22
  524. package/src/shared/chromium/browsers.ts +72 -3
  525. package/src/shared/chromium/cli-options.test.ts +22 -0
  526. package/src/shared/chromium/cli-options.ts +12 -0
  527. package/src/shared/chromium/cookie-reader.test.ts +13 -13
  528. package/src/shared/chromium/decryptor.test.ts +97 -32
  529. package/src/shared/chromium/decryptor.ts +27 -6
  530. package/src/shared/chromium/index.ts +3 -0
  531. package/src/shared/utils/cli-output.test.ts +57 -0
  532. package/src/shared/utils/cli-output.ts +8 -0
  533. package/src/shared/utils/concurrency.test.ts +6 -6
  534. package/src/shared/utils/derived-key-cache.test.ts +11 -11
  535. package/src/tui/app.ts +129 -20
  536. package/src/tui/utils.test.ts +31 -31
@@ -1,4 +1,4 @@
1
- import { afterEach, describe, expect, mock, test } from 'bun:test'
1
+ import { afterEach, describe, expect, mock, it } from 'bun:test'
2
2
 
3
3
  import { DiscordListener } from '@/platforms/discord/listener'
4
4
  import type {
@@ -16,12 +16,16 @@ let mockWsInstance: MockWs
16
16
  class MockWs {
17
17
  static OPEN = 1
18
18
  static CLOSED = 3
19
+ static lastUrl: string | null = null
19
20
  readyState = MockWs.OPEN
20
21
 
21
22
  private handlers = new Map<string, WsHandler[]>()
22
23
  sent: string[] = []
24
+ url: string
23
25
 
24
- constructor(_url: string, _options?: any) {
26
+ constructor(url: string, _options?: any) {
27
+ this.url = url
28
+ MockWs.lastUrl = url
25
29
  // oxlint-disable-next-line typescript-eslint/no-this-alias
26
30
  mockWsInstance = this
27
31
  }
@@ -111,7 +115,7 @@ describe('DiscordListener', () => {
111
115
  })
112
116
 
113
117
  describe('start', () => {
114
- test('calls gatewayConnect and opens WebSocket', async () => {
118
+ it('calls gatewayConnect and opens WebSocket', async () => {
115
119
  const client = createMockClient()
116
120
  listener = new DiscordListener(client)
117
121
 
@@ -121,7 +125,7 @@ describe('DiscordListener', () => {
121
125
  expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
122
126
  })
123
127
 
124
- test('is idempotent', async () => {
128
+ it('is idempotent', async () => {
125
129
  const client = createMockClient()
126
130
  listener = new DiscordListener(client)
127
131
 
@@ -133,7 +137,7 @@ describe('DiscordListener', () => {
133
137
  })
134
138
 
135
139
  describe('connected event', () => {
136
- test('emits connected with user/sessionId on READY', async () => {
140
+ it('emits connected with user/sessionId on READY', async () => {
137
141
  const client = createMockClient()
138
142
  listener = new DiscordListener(client)
139
143
 
@@ -152,7 +156,7 @@ describe('DiscordListener', () => {
152
156
  })
153
157
 
154
158
  describe('identify', () => {
155
- test('sends Identify after Hello', async () => {
159
+ it('sends Identify after Hello', async () => {
156
160
  const client = createMockClient()
157
161
  listener = new DiscordListener(client)
158
162
 
@@ -167,7 +171,7 @@ describe('DiscordListener', () => {
167
171
  expect(identifyMsg.d.token).toBe('fake-token')
168
172
  })
169
173
 
170
- test('sends Identify with custom intents', async () => {
174
+ it('sends Identify with custom intents', async () => {
171
175
  const client = createMockClient()
172
176
  const customIntents = 1 << 9
173
177
  listener = new DiscordListener(client, { intents: customIntents })
@@ -185,7 +189,7 @@ describe('DiscordListener', () => {
185
189
  })
186
190
 
187
191
  describe('message events', () => {
188
- test('emits message_create events', async () => {
192
+ it('emits message_create events', async () => {
189
193
  const client = createMockClient()
190
194
  listener = new DiscordListener(client)
191
195
 
@@ -213,7 +217,7 @@ describe('DiscordListener', () => {
213
217
  expect(messages[0].channel_id).toBe('C123')
214
218
  })
215
219
 
216
- test('emits message_update events', async () => {
220
+ it('emits message_update events', async () => {
217
221
  const client = createMockClient()
218
222
  listener = new DiscordListener(client)
219
223
 
@@ -235,7 +239,7 @@ describe('DiscordListener', () => {
235
239
  expect(updates[0].content).toBe('edited')
236
240
  })
237
241
 
238
- test('emits message_delete events', async () => {
242
+ it('emits message_delete events', async () => {
239
243
  const client = createMockClient()
240
244
  listener = new DiscordListener(client)
241
245
 
@@ -254,7 +258,7 @@ describe('DiscordListener', () => {
254
258
  })
255
259
 
256
260
  describe('reaction events', () => {
257
- test('emits message_reaction_add events', async () => {
261
+ it('emits message_reaction_add events', async () => {
258
262
  const client = createMockClient()
259
263
  listener = new DiscordListener(client)
260
264
 
@@ -283,7 +287,7 @@ describe('DiscordListener', () => {
283
287
  })
284
288
 
285
289
  describe('discord_event catch-all', () => {
286
- test('emits discord_event for every dispatch (not READY)', async () => {
290
+ it('emits discord_event for every dispatch (not READY)', async () => {
287
291
  const client = createMockClient()
288
292
  listener = new DiscordListener(client)
289
293
 
@@ -308,7 +312,7 @@ describe('DiscordListener', () => {
308
312
  })
309
313
 
310
314
  describe('heartbeat', () => {
311
- test('sends heartbeat after Hello (with jitter)', async () => {
315
+ it('sends heartbeat after Hello (with jitter)', async () => {
312
316
  const originalRandom = Math.random
313
317
  Math.random = () => 0
314
318
 
@@ -331,7 +335,7 @@ describe('DiscordListener', () => {
331
335
  }
332
336
  })
333
337
 
334
- test('heartbeat ACK not emitted as user event', async () => {
338
+ it('heartbeat ACK not emitted as user event', async () => {
335
339
  const client = createMockClient()
336
340
  listener = new DiscordListener(client)
337
341
 
@@ -347,7 +351,7 @@ describe('DiscordListener', () => {
347
351
  expect(events.length).toBe(0)
348
352
  })
349
353
 
350
- test('zombie connection triggers reconnect (no ACK received)', async () => {
354
+ it('zombie connection triggers reconnect (no ACK received)', async () => {
351
355
  const originalRandom = Math.random
352
356
  Math.random = () => 0
353
357
 
@@ -372,7 +376,7 @@ describe('DiscordListener', () => {
372
376
  })
373
377
 
374
378
  describe('stop', () => {
375
- test('closes WebSocket and prevents reconnection', async () => {
379
+ it('closes WebSocket and prevents reconnection', async () => {
376
380
  const client = createMockClient()
377
381
  listener = new DiscordListener(client)
378
382
 
@@ -387,7 +391,7 @@ describe('DiscordListener', () => {
387
391
  })
388
392
 
389
393
  describe('reconnection', () => {
390
- test('reconnects on WebSocket close when running', async () => {
394
+ it('reconnects on WebSocket close when running', async () => {
391
395
  const client = createMockClient()
392
396
  listener = new DiscordListener(client)
393
397
 
@@ -404,7 +408,7 @@ describe('DiscordListener', () => {
404
408
  expect(client.gatewayConnect.mock.calls.length).toBeGreaterThanOrEqual(2)
405
409
  })
406
410
 
407
- test('emits error and reconnects on gatewayConnect failure', async () => {
411
+ it('emits error and reconnects on gatewayConnect failure', async () => {
408
412
  let callCount = 0
409
413
  const client = createMockClient({
410
414
  gatewayConnect: mock(() => {
@@ -430,7 +434,7 @@ describe('DiscordListener', () => {
430
434
  })
431
435
 
432
436
  describe('on/off/once', () => {
433
- test('off removes listener', async () => {
437
+ it('off removes listener', async () => {
434
438
  const client = createMockClient()
435
439
  listener = new DiscordListener(client)
436
440
 
@@ -459,7 +463,7 @@ describe('DiscordListener', () => {
459
463
  expect(messages[0].content).toBe('a')
460
464
  })
461
465
 
462
- test('once fires only once', async () => {
466
+ it('once fires only once', async () => {
463
467
  const client = createMockClient()
464
468
  listener = new DiscordListener(client)
465
469
 
@@ -487,7 +491,7 @@ describe('DiscordListener', () => {
487
491
  })
488
492
 
489
493
  describe('opcode 7 Reconnect', () => {
490
- test('triggers immediate reconnect without backoff', async () => {
494
+ it('triggers immediate reconnect without backoff', async () => {
491
495
  const client = createMockClient()
492
496
  listener = new DiscordListener(client)
493
497
 
@@ -504,7 +508,7 @@ describe('DiscordListener', () => {
504
508
  })
505
509
 
506
510
  describe('opcode 9 InvalidSession', () => {
507
- test('d=false clears session state, reconnects with fresh identify', async () => {
511
+ it('d=false clears session state, reconnects with fresh identify', async () => {
508
512
  const client = createMockClient()
509
513
  listener = new DiscordListener(client)
510
514
 
@@ -522,7 +526,7 @@ describe('DiscordListener', () => {
522
526
  expect((listener as any).resumeGatewayUrl).toBeNull()
523
527
  })
524
528
 
525
- test('d=true allows resume on reconnect', async () => {
529
+ it('d=true allows resume on reconnect', async () => {
526
530
  const client = createMockClient()
527
531
  listener = new DiscordListener(client)
528
532
 
@@ -540,7 +544,7 @@ describe('DiscordListener', () => {
540
544
  })
541
545
 
542
546
  describe('resume', () => {
543
- test('sends Resume instead of Identify when session exists', async () => {
547
+ it('sends Resume instead of Identify when session exists', async () => {
544
548
  const client = createMockClient()
545
549
  listener = new DiscordListener(client)
546
550
 
@@ -565,7 +569,7 @@ describe('DiscordListener', () => {
565
569
  })
566
570
 
567
571
  describe('non-recoverable close codes', () => {
568
- test('emits error and stops on code 4004', async () => {
572
+ it('emits error and stops on code 4004', async () => {
569
573
  const client = createMockClient()
570
574
  listener = new DiscordListener(client)
571
575
 
@@ -585,7 +589,7 @@ describe('DiscordListener', () => {
585
589
  })
586
590
 
587
591
  describe('session reset close codes', () => {
588
- test('4007 clears session and reconnects with fresh identify', async () => {
592
+ it('4007 clears session and reconnects with fresh identify', async () => {
589
593
  const client = createMockClient()
590
594
  listener = new DiscordListener(client)
591
595
 
@@ -615,7 +619,7 @@ describe('DiscordListener', () => {
615
619
  expect(resumeMsg).toBeUndefined()
616
620
  })
617
621
 
618
- test('4009 clears session and reconnects with fresh identify', async () => {
622
+ it('4009 clears session and reconnects with fresh identify', async () => {
619
623
  const client = createMockClient()
620
624
  listener = new DiscordListener(client)
621
625
 
@@ -631,7 +635,7 @@ describe('DiscordListener', () => {
631
635
  })
632
636
 
633
637
  describe('duplicate Hello', () => {
634
- test('does not stack heartbeat timers on second Hello', async () => {
638
+ it('does not stack heartbeat timers on second Hello', async () => {
635
639
  const originalRandom = Math.random
636
640
  Math.random = () => 0
637
641
 
@@ -659,7 +663,7 @@ describe('DiscordListener', () => {
659
663
  })
660
664
 
661
665
  describe('InvalidSession timer safety', () => {
662
- test('stop cancels pending InvalidSession d=true timeout', async () => {
666
+ it('stop cancels pending InvalidSession d=true timeout', async () => {
663
667
  const originalRandom = Math.random
664
668
  Math.random = () => 0
665
669
 
@@ -682,7 +686,7 @@ describe('DiscordListener', () => {
682
686
  }
683
687
  })
684
688
 
685
- test('InvalidSession d=false sends fresh identify on reconnect', async () => {
689
+ it('InvalidSession d=false sends fresh identify on reconnect', async () => {
686
690
  const client = createMockClient()
687
691
  listener = new DiscordListener(client)
688
692
 
@@ -708,7 +712,7 @@ describe('DiscordListener', () => {
708
712
  })
709
713
 
710
714
  describe('server-requested heartbeat', () => {
711
- test('responds to opcode 1 with heartbeat', async () => {
715
+ it('responds to opcode 1 with heartbeat', async () => {
712
716
  const client = createMockClient()
713
717
  listener = new DiscordListener(client)
714
718
 
@@ -728,7 +732,7 @@ describe('DiscordListener', () => {
728
732
  })
729
733
 
730
734
  describe('sequence tracking', () => {
731
- test('tracks sequence from dispatch events', async () => {
735
+ it('tracks sequence from dispatch events', async () => {
732
736
  const client = createMockClient()
733
737
  listener = new DiscordListener(client)
734
738
 
@@ -746,7 +750,7 @@ describe('DiscordListener', () => {
746
750
  expect((listener as any).sequence).toBe(5)
747
751
  })
748
752
 
749
- test('ignores null sequence values', async () => {
753
+ it('ignores null sequence values', async () => {
750
754
  const client = createMockClient()
751
755
  listener = new DiscordListener(client)
752
756
 
@@ -773,7 +777,7 @@ describe('DiscordListener', () => {
773
777
  })
774
778
 
775
779
  describe('start after stop', () => {
776
- test('resets reconnect attempts on fresh start', async () => {
780
+ it('resets reconnect attempts on fresh start', async () => {
777
781
  const client = createMockClient()
778
782
  listener = new DiscordListener(client)
779
783
 
@@ -785,4 +789,58 @@ describe('DiscordListener', () => {
785
789
  expect((listener as any).reconnectAttempts).toBe(0)
786
790
  })
787
791
  })
792
+
793
+ describe('reconnect URL', () => {
794
+ it('appends ?v=10&encoding=json to resume_gateway_url on reconnect', async () => {
795
+ const client = createMockClient()
796
+ listener = new DiscordListener(client)
797
+
798
+ await listener.start()
799
+ mockWsInstance.simulateOpen()
800
+ mockWsInstance.simulateHello()
801
+ mockWsInstance.simulateMessage({
802
+ op: 0,
803
+ t: 'READY',
804
+ s: 1,
805
+ d: {
806
+ session_id: 'session_xyz',
807
+ resume_gateway_url: 'wss://gateway-us-east1-b.discord.gg',
808
+ user: { id: 'U_SELF', username: 'user' },
809
+ },
810
+ })
811
+
812
+ mockWsInstance.simulateClose()
813
+ await new Promise((r) => setTimeout(r, 1500))
814
+
815
+ expect(MockWs.lastUrl).toBe('wss://gateway-us-east1-b.discord.gg?v=10&encoding=json')
816
+ })
817
+ })
818
+
819
+ describe('reconnectAttempts deferred to READY/RESUMED', () => {
820
+ it('does not reset reconnectAttempts on socket open alone', async () => {
821
+ const client = createMockClient()
822
+ listener = new DiscordListener(client)
823
+
824
+ await listener.start()
825
+ ;(listener as any).reconnectAttempts = 5
826
+
827
+ mockWsInstance.simulateOpen()
828
+
829
+ expect((listener as any).reconnectAttempts).toBe(5)
830
+ })
831
+
832
+ it('resets reconnectAttempts on READY dispatch', async () => {
833
+ const client = createMockClient()
834
+ listener = new DiscordListener(client)
835
+
836
+ await listener.start()
837
+ ;(listener as any).reconnectAttempts = 5
838
+
839
+ mockWsInstance.simulateOpen()
840
+ mockWsInstance.simulateHello()
841
+ mockWsInstance.simulateReady()
842
+
843
+ expect((listener as any).reconnectAttempts).toBe(0)
844
+ })
845
+ })
788
846
  })
@@ -7,6 +7,7 @@ import type { DiscordListenerEventMap, DiscordGatewayGenericEvent } from './type
7
7
  import { DiscordGatewayOpcode, DiscordIntent } from './types'
8
8
 
9
9
  const GATEWAY_URL = 'wss://gateway.discord.gg/?v=10&encoding=json'
10
+ const GATEWAY_QUERY = '?v=10&encoding=json'
10
11
  const RECONNECT_BASE_DELAY = 1_000
11
12
  const RECONNECT_MAX_DELAY = 30_000
12
13
  const NON_RECOVERABLE_CLOSE_CODES = [4004, 4010, 4011, 4012, 4013, 4014]
@@ -40,6 +41,7 @@ export class DiscordListener {
40
41
  private resumeGatewayUrl: string | null = null
41
42
  private token: string | null = null
42
43
  private cachedUser: { id: string; username: string } | null = null
44
+ private generation = 0
43
45
 
44
46
  constructor(client: DiscordClient, options?: { intents?: number }) {
45
47
  this.client = client
@@ -50,11 +52,13 @@ export class DiscordListener {
50
52
  if (this.running) return
51
53
  this.running = true
52
54
  this.reconnectAttempts = 0
53
- await this.connect()
55
+ this.generation++
56
+ await this.connect(this.generation)
54
57
  }
55
58
 
56
59
  stop(): void {
57
60
  this.running = false
61
+ this.generation++
58
62
  this.clearTimers()
59
63
  if (this.ws) {
60
64
  this.ws.close()
@@ -82,39 +86,46 @@ export class DiscordListener {
82
86
  return this
83
87
  }
84
88
 
85
- private async connect(): Promise<void> {
86
- if (!this.running) return
89
+ private isCurrent(generation: number, ws?: WebSocket): boolean {
90
+ if (generation !== this.generation || !this.running) return false
91
+ if (ws !== undefined && this.ws !== ws) return false
92
+ return true
93
+ }
94
+
95
+ private async connect(generation: number): Promise<void> {
96
+ if (!this.isCurrent(generation)) return
87
97
 
88
98
  try {
89
99
  const { token } = await this.client.gatewayConnect()
90
- if (!this.running) return
100
+ if (!this.isCurrent(generation)) return
91
101
 
92
102
  this.token = token
93
103
 
94
- const url = this.resumeGatewayUrl ?? GATEWAY_URL
104
+ const url = this.resumeGatewayUrl ? `${this.resumeGatewayUrl}${GATEWAY_QUERY}` : GATEWAY_URL
95
105
  const ws = new WebSocket(url)
96
106
  this.ws = ws
97
107
 
98
108
  ws.on('open', () => {
99
- if (!this.running) {
109
+ if (!this.isCurrent(generation, ws)) {
100
110
  ws.close()
101
111
  return
102
112
  }
103
- this.reconnectAttempts = 0
104
113
  })
105
114
 
106
115
  ws.on('message', (raw) => {
116
+ if (!this.isCurrent(generation, ws)) return
107
117
  try {
108
118
  const data = JSON.parse(raw.toString())
109
- this.handleMessage(data)
119
+ this.handleMessage(data, generation, ws)
110
120
  } catch {
111
- // malformed message, ignore
121
+ // malformed gateway frame; ignore and let heartbeat handle liveness
112
122
  }
113
123
  })
114
124
 
115
125
  ws.on('close', (code) => {
126
+ if (!this.isCurrent(generation, ws)) return
116
127
  this.clearTimers()
117
- if (this.ws === ws) this.ws = null
128
+ this.ws = null
118
129
  if (NON_RECOVERABLE_CLOSE_CODES.includes(code)) {
119
130
  this.emitter.emit('error', new Error(`Discord gateway closed with non-recoverable code ${code}`))
120
131
  this.running = false
@@ -132,9 +143,11 @@ export class DiscordListener {
132
143
  })
133
144
 
134
145
  ws.on('error', (err) => {
146
+ if (!this.isCurrent(generation, ws)) return
135
147
  this.emitter.emit('error', err instanceof Error ? err : new Error(String(err)))
136
148
  })
137
149
  } catch (error) {
150
+ if (!this.isCurrent(generation)) return
138
151
  this.emitter.emit('error', error instanceof Error ? error : new Error(String(error)))
139
152
  if (this.running) {
140
153
  this.scheduleReconnect()
@@ -142,12 +155,13 @@ export class DiscordListener {
142
155
  }
143
156
  }
144
157
 
145
- private handleMessage(data: { op: number; d: any; s?: number; t?: string }): void {
158
+ private handleMessage(data: { op: number; d: any; s?: number; t?: string }, generation: number, ws: WebSocket): void {
159
+ if (!this.isCurrent(generation, ws)) return
146
160
  const { op, d, s, t } = data
147
161
 
148
162
  switch (op) {
149
163
  case DiscordGatewayOpcode.Hello:
150
- this.startHeartbeat(d.heartbeat_interval)
164
+ this.startHeartbeat(d.heartbeat_interval, generation, ws)
151
165
  if (this.sessionId) {
152
166
  this.sendResume()
153
167
  } else {
@@ -166,22 +180,21 @@ export class DiscordListener {
166
180
 
167
181
  case DiscordGatewayOpcode.Reconnect:
168
182
  this.reconnectAttempts = 0
169
- this.ws?.close()
183
+ ws.close()
170
184
  break
171
185
 
172
186
  case DiscordGatewayOpcode.InvalidSession: {
173
- const currentWs = this.ws
174
187
  if (d === true) {
175
188
  const delay = 1000 + Math.random() * 4000
176
189
  this.invalidSessionTimer = setTimeout(() => {
177
190
  this.invalidSessionTimer = null
178
- if (currentWs && currentWs === this.ws) currentWs.close()
191
+ if (this.isCurrent(generation, ws)) ws.close()
179
192
  }, delay)
180
193
  } else {
181
194
  this.sequence = null
182
195
  this.sessionId = null
183
196
  this.resumeGatewayUrl = null
184
- currentWs?.close()
197
+ ws.close()
185
198
  }
186
199
  break
187
200
  }
@@ -197,11 +210,13 @@ export class DiscordListener {
197
210
  this.sessionId = d.session_id
198
211
  this.resumeGatewayUrl = d.resume_gateway_url
199
212
  this.cachedUser = d.user
213
+ this.reconnectAttempts = 0
200
214
  this.emitter.emit('connected', { user: d.user, sessionId: d.session_id })
201
215
  return
202
216
  }
203
217
 
204
218
  if (t === 'RESUMED') {
219
+ this.reconnectAttempts = 0
205
220
  this.emitter.emit('connected', { user: this.cachedUser!, sessionId: this.sessionId! })
206
221
  return
207
222
  }
@@ -246,18 +261,23 @@ export class DiscordListener {
246
261
  this.ws?.send(JSON.stringify({ op: DiscordGatewayOpcode.Heartbeat, d: this.sequence }))
247
262
  }
248
263
 
249
- private startHeartbeat(interval: number): void {
264
+ private startHeartbeat(interval: number, generation: number, ws: WebSocket): void {
250
265
  this.clearHeartbeatTimers()
251
266
  this.heartbeatAckReceived = true
252
267
 
253
268
  this.heartbeatJitterTimer = setTimeout(() => {
254
269
  this.heartbeatJitterTimer = null
270
+ if (!this.isCurrent(generation, ws)) return
255
271
  this.heartbeatAckReceived = false
256
272
  this.sendHeartbeat()
257
273
 
258
274
  this.heartbeatTimer = setInterval(() => {
275
+ if (!this.isCurrent(generation, ws)) {
276
+ this.clearHeartbeatTimers()
277
+ return
278
+ }
259
279
  if (!this.heartbeatAckReceived) {
260
- this.ws?.close()
280
+ ws.close()
261
281
  return
262
282
  }
263
283
  this.heartbeatAckReceived = false
@@ -269,7 +289,11 @@ export class DiscordListener {
269
289
  private scheduleReconnect(): void {
270
290
  const delay = Math.min(RECONNECT_BASE_DELAY * 2 ** this.reconnectAttempts, RECONNECT_MAX_DELAY)
271
291
  this.reconnectAttempts++
272
- this.reconnectTimer = setTimeout(() => this.connect(), delay)
292
+ const generation = this.generation
293
+ this.reconnectTimer = setTimeout(() => {
294
+ this.reconnectTimer = null
295
+ this.connect(generation)
296
+ }, delay)
273
297
  }
274
298
 
275
299
  private clearHeartbeatTimers(): void {