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,299 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
2
+
3
+ const originalConsoleLog = console.log
4
+
5
+ const mockLoad = mock(() =>
6
+ Promise.resolve({ current_account: null, accounts: {} }),
7
+ )
8
+ const mockGetAccount = mock(() => Promise.resolve(null))
9
+ const mockListAccounts = mock(() => Promise.resolve([]))
10
+ const mockSetAccount = mock(() => Promise.resolve())
11
+ const mockSetCurrentAccount = mock(() => Promise.resolve())
12
+ const mockRemoveAccount = mock(() => Promise.resolve())
13
+ const mockLoadPendingLogin = mock(() => Promise.resolve(null))
14
+
15
+ mock.module('../credential-manager', () => ({
16
+ CredentialManager: class {
17
+ load = mockLoad
18
+ getAccount = mockGetAccount
19
+ listAccounts = mockListAccounts
20
+ setAccount = mockSetAccount
21
+ setCurrentAccount = mockSetCurrentAccount
22
+ removeAccount = mockRemoveAccount
23
+ loadPendingLogin = mockLoadPendingLogin
24
+ },
25
+ KakaoCredentialManager: class {
26
+ load = mockLoad
27
+ getAccount = mockGetAccount
28
+ listAccounts = mockListAccounts
29
+ setAccount = mockSetAccount
30
+ setCurrentAccount = mockSetCurrentAccount
31
+ removeAccount = mockRemoveAccount
32
+ loadPendingLogin = mockLoadPendingLogin
33
+ },
34
+ }))
35
+
36
+ import { authCommand } from './auth'
37
+
38
+ describe('auth commands', () => {
39
+ let consoleLogSpy: ReturnType<typeof mock>
40
+ let processExitSpy: ReturnType<typeof spyOn>
41
+
42
+ beforeEach(() => {
43
+ mockLoad.mockReset()
44
+ mockGetAccount.mockReset()
45
+ mockListAccounts.mockReset()
46
+ mockSetAccount.mockReset()
47
+ mockSetCurrentAccount.mockReset()
48
+ mockRemoveAccount.mockReset()
49
+ mockLoadPendingLogin.mockReset()
50
+
51
+ mockLoad.mockImplementation(() =>
52
+ Promise.resolve({ current_account: null, accounts: {} }),
53
+ )
54
+ mockGetAccount.mockImplementation(() => Promise.resolve(null))
55
+ mockListAccounts.mockImplementation(() => Promise.resolve([]))
56
+ mockSetAccount.mockImplementation(() => Promise.resolve())
57
+ mockSetCurrentAccount.mockImplementation(() => Promise.resolve())
58
+ mockRemoveAccount.mockImplementation(() => Promise.resolve())
59
+ mockLoadPendingLogin.mockImplementation(() => Promise.resolve(null))
60
+
61
+ consoleLogSpy = mock((..._args: unknown[]) => {})
62
+ console.log = consoleLogSpy
63
+ processExitSpy = spyOn(process, 'exit').mockImplementation((_code?: number) => {
64
+ throw new Error(`process.exit(${_code})`)
65
+ })
66
+ })
67
+
68
+ afterEach(() => {
69
+ console.log = originalConsoleLog
70
+ processExitSpy?.mockRestore()
71
+ })
72
+
73
+ describe('list', () => {
74
+ test('outputs empty array when no accounts', async () => {
75
+ mockListAccounts.mockImplementation(() => Promise.resolve([]))
76
+
77
+ await authCommand.parseAsync(['list'], { from: 'user' })
78
+
79
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
80
+ expect(output).toEqual([])
81
+ })
82
+
83
+ test('outputs accounts list with is_current flag', async () => {
84
+ mockListAccounts.mockImplementation(() =>
85
+ Promise.resolve([
86
+ {
87
+ account_id: 'user-1',
88
+ user_id: 'user-1',
89
+ device_type: 'tablet',
90
+ created_at: '2024-01-01T00:00:00.000Z',
91
+ updated_at: '2024-01-01T00:00:00.000Z',
92
+ is_current: true,
93
+ oauth_token: 'token-1',
94
+ refresh_token: 'refresh-1',
95
+ device_uuid: 'uuid-1',
96
+ },
97
+ {
98
+ account_id: 'user-2',
99
+ user_id: 'user-2',
100
+ device_type: 'pc',
101
+ created_at: '2024-01-02T00:00:00.000Z',
102
+ updated_at: '2024-01-02T00:00:00.000Z',
103
+ is_current: false,
104
+ oauth_token: 'token-2',
105
+ refresh_token: 'refresh-2',
106
+ device_uuid: 'uuid-2',
107
+ },
108
+ ]),
109
+ )
110
+
111
+ await authCommand.parseAsync(['list'], { from: 'user' })
112
+
113
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
114
+ expect(output).toHaveLength(2)
115
+ expect(output[0].account_id).toBe('user-1')
116
+ expect(output[0].is_current).toBe(true)
117
+ expect(output[1].account_id).toBe('user-2')
118
+ expect(output[1].is_current).toBe(false)
119
+ })
120
+ })
121
+
122
+ describe('use', () => {
123
+ test('switches to specified account', async () => {
124
+ mockGetAccount.mockImplementation(() =>
125
+ Promise.resolve({
126
+ account_id: 'user-1',
127
+ user_id: 'user-1',
128
+ device_type: 'tablet',
129
+ oauth_token: 'token-1',
130
+ refresh_token: 'refresh-1',
131
+ device_uuid: 'uuid-1',
132
+ created_at: '2024-01-01T00:00:00.000Z',
133
+ updated_at: '2024-01-01T00:00:00.000Z',
134
+ }),
135
+ )
136
+
137
+ await authCommand.parseAsync(['use', 'user-1'], { from: 'user' })
138
+
139
+ expect(mockSetCurrentAccount).toHaveBeenCalledWith('user-1')
140
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
141
+ expect(output.success).toBe(true)
142
+ expect(output.account_id).toBe('user-1')
143
+ })
144
+
145
+ test('outputs error and exits when account not found', async () => {
146
+ mockGetAccount.mockImplementation(() => Promise.resolve(null))
147
+
148
+ await expect(
149
+ authCommand.parseAsync(['use', 'nonexistent'], { from: 'user' }),
150
+ ).rejects.toThrow('process.exit')
151
+
152
+ expect(processExitSpy).toHaveBeenCalledWith(1)
153
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
154
+ expect(output.error).toContain('nonexistent')
155
+ })
156
+ })
157
+
158
+ describe('status', () => {
159
+ test('outputs error and exits when no account configured', async () => {
160
+ mockGetAccount.mockImplementation(() => Promise.resolve(null))
161
+
162
+ await expect(
163
+ authCommand.parseAsync(['status'], { from: 'user' }),
164
+ ).rejects.toThrow('process.exit')
165
+
166
+ expect(processExitSpy).toHaveBeenCalledWith(1)
167
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
168
+ expect(output.error).toBeDefined()
169
+ })
170
+
171
+ test('outputs account info when account exists', async () => {
172
+ mockGetAccount.mockImplementation(() =>
173
+ Promise.resolve({
174
+ account_id: 'user-1',
175
+ user_id: 'user-1',
176
+ device_type: 'tablet',
177
+ oauth_token: 'token-1',
178
+ refresh_token: 'refresh-1',
179
+ device_uuid: 'uuid-1',
180
+ created_at: '2024-01-01T00:00:00.000Z',
181
+ updated_at: '2024-01-01T00:00:00.000Z',
182
+ }),
183
+ )
184
+
185
+ await authCommand.parseAsync(['status'], { from: 'user' })
186
+
187
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
188
+ expect(output.account_id).toBe('user-1')
189
+ expect(output.user_id).toBe('user-1')
190
+ expect(output.device_type).toBe('tablet')
191
+ expect(output.has_refresh_token).toBe(true)
192
+ expect(output.has_device_uuid).toBe(true)
193
+ })
194
+
195
+ test('outputs status for specific --account', async () => {
196
+ mockGetAccount.mockImplementation((id?: string) => {
197
+ if (id === 'user-2') {
198
+ return Promise.resolve({
199
+ account_id: 'user-2',
200
+ user_id: 'user-2',
201
+ device_type: 'pc',
202
+ oauth_token: 'token-2',
203
+ refresh_token: 'refresh-2',
204
+ device_uuid: 'uuid-2',
205
+ created_at: '2024-01-02T00:00:00.000Z',
206
+ updated_at: '2024-01-02T00:00:00.000Z',
207
+ })
208
+ }
209
+ return Promise.resolve(null)
210
+ })
211
+
212
+ await authCommand.parseAsync(['status', '--account', 'user-2'], { from: 'user' })
213
+
214
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
215
+ expect(output.account_id).toBe('user-2')
216
+ expect(output.device_type).toBe('pc')
217
+ })
218
+ })
219
+
220
+ describe('logout', () => {
221
+ test('removes current account and outputs success', async () => {
222
+ mockLoad.mockImplementation(() =>
223
+ Promise.resolve({
224
+ current_account: 'user-1',
225
+ accounts: {
226
+ 'user-1': {
227
+ account_id: 'user-1',
228
+ user_id: 'user-1',
229
+ device_type: 'tablet',
230
+ oauth_token: 'token-1',
231
+ refresh_token: 'refresh-1',
232
+ device_uuid: 'uuid-1',
233
+ created_at: '2024-01-01T00:00:00.000Z',
234
+ updated_at: '2024-01-01T00:00:00.000Z',
235
+ },
236
+ },
237
+ }),
238
+ )
239
+
240
+ await authCommand.parseAsync(['logout'], { from: 'user' })
241
+
242
+ expect(mockRemoveAccount).toHaveBeenCalledWith('user-1')
243
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
244
+ expect(output.success).toBe(true)
245
+ expect(output.removed).toBe('user-1')
246
+ })
247
+
248
+ test('removes specific account with --account flag', async () => {
249
+ mockLoad.mockImplementation(() =>
250
+ Promise.resolve({
251
+ current_account: 'user-1',
252
+ accounts: {
253
+ 'user-1': {
254
+ account_id: 'user-1',
255
+ user_id: 'user-1',
256
+ device_type: 'tablet',
257
+ oauth_token: 'token-1',
258
+ refresh_token: 'refresh-1',
259
+ device_uuid: 'uuid-1',
260
+ created_at: '2024-01-01T00:00:00.000Z',
261
+ updated_at: '2024-01-01T00:00:00.000Z',
262
+ },
263
+ 'user-2': {
264
+ account_id: 'user-2',
265
+ user_id: 'user-2',
266
+ device_type: 'pc',
267
+ oauth_token: 'token-2',
268
+ refresh_token: 'refresh-2',
269
+ device_uuid: 'uuid-2',
270
+ created_at: '2024-01-02T00:00:00.000Z',
271
+ updated_at: '2024-01-02T00:00:00.000Z',
272
+ },
273
+ },
274
+ }),
275
+ )
276
+
277
+ await authCommand.parseAsync(['logout', '--account', 'user-2'], { from: 'user' })
278
+
279
+ expect(mockRemoveAccount).toHaveBeenCalledWith('user-2')
280
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
281
+ expect(output.success).toBe(true)
282
+ expect(output.removed).toBe('user-2')
283
+ })
284
+
285
+ test('outputs error and exits when no account configured', async () => {
286
+ mockLoad.mockImplementation(() =>
287
+ Promise.resolve({ current_account: null, accounts: {} }),
288
+ )
289
+
290
+ await expect(
291
+ authCommand.parseAsync(['logout'], { from: 'user' }),
292
+ ).rejects.toThrow('process.exit')
293
+
294
+ expect(processExitSpy).toHaveBeenCalledWith(1)
295
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
296
+ expect(output.error).toBeDefined()
297
+ })
298
+ })
299
+ })
@@ -0,0 +1,97 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const originalConsoleLog = console.log
4
+
5
+ const mockWithKakaoClient = mock(
6
+ async (_options: unknown, fn: (client: unknown) => Promise<unknown>) => {
7
+ return fn(mockClient)
8
+ },
9
+ )
10
+
11
+ const mockGetChats = mock(() =>
12
+ Promise.resolve([
13
+ { chat_id: 'chat-1', name: 'General', type: 'group', member_count: 5 },
14
+ { chat_id: 'chat-2', name: 'Direct', type: 'direct', member_count: 2 },
15
+ ]),
16
+ )
17
+
18
+ const mockClient = {
19
+ getChats: mockGetChats,
20
+ }
21
+
22
+ mock.module('./shared', () => ({
23
+ withKakaoClient: mockWithKakaoClient,
24
+ }))
25
+
26
+ import { chatCommand } from './chat'
27
+
28
+ describe('chat commands', () => {
29
+ let consoleLogSpy: ReturnType<typeof mock>
30
+
31
+ beforeEach(() => {
32
+ mockWithKakaoClient.mockReset()
33
+ mockGetChats.mockReset()
34
+
35
+ mockWithKakaoClient.mockImplementation(
36
+ async (_options: unknown, fn: (client: unknown) => Promise<unknown>) => {
37
+ return fn(mockClient)
38
+ },
39
+ )
40
+ mockGetChats.mockImplementation(() =>
41
+ Promise.resolve([
42
+ { chat_id: 'chat-1', name: 'General', type: 'group', member_count: 5 },
43
+ { chat_id: 'chat-2', name: 'Direct', type: 'direct', member_count: 2 },
44
+ ]),
45
+ )
46
+
47
+ consoleLogSpy = mock((..._args: unknown[]) => {}); console.log = consoleLogSpy
48
+ })
49
+
50
+ afterEach(() => {
51
+ console.log = originalConsoleLog
52
+ })
53
+
54
+ describe('list', () => {
55
+ test('lists chat rooms', async () => {
56
+ await chatCommand.parseAsync(['list'], { from: 'user' })
57
+
58
+ expect(mockGetChats).toHaveBeenCalled()
59
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
60
+ expect(output).toHaveLength(2)
61
+ expect(output[0].chat_id).toBe('chat-1')
62
+ expect(output[0].name).toBe('General')
63
+ })
64
+
65
+ test('passes --search option to getChats', async () => {
66
+ await chatCommand.parseAsync(['list', '--search', 'General'], { from: 'user' })
67
+
68
+ const call = mockGetChats.mock.calls[0][0] as { all?: boolean; search?: string }
69
+ expect(call.search).toBe('General')
70
+ })
71
+
72
+ test('passes --all flag to getChats', async () => {
73
+ await chatCommand.parseAsync(['list', '--all'], { from: 'user' })
74
+
75
+ const call = mockGetChats.mock.calls[0][0] as { all?: boolean; search?: string }
76
+ expect(call.all).toBe(true)
77
+ })
78
+
79
+ test('passes account option to withKakaoClient', async () => {
80
+ await chatCommand.parseAsync(['list', '--account', 'my-account'], { from: 'user' })
81
+
82
+ expect(mockWithKakaoClient).toHaveBeenCalledWith(
83
+ expect.objectContaining({ account: 'my-account' }),
84
+ expect.any(Function),
85
+ )
86
+ })
87
+
88
+ test('outputs empty array when no chats', async () => {
89
+ mockGetChats.mockImplementation(() => Promise.resolve([]))
90
+
91
+ await chatCommand.parseAsync(['list'], { from: 'user' })
92
+
93
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
94
+ expect(output).toEqual([])
95
+ })
96
+ })
97
+ })
@@ -1,3 +1,4 @@
1
1
  export { authCommand } from './auth'
2
2
  export { chatCommand } from './chat'
3
3
  export { messageCommand } from './message'
4
+ export { whoamiCommand } from './whoami'
@@ -0,0 +1,113 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const originalConsoleLog = console.log
4
+
5
+ const mockWithKakaoClient = mock(
6
+ async (_options: unknown, fn: (client: unknown) => Promise<unknown>) => {
7
+ return fn(mockClient)
8
+ },
9
+ )
10
+
11
+ const mockGetMessages = mock(() =>
12
+ Promise.resolve([
13
+ { log_id: '1', message: 'Hello', sender_id: 'user-1', created_at: 1000 },
14
+ ]),
15
+ )
16
+
17
+ const mockSendMessage = mock(() =>
18
+ Promise.resolve({ log_id: '2', message: 'Hi there', created_at: 2000 }),
19
+ )
20
+
21
+ const mockClient = {
22
+ getMessages: mockGetMessages,
23
+ sendMessage: mockSendMessage,
24
+ }
25
+
26
+ mock.module('./shared', () => ({
27
+ withKakaoClient: mockWithKakaoClient,
28
+ }))
29
+
30
+ import { messageCommand } from './message'
31
+
32
+ describe('message commands', () => {
33
+ let consoleLogSpy: ReturnType<typeof mock>
34
+
35
+ beforeEach(() => {
36
+ mockWithKakaoClient.mockReset()
37
+ mockGetMessages.mockReset()
38
+ mockSendMessage.mockReset()
39
+
40
+ mockWithKakaoClient.mockImplementation(
41
+ async (_options: unknown, fn: (client: unknown) => Promise<unknown>) => {
42
+ return fn(mockClient)
43
+ },
44
+ )
45
+ mockGetMessages.mockImplementation(() =>
46
+ Promise.resolve([
47
+ { log_id: '1', message: 'Hello', sender_id: 'user-1', created_at: 1000 },
48
+ ]),
49
+ )
50
+ mockSendMessage.mockImplementation(() =>
51
+ Promise.resolve({ log_id: '2', message: 'Hi there', created_at: 2000 }),
52
+ )
53
+
54
+ consoleLogSpy = mock((..._args: unknown[]) => {}); console.log = consoleLogSpy
55
+ })
56
+
57
+ afterEach(() => {
58
+ console.log = originalConsoleLog
59
+ })
60
+
61
+ describe('list', () => {
62
+ test('fetches messages for a chat room with default count', async () => {
63
+ await messageCommand.parseAsync(['list', 'chat-123', '--count', '20'], { from: 'user' })
64
+
65
+ expect(mockGetMessages).toHaveBeenCalledWith('chat-123', { count: 20, from: undefined })
66
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
67
+ expect(output).toHaveLength(1)
68
+ expect(output[0].log_id).toBe('1')
69
+ expect(output[0].message).toBe('Hello')
70
+ })
71
+
72
+ test('respects --count option', async () => {
73
+ await messageCommand.parseAsync(['list', 'chat-123', '--count', '5'], { from: 'user' })
74
+
75
+ expect(mockGetMessages).toHaveBeenCalledWith('chat-123', { count: 5, from: undefined })
76
+ })
77
+
78
+ test('respects --from option', async () => {
79
+ await messageCommand.parseAsync(['list', 'chat-123', '--count', '20', '--from', '999'], { from: 'user' })
80
+
81
+ expect(mockGetMessages).toHaveBeenCalledWith('chat-123', { count: 20, from: '999' })
82
+ })
83
+
84
+ test('passes account option to withKakaoClient', async () => {
85
+ await messageCommand.parseAsync(['list', 'chat-123', '--count', '20', '--account', 'my-account'], { from: 'user' })
86
+
87
+ expect(mockWithKakaoClient).toHaveBeenCalledWith(
88
+ expect.objectContaining({ account: 'my-account' }),
89
+ expect.any(Function),
90
+ )
91
+ })
92
+ })
93
+
94
+ describe('send', () => {
95
+ test('sends a message to a chat room', async () => {
96
+ await messageCommand.parseAsync(['send', 'chat-123', 'Hello world'], { from: 'user' })
97
+
98
+ expect(mockSendMessage).toHaveBeenCalledWith('chat-123', 'Hello world')
99
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
100
+ expect(output.log_id).toBe('2')
101
+ expect(output.message).toBe('Hi there')
102
+ })
103
+
104
+ test('passes account option to withKakaoClient', async () => {
105
+ await messageCommand.parseAsync(['send', 'chat-123', 'Hi', '--account', 'my-account'], { from: 'user' })
106
+
107
+ expect(mockWithKakaoClient).toHaveBeenCalledWith(
108
+ expect.objectContaining({ account: 'my-account' }),
109
+ expect.any(Function),
110
+ )
111
+ })
112
+ })
113
+ })
@@ -0,0 +1,116 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const originalConsoleLog = console.log
4
+
5
+ const mockWithKakaoClient = mock(
6
+ async (_options: unknown, fn: (client: unknown) => Promise<unknown>) => {
7
+ return fn(mockClient)
8
+ },
9
+ )
10
+
11
+ const mockGetProfile = mock(() =>
12
+ Promise.resolve({
13
+ user_id: 'user-1',
14
+ nickname: 'Test User',
15
+ profile_image_url: 'https://example.com/avatar.jpg',
16
+ original_profile_image_url: 'https://example.com/avatar_orig.jpg',
17
+ background_image_url: 'https://example.com/bg.jpg',
18
+ original_background_image_url: 'https://example.com/bg_orig.jpg',
19
+ fullname: 'Real Name',
20
+ status_message: 'Hello!',
21
+ account_display_id: 'testuser',
22
+ account_email: 'test@example.com',
23
+ pstn_number: '+821012345678',
24
+ email_verified: true,
25
+ }),
26
+ )
27
+
28
+ const mockClient = {
29
+ getProfile: mockGetProfile,
30
+ }
31
+
32
+ mock.module('./shared', () => ({
33
+ withKakaoClient: mockWithKakaoClient,
34
+ }))
35
+
36
+ import { whoamiCommand } from './whoami'
37
+
38
+ describe('whoami command', () => {
39
+ let consoleLogSpy: ReturnType<typeof mock>
40
+
41
+ beforeEach(() => {
42
+ mockWithKakaoClient.mockReset()
43
+ mockGetProfile.mockReset()
44
+
45
+ mockWithKakaoClient.mockImplementation(
46
+ async (_options: unknown, fn: (client: unknown) => Promise<unknown>) => {
47
+ return fn(mockClient)
48
+ },
49
+ )
50
+ mockGetProfile.mockImplementation(() =>
51
+ Promise.resolve({
52
+ user_id: 'user-1',
53
+ nickname: 'Test User',
54
+ profile_image_url: 'https://example.com/avatar.jpg',
55
+ original_profile_image_url: 'https://example.com/avatar_orig.jpg',
56
+ background_image_url: 'https://example.com/bg.jpg',
57
+ original_background_image_url: 'https://example.com/bg_orig.jpg',
58
+ fullname: 'Real Name',
59
+ status_message: 'Hello!',
60
+ account_display_id: 'testuser',
61
+ account_email: 'test@example.com',
62
+ pstn_number: '+821012345678',
63
+ email_verified: true,
64
+ }),
65
+ )
66
+
67
+ consoleLogSpy = mock((..._args: unknown[]) => {})
68
+ console.log = consoleLogSpy
69
+ })
70
+
71
+ afterEach(() => {
72
+ console.log = originalConsoleLog
73
+ })
74
+
75
+ test('outputs profile information', async () => {
76
+ await whoamiCommand.parseAsync([], { from: 'user' })
77
+
78
+ expect(mockGetProfile).toHaveBeenCalled()
79
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
80
+ expect(output.user_id).toBe('user-1')
81
+ expect(output.nickname).toBe('Test User')
82
+ expect(output.profile_image_url).toBe('https://example.com/avatar.jpg')
83
+ })
84
+
85
+ test('outputs enriched profile fields', async () => {
86
+ await whoamiCommand.parseAsync([], { from: 'user' })
87
+
88
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0])
89
+ expect(output.background_image_url).toBe('https://example.com/bg.jpg')
90
+ expect(output.original_background_image_url).toBe('https://example.com/bg_orig.jpg')
91
+ expect(output.fullname).toBe('Real Name')
92
+ expect(output.status_message).toBe('Hello!')
93
+ expect(output.account_display_id).toBe('testuser')
94
+ expect(output.account_email).toBe('test@example.com')
95
+ expect(output.pstn_number).toBe('+821012345678')
96
+ expect(output.email_verified).toBe(true)
97
+ })
98
+
99
+ test('passes account option to withKakaoClient', async () => {
100
+ await whoamiCommand.parseAsync(['--account', 'my-account'], { from: 'user' })
101
+
102
+ expect(mockWithKakaoClient).toHaveBeenCalledWith(
103
+ expect.objectContaining({ account: 'my-account' }),
104
+ expect.any(Function),
105
+ )
106
+ })
107
+
108
+ test('outputs profile with pretty flag', async () => {
109
+ await whoamiCommand.parseAsync(['--pretty'], { from: 'user' })
110
+
111
+ expect(mockGetProfile).toHaveBeenCalled()
112
+ const rawOutput = consoleLogSpy.mock.calls[0][0]
113
+ const output = JSON.parse(rawOutput)
114
+ expect(output.user_id).toBe('user-1')
115
+ })
116
+ })
@@ -0,0 +1,21 @@
1
+ import { Command } from 'commander'
2
+
3
+ import { handleError } from '@/shared/utils/error-handler'
4
+ import { formatOutput } from '@/shared/utils/output'
5
+
6
+ import { withKakaoClient } from './shared'
7
+
8
+ async function whoamiAction(options: { account?: string; pretty?: boolean }): Promise<void> {
9
+ try {
10
+ const profile = await withKakaoClient(options, (client) => client.getProfile())
11
+ console.log(formatOutput(profile, options.pretty))
12
+ } catch (error) {
13
+ handleError(error as Error)
14
+ }
15
+ }
16
+
17
+ export const whoamiCommand = new Command('whoami')
18
+ .description('Show current authenticated user')
19
+ .option('--account <id>', 'Use a specific KakaoTalk account')
20
+ .option('--pretty', 'Pretty print JSON output')
21
+ .action(whoamiAction)
@@ -12,6 +12,7 @@ import {
12
12
  KakaoTalkListener,
13
13
  KakaoTalkPushMemberEventSchema,
14
14
  KakaoTalkPushMessageEventSchema,
15
+ KakaoProfileSchema,
15
16
  KakaoTalkPushReadEventSchema,
16
17
  } from '@/platforms/kakaotalk/index'
17
18
 
@@ -66,3 +67,7 @@ test('KakaoTalkPushMemberEventSchema is exported from barrel', () => {
66
67
  test('KakaoTalkPushReadEventSchema is exported from barrel', () => {
67
68
  expect(typeof KakaoTalkPushReadEventSchema.parse).toBe('function')
68
69
  })
70
+
71
+ test('KakaoProfileSchema is exported from barrel', () => {
72
+ expect(typeof KakaoProfileSchema.parse).toBe('function')
73
+ })
@@ -8,6 +8,7 @@ export type {
8
8
  KakaoConfig,
9
9
  KakaoDeviceType,
10
10
  KakaoMessage,
11
+ KakaoProfile,
11
12
  KakaoSendResult,
12
13
  KakaoTalkListenerEventMap,
13
14
  KakaoTalkPushEvent,
@@ -21,6 +22,7 @@ export {
21
22
  KakaoChatSchema,
22
23
  KakaoConfigSchema,
23
24
  KakaoMessageSchema,
25
+ KakaoProfileSchema,
24
26
  KakaoSendResultSchema,
25
27
  KakaoTalkPushMemberEventSchema,
26
28
  KakaoTalkPushMessageEventSchema,