agent-messenger 2.10.1 → 2.11.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 (536) 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 +14 -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 +80 -31
  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/decryptor.d.ts +6 -0
  199. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
  200. package/dist/src/shared/chromium/decryptor.js +26 -6
  201. package/dist/src/shared/chromium/decryptor.js.map +1 -1
  202. package/dist/src/shared/chromium/index.d.ts +3 -1
  203. package/dist/src/shared/chromium/index.d.ts.map +1 -1
  204. package/dist/src/shared/chromium/index.js +2 -1
  205. package/dist/src/shared/chromium/index.js.map +1 -1
  206. package/dist/src/shared/utils/cli-output.d.ts +7 -0
  207. package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
  208. package/dist/src/shared/utils/cli-output.js +7 -0
  209. package/dist/src/shared/utils/cli-output.js.map +1 -0
  210. package/dist/src/tui/app.d.ts.map +1 -1
  211. package/dist/src/tui/app.js +73 -20
  212. package/dist/src/tui/app.js.map +1 -1
  213. package/docs/content/docs/cli/channeltalk.mdx +4 -0
  214. package/docs/content/docs/cli/discord.mdx +5 -0
  215. package/docs/content/docs/cli/instagram.mdx +3 -0
  216. package/docs/content/docs/cli/slack.mdx +5 -0
  217. package/docs/content/docs/cli/slackbot.mdx +60 -22
  218. package/docs/content/docs/cli/teams.mdx +5 -0
  219. package/docs/content/docs/cli/webex.mdx +3 -0
  220. package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
  221. package/docs/content/docs/sdk/discordbot.mdx +501 -0
  222. package/docs/content/docs/sdk/meta.json +2 -0
  223. package/docs/content/docs/sdk/slackbot.mdx +576 -0
  224. package/e2e/README.md +1 -1
  225. package/e2e/channeltalk.e2e.test.ts +13 -13
  226. package/e2e/channeltalkbot.e2e.test.ts +13 -13
  227. package/e2e/config.ts +9 -4
  228. package/e2e/discord.e2e.test.ts +24 -24
  229. package/e2e/discordbot.e2e.test.ts +16 -16
  230. package/e2e/instagram.e2e.test.ts +10 -10
  231. package/e2e/kakaotalk.e2e.test.ts +7 -7
  232. package/e2e/line.e2e.test.ts +8 -8
  233. package/e2e/slack.e2e.test.ts +34 -34
  234. package/e2e/slackbot.e2e.test.ts +14 -14
  235. package/e2e/teams.e2e.test.ts +23 -23
  236. package/e2e/telegram.e2e.test.ts +8 -8
  237. package/e2e/webex.e2e.test.ts +14 -14
  238. package/e2e/whatsapp.e2e.test.ts +8 -8
  239. package/e2e/whatsappbot.e2e.test.ts +6 -6
  240. package/examples/discordbot-listen.ts +65 -0
  241. package/examples/slackbot-listen.ts +65 -0
  242. package/package.json +14 -1
  243. package/skills/agent-channeltalk/SKILL.md +5 -1
  244. package/skills/agent-channeltalk/references/authentication.md +5 -1
  245. package/skills/agent-channeltalkbot/SKILL.md +17 -3
  246. package/skills/agent-channeltalkbot/references/authentication.md +7 -5
  247. package/skills/agent-discord/SKILL.md +5 -1
  248. package/skills/agent-discord/references/authentication.md +7 -1
  249. package/skills/agent-discordbot/SKILL.md +13 -2
  250. package/skills/agent-discordbot/references/common-patterns.md +1 -1
  251. package/skills/agent-instagram/SKILL.md +7 -1
  252. package/skills/agent-instagram/references/authentication.md +6 -0
  253. package/skills/agent-kakaotalk/SKILL.md +1 -1
  254. package/skills/agent-line/SKILL.md +1 -1
  255. package/skills/agent-slack/SKILL.md +5 -1
  256. package/skills/agent-slack/references/authentication.md +7 -1
  257. package/skills/agent-slackbot/SKILL.md +56 -4
  258. package/skills/agent-slackbot/references/authentication.md +4 -0
  259. package/skills/agent-teams/SKILL.md +5 -1
  260. package/skills/agent-teams/references/authentication.md +7 -1
  261. package/skills/agent-telegram/SKILL.md +1 -1
  262. package/skills/agent-webex/SKILL.md +7 -1
  263. package/skills/agent-webex/references/authentication.md +6 -0
  264. package/skills/agent-wechatbot/SKILL.md +16 -1
  265. package/skills/agent-wechatbot/references/authentication.md +219 -0
  266. package/skills/agent-wechatbot/references/common-patterns.md +358 -0
  267. package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
  268. package/skills/agent-wechatbot/templates/post-message.sh +122 -0
  269. package/skills/agent-wechatbot/templates/send-template.sh +152 -0
  270. package/skills/agent-whatsapp/SKILL.md +1 -1
  271. package/skills/agent-whatsappbot/SKILL.md +30 -1
  272. package/src/platforms/channeltalk/client.test.ts +26 -26
  273. package/src/platforms/channeltalk/commands/auth.test.ts +31 -19
  274. package/src/platforms/channeltalk/commands/auth.ts +15 -5
  275. package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
  276. package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
  277. package/src/platforms/channeltalk/commands/group.test.ts +4 -4
  278. package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
  279. package/src/platforms/channeltalk/commands/message.test.ts +17 -17
  280. package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
  281. package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
  282. package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
  283. package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
  284. package/src/platforms/channeltalk/index.test.ts +23 -23
  285. package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
  286. package/src/platforms/channeltalk/token-extractor.ts +24 -5
  287. package/src/platforms/channeltalk/types.test.ts +12 -12
  288. package/src/platforms/channeltalkbot/cli.ts +9 -0
  289. package/src/platforms/channeltalkbot/client.test.ts +14 -14
  290. package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
  291. package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
  292. package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
  293. package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
  294. package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
  295. package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
  296. package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
  297. package/src/platforms/channeltalkbot/commands/group.ts +1 -6
  298. package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
  299. package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
  300. package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
  301. package/src/platforms/channeltalkbot/commands/message.ts +1 -6
  302. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
  303. package/src/platforms/channeltalkbot/commands/whoami.test.ts +6 -4
  304. package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
  305. package/src/platforms/channeltalkbot/credential-manager.test.ts +123 -29
  306. package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
  307. package/src/platforms/channeltalkbot/index.test.ts +15 -15
  308. package/src/platforms/discord/client.test.ts +28 -28
  309. package/src/platforms/discord/commands/auth.test.ts +7 -7
  310. package/src/platforms/discord/commands/auth.ts +13 -2
  311. package/src/platforms/discord/commands/channel.test.ts +7 -7
  312. package/src/platforms/discord/commands/dm.test.ts +4 -4
  313. package/src/platforms/discord/commands/file.test.ts +4 -4
  314. package/src/platforms/discord/commands/friend.test.ts +6 -6
  315. package/src/platforms/discord/commands/member.test.ts +5 -5
  316. package/src/platforms/discord/commands/mention.test.ts +5 -5
  317. package/src/platforms/discord/commands/message.test.ts +9 -9
  318. package/src/platforms/discord/commands/note.test.ts +6 -6
  319. package/src/platforms/discord/commands/profile.test.ts +4 -4
  320. package/src/platforms/discord/commands/reaction.test.ts +5 -5
  321. package/src/platforms/discord/commands/server.test.ts +7 -7
  322. package/src/platforms/discord/commands/snapshot.test.ts +6 -6
  323. package/src/platforms/discord/commands/thread.test.ts +6 -6
  324. package/src/platforms/discord/commands/user.test.ts +5 -5
  325. package/src/platforms/discord/commands/whoami.test.ts +6 -6
  326. package/src/platforms/discord/credential-manager.test.ts +16 -16
  327. package/src/platforms/discord/ensure-auth.test.ts +8 -8
  328. package/src/platforms/discord/index.test.ts +17 -17
  329. package/src/platforms/discord/listener.test.ts +92 -34
  330. package/src/platforms/discord/listener.ts +43 -19
  331. package/src/platforms/discord/token-extractor.test.ts +53 -53
  332. package/src/platforms/discord/token-extractor.ts +30 -6
  333. package/src/platforms/discord/types.test.ts +26 -26
  334. package/src/platforms/discordbot/cli.ts +10 -0
  335. package/src/platforms/discordbot/client.test.ts +31 -31
  336. package/src/platforms/discordbot/client.ts +4 -0
  337. package/src/platforms/discordbot/commands/auth.test.ts +18 -18
  338. package/src/platforms/discordbot/commands/auth.ts +1 -5
  339. package/src/platforms/discordbot/commands/channel.test.ts +11 -11
  340. package/src/platforms/discordbot/commands/file.test.ts +7 -7
  341. package/src/platforms/discordbot/commands/message.test.ts +25 -25
  342. package/src/platforms/discordbot/commands/message.ts +1 -6
  343. package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
  344. package/src/platforms/discordbot/commands/server.test.ts +12 -12
  345. package/src/platforms/discordbot/commands/server.ts +1 -5
  346. package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
  347. package/src/platforms/discordbot/commands/thread.test.ts +10 -10
  348. package/src/platforms/discordbot/commands/user.test.ts +9 -9
  349. package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
  350. package/src/platforms/discordbot/commands/whoami.ts +1 -6
  351. package/src/platforms/discordbot/credential-manager.test.ts +28 -28
  352. package/src/platforms/discordbot/index.test.ts +82 -0
  353. package/src/platforms/discordbot/index.ts +27 -9
  354. package/src/platforms/discordbot/listener.test.ts +1002 -0
  355. package/src/platforms/discordbot/listener.ts +321 -0
  356. package/src/platforms/discordbot/types.ts +163 -0
  357. package/src/platforms/instagram/client.test.ts +18 -18
  358. package/src/platforms/instagram/commands/auth.test.ts +11 -11
  359. package/src/platforms/instagram/commands/auth.ts +9 -1
  360. package/src/platforms/instagram/commands/chat.test.ts +6 -6
  361. package/src/platforms/instagram/commands/message.test.ts +11 -11
  362. package/src/platforms/instagram/commands/shared.test.ts +12 -12
  363. package/src/platforms/instagram/commands/whoami.test.ts +3 -3
  364. package/src/platforms/instagram/credential-manager.test.ts +21 -21
  365. package/src/platforms/instagram/ensure-auth.test.ts +4 -4
  366. package/src/platforms/instagram/index.test.ts +9 -9
  367. package/src/platforms/instagram/listener.test.ts +8 -8
  368. package/src/platforms/instagram/token-extractor.test.ts +35 -35
  369. package/src/platforms/instagram/token-extractor.ts +13 -1
  370. package/src/platforms/kakaotalk/client.test.ts +33 -33
  371. package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
  372. package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
  373. package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
  374. package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
  375. package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
  376. package/src/platforms/kakaotalk/index.test.ts +15 -15
  377. package/src/platforms/kakaotalk/listener.test.ts +17 -17
  378. package/src/platforms/line/client.test.ts +17 -17
  379. package/src/platforms/line/commands/auth.test.ts +8 -8
  380. package/src/platforms/line/commands/chat.test.ts +7 -7
  381. package/src/platforms/line/commands/friend.test.ts +6 -6
  382. package/src/platforms/line/commands/message.test.ts +7 -7
  383. package/src/platforms/line/commands/whoami.test.ts +6 -6
  384. package/src/platforms/line/credential-manager.test.ts +17 -17
  385. package/src/platforms/line/index.test.ts +10 -10
  386. package/src/platforms/line/listener.test.ts +15 -15
  387. package/src/platforms/line/types.test.ts +14 -14
  388. package/src/platforms/slack/cli.test.ts +8 -8
  389. package/src/platforms/slack/client.test.ts +151 -151
  390. package/src/platforms/slack/commands/activity.test.ts +13 -13
  391. package/src/platforms/slack/commands/auth.test.ts +34 -34
  392. package/src/platforms/slack/commands/auth.ts +11 -2
  393. package/src/platforms/slack/commands/bookmark.test.ts +9 -9
  394. package/src/platforms/slack/commands/channel.test.ts +17 -17
  395. package/src/platforms/slack/commands/drafts.test.ts +7 -7
  396. package/src/platforms/slack/commands/emoji.test.ts +3 -3
  397. package/src/platforms/slack/commands/file.test.ts +12 -12
  398. package/src/platforms/slack/commands/message.test.ts +19 -19
  399. package/src/platforms/slack/commands/pin.test.ts +7 -7
  400. package/src/platforms/slack/commands/reaction.test.ts +10 -10
  401. package/src/platforms/slack/commands/reminder.test.ts +9 -9
  402. package/src/platforms/slack/commands/saved.test.ts +7 -7
  403. package/src/platforms/slack/commands/sections.test.ts +5 -5
  404. package/src/platforms/slack/commands/snapshot.test.ts +13 -13
  405. package/src/platforms/slack/commands/unread.test.ts +6 -6
  406. package/src/platforms/slack/commands/user.test.ts +10 -10
  407. package/src/platforms/slack/commands/usergroup.test.ts +15 -15
  408. package/src/platforms/slack/commands/whoami.test.ts +6 -6
  409. package/src/platforms/slack/commands/workspace.test.ts +26 -26
  410. package/src/platforms/slack/credential-manager.test.ts +14 -14
  411. package/src/platforms/slack/ensure-auth.test.ts +21 -21
  412. package/src/platforms/slack/index.test.ts +12 -12
  413. package/src/platforms/slack/listener.test.ts +17 -17
  414. package/src/platforms/slack/token-extractor-node.test.ts +2 -2
  415. package/src/platforms/slack/token-extractor.test.ts +133 -37
  416. package/src/platforms/slack/token-extractor.ts +76 -13
  417. package/src/platforms/slack/types.test.ts +21 -21
  418. package/src/platforms/slackbot/cli.ts +13 -1
  419. package/src/platforms/slackbot/client.test.ts +296 -22
  420. package/src/platforms/slackbot/client.ts +130 -2
  421. package/src/platforms/slackbot/commands/auth.test.ts +14 -14
  422. package/src/platforms/slackbot/commands/auth.ts +1 -5
  423. package/src/platforms/slackbot/commands/channel.test.ts +7 -7
  424. package/src/platforms/slackbot/commands/file.test.ts +201 -0
  425. package/src/platforms/slackbot/commands/file.ts +212 -0
  426. package/src/platforms/slackbot/commands/index.ts +1 -0
  427. package/src/platforms/slackbot/commands/message.test.ts +13 -13
  428. package/src/platforms/slackbot/commands/message.ts +22 -0
  429. package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
  430. package/src/platforms/slackbot/commands/user.test.ts +7 -7
  431. package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
  432. package/src/platforms/slackbot/commands/whoami.ts +1 -6
  433. package/src/platforms/slackbot/credential-manager.test.ts +83 -23
  434. package/src/platforms/slackbot/credential-manager.ts +32 -2
  435. package/src/platforms/slackbot/index.test.ts +59 -0
  436. package/src/platforms/slackbot/index.ts +31 -7
  437. package/src/platforms/slackbot/listener.test.ts +1012 -0
  438. package/src/platforms/slackbot/listener.ts +362 -0
  439. package/src/platforms/slackbot/types.test.ts +7 -7
  440. package/src/platforms/slackbot/types.ts +224 -1
  441. package/src/platforms/teams/client.test.ts +30 -30
  442. package/src/platforms/teams/commands/auth.test.ts +9 -9
  443. package/src/platforms/teams/commands/auth.ts +66 -7
  444. package/src/platforms/teams/commands/channel.test.ts +7 -7
  445. package/src/platforms/teams/commands/file.test.ts +4 -4
  446. package/src/platforms/teams/commands/message.test.ts +5 -5
  447. package/src/platforms/teams/commands/reaction.test.ts +4 -4
  448. package/src/platforms/teams/commands/snapshot.test.ts +7 -7
  449. package/src/platforms/teams/commands/team.test.ts +8 -8
  450. package/src/platforms/teams/commands/user.test.ts +4 -4
  451. package/src/platforms/teams/commands/whoami.test.ts +6 -6
  452. package/src/platforms/teams/credential-manager.test.ts +17 -17
  453. package/src/platforms/teams/ensure-auth.test.ts +69 -18
  454. package/src/platforms/teams/ensure-auth.ts +39 -11
  455. package/src/platforms/teams/index.test.ts +15 -15
  456. package/src/platforms/teams/token-extractor.test.ts +251 -69
  457. package/src/platforms/teams/token-extractor.ts +94 -31
  458. package/src/platforms/teams/types.test.ts +26 -26
  459. package/src/platforms/telegram/app-config.test.ts +4 -4
  460. package/src/platforms/telegram/chat-utils.test.ts +12 -12
  461. package/src/platforms/telegram/client.test.ts +4 -4
  462. package/src/platforms/telegram/commands/auth.test.ts +16 -16
  463. package/src/platforms/telegram/commands/chat.test.ts +9 -9
  464. package/src/platforms/telegram/commands/message.test.ts +6 -6
  465. package/src/platforms/telegram/commands/shared.test.ts +3 -3
  466. package/src/platforms/telegram/commands/whoami.test.ts +3 -3
  467. package/src/platforms/telegram/credential-manager.test.ts +10 -10
  468. package/src/platforms/telegram/types.test.ts +6 -6
  469. package/src/platforms/webex/app-config.test.ts +8 -8
  470. package/src/platforms/webex/cli.test.ts +5 -5
  471. package/src/platforms/webex/client.test.ts +65 -65
  472. package/src/platforms/webex/commands/auth.test.ts +18 -18
  473. package/src/platforms/webex/commands/auth.ts +13 -2
  474. package/src/platforms/webex/commands/member.test.ts +5 -5
  475. package/src/platforms/webex/commands/message.test.ts +12 -12
  476. package/src/platforms/webex/commands/snapshot.test.ts +5 -5
  477. package/src/platforms/webex/commands/space.test.ts +10 -10
  478. package/src/platforms/webex/commands/whoami.test.ts +6 -6
  479. package/src/platforms/webex/credential-manager.test.ts +22 -22
  480. package/src/platforms/webex/encryption.test.ts +4 -4
  481. package/src/platforms/webex/ensure-auth.test.ts +5 -5
  482. package/src/platforms/webex/index.test.ts +5 -5
  483. package/src/platforms/webex/markdown-to-html.test.ts +33 -33
  484. package/src/platforms/webex/token-extractor.test.ts +23 -23
  485. package/src/platforms/webex/token-extractor.ts +25 -3
  486. package/src/platforms/webex/types.test.ts +27 -27
  487. package/src/platforms/wechatbot/cli.ts +9 -0
  488. package/src/platforms/wechatbot/client.test.ts +27 -27
  489. package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
  490. package/src/platforms/wechatbot/commands/auth.ts +1 -5
  491. package/src/platforms/wechatbot/commands/message.test.ts +8 -8
  492. package/src/platforms/wechatbot/commands/message.ts +1 -6
  493. package/src/platforms/wechatbot/commands/template.test.ts +9 -9
  494. package/src/platforms/wechatbot/commands/template.ts +1 -6
  495. package/src/platforms/wechatbot/commands/user.test.ts +7 -7
  496. package/src/platforms/wechatbot/commands/user.ts +1 -6
  497. package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
  498. package/src/platforms/wechatbot/commands/whoami.ts +1 -6
  499. package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
  500. package/src/platforms/wechatbot/index.test.ts +10 -10
  501. package/src/platforms/wechatbot/types.test.ts +25 -25
  502. package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
  503. package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
  504. package/src/platforms/whatsapp/commands/message.test.ts +10 -10
  505. package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
  506. package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
  507. package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
  508. package/src/platforms/whatsapp/index.test.ts +8 -8
  509. package/src/platforms/whatsapp/types.test.ts +42 -42
  510. package/src/platforms/whatsappbot/cli.ts +9 -0
  511. package/src/platforms/whatsappbot/client.test.ts +27 -27
  512. package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
  513. package/src/platforms/whatsappbot/commands/auth.ts +1 -5
  514. package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
  515. package/src/platforms/whatsappbot/commands/message.ts +1 -6
  516. package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
  517. package/src/platforms/whatsappbot/commands/template.ts +1 -6
  518. package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
  519. package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
  520. package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
  521. package/src/platforms/whatsappbot/index.test.ts +7 -7
  522. package/src/platforms/whatsappbot/types.test.ts +18 -18
  523. package/src/shared/chromium/browsers.test.ts +102 -22
  524. package/src/shared/chromium/browsers.ts +72 -3
  525. package/src/shared/chromium/cli-options.test.ts +22 -0
  526. package/src/shared/chromium/cli-options.ts +12 -0
  527. package/src/shared/chromium/cookie-reader.test.ts +13 -13
  528. package/src/shared/chromium/decryptor.test.ts +97 -32
  529. package/src/shared/chromium/decryptor.ts +27 -6
  530. package/src/shared/chromium/index.ts +3 -0
  531. package/src/shared/utils/cli-output.test.ts +57 -0
  532. package/src/shared/utils/cli-output.ts +8 -0
  533. package/src/shared/utils/concurrency.test.ts +6 -6
  534. package/src/shared/utils/derived-key-cache.test.ts +11 -11
  535. package/src/tui/app.ts +129 -20
  536. package/src/tui/utils.test.ts +31 -31
@@ -1,6 +1,6 @@
1
- import { existsSync, readdirSync } from 'node:fs'
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs'
2
2
  import { homedir } from 'node:os'
3
- import { join } from 'node:path'
3
+ import { dirname, isAbsolute, join, resolve } from 'node:path'
4
4
 
5
5
  import type { BrowserConfig, KeychainVariant } from './types'
6
6
 
@@ -39,6 +39,17 @@ export const BROWSER_KEYCHAIN_VARIANTS: KeychainVariant[] = [
39
39
  { service: 'Chromium Safe Storage', account: 'Chromium' },
40
40
  ]
41
41
 
42
+ interface AgentBrowserProfileDiscoveryOptions {
43
+ cwd?: string
44
+ env?: NodeJS.ProcessEnv
45
+ homeDir?: string
46
+ customProfileDirs?: string[]
47
+ }
48
+
49
+ type AgentBrowserConfig = {
50
+ profile?: unknown
51
+ }
52
+
42
53
  export function getBrowserBasePath(browser: BrowserConfig, platform: NodeJS.Platform): string | null {
43
54
  let relative: string
44
55
  switch (platform) {
@@ -70,10 +81,41 @@ export function discoverBrowserProfileDirs(browserBase: string): string[] {
70
81
  if (!/^Profile \d+$/i.test(entry.name)) continue
71
82
  dirs.push(join(browserBase, entry.name))
72
83
  }
73
- } catch {}
84
+ } catch {
85
+ return dirs
86
+ }
74
87
  return dirs
75
88
  }
76
89
 
90
+ export function getAgentBrowserProfileDirs(options: AgentBrowserProfileDiscoveryOptions = {}): string[] {
91
+ const cwd = options.cwd ?? process.cwd()
92
+ const env = options.env ?? process.env
93
+ const homeDir = options.homeDir ?? homedir()
94
+ if (env.AGENT_MESSENGER_DISABLE_AGENT_BROWSER_PROFILE_DISCOVERY === '1') return []
95
+
96
+ const profileDirs: string[] = []
97
+
98
+ for (const profileDir of options.customProfileDirs ?? []) {
99
+ addAgentBrowserProfileDir(profileDirs, profileDir, cwd)
100
+ }
101
+
102
+ addAgentBrowserProfileDir(profileDirs, env.AGENT_BROWSER_PROFILE, cwd)
103
+
104
+ const configPaths = [
105
+ join(homeDir, '.agent-browser', 'config.json'),
106
+ join(cwd, 'agent-browser.json'),
107
+ env.AGENT_BROWSER_CONFIG,
108
+ ]
109
+
110
+ for (const configPath of configPaths) {
111
+ if (!configPath) continue
112
+ const config = readAgentBrowserConfig(configPath)
113
+ addAgentBrowserProfileDir(profileDirs, config?.profile, dirname(configPath))
114
+ }
115
+
116
+ return dedupePaths(profileDirs.flatMap((profileDir) => [profileDir, ...discoverBrowserProfileDirs(profileDir)]))
117
+ }
118
+
77
119
  export function findLocalStatePath(cookieOrProfilePath: string): string | null {
78
120
  const parts = cookieOrProfilePath.split(/[/\\]/)
79
121
  for (let levels = 2; levels <= 4; levels++) {
@@ -84,3 +126,30 @@ export function findLocalStatePath(cookieOrProfilePath: string): string | null {
84
126
  }
85
127
  return null
86
128
  }
129
+
130
+ function readAgentBrowserConfig(configPath: string): AgentBrowserConfig | null {
131
+ if (!existsSync(configPath)) return null
132
+ try {
133
+ const parsed = JSON.parse(readFileSync(configPath, 'utf8')) as unknown
134
+ if (!parsed || typeof parsed !== 'object') return null
135
+ return parsed as AgentBrowserConfig
136
+ } catch {
137
+ return null
138
+ }
139
+ }
140
+
141
+ function addAgentBrowserProfileDir(dirs: string[], profile: unknown, baseDir: string): void {
142
+ if (typeof profile !== 'string' || profile.length === 0) return
143
+ dirs.push(isAbsolute(profile) ? profile : resolve(baseDir, profile))
144
+ }
145
+
146
+ function dedupePaths(paths: string[]): string[] {
147
+ const seen = new Set<string>()
148
+ const result: string[] = []
149
+ for (const path of paths) {
150
+ if (seen.has(path)) continue
151
+ seen.add(path)
152
+ result.push(path)
153
+ }
154
+ return result
155
+ }
@@ -0,0 +1,22 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+
3
+ import { collectBrowserProfileOption } from './cli-options'
4
+
5
+ describe('collectBrowserProfileOption', () => {
6
+ it('collects repeated browser profile options', () => {
7
+ // when
8
+ const first = collectBrowserProfileOption('/tmp/profile-a')
9
+ const second = collectBrowserProfileOption('/tmp/profile-b', first)
10
+
11
+ // then
12
+ expect(second).toEqual(['/tmp/profile-a', '/tmp/profile-b'])
13
+ })
14
+
15
+ it('splits comma-separated browser profile options', () => {
16
+ // when
17
+ const profiles = collectBrowserProfileOption('/tmp/profile-a, /tmp/profile-b,,')
18
+
19
+ // then
20
+ expect(profiles).toEqual(['/tmp/profile-a', '/tmp/profile-b'])
21
+ })
22
+ })
@@ -0,0 +1,12 @@
1
+ export interface BrowserProfileOption {
2
+ browserProfile?: string[]
3
+ }
4
+
5
+ export function collectBrowserProfileOption(value: string, previous: string[] = []): string[] {
6
+ const paths = value
7
+ .split(',')
8
+ .map((path) => path.trim())
9
+ .filter((path) => path.length > 0)
10
+
11
+ return [...previous, ...paths]
12
+ }
@@ -1,5 +1,5 @@
1
1
  import { Database } from 'bun:sqlite'
2
- import { afterEach, describe, expect, test } from 'bun:test'
2
+ import { afterEach, describe, expect, it } from 'bun:test'
3
3
  import { existsSync, mkdtempSync, rmSync } from 'node:fs'
4
4
  import { tmpdir } from 'node:os'
5
5
  import { join } from 'node:path'
@@ -31,7 +31,7 @@ describe('ChromiumCookieReader', () => {
31
31
  })
32
32
 
33
33
  describe('queryAll', () => {
34
- test('returns all matching rows from a real SQLite database', async () => {
34
+ it('returns all matching rows from a real SQLite database', async () => {
35
35
  // given
36
36
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
37
37
  tempDirs.push(tempDir)
@@ -55,7 +55,7 @@ describe('ChromiumCookieReader', () => {
55
55
  ])
56
56
  })
57
57
 
58
- test('returns empty array when database file does not exist', async () => {
58
+ it('returns empty array when database file does not exist', async () => {
59
59
  // given
60
60
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
61
61
  tempDirs.push(tempDir)
@@ -69,7 +69,7 @@ describe('ChromiumCookieReader', () => {
69
69
  expect(result).toEqual([])
70
70
  })
71
71
 
72
- test('returns empty array when query matches no rows', async () => {
72
+ it('returns empty array when query matches no rows', async () => {
73
73
  // given
74
74
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
75
75
  tempDirs.push(tempDir)
@@ -86,7 +86,7 @@ describe('ChromiumCookieReader', () => {
86
86
  expect(result).toEqual([])
87
87
  })
88
88
 
89
- test('supports parameterized queries with params', async () => {
89
+ it('supports parameterized queries with params', async () => {
90
90
  // given
91
91
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
92
92
  tempDirs.push(tempDir)
@@ -108,7 +108,7 @@ describe('ChromiumCookieReader', () => {
108
108
  expect(result).toEqual([{ name: 'token', value: 'xyz789' }])
109
109
  })
110
110
 
111
- test('cleans up temp file after query', async () => {
111
+ it('cleans up temp file after query', async () => {
112
112
  // given
113
113
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
114
114
  tempDirs.push(tempDir)
@@ -135,7 +135,7 @@ describe('ChromiumCookieReader', () => {
135
135
  })
136
136
 
137
137
  describe('queryFirst', () => {
138
- test('returns first matching row from a real SQLite database', async () => {
138
+ it('returns first matching row from a real SQLite database', async () => {
139
139
  // given
140
140
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
141
141
  tempDirs.push(tempDir)
@@ -156,7 +156,7 @@ describe('ChromiumCookieReader', () => {
156
156
  expect(result).toEqual({ name: 'session', value: 'abc123' })
157
157
  })
158
158
 
159
- test('returns null when database file does not exist', async () => {
159
+ it('returns null when database file does not exist', async () => {
160
160
  // given
161
161
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
162
162
  tempDirs.push(tempDir)
@@ -170,7 +170,7 @@ describe('ChromiumCookieReader', () => {
170
170
  expect(result).toBeNull()
171
171
  })
172
172
 
173
- test('returns null when query matches no rows', async () => {
173
+ it('returns null when query matches no rows', async () => {
174
174
  // given
175
175
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
176
176
  tempDirs.push(tempDir)
@@ -187,7 +187,7 @@ describe('ChromiumCookieReader', () => {
187
187
  expect(result).toBeNull()
188
188
  })
189
189
 
190
- test('supports parameterized queries with params', async () => {
190
+ it('supports parameterized queries with params', async () => {
191
191
  // given
192
192
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
193
193
  tempDirs.push(tempDir)
@@ -211,7 +211,7 @@ describe('ChromiumCookieReader', () => {
211
211
  })
212
212
 
213
213
  describe('edge cases', () => {
214
- test('handles multiple calls to same reader instance', async () => {
214
+ it('handles multiple calls to same reader instance', async () => {
215
215
  // given
216
216
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
217
217
  tempDirs.push(tempDir)
@@ -241,7 +241,7 @@ describe('ChromiumCookieReader', () => {
241
241
  expect(firstRow).toEqual({ name: 'token', value: 'xyz789' })
242
242
  })
243
243
 
244
- test('returns empty array for malformed SQL without throwing', async () => {
244
+ it('returns empty array for malformed SQL without throwing', async () => {
245
245
  // given
246
246
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
247
247
  tempDirs.push(tempDir)
@@ -256,7 +256,7 @@ describe('ChromiumCookieReader', () => {
256
256
  expect(result).toEqual([])
257
257
  })
258
258
 
259
- test('returns null for malformed SQL without throwing', async () => {
259
+ it('returns null for malformed SQL without throwing', async () => {
260
260
  // given
261
261
  const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
262
262
  tempDirs.push(tempDir)
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, spyOn, test } from 'bun:test'
1
+ import { beforeEach, describe, expect, spyOn, it } from 'bun:test'
2
2
  import { createCipheriv, pbkdf2Sync, randomBytes } from 'node:crypto'
3
3
 
4
4
  import * as linuxKeyring from '@/shared/utils/linux-keyring'
@@ -29,7 +29,7 @@ describe('ChromiumCookieDecryptor', () => {
29
29
  })
30
30
 
31
31
  describe('constructor', () => {
32
- test('prepends appKeychainVariants before browser variants', () => {
32
+ it('prepends appKeychainVariants before browser variants', () => {
33
33
  // given
34
34
  const appVariants = [{ service: 'App Safe Storage', account: 'App' }]
35
35
 
@@ -40,7 +40,7 @@ describe('ChromiumCookieDecryptor', () => {
40
40
  expect((decryptor as any).keychainVariants).toEqual([...appVariants, ...BROWSER_KEYCHAIN_VARIANTS])
41
41
  })
42
42
 
43
- test('uses only browser variants when no appKeychainVariants provided', () => {
43
+ it('uses only browser variants when no appKeychainVariants provided', () => {
44
44
  // given
45
45
  const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin' })
46
46
 
@@ -50,7 +50,7 @@ describe('ChromiumCookieDecryptor', () => {
50
50
  })
51
51
 
52
52
  describe('isEncryptedValue', () => {
53
- test('returns true for v10 prefix with sufficient length', () => {
53
+ it('returns true for v10 prefix with sufficient length', () => {
54
54
  // given
55
55
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
56
56
 
@@ -61,7 +61,7 @@ describe('ChromiumCookieDecryptor', () => {
61
61
  expect(result).toBe(true)
62
62
  })
63
63
 
64
- test('returns true for v11 prefix with sufficient length', () => {
64
+ it('returns true for v11 prefix with sufficient length', () => {
65
65
  // given
66
66
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
67
67
 
@@ -72,7 +72,7 @@ describe('ChromiumCookieDecryptor', () => {
72
72
  expect(result).toBe(true)
73
73
  })
74
74
 
75
- test('returns false for non-v10/v11 prefix', () => {
75
+ it('returns false for non-v10/v11 prefix', () => {
76
76
  // given
77
77
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
78
78
 
@@ -83,7 +83,7 @@ describe('ChromiumCookieDecryptor', () => {
83
83
  expect(result).toBe(false)
84
84
  })
85
85
 
86
- test('returns false for too-short buffer (< 4 bytes)', () => {
86
+ it('returns false for too-short buffer (< 4 bytes)', () => {
87
87
  // given
88
88
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
89
89
 
@@ -94,7 +94,7 @@ describe('ChromiumCookieDecryptor', () => {
94
94
  expect(result).toBe(false)
95
95
  })
96
96
 
97
- test('returns false for null/empty buffer', () => {
97
+ it('returns false for null/empty buffer', () => {
98
98
  // given
99
99
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
100
100
 
@@ -105,7 +105,7 @@ describe('ChromiumCookieDecryptor', () => {
105
105
  })
106
106
 
107
107
  describe('decryptAESCBC / decryptAESCBCRaw', () => {
108
- test('decrypts v10-prefixed AES-128-CBC data with correct key', () => {
108
+ it('decrypts v10-prefixed AES-128-CBC data with correct key', () => {
109
109
  // given
110
110
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
111
111
  const encrypted = encryptAESCBC('test-value', peanutsKey)
@@ -117,7 +117,7 @@ describe('ChromiumCookieDecryptor', () => {
117
117
  expect(result).toBe('test-value')
118
118
  })
119
119
 
120
- test('returns null with wrong key', () => {
120
+ it('returns null with wrong key', () => {
121
121
  // given
122
122
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
123
123
  const encrypted = encryptAESCBC('test-value', peanutsKey)
@@ -130,7 +130,7 @@ describe('ChromiumCookieDecryptor', () => {
130
130
  expect(result).toBeNull()
131
131
  })
132
132
 
133
- test('returns null for corrupted ciphertext', () => {
133
+ it('returns null for corrupted ciphertext', () => {
134
134
  // given
135
135
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
136
136
  const encrypted = encryptAESCBC('test-value', peanutsKey)
@@ -144,7 +144,7 @@ describe('ChromiumCookieDecryptor', () => {
144
144
  expect(result).toBeNull()
145
145
  })
146
146
 
147
- test('decryptAESCBC returns string, decryptAESCBCRaw returns Buffer', () => {
147
+ it('decryptAESCBC returns string, decryptAESCBCRaw returns Buffer', () => {
148
148
  // given
149
149
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
150
150
  const encrypted = encryptAESCBC('test-value', peanutsKey)
@@ -160,7 +160,7 @@ describe('ChromiumCookieDecryptor', () => {
160
160
  })
161
161
 
162
162
  describe('decryptAESGCM / decryptAESGCMRaw', () => {
163
- test('decrypts v10-prefixed AES-256-GCM data with correct key', () => {
163
+ it('decrypts v10-prefixed AES-256-GCM data with correct key', () => {
164
164
  // given
165
165
  const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
166
166
  const masterKey = randomBytes(32)
@@ -173,7 +173,7 @@ describe('ChromiumCookieDecryptor', () => {
173
173
  expect(result).toBe('test-value')
174
174
  })
175
175
 
176
- test('returns null with wrong key', () => {
176
+ it('returns null with wrong key', () => {
177
177
  // given
178
178
  const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
179
179
  const masterKey = randomBytes(32)
@@ -186,7 +186,7 @@ describe('ChromiumCookieDecryptor', () => {
186
186
  expect(result).toBeNull()
187
187
  })
188
188
 
189
- test('returns null for data shorter than minimum length (3+12+16 = 31 bytes)', () => {
189
+ it('returns null for data shorter than minimum length (3+12+16 = 31 bytes)', () => {
190
190
  // given
191
191
  const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
192
192
 
@@ -197,7 +197,7 @@ describe('ChromiumCookieDecryptor', () => {
197
197
  expect(result).toBeNull()
198
198
  })
199
199
 
200
- test('decryptAESGCM returns string, decryptAESGCMRaw returns Buffer', () => {
200
+ it('decryptAESGCM returns string, decryptAESGCMRaw returns Buffer', () => {
201
201
  // given
202
202
  const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
203
203
  const masterKey = randomBytes(32)
@@ -214,7 +214,7 @@ describe('ChromiumCookieDecryptor', () => {
214
214
  })
215
215
 
216
216
  describe('decryptCookie / decryptCookieRaw', () => {
217
- test('returns plaintext for non-encrypted values (no v10/v11 prefix)', () => {
217
+ it('returns plaintext for non-encrypted values (no v10/v11 prefix)', () => {
218
218
  // given
219
219
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
220
220
  const plaintext = Buffer.from('plain-cookie')
@@ -228,7 +228,7 @@ describe('ChromiumCookieDecryptor', () => {
228
228
  expect(rawResult).toEqual(plaintext)
229
229
  })
230
230
 
231
- test('dispatches to Linux decryption for linux platform with v10 prefix', () => {
231
+ it('dispatches to Linux decryption for linux platform with v10 prefix', () => {
232
232
  // given
233
233
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
234
234
  const encrypted = Buffer.from('v10cookie')
@@ -242,7 +242,7 @@ describe('ChromiumCookieDecryptor', () => {
242
242
  spy.mockRestore()
243
243
  })
244
244
 
245
- test('returns null for unsupported platform (e.g. freebsd)', () => {
245
+ it('returns null for unsupported platform (e.g. freebsd)', () => {
246
246
  // given
247
247
  const decryptor = new ChromiumCookieDecryptor({ platform: 'freebsd' as NodeJS.Platform })
248
248
 
@@ -253,7 +253,7 @@ describe('ChromiumCookieDecryptor', () => {
253
253
  expect(result).toBeNull()
254
254
  })
255
255
 
256
- test('decryptCookie returns string, decryptCookieRaw returns Buffer', () => {
256
+ it('decryptCookie returns string, decryptCookieRaw returns Buffer', () => {
257
257
  // given
258
258
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
259
259
  const encrypted = encryptAESCBC('test-value', peanutsKey)
@@ -269,7 +269,7 @@ describe('ChromiumCookieDecryptor', () => {
269
269
  })
270
270
 
271
271
  describe('decryptLinuxCookieRaw', () => {
272
- test('decrypts v10-prefixed cookie using peanuts key (known key, verifiable)', () => {
272
+ it('decrypts v10-prefixed cookie using peanuts key (known key, verifiable)', () => {
273
273
  // given
274
274
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
275
275
  const encrypted = encryptAESCBC('linux-cookie', peanutsKey)
@@ -281,7 +281,7 @@ describe('ChromiumCookieDecryptor', () => {
281
281
  expect(result).toEqual(Buffer.from('linux-cookie'))
282
282
  })
283
283
 
284
- test('falls back to peanuts key for v11 when no keyring app names configured', () => {
284
+ it('falls back to peanuts key for v11 when no keyring app names configured', () => {
285
285
  // given
286
286
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
287
287
  const encrypted = encryptAESCBC('linux-v11-cookie', peanutsKey, 'v11')
@@ -295,7 +295,7 @@ describe('ChromiumCookieDecryptor', () => {
295
295
  })
296
296
 
297
297
  describe('decryptDPAPI', () => {
298
- test('returns null on non-win32 platforms', () => {
298
+ it('returns null on non-win32 platforms', () => {
299
299
  // given
300
300
  const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
301
301
 
@@ -307,8 +307,73 @@ describe('ChromiumCookieDecryptor', () => {
307
307
  })
308
308
  })
309
309
 
310
+ describe('extractDPAPIPayload', () => {
311
+ it('extracts payload wrapped in markers', () => {
312
+ // given
313
+ const b64 = Buffer.from('hello').toString('base64')
314
+ const stdout = `<<<B64>>>${b64}<<<END>>>\r\n`
315
+
316
+ // when
317
+ const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
318
+
319
+ // then
320
+ expect(result).toBe(b64)
321
+ })
322
+
323
+ it('strips CLIXML progress-stream contamination before the payload', () => {
324
+ // given: PowerShell emits CLIXML on first module auto-load
325
+ const b64 = Buffer.from('secret-token').toString('base64')
326
+ const stdout =
327
+ '#< CLIXML\r\n' +
328
+ '<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">' +
329
+ '<Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T>' +
330
+ '<T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record">' +
331
+ '<AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC>' +
332
+ '<T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>' +
333
+ `<<<B64>>>${b64}<<<END>>>\r\n`
334
+
335
+ // when
336
+ const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
337
+
338
+ // then
339
+ expect(result).toBe(b64)
340
+ })
341
+
342
+ it('tolerates whitespace and line breaks inside the payload', () => {
343
+ // given
344
+ const b64 = Buffer.from('hello').toString('base64')
345
+ const chunked = b64.slice(0, 3) + '\r\n' + b64.slice(3)
346
+ const stdout = `<<<B64>>>${chunked}<<<END>>>`
347
+
348
+ // when
349
+ const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
350
+
351
+ // then
352
+ expect(result).toBe(b64)
353
+ })
354
+
355
+ it('returns null when markers are missing', () => {
356
+ // given: stdout contains only CLIXML noise, no real payload
357
+ const stdout = '#< CLIXML\r\n<Objs></Objs>\r\n'
358
+
359
+ // when
360
+ const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
361
+
362
+ // then
363
+ expect(result).toBeNull()
364
+ })
365
+
366
+ it('returns null when payload between markers is empty', () => {
367
+ // when
368
+ const result = ChromiumCookieDecryptor.extractDPAPIPayload('<<<B64>>><<<END>>>')
369
+
370
+ // then
371
+ expect(result).toBeNull()
372
+ })
373
+ })
374
+
310
375
  describe('stripIntegrityHash', () => {
311
- test('returns input unchanged when length <= 32', () => {
376
+ it('returns input unchanged when length <= 32', () => {
312
377
  // given
313
378
  const decrypted = Buffer.alloc(32, 0x41)
314
379
 
@@ -319,7 +384,7 @@ describe('ChromiumCookieDecryptor', () => {
319
384
  expect(result).toEqual(decrypted)
320
385
  })
321
386
 
322
- test('strips first 32 bytes when they contain non-printable characters', () => {
387
+ it('strips first 32 bytes when they contain non-printable characters', () => {
323
388
  // given
324
389
  const hash = Buffer.concat([Buffer.from([0x00, 0x1f, 0xff]), Buffer.alloc(29, 0x01)])
325
390
  const value = Buffer.from('cookie-value')
@@ -331,7 +396,7 @@ describe('ChromiumCookieDecryptor', () => {
331
396
  expect(result).toEqual(value)
332
397
  })
333
398
 
334
- test('returns input unchanged when first 32 bytes are all printable ASCII', () => {
399
+ it('returns input unchanged when first 32 bytes are all printable ASCII', () => {
335
400
  // given
336
401
  const printablePrefix = Buffer.from('12345678901234567890123456789012')
337
402
  const decrypted = Buffer.concat([printablePrefix, Buffer.from('cookie-value')])
@@ -343,7 +408,7 @@ describe('ChromiumCookieDecryptor', () => {
343
408
  expect(result).toEqual(decrypted)
344
409
  })
345
410
 
346
- test('correctly strips binary hash prefix followed by readable cookie value', () => {
411
+ it('correctly strips binary hash prefix followed by readable cookie value', () => {
347
412
  // given
348
413
  const hash = randomBytes(32)
349
414
  const value = Buffer.from('readable-cookie-value')
@@ -355,7 +420,7 @@ describe('ChromiumCookieDecryptor', () => {
355
420
  expect(result).toEqual(value)
356
421
  })
357
422
 
358
- test('handles non-printable bytes that would be mangled by UTF-8 conversion (the v130+ fix)', () => {
423
+ it('handles non-printable bytes that would be mangled by UTF-8 conversion (the v130+ fix)', () => {
359
424
  // given
360
425
  const binaryPrefix = Buffer.from([
361
426
  ...Array.from({ length: 16 }, (_, i) => i),
@@ -372,7 +437,7 @@ describe('ChromiumCookieDecryptor', () => {
372
437
  })
373
438
 
374
439
  describe('loadCachedKey / clearKeyCache', () => {
375
- test('loadCachedKey is no-op on non-darwin platform', async () => {
440
+ it('loadCachedKey is no-op on non-darwin platform', async () => {
376
441
  // given
377
442
  const keyCache = {
378
443
  get: async () => Buffer.from('should-not-be-used'),
@@ -392,7 +457,7 @@ describe('ChromiumCookieDecryptor', () => {
392
457
  expect((decryptor as any).usedCachedKey).toBe(false)
393
458
  })
394
459
 
395
- test('loadCachedKey is no-op when no keyCache configured', async () => {
460
+ it('loadCachedKey is no-op when no keyCache configured', async () => {
396
461
  // given
397
462
  const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin', keyCachePlatform: 'slack' })
398
463
 
@@ -404,7 +469,7 @@ describe('ChromiumCookieDecryptor', () => {
404
469
  expect((decryptor as any).usedCachedKey).toBe(false)
405
470
  })
406
471
 
407
- test('clearKeyCache resets cached key state', async () => {
472
+ it('clearKeyCache resets cached key state', async () => {
408
473
  // given
409
474
  const clear = async () => {}
410
475
  const keyCache = { get: async () => null, clear }
@@ -426,7 +491,7 @@ describe('ChromiumCookieDecryptor', () => {
426
491
  })
427
492
 
428
493
  describe('linux v11 keyring behavior', () => {
429
- test('uses configured keyring password before falling back', () => {
494
+ it('uses configured keyring password before falling back', () => {
430
495
  // given
431
496
  const password = 'secret-from-keyring'
432
497
  const key = pbkdf2Sync(password, 'saltysalt', 1, 16, 'sha1')
@@ -187,22 +187,43 @@ export class ChromiumCookieDecryptor {
187
187
  if (this.platform !== 'win32') return null
188
188
  try {
189
189
  const b64Input = encrypted.toString('base64')
190
+ // Silence progress/information/warning streams so PowerShell doesn't emit CLIXML
191
+ // ("#< CLIXML ...") alongside our base64 payload when modules auto-load on first use.
192
+ // Wrap the payload in explicit markers so we can recover it even if stray output leaks in.
190
193
  const script = [
194
+ "$ProgressPreference='SilentlyContinue'",
195
+ "$InformationPreference='SilentlyContinue'",
196
+ "$WarningPreference='SilentlyContinue'",
191
197
  'Add-Type -AssemblyName System.Security',
192
198
  `$d=[System.Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String("${b64Input}"),$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser)`,
193
- '[Convert]::ToBase64String($d)',
199
+ "Write-Host ('<<<B64>>>'+[Convert]::ToBase64String($d)+'<<<END>>>')",
194
200
  ].join(';')
195
201
  const encodedCommand = Buffer.from(script, 'utf16le').toString('base64')
196
- const result = execSync(`powershell -NoProfile -NonInteractive -EncodedCommand ${encodedCommand}`, {
197
- encoding: 'utf8',
198
- timeout: 10000,
199
- }).trim()
200
- return Buffer.from(result, 'base64')
202
+ const rawResult = execSync(
203
+ `powershell -NoProfile -NonInteractive -OutputFormat Text -EncodedCommand ${encodedCommand}`,
204
+ { encoding: 'utf8', timeout: 10000 },
205
+ )
206
+ const b64 = ChromiumCookieDecryptor.extractDPAPIPayload(rawResult)
207
+ if (!b64) return null
208
+ return Buffer.from(b64, 'base64')
201
209
  } catch {
202
210
  return null
203
211
  }
204
212
  }
205
213
 
214
+ /**
215
+ * Extract the base64-encoded DPAPI payload from PowerShell stdout, stripping any
216
+ * CLIXML progress-stream contamination or other stray output. Returns null if
217
+ * no valid payload is found.
218
+ */
219
+ static extractDPAPIPayload(stdout: string): string | null {
220
+ const match = stdout.match(/<<<B64>>>([A-Za-z0-9+/=\r\n]*)<<<END>>>/)
221
+ if (!match) return null
222
+ const b64 = match[1].replace(/\s+/g, '')
223
+ if (!b64) return null
224
+ return b64
225
+ }
226
+
206
227
  static stripIntegrityHash(decrypted: Buffer): Buffer {
207
228
  if (decrypted.length <= 32) return decrypted
208
229
  const hasNonPrintablePrefix = decrypted.subarray(0, 32).some((b) => b < 0x20 || b > 0x7e)
@@ -4,8 +4,11 @@ export {
4
4
  CHROMIUM_BROWSERS,
5
5
  discoverBrowserProfileDirs,
6
6
  findLocalStatePath,
7
+ getAgentBrowserProfileDirs,
7
8
  getBrowserBasePath,
8
9
  } from './browsers'
9
10
  export { ChromiumCookieDecryptor } from './decryptor'
10
11
  export type { ChromiumDecryptorOptions } from './decryptor'
11
12
  export { ChromiumCookieReader } from './cookie-reader'
13
+ export { collectBrowserProfileOption } from './cli-options'
14
+ export type { BrowserProfileOption } from './cli-options'