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,16 +1,25 @@
1
1
  import { Database } from 'bun:sqlite'
2
- import { afterEach, describe, expect, spyOn, test } from 'bun:test'
2
+ import { afterEach, describe, expect, spyOn, it } from 'bun:test'
3
3
  import { createCipheriv, randomBytes } from 'node:crypto'
4
4
  import * as fs from 'node:fs'
5
5
  import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
6
6
  import { tmpdir } from 'node:os'
7
7
  import { join } from 'node:path'
8
8
 
9
+ import { ChromiumCookieDecryptor } from '@/shared/chromium'
10
+
9
11
  import { ExtractedWorkspace, TokenExtractor } from './token-extractor'
10
12
 
11
13
  const tempDirs: string[] = []
14
+ const originalAgentBrowserProfile = process.env.AGENT_BROWSER_PROFILE
12
15
 
13
16
  afterEach(() => {
17
+ if (originalAgentBrowserProfile) {
18
+ process.env.AGENT_BROWSER_PROFILE = originalAgentBrowserProfile
19
+ } else {
20
+ delete process.env.AGENT_BROWSER_PROFILE
21
+ }
22
+
14
23
  for (const dir of tempDirs) {
15
24
  rmSync(dir, { recursive: true, force: true })
16
25
  }
@@ -33,7 +42,7 @@ function createCookiesDb(
33
42
  }
34
43
 
35
44
  describe('TokenExtractor token deduplication', () => {
36
- test('keeps first token per team and upgrades unknown team name', async () => {
45
+ it('keeps first token per team and upgrades unknown team name', async () => {
37
46
  // given — two .log entries for the same team: first has unknown name, second has a name
38
47
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-dedup-'))
39
48
  tempDirs.push(slackDir)
@@ -59,7 +68,7 @@ describe('TokenExtractor token deduplication', () => {
59
68
  expect(result[0].workspace_name).toBe('workspace-name')
60
69
  })
61
70
 
62
- test('prefers Local Storage token over IndexedDB token for same team', async () => {
71
+ it('prefers Local Storage token over IndexedDB token for same team', async () => {
63
72
  // given — same team in Local Storage (valid) and IndexedDB (stale)
64
73
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-dedup-tier-'))
65
74
  tempDirs.push(slackDir)
@@ -87,7 +96,7 @@ describe('TokenExtractor token deduplication', () => {
87
96
  expect(result[0].workspace_name).toBe('valid-workspace')
88
97
  })
89
98
 
90
- test('prefers IndexedDB token when Local Storage has no token for team', async () => {
99
+ it('prefers IndexedDB token when Local Storage has no token for team', async () => {
91
100
  // given — token only in IndexedDB
92
101
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-dedup-idb-only-'))
93
102
  tempDirs.push(slackDir)
@@ -108,7 +117,7 @@ describe('TokenExtractor token deduplication', () => {
108
117
  expect(result[0].token).toBe(token)
109
118
  })
110
119
 
111
- test('prefers storage dir token over IndexedDB token for same team', async () => {
120
+ it('prefers storage dir token over IndexedDB token for same team', async () => {
112
121
  // given — structured JSON in storage dir vs raw token in IndexedDB
113
122
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-dedup-storage-'))
114
123
  tempDirs.push(slackDir)
@@ -136,7 +145,7 @@ describe('TokenExtractor token deduplication', () => {
136
145
  expect(result[0].workspace_name).toBe('storage-workspace')
137
146
  })
138
147
 
139
- test('prefers .log tokens over .ldb tokens for same team', async () => {
148
+ it('prefers .log tokens over .ldb tokens for same team', async () => {
140
149
  // given — same team ID in both .log (fresh) and .ldb (stale)
141
150
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-dedup-order-'))
142
151
  tempDirs.push(slackDir)
@@ -160,7 +169,7 @@ describe('TokenExtractor token deduplication', () => {
160
169
  expect(result[0].token).toBe(freshToken)
161
170
  })
162
171
 
163
- test('keeps all tokens with unknown teamId instead of merging them', async () => {
172
+ it('keeps all tokens with unknown teamId instead of merging them', async () => {
164
173
  // given — two different tokens without team ID context (no T[A-Z0-9] nearby)
165
174
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-dedup-unknown-'))
166
175
  tempDirs.push(slackDir)
@@ -203,7 +212,7 @@ describe('TokenExtractor LevelDB fragmentation markers', () => {
203
212
  return Buffer.concat([prefix, segments[0] ? Buffer.concat(segments) : Buffer.alloc(0), suffix])
204
213
  }
205
214
 
206
- test('extracts token with old fragmentation marker [19 0d f0 NN]', async () => {
215
+ it('extracts token with old fragmentation marker [19 0d f0 NN]', async () => {
207
216
  // given
208
217
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-marker-old-'))
209
218
  tempDirs.push(slackDir)
@@ -225,7 +234,7 @@ describe('TokenExtractor LevelDB fragmentation markers', () => {
225
234
  expect(result[0].token).toBe(`xoxc-1111111111-2222222222-3333333333-${hex64}`)
226
235
  })
227
236
 
228
- test('extracts token with new fragmentation marker [15 0b f0 43]', async () => {
237
+ it('extracts token with new fragmentation marker [15 0b f0 43]', async () => {
229
238
  // given — marker whose 4th byte (0x43 = "C") is a valid hex char
230
239
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-marker-new-'))
231
240
  tempDirs.push(slackDir)
@@ -248,7 +257,7 @@ describe('TokenExtractor LevelDB fragmentation markers', () => {
248
257
  expect(result[0].token).not.toContain('C')
249
258
  })
250
259
 
251
- test('extracts token with new fragmentation marker [15 0b f0 58]', async () => {
260
+ it('extracts token with new fragmentation marker [15 0b f0 58]', async () => {
252
261
  // given — marker whose 4th byte (0x58 = "X") is not a valid hex char
253
262
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-marker-58-'))
254
263
  tempDirs.push(slackDir)
@@ -272,7 +281,7 @@ describe('TokenExtractor LevelDB fragmentation markers', () => {
272
281
  })
273
282
 
274
283
  describe('TokenExtractor Linux cookie decryption', () => {
275
- test('decrypts v10 cookie using peanuts password on Linux', async () => {
284
+ it('decrypts v10 cookie using peanuts password on Linux', async () => {
276
285
  // given — LevelDB with valid token + v10-encrypted cookie using Linux key
277
286
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-linux-'))
278
287
  tempDirs.push(slackDir)
@@ -311,7 +320,7 @@ describe('TokenExtractor Linux cookie decryption', () => {
311
320
  })
312
321
 
313
322
  describe('TokenExtractor Linux v11 cookie decryption', () => {
314
- test('decrypts v11 cookie using gnome-keyring password on Linux', () => {
323
+ it('decrypts v11 cookie using gnome-keyring password on Linux', () => {
315
324
  // given — v11-prefixed cookie encrypted with a known keyring password
316
325
  const { createCipheriv, pbkdf2Sync } = require('node:crypto')
317
326
  const testPassword = 'test-gnome-keyring-password'
@@ -338,7 +347,7 @@ describe('TokenExtractor Linux v11 cookie decryption', () => {
338
347
  keyringPasswordSpy.mockRestore()
339
348
  })
340
349
 
341
- test('falls back to peanuts key when keyring is unavailable for v11 cookie', () => {
350
+ it('falls back to peanuts key when keyring is unavailable for v11 cookie', () => {
342
351
  // given — v11-prefixed cookie encrypted with peanuts (tests fallback code path)
343
352
  const { createCipheriv, pbkdf2Sync } = require('node:crypto')
344
353
  const key = pbkdf2Sync('peanuts', 'saltysalt', 1, 16, 'sha1')
@@ -363,7 +372,7 @@ describe('TokenExtractor Linux v11 cookie decryption', () => {
363
372
  })
364
373
 
365
374
  describe('TokenExtractor debug logging', () => {
366
- test('calls debugLog callback during extraction', async () => {
375
+ it('calls debugLog callback during extraction', async () => {
367
376
  // given
368
377
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-debug-'))
369
378
  tempDirs.push(slackDir)
@@ -380,7 +389,7 @@ describe('TokenExtractor debug logging', () => {
380
389
  expect(messages.length).toBeGreaterThan(0)
381
390
  })
382
391
 
383
- test('does not throw when debugLog is not provided', async () => {
392
+ it('does not throw when debugLog is not provided', async () => {
384
393
  // given
385
394
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-no-debug-'))
386
395
  tempDirs.push(slackDir)
@@ -394,12 +403,12 @@ describe('TokenExtractor debug logging', () => {
394
403
  })
395
404
 
396
405
  describe('TokenExtractor Windows DPAPI', () => {
397
- test('decryptDPAPI returns null on non-win32 platform', () => {
406
+ it('decryptDPAPI returns null on non-win32 platform', () => {
398
407
  const extractor = new TokenExtractor('darwin', '/tmp/slack-test')
399
408
  expect(extractor.decryptDPAPI(Buffer.from('test'))).toBeNull()
400
409
  })
401
410
 
402
- test('decryptV10CookieWindows decrypts AES-256-GCM with master key from Local State', () => {
411
+ it('decryptV10CookieWindows decrypts AES-256-GCM with master key from Local State', () => {
403
412
  // given — known master key and AES-256-GCM encrypted cookie
404
413
  const masterKey = randomBytes(32)
405
414
 
@@ -423,7 +432,7 @@ describe('TokenExtractor Windows DPAPI', () => {
423
432
  expect(extractor.tryDecryptCookie(encrypted)).toBe(plaintext)
424
433
  })
425
434
 
426
- test('decryptV10CookieWindows falls back to direct DPAPI when no Local State', () => {
435
+ it('decryptV10CookieWindows falls back to direct DPAPI when no Local State', () => {
427
436
  class TestTokenExtractor extends TokenExtractor {
428
437
  override getWindowsMasterKey(): null {
429
438
  return null
@@ -439,7 +448,7 @@ describe('TokenExtractor Windows DPAPI', () => {
439
448
  expect(extractor.tryDecryptCookie(encrypted)).toBe('xoxd-dpapiDirectCookie%2B')
440
449
  })
441
450
 
442
- test('tryDecryptCookie handles Windows pre-v80 cookies without version prefix', () => {
451
+ it('tryDecryptCookie handles Windows pre-v80 cookies without version prefix', () => {
443
452
  class TestTokenExtractor extends TokenExtractor {
444
453
  override decryptDPAPI(_encrypted: Buffer): Buffer | null {
445
454
  return Buffer.from('xoxd-preV80Cookie%2B')
@@ -452,7 +461,7 @@ describe('TokenExtractor Windows DPAPI', () => {
452
461
  expect(extractor.tryDecryptCookie(encrypted)).toBe('xoxd-preV80Cookie%2B')
453
462
  })
454
463
 
455
- test('getWindowsMasterKey reads and decrypts key from Local State file', () => {
464
+ it('getWindowsMasterKey reads and decrypts key from Local State file', () => {
456
465
  // given
457
466
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-win-'))
458
467
  tempDirs.push(slackDir)
@@ -477,7 +486,7 @@ describe('TokenExtractor Windows DPAPI', () => {
477
486
  expect(extractor.getWindowsMasterKey()).toEqual(fakeDecryptedKey)
478
487
  })
479
488
 
480
- test('getWindowsMasterKey returns null when Local State is missing', () => {
489
+ it('getWindowsMasterKey returns null when Local State is missing', () => {
481
490
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-no-ls-'))
482
491
  tempDirs.push(slackDir)
483
492
 
@@ -485,7 +494,7 @@ describe('TokenExtractor Windows DPAPI', () => {
485
494
  expect(extractor.getWindowsMasterKey()).toBeNull()
486
495
  })
487
496
 
488
- test('getWindowsMasterKey returns null when encrypted_key has no DPAPI prefix', () => {
497
+ it('getWindowsMasterKey returns null when encrypted_key has no DPAPI prefix', () => {
489
498
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-bad-ls-'))
490
499
  tempDirs.push(slackDir)
491
500
 
@@ -496,7 +505,7 @@ describe('TokenExtractor Windows DPAPI', () => {
496
505
  expect(extractor.getWindowsMasterKey()).toBeNull()
497
506
  })
498
507
 
499
- test('extract throws descriptive error when cookie file is locked (EBUSY)', async () => {
508
+ it('extract throws descriptive error when cookie file is locked (EBUSY)', async () => {
500
509
  // given — LevelDB with a valid token but Cookies file locked by Slack
501
510
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-ebusy-'))
502
511
  tempDirs.push(slackDir)
@@ -523,7 +532,7 @@ describe('TokenExtractor Windows DPAPI', () => {
523
532
  }
524
533
  })
525
534
 
526
- test('extract decrypts Windows v10 cookies end-to-end with mocked DPAPI', async () => {
535
+ it('extract decrypts Windows v10 cookies end-to-end with mocked DPAPI', async () => {
527
536
  // given — SQLite DB with v10-encrypted cookie, Local State with master key, LevelDB with token
528
537
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-win-e2e-'))
529
538
  tempDirs.push(slackDir)
@@ -582,7 +591,7 @@ describe('TokenExtractor Windows DPAPI', () => {
582
591
  })
583
592
 
584
593
  describe('TokenExtractor IndexedDB blob files', () => {
585
- test('extracts token from blob file when not in LevelDB', async () => {
594
+ it('extracts token from blob file when not in LevelDB', async () => {
586
595
  // given — token only exists in an IndexedDB blob file, not in LevelDB
587
596
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-blob-'))
588
597
  tempDirs.push(slackDir)
@@ -604,7 +613,7 @@ describe('TokenExtractor IndexedDB blob files', () => {
604
613
  expect(result[0].workspace_id).toBe('T12345678')
605
614
  })
606
615
 
607
- test('extracts tokens from both LevelDB and blob files for different teams', async () => {
616
+ it('extracts tokens from both LevelDB and blob files for different teams', async () => {
608
617
  // given — one workspace token in LevelDB, another in blob file
609
618
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-blob-multi-'))
610
619
  tempDirs.push(slackDir)
@@ -632,7 +641,7 @@ describe('TokenExtractor IndexedDB blob files', () => {
632
641
  expect(teamIds).toEqual(['TAAAAAAAA', 'TBBBBBBBBB'])
633
642
  })
634
643
 
635
- test('LevelDB token wins over blob file token for same team', async () => {
644
+ it('LevelDB token wins over blob file token for same team', async () => {
636
645
  // given — same team in both LevelDB (.log = highest raw priority) and blob file
637
646
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-blob-dedup-'))
638
647
  tempDirs.push(slackDir)
@@ -659,7 +668,7 @@ describe('TokenExtractor IndexedDB blob files', () => {
659
668
  expect(result[0].token).toBe(ldbToken)
660
669
  })
661
670
 
662
- test('merges same token from LDB and blob with different teamIds', async () => {
671
+ it('merges same token from LDB and blob with different teamIds', async () => {
663
672
  // given — same token in LevelDB (correct teamId) and blob file (false-positive teamId from binary)
664
673
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-blob-dup-'))
665
674
  tempDirs.push(slackDir)
@@ -685,7 +694,7 @@ describe('TokenExtractor IndexedDB blob files', () => {
685
694
  expect(result[0].token).toBe(token)
686
695
  })
687
696
 
688
- test('skips blob files larger than 10MB', async () => {
697
+ it('skips blob files larger than 10MB', async () => {
689
698
  // given — blob file exceeds size limit
690
699
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-blob-large-'))
691
700
  tempDirs.push(slackDir)
@@ -710,7 +719,7 @@ describe('TokenExtractor IndexedDB blob files', () => {
710
719
  })
711
720
 
712
721
  describe('TokenExtractor getWorkspaceDomains', () => {
713
- test('reads workspace domains from root-state.json', () => {
722
+ it('reads workspace domains from root-state.json', () => {
714
723
  // given
715
724
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-domains-'))
716
725
  tempDirs.push(slackDir)
@@ -735,7 +744,7 @@ describe('TokenExtractor getWorkspaceDomains', () => {
735
744
  expect(domains).toEqual({ T111: 'acme-corp', T222: 'devteam' })
736
745
  })
737
746
 
738
- test('returns empty when root-state.json is missing', () => {
747
+ it('returns empty when root-state.json is missing', () => {
739
748
  // given
740
749
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-no-rootstate-'))
741
750
  tempDirs.push(slackDir)
@@ -748,7 +757,7 @@ describe('TokenExtractor getWorkspaceDomains', () => {
748
757
  expect(domains).toEqual({})
749
758
  })
750
759
 
751
- test('returns empty when root-state.json has no workspaces', () => {
760
+ it('returns empty when root-state.json has no workspaces', () => {
752
761
  // given
753
762
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-empty-rootstate-'))
754
763
  tempDirs.push(slackDir)
@@ -765,7 +774,7 @@ describe('TokenExtractor getWorkspaceDomains', () => {
765
774
  expect(domains).toEqual({})
766
775
  })
767
776
 
768
- test('skips workspaces without domain field', () => {
777
+ it('skips workspaces without domain field', () => {
769
778
  // given
770
779
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-partial-rootstate-'))
771
780
  tempDirs.push(slackDir)
@@ -792,7 +801,7 @@ describe('TokenExtractor getWorkspaceDomains', () => {
792
801
  })
793
802
 
794
803
  describe('TokenExtractor browser fallback', () => {
795
- test('extractFromBrowsers returns empty array when no browser profiles have tokens', async () => {
804
+ it('extractFromBrowsers returns empty array when no browser profiles have tokens', async () => {
796
805
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-nonexistent-'))
797
806
  tempDirs.push(slackDir)
798
807
  rmSync(slackDir, { recursive: true, force: true })
@@ -802,7 +811,53 @@ describe('TokenExtractor browser fallback', () => {
802
811
  expect(result).toEqual([])
803
812
  })
804
813
 
805
- test('extract tries desktop before browser profiles', async () => {
814
+ it('resolves Local State from agent-browser profile root for encrypted cookies', async () => {
815
+ // given
816
+ const agentBrowserProfile = mkdtempSync(join(tmpdir(), 'agent-browser-slack-profile-'))
817
+ tempDirs.push(agentBrowserProfile)
818
+ process.env.AGENT_BROWSER_PROFILE = agentBrowserProfile
819
+
820
+ const hex64 = 'c'.repeat(64)
821
+ const token = `xoxc-1111111111-2222222222-3333333333-${hex64}`
822
+ const profileDir = join(agentBrowserProfile, 'Default')
823
+ const leveldbDir = join(profileDir, 'Local Storage', 'leveldb')
824
+ const networkDir = join(profileDir, 'Network')
825
+ mkdirSync(leveldbDir, { recursive: true })
826
+ mkdirSync(networkDir, { recursive: true })
827
+ writeFileSync(join(leveldbDir, '000001.log'), `"${token}"T12345678"name":"agent-browser-workspace"`)
828
+ writeFileSync(join(agentBrowserProfile, 'Local State'), '{}')
829
+ createCookiesDb(join(networkDir, 'Cookies'), [
830
+ {
831
+ name: 'd',
832
+ value: '',
833
+ encrypted_value: new Uint8Array([1, 2, 3]),
834
+ host_key: '.slack.com',
835
+ last_access_utc: 1,
836
+ },
837
+ ])
838
+ const decryptSpy = spyOn(ChromiumCookieDecryptor.prototype, 'decryptCookie').mockReturnValue('xoxd-AgentBrowser')
839
+
840
+ try {
841
+ // when
842
+ const extractor = new TokenExtractor('darwin', join(agentBrowserProfile, 'missing-desktop'))
843
+ const result = await extractor.extractFromBrowsers()
844
+
845
+ // then
846
+ expect(result).toEqual([
847
+ {
848
+ workspace_id: 'T12345678',
849
+ workspace_name: 'agent-browser-workspace',
850
+ token,
851
+ cookie: 'xoxd-AgentBrowser',
852
+ },
853
+ ])
854
+ expect(decryptSpy).toHaveBeenCalledWith(Buffer.from([1, 2, 3]), join(agentBrowserProfile, 'Local State'))
855
+ } finally {
856
+ decryptSpy.mockRestore()
857
+ }
858
+ })
859
+
860
+ it('extract tries desktop before browser profiles', async () => {
806
861
  // given — slackDir with LevelDB token data
807
862
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-fallback-desktop-'))
808
863
  tempDirs.push(slackDir)
@@ -826,7 +881,48 @@ describe('TokenExtractor browser fallback', () => {
826
881
  extractFromBrowsersSpy.mockRestore()
827
882
  })
828
883
 
829
- test('extract falls back to browser profiles when desktop has no tokens', async () => {
884
+ it('custom browser profile can upgrade desktop token with a cookie', async () => {
885
+ // given
886
+ const slackDir = mkdtempSync(join(tmpdir(), 'slack-custom-cookie-upgrade-'))
887
+ tempDirs.push(slackDir)
888
+
889
+ const hex64 = 'd'.repeat(64)
890
+ const token = `xoxc-1111111111-2222222222-3333333333-${hex64}`
891
+ const leveldbDir = join(slackDir, 'Local Storage', 'leveldb')
892
+ mkdirSync(leveldbDir, { recursive: true })
893
+ writeFileSync(join(leveldbDir, '000001.log'), `"${token}"T12345678"name":"desktop-workspace"`)
894
+
895
+ const browserWorkspace: ExtractedWorkspace = {
896
+ workspace_id: 'T12345678',
897
+ workspace_name: 'browser-workspace',
898
+ token,
899
+ cookie: 'xoxd-browser-cookie',
900
+ }
901
+ const extractFromBrowsersSpy = spyOn(TokenExtractor.prototype as any, 'extractFromBrowsers').mockResolvedValue([
902
+ browserWorkspace,
903
+ ])
904
+
905
+ try {
906
+ // when
907
+ const extractor = new TokenExtractor('darwin', slackDir, undefined, undefined, ['/tmp/custom-profile'])
908
+ const result = await extractor.extract()
909
+
910
+ // then
911
+ expect(extractFromBrowsersSpy).toHaveBeenCalled()
912
+ expect(result).toEqual([
913
+ {
914
+ workspace_id: 'T12345678',
915
+ workspace_name: 'desktop-workspace',
916
+ token,
917
+ cookie: 'xoxd-browser-cookie',
918
+ },
919
+ ])
920
+ } finally {
921
+ extractFromBrowsersSpy.mockRestore()
922
+ }
923
+ })
924
+
925
+ it('extract falls back to browser profiles when desktop has no tokens', async () => {
830
926
  // given — empty slackDir (no tokens)
831
927
  const slackDir = mkdtempSync(join(tmpdir(), 'slack-fallback-browser-'))
832
928
  tempDirs.push(slackDir)
@@ -855,7 +951,7 @@ describe('TokenExtractor browser fallback', () => {
855
951
  extractFromBrowsersSpy.mockRestore()
856
952
  })
857
953
 
858
- test('extract falls back to browser when slackDir does not exist', async () => {
954
+ it('extract falls back to browser when slackDir does not exist', async () => {
859
955
  // given — non-existent slackDir
860
956
  const slackDir = '/nonexistent/slack/dir'
861
957
  const hex64 = 'c'.repeat(64)
@@ -12,7 +12,9 @@ import {
12
12
  ChromiumCookieDecryptor,
13
13
  ChromiumCookieReader,
14
14
  discoverBrowserProfileDirs,
15
+ findLocalStatePath,
15
16
  getBrowserBasePath,
17
+ getAgentBrowserProfileDirs,
16
18
  } from '@/shared/chromium'
17
19
  import { DerivedKeyCache } from '@/shared/utils/derived-key-cache'
18
20
  import { lookupLinuxKeyringPassword } from '@/shared/utils/linux-keyring'
@@ -63,12 +65,14 @@ export class TokenExtractor {
63
65
  private debugLog: ((message: string) => void) | null
64
66
  private browserDecryptor: ChromiumCookieDecryptor
65
67
  private browserCookieReader: ChromiumCookieReader
68
+ private customBrowserProfileDirs: string[]
66
69
 
67
70
  constructor(
68
71
  platform?: NodeJS.Platform,
69
72
  slackDir?: string,
70
73
  keyCache?: DerivedKeyCache,
71
74
  debugLog?: (message: string) => void,
75
+ customBrowserProfileDirs?: string[],
72
76
  ) {
73
77
  this.platform = platform ?? process.platform
74
78
 
@@ -79,6 +83,7 @@ export class TokenExtractor {
79
83
  this.slackDir = slackDir ?? this.getSlackDir()
80
84
  this.keyCache = keyCache ?? new DerivedKeyCache()
81
85
  this.debugLog = debugLog ?? null
86
+ this.customBrowserProfileDirs = customBrowserProfileDirs ?? []
82
87
  this.browserDecryptor = new ChromiumCookieDecryptor({ platform: this.platform })
83
88
  this.browserCookieReader = new ChromiumCookieReader()
84
89
  }
@@ -188,6 +193,9 @@ export class TokenExtractor {
188
193
  }
189
194
 
190
195
  async extract(): Promise<ExtractedWorkspace[]> {
196
+ const results: ExtractedWorkspace[] = []
197
+ const seenTokens = new Set<string>()
198
+
191
199
  if (existsSync(this.slackDir)) {
192
200
  await this.getDerivedKeyAsync()
193
201
 
@@ -201,27 +209,55 @@ export class TokenExtractor {
201
209
  if (this.cachedKey) {
202
210
  await this.keyCache.set('slack', this.cachedKey)
203
211
  const retryCookie = await this.extractCookieFromSQLite()
204
- return tokens.map((t) => ({
205
- workspace_id: t.teamId,
206
- workspace_name: t.teamName,
207
- token: t.token,
208
- cookie: retryCookie,
209
- }))
212
+ this.addExtractedWorkspaces(results, seenTokens, tokens, retryCookie)
213
+ return this.customBrowserProfileDirs.length > 0 ? this.mergeBrowserResults(results, seenTokens) : results
210
214
  }
211
215
  }
212
216
 
213
- return tokens.map((t) => ({
214
- workspace_id: t.teamId,
215
- workspace_name: t.teamName,
216
- token: t.token,
217
- cookie: cookie,
218
- }))
217
+ this.addExtractedWorkspaces(results, seenTokens, tokens, cookie)
218
+ return this.customBrowserProfileDirs.length > 0 ? this.mergeBrowserResults(results, seenTokens) : results
219
219
  }
220
220
  }
221
221
 
222
222
  return this.extractFromBrowsers()
223
223
  }
224
224
 
225
+ private async mergeBrowserResults(
226
+ results: ExtractedWorkspace[],
227
+ seenTokens: Set<string>,
228
+ ): Promise<ExtractedWorkspace[]> {
229
+ for (const workspace of await this.extractFromBrowsers()) {
230
+ const existing = results.find((item) => item.token === workspace.token)
231
+ if (existing) {
232
+ if (!existing.cookie && workspace.cookie) {
233
+ existing.cookie = workspace.cookie
234
+ }
235
+ continue
236
+ }
237
+ seenTokens.add(workspace.token)
238
+ results.push(workspace)
239
+ }
240
+ return results
241
+ }
242
+
243
+ private addExtractedWorkspaces(
244
+ results: ExtractedWorkspace[],
245
+ seenTokens: Set<string>,
246
+ tokens: TokenInfo[],
247
+ cookie: string,
248
+ ): void {
249
+ for (const token of tokens) {
250
+ if (seenTokens.has(token.token)) continue
251
+ seenTokens.add(token.token)
252
+ results.push({
253
+ workspace_id: token.teamId,
254
+ workspace_name: token.teamName,
255
+ token: token.token,
256
+ cookie,
257
+ })
258
+ }
259
+ }
260
+
225
261
  async extractFromBrowsers(): Promise<ExtractedWorkspace[]> {
226
262
  const results: ExtractedWorkspace[] = []
227
263
  const seenTokens = new Set<string>()
@@ -259,6 +295,33 @@ export class TokenExtractor {
259
295
  }
260
296
  }
261
297
 
298
+ for (const profileDir of getAgentBrowserProfileDirs({ customProfileDirs: this.customBrowserProfileDirs })) {
299
+ const leveldbDir = join(profileDir, 'Local Storage', 'leveldb')
300
+ if (!existsSync(leveldbDir)) continue
301
+
302
+ let tokenInfos: TokenInfo[]
303
+ try {
304
+ tokenInfos = await this.extractFromLevelDB(leveldbDir, 'local-storage')
305
+ } catch {
306
+ continue
307
+ }
308
+
309
+ if (tokenInfos.length === 0) continue
310
+
311
+ const cookie = await this.extractCookieFromBrowserProfile(profileDir, profileDir)
312
+
313
+ for (const t of tokenInfos) {
314
+ if (seenTokens.has(t.token)) continue
315
+ seenTokens.add(t.token)
316
+ results.push({
317
+ workspace_id: t.teamId,
318
+ workspace_name: t.teamName,
319
+ token: t.token,
320
+ cookie,
321
+ })
322
+ }
323
+ }
324
+
262
325
  return results
263
326
  }
264
327
 
@@ -293,7 +356,7 @@ export class TokenExtractor {
293
356
  if (row.value?.startsWith('xoxd-')) return row.value
294
357
 
295
358
  if (row.encrypted_value && row.encrypted_value.length > 0) {
296
- const localStatePath = join(browserBase, 'Local State')
359
+ const localStatePath = findLocalStatePath(cookiesPath) ?? join(browserBase, 'Local State')
297
360
  const decrypted = this.browserDecryptor.decryptCookie(
298
361
  Buffer.from(row.encrypted_value),
299
362
  existsSync(localStatePath) ? localStatePath : undefined,