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
@@ -0,0 +1,321 @@
1
+ import { EventEmitter } from 'events'
2
+
3
+ import WebSocket from 'ws'
4
+
5
+ import type { DiscordBotClient } from './client'
6
+ import type { DiscordBotListenerEventMap, DiscordGatewayGenericEvent } from './types'
7
+ import { DiscordGatewayOpcode, DiscordIntent } from './types'
8
+
9
+ const GATEWAY_URL = 'wss://gateway.discord.gg/?v=10&encoding=json'
10
+ const GATEWAY_QUERY = '?v=10&encoding=json'
11
+ const RECONNECT_BASE_DELAY = 1_000
12
+ const RECONNECT_MAX_DELAY = 30_000
13
+ const NON_RECOVERABLE_CLOSE_CODES = [4004, 4010, 4011, 4012, 4013, 4014]
14
+ const SESSION_RESET_CLOSE_CODES = [4007, 4009]
15
+
16
+ const DEFAULT_INTENTS =
17
+ DiscordIntent.Guilds |
18
+ DiscordIntent.GuildMessages |
19
+ DiscordIntent.GuildMessageReactions |
20
+ DiscordIntent.GuildMessageTyping |
21
+ DiscordIntent.DirectMessages |
22
+ DiscordIntent.DirectMessageReactions |
23
+ DiscordIntent.DirectMessageTyping
24
+
25
+ type EventKey = keyof DiscordBotListenerEventMap
26
+
27
+ export class DiscordBotListener {
28
+ private client: DiscordBotClient
29
+ private intents: number
30
+ private running = false
31
+ private ws: WebSocket | null = null
32
+ private emitter = new EventEmitter()
33
+ private heartbeatTimer: ReturnType<typeof setInterval> | null = null
34
+ private heartbeatAckReceived = true
35
+ private heartbeatJitterTimer: ReturnType<typeof setTimeout> | null = null
36
+ private invalidSessionTimer: ReturnType<typeof setTimeout> | null = null
37
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null
38
+ private reconnectAttempts = 0
39
+ private sequence: number | null = null
40
+ private sessionId: string | null = null
41
+ private resumeGatewayUrl: string | null = null
42
+ private token: string | null = null
43
+ private cachedUser: { id: string; username: string } | null = null
44
+ private generation = 0
45
+
46
+ constructor(client: DiscordBotClient, options?: { intents?: number }) {
47
+ this.client = client
48
+ this.intents = options?.intents ?? DEFAULT_INTENTS
49
+ }
50
+
51
+ async start(): Promise<void> {
52
+ if (this.running) return
53
+ this.running = true
54
+ this.reconnectAttempts = 0
55
+ this.generation++
56
+ await this.connect(this.generation)
57
+ }
58
+
59
+ stop(): void {
60
+ this.running = false
61
+ this.generation++
62
+ this.clearTimers()
63
+ if (this.ws) {
64
+ this.ws.close()
65
+ this.ws = null
66
+ }
67
+ this.sequence = null
68
+ this.sessionId = null
69
+ this.resumeGatewayUrl = null
70
+ this.token = null
71
+ this.cachedUser = null
72
+ }
73
+
74
+ on<K extends EventKey>(event: K, listener: (...args: DiscordBotListenerEventMap[K]) => void): this {
75
+ this.emitter.on(event, listener as (...args: any[]) => void)
76
+ return this
77
+ }
78
+
79
+ off<K extends EventKey>(event: K, listener: (...args: DiscordBotListenerEventMap[K]) => void): this {
80
+ this.emitter.off(event, listener as (...args: any[]) => void)
81
+ return this
82
+ }
83
+
84
+ once<K extends EventKey>(event: K, listener: (...args: DiscordBotListenerEventMap[K]) => void): this {
85
+ this.emitter.once(event, listener as (...args: any[]) => void)
86
+ return this
87
+ }
88
+
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
97
+
98
+ try {
99
+ const { token } = await this.client.gatewayConnect()
100
+ if (!this.isCurrent(generation)) return
101
+
102
+ this.token = token
103
+
104
+ const url = this.resumeGatewayUrl ? `${this.resumeGatewayUrl}${GATEWAY_QUERY}` : GATEWAY_URL
105
+ const ws = new WebSocket(url)
106
+ this.ws = ws
107
+
108
+ ws.on('open', () => {
109
+ if (!this.isCurrent(generation, ws)) {
110
+ ws.close()
111
+ return
112
+ }
113
+ })
114
+
115
+ ws.on('message', (raw) => {
116
+ if (!this.isCurrent(generation, ws)) return
117
+ try {
118
+ const data = JSON.parse(raw.toString())
119
+ this.handleMessage(data, generation, ws)
120
+ } catch {
121
+ // malformed gateway frame; ignore and let heartbeat handle liveness
122
+ }
123
+ })
124
+
125
+ ws.on('close', (code) => {
126
+ if (!this.isCurrent(generation, ws)) return
127
+ this.clearTimers()
128
+ this.ws = null
129
+ if (NON_RECOVERABLE_CLOSE_CODES.includes(code)) {
130
+ this.emitter.emit('error', new Error(`Discord gateway closed with non-recoverable code ${code}`))
131
+ this.running = false
132
+ return
133
+ }
134
+ if (SESSION_RESET_CLOSE_CODES.includes(code)) {
135
+ this.sequence = null
136
+ this.sessionId = null
137
+ this.resumeGatewayUrl = null
138
+ }
139
+ if (this.running) {
140
+ this.emitter.emit('disconnected')
141
+ this.scheduleReconnect()
142
+ }
143
+ })
144
+
145
+ ws.on('error', (err) => {
146
+ if (!this.isCurrent(generation, ws)) return
147
+ this.emitter.emit('error', err instanceof Error ? err : new Error(String(err)))
148
+ })
149
+ } catch (error) {
150
+ if (!this.isCurrent(generation)) return
151
+ this.emitter.emit('error', error instanceof Error ? error : new Error(String(error)))
152
+ if (this.running) {
153
+ this.scheduleReconnect()
154
+ }
155
+ }
156
+ }
157
+
158
+ private handleMessage(data: { op: number; d: any; s?: number; t?: string }, generation: number, ws: WebSocket): void {
159
+ if (!this.isCurrent(generation, ws)) return
160
+ const { op, d, s, t } = data
161
+
162
+ switch (op) {
163
+ case DiscordGatewayOpcode.Hello:
164
+ this.startHeartbeat(d.heartbeat_interval, generation, ws)
165
+ if (this.sessionId) {
166
+ this.sendResume()
167
+ } else {
168
+ this.sendIdentify()
169
+ }
170
+ break
171
+
172
+ case DiscordGatewayOpcode.HeartbeatACK:
173
+ this.heartbeatAckReceived = true
174
+ break
175
+
176
+ case DiscordGatewayOpcode.Dispatch:
177
+ if (typeof s === 'number') this.sequence = s
178
+ if (t) this.handleDispatch(t, d)
179
+ break
180
+
181
+ case DiscordGatewayOpcode.Reconnect:
182
+ this.reconnectAttempts = 0
183
+ ws.close()
184
+ break
185
+
186
+ case DiscordGatewayOpcode.InvalidSession: {
187
+ if (d === true) {
188
+ const delay = 1000 + Math.random() * 4000
189
+ this.invalidSessionTimer = setTimeout(() => {
190
+ this.invalidSessionTimer = null
191
+ if (this.isCurrent(generation, ws)) ws.close()
192
+ }, delay)
193
+ } else {
194
+ this.sequence = null
195
+ this.sessionId = null
196
+ this.resumeGatewayUrl = null
197
+ ws.close()
198
+ }
199
+ break
200
+ }
201
+
202
+ case DiscordGatewayOpcode.Heartbeat:
203
+ this.sendHeartbeat()
204
+ break
205
+ }
206
+ }
207
+
208
+ private handleDispatch(t: string, d: any): void {
209
+ if (t === 'READY') {
210
+ this.sessionId = d.session_id
211
+ this.resumeGatewayUrl = d.resume_gateway_url
212
+ this.cachedUser = d.user
213
+ this.reconnectAttempts = 0
214
+ this.emitter.emit('connected', { user: d.user, sessionId: d.session_id })
215
+ return
216
+ }
217
+
218
+ if (t === 'RESUMED') {
219
+ this.reconnectAttempts = 0
220
+ this.emitter.emit('connected', { user: this.cachedUser!, sessionId: this.sessionId! })
221
+ return
222
+ }
223
+
224
+ const eventType = t.toLowerCase()
225
+ const event: DiscordGatewayGenericEvent = { ...d, type: t }
226
+ this.emitter.emit(eventType, event)
227
+ this.emitter.emit('discord_event', event)
228
+ }
229
+
230
+ private sendIdentify(): void {
231
+ this.ws?.send(
232
+ JSON.stringify({
233
+ op: DiscordGatewayOpcode.Identify,
234
+ d: {
235
+ token: this.token,
236
+ intents: this.intents,
237
+ properties: {
238
+ os: 'linux',
239
+ browser: 'agent-messenger',
240
+ device: 'agent-messenger',
241
+ },
242
+ },
243
+ }),
244
+ )
245
+ }
246
+
247
+ private sendResume(): void {
248
+ this.ws?.send(
249
+ JSON.stringify({
250
+ op: DiscordGatewayOpcode.Resume,
251
+ d: {
252
+ token: this.token,
253
+ session_id: this.sessionId,
254
+ seq: this.sequence,
255
+ },
256
+ }),
257
+ )
258
+ }
259
+
260
+ private sendHeartbeat(): void {
261
+ this.ws?.send(JSON.stringify({ op: DiscordGatewayOpcode.Heartbeat, d: this.sequence }))
262
+ }
263
+
264
+ private startHeartbeat(interval: number, generation: number, ws: WebSocket): void {
265
+ this.clearHeartbeatTimers()
266
+ this.heartbeatAckReceived = true
267
+
268
+ this.heartbeatJitterTimer = setTimeout(() => {
269
+ this.heartbeatJitterTimer = null
270
+ if (!this.isCurrent(generation, ws)) return
271
+ this.heartbeatAckReceived = false
272
+ this.sendHeartbeat()
273
+
274
+ this.heartbeatTimer = setInterval(() => {
275
+ if (!this.isCurrent(generation, ws)) {
276
+ this.clearHeartbeatTimers()
277
+ return
278
+ }
279
+ if (!this.heartbeatAckReceived) {
280
+ ws.close()
281
+ return
282
+ }
283
+ this.heartbeatAckReceived = false
284
+ this.sendHeartbeat()
285
+ }, interval)
286
+ }, Math.random() * interval)
287
+ }
288
+
289
+ private scheduleReconnect(): void {
290
+ const delay = Math.min(RECONNECT_BASE_DELAY * 2 ** this.reconnectAttempts, RECONNECT_MAX_DELAY)
291
+ this.reconnectAttempts++
292
+ const generation = this.generation
293
+ this.reconnectTimer = setTimeout(() => {
294
+ this.reconnectTimer = null
295
+ this.connect(generation)
296
+ }, delay)
297
+ }
298
+
299
+ private clearHeartbeatTimers(): void {
300
+ if (this.heartbeatTimer) {
301
+ clearInterval(this.heartbeatTimer)
302
+ this.heartbeatTimer = null
303
+ }
304
+ if (this.heartbeatJitterTimer) {
305
+ clearTimeout(this.heartbeatJitterTimer)
306
+ this.heartbeatJitterTimer = null
307
+ }
308
+ }
309
+
310
+ private clearTimers(): void {
311
+ this.clearHeartbeatTimers()
312
+ if (this.invalidSessionTimer) {
313
+ clearTimeout(this.invalidSessionTimer)
314
+ this.invalidSessionTimer = null
315
+ }
316
+ if (this.reconnectTimer) {
317
+ clearTimeout(this.reconnectTimer)
318
+ this.reconnectTimer = null
319
+ }
320
+ }
321
+ }
@@ -187,3 +187,166 @@ export const DiscordFileSchema = z.object({
187
187
  height: z.number().optional(),
188
188
  width: z.number().optional(),
189
189
  })
190
+
191
+ export const DiscordGatewayOpcode = {
192
+ Dispatch: 0,
193
+ Heartbeat: 1,
194
+ Identify: 2,
195
+ PresenceUpdate: 3,
196
+ VoiceStateUpdate: 4,
197
+ Resume: 6,
198
+ Reconnect: 7,
199
+ RequestGuildMembers: 8,
200
+ InvalidSession: 9,
201
+ Hello: 10,
202
+ HeartbeatACK: 11,
203
+ } as const
204
+
205
+ export const DiscordIntent = {
206
+ Guilds: 1 << 0,
207
+ GuildMembers: 1 << 1, // privileged
208
+ GuildModeration: 1 << 2,
209
+ GuildEmojisAndStickers: 1 << 3,
210
+ GuildIntegrations: 1 << 4,
211
+ GuildWebhooks: 1 << 5,
212
+ GuildInvites: 1 << 6,
213
+ GuildVoiceStates: 1 << 7,
214
+ GuildPresences: 1 << 8, // privileged
215
+ GuildMessages: 1 << 9,
216
+ GuildMessageReactions: 1 << 10,
217
+ GuildMessageTyping: 1 << 11,
218
+ DirectMessages: 1 << 12,
219
+ DirectMessageReactions: 1 << 13,
220
+ DirectMessageTyping: 1 << 14,
221
+ MessageContent: 1 << 15, // privileged
222
+ GuildScheduledEvents: 1 << 16,
223
+ AutoModerationConfiguration: 1 << 20,
224
+ AutoModerationExecution: 1 << 21,
225
+ } as const
226
+
227
+ export interface DiscordGatewayMessageCreateEvent {
228
+ type: 'MESSAGE_CREATE'
229
+ id: string
230
+ channel_id: string
231
+ guild_id?: string
232
+ author: { id: string; username: string; bot?: boolean }
233
+ content: string
234
+ timestamp: string
235
+ edited_timestamp?: string
236
+ mentions?: DiscordUser[]
237
+ attachments?: DiscordFile[]
238
+ }
239
+
240
+ export interface DiscordGatewayMessageUpdateEvent {
241
+ type: 'MESSAGE_UPDATE'
242
+ id: string
243
+ channel_id: string
244
+ guild_id?: string
245
+ content?: string
246
+ edited_timestamp?: string
247
+ }
248
+
249
+ export interface DiscordGatewayMessageDeleteEvent {
250
+ type: 'MESSAGE_DELETE'
251
+ id: string
252
+ channel_id: string
253
+ guild_id?: string
254
+ }
255
+
256
+ export interface DiscordGatewayReactionEvent {
257
+ type: 'MESSAGE_REACTION_ADD' | 'MESSAGE_REACTION_REMOVE'
258
+ user_id: string
259
+ channel_id: string
260
+ message_id: string
261
+ guild_id?: string
262
+ emoji: { id?: string; name: string }
263
+ }
264
+
265
+ export interface DiscordGatewayMemberEvent {
266
+ type: 'GUILD_MEMBER_ADD' | 'GUILD_MEMBER_REMOVE'
267
+ guild_id: string
268
+ user: { id: string; username: string }
269
+ }
270
+
271
+ export interface DiscordGatewayTypingEvent {
272
+ type: 'TYPING_START'
273
+ user_id: string
274
+ channel_id: string
275
+ guild_id?: string
276
+ timestamp: number
277
+ }
278
+
279
+ export interface DiscordGatewayPresenceEvent {
280
+ type: 'PRESENCE_UPDATE'
281
+ user: { id: string }
282
+ guild_id: string
283
+ status: 'online' | 'idle' | 'dnd' | 'offline'
284
+ activities?: Array<{ name: string; type: number }>
285
+ }
286
+
287
+ export interface DiscordGatewayChannelEvent {
288
+ type: 'CHANNEL_CREATE' | 'CHANNEL_UPDATE' | 'CHANNEL_DELETE'
289
+ id: string
290
+ guild_id?: string
291
+ name?: string
292
+ }
293
+
294
+ export interface DiscordGatewayGuildEvent {
295
+ type: 'GUILD_CREATE' | 'GUILD_UPDATE' | 'GUILD_DELETE'
296
+ id: string
297
+ name?: string
298
+ unavailable?: boolean
299
+ }
300
+
301
+ export interface DiscordGatewayInteractionEvent {
302
+ type: 'INTERACTION_CREATE'
303
+ id: string
304
+ application_id: string
305
+ token: string
306
+ data?: Record<string, unknown>
307
+ channel_id?: string
308
+ guild_id?: string
309
+ member?: Record<string, unknown>
310
+ user?: { id: string; username: string }
311
+ }
312
+
313
+ export interface DiscordGatewayGenericEvent {
314
+ type: string
315
+ [key: string]: unknown
316
+ }
317
+
318
+ export type DiscordGatewayEvent =
319
+ | DiscordGatewayMessageCreateEvent
320
+ | DiscordGatewayMessageUpdateEvent
321
+ | DiscordGatewayMessageDeleteEvent
322
+ | DiscordGatewayReactionEvent
323
+ | DiscordGatewayMemberEvent
324
+ | DiscordGatewayTypingEvent
325
+ | DiscordGatewayPresenceEvent
326
+ | DiscordGatewayChannelEvent
327
+ | DiscordGatewayGuildEvent
328
+ | DiscordGatewayInteractionEvent
329
+ | DiscordGatewayGenericEvent
330
+
331
+ export interface DiscordBotListenerEventMap {
332
+ message_create: [event: DiscordGatewayMessageCreateEvent]
333
+ message_update: [event: DiscordGatewayMessageUpdateEvent]
334
+ message_delete: [event: DiscordGatewayMessageDeleteEvent]
335
+ message_reaction_add: [event: DiscordGatewayReactionEvent]
336
+ message_reaction_remove: [event: DiscordGatewayReactionEvent]
337
+ guild_member_add: [event: DiscordGatewayMemberEvent]
338
+ guild_member_remove: [event: DiscordGatewayMemberEvent]
339
+ presence_update: [event: DiscordGatewayPresenceEvent]
340
+ typing_start: [event: DiscordGatewayTypingEvent]
341
+ channel_create: [event: DiscordGatewayChannelEvent]
342
+ channel_update: [event: DiscordGatewayChannelEvent]
343
+ channel_delete: [event: DiscordGatewayChannelEvent]
344
+ guild_create: [event: DiscordGatewayGuildEvent]
345
+ guild_update: [event: DiscordGatewayGuildEvent]
346
+ guild_delete: [event: DiscordGatewayGuildEvent]
347
+ interaction_create: [event: DiscordGatewayInteractionEvent]
348
+ discord_event: [event: DiscordGatewayGenericEvent]
349
+ connected: [info: { user: { id: string; username: string }; sessionId: string }]
350
+ disconnected: []
351
+ error: [error: Error]
352
+ }
@@ -1,4 +1,4 @@
1
- import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from 'bun:test'
1
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'bun:test'
2
2
  import { generateKeyPairSync } from 'node:crypto'
3
3
  import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
4
4
  import { join } from 'node:path'
@@ -82,14 +82,14 @@ async function loadedClient(): Promise<InstagramClient> {
82
82
 
83
83
  describe('InstagramClient', () => {
84
84
  describe('constructor', () => {
85
- test('creates instance with default credential manager', () => {
85
+ it('creates instance with default credential manager', () => {
86
86
  const client = new InstagramClient()
87
87
  expect(client).toBeInstanceOf(InstagramClient)
88
88
  })
89
89
  })
90
90
 
91
91
  describe('login', () => {
92
- test('throws when no account configured', async () => {
92
+ it('throws when no account configured', async () => {
93
93
  const mockManager = {
94
94
  getAccount: () => Promise.resolve(null),
95
95
  } as any
@@ -100,7 +100,7 @@ describe('InstagramClient', () => {
100
100
  await expect(client.login()).rejects.toThrow('No Instagram credentials found')
101
101
  })
102
102
 
103
- test('loads session from disk when file exists', async () => {
103
+ it('loads session from disk when file exists', async () => {
104
104
  const mockManager = {
105
105
  getAccount: () =>
106
106
  Promise.resolve({ account_id: 'testuser', username: 'testuser', created_at: '', updated_at: '' }),
@@ -116,7 +116,7 @@ describe('InstagramClient', () => {
116
116
  })
117
117
 
118
118
  describe('plaintextPassword format', () => {
119
- test('produces #PWD_INSTAGRAM:0:timestamp:rawpassword format', async () => {
119
+ it('produces #PWD_INSTAGRAM:0:timestamp:rawpassword format', async () => {
120
120
  fetchResponses.push(
121
121
  new Response(null, {
122
122
  status: 200,
@@ -142,7 +142,7 @@ describe('InstagramClient', () => {
142
142
  })
143
143
 
144
144
  describe('encryptPassword format', () => {
145
- test('produces #PWD_INSTAGRAM:4:timestamp:base64 format when encryption key provided', async () => {
145
+ it('produces #PWD_INSTAGRAM:4:timestamp:base64 format when encryption key provided', async () => {
146
146
  fetchResponses.push(
147
147
  new Response(null, {
148
148
  status: 200,
@@ -173,7 +173,7 @@ describe('InstagramClient', () => {
173
173
  })
174
174
 
175
175
  describe('buildHeaders', () => {
176
- test('includes required Instagram headers', async () => {
176
+ it('includes required Instagram headers', async () => {
177
177
  fetchResponses.push(new Response(null, { status: 200, headers: {} }))
178
178
  fetchResponses.push(jsonResponse({ status: 'ok', logged_in_user: { pk: '99' } }))
179
179
 
@@ -189,7 +189,7 @@ describe('InstagramClient', () => {
189
189
  expect(headers['Content-Type']).toContain('application/x-www-form-urlencoded')
190
190
  })
191
191
 
192
- test('includes device headers when session is set', async () => {
192
+ it('includes device headers when session is set', async () => {
193
193
  fetchResponses.push(jsonResponse({ status: 'ok', inbox: { threads: [] } }))
194
194
 
195
195
  const client = await loadedClient()
@@ -204,7 +204,7 @@ describe('InstagramClient', () => {
204
204
  })
205
205
 
206
206
  describe('mapThread', () => {
207
- test('maps API thread to InstagramChatSummary', async () => {
207
+ it('maps API thread to InstagramChatSummary', async () => {
208
208
  const thread = {
209
209
  thread_id: 'thread-42',
210
210
  thread_title: 'Team Chat',
@@ -231,7 +231,7 @@ describe('InstagramClient', () => {
231
231
  expect(chat.participant_count).toBe(3)
232
232
  })
233
233
 
234
- test('falls back to user names when no thread_title', async () => {
234
+ it('falls back to user names when no thread_title', async () => {
235
235
  const thread = {
236
236
  thread_id: 't-1',
237
237
  thread_type: 'private',
@@ -250,7 +250,7 @@ describe('InstagramClient', () => {
250
250
  })
251
251
 
252
252
  describe('mapMessage', () => {
253
- test('maps API item to InstagramMessageSummary with media_url', async () => {
253
+ it('maps API item to InstagramMessageSummary with media_url', async () => {
254
254
  const item = {
255
255
  item_id: 'msg-7',
256
256
  user_id: '10',
@@ -282,7 +282,7 @@ describe('InstagramClient', () => {
282
282
  expect(msg.media_url).toBe('https://cdn.example.com/photo.jpg')
283
283
  })
284
284
 
285
- test('sets is_outgoing true when from matches userId', async () => {
285
+ it('sets is_outgoing true when from matches userId', async () => {
286
286
  const item = {
287
287
  item_id: 'msg-8',
288
288
  user_id: '42',
@@ -300,7 +300,7 @@ describe('InstagramClient', () => {
300
300
  })
301
301
 
302
302
  describe('request', () => {
303
- test('throws rate_limited on 429', async () => {
303
+ it('throws rate_limited on 429', async () => {
304
304
  fetchResponses.push(new Response('Rate limited', { status: 429 }))
305
305
 
306
306
  const client = await loadedClient()
@@ -310,7 +310,7 @@ describe('InstagramClient', () => {
310
310
  expect((err as InstagramError).code).toBe('rate_limited')
311
311
  })
312
312
 
313
- test('throws on JSON parse error', async () => {
313
+ it('throws on JSON parse error', async () => {
314
314
  fetchResponses.push(new Response('not json', { status: 200 }))
315
315
 
316
316
  const client = await loadedClient()
@@ -318,7 +318,7 @@ describe('InstagramClient', () => {
318
318
  await expect(client.listChats()).rejects.toThrow(InstagramError)
319
319
  })
320
320
 
321
- test('returns parsed response on success', async () => {
321
+ it('returns parsed response on success', async () => {
322
322
  fetchResponses.push(jsonResponse({ status: 'ok', inbox: { threads: [] } }))
323
323
 
324
324
  const client = await loadedClient()
@@ -329,7 +329,7 @@ describe('InstagramClient', () => {
329
329
  })
330
330
 
331
331
  describe('searchUsers', () => {
332
- test('maps response to user list', async () => {
332
+ it('maps response to user list', async () => {
333
333
  fetchResponses.push(
334
334
  jsonResponse({
335
335
  status: 'ok',
@@ -350,7 +350,7 @@ describe('InstagramClient', () => {
350
350
  })
351
351
 
352
352
  describe('sendMessage', () => {
353
- test('sends correct body params', async () => {
353
+ it('sends correct body params', async () => {
354
354
  fetchResponses.push(
355
355
  jsonResponse({
356
356
  status: 'ok',
@@ -370,7 +370,7 @@ describe('InstagramClient', () => {
370
370
  })
371
371
 
372
372
  describe('sendMessageToUser', () => {
373
- test('sends correct body params', async () => {
373
+ it('sends correct body params', async () => {
374
374
  fetchResponses.push(
375
375
  jsonResponse({
376
376
  status: 'ok',