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
@@ -1,18 +1,14 @@
1
1
  import { afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
2
2
 
3
- import { WebexClient } from '../client'
4
3
  import { WebexError } from '../types'
5
- import { deleteAction, dmAction, editAction, getAction, listAction, sendAction } from './message'
6
4
 
7
- let clientSendMessageSpy: ReturnType<typeof spyOn>
8
- let clientSendDirectMessageSpy: ReturnType<typeof spyOn>
9
- let clientListMessagesSpy: ReturnType<typeof spyOn>
10
- let clientGetMessageSpy: ReturnType<typeof spyOn>
11
- let clientDeleteMessageSpy: ReturnType<typeof spyOn>
12
- let clientEditMessageSpy: ReturnType<typeof spyOn>
13
- let clientLoginSpy: ReturnType<typeof spyOn>
14
- const originalConsoleLog = console.log
15
- const originalConsoleError = console.error
5
+ const mockHandleError = mock((err: Error) => {
6
+ throw err
7
+ })
8
+
9
+ mock.module('@/shared/utils/error-handler', () => ({
10
+ handleError: mockHandleError,
11
+ }))
16
12
 
17
13
  const mockMessage = {
18
14
  id: 'msg_123',
@@ -34,202 +30,159 @@ const mockMessage2 = {
34
30
  created: '2025-01-29T10:01:00.000Z',
35
31
  }
36
32
 
37
- beforeEach(() => {
38
- clientLoginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient() as any)
39
-
40
- clientSendMessageSpy = spyOn(WebexClient.prototype, 'sendMessage').mockResolvedValue(mockMessage)
33
+ const mockSendMessage = mock(() => Promise.resolve(mockMessage))
34
+ const mockSendDirectMessage = mock(() => Promise.resolve(mockMessage))
35
+ const mockListMessages = mock(() => Promise.resolve([mockMessage, mockMessage2]))
36
+ const mockGetMessage = mock(() => Promise.resolve(mockMessage))
37
+ const mockDeleteMessage = mock(() => Promise.resolve(undefined))
38
+ const mockEditMessage = mock(() => Promise.resolve({ ...mockMessage, text: 'Updated message' }))
39
+
40
+ const mockClient = {
41
+ sendMessage: mockSendMessage,
42
+ sendDirectMessage: mockSendDirectMessage,
43
+ listMessages: mockListMessages,
44
+ getMessage: mockGetMessage,
45
+ deleteMessage: mockDeleteMessage,
46
+ editMessage: mockEditMessage,
47
+ }
41
48
 
42
- clientSendDirectMessageSpy = spyOn(WebexClient.prototype, 'sendDirectMessage').mockResolvedValue(mockMessage)
49
+ const mockLogin = mock(() => Promise.resolve(mockClient))
43
50
 
44
- clientListMessagesSpy = spyOn(WebexClient.prototype, 'listMessages').mockResolvedValue([
45
- mockMessage,
46
- mockMessage2,
47
- ])
51
+ mock.module('../client', () => ({
52
+ WebexClient: class {
53
+ login = mockLogin
54
+ },
55
+ }))
48
56
 
49
- clientGetMessageSpy = spyOn(WebexClient.prototype, 'getMessage').mockResolvedValue(mockMessage)
57
+ import { deleteAction, dmAction, editAction, getAction, listAction, sendAction } from './message'
50
58
 
51
- clientDeleteMessageSpy = spyOn(WebexClient.prototype, 'deleteMessage').mockResolvedValue(
52
- undefined,
53
- )
59
+ let consoleLogSpy: ReturnType<typeof spyOn>
54
60
 
55
- clientEditMessageSpy = spyOn(WebexClient.prototype, 'editMessage').mockResolvedValue({
56
- ...mockMessage,
57
- text: 'Updated message',
61
+ beforeEach(() => {
62
+ mockSendMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
63
+ mockSendDirectMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
64
+ mockListMessages.mockReset().mockImplementation(() => Promise.resolve([mockMessage, mockMessage2]))
65
+ mockGetMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
66
+ mockDeleteMessage.mockReset().mockImplementation(() => Promise.resolve(undefined))
67
+ mockEditMessage.mockReset().mockImplementation(() => Promise.resolve({ ...mockMessage, text: 'Updated message' }))
68
+ mockLogin.mockReset().mockImplementation(() => Promise.resolve(mockClient))
69
+ mockHandleError.mockReset().mockImplementation((err: Error) => {
70
+ throw err
58
71
  })
72
+
73
+ consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
59
74
  })
60
75
 
61
76
  afterEach(() => {
62
- clientLoginSpy?.mockRestore()
63
- clientSendMessageSpy?.mockRestore()
64
- clientSendDirectMessageSpy?.mockRestore()
65
- clientListMessagesSpy?.mockRestore()
66
- clientGetMessageSpy?.mockRestore()
67
- clientDeleteMessageSpy?.mockRestore()
68
- clientEditMessageSpy?.mockRestore()
69
- console.log = originalConsoleLog
70
- console.error = originalConsoleError
77
+ consoleLogSpy.mockRestore()
71
78
  })
72
79
 
73
80
  test('send: calls sendMessage with correct args and outputs result', async () => {
74
- const consoleSpy = mock((_msg: string) => {})
75
- console.log = consoleSpy
76
-
77
81
  await sendAction('space_456', 'Hello world', { pretty: false })
78
82
 
79
- expect(clientSendMessageSpy).toHaveBeenCalledWith('space_456', 'Hello world', {
83
+ expect(mockSendMessage).toHaveBeenCalledWith('space_456', 'Hello world', {
80
84
  markdown: undefined,
81
85
  })
82
- expect(consoleSpy).toHaveBeenCalled()
83
- const output = consoleSpy.mock.calls[0][0]
86
+ expect(consoleLogSpy).toHaveBeenCalled()
87
+ const output = consoleLogSpy.mock.calls[0][0]
84
88
  expect(output).toContain('msg_123')
85
89
  expect(output).toContain('space_456')
86
90
  expect(output).toContain('user@example.com')
87
91
  })
88
92
 
89
93
  test('send: with --markdown passes markdown option', async () => {
90
- const consoleSpy = mock((_msg: string) => {})
91
- console.log = consoleSpy
92
-
93
94
  await sendAction('space_456', '**bold**', { markdown: true, pretty: false })
94
95
 
95
- expect(clientSendMessageSpy).toHaveBeenCalledWith('space_456', '**bold**', { markdown: true })
96
+ expect(mockSendMessage).toHaveBeenCalledWith('space_456', '**bold**', { markdown: true })
96
97
  })
97
98
 
98
99
  test('send: not authenticated shows error', async () => {
99
- clientLoginSpy.mockRejectedValue(new WebexError('No Webex credentials found.', 'no_credentials'))
100
-
101
- let stderrOutput = ''
102
- const origWrite = process.stderr.write
103
- process.stderr.write = ((chunk: string | Uint8Array) => {
104
- stderrOutput += typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk)
105
- return true
106
- }) as typeof process.stderr.write
100
+ mockLogin.mockImplementation(async () => {
101
+ throw new WebexError('No Webex credentials found.', 'no_credentials')
102
+ })
107
103
 
108
- const originalExit = process.exit
109
- process.exit = mock((_code?: number) => {
110
- throw new Error('process.exit called')
111
- }) as never
104
+ await expect(sendAction('space_456', 'Hello', { pretty: false })).rejects.toThrow('No Webex credentials found.')
112
105
 
113
- try {
114
- await sendAction('space_456', 'Hello', { pretty: false })
115
- } catch {
116
- } finally {
117
- process.exit = originalExit
118
- process.stderr.write = origWrite
119
- }
120
-
121
- expect(stderrOutput).toContain('No Webex credentials found')
106
+ expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
122
107
  })
123
108
 
124
109
  test('dm: calls sendDirectMessage with email and text', async () => {
125
- const consoleSpy = mock((_msg: string) => {})
126
- console.log = consoleSpy
127
-
128
110
  await dmAction('alice@example.com', 'Hello!', { pretty: false })
129
111
 
130
- expect(clientSendDirectMessageSpy).toHaveBeenCalledWith('alice@example.com', 'Hello!', {
112
+ expect(mockSendDirectMessage).toHaveBeenCalledWith('alice@example.com', 'Hello!', {
131
113
  markdown: undefined,
132
114
  })
133
- expect(consoleSpy).toHaveBeenCalled()
134
- const output = consoleSpy.mock.calls[0][0]
115
+ expect(consoleLogSpy).toHaveBeenCalled()
116
+ const output = consoleLogSpy.mock.calls[0][0]
135
117
  expect(output).toContain('msg_123')
136
118
  })
137
119
 
138
120
  test('dm: with --markdown passes markdown option', async () => {
139
- const consoleSpy = mock((_msg: string) => {})
140
- console.log = consoleSpy
141
-
142
121
  await dmAction('alice@example.com', '**bold**', { markdown: true, pretty: false })
143
122
 
144
- expect(clientSendDirectMessageSpy).toHaveBeenCalledWith('alice@example.com', '**bold**', {
123
+ expect(mockSendDirectMessage).toHaveBeenCalledWith('alice@example.com', '**bold**', {
145
124
  markdown: true,
146
125
  })
147
126
  })
148
127
 
149
128
  test('list: calls listMessages with limit and outputs array', async () => {
150
- const consoleSpy = mock((_msg: string) => {})
151
- console.log = consoleSpy
152
-
153
129
  await listAction('space_456', { limit: 50, pretty: false })
154
130
 
155
- expect(clientListMessagesSpy).toHaveBeenCalledWith('space_456', { max: 50 })
156
- expect(consoleSpy).toHaveBeenCalled()
157
- const output = consoleSpy.mock.calls[0][0]
131
+ expect(mockListMessages).toHaveBeenCalledWith('space_456', { max: 50 })
132
+ expect(consoleLogSpy).toHaveBeenCalled()
133
+ const output = consoleLogSpy.mock.calls[0][0]
158
134
  expect(output).toContain('msg_123')
159
135
  expect(output).toContain('msg_124')
160
136
  })
161
137
 
162
138
  test('get: calls getMessage with correct id and outputs result', async () => {
163
- const consoleSpy = mock((_msg: string) => {})
164
- console.log = consoleSpy
165
-
166
139
  await getAction('msg_123', { pretty: false })
167
140
 
168
- expect(clientGetMessageSpy).toHaveBeenCalledWith('msg_123')
169
- expect(consoleSpy).toHaveBeenCalled()
170
- const output = consoleSpy.mock.calls[0][0]
141
+ expect(mockGetMessage).toHaveBeenCalledWith('msg_123')
142
+ expect(consoleLogSpy).toHaveBeenCalled()
143
+ const output = consoleLogSpy.mock.calls[0][0]
171
144
  expect(output).toContain('msg_123')
172
145
  expect(output).toContain('user@example.com')
173
146
  })
174
147
 
175
148
  test('delete: with --force calls deleteMessage and outputs deleted id', async () => {
176
- const consoleSpy = mock((_msg: string) => {})
177
- console.log = consoleSpy
178
-
179
149
  await deleteAction('msg_123', { force: true, pretty: false })
180
150
 
181
- expect(clientDeleteMessageSpy).toHaveBeenCalledWith('msg_123')
182
- expect(consoleSpy).toHaveBeenCalled()
183
- const output = consoleSpy.mock.calls[0][0]
151
+ expect(mockDeleteMessage).toHaveBeenCalledWith('msg_123')
152
+ expect(consoleLogSpy).toHaveBeenCalled()
153
+ const output = consoleLogSpy.mock.calls[0][0]
184
154
  expect(output).toContain('deleted')
185
155
  expect(output).toContain('msg_123')
186
156
  })
187
157
 
188
158
  test('delete: without --force shows warning and does not delete', async () => {
189
- const consoleSpy = mock((_msg: string) => {})
190
- console.log = consoleSpy
191
-
192
- const originalExit = process.exit
193
- process.exit = mock((_code?: number) => {
194
- throw new Error('process.exit called')
195
- }) as never
196
-
197
159
  try {
198
160
  await deleteAction('msg_123', { force: false, pretty: false })
199
- } catch {
200
- } finally {
201
- process.exit = originalExit
202
- }
203
-
204
- expect(clientDeleteMessageSpy).not.toHaveBeenCalled()
205
- expect(consoleSpy).toHaveBeenCalled()
206
- const output = consoleSpy.mock.calls[0][0]
161
+ } catch {}
162
+
163
+ expect(mockDeleteMessage).not.toHaveBeenCalled()
164
+ expect(consoleLogSpy).toHaveBeenCalled()
165
+ const output = consoleLogSpy.mock.calls[0][0]
207
166
  expect(output).toContain('warning')
208
167
  expect(output).toContain('--force')
209
168
  })
210
169
 
211
170
  test('edit: calls editMessage with roomId in args and outputs result', async () => {
212
- const consoleSpy = mock((_msg: string) => {})
213
- console.log = consoleSpy
214
-
215
171
  await editAction('msg_123', 'space_456', 'Updated message', { pretty: false })
216
172
 
217
- expect(clientEditMessageSpy).toHaveBeenCalledWith('msg_123', 'space_456', 'Updated message', {
173
+ expect(mockEditMessage).toHaveBeenCalledWith('msg_123', 'space_456', 'Updated message', {
218
174
  markdown: undefined,
219
175
  })
220
- expect(consoleSpy).toHaveBeenCalled()
221
- const output = consoleSpy.mock.calls[0][0]
176
+ expect(consoleLogSpy).toHaveBeenCalled()
177
+ const output = consoleLogSpy.mock.calls[0][0]
222
178
  expect(output).toContain('msg_123')
223
179
  expect(output).toContain('Updated message')
224
180
  })
225
181
 
226
182
  test('edit: with --markdown passes markdown option', async () => {
227
- const consoleSpy = mock((_msg: string) => {})
228
- console.log = consoleSpy
229
-
230
183
  await editAction('msg_123', 'space_456', '**updated**', { markdown: true, pretty: false })
231
184
 
232
- expect(clientEditMessageSpy).toHaveBeenCalledWith('msg_123', 'space_456', '**updated**', {
185
+ expect(mockEditMessage).toHaveBeenCalledWith('msg_123', 'space_456', '**updated**', {
233
186
  markdown: true,
234
187
  })
235
188
  })
@@ -83,7 +83,7 @@ export async function deleteAction(
83
83
  console.log(
84
84
  formatOutput({ warning: 'Use --force to confirm deletion', messageId }, options.pretty),
85
85
  )
86
- process.exit(0)
86
+ return process.exit(0)
87
87
  }
88
88
 
89
89
  const client = await new WebexClient().login()
@@ -1,44 +1,63 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
2
- import { WebexClient } from '../client'
3
2
  import { WebexError } from '../types'
4
- import { snapshotAction } from './snapshot'
5
3
 
6
- describe('snapshot command', () => {
7
- let consoleSpy: ReturnType<typeof spyOn>
8
- let consoleErrorSpy: ReturnType<typeof spyOn>
9
- let stderrOutput: string
10
- let origStderrWrite: typeof process.stderr.write
4
+ const mockHandleError = mock((err: Error) => {
5
+ throw err
6
+ })
7
+
8
+ mock.module('@/shared/utils/error-handler', () => ({
9
+ handleError: mockHandleError,
10
+ }))
11
+
12
+ const mockSpaces = [
13
+ { id: 'space-1', title: 'General', type: 'group', isLocked: false, lastActivity: '2024-01-15T00:00:00.000Z', created: '2024-01-01T00:00:00.000Z', creatorId: 'person-1' },
14
+ ]
15
+
16
+ const mockMessages = [
17
+ { id: 'msg-1', roomId: 'space-1', roomType: 'group', text: 'Hello', personId: 'person-1', personEmail: 'alice@example.com', created: '2024-01-15T00:00:00.000Z' },
18
+ ]
19
+
20
+ const mockMembers = [
21
+ { id: 'mem-1', roomId: 'space-1', personId: 'person-1', personEmail: 'alice@example.com', personDisplayName: 'Alice', isModerator: true, created: '2024-01-01T00:00:00.000Z' },
22
+ ]
23
+
24
+ const mockListSpaces = mock(() => Promise.resolve(mockSpaces as any))
25
+ const mockListMessages = mock(() => Promise.resolve(mockMessages as any))
26
+ const mockListMemberships = mock(() => Promise.resolve(mockMembers as any))
11
27
 
12
- const mockSpaces = [
13
- { id: 'space-1', title: 'General', type: 'group', isLocked: false, lastActivity: '2024-01-15T00:00:00.000Z', created: '2024-01-01T00:00:00.000Z', creatorId: 'person-1' },
14
- ]
28
+ const mockClient = {
29
+ listSpaces: mockListSpaces,
30
+ listMessages: mockListMessages,
31
+ listMemberships: mockListMemberships,
32
+ }
15
33
 
16
- const mockMessages = [
17
- { id: 'msg-1', roomId: 'space-1', roomType: 'group', text: 'Hello', personId: 'person-1', personEmail: 'alice@example.com', created: '2024-01-15T00:00:00.000Z' },
18
- ]
34
+ const mockLogin = mock(() => Promise.resolve(mockClient))
19
35
 
20
- const mockMembers = [
21
- { id: 'mem-1', roomId: 'space-1', personId: 'person-1', personEmail: 'alice@example.com', personDisplayName: 'Alice', isModerator: true, created: '2024-01-01T00:00:00.000Z' },
22
- ]
36
+ mock.module('../client', () => ({
37
+ WebexClient: class {
38
+ login = mockLogin
39
+ },
40
+ }))
41
+
42
+ import { snapshotAction } from './snapshot'
43
+
44
+ describe('snapshot command', () => {
45
+ let consoleSpy: ReturnType<typeof spyOn>
23
46
 
24
47
  beforeEach(() => {
48
+ mockListSpaces.mockReset().mockImplementation(() => Promise.resolve(mockSpaces as any))
49
+ mockListMessages.mockReset().mockImplementation(() => Promise.resolve(mockMessages as any))
50
+ mockListMemberships.mockReset().mockImplementation(() => Promise.resolve(mockMembers as any))
51
+ mockLogin.mockReset().mockImplementation(() => Promise.resolve(mockClient))
52
+ mockHandleError.mockReset().mockImplementation((err: Error) => {
53
+ throw err
54
+ })
55
+
25
56
  consoleSpy = spyOn(console, 'log').mockImplementation(() => {})
26
- consoleErrorSpy = spyOn(console, 'error').mockImplementation(() => {})
27
- stderrOutput = ''
28
- origStderrWrite = process.stderr.write
29
- process.stderr.write = ((chunk: string | Uint8Array) => {
30
- stderrOutput += typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk)
31
- return true
32
- }) as typeof process.stderr.write
33
- spyOn(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient() as any)
34
- spyOn(WebexClient.prototype, 'listSpaces').mockResolvedValue(mockSpaces as any)
35
- spyOn(WebexClient.prototype, 'listMessages').mockResolvedValue(mockMessages as any)
36
- spyOn(WebexClient.prototype, 'listMemberships').mockResolvedValue(mockMembers as any)
37
57
  })
38
58
 
39
59
  afterEach(() => {
40
- process.stderr.write = origStderrWrite
41
- mock.restore()
60
+ consoleSpy.mockRestore()
42
61
  })
43
62
 
44
63
  test('full snapshot includes spaces, recent_messages, members', async () => {
@@ -78,28 +97,18 @@ describe('snapshot command', () => {
78
97
  })
79
98
 
80
99
  test('not authenticated outputs error', async () => {
81
- spyOn(WebexClient.prototype, 'login').mockRejectedValue(
82
- new WebexError('No Webex credentials found.', 'no_credentials'),
83
- )
100
+ mockLogin.mockImplementation(async () => {
101
+ throw new WebexError('No Webex credentials found.', 'no_credentials')
102
+ })
84
103
 
85
- const originalExit = process.exit
86
- process.exit = mock((_code?: number) => { throw new Error('process.exit called') }) as never
104
+ await expect(snapshotAction({})).rejects.toThrow('No Webex credentials found.')
87
105
 
88
- try {
89
- await snapshotAction({})
90
- } catch {
91
- } finally {
92
- process.exit = originalExit
93
- }
94
-
95
- expect(stderrOutput).toContain('No Webex credentials found')
106
+ expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
96
107
  })
97
108
 
98
109
  test('passes limit option to listMessages', async () => {
99
- const listMessagesSpy = spyOn(WebexClient.prototype, 'listMessages').mockResolvedValue(mockMessages as any)
100
-
101
110
  await snapshotAction({ limit: 5 })
102
111
 
103
- expect(listMessagesSpy).toHaveBeenCalledWith('space-1', { max: 5 })
112
+ expect(mockListMessages).toHaveBeenCalledWith('space-1', { max: 5 })
104
113
  })
105
114
  })
@@ -1,8 +1,14 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
2
2
 
3
- import { WebexClient } from '../client'
4
3
  import { WebexError } from '../types'
5
- import { infoAction, listAction } from './space'
4
+
5
+ const mockHandleError = mock((err: Error) => {
6
+ throw err
7
+ })
8
+
9
+ mock.module('@/shared/utils/error-handler', () => ({
10
+ handleError: mockHandleError,
11
+ }))
6
12
 
7
13
  const mockSpaces = [
8
14
  {
@@ -36,54 +42,42 @@ const mockSpace = {
36
42
  creatorId: 'person-1',
37
43
  }
38
44
 
39
- let clientLoginSpy: ReturnType<typeof spyOn>
40
- let clientListSpacesSpy: ReturnType<typeof spyOn>
41
- let clientGetSpaceSpy: ReturnType<typeof spyOn>
42
- let consoleLogSpy: ReturnType<typeof spyOn>
43
- let consoleErrorSpy: ReturnType<typeof spyOn>
44
- let processExitSpy: ReturnType<typeof spyOn>
45
- let stderrOutput: string
46
- let origStderrWrite: typeof process.stderr.write
47
-
48
- beforeEach(() => {
49
- clientLoginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(
50
- new WebexClient() as InstanceType<typeof WebexClient>,
51
- )
45
+ const mockListSpaces = mock(() => Promise.resolve(mockSpaces))
46
+ const mockGetSpace = mock(() => Promise.resolve(mockSpace))
47
+ const mockLogin = mock(() => Promise.resolve({ listSpaces: mockListSpaces, getSpace: mockGetSpace }))
52
48
 
53
- clientListSpacesSpy = spyOn(WebexClient.prototype, 'listSpaces').mockResolvedValue(mockSpaces)
49
+ mock.module('../client', () => ({
50
+ WebexClient: class {
51
+ login = mockLogin
52
+ },
53
+ }))
54
54
 
55
- clientGetSpaceSpy = spyOn(WebexClient.prototype, 'getSpace').mockResolvedValue(mockSpace)
55
+ import { infoAction, listAction } from './space'
56
56
 
57
- consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
58
- consoleErrorSpy = spyOn(console, 'error').mockImplementation(() => {})
57
+ let consoleLogSpy: ReturnType<typeof spyOn>
59
58
 
60
- processExitSpy = spyOn(process, 'exit').mockImplementation((_code?: number) => {
61
- throw new Error(`process.exit(${_code})`)
59
+ beforeEach(() => {
60
+ mockListSpaces.mockReset().mockImplementation(() => Promise.resolve(mockSpaces))
61
+ mockGetSpace.mockReset().mockImplementation(() => Promise.resolve(mockSpace))
62
+ mockLogin.mockReset().mockImplementation(() =>
63
+ Promise.resolve({ listSpaces: mockListSpaces, getSpace: mockGetSpace }),
64
+ )
65
+ mockHandleError.mockReset().mockImplementation((err: Error) => {
66
+ throw err
62
67
  })
63
68
 
64
- stderrOutput = ''
65
- origStderrWrite = process.stderr.write
66
- process.stderr.write = ((chunk: string | Uint8Array) => {
67
- stderrOutput += typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk)
68
- return true
69
- }) as typeof process.stderr.write
69
+ consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
70
70
  })
71
71
 
72
72
  afterEach(() => {
73
- process.stderr.write = origStderrWrite
74
- clientLoginSpy?.mockRestore()
75
- clientListSpacesSpy?.mockRestore()
76
- clientGetSpaceSpy?.mockRestore()
77
- consoleLogSpy?.mockRestore()
78
- consoleErrorSpy?.mockRestore()
79
- processExitSpy?.mockRestore()
73
+ consoleLogSpy.mockRestore()
80
74
  })
81
75
 
82
76
  describe('listAction', () => {
83
77
  test('calls listSpaces and outputs mapped array', async () => {
84
78
  await listAction({})
85
79
 
86
- expect(clientListSpacesSpy).toHaveBeenCalled()
80
+ expect(mockListSpaces).toHaveBeenCalled()
87
81
  expect(consoleLogSpy).toHaveBeenCalledWith(
88
82
  JSON.stringify([
89
83
  {
@@ -107,13 +101,13 @@ describe('listAction', () => {
107
101
  test('passes type and limit options to listSpaces', async () => {
108
102
  await listAction({ type: 'group', limit: 10 })
109
103
 
110
- expect(clientListSpacesSpy).toHaveBeenCalledWith({ type: 'group', max: 10 })
104
+ expect(mockListSpaces).toHaveBeenCalledWith({ type: 'group', max: 10 })
111
105
  })
112
106
 
113
107
  test('passes undefined type and limit when not provided', async () => {
114
108
  await listAction({})
115
109
 
116
- expect(clientListSpacesSpy).toHaveBeenCalledWith({ type: undefined, max: undefined })
110
+ expect(mockListSpaces).toHaveBeenCalledWith({ type: undefined, max: undefined })
117
111
  })
118
112
 
119
113
  test('outputs pretty-printed JSON when pretty is true', async () => {
@@ -144,12 +138,14 @@ describe('listAction', () => {
144
138
  })
145
139
 
146
140
  test('not authenticated: outputs error and exits', async () => {
147
- clientLoginSpy.mockRejectedValue(new WebexError('No Webex credentials found.', 'no_credentials'))
141
+ mockLogin.mockImplementation(async () => {
142
+ throw new WebexError('No Webex credentials found.', 'no_credentials')
143
+ })
148
144
 
149
- await expect(listAction({})).rejects.toThrow('process.exit(1)')
145
+ await expect(listAction({})).rejects.toThrow('No Webex credentials found.')
150
146
 
151
- expect(clientListSpacesSpy).not.toHaveBeenCalled()
152
- expect(stderrOutput).toContain('No Webex credentials found')
147
+ expect(mockListSpaces).not.toHaveBeenCalled()
148
+ expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
153
149
  })
154
150
  })
155
151
 
@@ -157,7 +153,7 @@ describe('infoAction', () => {
157
153
  test('calls getSpace with spaceId and outputs space details', async () => {
158
154
  await infoAction('space-1', {})
159
155
 
160
- expect(clientGetSpaceSpy).toHaveBeenCalledWith('space-1')
156
+ expect(mockGetSpace).toHaveBeenCalledWith('space-1')
161
157
  expect(consoleLogSpy).toHaveBeenCalledWith(
162
158
  JSON.stringify({
163
159
  id: 'space-1',
@@ -173,8 +169,7 @@ describe('infoAction', () => {
173
169
  })
174
170
 
175
171
  test('outputs null for teamId when not present', async () => {
176
- const spaceWithoutTeam = { ...mockSpace, teamId: undefined }
177
- clientGetSpaceSpy.mockResolvedValue(spaceWithoutTeam)
172
+ mockGetSpace.mockImplementation(() => Promise.resolve({ ...mockSpace, teamId: undefined }))
178
173
 
179
174
  await infoAction('space-1', {})
180
175
 
@@ -206,11 +201,13 @@ describe('infoAction', () => {
206
201
  })
207
202
 
208
203
  test('not authenticated: outputs error and exits', async () => {
209
- clientLoginSpy.mockRejectedValue(new WebexError('No Webex credentials found.', 'no_credentials'))
204
+ mockLogin.mockImplementation(async () => {
205
+ throw new WebexError('No Webex credentials found.', 'no_credentials')
206
+ })
210
207
 
211
- await expect(infoAction('space-1', {})).rejects.toThrow('process.exit(1)')
208
+ await expect(infoAction('space-1', {})).rejects.toThrow('No Webex credentials found.')
212
209
 
213
- expect(clientGetSpaceSpy).not.toHaveBeenCalled()
214
- expect(stderrOutput).toContain('No Webex credentials found')
210
+ expect(mockGetSpace).not.toHaveBeenCalled()
211
+ expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
215
212
  })
216
213
  })