agent-messenger 2.4.0 → 2.6.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 (359) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.github/workflows/ci.yml +35 -0
  3. package/.github/workflows/release.yml +0 -12
  4. package/README.md +3 -3
  5. package/bun.lock +10 -2
  6. package/dist/package.json +3 -1
  7. package/dist/src/platforms/channeltalk/cli.d.ts.map +1 -1
  8. package/dist/src/platforms/channeltalk/cli.js +2 -1
  9. package/dist/src/platforms/channeltalk/cli.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/commands/index.d.ts +1 -0
  11. package/dist/src/platforms/channeltalk/commands/index.d.ts.map +1 -1
  12. package/dist/src/platforms/channeltalk/commands/index.js +1 -0
  13. package/dist/src/platforms/channeltalk/commands/index.js.map +1 -1
  14. package/dist/src/platforms/channeltalk/commands/whoami.d.ts +22 -0
  15. package/dist/src/platforms/channeltalk/commands/whoami.d.ts.map +1 -0
  16. package/dist/src/platforms/channeltalk/commands/whoami.js +40 -0
  17. package/dist/src/platforms/channeltalk/commands/whoami.js.map +1 -0
  18. package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
  19. package/dist/src/platforms/channeltalkbot/cli.js +2 -1
  20. package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
  21. package/dist/src/platforms/channeltalkbot/commands/index.d.ts +1 -0
  22. package/dist/src/platforms/channeltalkbot/commands/index.d.ts.map +1 -1
  23. package/dist/src/platforms/channeltalkbot/commands/index.js +1 -0
  24. package/dist/src/platforms/channeltalkbot/commands/index.js.map +1 -1
  25. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts +13 -0
  26. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -0
  27. package/dist/src/platforms/channeltalkbot/commands/whoami.js +31 -0
  28. package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -0
  29. package/dist/src/platforms/discord/cli.d.ts.map +1 -1
  30. package/dist/src/platforms/discord/cli.js +2 -1
  31. package/dist/src/platforms/discord/cli.js.map +1 -1
  32. package/dist/src/platforms/discord/commands/index.d.ts +1 -0
  33. package/dist/src/platforms/discord/commands/index.d.ts.map +1 -1
  34. package/dist/src/platforms/discord/commands/index.js +1 -0
  35. package/dist/src/platforms/discord/commands/index.js.map +1 -1
  36. package/dist/src/platforms/discord/commands/whoami.d.ts +6 -0
  37. package/dist/src/platforms/discord/commands/whoami.d.ts.map +1 -0
  38. package/dist/src/platforms/discord/commands/whoami.js +33 -0
  39. package/dist/src/platforms/discord/commands/whoami.js.map +1 -0
  40. package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
  41. package/dist/src/platforms/discordbot/cli.js +2 -1
  42. package/dist/src/platforms/discordbot/cli.js.map +1 -1
  43. package/dist/src/platforms/discordbot/commands/index.d.ts +1 -0
  44. package/dist/src/platforms/discordbot/commands/index.d.ts.map +1 -1
  45. package/dist/src/platforms/discordbot/commands/index.js +1 -0
  46. package/dist/src/platforms/discordbot/commands/index.js.map +1 -1
  47. package/dist/src/platforms/discordbot/commands/whoami.d.ts +14 -0
  48. package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -0
  49. package/dist/src/platforms/discordbot/commands/whoami.js +32 -0
  50. package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -0
  51. package/dist/src/platforms/instagram/cli.d.ts.map +1 -1
  52. package/dist/src/platforms/instagram/cli.js +2 -1
  53. package/dist/src/platforms/instagram/cli.js.map +1 -1
  54. package/dist/src/platforms/instagram/client.d.ts +6 -0
  55. package/dist/src/platforms/instagram/client.d.ts.map +1 -1
  56. package/dist/src/platforms/instagram/client.js +12 -0
  57. package/dist/src/platforms/instagram/client.js.map +1 -1
  58. package/dist/src/platforms/instagram/commands/index.d.ts +1 -0
  59. package/dist/src/platforms/instagram/commands/index.d.ts.map +1 -1
  60. package/dist/src/platforms/instagram/commands/index.js +1 -0
  61. package/dist/src/platforms/instagram/commands/index.js.map +1 -1
  62. package/dist/src/platforms/instagram/commands/whoami.d.ts +7 -0
  63. package/dist/src/platforms/instagram/commands/whoami.d.ts.map +1 -0
  64. package/dist/src/platforms/instagram/commands/whoami.js +19 -0
  65. package/dist/src/platforms/instagram/commands/whoami.js.map +1 -0
  66. package/dist/src/platforms/kakaotalk/cli.js +2 -2
  67. package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
  68. package/dist/src/platforms/kakaotalk/client.d.ts +4 -1
  69. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  70. package/dist/src/platforms/kakaotalk/client.js +193 -27
  71. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  72. package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
  73. package/dist/src/platforms/kakaotalk/commands/auth.js +24 -55
  74. package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
  75. package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -1
  76. package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
  77. package/dist/src/platforms/kakaotalk/commands/index.js +1 -1
  78. package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
  79. package/dist/src/platforms/kakaotalk/commands/whoami.d.ts +3 -0
  80. package/dist/src/platforms/kakaotalk/commands/whoami.d.ts.map +1 -0
  81. package/dist/src/platforms/kakaotalk/commands/{profile.js → whoami.js} +5 -5
  82. package/dist/src/platforms/kakaotalk/commands/whoami.js.map +1 -0
  83. package/dist/src/platforms/kakaotalk/credential-manager.d.ts.map +1 -1
  84. package/dist/src/platforms/kakaotalk/credential-manager.js +1 -0
  85. package/dist/src/platforms/kakaotalk/credential-manager.js.map +1 -1
  86. package/dist/src/platforms/kakaotalk/index.d.ts +1 -1
  87. package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
  88. package/dist/src/platforms/kakaotalk/index.js.map +1 -1
  89. package/dist/src/platforms/kakaotalk/listener.js +2 -2
  90. package/dist/src/platforms/kakaotalk/listener.js.map +1 -1
  91. package/dist/src/platforms/kakaotalk/protocol/config.d.ts +8 -2
  92. package/dist/src/platforms/kakaotalk/protocol/config.d.ts.map +1 -1
  93. package/dist/src/platforms/kakaotalk/protocol/config.js +15 -2
  94. package/dist/src/platforms/kakaotalk/protocol/config.js.map +1 -1
  95. package/dist/src/platforms/kakaotalk/protocol/session.d.ts +6 -2
  96. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  97. package/dist/src/platforms/kakaotalk/protocol/session.js +37 -15
  98. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  99. package/dist/src/platforms/kakaotalk/protocol/types.d.ts +17 -0
  100. package/dist/src/platforms/kakaotalk/protocol/types.d.ts.map +1 -1
  101. package/dist/src/platforms/kakaotalk/protocol/types.js.map +1 -1
  102. package/dist/src/platforms/kakaotalk/types.d.ts +22 -0
  103. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  104. package/dist/src/platforms/kakaotalk/types.js +7 -0
  105. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  106. package/dist/src/platforms/line/cli.js +2 -2
  107. package/dist/src/platforms/line/cli.js.map +1 -1
  108. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  109. package/dist/src/platforms/line/commands/auth.js +9 -59
  110. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  111. package/dist/src/platforms/line/commands/index.d.ts +1 -1
  112. package/dist/src/platforms/line/commands/index.d.ts.map +1 -1
  113. package/dist/src/platforms/line/commands/index.js +1 -1
  114. package/dist/src/platforms/line/commands/index.js.map +1 -1
  115. package/dist/src/platforms/line/commands/whoami.d.ts +3 -0
  116. package/dist/src/platforms/line/commands/whoami.d.ts.map +1 -0
  117. package/dist/src/platforms/line/commands/{profile.js → whoami.js} +5 -5
  118. package/dist/src/platforms/line/commands/whoami.js.map +1 -0
  119. package/dist/src/platforms/slack/cli.d.ts.map +1 -1
  120. package/dist/src/platforms/slack/cli.js +2 -1
  121. package/dist/src/platforms/slack/cli.js.map +1 -1
  122. package/dist/src/platforms/slack/commands/index.d.ts +1 -0
  123. package/dist/src/platforms/slack/commands/index.d.ts.map +1 -1
  124. package/dist/src/platforms/slack/commands/index.js +1 -0
  125. package/dist/src/platforms/slack/commands/index.js.map +1 -1
  126. package/dist/src/platforms/slack/commands/whoami.d.ts +6 -0
  127. package/dist/src/platforms/slack/commands/whoami.d.ts.map +1 -0
  128. package/dist/src/platforms/slack/commands/whoami.js +39 -0
  129. package/dist/src/platforms/slack/commands/whoami.js.map +1 -0
  130. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  131. package/dist/src/platforms/slackbot/cli.js +2 -1
  132. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  133. package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
  134. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
  135. package/dist/src/platforms/slackbot/commands/index.js +1 -0
  136. package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
  137. package/dist/src/platforms/slackbot/commands/whoami.d.ts +14 -0
  138. package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -0
  139. package/dist/src/platforms/slackbot/commands/whoami.js +32 -0
  140. package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -0
  141. package/dist/src/platforms/teams/cli.d.ts.map +1 -1
  142. package/dist/src/platforms/teams/cli.js +2 -1
  143. package/dist/src/platforms/teams/cli.js.map +1 -1
  144. package/dist/src/platforms/teams/commands/index.d.ts +1 -0
  145. package/dist/src/platforms/teams/commands/index.d.ts.map +1 -1
  146. package/dist/src/platforms/teams/commands/index.js +1 -0
  147. package/dist/src/platforms/teams/commands/index.js.map +1 -1
  148. package/dist/src/platforms/teams/commands/whoami.d.ts +6 -0
  149. package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -0
  150. package/dist/src/platforms/teams/commands/whoami.js +30 -0
  151. package/dist/src/platforms/teams/commands/whoami.js.map +1 -0
  152. package/dist/src/platforms/telegram/cli.d.ts.map +1 -1
  153. package/dist/src/platforms/telegram/cli.js +2 -1
  154. package/dist/src/platforms/telegram/cli.js.map +1 -1
  155. package/dist/src/platforms/telegram/commands/index.d.ts +1 -0
  156. package/dist/src/platforms/telegram/commands/index.d.ts.map +1 -1
  157. package/dist/src/platforms/telegram/commands/index.js +1 -0
  158. package/dist/src/platforms/telegram/commands/index.js.map +1 -1
  159. package/dist/src/platforms/telegram/commands/whoami.d.ts +7 -0
  160. package/dist/src/platforms/telegram/commands/whoami.d.ts.map +1 -0
  161. package/dist/src/platforms/telegram/commands/whoami.js +27 -0
  162. package/dist/src/platforms/telegram/commands/whoami.js.map +1 -0
  163. package/dist/src/platforms/webex/cli.d.ts.map +1 -1
  164. package/dist/src/platforms/webex/cli.js +2 -1
  165. package/dist/src/platforms/webex/cli.js.map +1 -1
  166. package/dist/src/platforms/webex/commands/index.d.ts +1 -0
  167. package/dist/src/platforms/webex/commands/index.d.ts.map +1 -1
  168. package/dist/src/platforms/webex/commands/index.js +1 -0
  169. package/dist/src/platforms/webex/commands/index.js.map +1 -1
  170. package/dist/src/platforms/webex/commands/message.js +1 -1
  171. package/dist/src/platforms/webex/commands/message.js.map +1 -1
  172. package/dist/src/platforms/webex/commands/whoami.d.ts +6 -0
  173. package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -0
  174. package/dist/src/platforms/webex/commands/whoami.js +30 -0
  175. package/dist/src/platforms/webex/commands/whoami.js.map +1 -0
  176. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
  177. package/dist/src/platforms/wechatbot/cli.js +2 -1
  178. package/dist/src/platforms/wechatbot/cli.js.map +1 -1
  179. package/dist/src/platforms/wechatbot/commands/index.d.ts +1 -0
  180. package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -1
  181. package/dist/src/platforms/wechatbot/commands/index.js +1 -0
  182. package/dist/src/platforms/wechatbot/commands/index.js.map +1 -1
  183. package/dist/src/platforms/wechatbot/commands/whoami.d.ts +12 -0
  184. package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -0
  185. package/dist/src/platforms/wechatbot/commands/whoami.js +33 -0
  186. package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -0
  187. package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
  188. package/dist/src/platforms/whatsapp/cli.js +2 -1
  189. package/dist/src/platforms/whatsapp/cli.js.map +1 -1
  190. package/dist/src/platforms/whatsapp/client.d.ts +8 -0
  191. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  192. package/dist/src/platforms/whatsapp/client.js +116 -8
  193. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  194. package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
  195. package/dist/src/platforms/whatsapp/commands/auth.js +115 -45
  196. package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
  197. package/dist/src/platforms/whatsapp/commands/index.d.ts +1 -0
  198. package/dist/src/platforms/whatsapp/commands/index.d.ts.map +1 -1
  199. package/dist/src/platforms/whatsapp/commands/index.js +1 -0
  200. package/dist/src/platforms/whatsapp/commands/index.js.map +1 -1
  201. package/dist/src/platforms/whatsapp/commands/shared.js +2 -2
  202. package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
  203. package/dist/src/platforms/whatsapp/commands/whoami.d.ts +7 -0
  204. package/dist/src/platforms/whatsapp/commands/whoami.d.ts.map +1 -0
  205. package/dist/src/platforms/whatsapp/commands/whoami.js +19 -0
  206. package/dist/src/platforms/whatsapp/commands/whoami.js.map +1 -0
  207. package/dist/src/platforms/whatsapp/ensure-auth.js +2 -2
  208. package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
  209. package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
  210. package/dist/src/platforms/whatsappbot/cli.js +2 -1
  211. package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
  212. package/dist/src/platforms/whatsappbot/commands/index.d.ts +1 -0
  213. package/dist/src/platforms/whatsappbot/commands/index.d.ts.map +1 -1
  214. package/dist/src/platforms/whatsappbot/commands/index.js +1 -0
  215. package/dist/src/platforms/whatsappbot/commands/index.js.map +1 -1
  216. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts +17 -0
  217. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -0
  218. package/dist/src/platforms/whatsappbot/commands/whoami.js +39 -0
  219. package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -0
  220. package/dist/src/shared/utils/qr.d.ts +15 -0
  221. package/dist/src/shared/utils/qr.d.ts.map +1 -0
  222. package/dist/src/shared/utils/qr.js +74 -0
  223. package/dist/src/shared/utils/qr.js.map +1 -0
  224. package/dist/src/tui/adapters/kakaotalk-adapter.d.ts.map +1 -1
  225. package/dist/src/tui/adapters/kakaotalk-adapter.js +5 -2
  226. package/dist/src/tui/adapters/kakaotalk-adapter.js.map +1 -1
  227. package/dist/src/tui/adapters/whatsapp-adapter.d.ts.map +1 -1
  228. package/dist/src/tui/adapters/whatsapp-adapter.js +20 -15
  229. package/dist/src/tui/adapters/whatsapp-adapter.js.map +1 -1
  230. package/docs/content/docs/cli/channeltalk.mdx +11 -0
  231. package/docs/content/docs/cli/channeltalkbot.mdx +9 -0
  232. package/docs/content/docs/cli/discord.mdx +10 -0
  233. package/docs/content/docs/cli/discordbot.mdx +9 -0
  234. package/docs/content/docs/cli/instagram.mdx +11 -0
  235. package/docs/content/docs/cli/kakaotalk.mdx +27 -39
  236. package/docs/content/docs/cli/line.mdx +4 -4
  237. package/docs/content/docs/cli/slack.mdx +10 -0
  238. package/docs/content/docs/cli/slackbot.mdx +9 -0
  239. package/docs/content/docs/cli/teams.mdx +10 -0
  240. package/docs/content/docs/cli/telegram.mdx +11 -0
  241. package/docs/content/docs/cli/webex.mdx +10 -0
  242. package/docs/content/docs/cli/wechatbot.mdx +9 -0
  243. package/docs/content/docs/cli/whatsapp.mdx +36 -7
  244. package/docs/content/docs/cli/whatsappbot.mdx +9 -0
  245. package/e2e/config.ts +1 -1
  246. package/package.json +3 -1
  247. package/skills/agent-channeltalk/SKILL.md +12 -1
  248. package/skills/agent-channeltalkbot/SKILL.md +10 -1
  249. package/skills/agent-discord/SKILL.md +11 -1
  250. package/skills/agent-discordbot/SKILL.md +10 -1
  251. package/skills/agent-instagram/SKILL.md +12 -1
  252. package/skills/agent-kakaotalk/SKILL.md +24 -70
  253. package/skills/agent-kakaotalk/references/authentication.md +4 -69
  254. package/skills/agent-kakaotalk/references/common-patterns.md +14 -1
  255. package/skills/agent-line/SKILL.md +5 -5
  256. package/skills/agent-slack/SKILL.md +11 -1
  257. package/skills/agent-slackbot/SKILL.md +10 -1
  258. package/skills/agent-teams/SKILL.md +11 -1
  259. package/skills/agent-telegram/SKILL.md +6 -1
  260. package/skills/agent-webex/SKILL.md +11 -1
  261. package/skills/agent-wechatbot/SKILL.md +10 -1
  262. package/skills/agent-whatsapp/SKILL.md +52 -15
  263. package/skills/agent-whatsapp/references/authentication.md +36 -6
  264. package/skills/agent-whatsappbot/SKILL.md +10 -1
  265. package/src/platforms/channeltalk/cli.ts +2 -0
  266. package/src/platforms/channeltalk/commands/index.ts +1 -0
  267. package/src/platforms/channeltalk/commands/whoami.test.ts +64 -0
  268. package/src/platforms/channeltalk/commands/whoami.ts +62 -0
  269. package/src/platforms/channeltalkbot/cli.ts +2 -0
  270. package/src/platforms/channeltalkbot/commands/index.ts +1 -0
  271. package/src/platforms/channeltalkbot/commands/whoami.test.ts +104 -0
  272. package/src/platforms/channeltalkbot/commands/whoami.ts +42 -0
  273. package/src/platforms/discord/cli.ts +2 -0
  274. package/src/platforms/discord/commands/index.ts +1 -0
  275. package/src/platforms/discord/commands/whoami.test.ts +91 -0
  276. package/src/platforms/discord/commands/whoami.ts +36 -0
  277. package/src/platforms/discordbot/cli.ts +2 -0
  278. package/src/platforms/discordbot/commands/index.ts +1 -0
  279. package/src/platforms/discordbot/commands/whoami.test.ts +96 -0
  280. package/src/platforms/discordbot/commands/whoami.ts +44 -0
  281. package/src/platforms/instagram/cli.ts +2 -1
  282. package/src/platforms/instagram/client.ts +13 -0
  283. package/src/platforms/instagram/commands/chat.test.ts +1 -5
  284. package/src/platforms/instagram/commands/index.ts +1 -0
  285. package/src/platforms/instagram/commands/message.test.ts +1 -5
  286. package/src/platforms/instagram/commands/whoami.test.ts +60 -0
  287. package/src/platforms/instagram/commands/whoami.ts +21 -0
  288. package/src/platforms/kakaotalk/cli.ts +2 -2
  289. package/src/platforms/kakaotalk/client.test.ts +25 -14
  290. package/src/platforms/kakaotalk/client.ts +228 -33
  291. package/src/platforms/kakaotalk/commands/auth.ts +22 -73
  292. package/src/platforms/kakaotalk/commands/index.ts +1 -1
  293. package/src/platforms/kakaotalk/commands/{profile.test.ts → whoami.test.ts} +37 -5
  294. package/src/platforms/kakaotalk/commands/{profile.ts → whoami.ts} +4 -4
  295. package/src/platforms/kakaotalk/credential-manager.ts +1 -0
  296. package/src/platforms/kakaotalk/index.ts +1 -0
  297. package/src/platforms/kakaotalk/listener.test.ts +2 -2
  298. package/src/platforms/kakaotalk/listener.ts +2 -2
  299. package/src/platforms/kakaotalk/protocol/config.ts +26 -2
  300. package/src/platforms/kakaotalk/protocol/session.ts +42 -16
  301. package/src/platforms/kakaotalk/protocol/types.ts +9 -0
  302. package/src/platforms/kakaotalk/types.ts +16 -0
  303. package/src/platforms/line/cli.ts +2 -2
  304. package/src/platforms/line/commands/auth.ts +37 -70
  305. package/src/platforms/line/commands/index.ts +1 -1
  306. package/src/platforms/line/commands/{profile.test.ts → whoami.test.ts} +11 -11
  307. package/src/platforms/line/commands/{profile.ts → whoami.ts} +4 -4
  308. package/src/platforms/slack/cli.ts +2 -0
  309. package/src/platforms/slack/commands/index.ts +1 -0
  310. package/src/platforms/slack/commands/whoami.test.ts +126 -0
  311. package/src/platforms/slack/commands/whoami.ts +40 -0
  312. package/src/platforms/slackbot/cli.ts +2 -1
  313. package/src/platforms/slackbot/commands/index.ts +1 -0
  314. package/src/platforms/slackbot/commands/whoami.test.ts +102 -0
  315. package/src/platforms/slackbot/commands/whoami.ts +44 -0
  316. package/src/platforms/teams/cli.ts +2 -0
  317. package/src/platforms/teams/commands/index.ts +1 -0
  318. package/src/platforms/teams/commands/whoami.test.ts +83 -0
  319. package/src/platforms/teams/commands/whoami.ts +33 -0
  320. package/src/platforms/telegram/cli.ts +2 -1
  321. package/src/platforms/telegram/commands/index.ts +1 -0
  322. package/src/platforms/telegram/commands/whoami.test.ts +75 -0
  323. package/src/platforms/telegram/commands/whoami.ts +29 -0
  324. package/src/platforms/webex/cli.ts +2 -1
  325. package/src/platforms/webex/commands/auth.test.ts +58 -46
  326. package/src/platforms/webex/commands/index.ts +1 -0
  327. package/src/platforms/webex/commands/member.test.ts +1 -5
  328. package/src/platforms/webex/commands/message.test.ts +1 -5
  329. package/src/platforms/webex/commands/message.ts +1 -1
  330. package/src/platforms/webex/commands/snapshot.test.ts +1 -5
  331. package/src/platforms/webex/commands/space.test.ts +1 -5
  332. package/src/platforms/webex/commands/whoami.test.ts +113 -0
  333. package/src/platforms/webex/commands/whoami.ts +31 -0
  334. package/src/platforms/webex/credential-manager.test.ts +0 -1
  335. package/src/platforms/wechatbot/cli.ts +2 -1
  336. package/src/platforms/wechatbot/commands/index.ts +1 -0
  337. package/src/platforms/wechatbot/commands/whoami.test.ts +109 -0
  338. package/src/platforms/wechatbot/commands/whoami.ts +43 -0
  339. package/src/platforms/whatsapp/cli.ts +2 -1
  340. package/src/platforms/whatsapp/client.ts +156 -24
  341. package/src/platforms/whatsapp/commands/auth.ts +176 -70
  342. package/src/platforms/whatsapp/commands/index.ts +1 -0
  343. package/src/platforms/whatsapp/commands/shared.ts +2 -2
  344. package/src/platforms/whatsapp/commands/whoami.test.ts +59 -0
  345. package/src/platforms/whatsapp/commands/whoami.ts +21 -0
  346. package/src/platforms/whatsapp/ensure-auth.ts +2 -2
  347. package/src/platforms/whatsappbot/cli.ts +2 -1
  348. package/src/platforms/whatsappbot/commands/index.ts +1 -0
  349. package/src/platforms/whatsappbot/commands/whoami.test.ts +100 -0
  350. package/src/platforms/whatsappbot/commands/whoami.ts +57 -0
  351. package/src/shared/utils/qr.ts +92 -0
  352. package/src/tui/adapters/kakaotalk-adapter.ts +5 -2
  353. package/src/tui/adapters/whatsapp-adapter.ts +19 -16
  354. package/dist/src/platforms/kakaotalk/commands/profile.d.ts +0 -3
  355. package/dist/src/platforms/kakaotalk/commands/profile.d.ts.map +0 -1
  356. package/dist/src/platforms/kakaotalk/commands/profile.js.map +0 -1
  357. package/dist/src/platforms/line/commands/profile.d.ts +0 -3
  358. package/dist/src/platforms/line/commands/profile.d.ts.map +0 -1
  359. package/dist/src/platforms/line/commands/profile.js.map +0 -1
@@ -5,7 +5,7 @@ import type { Command as CommandType } from 'commander'
5
5
  import { Command } from 'commander'
6
6
 
7
7
  import pkg from '../../../package.json' with { type: 'json' }
8
- import { authCommand, chatCommand, messageCommand } from './commands/index'
8
+ import { authCommand, chatCommand, messageCommand, whoamiCommand } from './commands/index'
9
9
  import { ensureWhatsAppAuth } from './ensure-auth'
10
10
 
11
11
  function isAuthCommand(command: CommandType): boolean {
@@ -32,6 +32,7 @@ program.hook('preAction', async (_thisCommand, actionCommand) => {
32
32
  program.addCommand(authCommand)
33
33
  program.addCommand(chatCommand)
34
34
  program.addCommand(messageCommand)
35
+ program.addCommand(whoamiCommand)
35
36
 
36
37
  program.parse(process.argv)
37
38
 
@@ -1,6 +1,8 @@
1
1
  import { existsSync } from 'node:fs'
2
2
  import { readFile, writeFile } from 'node:fs/promises'
3
3
  import { join } from 'node:path'
4
+
5
+ import { Boom } from '@hapi/boom'
4
6
  import makeWASocket, {
5
7
  DisconnectReason,
6
8
  fetchLatestBaileysVersion,
@@ -12,8 +14,8 @@ import makeWASocket, {
12
14
  type WAMessage,
13
15
  type WASocket,
14
16
  } from '@whiskeysockets/baileys'
15
- import { Boom } from '@hapi/boom'
16
17
  import pino from 'pino'
18
+
17
19
  import {
18
20
  extractMessageText,
19
21
  getMessageType,
@@ -28,7 +30,12 @@ const MAX_MESSAGES_PER_CHAT = 500
28
30
  function toTimestampMs(ts: unknown): number {
29
31
  if (ts == null) return 0
30
32
  if (typeof ts === 'number') return ts * 1000
31
- if (typeof ts === 'object' && ts !== null && 'toNumber' in ts && typeof (ts as Record<string, unknown>).toNumber === 'function') {
33
+ if (
34
+ typeof ts === 'object' &&
35
+ ts !== null &&
36
+ 'toNumber' in ts &&
37
+ typeof (ts as Record<string, unknown>).toNumber === 'function'
38
+ ) {
32
39
  return (ts as { toNumber(): number }).toNumber() * 1000
33
40
  }
34
41
  const n = Number(ts)
@@ -44,11 +51,7 @@ function resolveJid(input: string): string {
44
51
  function summarizeMessage(msg: WAMessage): WhatsAppMessageSummary {
45
52
  const jid = msg.key.remoteJid ?? ''
46
53
  const isGroup = jid.endsWith('@g.us')
47
- const from = msg.key.fromMe
48
- ? ''
49
- : isGroup
50
- ? (msg.key.participant ?? msg.participant ?? jid)
51
- : jid
54
+ const from = msg.key.fromMe ? '' : isGroup ? (msg.key.participant ?? msg.participant ?? jid) : jid
52
55
 
53
56
  return {
54
57
  id: msg.key.id ?? '',
@@ -62,10 +65,7 @@ function summarizeMessage(msg: WAMessage): WhatsAppMessageSummary {
62
65
  }
63
66
  }
64
67
 
65
- function summarizeChat(
66
- chat: Chat,
67
- lastMessage?: WhatsAppMessageSummary,
68
- ): WhatsAppChatSummary {
68
+ function summarizeChat(chat: Chat, lastMessage?: WhatsAppMessageSummary): WhatsAppChatSummary {
69
69
  const id = chat.id ?? ''
70
70
  return {
71
71
  id,
@@ -106,7 +106,7 @@ export class WhatsAppClient {
106
106
  const account = await manager.getAccount()
107
107
  if (!account) {
108
108
  throw new WhatsAppError(
109
- 'No WhatsApp credentials found. Run "agent-whatsapp auth login --phone <phone-number>" first.',
109
+ 'No WhatsApp credentials found. Run "agent-whatsapp auth login --qr" or "agent-whatsapp auth login --phone <phone-number>" first.',
110
110
  'no_credentials',
111
111
  )
112
112
  }
@@ -226,10 +226,12 @@ export class WhatsAppClient {
226
226
  retries++
227
227
  if (retries > MAX_RETRIES) {
228
228
  clearTimeout(timeout)
229
- outerReject(new WhatsAppError(
230
- `Connection failed after ${MAX_RETRIES} retries: ${lastDisconnect?.error?.message ?? 'unknown'}`,
231
- 'max_retries',
232
- ))
229
+ outerReject(
230
+ new WhatsAppError(
231
+ `Connection failed after ${MAX_RETRIES} retries: ${lastDisconnect?.error?.message ?? 'unknown'}`,
232
+ 'max_retries',
233
+ ),
234
+ )
233
235
  return
234
236
  }
235
237
 
@@ -326,10 +328,12 @@ export class WhatsAppClient {
326
328
  retries++
327
329
  if (retries > MAX_RETRIES) {
328
330
  clearTimeout(overallTimeout)
329
- outerReject(new WhatsAppError(
330
- `Connection failed after ${MAX_RETRIES} retries: ${lastDisconnect?.error?.message ?? 'unknown'}`,
331
- 'max_retries',
332
- ))
331
+ outerReject(
332
+ new WhatsAppError(
333
+ `Connection failed after ${MAX_RETRIES} retries: ${lastDisconnect?.error?.message ?? 'unknown'}`,
334
+ 'max_retries',
335
+ ),
336
+ )
333
337
  return
334
338
  }
335
339
 
@@ -362,8 +366,120 @@ export class WhatsAppClient {
362
366
  })
363
367
  }
364
368
 
369
+ async connectForQR(onQR: (qr: string) => void | Promise<void>): Promise<{ waitForAuth: () => Promise<void> }> {
370
+ this.ensureAuth()
371
+ this.pendingPromise = new Promise<void>((resolve) => {
372
+ this.pendingResolve = resolve
373
+ })
374
+
375
+ const authCompletePromise = new Promise<void>((resolve, reject) => {
376
+ this.authCompleteResolve = resolve
377
+ this.authCompleteReject = reject
378
+ })
379
+
380
+ const MAX_RETRIES = 5
381
+ let retries = 0
382
+
383
+ return new Promise((outerResolve, outerReject) => {
384
+ let qrEmitted = false
385
+
386
+ const overallTimeout = setTimeout(() => {
387
+ const err = new WhatsAppError('QR auth timed out', 'qr_timeout')
388
+ if (qrEmitted) {
389
+ this.authCompleteReject?.(err)
390
+ } else {
391
+ outerReject(err)
392
+ }
393
+ }, 120_000)
394
+
395
+ const onError = (err: unknown): void => {
396
+ clearTimeout(overallTimeout)
397
+ const error = err instanceof Error ? err : new WhatsAppError(String(err), 'qr_error')
398
+ if (qrEmitted) {
399
+ this.authCompleteReject?.(error)
400
+ } else {
401
+ outerReject(error)
402
+ }
403
+ }
404
+
405
+ const attempt = async (): Promise<void> => {
406
+ const { sock, saveCreds } = await this.createSocket()
407
+ this.setupBufferListeners(sock, saveCreds)
408
+
409
+ sock.ev.on('connection.update', async (update: Partial<ConnectionState>) => {
410
+ const { connection, lastDisconnect, qr } = update
411
+
412
+ if (qr) {
413
+ try {
414
+ await onQR(qr)
415
+ } catch (err) {
416
+ onError(err)
417
+ return
418
+ }
419
+ if (!qrEmitted) {
420
+ qrEmitted = true
421
+ outerResolve({ waitForAuth: () => authCompletePromise })
422
+ }
423
+ }
424
+
425
+ if (connection === 'open') {
426
+ clearTimeout(overallTimeout)
427
+ this.authCompleteResolve?.()
428
+ if (!qrEmitted) {
429
+ qrEmitted = true
430
+ outerResolve({ waitForAuth: async () => {} })
431
+ }
432
+ }
433
+
434
+ if (connection === 'close') {
435
+ this.cleanupSocket(sock)
436
+
437
+ const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
438
+
439
+ if (statusCode === DisconnectReason.forbidden) {
440
+ clearTimeout(overallTimeout)
441
+ const err = new WhatsAppError('Account banned or restricted.', 'forbidden')
442
+ if (qrEmitted) {
443
+ this.authCompleteReject?.(err)
444
+ } else {
445
+ outerReject(err)
446
+ }
447
+ return
448
+ }
449
+
450
+ if (qrEmitted) {
451
+ // Post-QR scan: keep reconnecting until auth completes
452
+ setTimeout(() => attempt().catch(onError), 2000)
453
+ return
454
+ }
455
+
456
+ retries++
457
+ if (retries > MAX_RETRIES) {
458
+ clearTimeout(overallTimeout)
459
+ outerReject(
460
+ new WhatsAppError(
461
+ `Connection failed after ${MAX_RETRIES} retries: ${lastDisconnect?.error?.message ?? 'unknown'}`,
462
+ 'max_retries',
463
+ ),
464
+ )
465
+ return
466
+ }
467
+
468
+ setTimeout(() => attempt().catch(onError), 1000)
469
+ }
470
+ })
471
+ }
472
+
473
+ attempt().catch(onError)
474
+ })
475
+ }
476
+
365
477
  private cleanupSocket(sock: WASocket): void {
366
- try { sock.end(undefined) } catch { /* already closed */ }
478
+ try {
479
+ sock.end(undefined)
480
+ } catch {
481
+ /* already closed */
482
+ }
367
483
  }
368
484
 
369
485
  private setupBufferListeners(sock: WASocket, saveCreds: () => Promise<void>): void {
@@ -475,9 +591,7 @@ export class WhatsAppClient {
475
591
  async searchChats(query: string, limit?: number): Promise<WhatsAppChatSummary[]> {
476
592
  const allChats = await this.listChats()
477
593
  const lower = query.toLowerCase()
478
- const filtered = allChats.filter((c) =>
479
- c.name.toLowerCase().includes(lower) || c.id.toLowerCase().includes(lower),
480
- )
594
+ const filtered = allChats.filter((c) => c.name.toLowerCase().includes(lower) || c.id.toLowerCase().includes(lower))
481
595
  return limit ? filtered.slice(0, limit) : filtered
482
596
  }
483
597
 
@@ -515,6 +629,24 @@ export class WhatsAppClient {
515
629
  return summarizeMessage(result)
516
630
  }
517
631
 
632
+ async getProfile(): Promise<{ id: string; name: string | null; phone_number: string | null }> {
633
+ this.ensureAuth()
634
+ if (!this.sock) {
635
+ throw new WhatsAppError('Not connected. Call connect() first.', 'not_connected')
636
+ }
637
+ const user = this.sock.user
638
+ if (!user) {
639
+ throw new WhatsAppError('Not connected. Call connect() first.', 'not_connected')
640
+ }
641
+ const jid = user.id ?? ''
642
+ const phone = jid.includes(':') ? jid.split(':')[0] : jid.split('@')[0]
643
+ return {
644
+ id: jid,
645
+ name: user.name ?? null,
646
+ phone_number: phone || null,
647
+ }
648
+ }
649
+
518
650
  getSocket(): WASocket | null {
519
651
  return this.sock
520
652
  }
@@ -1,13 +1,19 @@
1
1
  import { rm } from 'node:fs/promises'
2
+
2
3
  import { Command } from 'commander'
4
+
3
5
  import { handleError } from '@/shared/utils/error-handler'
4
6
  import { formatOutput } from '@/shared/utils/output'
7
+ import { displayQR } from '@/shared/utils/qr'
8
+ import { info } from '@/shared/utils/stderr'
9
+
5
10
  import { WhatsAppClient } from '../client'
6
11
  import { WhatsAppCredentialManager } from '../credential-manager'
7
12
  import { createAccountId } from '../types'
8
13
 
9
14
  interface LoginOptions {
10
- phone: string
15
+ phone?: string
16
+ qr?: boolean
11
17
  pretty?: boolean
12
18
  }
13
19
 
@@ -16,58 +22,145 @@ interface StatusOptions {
16
22
  pretty?: boolean
17
23
  }
18
24
 
19
- async function loginAction(options: LoginOptions): Promise<void> {
25
+ function isInteractiveSession(): boolean {
26
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY)
27
+ }
28
+
29
+ async function loginWithPairingCode(options: LoginOptions & { phone: string }): Promise<void> {
30
+ const manager = new WhatsAppCredentialManager()
31
+ const accountId = createAccountId(options.phone)
32
+ const existingPaths = manager.getAccountPaths(accountId)
33
+ await rm(existingPaths.auth_dir, { recursive: true, force: true })
34
+ const paths = await manager.ensureAccountPaths(accountId)
35
+ const client = await new WhatsAppClient().login({ authDir: paths.auth_dir })
36
+
37
+ let code: string
38
+ let waitForAuth: () => Promise<void>
39
+
20
40
  try {
21
- const manager = new WhatsAppCredentialManager()
22
- const accountId = createAccountId(options.phone)
23
- // Clear stale session files so Baileys starts fresh for pairing
24
- const existingPaths = manager.getAccountPaths(accountId)
25
- await rm(existingPaths.auth_dir, { recursive: true, force: true })
26
- const paths = await manager.ensureAccountPaths(accountId)
27
- const client = await new WhatsAppClient().login({ authDir: paths.auth_dir })
28
-
29
- let code: string
30
- let waitForAuth: () => Promise<void>
31
-
32
- try {
33
- const result = await client.connectForPairing(options.phone)
34
- code = result.code
35
- waitForAuth = result.waitForAuth
36
- } catch (err) {
37
- await client.close()
38
- throw err
39
- }
41
+ const result = await client.connectForPairing(options.phone)
42
+ code = result.code
43
+ waitForAuth = result.waitForAuth
44
+ } catch (err) {
45
+ await client.close()
46
+ throw err
47
+ }
40
48
 
41
- const formatted = code.length === 8 ? `${code.slice(0, 4)}-${code.slice(4)}` : code
49
+ const formatted = code.length === 8 ? `${code.slice(0, 4)}-${code.slice(4)}` : code
42
50
 
43
- console.log(formatOutput({
44
- pairing_code: formatted,
45
- message: 'Enter this code in WhatsApp > Linked Devices > Link with phone number',
46
- }, options.pretty))
51
+ console.log(
52
+ formatOutput(
53
+ {
54
+ pairing_code: formatted,
55
+ message: 'Enter this code in WhatsApp > Linked Devices > Link with phone number',
56
+ },
57
+ options.pretty,
58
+ ),
59
+ )
47
60
 
48
- try {
49
- await waitForAuth()
50
- } catch (err) {
51
- await client.close()
52
- throw err
53
- }
61
+ try {
62
+ await waitForAuth()
63
+ } catch (err) {
64
+ await client.close()
65
+ throw err
66
+ }
67
+
68
+ const now = new Date().toISOString()
69
+ await manager.setAccount({
70
+ account_id: accountId,
71
+ phone_number: options.phone,
72
+ created_at: now,
73
+ updated_at: now,
74
+ })
75
+ await manager.setCurrent(accountId)
76
+ await client.close()
77
+
78
+ console.log(
79
+ formatOutput(
80
+ {
81
+ authenticated: true,
82
+ account_id: accountId,
83
+ phone_number: options.phone,
84
+ },
85
+ options.pretty,
86
+ ),
87
+ )
88
+ process.exit(0)
89
+ }
90
+
91
+ async function loginWithQR(options: LoginOptions): Promise<void> {
92
+ const manager = new WhatsAppCredentialManager()
93
+ const accountId = 'qr-default'
94
+ const existingPaths = manager.getAccountPaths(accountId)
95
+ await rm(existingPaths.auth_dir, { recursive: true, force: true })
96
+ const paths = await manager.ensureAccountPaths(accountId)
97
+ const client = await new WhatsAppClient().login({ authDir: paths.auth_dir })
98
+ const interactive = isInteractiveSession()
99
+
100
+ let waitForAuth: () => Promise<void>
101
+ let browserOpened = false
54
102
 
55
- const now = new Date().toISOString()
56
- await manager.setAccount({
57
- account_id: accountId,
58
- phone_number: options.phone,
59
- created_at: now,
60
- updated_at: now,
103
+ try {
104
+ const result = await client.connectForQR(async (qr) => {
105
+ await displayQR(qr, {
106
+ platform: 'WhatsApp',
107
+ brandColor: '#25D366',
108
+ scanInstruction: 'Scan with WhatsApp on your phone',
109
+ interactive,
110
+ openBrowser: interactive && !browserOpened,
111
+ formatOutput,
112
+ pretty: options.pretty,
113
+ })
114
+ browserOpened = true
61
115
  })
62
- await manager.setCurrent(accountId)
116
+ waitForAuth = result.waitForAuth
117
+ } catch (err) {
63
118
  await client.close()
119
+ throw err
120
+ }
64
121
 
65
- console.log(formatOutput({
66
- authenticated: true,
67
- account_id: accountId,
68
- phone_number: options.phone,
69
- }, options.pretty))
70
- process.exit(0)
122
+ if (interactive) {
123
+ info('\nWaiting for QR code scan...')
124
+ }
125
+
126
+ try {
127
+ await waitForAuth()
128
+ } catch (err) {
129
+ await client.close()
130
+ throw err
131
+ }
132
+
133
+ const now = new Date().toISOString()
134
+ await manager.setAccount({
135
+ account_id: accountId,
136
+ created_at: now,
137
+ updated_at: now,
138
+ })
139
+ await manager.setCurrent(accountId)
140
+ await client.close()
141
+
142
+ console.log(
143
+ formatOutput(
144
+ {
145
+ authenticated: true,
146
+ account_id: accountId,
147
+ },
148
+ options.pretty,
149
+ ),
150
+ )
151
+ process.exit(0)
152
+ }
153
+
154
+ async function loginAction(options: LoginOptions): Promise<void> {
155
+ try {
156
+ if (options.qr) {
157
+ await loginWithQR(options)
158
+ } else if (options.phone) {
159
+ await loginWithPairingCode(options as LoginOptions & { phone: string })
160
+ } else {
161
+ console.error('Error: Either --phone or --qr is required')
162
+ process.exit(1)
163
+ }
71
164
  } catch (error) {
72
165
  handleError(error as Error)
73
166
  }
@@ -79,21 +172,31 @@ async function statusAction(options: StatusOptions): Promise<void> {
79
172
  const account = await manager.getAccount(options.account)
80
173
 
81
174
  if (!account) {
82
- console.log(formatOutput({
83
- error: options.account
84
- ? `WhatsApp account "${options.account}" not found.`
85
- : 'No WhatsApp account configured. Run "auth login --phone <phone-number>" first.',
86
- }, options.pretty))
175
+ console.log(
176
+ formatOutput(
177
+ {
178
+ error: options.account
179
+ ? `WhatsApp account "${options.account}" not found.`
180
+ : 'No WhatsApp account configured. Run "auth login --qr" or "auth login --phone <phone-number>" first.',
181
+ },
182
+ options.pretty,
183
+ ),
184
+ )
87
185
  process.exit(1)
88
186
  }
89
187
 
90
- console.log(formatOutput({
91
- account_id: account.account_id,
92
- phone_number: account.phone_number,
93
- name: account.name,
94
- created_at: account.created_at,
95
- updated_at: account.updated_at,
96
- }, options.pretty))
188
+ console.log(
189
+ formatOutput(
190
+ {
191
+ account_id: account.account_id,
192
+ phone_number: account.phone_number,
193
+ name: account.name,
194
+ created_at: account.created_at,
195
+ updated_at: account.updated_at,
196
+ },
197
+ options.pretty,
198
+ ),
199
+ )
97
200
  } catch (error) {
98
201
  handleError(error as Error)
99
202
  }
@@ -104,17 +207,19 @@ async function listAction(options: { pretty?: boolean }): Promise<void> {
104
207
  const manager = new WhatsAppCredentialManager()
105
208
  const accounts = await manager.listAccounts()
106
209
 
107
- console.log(formatOutput(
108
- accounts.map((account) => ({
109
- account_id: account.account_id,
110
- phone_number: account.phone_number,
111
- name: account.name,
112
- created_at: account.created_at,
113
- updated_at: account.updated_at,
114
- is_current: account.is_current,
115
- })),
116
- options.pretty,
117
- ))
210
+ console.log(
211
+ formatOutput(
212
+ accounts.map((account) => ({
213
+ account_id: account.account_id,
214
+ phone_number: account.phone_number,
215
+ name: account.name,
216
+ created_at: account.created_at,
217
+ updated_at: account.updated_at,
218
+ is_current: account.is_current,
219
+ })),
220
+ options.pretty,
221
+ ),
222
+ )
118
223
  } catch (error) {
119
224
  handleError(error as Error)
120
225
  }
@@ -175,8 +280,9 @@ export const authCommand = new Command('auth')
175
280
  .description('WhatsApp authentication commands')
176
281
  .addCommand(
177
282
  new Command('login')
178
- .description('Link as a companion device using a pairing code')
179
- .requiredOption('--phone <number>', 'Phone number in international format (e.g. +12025551234)')
283
+ .description('Link as a companion device via pairing code (--phone) or QR code (--qr)')
284
+ .option('--phone <number>', 'Phone number in international format (e.g. +12025551234)')
285
+ .option('--qr', 'Link by scanning a QR code instead of entering a pairing code')
180
286
  .option('--pretty', 'Pretty print JSON output')
181
287
  .action(loginAction),
182
288
  )
@@ -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'
@@ -40,8 +40,8 @@ export async function withWhatsAppClient<T>(
40
40
  formatOutput(
41
41
  {
42
42
  error: options.account
43
- ? `WhatsApp account "${options.account}" not found. Run "agent-whatsapp auth login --phone <phone-number>" first.`
44
- : 'Not authenticated. Run "agent-whatsapp auth login --phone <phone-number>" first.',
43
+ ? `WhatsApp account "${options.account}" not found. Run "agent-whatsapp auth login --qr" or "agent-whatsapp auth login --phone <phone-number>" first.`
44
+ : 'Not authenticated. Run "agent-whatsapp auth login --qr" or "agent-whatsapp auth login --phone <phone-number>" first.',
45
45
  },
46
46
  options.pretty,
47
47
  ),
@@ -0,0 +1,59 @@
1
+ import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
2
+
3
+ import type { WhatsAppClient } from '../client'
4
+ import * as sharedModule from './shared'
5
+ import { whoamiAction } from './whoami'
6
+
7
+ let mockProfileData: { id: string; name: string | null; phone_number: string | null } = {
8
+ id: '12025551234:1@s.whatsapp.net',
9
+ name: 'Test User',
10
+ phone_number: '12025551234',
11
+ }
12
+
13
+ let withWhatsAppClientSpy: ReturnType<typeof spyOn>
14
+ let consoleLogSpy: ReturnType<typeof spyOn>
15
+
16
+ describe('whoami command', () => {
17
+ beforeEach(() => {
18
+ mockProfileData = {
19
+ id: '12025551234:1@s.whatsapp.net',
20
+ name: 'Test User',
21
+ phone_number: '12025551234',
22
+ }
23
+
24
+ withWhatsAppClientSpy = spyOn(sharedModule, 'withWhatsAppClient').mockImplementation(
25
+ async (_opts, fn) => fn({ getProfile: () => Promise.resolve(mockProfileData) } as unknown as WhatsAppClient),
26
+ )
27
+ consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
28
+ })
29
+
30
+ afterEach(() => {
31
+ withWhatsAppClientSpy?.mockRestore()
32
+ consoleLogSpy?.mockRestore()
33
+ })
34
+
35
+ test('outputs profile information', async () => {
36
+ await whoamiAction({})
37
+
38
+ expect(consoleLogSpy).toHaveBeenCalledTimes(1)
39
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string)
40
+ expect(output.id).toBe('12025551234:1@s.whatsapp.net')
41
+ expect(output.name).toBe('Test User')
42
+ expect(output.phone_number).toBe('12025551234')
43
+ })
44
+
45
+ test('outputs profile with null name', async () => {
46
+ mockProfileData = {
47
+ id: '12025551234@s.whatsapp.net',
48
+ name: null,
49
+ phone_number: '12025551234',
50
+ }
51
+
52
+ await whoamiAction({})
53
+
54
+ expect(consoleLogSpy).toHaveBeenCalledTimes(1)
55
+ const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string)
56
+ expect(output.id).toBe('12025551234@s.whatsapp.net')
57
+ expect(output.name).toBeNull()
58
+ })
59
+ })
@@ -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 { withWhatsAppClient } from './shared'
7
+
8
+ export async function whoamiAction(options: { account?: string; pretty?: boolean }): Promise<void> {
9
+ try {
10
+ const profile = await withWhatsAppClient(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 WhatsApp account')
20
+ .option('--pretty', 'Pretty print JSON output')
21
+ .action(whoamiAction)
@@ -9,7 +9,7 @@ export async function ensureWhatsAppAuth(): Promise<void> {
9
9
 
10
10
  if (!account) {
11
11
  console.log(formatOutput({
12
- error: 'Not authenticated. Run "agent-whatsapp auth login --phone <phone-number>" first.',
12
+ error: 'Not authenticated. Run "agent-whatsapp auth login --qr" or "agent-whatsapp auth login --phone <phone-number>" first.',
13
13
  }))
14
14
  process.exit(1)
15
15
  }
@@ -19,7 +19,7 @@ export async function ensureWhatsAppAuth(): Promise<void> {
19
19
 
20
20
  if (!existsSync(credsPath)) {
21
21
  console.log(formatOutput({
22
- error: 'Auth credentials missing. Run "agent-whatsapp auth login --phone <phone-number>" to re-authenticate.',
22
+ error: 'Auth credentials missing. Run "agent-whatsapp auth login --qr" or "agent-whatsapp auth login --phone <phone-number>" to re-authenticate.',
23
23
  }))
24
24
  process.exit(1)
25
25
  }