agent-messenger 2.10.2 → 2.11.1

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 (330) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.env.template +4 -1
  3. package/README.md +77 -27
  4. package/bun.lock +26 -0
  5. package/dist/package.json +21 -1
  6. package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
  7. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  8. package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
  9. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
  11. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  12. package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
  13. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  14. package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
  15. package/dist/src/platforms/channeltalkbot/cli.js +11 -1
  16. package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
  17. package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
  18. package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
  19. package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
  20. package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
  21. package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
  22. package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
  23. package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
  24. package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
  25. package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
  26. package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
  27. package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
  28. package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
  29. package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
  30. package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
  31. package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
  32. package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
  33. package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
  34. package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
  35. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
  36. package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
  37. package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
  38. package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
  39. package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
  40. package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
  41. package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
  42. package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
  43. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  44. package/dist/src/platforms/discord/commands/auth.js +3 -1
  45. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  46. package/dist/src/platforms/discord/listener.d.ts +2 -0
  47. package/dist/src/platforms/discord/listener.d.ts.map +1 -1
  48. package/dist/src/platforms/discord/listener.js +51 -21
  49. package/dist/src/platforms/discord/listener.js.map +1 -1
  50. package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
  51. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  52. package/dist/src/platforms/discord/token-extractor.js +21 -6
  53. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  54. package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
  55. package/dist/src/platforms/discordbot/cli.js +12 -1
  56. package/dist/src/platforms/discordbot/cli.js.map +1 -1
  57. package/dist/src/platforms/discordbot/client.d.ts +3 -0
  58. package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
  59. package/dist/src/platforms/discordbot/client.js +3 -0
  60. package/dist/src/platforms/discordbot/client.js.map +1 -1
  61. package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
  62. package/dist/src/platforms/discordbot/commands/auth.js +1 -5
  63. package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
  64. package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
  65. package/dist/src/platforms/discordbot/commands/message.js +1 -6
  66. package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
  67. package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
  68. package/dist/src/platforms/discordbot/commands/server.js +1 -4
  69. package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
  70. package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
  71. package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
  72. package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
  73. package/dist/src/platforms/discordbot/index.d.ts +3 -1
  74. package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
  75. package/dist/src/platforms/discordbot/index.js +2 -1
  76. package/dist/src/platforms/discordbot/index.js.map +1 -1
  77. package/dist/src/platforms/discordbot/listener.d.ts +43 -0
  78. package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
  79. package/dist/src/platforms/discordbot/listener.js +292 -0
  80. package/dist/src/platforms/discordbot/listener.js.map +1 -0
  81. package/dist/src/platforms/discordbot/types.d.ts +161 -0
  82. package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
  83. package/dist/src/platforms/discordbot/types.js +34 -0
  84. package/dist/src/platforms/discordbot/types.js.map +1 -1
  85. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  86. package/dist/src/platforms/instagram/commands/auth.js +3 -1
  87. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  88. package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
  89. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
  90. package/dist/src/platforms/instagram/token-extractor.js +11 -2
  91. package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
  92. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  93. package/dist/src/platforms/slack/commands/auth.js +4 -2
  94. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  95. package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
  96. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  97. package/dist/src/platforms/slack/token-extractor.js +64 -15
  98. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  99. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  100. package/dist/src/platforms/slackbot/cli.js +15 -3
  101. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  102. package/dist/src/platforms/slackbot/client.d.ts +22 -1
  103. package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
  104. package/dist/src/platforms/slackbot/client.js +104 -1
  105. package/dist/src/platforms/slackbot/client.js.map +1 -1
  106. package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
  107. package/dist/src/platforms/slackbot/commands/auth.js +1 -5
  108. package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
  109. package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
  110. package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
  111. package/dist/src/platforms/slackbot/commands/file.js +164 -0
  112. package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
  113. package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
  114. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
  115. package/dist/src/platforms/slackbot/commands/index.js +1 -0
  116. package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
  117. package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
  118. package/dist/src/platforms/slackbot/commands/message.js +19 -0
  119. package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
  120. package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
  121. package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
  122. package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
  123. package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
  124. package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
  125. package/dist/src/platforms/slackbot/credential-manager.js +30 -2
  126. package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
  127. package/dist/src/platforms/slackbot/index.d.ts +4 -1
  128. package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
  129. package/dist/src/platforms/slackbot/index.js +1 -0
  130. package/dist/src/platforms/slackbot/index.js.map +1 -1
  131. package/dist/src/platforms/slackbot/listener.d.ts +44 -0
  132. package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
  133. package/dist/src/platforms/slackbot/listener.js +313 -0
  134. package/dist/src/platforms/slackbot/listener.js.map +1 -0
  135. package/dist/src/platforms/slackbot/types.d.ts +196 -1
  136. package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
  137. package/dist/src/platforms/slackbot/types.js +4 -1
  138. package/dist/src/platforms/slackbot/types.js.map +1 -1
  139. package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
  140. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  141. package/dist/src/platforms/teams/commands/auth.js +37 -6
  142. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  143. package/dist/src/platforms/teams/ensure-auth.js +31 -9
  144. package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
  145. package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
  146. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  147. package/dist/src/platforms/teams/token-extractor.js +71 -29
  148. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  149. package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
  150. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  151. package/dist/src/platforms/webex/commands/auth.js +3 -1
  152. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  153. package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
  154. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  155. package/dist/src/platforms/webex/token-extractor.js +16 -2
  156. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  157. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
  158. package/dist/src/platforms/wechatbot/cli.js +11 -1
  159. package/dist/src/platforms/wechatbot/cli.js.map +1 -1
  160. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
  161. package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
  162. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
  163. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
  164. package/dist/src/platforms/wechatbot/commands/message.js +1 -6
  165. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
  166. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
  167. package/dist/src/platforms/wechatbot/commands/template.js +1 -6
  168. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
  169. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
  170. package/dist/src/platforms/wechatbot/commands/user.js +1 -6
  171. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
  172. package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
  173. package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
  174. package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
  175. package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
  176. package/dist/src/platforms/whatsappbot/cli.js +11 -1
  177. package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
  178. package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
  179. package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
  180. package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
  181. package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
  182. package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
  183. package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
  184. package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
  185. package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
  186. package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
  187. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
  188. package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
  189. package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
  190. package/dist/src/shared/chromium/browsers.d.ts +8 -0
  191. package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
  192. package/dist/src/shared/chromium/browsers.js +58 -3
  193. package/dist/src/shared/chromium/browsers.js.map +1 -1
  194. package/dist/src/shared/chromium/cli-options.d.ts +5 -0
  195. package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
  196. package/dist/src/shared/chromium/cli-options.js +8 -0
  197. package/dist/src/shared/chromium/cli-options.js.map +1 -0
  198. package/dist/src/shared/chromium/index.d.ts +3 -1
  199. package/dist/src/shared/chromium/index.d.ts.map +1 -1
  200. package/dist/src/shared/chromium/index.js +2 -1
  201. package/dist/src/shared/chromium/index.js.map +1 -1
  202. package/dist/src/shared/utils/cli-output.d.ts +7 -0
  203. package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
  204. package/dist/src/shared/utils/cli-output.js +7 -0
  205. package/dist/src/shared/utils/cli-output.js.map +1 -0
  206. package/dist/src/tui/app.d.ts.map +1 -1
  207. package/dist/src/tui/app.js +73 -20
  208. package/dist/src/tui/app.js.map +1 -1
  209. package/docs/content/docs/cli/channeltalk.mdx +4 -0
  210. package/docs/content/docs/cli/discord.mdx +5 -0
  211. package/docs/content/docs/cli/instagram.mdx +3 -0
  212. package/docs/content/docs/cli/slack.mdx +5 -0
  213. package/docs/content/docs/cli/slackbot.mdx +60 -22
  214. package/docs/content/docs/cli/teams.mdx +5 -0
  215. package/docs/content/docs/cli/webex.mdx +3 -0
  216. package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
  217. package/docs/content/docs/sdk/discordbot.mdx +501 -0
  218. package/docs/content/docs/sdk/meta.json +2 -0
  219. package/docs/content/docs/sdk/slackbot.mdx +576 -0
  220. package/e2e/README.md +1 -1
  221. package/e2e/config.ts +9 -4
  222. package/examples/discordbot-listen.ts +65 -0
  223. package/examples/slackbot-listen.ts +65 -0
  224. package/package.json +21 -1
  225. package/skills/agent-channeltalk/SKILL.md +5 -1
  226. package/skills/agent-channeltalk/references/authentication.md +5 -1
  227. package/skills/agent-channeltalkbot/SKILL.md +17 -3
  228. package/skills/agent-channeltalkbot/references/authentication.md +7 -5
  229. package/skills/agent-discord/SKILL.md +5 -1
  230. package/skills/agent-discord/references/authentication.md +7 -1
  231. package/skills/agent-discordbot/SKILL.md +13 -2
  232. package/skills/agent-discordbot/references/common-patterns.md +1 -1
  233. package/skills/agent-instagram/SKILL.md +7 -1
  234. package/skills/agent-instagram/references/authentication.md +6 -0
  235. package/skills/agent-kakaotalk/SKILL.md +1 -1
  236. package/skills/agent-line/SKILL.md +1 -1
  237. package/skills/agent-slack/SKILL.md +5 -1
  238. package/skills/agent-slack/references/authentication.md +7 -1
  239. package/skills/agent-slackbot/SKILL.md +56 -4
  240. package/skills/agent-slackbot/references/authentication.md +4 -0
  241. package/skills/agent-teams/SKILL.md +5 -1
  242. package/skills/agent-teams/references/authentication.md +7 -1
  243. package/skills/agent-telegram/SKILL.md +1 -1
  244. package/skills/agent-webex/SKILL.md +7 -1
  245. package/skills/agent-webex/references/authentication.md +6 -0
  246. package/skills/agent-wechatbot/SKILL.md +16 -1
  247. package/skills/agent-wechatbot/references/authentication.md +219 -0
  248. package/skills/agent-wechatbot/references/common-patterns.md +358 -0
  249. package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
  250. package/skills/agent-wechatbot/templates/post-message.sh +122 -0
  251. package/skills/agent-wechatbot/templates/send-template.sh +152 -0
  252. package/skills/agent-whatsapp/SKILL.md +1 -1
  253. package/skills/agent-whatsappbot/SKILL.md +30 -1
  254. package/src/platforms/channeltalk/commands/auth.test.ts +15 -3
  255. package/src/platforms/channeltalk/commands/auth.ts +15 -5
  256. package/src/platforms/channeltalk/token-extractor.ts +24 -5
  257. package/src/platforms/channeltalkbot/cli.ts +9 -0
  258. package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
  259. package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
  260. package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
  261. package/src/platforms/channeltalkbot/commands/group.ts +1 -6
  262. package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
  263. package/src/platforms/channeltalkbot/commands/message.ts +1 -6
  264. package/src/platforms/channeltalkbot/commands/whoami.test.ts +2 -0
  265. package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
  266. package/src/platforms/channeltalkbot/credential-manager.test.ts +96 -2
  267. package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
  268. package/src/platforms/discord/commands/auth.ts +13 -2
  269. package/src/platforms/discord/listener.test.ts +59 -1
  270. package/src/platforms/discord/listener.ts +43 -19
  271. package/src/platforms/discord/token-extractor.ts +30 -6
  272. package/src/platforms/discordbot/cli.ts +10 -0
  273. package/src/platforms/discordbot/client.ts +4 -0
  274. package/src/platforms/discordbot/commands/auth.ts +1 -5
  275. package/src/platforms/discordbot/commands/message.ts +1 -6
  276. package/src/platforms/discordbot/commands/server.ts +1 -5
  277. package/src/platforms/discordbot/commands/whoami.ts +1 -6
  278. package/src/platforms/discordbot/index.test.ts +82 -0
  279. package/src/platforms/discordbot/index.ts +27 -9
  280. package/src/platforms/discordbot/listener.test.ts +1002 -0
  281. package/src/platforms/discordbot/listener.ts +321 -0
  282. package/src/platforms/discordbot/types.ts +163 -0
  283. package/src/platforms/instagram/commands/auth.ts +9 -1
  284. package/src/platforms/instagram/token-extractor.ts +13 -1
  285. package/src/platforms/slack/commands/auth.ts +11 -2
  286. package/src/platforms/slack/token-extractor.test.ts +96 -0
  287. package/src/platforms/slack/token-extractor.ts +76 -13
  288. package/src/platforms/slackbot/cli.ts +13 -1
  289. package/src/platforms/slackbot/client.test.ts +274 -0
  290. package/src/platforms/slackbot/client.ts +130 -2
  291. package/src/platforms/slackbot/commands/auth.ts +1 -5
  292. package/src/platforms/slackbot/commands/file.test.ts +201 -0
  293. package/src/platforms/slackbot/commands/file.ts +212 -0
  294. package/src/platforms/slackbot/commands/index.ts +1 -0
  295. package/src/platforms/slackbot/commands/message.ts +22 -0
  296. package/src/platforms/slackbot/commands/whoami.ts +1 -6
  297. package/src/platforms/slackbot/credential-manager.test.ts +62 -2
  298. package/src/platforms/slackbot/credential-manager.ts +32 -2
  299. package/src/platforms/slackbot/index.test.ts +59 -0
  300. package/src/platforms/slackbot/index.ts +31 -7
  301. package/src/platforms/slackbot/listener.test.ts +1012 -0
  302. package/src/platforms/slackbot/listener.ts +362 -0
  303. package/src/platforms/slackbot/types.ts +224 -1
  304. package/src/platforms/teams/commands/auth.test.ts +1 -1
  305. package/src/platforms/teams/commands/auth.ts +66 -7
  306. package/src/platforms/teams/ensure-auth.test.ts +56 -5
  307. package/src/platforms/teams/ensure-auth.ts +39 -11
  308. package/src/platforms/teams/token-extractor.test.ts +146 -24
  309. package/src/platforms/teams/token-extractor.ts +87 -29
  310. package/src/platforms/webex/commands/auth.ts +13 -2
  311. package/src/platforms/webex/token-extractor.ts +25 -3
  312. package/src/platforms/wechatbot/cli.ts +9 -0
  313. package/src/platforms/wechatbot/commands/auth.ts +1 -5
  314. package/src/platforms/wechatbot/commands/message.ts +1 -6
  315. package/src/platforms/wechatbot/commands/template.ts +1 -6
  316. package/src/platforms/wechatbot/commands/user.ts +1 -6
  317. package/src/platforms/wechatbot/commands/whoami.ts +1 -6
  318. package/src/platforms/whatsappbot/cli.ts +9 -0
  319. package/src/platforms/whatsappbot/commands/auth.ts +1 -5
  320. package/src/platforms/whatsappbot/commands/message.ts +1 -6
  321. package/src/platforms/whatsappbot/commands/template.ts +1 -6
  322. package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
  323. package/src/shared/chromium/browsers.test.ts +80 -0
  324. package/src/shared/chromium/browsers.ts +72 -3
  325. package/src/shared/chromium/cli-options.test.ts +22 -0
  326. package/src/shared/chromium/cli-options.ts +12 -0
  327. package/src/shared/chromium/index.ts +3 -0
  328. package/src/shared/utils/cli-output.test.ts +57 -0
  329. package/src/shared/utils/cli-output.ts +8 -0
  330. package/src/tui/app.ts +129 -20
@@ -1,13 +1,28 @@
1
1
  import { WebClient } from '@slack/web-api'
2
2
 
3
3
  import { SlackBotCredentialManager } from './credential-manager'
4
- import { SlackBotError, type SlackChannel, type SlackMessage, type SlackUser } from './types'
4
+ import { SlackBotError, type SlackChannel, type SlackFile, type SlackMessage, type SlackUser } from './types'
5
5
 
6
6
  const MAX_RETRIES = 3
7
7
  const RATE_LIMIT_ERROR_CODE = 'slack_webapi_rate_limited_error'
8
8
 
9
+ function mapSlackFile(f: any): SlackFile {
10
+ return {
11
+ id: f?.id || '',
12
+ name: f?.name || '',
13
+ title: f?.title || f?.name || '',
14
+ mimetype: f?.mimetype || 'application/octet-stream',
15
+ size: f?.size || 0,
16
+ url_private: f?.url_private || '',
17
+ created: f?.created || 0,
18
+ user: f?.user || '',
19
+ channels: f?.channels,
20
+ }
21
+ }
22
+
9
23
  export class SlackBotClient {
10
24
  private client: WebClient | null = null
25
+ private token: string | null = null
11
26
 
12
27
  async login(credentials?: { token: string }): Promise<this> {
13
28
  if (credentials) {
@@ -18,6 +33,7 @@ export class SlackBotClient {
18
33
  if (!token.startsWith('xoxb-')) {
19
34
  throw new SlackBotError('Token must be a bot token (xoxb-)', 'invalid_token_type')
20
35
  }
36
+ this.token = token
21
37
  this.client = new WebClient(token)
22
38
  } else {
23
39
  const credManager = new SlackBotCredentialManager()
@@ -52,7 +68,9 @@ export class SlackBotClient {
52
68
  break
53
69
  }
54
70
  }
55
- throw new SlackBotError(lastError?.message || 'Unknown error', (lastError as any)?.code || 'unknown_error')
71
+ const code = (lastError as any)?.code || 'unknown_error'
72
+ const retryAfter = code === RATE_LIMIT_ERROR_CODE ? (lastError as any)?.retryAfter : undefined
73
+ throw new SlackBotError(lastError?.message || 'Unknown error', code, retryAfter)
56
74
  }
57
75
 
58
76
  private sleep(ms: number): Promise<void> {
@@ -451,6 +469,17 @@ export class SlackBotClient {
451
469
  })
452
470
  }
453
471
 
472
+ async setAssistantStatus(channel: string, threadTs: string, status: string): Promise<void> {
473
+ return this.withRetry(async () => {
474
+ const response = await this.ensureAuth().assistant.threads.setStatus({
475
+ channel_id: channel,
476
+ thread_ts: threadTs,
477
+ status,
478
+ })
479
+ this.checkResponse(response)
480
+ })
481
+ }
482
+
454
483
  async joinChannel(channel: string): Promise<void> {
455
484
  return this.withRetry(async () => {
456
485
  const response = await this.ensureAuth().conversations.join({ channel })
@@ -464,4 +493,103 @@ export class SlackBotClient {
464
493
  this.checkResponse(response)
465
494
  })
466
495
  }
496
+
497
+ async uploadFile(
498
+ channel: string,
499
+ file: Buffer,
500
+ filename: string,
501
+ options?: { thread_ts?: string; title?: string; initial_comment?: string },
502
+ ): Promise<SlackFile> {
503
+ return this.withRetry(async () => {
504
+ const response = await this.ensureAuth().files.uploadV2({
505
+ channel_id: channel,
506
+ file,
507
+ filename,
508
+ thread_ts: options?.thread_ts,
509
+ title: options?.title,
510
+ initial_comment: options?.initial_comment,
511
+ })
512
+ this.checkResponse(response)
513
+
514
+ const completionFiles = (response as any).files?.[0]?.files
515
+ const f = completionFiles?.[0]
516
+ if (!f) {
517
+ throw new SlackBotError('No file returned in upload response', 'file_not_found')
518
+ }
519
+ return mapSlackFile(f)
520
+ })
521
+ }
522
+
523
+ async listFiles(options?: { channel?: string; user?: string; limit?: number }): Promise<SlackFile[]> {
524
+ return this.withRetry(async () => {
525
+ const response = await this.ensureAuth().files.list({
526
+ channel: options?.channel,
527
+ user: options?.user,
528
+ count: options?.limit,
529
+ })
530
+ this.checkResponse(response)
531
+
532
+ return (response.files || []).map((f) => mapSlackFile(f))
533
+ })
534
+ }
535
+
536
+ async getFileInfo(fileId: string): Promise<SlackFile> {
537
+ return this.withRetry(async () => {
538
+ const response = await this.ensureAuth().files.info({ file: fileId })
539
+ this.checkResponse(response)
540
+
541
+ return mapSlackFile(response.file)
542
+ })
543
+ }
544
+
545
+ async downloadFile(fileId: string): Promise<{ buffer: Buffer; file: SlackFile }> {
546
+ const file = await this.getFileInfo(fileId)
547
+
548
+ if (!file.url_private) {
549
+ throw new SlackBotError('File has no download URL', 'no_download_url')
550
+ }
551
+
552
+ if (!this.token) {
553
+ throw new SlackBotError('Not authenticated. Call .login() first.', 'not_authenticated')
554
+ }
555
+
556
+ const response = await fetch(file.url_private, {
557
+ headers: { Authorization: `Bearer ${this.token}` },
558
+ })
559
+
560
+ if (!response.ok) {
561
+ throw new SlackBotError(`Failed to download file: ${response.statusText}`, 'download_failed')
562
+ }
563
+
564
+ const arrayBuffer = await response.arrayBuffer()
565
+ return {
566
+ buffer: Buffer.from(arrayBuffer),
567
+ file,
568
+ }
569
+ }
570
+
571
+ async deleteFile(fileId: string): Promise<void> {
572
+ return this.withRetry(async () => {
573
+ const response = await this.ensureAuth().files.delete({ file: fileId })
574
+ this.checkResponse(response)
575
+ })
576
+ }
577
+
578
+ async appsConnectionsOpen(appToken: string): Promise<{ url: string }> {
579
+ if (!appToken) {
580
+ throw new SlackBotError('App-level token is required for Socket Mode', 'missing_app_token')
581
+ }
582
+ if (!appToken.startsWith('xapp-')) {
583
+ throw new SlackBotError(
584
+ 'Token must be an app-level token (xapp-) with connections:write scope',
585
+ 'invalid_app_token_type',
586
+ )
587
+ }
588
+
589
+ return this.withRetry(async () => {
590
+ const response = await new WebClient(appToken).apps.connections.open()
591
+ this.checkResponse(response)
592
+ return { url: (response as { url: string }).url }
593
+ })
594
+ }
467
595
  }
@@ -1,5 +1,6 @@
1
1
  import { Command } from 'commander'
2
2
 
3
+ import { cliOutput } from '@/shared/utils/cli-output'
3
4
  import { formatOutput } from '@/shared/utils/output'
4
5
 
5
6
  import { SlackBotClient } from '../client'
@@ -177,11 +178,6 @@ export async function removeAction(botId: string, options: ActionOptions): Promi
177
178
  }
178
179
  }
179
180
 
180
- function cliOutput(result: ActionResult, pretty?: boolean, exitOnError = true): void {
181
- console.log(formatOutput(result, pretty))
182
- if (result.error && exitOnError) process.exit(1)
183
- }
184
-
185
181
  export const authCommand = new Command('auth')
186
182
  .description('Bot authentication commands')
187
183
  .addCommand(
@@ -0,0 +1,201 @@
1
+ import { beforeEach, describe, expect, mock, it } from 'bun:test'
2
+
3
+ const mockResolveChannel = mock((_channel: string) => Promise.resolve('C123456'))
4
+ const mockUploadFile = mock(() =>
5
+ Promise.resolve({
6
+ id: 'F123',
7
+ name: 'test.txt',
8
+ title: 'test.txt',
9
+ mimetype: 'text/plain',
10
+ size: 12,
11
+ url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
12
+ created: 1234567890,
13
+ user: 'U123',
14
+ channels: ['C123456'],
15
+ }),
16
+ )
17
+ const mockListFiles = mock(() =>
18
+ Promise.resolve([
19
+ {
20
+ id: 'F123',
21
+ name: 'test.txt',
22
+ title: 'test.txt',
23
+ mimetype: 'text/plain',
24
+ size: 1024,
25
+ url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
26
+ created: 1234567890,
27
+ user: 'U123',
28
+ channels: ['C123456'],
29
+ },
30
+ {
31
+ id: 'F456',
32
+ name: 'document.pdf',
33
+ title: 'document.pdf',
34
+ mimetype: 'application/pdf',
35
+ size: 2048,
36
+ url_private: 'https://files.slack.com/files-pri/T123-F456/document.pdf',
37
+ created: 1234567891,
38
+ user: 'U456',
39
+ channels: ['C123456'],
40
+ },
41
+ ]),
42
+ )
43
+ const mockGetFileInfo = mock(() =>
44
+ Promise.resolve({
45
+ id: 'F123',
46
+ name: 'test.txt',
47
+ title: 'test.txt',
48
+ mimetype: 'text/plain',
49
+ size: 1024,
50
+ url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
51
+ created: 1234567890,
52
+ user: 'U123',
53
+ channels: ['C123456'],
54
+ }),
55
+ )
56
+ const mockDownloadFile = mock(() =>
57
+ Promise.resolve({
58
+ buffer: Buffer.from('downloaded content'),
59
+ file: {
60
+ id: 'F123',
61
+ name: 'test.txt',
62
+ title: 'test.txt',
63
+ mimetype: 'text/plain',
64
+ size: 18,
65
+ url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
66
+ created: 1234567890,
67
+ user: 'U123',
68
+ channels: ['C123456'],
69
+ },
70
+ }),
71
+ )
72
+ const mockDeleteFile = mock(() => Promise.resolve())
73
+
74
+ mock.module('../client', () => ({
75
+ SlackBotClient: class MockSlackBotClient {
76
+ async login(_credentials?: { token: string }) {
77
+ return this
78
+ }
79
+ resolveChannel = mockResolveChannel
80
+ uploadFile = mockUploadFile
81
+ listFiles = mockListFiles
82
+ getFileInfo = mockGetFileInfo
83
+ downloadFile = mockDownloadFile
84
+ deleteFile = mockDeleteFile
85
+ },
86
+ }))
87
+
88
+ import { SlackBotClient } from '../client'
89
+
90
+ describe('file commands', () => {
91
+ beforeEach(() => {
92
+ mockResolveChannel.mockClear()
93
+ mockUploadFile.mockClear()
94
+ mockListFiles.mockClear()
95
+ mockGetFileInfo.mockClear()
96
+ mockDownloadFile.mockClear()
97
+ mockDeleteFile.mockClear()
98
+ })
99
+
100
+ describe('uploadFile', () => {
101
+ it('uploads a file to a channel', async () => {
102
+ // given
103
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
104
+
105
+ // when
106
+ const file = await client.uploadFile('C123456', Buffer.from('test content'), 'test.txt')
107
+
108
+ // then
109
+ expect(file.id).toBe('F123')
110
+ expect(file.name).toBe('test.txt')
111
+ expect(file.channels).toContain('C123456')
112
+ })
113
+
114
+ it('forwards thread, title, and initial_comment options', async () => {
115
+ // given
116
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
117
+
118
+ // when
119
+ await client.uploadFile('C123456', Buffer.from('x'), 'test.txt', {
120
+ thread_ts: '1234567890.000100',
121
+ title: 'My Title',
122
+ initial_comment: 'Here you go',
123
+ })
124
+
125
+ // then
126
+ expect(mockUploadFile).toHaveBeenCalledWith('C123456', Buffer.from('x'), 'test.txt', {
127
+ thread_ts: '1234567890.000100',
128
+ title: 'My Title',
129
+ initial_comment: 'Here you go',
130
+ })
131
+ })
132
+ })
133
+
134
+ describe('listFiles', () => {
135
+ it('returns all files visible to the bot', async () => {
136
+ // given
137
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
138
+
139
+ // when
140
+ const files = await client.listFiles()
141
+
142
+ // then
143
+ expect(files).toHaveLength(2)
144
+ expect(files[0].name).toBe('test.txt')
145
+ expect(files[1].name).toBe('document.pdf')
146
+ })
147
+
148
+ it('forwards channel/user/limit filters', async () => {
149
+ // given
150
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
151
+
152
+ // when
153
+ await client.listFiles({ channel: 'C123456', user: 'U123', limit: 50 })
154
+
155
+ // then
156
+ expect(mockListFiles).toHaveBeenCalledWith({ channel: 'C123456', user: 'U123', limit: 50 })
157
+ })
158
+ })
159
+
160
+ describe('getFileInfo', () => {
161
+ it('returns file metadata', async () => {
162
+ // given
163
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
164
+
165
+ // when
166
+ const file = await client.getFileInfo('F123')
167
+
168
+ // then
169
+ expect(file.id).toBe('F123')
170
+ expect(file.name).toBe('test.txt')
171
+ expect(file.url_private).toBe('https://files.slack.com/files-pri/T123-F123/test.txt')
172
+ })
173
+ })
174
+
175
+ describe('downloadFile', () => {
176
+ it('returns buffer and file metadata', async () => {
177
+ // given
178
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
179
+
180
+ // when
181
+ const result = await client.downloadFile('F123')
182
+
183
+ // then
184
+ expect(result.file.id).toBe('F123')
185
+ expect(result.buffer.toString()).toBe('downloaded content')
186
+ })
187
+ })
188
+
189
+ describe('deleteFile', () => {
190
+ it("deletes the bot's file", async () => {
191
+ // given
192
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
193
+
194
+ // when
195
+ await client.deleteFile('F123')
196
+
197
+ // then
198
+ expect(mockDeleteFile).toHaveBeenCalledWith('F123')
199
+ })
200
+ })
201
+ })
@@ -0,0 +1,212 @@
1
+ import { readFileSync, statSync, writeFileSync } from 'node:fs'
2
+ import { basename, join, resolve } from 'node:path'
3
+
4
+ import { Command } from 'commander'
5
+
6
+ import { handleError } from '@/shared/utils/error-handler'
7
+ import { formatOutput } from '@/shared/utils/output'
8
+
9
+ import { type BotOption, getClient } from './shared'
10
+
11
+ async function uploadAction(
12
+ channelInput: string,
13
+ path: string,
14
+ options: BotOption & { filename?: string; thread?: string; title?: string; comment?: string },
15
+ ): Promise<void> {
16
+ try {
17
+ const client = await getClient(options)
18
+ const channel = await client.resolveChannel(channelInput)
19
+
20
+ const filePath = resolve(path)
21
+ const fileBuffer = readFileSync(filePath)
22
+ const filename = options.filename || basename(filePath) || 'file'
23
+
24
+ const file = await client.uploadFile(channel, fileBuffer, filename, {
25
+ thread_ts: options.thread,
26
+ title: options.title,
27
+ initial_comment: options.comment,
28
+ })
29
+
30
+ console.log(
31
+ formatOutput(
32
+ {
33
+ id: file.id,
34
+ name: file.name,
35
+ title: file.title,
36
+ mimetype: file.mimetype,
37
+ size: file.size,
38
+ url_private: file.url_private,
39
+ created: file.created,
40
+ user: file.user,
41
+ channels: file.channels,
42
+ },
43
+ options.pretty,
44
+ ),
45
+ )
46
+ } catch (error) {
47
+ handleError(error as Error)
48
+ }
49
+ }
50
+
51
+ async function listAction(options: BotOption & { channel?: string; user?: string; limit?: string }): Promise<void> {
52
+ try {
53
+ const client = await getClient(options)
54
+ const channel = options.channel ? await client.resolveChannel(options.channel) : undefined
55
+ const limit = options.limit ? parseInt(options.limit, 10) : undefined
56
+
57
+ const files = await client.listFiles({ channel, user: options.user, limit })
58
+
59
+ console.log(
60
+ formatOutput(
61
+ files.map((file) => ({
62
+ id: file.id,
63
+ name: file.name,
64
+ title: file.title,
65
+ mimetype: file.mimetype,
66
+ size: file.size,
67
+ url_private: file.url_private,
68
+ created: file.created,
69
+ user: file.user,
70
+ channels: file.channels,
71
+ })),
72
+ options.pretty,
73
+ ),
74
+ )
75
+ } catch (error) {
76
+ handleError(error as Error)
77
+ }
78
+ }
79
+
80
+ async function infoAction(fileId: string, options: BotOption): Promise<void> {
81
+ try {
82
+ const client = await getClient(options)
83
+ const file = await client.getFileInfo(fileId)
84
+
85
+ console.log(
86
+ formatOutput(
87
+ {
88
+ id: file.id,
89
+ name: file.name,
90
+ title: file.title,
91
+ mimetype: file.mimetype,
92
+ size: file.size,
93
+ url_private: file.url_private,
94
+ created: file.created,
95
+ user: file.user,
96
+ channels: file.channels,
97
+ },
98
+ options.pretty,
99
+ ),
100
+ )
101
+ } catch (error) {
102
+ handleError(error as Error)
103
+ }
104
+ }
105
+
106
+ async function downloadAction(fileId: string, outputPath: string | undefined, options: BotOption): Promise<void> {
107
+ try {
108
+ const client = await getClient(options)
109
+ const { buffer, file } = await client.downloadFile(fileId)
110
+
111
+ const safeName = basename(file.name.replace(/\\/g, '/'))
112
+ let destPath = outputPath ? resolve(outputPath) : resolve(safeName)
113
+ let isDirectory = false
114
+ try {
115
+ isDirectory = statSync(destPath).isDirectory()
116
+ } catch (error) {
117
+ const err = error as NodeJS.ErrnoException
118
+ if (err.code !== 'ENOENT') {
119
+ throw error
120
+ }
121
+ }
122
+
123
+ if (isDirectory) {
124
+ destPath = join(destPath, safeName)
125
+ }
126
+
127
+ writeFileSync(destPath, buffer)
128
+
129
+ console.log(
130
+ formatOutput(
131
+ {
132
+ id: file.id,
133
+ name: file.name,
134
+ mimetype: file.mimetype,
135
+ size: file.size,
136
+ path: destPath,
137
+ },
138
+ options.pretty,
139
+ ),
140
+ )
141
+ } catch (error) {
142
+ handleError(error as Error)
143
+ }
144
+ }
145
+
146
+ async function deleteAction(fileId: string, options: BotOption & { force?: boolean }): Promise<void> {
147
+ try {
148
+ if (!options.force) {
149
+ console.log(formatOutput({ warning: 'Use --force to confirm deletion', file_id: fileId }, options.pretty))
150
+ process.exit(1)
151
+ }
152
+
153
+ const client = await getClient(options)
154
+ await client.deleteFile(fileId)
155
+
156
+ console.log(formatOutput({ deleted: fileId }, options.pretty))
157
+ } catch (error) {
158
+ handleError(error as Error)
159
+ }
160
+ }
161
+
162
+ export const fileCommand = new Command('file')
163
+ .description('File commands')
164
+ .addCommand(
165
+ new Command('upload')
166
+ .description('Upload file to a channel')
167
+ .argument('<channel>', 'Channel ID or name')
168
+ .argument('<path>', 'File path')
169
+ .option('--filename <name>', 'Override filename')
170
+ .option('--thread <ts>', 'Upload as a reply to a thread')
171
+ .option('--title <title>', 'File title')
172
+ .option('--comment <text>', 'Initial comment posted with the file')
173
+ .option('--bot <id>', 'Use specific bot')
174
+ .option('--pretty', 'Pretty print JSON output')
175
+ .action(uploadAction),
176
+ )
177
+ .addCommand(
178
+ new Command('list')
179
+ .description('List files visible to the bot')
180
+ .option('--channel <id>', 'Filter by channel ID or name')
181
+ .option('--user <id>', 'Filter by user ID')
182
+ .option('--limit <n>', 'Number of files to fetch')
183
+ .option('--bot <id>', 'Use specific bot')
184
+ .option('--pretty', 'Pretty print JSON output')
185
+ .action(listAction),
186
+ )
187
+ .addCommand(
188
+ new Command('info')
189
+ .description('Show file details')
190
+ .argument('<file>', 'File ID')
191
+ .option('--bot <id>', 'Use specific bot')
192
+ .option('--pretty', 'Pretty print JSON output')
193
+ .action(infoAction),
194
+ )
195
+ .addCommand(
196
+ new Command('download')
197
+ .description('Download a file by ID')
198
+ .argument('<file>', 'File ID')
199
+ .argument('[output-path]', 'Output file path or directory')
200
+ .option('--bot <id>', 'Use specific bot')
201
+ .option('--pretty', 'Pretty print JSON output')
202
+ .action(downloadAction),
203
+ )
204
+ .addCommand(
205
+ new Command('delete')
206
+ .description("Delete a file (bot's own files only)")
207
+ .argument('<file>', 'File ID')
208
+ .option('--force', 'Skip confirmation')
209
+ .option('--bot <id>', 'Use specific bot')
210
+ .option('--pretty', 'Pretty print JSON output')
211
+ .action(deleteAction),
212
+ )
@@ -1,5 +1,6 @@
1
1
  export { authCommand } from './auth'
2
2
  export { channelCommand } from './channel'
3
+ export { fileCommand } from './file'
3
4
  export { messageCommand } from './message'
4
5
  export { reactionCommand } from './reaction'
5
6
  export { userCommand } from './user'
@@ -98,6 +98,18 @@ async function deleteAction(channelInput: string, ts: string, options: BotOption
98
98
  }
99
99
  }
100
100
 
101
+ async function typingAction(channelInput: string, threadTs: string, status: string, options: BotOption): Promise<void> {
102
+ try {
103
+ const client = await getClient(options)
104
+ const channel = await client.resolveChannel(channelInput)
105
+ await client.setAssistantStatus(channel, threadTs, status)
106
+
107
+ console.log(formatOutput({ channel, thread_ts: threadTs, status }, options.pretty))
108
+ } catch (error) {
109
+ handleError(error as Error)
110
+ }
111
+ }
112
+
101
113
  async function repliesAction(
102
114
  channelInput: string,
103
115
  threadTs: string,
@@ -165,6 +177,16 @@ export const messageCommand = new Command('message')
165
177
  .option('--pretty', 'Pretty print JSON output')
166
178
  .action(deleteAction),
167
179
  )
180
+ .addCommand(
181
+ new Command('typing')
182
+ .description('Set typing status in an AI Assistant thread (e.g. "is typing...")')
183
+ .argument('<channel>', 'Channel ID or name')
184
+ .argument('<thread_ts>', 'Thread timestamp')
185
+ .argument('[status]', 'Status text (pass empty string to clear)', 'is typing...')
186
+ .option('--bot <id>', 'Use specific bot')
187
+ .option('--pretty', 'Pretty print JSON output')
188
+ .action(typingAction),
189
+ )
168
190
  .addCommand(
169
191
  new Command('replies')
170
192
  .description('Get thread replies')
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander'
2
2
 
3
- import { formatOutput } from '@/shared/utils/output'
3
+ import { cliOutput } from '@/shared/utils/cli-output'
4
4
 
5
5
  import type { BotOption } from './shared'
6
6
  import { getClient } from './shared'
@@ -30,11 +30,6 @@ export async function whoamiAction(options: BotOption): Promise<WhoamiResult> {
30
30
  }
31
31
  }
32
32
 
33
- function cliOutput(result: WhoamiResult, pretty?: boolean): void {
34
- console.log(formatOutput(result, pretty))
35
- if (result.error) process.exit(1)
36
- }
37
-
38
33
  export const whoamiCommand = new Command('whoami')
39
34
  .description('Show current authenticated bot')
40
35
  .option('--bot <id>', 'Bot ID to use')