agent-messenger 2.3.0 → 2.5.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 (438) hide show
  1. package/.claude-plugin/README.md +16 -16
  2. package/.claude-plugin/marketplace.json +29 -29
  3. package/.claude-plugin/plugin.json +5 -5
  4. package/.github/workflows/release.yml +0 -12
  5. package/CONTRIBUTING.md +1 -1
  6. package/README.md +11 -8
  7. package/bun.lock +70 -110
  8. package/bunfig.toml +3 -0
  9. package/dist/package.json +11 -3
  10. package/dist/src/platforms/channeltalk/cli.d.ts.map +1 -1
  11. package/dist/src/platforms/channeltalk/cli.js +2 -1
  12. package/dist/src/platforms/channeltalk/cli.js.map +1 -1
  13. package/dist/src/platforms/channeltalk/commands/index.d.ts +1 -0
  14. package/dist/src/platforms/channeltalk/commands/index.d.ts.map +1 -1
  15. package/dist/src/platforms/channeltalk/commands/index.js +1 -0
  16. package/dist/src/platforms/channeltalk/commands/index.js.map +1 -1
  17. package/dist/src/platforms/channeltalk/commands/whoami.d.ts +22 -0
  18. package/dist/src/platforms/channeltalk/commands/whoami.d.ts.map +1 -0
  19. package/dist/src/platforms/channeltalk/commands/whoami.js +40 -0
  20. package/dist/src/platforms/channeltalk/commands/whoami.js.map +1 -0
  21. package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
  22. package/dist/src/platforms/channeltalkbot/cli.js +2 -1
  23. package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
  24. package/dist/src/platforms/channeltalkbot/commands/index.d.ts +1 -0
  25. package/dist/src/platforms/channeltalkbot/commands/index.d.ts.map +1 -1
  26. package/dist/src/platforms/channeltalkbot/commands/index.js +1 -0
  27. package/dist/src/platforms/channeltalkbot/commands/index.js.map +1 -1
  28. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts +13 -0
  29. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -0
  30. package/dist/src/platforms/channeltalkbot/commands/whoami.js +31 -0
  31. package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -0
  32. package/dist/src/platforms/discord/cli.d.ts.map +1 -1
  33. package/dist/src/platforms/discord/cli.js +2 -1
  34. package/dist/src/platforms/discord/cli.js.map +1 -1
  35. package/dist/src/platforms/discord/commands/index.d.ts +1 -0
  36. package/dist/src/platforms/discord/commands/index.d.ts.map +1 -1
  37. package/dist/src/platforms/discord/commands/index.js +1 -0
  38. package/dist/src/platforms/discord/commands/index.js.map +1 -1
  39. package/dist/src/platforms/discord/commands/whoami.d.ts +6 -0
  40. package/dist/src/platforms/discord/commands/whoami.d.ts.map +1 -0
  41. package/dist/src/platforms/discord/commands/whoami.js +33 -0
  42. package/dist/src/platforms/discord/commands/whoami.js.map +1 -0
  43. package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
  44. package/dist/src/platforms/discordbot/cli.js +2 -1
  45. package/dist/src/platforms/discordbot/cli.js.map +1 -1
  46. package/dist/src/platforms/discordbot/client.js +2 -2
  47. package/dist/src/platforms/discordbot/client.js.map +1 -1
  48. package/dist/src/platforms/discordbot/commands/index.d.ts +1 -0
  49. package/dist/src/platforms/discordbot/commands/index.d.ts.map +1 -1
  50. package/dist/src/platforms/discordbot/commands/index.js +1 -0
  51. package/dist/src/platforms/discordbot/commands/index.js.map +1 -1
  52. package/dist/src/platforms/discordbot/commands/whoami.d.ts +14 -0
  53. package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -0
  54. package/dist/src/platforms/discordbot/commands/whoami.js +32 -0
  55. package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -0
  56. package/dist/src/platforms/instagram/cli.d.ts.map +1 -1
  57. package/dist/src/platforms/instagram/cli.js +2 -1
  58. package/dist/src/platforms/instagram/cli.js.map +1 -1
  59. package/dist/src/platforms/instagram/client.d.ts +6 -0
  60. package/dist/src/platforms/instagram/client.d.ts.map +1 -1
  61. package/dist/src/platforms/instagram/client.js +12 -0
  62. package/dist/src/platforms/instagram/client.js.map +1 -1
  63. package/dist/src/platforms/instagram/commands/index.d.ts +1 -0
  64. package/dist/src/platforms/instagram/commands/index.d.ts.map +1 -1
  65. package/dist/src/platforms/instagram/commands/index.js +1 -0
  66. package/dist/src/platforms/instagram/commands/index.js.map +1 -1
  67. package/dist/src/platforms/instagram/commands/whoami.d.ts +7 -0
  68. package/dist/src/platforms/instagram/commands/whoami.d.ts.map +1 -0
  69. package/dist/src/platforms/instagram/commands/whoami.js +19 -0
  70. package/dist/src/platforms/instagram/commands/whoami.js.map +1 -0
  71. package/dist/src/platforms/kakaotalk/cli.d.ts.map +1 -1
  72. package/dist/src/platforms/kakaotalk/cli.js +2 -1
  73. package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
  74. package/dist/src/platforms/kakaotalk/client.d.ts +2 -1
  75. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  76. package/dist/src/platforms/kakaotalk/client.js +225 -23
  77. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  78. package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -0
  79. package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
  80. package/dist/src/platforms/kakaotalk/commands/index.js +1 -0
  81. package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
  82. package/dist/src/platforms/kakaotalk/commands/whoami.d.ts +3 -0
  83. package/dist/src/platforms/kakaotalk/commands/whoami.d.ts.map +1 -0
  84. package/dist/src/platforms/kakaotalk/commands/whoami.js +19 -0
  85. package/dist/src/platforms/kakaotalk/commands/whoami.js.map +1 -0
  86. package/dist/src/platforms/kakaotalk/index.d.ts +2 -2
  87. package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
  88. package/dist/src/platforms/kakaotalk/index.js +1 -1
  89. package/dist/src/platforms/kakaotalk/index.js.map +1 -1
  90. package/dist/src/platforms/kakaotalk/protocol/session.d.ts +4 -2
  91. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  92. package/dist/src/platforms/kakaotalk/protocol/session.js +27 -7
  93. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  94. package/dist/src/platforms/kakaotalk/protocol/types.d.ts +17 -0
  95. package/dist/src/platforms/kakaotalk/protocol/types.d.ts.map +1 -1
  96. package/dist/src/platforms/kakaotalk/protocol/types.js.map +1 -1
  97. package/dist/src/platforms/kakaotalk/types.d.ts +28 -0
  98. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  99. package/dist/src/platforms/kakaotalk/types.js +14 -0
  100. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  101. package/dist/src/platforms/line/cli.js +2 -2
  102. package/dist/src/platforms/line/cli.js.map +1 -1
  103. package/dist/src/platforms/line/client.d.ts.map +1 -1
  104. package/dist/src/platforms/line/client.js +9 -36
  105. package/dist/src/platforms/line/client.js.map +1 -1
  106. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  107. package/dist/src/platforms/line/commands/auth.js +9 -47
  108. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  109. package/dist/src/platforms/line/commands/index.d.ts +1 -1
  110. package/dist/src/platforms/line/commands/index.d.ts.map +1 -1
  111. package/dist/src/platforms/line/commands/index.js +1 -1
  112. package/dist/src/platforms/line/commands/index.js.map +1 -1
  113. package/dist/src/platforms/line/commands/whoami.d.ts +3 -0
  114. package/dist/src/platforms/line/commands/whoami.d.ts.map +1 -0
  115. package/dist/src/platforms/line/commands/{profile.js → whoami.js} +5 -5
  116. package/dist/src/platforms/line/commands/whoami.js.map +1 -0
  117. package/dist/src/platforms/slack/cli.d.ts.map +1 -1
  118. package/dist/src/platforms/slack/cli.js +2 -1
  119. package/dist/src/platforms/slack/cli.js.map +1 -1
  120. package/dist/src/platforms/slack/commands/index.d.ts +1 -0
  121. package/dist/src/platforms/slack/commands/index.d.ts.map +1 -1
  122. package/dist/src/platforms/slack/commands/index.js +1 -0
  123. package/dist/src/platforms/slack/commands/index.js.map +1 -1
  124. package/dist/src/platforms/slack/commands/whoami.d.ts +6 -0
  125. package/dist/src/platforms/slack/commands/whoami.d.ts.map +1 -0
  126. package/dist/src/platforms/slack/commands/whoami.js +39 -0
  127. package/dist/src/platforms/slack/commands/whoami.js.map +1 -0
  128. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  129. package/dist/src/platforms/slackbot/cli.js +2 -1
  130. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  131. package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
  132. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
  133. package/dist/src/platforms/slackbot/commands/index.js +1 -0
  134. package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
  135. package/dist/src/platforms/slackbot/commands/whoami.d.ts +14 -0
  136. package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -0
  137. package/dist/src/platforms/slackbot/commands/whoami.js +32 -0
  138. package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -0
  139. package/dist/src/platforms/teams/cli.d.ts.map +1 -1
  140. package/dist/src/platforms/teams/cli.js +2 -1
  141. package/dist/src/platforms/teams/cli.js.map +1 -1
  142. package/dist/src/platforms/teams/commands/index.d.ts +1 -0
  143. package/dist/src/platforms/teams/commands/index.d.ts.map +1 -1
  144. package/dist/src/platforms/teams/commands/index.js +1 -0
  145. package/dist/src/platforms/teams/commands/index.js.map +1 -1
  146. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
  147. package/dist/src/platforms/teams/commands/reaction.js +2 -0
  148. package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
  149. package/dist/src/platforms/teams/commands/whoami.d.ts +6 -0
  150. package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -0
  151. package/dist/src/platforms/teams/commands/whoami.js +30 -0
  152. package/dist/src/platforms/teams/commands/whoami.js.map +1 -0
  153. package/dist/src/platforms/telegram/cli.d.ts.map +1 -1
  154. package/dist/src/platforms/telegram/cli.js +2 -1
  155. package/dist/src/platforms/telegram/cli.js.map +1 -1
  156. package/dist/src/platforms/telegram/commands/index.d.ts +1 -0
  157. package/dist/src/platforms/telegram/commands/index.d.ts.map +1 -1
  158. package/dist/src/platforms/telegram/commands/index.js +1 -0
  159. package/dist/src/platforms/telegram/commands/index.js.map +1 -1
  160. package/dist/src/platforms/telegram/commands/whoami.d.ts +7 -0
  161. package/dist/src/platforms/telegram/commands/whoami.d.ts.map +1 -0
  162. package/dist/src/platforms/telegram/commands/whoami.js +27 -0
  163. package/dist/src/platforms/telegram/commands/whoami.js.map +1 -0
  164. package/dist/src/platforms/webex/cli.d.ts.map +1 -1
  165. package/dist/src/platforms/webex/cli.js +2 -1
  166. package/dist/src/platforms/webex/cli.js.map +1 -1
  167. package/dist/src/platforms/webex/commands/index.d.ts +1 -0
  168. package/dist/src/platforms/webex/commands/index.d.ts.map +1 -1
  169. package/dist/src/platforms/webex/commands/index.js +1 -0
  170. package/dist/src/platforms/webex/commands/index.js.map +1 -1
  171. package/dist/src/platforms/webex/commands/message.js +1 -1
  172. package/dist/src/platforms/webex/commands/message.js.map +1 -1
  173. package/dist/src/platforms/webex/commands/whoami.d.ts +6 -0
  174. package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -0
  175. package/dist/src/platforms/webex/commands/whoami.js +30 -0
  176. package/dist/src/platforms/webex/commands/whoami.js.map +1 -0
  177. package/dist/src/platforms/wechatbot/cli.d.ts +5 -0
  178. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -0
  179. package/dist/src/platforms/wechatbot/cli.js +19 -0
  180. package/dist/src/platforms/wechatbot/cli.js.map +1 -0
  181. package/dist/src/platforms/wechatbot/client.d.ts +36 -0
  182. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -0
  183. package/dist/src/platforms/wechatbot/client.js +208 -0
  184. package/dist/src/platforms/wechatbot/client.js.map +1 -0
  185. package/dist/src/platforms/wechatbot/commands/auth.d.ts +28 -0
  186. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -0
  187. package/dist/src/platforms/wechatbot/commands/auth.js +164 -0
  188. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -0
  189. package/dist/src/platforms/wechatbot/commands/index.d.ts +6 -0
  190. package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -0
  191. package/dist/src/platforms/wechatbot/commands/index.js +6 -0
  192. package/dist/src/platforms/wechatbot/commands/index.js.map +1 -0
  193. package/dist/src/platforms/wechatbot/commands/message.d.ts +18 -0
  194. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -0
  195. package/dist/src/platforms/wechatbot/commands/message.js +80 -0
  196. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -0
  197. package/dist/src/platforms/wechatbot/commands/shared.d.ts +9 -0
  198. package/dist/src/platforms/wechatbot/commands/shared.d.ts.map +1 -0
  199. package/dist/src/platforms/wechatbot/commands/shared.js +13 -0
  200. package/dist/src/platforms/wechatbot/commands/shared.js.map +1 -0
  201. package/dist/src/platforms/wechatbot/commands/template.d.ts +19 -0
  202. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -0
  203. package/dist/src/platforms/wechatbot/commands/template.js +76 -0
  204. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -0
  205. package/dist/src/platforms/wechatbot/commands/user.d.ts +20 -0
  206. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -0
  207. package/dist/src/platforms/wechatbot/commands/user.js +53 -0
  208. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -0
  209. package/dist/src/platforms/wechatbot/commands/whoami.d.ts +12 -0
  210. package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -0
  211. package/dist/src/platforms/wechatbot/commands/whoami.js +33 -0
  212. package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -0
  213. package/dist/src/platforms/wechatbot/credential-manager.d.ts +17 -0
  214. package/dist/src/platforms/wechatbot/credential-manager.d.ts.map +1 -0
  215. package/dist/src/platforms/wechatbot/credential-manager.js +121 -0
  216. package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -0
  217. package/dist/src/platforms/wechatbot/index.d.ts +5 -0
  218. package/dist/src/platforms/wechatbot/index.d.ts.map +1 -0
  219. package/dist/src/platforms/wechatbot/index.js +4 -0
  220. package/dist/src/platforms/wechatbot/index.js.map +1 -0
  221. package/dist/src/platforms/wechatbot/types.d.ts +94 -0
  222. package/dist/src/platforms/wechatbot/types.d.ts.map +1 -0
  223. package/dist/src/platforms/wechatbot/types.js +54 -0
  224. package/dist/src/platforms/wechatbot/types.js.map +1 -0
  225. package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
  226. package/dist/src/platforms/whatsapp/cli.js +2 -1
  227. package/dist/src/platforms/whatsapp/cli.js.map +1 -1
  228. package/dist/src/platforms/whatsapp/client.d.ts +9 -0
  229. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  230. package/dist/src/platforms/whatsapp/client.js +143 -21
  231. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  232. package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
  233. package/dist/src/platforms/whatsapp/commands/auth.js +133 -60
  234. package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
  235. package/dist/src/platforms/whatsapp/commands/index.d.ts +1 -0
  236. package/dist/src/platforms/whatsapp/commands/index.d.ts.map +1 -1
  237. package/dist/src/platforms/whatsapp/commands/index.js +1 -0
  238. package/dist/src/platforms/whatsapp/commands/index.js.map +1 -1
  239. package/dist/src/platforms/whatsapp/commands/shared.js +2 -2
  240. package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
  241. package/dist/src/platforms/whatsapp/commands/whoami.d.ts +7 -0
  242. package/dist/src/platforms/whatsapp/commands/whoami.d.ts.map +1 -0
  243. package/dist/src/platforms/whatsapp/commands/whoami.js +19 -0
  244. package/dist/src/platforms/whatsapp/commands/whoami.js.map +1 -0
  245. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  246. package/dist/src/platforms/whatsapp/credential-manager.js +14 -8
  247. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  248. package/dist/src/platforms/whatsapp/ensure-auth.js +2 -2
  249. package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
  250. package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
  251. package/dist/src/platforms/whatsappbot/cli.js +2 -1
  252. package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
  253. package/dist/src/platforms/whatsappbot/commands/index.d.ts +1 -0
  254. package/dist/src/platforms/whatsappbot/commands/index.d.ts.map +1 -1
  255. package/dist/src/platforms/whatsappbot/commands/index.js +1 -0
  256. package/dist/src/platforms/whatsappbot/commands/index.js.map +1 -1
  257. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts +17 -0
  258. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -0
  259. package/dist/src/platforms/whatsappbot/commands/whoami.js +39 -0
  260. package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -0
  261. package/dist/src/shared/utils/qr.d.ts +15 -0
  262. package/dist/src/shared/utils/qr.d.ts.map +1 -0
  263. package/dist/src/shared/utils/qr.js +74 -0
  264. package/dist/src/shared/utils/qr.js.map +1 -0
  265. package/dist/src/tui/adapters/whatsapp-adapter.d.ts.map +1 -1
  266. package/dist/src/tui/adapters/whatsapp-adapter.js +20 -15
  267. package/dist/src/tui/adapters/whatsapp-adapter.js.map +1 -1
  268. package/docs/content/docs/agent-skills.mdx +4 -4
  269. package/docs/content/docs/cli/channeltalk.mdx +12 -1
  270. package/docs/content/docs/cli/channeltalkbot.mdx +10 -1
  271. package/docs/content/docs/cli/discord.mdx +11 -1
  272. package/docs/content/docs/cli/discordbot.mdx +10 -1
  273. package/docs/content/docs/cli/instagram.mdx +12 -1
  274. package/docs/content/docs/cli/kakaotalk.mdx +25 -1
  275. package/docs/content/docs/cli/line.mdx +5 -5
  276. package/docs/content/docs/cli/meta.json +1 -0
  277. package/docs/content/docs/cli/slack.mdx +11 -1
  278. package/docs/content/docs/cli/slackbot.mdx +10 -1
  279. package/docs/content/docs/cli/teams.mdx +11 -1
  280. package/docs/content/docs/cli/telegram.mdx +11 -0
  281. package/docs/content/docs/cli/webex.mdx +11 -1
  282. package/docs/content/docs/cli/wechatbot.mdx +188 -0
  283. package/docs/content/docs/cli/whatsapp.mdx +37 -8
  284. package/docs/content/docs/cli/whatsappbot.mdx +10 -1
  285. package/docs/content/docs/sdk/meta.json +1 -1
  286. package/docs/content/docs/sdk/wechatbot.mdx +282 -0
  287. package/docs/content/docs/tui.mdx +1 -1
  288. package/docs/src/app/page.tsx +5 -5
  289. package/package.json +11 -3
  290. package/skills/agent-channeltalk/SKILL.md +12 -1
  291. package/skills/agent-channeltalkbot/SKILL.md +10 -1
  292. package/skills/agent-discord/SKILL.md +11 -1
  293. package/skills/agent-discordbot/SKILL.md +10 -1
  294. package/skills/agent-instagram/SKILL.md +12 -1
  295. package/skills/agent-kakaotalk/SKILL.md +30 -1
  296. package/skills/agent-kakaotalk/references/common-patterns.md +1 -1
  297. package/skills/agent-line/SKILL.md +11 -15
  298. package/skills/agent-line/references/authentication.md +13 -4
  299. package/skills/agent-slack/SKILL.md +11 -1
  300. package/skills/agent-slackbot/SKILL.md +10 -1
  301. package/skills/agent-teams/SKILL.md +11 -1
  302. package/skills/agent-telegram/SKILL.md +6 -1
  303. package/skills/agent-webex/SKILL.md +11 -1
  304. package/skills/agent-wechatbot/SKILL.md +394 -0
  305. package/skills/agent-whatsapp/SKILL.md +63 -15
  306. package/skills/agent-whatsapp/references/authentication.md +36 -6
  307. package/skills/agent-whatsappbot/SKILL.md +10 -1
  308. package/src/platforms/channeltalk/cli.ts +2 -0
  309. package/src/platforms/channeltalk/commands/index.ts +1 -0
  310. package/src/platforms/channeltalk/commands/whoami.test.ts +64 -0
  311. package/src/platforms/channeltalk/commands/whoami.ts +62 -0
  312. package/src/platforms/channeltalkbot/cli.ts +2 -0
  313. package/src/platforms/channeltalkbot/commands/index.ts +1 -0
  314. package/src/platforms/channeltalkbot/commands/whoami.test.ts +104 -0
  315. package/src/platforms/channeltalkbot/commands/whoami.ts +42 -0
  316. package/src/platforms/discord/cli.ts +2 -0
  317. package/src/platforms/discord/commands/index.ts +1 -0
  318. package/src/platforms/discord/commands/whoami.test.ts +91 -0
  319. package/src/platforms/discord/commands/whoami.ts +36 -0
  320. package/src/platforms/discord/credential-manager.test.ts +18 -1
  321. package/src/platforms/discordbot/cli.ts +2 -0
  322. package/src/platforms/discordbot/client.ts +2 -2
  323. package/src/platforms/discordbot/commands/index.ts +1 -0
  324. package/src/platforms/discordbot/commands/whoami.test.ts +96 -0
  325. package/src/platforms/discordbot/commands/whoami.ts +44 -0
  326. package/src/platforms/instagram/cli.ts +2 -1
  327. package/src/platforms/instagram/client.ts +13 -0
  328. package/src/platforms/instagram/commands/auth.test.ts +216 -0
  329. package/src/platforms/instagram/commands/chat.test.ts +123 -0
  330. package/src/platforms/instagram/commands/index.ts +1 -0
  331. package/src/platforms/instagram/commands/message.test.ts +174 -0
  332. package/src/platforms/instagram/commands/whoami.test.ts +60 -0
  333. package/src/platforms/instagram/commands/whoami.ts +21 -0
  334. package/src/platforms/kakaotalk/cli.ts +2 -1
  335. package/src/platforms/kakaotalk/client.test.ts +182 -14
  336. package/src/platforms/kakaotalk/client.ts +261 -27
  337. package/src/platforms/kakaotalk/commands/auth.test.ts +299 -0
  338. package/src/platforms/kakaotalk/commands/chat.test.ts +97 -0
  339. package/src/platforms/kakaotalk/commands/index.ts +1 -0
  340. package/src/platforms/kakaotalk/commands/message.test.ts +113 -0
  341. package/src/platforms/kakaotalk/commands/whoami.test.ts +116 -0
  342. package/src/platforms/kakaotalk/commands/whoami.ts +21 -0
  343. package/src/platforms/kakaotalk/index.test.ts +5 -0
  344. package/src/platforms/kakaotalk/index.ts +2 -0
  345. package/src/platforms/kakaotalk/protocol/session.ts +29 -7
  346. package/src/platforms/kakaotalk/protocol/types.ts +9 -0
  347. package/src/platforms/kakaotalk/types.ts +30 -0
  348. package/src/platforms/line/cli.ts +2 -2
  349. package/src/platforms/line/client.ts +14 -39
  350. package/src/platforms/line/commands/auth.test.ts +141 -0
  351. package/src/platforms/line/commands/auth.ts +37 -61
  352. package/src/platforms/line/commands/chat.test.ts +110 -0
  353. package/src/platforms/line/commands/friend.test.ts +98 -0
  354. package/src/platforms/line/commands/index.ts +1 -1
  355. package/src/platforms/line/commands/message.test.ts +119 -0
  356. package/src/platforms/line/commands/whoami.test.ts +85 -0
  357. package/src/platforms/line/commands/{profile.ts → whoami.ts} +4 -4
  358. package/src/platforms/slack/cli.ts +2 -0
  359. package/src/platforms/slack/commands/index.ts +1 -0
  360. package/src/platforms/slack/commands/whoami.test.ts +126 -0
  361. package/src/platforms/slack/commands/whoami.ts +40 -0
  362. package/src/platforms/slackbot/cli.ts +2 -1
  363. package/src/platforms/slackbot/commands/channel.test.ts +139 -0
  364. package/src/platforms/slackbot/commands/index.ts +1 -0
  365. package/src/platforms/slackbot/commands/message.test.ts +226 -0
  366. package/src/platforms/slackbot/commands/reaction.test.ts +90 -0
  367. package/src/platforms/slackbot/commands/user.test.ts +143 -0
  368. package/src/platforms/slackbot/commands/whoami.test.ts +102 -0
  369. package/src/platforms/slackbot/commands/whoami.ts +44 -0
  370. package/src/platforms/teams/cli.ts +2 -0
  371. package/src/platforms/teams/commands/index.ts +1 -0
  372. package/src/platforms/teams/commands/reaction.test.ts +45 -61
  373. package/src/platforms/teams/commands/reaction.ts +2 -0
  374. package/src/platforms/teams/commands/whoami.test.ts +83 -0
  375. package/src/platforms/teams/commands/whoami.ts +33 -0
  376. package/src/platforms/telegram/cli.ts +2 -1
  377. package/src/platforms/telegram/commands/chat.test.ts +125 -0
  378. package/src/platforms/telegram/commands/index.ts +1 -0
  379. package/src/platforms/telegram/commands/message.test.ts +92 -0
  380. package/src/platforms/telegram/commands/whoami.test.ts +75 -0
  381. package/src/platforms/telegram/commands/whoami.ts +29 -0
  382. package/src/platforms/webex/cli.ts +2 -1
  383. package/src/platforms/webex/commands/auth.test.ts +58 -46
  384. package/src/platforms/webex/commands/index.ts +1 -0
  385. package/src/platforms/webex/commands/member.test.ts +60 -57
  386. package/src/platforms/webex/commands/message.test.ts +74 -121
  387. package/src/platforms/webex/commands/message.ts +1 -1
  388. package/src/platforms/webex/commands/snapshot.test.ts +54 -45
  389. package/src/platforms/webex/commands/space.test.ts +46 -49
  390. package/src/platforms/webex/commands/whoami.test.ts +113 -0
  391. package/src/platforms/webex/commands/whoami.ts +31 -0
  392. package/src/platforms/webex/credential-manager.test.ts +0 -1
  393. package/src/platforms/wechatbot/cli.ts +25 -0
  394. package/src/platforms/wechatbot/client.test.ts +497 -0
  395. package/src/platforms/wechatbot/client.ts +268 -0
  396. package/src/platforms/wechatbot/commands/auth.test.ts +211 -0
  397. package/src/platforms/wechatbot/commands/auth.ts +203 -0
  398. package/src/platforms/wechatbot/commands/index.ts +5 -0
  399. package/src/platforms/wechatbot/commands/message.test.ts +155 -0
  400. package/src/platforms/wechatbot/commands/message.ts +104 -0
  401. package/src/platforms/wechatbot/commands/shared.ts +22 -0
  402. package/src/platforms/wechatbot/commands/template.test.ts +199 -0
  403. package/src/platforms/wechatbot/commands/template.ts +102 -0
  404. package/src/platforms/wechatbot/commands/user.test.ts +165 -0
  405. package/src/platforms/wechatbot/commands/user.ts +75 -0
  406. package/src/platforms/wechatbot/commands/whoami.test.ts +109 -0
  407. package/src/platforms/wechatbot/commands/whoami.ts +43 -0
  408. package/src/platforms/wechatbot/credential-manager.test.ts +255 -0
  409. package/src/platforms/wechatbot/credential-manager.ts +148 -0
  410. package/src/platforms/wechatbot/index.test.ts +49 -0
  411. package/src/platforms/wechatbot/index.ts +19 -0
  412. package/src/platforms/wechatbot/types.test.ts +223 -0
  413. package/src/platforms/wechatbot/types.ts +107 -0
  414. package/src/platforms/whatsapp/cli.ts +2 -1
  415. package/src/platforms/whatsapp/client.ts +180 -37
  416. package/src/platforms/whatsapp/commands/auth.test.ts +311 -0
  417. package/src/platforms/whatsapp/commands/auth.ts +194 -84
  418. package/src/platforms/whatsapp/commands/chat.test.ts +198 -0
  419. package/src/platforms/whatsapp/commands/index.ts +1 -0
  420. package/src/platforms/whatsapp/commands/message.test.ts +231 -0
  421. package/src/platforms/whatsapp/commands/shared.ts +2 -2
  422. package/src/platforms/whatsapp/commands/whoami.test.ts +59 -0
  423. package/src/platforms/whatsapp/commands/whoami.ts +21 -0
  424. package/src/platforms/whatsapp/credential-manager.test.ts +20 -0
  425. package/src/platforms/whatsapp/credential-manager.ts +17 -8
  426. package/src/platforms/whatsapp/ensure-auth.ts +2 -2
  427. package/src/platforms/whatsappbot/cli.ts +2 -1
  428. package/src/platforms/whatsappbot/commands/auth.test.ts +217 -0
  429. package/src/platforms/whatsappbot/commands/index.ts +1 -0
  430. package/src/platforms/whatsappbot/commands/message.test.ts +198 -0
  431. package/src/platforms/whatsappbot/commands/template.test.ts +112 -0
  432. package/src/platforms/whatsappbot/commands/whoami.test.ts +100 -0
  433. package/src/platforms/whatsappbot/commands/whoami.ts +57 -0
  434. package/src/shared/utils/qr.ts +92 -0
  435. package/src/tui/adapters/whatsapp-adapter.ts +19 -16
  436. package/dist/src/platforms/line/commands/profile.d.ts +0 -3
  437. package/dist/src/platforms/line/commands/profile.d.ts.map +0 -1
  438. package/dist/src/platforms/line/commands/profile.js.map +0 -1
@@ -0,0 +1,165 @@
1
+ import { afterAll, describe, expect, mock, test } from 'bun:test'
2
+ import { rmSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+
5
+ import { WeChatBotCredentialManager } from '@/platforms/wechatbot/credential-manager'
6
+
7
+ const mockFollowersResult = {
8
+ total: 2,
9
+ count: 2,
10
+ openids: ['openid-1', 'openid-2'],
11
+ next_openid: '',
12
+ }
13
+
14
+ const mockUserInfo = {
15
+ subscribe: 1,
16
+ openid: 'openid-123',
17
+ language: 'zh_CN',
18
+ subscribe_time: 1609459200,
19
+ remark: '',
20
+ tagid_list: [],
21
+ subscribe_scene: 'ADD_SCENE_QR_CODE',
22
+ qr_scene: 0,
23
+ qr_scene_str: '',
24
+ }
25
+
26
+ mock.module('../client', () => ({
27
+ WeChatBotClient: class MockWeChatBotClient {
28
+ async login() {
29
+ return this
30
+ }
31
+ getFollowers = mock(() => Promise.resolve(mockFollowersResult))
32
+ getUserInfo = mock(() => Promise.resolve(mockUserInfo))
33
+ },
34
+ }))
35
+
36
+ const { listAction } = await import('@/platforms/wechatbot/commands/user')
37
+
38
+ const testDirs: string[] = []
39
+
40
+ function makeCredManager(): WeChatBotCredentialManager {
41
+ const dir = join(
42
+ import.meta.dir,
43
+ `.test-user-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
44
+ )
45
+ testDirs.push(dir)
46
+ return new WeChatBotCredentialManager(dir)
47
+ }
48
+
49
+ async function makeCredManagerWithCreds(): Promise<WeChatBotCredentialManager> {
50
+ const manager = makeCredManager()
51
+ await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
52
+ return manager
53
+ }
54
+
55
+ afterAll(() => {
56
+ for (const dir of testDirs) {
57
+ rmSync(dir, { recursive: true, force: true })
58
+ }
59
+ })
60
+
61
+ describe('listAction (user)', () => {
62
+ test('returns followers list with total, count, openids, next_openid', async () => {
63
+ const credManager = await makeCredManagerWithCreds()
64
+ const result = await listAction({ _credManager: credManager })
65
+
66
+ expect(result.total).toBe(2)
67
+ expect(result.count).toBe(2)
68
+ expect(result.openids).toEqual(['openid-1', 'openid-2'])
69
+ expect(result.next_openid).toBe('')
70
+ })
71
+
72
+ test('returns error when client throws', async () => {
73
+ mock.module('../client', () => ({
74
+ WeChatBotClient: class MockWeChatBotClient {
75
+ async login() {
76
+ return this
77
+ }
78
+ getFollowers = mock(() => Promise.reject(new Error('API error')))
79
+ },
80
+ }))
81
+
82
+ const { listAction: listActionFresh } = await import('@/platforms/wechatbot/commands/user')
83
+ const credManager = await makeCredManagerWithCreds()
84
+ const result = await listActionFresh({ _credManager: credManager })
85
+
86
+ expect(result.error).toBe('API error')
87
+ expect(result.openids).toBeUndefined()
88
+ })
89
+
90
+ test('passes nextOpenid option to client', async () => {
91
+ const getFollowersMock = mock(() =>
92
+ Promise.resolve({ total: 1, count: 1, openids: ['openid-3'], next_openid: '' }),
93
+ )
94
+ mock.module('../client', () => ({
95
+ WeChatBotClient: class MockWeChatBotClient {
96
+ async login() {
97
+ return this
98
+ }
99
+ getFollowers = getFollowersMock
100
+ },
101
+ }))
102
+
103
+ const { listAction: listActionFresh } = await import('@/platforms/wechatbot/commands/user')
104
+ const credManager = await makeCredManagerWithCreds()
105
+ await listActionFresh({ nextOpenid: 'openid-2', _credManager: credManager })
106
+
107
+ expect(getFollowersMock).toHaveBeenCalledWith('openid-2')
108
+ })
109
+ })
110
+
111
+ describe('getAction', () => {
112
+ test('returns user info for given openId', async () => {
113
+ mock.module('../client', () => ({
114
+ WeChatBotClient: class MockWeChatBotClient {
115
+ async login() {
116
+ return this
117
+ }
118
+ getUserInfo = mock(() => Promise.resolve(mockUserInfo))
119
+ },
120
+ }))
121
+
122
+ const { getAction: getActionFresh } = await import('@/platforms/wechatbot/commands/user')
123
+ const credManager = await makeCredManagerWithCreds()
124
+ const result = await getActionFresh('openid-123', { _credManager: credManager })
125
+
126
+ expect(result.user).toEqual(mockUserInfo)
127
+ expect(result.user?.openid).toBe('openid-123')
128
+ })
129
+
130
+ test('returns error when client throws', async () => {
131
+ mock.module('../client', () => ({
132
+ WeChatBotClient: class MockWeChatBotClient {
133
+ async login() {
134
+ return this
135
+ }
136
+ getUserInfo = mock(() => Promise.reject(new Error('user not found')))
137
+ },
138
+ }))
139
+
140
+ const { getAction: getActionFresh } = await import('@/platforms/wechatbot/commands/user')
141
+ const credManager = await makeCredManagerWithCreds()
142
+ const result = await getActionFresh('nonexistent-openid', { _credManager: credManager })
143
+
144
+ expect(result.error).toBe('user not found')
145
+ expect(result.user).toBeUndefined()
146
+ })
147
+
148
+ test('passes lang option to client', async () => {
149
+ const getUserInfoMock = mock(() => Promise.resolve({ ...mockUserInfo, language: 'en' }))
150
+ mock.module('../client', () => ({
151
+ WeChatBotClient: class MockWeChatBotClient {
152
+ async login() {
153
+ return this
154
+ }
155
+ getUserInfo = getUserInfoMock
156
+ },
157
+ }))
158
+
159
+ const { getAction: getActionFresh } = await import('@/platforms/wechatbot/commands/user')
160
+ const credManager = await makeCredManagerWithCreds()
161
+ await getActionFresh('openid-123', { lang: 'en', _credManager: credManager })
162
+
163
+ expect(getUserInfoMock).toHaveBeenCalledWith('openid-123', 'en')
164
+ })
165
+ })
@@ -0,0 +1,75 @@
1
+ import { Command } from 'commander'
2
+
3
+ import { formatOutput } from '@/shared/utils/output'
4
+
5
+ import type { WeChatBotUserInfo } from '../types'
6
+ import type { AccountOption } from './shared'
7
+ import { getClient } from './shared'
8
+
9
+ interface UserResult {
10
+ total?: number
11
+ count?: number
12
+ openids?: string[]
13
+ next_openid?: string
14
+ user?: WeChatBotUserInfo
15
+ error?: string
16
+ }
17
+
18
+ type UserOptions = AccountOption & {
19
+ nextOpenid?: string
20
+ lang?: string
21
+ }
22
+
23
+ export async function listAction(options: UserOptions): Promise<UserResult> {
24
+ try {
25
+ const client = await getClient(options)
26
+ const result = await client.getFollowers(options.nextOpenid)
27
+ return {
28
+ total: result.total,
29
+ count: result.count,
30
+ openids: result.openids,
31
+ next_openid: result.next_openid,
32
+ }
33
+ } catch (error) {
34
+ return { error: (error as Error).message }
35
+ }
36
+ }
37
+
38
+ export async function getAction(openId: string, options: UserOptions): Promise<UserResult> {
39
+ try {
40
+ const client = await getClient(options)
41
+ const user = await client.getUserInfo(openId, options.lang)
42
+ return { user }
43
+ } catch (error) {
44
+ return { error: (error as Error).message }
45
+ }
46
+ }
47
+
48
+ function cliOutput(result: UserResult, pretty?: boolean): void {
49
+ console.log(formatOutput(result, pretty))
50
+ if (result.error) process.exit(1)
51
+ }
52
+
53
+ export const userCommand = new Command('user')
54
+ .description('User management commands')
55
+ .addCommand(
56
+ new Command('list')
57
+ .description('List followers')
58
+ .option('--next-openid <cursor>', 'Cursor for pagination')
59
+ .option('--account <id>', 'Account ID')
60
+ .option('--pretty', 'Pretty print JSON output')
61
+ .action(async (opts: UserOptions) => {
62
+ cliOutput(await listAction(opts), opts.pretty)
63
+ }),
64
+ )
65
+ .addCommand(
66
+ new Command('get')
67
+ .description('Get user info by OpenID')
68
+ .argument('<open-id>', 'User OpenID')
69
+ .option('--lang <lang>', 'Language (zh_CN, zh_TW, en)', 'zh_CN')
70
+ .option('--account <id>', 'Account ID')
71
+ .option('--pretty', 'Pretty print JSON output')
72
+ .action(async (openId: string, opts: UserOptions) => {
73
+ cliOutput(await getAction(openId, opts), opts.pretty)
74
+ }),
75
+ )
@@ -0,0 +1,109 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
2
+ import { existsSync, rmSync } from 'node:fs'
3
+ import { mkdir } from 'node:fs/promises'
4
+ import { tmpdir } from 'node:os'
5
+ import { join } from 'node:path'
6
+
7
+ const mockVerifyCredentials = mock(() => Promise.resolve(true))
8
+
9
+ mock.module('../client', () => ({
10
+ WeChatBotClient: class MockWeChatBotClient {
11
+ async login(_credentials?: { appId: string; appSecret: string }) {
12
+ return this
13
+ }
14
+ verifyCredentials = mockVerifyCredentials
15
+ },
16
+ }))
17
+
18
+ import { WeChatBotCredentialManager } from '../credential-manager'
19
+ import { whoamiAction } from './whoami'
20
+
21
+ describe('whoami command', () => {
22
+ let tempDir: string
23
+ let originalEnv: NodeJS.ProcessEnv
24
+
25
+ beforeEach(async () => {
26
+ tempDir = join(tmpdir(), `wechatbot-whoami-test-${Date.now()}`)
27
+ await mkdir(tempDir, { recursive: true })
28
+ originalEnv = { ...process.env }
29
+ delete process.env.E2E_WECHATBOT_APP_ID
30
+ delete process.env.E2E_WECHATBOT_APP_SECRET
31
+ mockVerifyCredentials.mockClear()
32
+ })
33
+
34
+ afterEach(() => {
35
+ if (existsSync(tempDir)) {
36
+ rmSync(tempDir, { recursive: true })
37
+ }
38
+ process.env = originalEnv
39
+ })
40
+
41
+ test('returns app_id, account_name, and verified status', async () => {
42
+ const manager = new WeChatBotCredentialManager(tempDir)
43
+ await manager.setCredentials({
44
+ app_id: 'wx1234567890',
45
+ app_secret: 'secret123',
46
+ account_name: 'Test Official Account',
47
+ })
48
+
49
+ const result = await whoamiAction({ _credManager: manager })
50
+
51
+ expect(result.app_id).toBe('wx1234567890')
52
+ expect(result.account_name).toBe('Test Official Account')
53
+ expect(result.verified).toBe(true)
54
+ expect(result.error).toBeUndefined()
55
+ })
56
+
57
+ test('returns info for specific --account', async () => {
58
+ const manager = new WeChatBotCredentialManager(tempDir)
59
+ await manager.setCredentials({
60
+ app_id: 'wxAAA',
61
+ app_secret: 'secretA',
62
+ account_name: 'Account A',
63
+ })
64
+ await manager.setCredentials({
65
+ app_id: 'wxBBB',
66
+ app_secret: 'secretB',
67
+ account_name: 'Account B',
68
+ })
69
+
70
+ const result = await whoamiAction({ account: 'wxAAA', _credManager: manager })
71
+
72
+ expect(result.app_id).toBe('wxAAA')
73
+ expect(result.account_name).toBe('Account A')
74
+ expect(result.verified).toBe(true)
75
+ })
76
+
77
+ test('returns verified false when credentials are invalid', async () => {
78
+ mockVerifyCredentials.mockImplementationOnce(() => Promise.resolve(false))
79
+
80
+ const manager = new WeChatBotCredentialManager(tempDir)
81
+ await manager.setCredentials({
82
+ app_id: 'wx1234567890',
83
+ app_secret: 'bad-secret',
84
+ account_name: 'Test Account',
85
+ })
86
+
87
+ const result = await whoamiAction({ _credManager: manager })
88
+
89
+ expect(result.app_id).toBe('wx1234567890')
90
+ expect(result.verified).toBe(false)
91
+ expect(result.error).toBeUndefined()
92
+ })
93
+
94
+ test('returns error when client throws', async () => {
95
+ mockVerifyCredentials.mockImplementationOnce(() => Promise.reject(new Error('Network error')))
96
+
97
+ const manager = new WeChatBotCredentialManager(tempDir)
98
+ await manager.setCredentials({
99
+ app_id: 'wx1234567890',
100
+ app_secret: 'secret123',
101
+ account_name: 'Test Account',
102
+ })
103
+
104
+ const result = await whoamiAction({ _credManager: manager })
105
+
106
+ expect(result.error).toBeDefined()
107
+ expect(result.error).toContain('Network error')
108
+ })
109
+ })
@@ -0,0 +1,43 @@
1
+ import { Command } from 'commander'
2
+
3
+ import { formatOutput } from '@/shared/utils/output'
4
+
5
+ import { WeChatBotCredentialManager } from '../credential-manager'
6
+ import type { AccountOption } from './shared'
7
+ import { getClient } from './shared'
8
+
9
+ interface WhoamiResult {
10
+ app_id?: string | null
11
+ account_name?: string | null
12
+ verified?: boolean
13
+ error?: string
14
+ }
15
+
16
+ export async function whoamiAction(options: AccountOption): Promise<WhoamiResult> {
17
+ try {
18
+ const client = await getClient(options)
19
+ const verified = await client.verifyCredentials()
20
+ const credManager = options._credManager ?? new WeChatBotCredentialManager()
21
+ const creds = await credManager.getCredentials(options.account)
22
+ return {
23
+ app_id: creds?.app_id ?? null,
24
+ account_name: creds?.account_name ?? null,
25
+ verified,
26
+ }
27
+ } catch (error) {
28
+ return { error: (error as Error).message }
29
+ }
30
+ }
31
+
32
+ function cliOutput(result: WhoamiResult, pretty?: boolean): void {
33
+ console.log(formatOutput(result, pretty))
34
+ if (result.error) process.exit(1)
35
+ }
36
+
37
+ export const whoamiCommand = new Command('whoami')
38
+ .description('Show current authenticated bot')
39
+ .option('--account <id>', 'Account ID to use')
40
+ .option('--pretty', 'Pretty print JSON output')
41
+ .action(async (opts: AccountOption) => {
42
+ cliOutput(await whoamiAction(opts), opts.pretty)
43
+ })
@@ -0,0 +1,255 @@
1
+ import { afterAll, describe, expect, test } from 'bun:test'
2
+ import { existsSync, rmSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+
5
+ import { WeChatBotCredentialManager } from '@/platforms/wechatbot/credential-manager'
6
+
7
+ const testDirs: string[] = []
8
+
9
+ function setup(): WeChatBotCredentialManager {
10
+ const testConfigDir = join(
11
+ import.meta.dir,
12
+ `.test-wechatbot-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
13
+ )
14
+ testDirs.push(testConfigDir)
15
+ return new WeChatBotCredentialManager(testConfigDir)
16
+ }
17
+
18
+ afterAll(() => {
19
+ for (const dir of testDirs) {
20
+ rmSync(dir, { recursive: true, force: true })
21
+ }
22
+ })
23
+
24
+ describe('WeChatBotCredentialManager', () => {
25
+ test('load returns default config when file does not exist', async () => {
26
+ const manager = setup()
27
+ const config = await manager.load()
28
+
29
+ expect(config).toEqual({
30
+ current: null,
31
+ accounts: {},
32
+ })
33
+ })
34
+
35
+ test('save creates file with correct content', async () => {
36
+ const testConfigDir = join(
37
+ import.meta.dir,
38
+ `.test-wechatbot-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
39
+ )
40
+ testDirs.push(testConfigDir)
41
+ const manager = new WeChatBotCredentialManager(testConfigDir)
42
+ const config = {
43
+ current: { account_id: 'wx123' },
44
+ accounts: {
45
+ wx123: {
46
+ app_id: 'wx123',
47
+ app_secret: 'secret123',
48
+ account_name: 'Test Account',
49
+ },
50
+ },
51
+ }
52
+
53
+ await manager.save(config)
54
+
55
+ const credentialsPath = join(testConfigDir, 'wechatbot-credentials.json')
56
+ expect(existsSync(credentialsPath)).toBe(true)
57
+
58
+ const file = Bun.file(credentialsPath)
59
+ const content = await file.text()
60
+ const loaded = JSON.parse(content)
61
+ expect(loaded).toEqual(config)
62
+ })
63
+
64
+ test('getCredentials returns null when not configured', async () => {
65
+ const manager = setup()
66
+ const creds = await manager.getCredentials()
67
+ expect(creds).toBeNull()
68
+ })
69
+
70
+ test('getCredentials returns credentials from env vars when E2E env vars are set', async () => {
71
+ const originalAppId = process.env.E2E_WECHATBOT_APP_ID
72
+ const originalAppSecret = process.env.E2E_WECHATBOT_APP_SECRET
73
+
74
+ process.env.E2E_WECHATBOT_APP_ID = 'env-app-id'
75
+ process.env.E2E_WECHATBOT_APP_SECRET = 'env-app-secret'
76
+
77
+ try {
78
+ const manager = setup()
79
+ const creds = await manager.getCredentials()
80
+ expect(creds).toEqual({
81
+ app_id: 'env-app-id',
82
+ app_secret: 'env-app-secret',
83
+ account_name: 'env',
84
+ })
85
+ } finally {
86
+ if (originalAppId === undefined) {
87
+ delete process.env.E2E_WECHATBOT_APP_ID
88
+ } else {
89
+ process.env.E2E_WECHATBOT_APP_ID = originalAppId
90
+ }
91
+ if (originalAppSecret === undefined) {
92
+ delete process.env.E2E_WECHATBOT_APP_SECRET
93
+ } else {
94
+ process.env.E2E_WECHATBOT_APP_SECRET = originalAppSecret
95
+ }
96
+ }
97
+ })
98
+
99
+ test('getCredentials ignores env vars when accountId is provided', async () => {
100
+ const originalAppId = process.env.E2E_WECHATBOT_APP_ID
101
+ const originalAppSecret = process.env.E2E_WECHATBOT_APP_SECRET
102
+
103
+ process.env.E2E_WECHATBOT_APP_ID = 'env-app-id'
104
+ process.env.E2E_WECHATBOT_APP_SECRET = 'env-app-secret'
105
+
106
+ try {
107
+ const manager = setup()
108
+ const creds = await manager.getCredentials('nonexistent-id')
109
+ expect(creds).toBeNull()
110
+ } finally {
111
+ if (originalAppId === undefined) {
112
+ delete process.env.E2E_WECHATBOT_APP_ID
113
+ } else {
114
+ process.env.E2E_WECHATBOT_APP_ID = originalAppId
115
+ }
116
+ if (originalAppSecret === undefined) {
117
+ delete process.env.E2E_WECHATBOT_APP_SECRET
118
+ } else {
119
+ process.env.E2E_WECHATBOT_APP_SECRET = originalAppSecret
120
+ }
121
+ }
122
+ })
123
+
124
+ test('getCredentials returns specific account by accountId', async () => {
125
+ const manager = setup()
126
+ await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
127
+ await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
128
+
129
+ const creds = await manager.getCredentials('wx-a')
130
+ expect(creds).toEqual({
131
+ app_id: 'wx-a',
132
+ app_secret: 'secret-a',
133
+ account_name: 'Account A',
134
+ })
135
+ })
136
+
137
+ test('getCredentials returns null for nonexistent accountId', async () => {
138
+ const manager = setup()
139
+ const creds = await manager.getCredentials('nonexistent')
140
+ expect(creds).toBeNull()
141
+ })
142
+
143
+ test('setCredentials saves and sets as current', async () => {
144
+ const manager = setup()
145
+ await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
146
+
147
+ const creds = await manager.getCredentials()
148
+ expect(creds).toEqual({
149
+ app_id: 'wx123',
150
+ app_secret: 'secret123',
151
+ account_name: 'My Account',
152
+ })
153
+
154
+ const config = await manager.load()
155
+ expect(config.current).toEqual({ account_id: 'wx123' })
156
+ })
157
+
158
+ test('removeAccount deletes account and adjusts current', async () => {
159
+ const manager = setup()
160
+ await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
161
+
162
+ const removed = await manager.removeAccount('wx123')
163
+ expect(removed).toBe(true)
164
+
165
+ const creds = await manager.getCredentials()
166
+ expect(creds).toBeNull()
167
+
168
+ const config = await manager.load()
169
+ expect(config.current).toBeNull()
170
+ expect(config.accounts['wx123']).toBeUndefined()
171
+ })
172
+
173
+ test('removeAccount returns false for non-existent account', async () => {
174
+ const manager = setup()
175
+ const removed = await manager.removeAccount('nonexistent')
176
+ expect(removed).toBe(false)
177
+ })
178
+
179
+ test('removeAccount does not clear current when a different account is removed', async () => {
180
+ const manager = setup()
181
+ await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
182
+ await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
183
+
184
+ const removed = await manager.removeAccount('wx-a')
185
+ expect(removed).toBe(true)
186
+
187
+ const config = await manager.load()
188
+ expect(config.current).toEqual({ account_id: 'wx-b' })
189
+ })
190
+
191
+ test('setCurrent switches active account', async () => {
192
+ const manager = setup()
193
+ await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
194
+ await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
195
+
196
+ const result = await manager.setCurrent('wx-a')
197
+ expect(result).toBe(true)
198
+
199
+ const config = await manager.load()
200
+ expect(config.current).toEqual({ account_id: 'wx-a' })
201
+ })
202
+
203
+ test('setCurrent returns false for non-existent account', async () => {
204
+ const manager = setup()
205
+ const result = await manager.setCurrent('nonexistent')
206
+ expect(result).toBe(false)
207
+ })
208
+
209
+ test('listAll returns all accounts with is_current flag', async () => {
210
+ const manager = setup()
211
+ await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
212
+ await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
213
+
214
+ const accounts = await manager.listAll()
215
+ expect(accounts).toHaveLength(2)
216
+
217
+ const acctA = accounts.find((a) => a.app_id === 'wx-a')
218
+ const acctB = accounts.find((a) => a.app_id === 'wx-b')
219
+
220
+ expect(acctA?.is_current).toBe(false)
221
+ expect(acctB?.is_current).toBe(true)
222
+ })
223
+
224
+ test('listAll returns empty array when no accounts', async () => {
225
+ const manager = setup()
226
+ const accounts = await manager.listAll()
227
+ expect(accounts).toHaveLength(0)
228
+ })
229
+
230
+ test('clearCredentials resets everything', async () => {
231
+ const manager = setup()
232
+ await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
233
+
234
+ await manager.clearCredentials()
235
+
236
+ const config = await manager.load()
237
+ expect(config.current).toBeNull()
238
+ expect(config.accounts).toEqual({})
239
+ })
240
+
241
+ test('round-trip: set → get → remove → get null', async () => {
242
+ const manager = setup()
243
+
244
+ await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
245
+
246
+ const creds = await manager.getCredentials()
247
+ expect(creds?.app_id).toBe('wx123')
248
+ expect(creds?.app_secret).toBe('secret123')
249
+
250
+ await manager.removeAccount('wx123')
251
+
252
+ const afterRemove = await manager.getCredentials()
253
+ expect(afterRemove).toBeNull()
254
+ })
255
+ })