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, beforeEach, describe, expect, mock, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, it } from 'bun:test'
2
2
  import { existsSync, rmSync } from 'node:fs'
3
3
  import { mkdir } from 'node:fs/promises'
4
4
  import { tmpdir } from 'node:os'
@@ -67,7 +67,7 @@ describe('snapshot command', () => {
67
67
  })
68
68
 
69
69
  describe('snapshotAction', () => {
70
- test('brief snapshot returns workspace, groups (names), chat counts, and hint', async () => {
70
+ it('brief snapshot returns workspace, groups (names), chat counts, and hint', async () => {
71
71
  const manager = new ChannelBotCredentialManager(tempDir)
72
72
  const result = await snapshotAction({ _credManager: manager })
73
73
 
@@ -85,7 +85,7 @@ describe('snapshot command', () => {
85
85
  expect(mockGetGroupMessages).not.toHaveBeenCalled()
86
86
  })
87
87
 
88
- test('full snapshot returns workspace, groups, user_chats, managers, bots', async () => {
88
+ it('full snapshot returns workspace, groups, user_chats, managers, bots', async () => {
89
89
  const manager = new ChannelBotCredentialManager(tempDir)
90
90
  const result = await snapshotAction({ full: true, _credManager: manager })
91
91
 
@@ -99,7 +99,7 @@ describe('snapshot command', () => {
99
99
  expect(result.bots).toBeDefined()
100
100
  })
101
101
 
102
- test('groups-only flag skips user_chats, managers, bots', async () => {
102
+ it('groups-only flag skips user_chats, managers, bots', async () => {
103
103
  const manager = new ChannelBotCredentialManager(tempDir)
104
104
  const result = await snapshotAction({ full: true, groupsOnly: true, _credManager: manager })
105
105
 
@@ -111,7 +111,7 @@ describe('snapshot command', () => {
111
111
  expect(result.bots).toBeUndefined()
112
112
  })
113
113
 
114
- test('chats-only flag skips groups, managers, bots', async () => {
114
+ it('chats-only flag skips groups, managers, bots', async () => {
115
115
  const manager = new ChannelBotCredentialManager(tempDir)
116
116
  const result = await snapshotAction({ full: true, chatsOnly: true, _credManager: manager })
117
117
 
@@ -123,7 +123,7 @@ describe('snapshot command', () => {
123
123
  expect(result.bots).toBeUndefined()
124
124
  })
125
125
 
126
- test('full groups include recent messages', async () => {
126
+ it('full groups include recent messages', async () => {
127
127
  const manager = new ChannelBotCredentialManager(tempDir)
128
128
  const result = await snapshotAction({ full: true, groupsOnly: true, limit: 3, _credManager: manager })
129
129
 
@@ -131,7 +131,7 @@ describe('snapshot command', () => {
131
131
  expect(result.groups?.[0].messages?.[0].id).toBe('msg1')
132
132
  })
133
133
 
134
- test('full user_chats includes counts and recent opened', async () => {
134
+ it('full user_chats includes counts and recent opened', async () => {
135
135
  const manager = new ChannelBotCredentialManager(tempDir)
136
136
  const result = await snapshotAction({ full: true, chatsOnly: true, _credManager: manager })
137
137
 
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, it } from 'bun:test'
2
2
  import { existsSync, rmSync } from 'node:fs'
3
3
  import { mkdir } from 'node:fs/promises'
4
4
  import { tmpdir } from 'node:os'
@@ -35,6 +35,8 @@ describe('whoami command', () => {
35
35
  originalEnv = { ...process.env }
36
36
  delete process.env.E2E_CHANNELBOT_ACCESS_KEY
37
37
  delete process.env.E2E_CHANNELBOT_ACCESS_SECRET
38
+ delete process.env.E2E_CHANNELTALKBOT_ACCESS_KEY
39
+ delete process.env.E2E_CHANNELTALKBOT_ACCESS_SECRET
38
40
  mockGetChannel.mockClear()
39
41
  })
40
42
 
@@ -45,7 +47,7 @@ describe('whoami command', () => {
45
47
  process.env = originalEnv
46
48
  })
47
49
 
48
- test('returns channel info for current workspace', async () => {
50
+ it('returns channel info for current workspace', async () => {
49
51
  const manager = new ChannelBotCredentialManager(tempDir)
50
52
  await manager.setCredentials({
51
53
  workspace_id: 'workspace1',
@@ -63,7 +65,7 @@ describe('whoami command', () => {
63
65
  expect(result.error).toBeUndefined()
64
66
  })
65
67
 
66
- test('returns channel info for specific --workspace', async () => {
68
+ it('returns channel info for specific --workspace', async () => {
67
69
  const manager = new ChannelBotCredentialManager(tempDir)
68
70
  await manager.setCredentials({
69
71
  workspace_id: 'workspace1',
@@ -85,7 +87,7 @@ describe('whoami command', () => {
85
87
  expect(mockGetChannel).toHaveBeenCalledTimes(1)
86
88
  })
87
89
 
88
- test('returns error when client throws', async () => {
90
+ it('returns error when client throws', async () => {
89
91
  mockGetChannel.mockImplementationOnce(() => Promise.reject(new Error('API Error')))
90
92
 
91
93
  const manager = new ChannelBotCredentialManager(tempDir)
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander'
2
2
 
3
- import { formatOutput } from '@/shared/utils/output'
3
+ import { cliOutput } from '@/shared/utils/cli-output'
4
4
 
5
5
  import type { WorkspaceOption } from './shared'
6
6
  import { getClient } from './shared'
@@ -28,11 +28,6 @@ export async function whoamiAction(options: WorkspaceOption): Promise<WhoamiResu
28
28
  }
29
29
  }
30
30
 
31
- function cliOutput(result: WhoamiResult, pretty?: boolean): void {
32
- console.log(formatOutput(result, pretty))
33
- if (result.error) process.exit(1)
34
- }
35
-
36
31
  export const whoamiCommand = new Command('whoami')
37
32
  .description('Show current authenticated bot')
38
33
  .option('--workspace <id>', 'Workspace ID to use')
@@ -1,6 +1,6 @@
1
- import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
2
2
  import { existsSync, rmSync } from 'node:fs'
3
- import { mkdir, stat } from 'node:fs/promises'
3
+ import { mkdir, readFile, stat, writeFile } from 'node:fs/promises'
4
4
  import { tmpdir } from 'node:os'
5
5
  import { join } from 'node:path'
6
6
 
@@ -36,10 +36,12 @@ describe('ChannelBotCredentialManager', () => {
36
36
  }
37
37
  delete process.env.E2E_CHANNELBOT_ACCESS_KEY
38
38
  delete process.env.E2E_CHANNELBOT_ACCESS_SECRET
39
+ delete process.env.E2E_CHANNELTALKBOT_ACCESS_KEY
40
+ delete process.env.E2E_CHANNELTALKBOT_ACCESS_SECRET
39
41
  })
40
42
 
41
43
  describe('load', () => {
42
- test('returns empty config when no file exists', async () => {
44
+ it('returns empty config when no file exists', async () => {
43
45
  const config = await manager.load()
44
46
 
45
47
  expect(config.current).toBeNull()
@@ -49,7 +51,7 @@ describe('ChannelBotCredentialManager', () => {
49
51
  })
50
52
 
51
53
  describe('save and load', () => {
52
- test('persists config to file', async () => {
54
+ it('persists config to file', async () => {
53
55
  const config = {
54
56
  current: { workspace_id: 'ch_abc123' },
55
57
  workspaces: {
@@ -71,11 +73,11 @@ describe('ChannelBotCredentialManager', () => {
71
73
  })
72
74
 
73
75
  describe('getCredentials', () => {
74
- test('returns null when no credentials exist', async () => {
76
+ it('returns null when no credentials exist', async () => {
75
77
  expect(await manager.getCredentials()).toBeNull()
76
78
  })
77
79
 
78
- test('returns current workspace credentials', async () => {
80
+ it('returns current workspace credentials', async () => {
79
81
  await manager.setCredentials(WORKSPACE_A)
80
82
 
81
83
  const creds = await manager.getCredentials()
@@ -83,7 +85,7 @@ describe('ChannelBotCredentialManager', () => {
83
85
  expect(creds).toEqual(WORKSPACE_A)
84
86
  })
85
87
 
86
- test('returns specific workspace by id', async () => {
88
+ it('returns specific workspace by id', async () => {
87
89
  await manager.setCredentials(WORKSPACE_A)
88
90
  await manager.setCredentials(WORKSPACE_B)
89
91
 
@@ -92,7 +94,7 @@ describe('ChannelBotCredentialManager', () => {
92
94
  expect(creds).toEqual(WORKSPACE_A)
93
95
  })
94
96
 
95
- test('returns null for non-existent workspace id', async () => {
97
+ it('returns null for non-existent workspace id', async () => {
96
98
  await manager.setCredentials(WORKSPACE_A)
97
99
 
98
100
  const creds = await manager.getCredentials('nonexistent')
@@ -100,7 +102,7 @@ describe('ChannelBotCredentialManager', () => {
100
102
  expect(creds).toBeNull()
101
103
  })
102
104
 
103
- test('env vars take precedence when no workspaceId specified', async () => {
105
+ it('env vars take precedence when no workspaceId specified', async () => {
104
106
  await manager.setCredentials(WORKSPACE_A)
105
107
 
106
108
  process.env.E2E_CHANNELBOT_ACCESS_KEY = 'env-key'
@@ -114,7 +116,7 @@ describe('ChannelBotCredentialManager', () => {
114
116
  expect(creds?.workspace_name).toBe('env')
115
117
  })
116
118
 
117
- test('env vars ignored when workspaceId explicitly provided', async () => {
119
+ it('env vars ignored when workspaceId explicitly provided', async () => {
118
120
  await manager.setCredentials(WORKSPACE_A)
119
121
 
120
122
  process.env.E2E_CHANNELBOT_ACCESS_KEY = 'env-key'
@@ -129,7 +131,7 @@ describe('ChannelBotCredentialManager', () => {
129
131
  })
130
132
 
131
133
  describe('setCredentials', () => {
132
- test('stores workspace and sets as current', async () => {
134
+ it('stores workspace and sets as current', async () => {
133
135
  await manager.setCredentials(WORKSPACE_A)
134
136
 
135
137
  const config = await manager.load()
@@ -137,7 +139,7 @@ describe('ChannelBotCredentialManager', () => {
137
139
  expect(config.workspaces['ch_abc123']).toEqual(WORKSPACE_A)
138
140
  })
139
141
 
140
- test('stores multiple workspaces', async () => {
142
+ it('stores multiple workspaces', async () => {
141
143
  await manager.setCredentials(WORKSPACE_A)
142
144
  await manager.setCredentials(WORKSPACE_B)
143
145
 
@@ -146,7 +148,7 @@ describe('ChannelBotCredentialManager', () => {
146
148
  expect(config.current).toEqual({ workspace_id: 'ch_def456' })
147
149
  })
148
150
 
149
- test('overwrites existing workspace with same id', async () => {
151
+ it('overwrites existing workspace with same id', async () => {
150
152
  await manager.setCredentials(WORKSPACE_A)
151
153
  const updated = { ...WORKSPACE_A, workspace_name: 'Updated Company A' }
152
154
  await manager.setCredentials(updated)
@@ -158,7 +160,7 @@ describe('ChannelBotCredentialManager', () => {
158
160
  })
159
161
 
160
162
  describe('listAll', () => {
161
- test('returns all workspaces with current flag', async () => {
163
+ it('returns all workspaces with current flag', async () => {
162
164
  await manager.setCredentials(WORKSPACE_A)
163
165
  await manager.setCredentials(WORKSPACE_B)
164
166
 
@@ -169,7 +171,7 @@ describe('ChannelBotCredentialManager', () => {
169
171
  expect(all.find((w) => w.workspace_id === 'ch_def456')?.is_current).toBe(true)
170
172
  })
171
173
 
172
- test('returns empty array when no workspaces exist', async () => {
174
+ it('returns empty array when no workspaces exist', async () => {
173
175
  const all = await manager.listAll()
174
176
 
175
177
  expect(all).toEqual([])
@@ -177,7 +179,7 @@ describe('ChannelBotCredentialManager', () => {
177
179
  })
178
180
 
179
181
  describe('setCurrent', () => {
180
- test('switches current workspace', async () => {
182
+ it('switches current workspace', async () => {
181
183
  await manager.setCredentials(WORKSPACE_A)
182
184
  await manager.setCredentials(WORKSPACE_B)
183
185
 
@@ -188,13 +190,13 @@ describe('ChannelBotCredentialManager', () => {
188
190
  expect(creds?.workspace_id).toBe('ch_abc123')
189
191
  })
190
192
 
191
- test('returns false for unknown workspace', async () => {
193
+ it('returns false for unknown workspace', async () => {
192
194
  expect(await manager.setCurrent('nonexistent')).toBe(false)
193
195
  })
194
196
  })
195
197
 
196
198
  describe('removeWorkspace', () => {
197
- test('removes a workspace by id', async () => {
199
+ it('removes a workspace by id', async () => {
198
200
  await manager.setCredentials(WORKSPACE_A)
199
201
  await manager.setCredentials(WORKSPACE_B)
200
202
 
@@ -205,7 +207,7 @@ describe('ChannelBotCredentialManager', () => {
205
207
  expect(Object.keys(config.workspaces)).toEqual(['ch_def456'])
206
208
  })
207
209
 
208
- test('clears current when current workspace removed', async () => {
210
+ it('clears current when current workspace removed', async () => {
209
211
  await manager.setCredentials(WORKSPACE_A)
210
212
 
211
213
  await manager.removeWorkspace('ch_abc123')
@@ -214,11 +216,11 @@ describe('ChannelBotCredentialManager', () => {
214
216
  expect(config.current).toBeNull()
215
217
  })
216
218
 
217
- test('returns false for unknown workspace', async () => {
219
+ it('returns false for unknown workspace', async () => {
218
220
  expect(await manager.removeWorkspace('nonexistent')).toBe(false)
219
221
  })
220
222
 
221
- test('does not clear current if removing non-current workspace', async () => {
223
+ it('does not clear current if removing non-current workspace', async () => {
222
224
  await manager.setCredentials(WORKSPACE_A)
223
225
  await manager.setCredentials(WORKSPACE_B)
224
226
 
@@ -230,7 +232,7 @@ describe('ChannelBotCredentialManager', () => {
230
232
  })
231
233
 
232
234
  describe('clearCredentials', () => {
233
- test('removes all credentials', async () => {
235
+ it('removes all credentials', async () => {
234
236
  await manager.setCredentials(WORKSPACE_A)
235
237
  await manager.setCredentials(WORKSPACE_B)
236
238
 
@@ -244,13 +246,13 @@ describe('ChannelBotCredentialManager', () => {
244
246
  })
245
247
 
246
248
  describe('getDefaultBot', () => {
247
- test('returns null initially', async () => {
249
+ it('returns null initially', async () => {
248
250
  const bot = await manager.getDefaultBot()
249
251
 
250
252
  expect(bot).toBeNull()
251
253
  })
252
254
 
253
- test('returns default bot name', async () => {
255
+ it('returns default bot name', async () => {
254
256
  await manager.setDefaultBot('my-bot')
255
257
 
256
258
  const bot = await manager.getDefaultBot()
@@ -260,7 +262,7 @@ describe('ChannelBotCredentialManager', () => {
260
262
  })
261
263
 
262
264
  describe('setDefaultBot', () => {
263
- test('saves and retrieves default bot', async () => {
265
+ it('saves and retrieves default bot', async () => {
264
266
  await manager.setDefaultBot('my-bot')
265
267
 
266
268
  const bot = await manager.getDefaultBot()
@@ -268,7 +270,7 @@ describe('ChannelBotCredentialManager', () => {
268
270
  expect(bot).toBe('my-bot')
269
271
  })
270
272
 
271
- test('updates existing default bot', async () => {
273
+ it('updates existing default bot', async () => {
272
274
  await manager.setDefaultBot('bot-1')
273
275
  await manager.setDefaultBot('bot-2')
274
276
 
@@ -277,7 +279,7 @@ describe('ChannelBotCredentialManager', () => {
277
279
  expect(bot).toBe('bot-2')
278
280
  })
279
281
 
280
- test('scopes default bot to current workspace', async () => {
282
+ it('scopes default bot to current workspace', async () => {
281
283
  // given
282
284
  await manager.setCredentials(WORKSPACE_A)
283
285
  await manager.setDefaultBot('bot-a')
@@ -296,13 +298,105 @@ describe('ChannelBotCredentialManager', () => {
296
298
  })
297
299
 
298
300
  describe('file permissions', () => {
299
- test('saves file with secure permissions (600)', async () => {
301
+ it('saves file with secure permissions (600)', async () => {
300
302
  await manager.setCredentials(WORKSPACE_A)
301
303
 
302
- const credPath = join(tempDir, 'channelbot-credentials.json')
304
+ const credPath = join(tempDir, 'channeltalkbot-credentials.json')
303
305
  const stats = await stat(credPath)
304
306
 
305
307
  expect(stats.mode & 0o777).toBe(0o600)
306
308
  })
307
309
  })
310
+
311
+ describe('legacy filename migration', () => {
312
+ it('renames channelbot-credentials.json to channeltalkbot-credentials.json on load', async () => {
313
+ const legacyPath = join(tempDir, 'channelbot-credentials.json')
314
+ const newPath = join(tempDir, 'channeltalkbot-credentials.json')
315
+ const legacyConfig = {
316
+ current: { workspace_id: WORKSPACE_A.workspace_id },
317
+ workspaces: { [WORKSPACE_A.workspace_id]: WORKSPACE_A },
318
+ default_bot: null,
319
+ }
320
+ await writeFile(legacyPath, JSON.stringify(legacyConfig))
321
+
322
+ const config = await manager.load()
323
+
324
+ expect(config.workspaces[WORKSPACE_A.workspace_id]).toEqual(WORKSPACE_A)
325
+ expect(existsSync(legacyPath)).toBe(false)
326
+ expect(existsSync(newPath)).toBe(true)
327
+ const migrated = JSON.parse(await readFile(newPath, 'utf-8'))
328
+ expect(migrated.workspaces[WORKSPACE_A.workspace_id]).toEqual(WORKSPACE_A)
329
+ })
330
+
331
+ it('does not overwrite an existing channeltalkbot-credentials.json', async () => {
332
+ const legacyPath = join(tempDir, 'channelbot-credentials.json')
333
+ const newPath = join(tempDir, 'channeltalkbot-credentials.json')
334
+ await writeFile(legacyPath, JSON.stringify({ workspaces: { stale: WORKSPACE_A } }))
335
+ const newConfig = {
336
+ current: { workspace_id: WORKSPACE_B.workspace_id },
337
+ workspaces: { [WORKSPACE_B.workspace_id]: WORKSPACE_B },
338
+ default_bot: null,
339
+ }
340
+ await writeFile(newPath, JSON.stringify(newConfig))
341
+
342
+ const config = await manager.load()
343
+
344
+ expect(config.workspaces[WORKSPACE_B.workspace_id]).toEqual(WORKSPACE_B)
345
+ expect(config.workspaces['stale']).toBeUndefined()
346
+ expect(existsSync(legacyPath)).toBe(true)
347
+ })
348
+
349
+ it('does not write back to legacy path when migration fails (no split-brain)', async () => {
350
+ const legacyPath = join(tempDir, 'channelbot-credentials.json')
351
+ const newPath = join(tempDir, 'channeltalkbot-credentials.json')
352
+ await writeFile(legacyPath, JSON.stringify({ workspaces: {}, default_bot: null }))
353
+
354
+ // Inject a rename that fails on first call to simulate a concurrent migration losing the race.
355
+ class FailingMigrationManager extends ChannelBotCredentialManager {
356
+ constructor(dir: string) {
357
+ super(dir)
358
+ let called = false
359
+ this.renameFile = async () => {
360
+ if (!called) {
361
+ called = true
362
+ throw new Error('ENOENT: simulated concurrent rename winner')
363
+ }
364
+ }
365
+ }
366
+ }
367
+ const failingManager = new FailingMigrationManager(tempDir)
368
+
369
+ await failingManager.load()
370
+ await failingManager.setCredentials(WORKSPACE_A)
371
+
372
+ // After failure, the manager must write to the NEW path, never re-create the legacy file.
373
+ expect(existsSync(newPath)).toBe(true)
374
+ const persisted = JSON.parse(await readFile(newPath, 'utf-8'))
375
+ expect(persisted.workspaces[WORKSPACE_A.workspace_id]).toEqual(WORKSPACE_A)
376
+ })
377
+ })
378
+
379
+ describe('env var prefix compatibility', () => {
380
+ it('prefers E2E_CHANNELTALKBOT_* over E2E_CHANNELBOT_*', async () => {
381
+ process.env.E2E_CHANNELBOT_ACCESS_KEY = 'old-key'
382
+ process.env.E2E_CHANNELBOT_ACCESS_SECRET = 'old-secret'
383
+ process.env.E2E_CHANNELTALKBOT_ACCESS_KEY = 'new-key'
384
+ process.env.E2E_CHANNELTALKBOT_ACCESS_SECRET = 'new-secret'
385
+
386
+ const creds = await manager.getCredentials()
387
+
388
+ expect(creds?.access_key).toBe('new-key')
389
+ expect(creds?.access_secret).toBe('new-secret')
390
+ })
391
+
392
+ it('falls back to E2E_CHANNELBOT_* when E2E_CHANNELTALKBOT_* is unset', async () => {
393
+ process.env.E2E_CHANNELBOT_ACCESS_KEY = 'legacy-key'
394
+ process.env.E2E_CHANNELBOT_ACCESS_SECRET = 'legacy-secret'
395
+
396
+ const creds = await manager.getCredentials()
397
+
398
+ expect(creds?.access_key).toBe('legacy-key')
399
+ expect(creds?.access_secret).toBe('legacy-secret')
400
+ })
401
+ })
308
402
  })
@@ -1,21 +1,30 @@
1
1
  import { existsSync } from 'node:fs'
2
- import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
2
+ import { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises'
3
3
  import { homedir } from 'node:os'
4
4
  import { join } from 'node:path'
5
5
 
6
6
  import type { ChannelBotConfig, ChannelBotCredentials, ChannelBotWorkspaceEntry } from './types'
7
7
  import { ChannelBotConfigSchema } from './types'
8
8
 
9
+ const LEGACY_FILENAME = 'channelbot-credentials.json'
10
+ const CREDENTIALS_FILENAME = 'channeltalkbot-credentials.json'
11
+
9
12
  export class ChannelBotCredentialManager {
10
13
  private configDir: string
11
14
  private credentialsPath: string
15
+ private legacyPath: string
16
+ private migratedLegacyFile = false
17
+ protected renameFile: typeof rename = rename
12
18
 
13
19
  constructor(configDir?: string) {
14
20
  this.configDir = configDir ?? join(homedir(), '.config', 'agent-messenger')
15
- this.credentialsPath = join(this.configDir, 'channelbot-credentials.json')
21
+ this.credentialsPath = join(this.configDir, CREDENTIALS_FILENAME)
22
+ this.legacyPath = join(this.configDir, LEGACY_FILENAME)
16
23
  }
17
24
 
18
25
  async load(): Promise<ChannelBotConfig> {
26
+ await this.migrateLegacyFileIfNeeded()
27
+
19
28
  if (!existsSync(this.credentialsPath)) {
20
29
  return { current: null, workspaces: {}, default_bot: null }
21
30
  }
@@ -34,6 +43,30 @@ export class ChannelBotCredentialManager {
34
43
  return parsed.data
35
44
  }
36
45
 
46
+ private async migrateLegacyFileIfNeeded(): Promise<void> {
47
+ if (this.migratedLegacyFile) return
48
+ if (existsSync(this.credentialsPath)) {
49
+ this.migratedLegacyFile = true
50
+ return
51
+ }
52
+ if (!existsSync(this.legacyPath)) {
53
+ this.migratedLegacyFile = true
54
+ return
55
+ }
56
+ try {
57
+ await this.renameFile(this.legacyPath, this.credentialsPath)
58
+ process.stderr.write(
59
+ `[agent-channeltalkbot] Migrated credentials: ${LEGACY_FILENAME} -> ${CREDENTIALS_FILENAME}\n`,
60
+ )
61
+ } catch {
62
+ // Rename failed. If a concurrent process succeeded, the new file now exists — use it.
63
+ // Otherwise (real failure: permissions, etc.) keep the new path; load() will return
64
+ // empty config and the user can re-run `auth set`. Never fall back to writing the
65
+ // legacy path, which would resurrect the split-brain we are migrating away from.
66
+ }
67
+ this.migratedLegacyFile = true
68
+ }
69
+
37
70
  async save(config: ChannelBotConfig): Promise<void> {
38
71
  await mkdir(this.configDir, { recursive: true })
39
72
  await writeFile(this.credentialsPath, JSON.stringify(config, null, 2), { mode: 0o600 })
@@ -41,8 +74,8 @@ export class ChannelBotCredentialManager {
41
74
  }
42
75
 
43
76
  async getCredentials(workspaceId?: string): Promise<ChannelBotCredentials | null> {
44
- const envAccessKey = process.env.E2E_CHANNELBOT_ACCESS_KEY
45
- const envAccessSecret = process.env.E2E_CHANNELBOT_ACCESS_SECRET
77
+ const envAccessKey = process.env.E2E_CHANNELTALKBOT_ACCESS_KEY ?? process.env.E2E_CHANNELBOT_ACCESS_KEY
78
+ const envAccessSecret = process.env.E2E_CHANNELTALKBOT_ACCESS_SECRET ?? process.env.E2E_CHANNELBOT_ACCESS_SECRET
46
79
 
47
80
  if (envAccessKey && envAccessSecret && !workspaceId) {
48
81
  return {
@@ -1,4 +1,4 @@
1
- import { expect, test } from 'bun:test'
1
+ import { expect, it } from 'bun:test'
2
2
 
3
3
  import {
4
4
  ChannelBotBotSchema,
@@ -17,58 +17,58 @@ import {
17
17
  MessageBlockSchema,
18
18
  } from '@/platforms/channeltalkbot/index'
19
19
 
20
- test('ChannelBotClient is exported from barrel', () => {
20
+ it('ChannelBotClient is exported from barrel', () => {
21
21
  expect(typeof ChannelBotClient).toBe('function')
22
22
  })
23
23
 
24
- test('ChannelBotError is exported from barrel', () => {
24
+ it('ChannelBotError is exported from barrel', () => {
25
25
  expect(typeof ChannelBotError).toBe('function')
26
26
  })
27
27
 
28
- test('ChannelBotCredentialManager is exported from barrel', () => {
28
+ it('ChannelBotCredentialManager is exported from barrel', () => {
29
29
  expect(typeof ChannelBotCredentialManager).toBe('function')
30
30
  })
31
31
 
32
- test('ChannelBotBotSchema is exported from barrel', () => {
32
+ it('ChannelBotBotSchema is exported from barrel', () => {
33
33
  expect(typeof ChannelBotBotSchema.parse).toBe('function')
34
34
  })
35
35
 
36
- test('ChannelBotChannelSchema is exported from barrel', () => {
36
+ it('ChannelBotChannelSchema is exported from barrel', () => {
37
37
  expect(typeof ChannelBotChannelSchema.parse).toBe('function')
38
38
  })
39
39
 
40
- test('ChannelBotConfigSchema is exported from barrel', () => {
40
+ it('ChannelBotConfigSchema is exported from barrel', () => {
41
41
  expect(typeof ChannelBotConfigSchema.parse).toBe('function')
42
42
  })
43
43
 
44
- test('ChannelBotCredentialsSchema is exported from barrel', () => {
44
+ it('ChannelBotCredentialsSchema is exported from barrel', () => {
45
45
  expect(typeof ChannelBotCredentialsSchema.parse).toBe('function')
46
46
  })
47
47
 
48
- test('ChannelBotGroupSchema is exported from barrel', () => {
48
+ it('ChannelBotGroupSchema is exported from barrel', () => {
49
49
  expect(typeof ChannelBotGroupSchema.parse).toBe('function')
50
50
  })
51
51
 
52
- test('ChannelBotManagerSchema is exported from barrel', () => {
52
+ it('ChannelBotManagerSchema is exported from barrel', () => {
53
53
  expect(typeof ChannelBotManagerSchema.parse).toBe('function')
54
54
  })
55
55
 
56
- test('ChannelBotMessageSchema is exported from barrel', () => {
56
+ it('ChannelBotMessageSchema is exported from barrel', () => {
57
57
  expect(typeof ChannelBotMessageSchema.parse).toBe('function')
58
58
  })
59
59
 
60
- test('ChannelBotUserChatSchema is exported from barrel', () => {
60
+ it('ChannelBotUserChatSchema is exported from barrel', () => {
61
61
  expect(typeof ChannelBotUserChatSchema.parse).toBe('function')
62
62
  })
63
63
 
64
- test('ChannelBotUserSchema is exported from barrel', () => {
64
+ it('ChannelBotUserSchema is exported from barrel', () => {
65
65
  expect(typeof ChannelBotUserSchema.parse).toBe('function')
66
66
  })
67
67
 
68
- test('ChannelBotWorkspaceEntrySchema is exported from barrel', () => {
68
+ it('ChannelBotWorkspaceEntrySchema is exported from barrel', () => {
69
69
  expect(typeof ChannelBotWorkspaceEntrySchema.parse).toBe('function')
70
70
  })
71
71
 
72
- test('MessageBlockSchema is exported from barrel', () => {
72
+ it('MessageBlockSchema is exported from barrel', () => {
73
73
  expect(typeof MessageBlockSchema.parse).toBe('function')
74
74
  })