agent-messenger 2.7.0 → 2.9.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 (553) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.github/workflows/ci.yml +6 -0
  3. package/.oxfmtrc.json +13 -1
  4. package/.oxlintrc.json +10 -1
  5. package/README.md +1 -12
  6. package/dist/package.json +59 -58
  7. package/dist/src/platforms/channeltalk/client.d.ts.map +1 -1
  8. package/dist/src/platforms/channeltalk/client.js +2 -2
  9. package/dist/src/platforms/channeltalk/client.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  11. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  12. package/dist/src/platforms/channeltalk/commands/message.d.ts.map +1 -1
  13. package/dist/src/platforms/channeltalk/commands/message.js.map +1 -1
  14. package/dist/src/platforms/channeltalk/commands/snapshot.d.ts +4 -2
  15. package/dist/src/platforms/channeltalk/commands/snapshot.d.ts.map +1 -1
  16. package/dist/src/platforms/channeltalk/commands/snapshot.js +86 -31
  17. package/dist/src/platforms/channeltalk/commands/snapshot.js.map +1 -1
  18. package/dist/src/platforms/channeltalk/ensure-auth.d.ts.map +1 -1
  19. package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
  20. package/dist/src/platforms/channeltalk/token-extractor.d.ts +9 -23
  21. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  22. package/dist/src/platforms/channeltalk/token-extractor.js +109 -341
  23. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  24. package/dist/src/platforms/channeltalkbot/client.d.ts +1 -1
  25. package/dist/src/platforms/channeltalkbot/client.d.ts.map +1 -1
  26. package/dist/src/platforms/channeltalkbot/client.js +4 -4
  27. package/dist/src/platforms/channeltalkbot/client.js.map +1 -1
  28. package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
  29. package/dist/src/platforms/channeltalkbot/commands/auth.js +4 -1
  30. package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
  31. package/dist/src/platforms/channeltalkbot/commands/shared.d.ts.map +1 -1
  32. package/dist/src/platforms/channeltalkbot/commands/shared.js.map +1 -1
  33. package/dist/src/platforms/channeltalkbot/commands/snapshot.d.ts +3 -1
  34. package/dist/src/platforms/channeltalkbot/commands/snapshot.d.ts.map +1 -1
  35. package/dist/src/platforms/channeltalkbot/commands/snapshot.js +110 -60
  36. package/dist/src/platforms/channeltalkbot/commands/snapshot.js.map +1 -1
  37. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  38. package/dist/src/platforms/discord/commands/snapshot.d.ts +1 -0
  39. package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -1
  40. package/dist/src/platforms/discord/commands/snapshot.js +48 -34
  41. package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
  42. package/dist/src/platforms/discord/commands/whoami.d.ts.map +1 -1
  43. package/dist/src/platforms/discord/commands/whoami.js.map +1 -1
  44. package/dist/src/platforms/discord/token-extractor.d.ts +2 -10
  45. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  46. package/dist/src/platforms/discord/token-extractor.js +38 -172
  47. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  48. package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
  49. package/dist/src/platforms/discordbot/client.js.map +1 -1
  50. package/dist/src/platforms/discordbot/commands/snapshot.d.ts +2 -0
  51. package/dist/src/platforms/discordbot/commands/snapshot.d.ts.map +1 -1
  52. package/dist/src/platforms/discordbot/commands/snapshot.js +46 -34
  53. package/dist/src/platforms/discordbot/commands/snapshot.js.map +1 -1
  54. package/dist/src/platforms/instagram/cli.d.ts.map +1 -1
  55. package/dist/src/platforms/instagram/cli.js +1 -4
  56. package/dist/src/platforms/instagram/cli.js.map +1 -1
  57. package/dist/src/platforms/instagram/client.d.ts.map +1 -1
  58. package/dist/src/platforms/instagram/client.js +8 -7
  59. package/dist/src/platforms/instagram/client.js.map +1 -1
  60. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  61. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  62. package/dist/src/platforms/instagram/commands/chat.d.ts.map +1 -1
  63. package/dist/src/platforms/instagram/commands/chat.js.map +1 -1
  64. package/dist/src/platforms/instagram/commands/message.d.ts.map +1 -1
  65. package/dist/src/platforms/instagram/commands/message.js.map +1 -1
  66. package/dist/src/platforms/instagram/commands/shared.d.ts.map +1 -1
  67. package/dist/src/platforms/instagram/commands/shared.js.map +1 -1
  68. package/dist/src/platforms/instagram/credential-manager.d.ts.map +1 -1
  69. package/dist/src/platforms/instagram/credential-manager.js +1 -1
  70. package/dist/src/platforms/instagram/credential-manager.js.map +1 -1
  71. package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
  72. package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
  73. package/dist/src/platforms/instagram/token-extractor.d.ts +7 -19
  74. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
  75. package/dist/src/platforms/instagram/token-extractor.js +44 -270
  76. package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
  77. package/dist/src/platforms/instagram/types.d.ts.map +1 -1
  78. package/dist/src/platforms/instagram/types.js +4 -2
  79. package/dist/src/platforms/instagram/types.js.map +1 -1
  80. package/dist/src/platforms/kakaotalk/auth/kakao-login.d.ts.map +1 -1
  81. package/dist/src/platforms/kakaotalk/auth/kakao-login.js +18 -4
  82. package/dist/src/platforms/kakaotalk/auth/kakao-login.js.map +1 -1
  83. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  84. package/dist/src/platforms/kakaotalk/client.js +3 -3
  85. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  86. package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
  87. package/dist/src/platforms/kakaotalk/commands/auth.js +15 -9
  88. package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
  89. package/dist/src/platforms/kakaotalk/commands/shared.d.ts.map +1 -1
  90. package/dist/src/platforms/kakaotalk/commands/shared.js.map +1 -1
  91. package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
  92. package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
  93. package/dist/src/platforms/kakaotalk/protocol/crypto.js +1 -1
  94. package/dist/src/platforms/kakaotalk/protocol/crypto.js.map +1 -1
  95. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  96. package/dist/src/platforms/kakaotalk/protocol/session.js +1 -3
  97. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  98. package/dist/src/platforms/kakaotalk/token-extractor.js +5 -2
  99. package/dist/src/platforms/kakaotalk/token-extractor.js.map +1 -1
  100. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  101. package/dist/src/platforms/kakaotalk/types.js +4 -2
  102. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  103. package/dist/src/platforms/line/cli.d.ts.map +1 -1
  104. package/dist/src/platforms/line/cli.js +1 -4
  105. package/dist/src/platforms/line/cli.js.map +1 -1
  106. package/dist/src/platforms/line/client.d.ts.map +1 -1
  107. package/dist/src/platforms/line/client.js +5 -13
  108. package/dist/src/platforms/line/client.js.map +1 -1
  109. package/dist/src/platforms/line/commands/chat.d.ts.map +1 -1
  110. package/dist/src/platforms/line/commands/chat.js.map +1 -1
  111. package/dist/src/platforms/line/commands/message.d.ts.map +1 -1
  112. package/dist/src/platforms/line/commands/message.js.map +1 -1
  113. package/dist/src/platforms/line/listener.js +1 -1
  114. package/dist/src/platforms/line/listener.js.map +1 -1
  115. package/dist/src/platforms/slack/cli.d.ts.map +1 -1
  116. package/dist/src/platforms/slack/cli.js.map +1 -1
  117. package/dist/src/platforms/slack/client-mappers.d.ts +14 -0
  118. package/dist/src/platforms/slack/client-mappers.d.ts.map +1 -0
  119. package/dist/src/platforms/slack/client-mappers.js +245 -0
  120. package/dist/src/platforms/slack/client-mappers.js.map +1 -0
  121. package/dist/src/platforms/slack/client.d.ts +0 -1
  122. package/dist/src/platforms/slack/client.d.ts.map +1 -1
  123. package/dist/src/platforms/slack/client.js +41 -455
  124. package/dist/src/platforms/slack/client.js.map +1 -1
  125. package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
  126. package/dist/src/platforms/slack/commands/channel.js.map +1 -1
  127. package/dist/src/platforms/slack/commands/emoji.d.ts.map +1 -1
  128. package/dist/src/platforms/slack/commands/emoji.js +1 -3
  129. package/dist/src/platforms/slack/commands/emoji.js.map +1 -1
  130. package/dist/src/platforms/slack/commands/message.d.ts.map +1 -1
  131. package/dist/src/platforms/slack/commands/message.js.map +1 -1
  132. package/dist/src/platforms/slack/commands/reminder.d.ts.map +1 -1
  133. package/dist/src/platforms/slack/commands/reminder.js.map +1 -1
  134. package/dist/src/platforms/slack/commands/snapshot.d.ts.map +1 -1
  135. package/dist/src/platforms/slack/commands/snapshot.js +75 -55
  136. package/dist/src/platforms/slack/commands/snapshot.js.map +1 -1
  137. package/dist/src/platforms/slack/commands/user.d.ts.map +1 -1
  138. package/dist/src/platforms/slack/commands/user.js.map +1 -1
  139. package/dist/src/platforms/slack/commands/usergroup.d.ts.map +1 -1
  140. package/dist/src/platforms/slack/commands/usergroup.js.map +1 -1
  141. package/dist/src/platforms/slack/commands/whoami.d.ts.map +1 -1
  142. package/dist/src/platforms/slack/commands/whoami.js.map +1 -1
  143. package/dist/src/platforms/slack/token-extractor.d.ts +2 -6
  144. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  145. package/dist/src/platforms/slack/token-extractor.js +35 -229
  146. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  147. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  148. package/dist/src/platforms/slackbot/cli.js +1 -1
  149. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  150. package/dist/src/platforms/teams/client.d.ts.map +1 -1
  151. package/dist/src/platforms/teams/client.js +1 -1
  152. package/dist/src/platforms/teams/client.js.map +1 -1
  153. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  154. package/dist/src/platforms/teams/commands/auth.js +4 -1
  155. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  156. package/dist/src/platforms/teams/commands/snapshot.d.ts +1 -0
  157. package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
  158. package/dist/src/platforms/teams/commands/snapshot.js +44 -31
  159. package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
  160. package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -1
  161. package/dist/src/platforms/teams/commands/whoami.js.map +1 -1
  162. package/dist/src/platforms/teams/token-extractor.d.ts +6 -18
  163. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  164. package/dist/src/platforms/teams/token-extractor.js +71 -324
  165. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  166. package/dist/src/platforms/telegram/cli.d.ts.map +1 -1
  167. package/dist/src/platforms/telegram/cli.js +1 -4
  168. package/dist/src/platforms/telegram/cli.js.map +1 -1
  169. package/dist/src/platforms/telegram/client.d.ts.map +1 -1
  170. package/dist/src/platforms/telegram/client.js.map +1 -1
  171. package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
  172. package/dist/src/platforms/telegram/commands/auth.js +1 -1
  173. package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
  174. package/dist/src/platforms/telegram/commands/chat.d.ts.map +1 -1
  175. package/dist/src/platforms/telegram/commands/chat.js.map +1 -1
  176. package/dist/src/platforms/telegram/commands/message.d.ts.map +1 -1
  177. package/dist/src/platforms/telegram/commands/message.js.map +1 -1
  178. package/dist/src/platforms/telegram/commands/whoami.js +1 -1
  179. package/dist/src/platforms/telegram/commands/whoami.js.map +1 -1
  180. package/dist/src/platforms/telegram/credential-manager.d.ts.map +1 -1
  181. package/dist/src/platforms/telegram/credential-manager.js +6 -2
  182. package/dist/src/platforms/telegram/credential-manager.js.map +1 -1
  183. package/dist/src/platforms/telegram/my-telegram-org.js.map +1 -1
  184. package/dist/src/platforms/webex/cli.d.ts.map +1 -1
  185. package/dist/src/platforms/webex/cli.js +1 -4
  186. package/dist/src/platforms/webex/cli.js.map +1 -1
  187. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  188. package/dist/src/platforms/webex/client.js +3 -7
  189. package/dist/src/platforms/webex/client.js.map +1 -1
  190. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  191. package/dist/src/platforms/webex/commands/auth.js +1 -3
  192. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  193. package/dist/src/platforms/webex/commands/member.d.ts.map +1 -1
  194. package/dist/src/platforms/webex/commands/member.js +1 -3
  195. package/dist/src/platforms/webex/commands/member.js.map +1 -1
  196. package/dist/src/platforms/webex/commands/message.d.ts.map +1 -1
  197. package/dist/src/platforms/webex/commands/message.js.map +1 -1
  198. package/dist/src/platforms/webex/commands/snapshot.d.ts +1 -0
  199. package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
  200. package/dist/src/platforms/webex/commands/snapshot.js +14 -7
  201. package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
  202. package/dist/src/platforms/webex/commands/space.d.ts.map +1 -1
  203. package/dist/src/platforms/webex/commands/space.js.map +1 -1
  204. package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -1
  205. package/dist/src/platforms/webex/commands/whoami.js.map +1 -1
  206. package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -1
  207. package/dist/src/platforms/webex/credential-manager.js.map +1 -1
  208. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
  209. package/dist/src/platforms/webex/ensure-auth.js +1 -3
  210. package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
  211. package/dist/src/platforms/webex/index.d.ts +1 -1
  212. package/dist/src/platforms/webex/index.d.ts.map +1 -1
  213. package/dist/src/platforms/webex/index.js.map +1 -1
  214. package/dist/src/platforms/webex/markdown-to-html.js.map +1 -1
  215. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  216. package/dist/src/platforms/webex/token-extractor.js +5 -14
  217. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  218. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -1
  219. package/dist/src/platforms/wechatbot/client.js.map +1 -1
  220. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
  221. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
  222. package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
  223. package/dist/src/platforms/whatsapp/cli.js +1 -4
  224. package/dist/src/platforms/whatsapp/cli.js.map +1 -1
  225. package/dist/src/platforms/whatsapp/commands/chat.d.ts.map +1 -1
  226. package/dist/src/platforms/whatsapp/commands/chat.js.map +1 -1
  227. package/dist/src/platforms/whatsapp/commands/message.d.ts.map +1 -1
  228. package/dist/src/platforms/whatsapp/commands/message.js.map +1 -1
  229. package/dist/src/platforms/whatsapp/commands/shared.d.ts.map +1 -1
  230. package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
  231. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  232. package/dist/src/platforms/whatsapp/credential-manager.js +1 -1
  233. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  234. package/dist/src/platforms/whatsapp/ensure-auth.d.ts.map +1 -1
  235. package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
  236. package/dist/src/platforms/whatsappbot/client.d.ts.map +1 -1
  237. package/dist/src/platforms/whatsappbot/client.js +2 -2
  238. package/dist/src/platforms/whatsappbot/client.js.map +1 -1
  239. package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
  240. package/dist/src/platforms/whatsappbot/commands/auth.js +4 -1
  241. package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
  242. package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
  243. package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
  244. package/dist/src/platforms/whatsappbot/commands/shared.d.ts.map +1 -1
  245. package/dist/src/platforms/whatsappbot/commands/shared.js.map +1 -1
  246. package/dist/src/shared/chromium/browsers.d.ts +7 -0
  247. package/dist/src/shared/chromium/browsers.d.ts.map +1 -0
  248. package/dist/src/shared/chromium/browsers.js +89 -0
  249. package/dist/src/shared/chromium/browsers.js.map +1 -0
  250. package/dist/src/shared/chromium/cookie-reader.d.ts +20 -0
  251. package/dist/src/shared/chromium/cookie-reader.d.ts.map +1 -0
  252. package/dist/src/shared/chromium/cookie-reader.js +99 -0
  253. package/dist/src/shared/chromium/cookie-reader.js.map +1 -0
  254. package/dist/src/shared/chromium/decryptor.d.ts +42 -0
  255. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -0
  256. package/dist/src/shared/chromium/decryptor.js +205 -0
  257. package/dist/src/shared/chromium/decryptor.js.map +1 -0
  258. package/dist/src/shared/chromium/index.d.ts +6 -0
  259. package/dist/src/shared/chromium/index.d.ts.map +1 -0
  260. package/dist/src/shared/chromium/index.js +4 -0
  261. package/dist/src/shared/chromium/index.js.map +1 -0
  262. package/dist/src/shared/chromium/types.d.ts +11 -0
  263. package/dist/src/shared/chromium/types.d.ts.map +1 -0
  264. package/dist/src/shared/chromium/types.js +2 -0
  265. package/dist/src/shared/chromium/types.js.map +1 -0
  266. package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
  267. package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
  268. package/dist/src/shared/utils/linux-keyring.js +4 -1
  269. package/dist/src/shared/utils/linux-keyring.js.map +1 -1
  270. package/dist/src/tui/adapters/kakaotalk-adapter.d.ts.map +1 -1
  271. package/dist/src/tui/adapters/kakaotalk-adapter.js +6 -1
  272. package/dist/src/tui/adapters/kakaotalk-adapter.js.map +1 -1
  273. package/dist/src/tui/adapters/telegram-adapter.js +1 -1
  274. package/dist/src/tui/adapters/telegram-adapter.js.map +1 -1
  275. package/dist/src/tui/adapters/webex-adapter.js +1 -1
  276. package/dist/src/tui/adapters/webex-adapter.js.map +1 -1
  277. package/dist/src/tui/app.d.ts.map +1 -1
  278. package/dist/src/tui/app.js +112 -23
  279. package/dist/src/tui/app.js.map +1 -1
  280. package/dist/src/tui/utils.d.ts.map +1 -1
  281. package/dist/src/tui/utils.js +11 -13
  282. package/dist/src/tui/utils.js.map +1 -1
  283. package/dist/src/tui/views/channel-picker.d.ts.map +1 -1
  284. package/dist/src/tui/views/channel-picker.js.map +1 -1
  285. package/dist/src/tui/views/workspace-picker.d.ts.map +1 -1
  286. package/dist/src/tui/views/workspace-picker.js.map +1 -1
  287. package/docs/content/docs/agent-skills.mdx +0 -10
  288. package/docs/content/docs/cli/channeltalk.mdx +42 -30
  289. package/docs/content/docs/cli/channeltalkbot.mdx +23 -13
  290. package/docs/content/docs/cli/discord.mdx +23 -7
  291. package/docs/content/docs/cli/discordbot.mdx +23 -7
  292. package/docs/content/docs/cli/instagram.mdx +4 -4
  293. package/docs/content/docs/cli/kakaotalk.mdx +9 -8
  294. package/docs/content/docs/cli/line.mdx +14 -14
  295. package/docs/content/docs/cli/slack.mdx +24 -7
  296. package/docs/content/docs/cli/teams.mdx +24 -8
  297. package/docs/content/docs/cli/webex.mdx +34 -21
  298. package/docs/content/docs/cli/wechatbot.mdx +12 -11
  299. package/docs/content/docs/cli/whatsapp.mdx +5 -4
  300. package/docs/content/docs/cli/whatsappbot.mdx +11 -11
  301. package/docs/content/docs/index.mdx +7 -7
  302. package/docs/content/docs/meta.json +1 -9
  303. package/docs/content/docs/sdk/channeltalk.mdx +5 -6
  304. package/docs/content/docs/sdk/channeltalkbot.mdx +6 -12
  305. package/docs/content/docs/sdk/discord.mdx +36 -43
  306. package/docs/content/docs/sdk/instagram.mdx +18 -18
  307. package/docs/content/docs/sdk/kakaotalk.mdx +27 -18
  308. package/docs/content/docs/sdk/line.mdx +8 -13
  309. package/docs/content/docs/sdk/meta.json +14 -1
  310. package/docs/content/docs/sdk/slack.mdx +36 -42
  311. package/docs/content/docs/sdk/teams.mdx +2 -8
  312. package/docs/content/docs/sdk/webex.mdx +2 -12
  313. package/docs/content/docs/sdk/wechatbot.mdx +1 -5
  314. package/docs/content/docs/sdk/whatsapp.mdx +10 -19
  315. package/docs/content/docs/sdk/whatsappbot.mdx +2 -10
  316. package/docs/content/docs/tui.mdx +23 -23
  317. package/docs/src/app/page.tsx +353 -108
  318. package/e2e/channeltalkbot.e2e.test.ts +1 -5
  319. package/e2e/config.ts +6 -2
  320. package/package.json +59 -58
  321. package/scripts/prepublish.ts +1 -3
  322. package/skills/agent-channeltalk/SKILL.md +19 -9
  323. package/skills/agent-channeltalk/references/common-patterns.md +10 -9
  324. package/skills/agent-channeltalkbot/SKILL.md +19 -9
  325. package/skills/agent-channeltalkbot/references/common-patterns.md +10 -9
  326. package/skills/agent-discord/SKILL.md +18 -9
  327. package/skills/agent-discord/references/common-patterns.md +8 -7
  328. package/skills/agent-discordbot/SKILL.md +18 -9
  329. package/skills/agent-instagram/SKILL.md +1 -1
  330. package/skills/agent-kakaotalk/SKILL.md +1 -1
  331. package/skills/agent-line/SKILL.md +1 -1
  332. package/skills/agent-slack/SKILL.md +19 -10
  333. package/skills/agent-slack/references/common-patterns.md +4 -7
  334. package/skills/agent-slackbot/SKILL.md +1 -1
  335. package/skills/agent-teams/SKILL.md +18 -9
  336. package/skills/agent-teams/references/common-patterns.md +9 -7
  337. package/skills/agent-telegram/SKILL.md +1 -1
  338. package/skills/agent-webex/SKILL.md +13 -4
  339. package/skills/agent-webex/references/common-patterns.md +8 -2
  340. package/skills/agent-wechatbot/SKILL.md +1 -1
  341. package/skills/agent-whatsapp/SKILL.md +1 -1
  342. package/skills/agent-whatsappbot/SKILL.md +1 -1
  343. package/src/platforms/channeltalk/client.test.ts +116 -29
  344. package/src/platforms/channeltalk/client.ts +26 -6
  345. package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
  346. package/src/platforms/channeltalk/commands/auth.ts +19 -5
  347. package/src/platforms/channeltalk/commands/message.test.ts +2 -6
  348. package/src/platforms/channeltalk/commands/message.ts +5 -1
  349. package/src/platforms/channeltalk/commands/snapshot.test.ts +77 -30
  350. package/src/platforms/channeltalk/commands/snapshot.ts +112 -34
  351. package/src/platforms/channeltalk/ensure-auth.test.ts +20 -17
  352. package/src/platforms/channeltalk/ensure-auth.ts +6 -7
  353. package/src/platforms/channeltalk/index.ts +0 -1
  354. package/src/platforms/channeltalk/token-extractor.test.ts +33 -25
  355. package/src/platforms/channeltalk/token-extractor.ts +120 -372
  356. package/src/platforms/channeltalkbot/client.test.ts +1 -3
  357. package/src/platforms/channeltalkbot/client.ts +39 -13
  358. package/src/platforms/channeltalkbot/commands/auth.test.ts +3 -1
  359. package/src/platforms/channeltalkbot/commands/auth.ts +4 -1
  360. package/src/platforms/channeltalkbot/commands/bot.test.ts +13 -5
  361. package/src/platforms/channeltalkbot/commands/message.test.ts +12 -6
  362. package/src/platforms/channeltalkbot/commands/shared.ts +6 -2
  363. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +43 -13
  364. package/src/platforms/channeltalkbot/commands/snapshot.ts +131 -64
  365. package/src/platforms/channeltalkbot/credential-manager.test.ts +1 -1
  366. package/src/platforms/channeltalkbot/index.test.ts +0 -2
  367. package/src/platforms/channeltalkbot/index.ts +0 -1
  368. package/src/platforms/discord/commands/auth.test.ts +6 -4
  369. package/src/platforms/discord/commands/auth.ts +14 -14
  370. package/src/platforms/discord/commands/snapshot.test.ts +1 -1
  371. package/src/platforms/discord/commands/snapshot.ts +58 -42
  372. package/src/platforms/discord/commands/whoami.test.ts +2 -4
  373. package/src/platforms/discord/commands/whoami.ts +2 -0
  374. package/src/platforms/discord/ensure-auth.test.ts +5 -3
  375. package/src/platforms/discord/index.ts +0 -1
  376. package/src/platforms/discord/listener.test.ts +7 -1
  377. package/src/platforms/discord/token-extractor.test.ts +18 -12
  378. package/src/platforms/discord/token-extractor.ts +46 -190
  379. package/src/platforms/discordbot/client.ts +1 -4
  380. package/src/platforms/discordbot/commands/auth.test.ts +3 -1
  381. package/src/platforms/discordbot/commands/channel.test.ts +3 -1
  382. package/src/platforms/discordbot/commands/message.test.ts +3 -1
  383. package/src/platforms/discordbot/commands/server.test.ts +3 -1
  384. package/src/platforms/discordbot/commands/snapshot.test.ts +43 -19
  385. package/src/platforms/discordbot/commands/snapshot.ts +54 -37
  386. package/src/platforms/discordbot/commands/thread.test.ts +3 -1
  387. package/src/platforms/discordbot/commands/user.test.ts +3 -1
  388. package/src/platforms/instagram/cli.ts +1 -4
  389. package/src/platforms/instagram/client.test.ts +3 -8
  390. package/src/platforms/instagram/client.ts +39 -34
  391. package/src/platforms/instagram/commands/auth.test.ts +13 -12
  392. package/src/platforms/instagram/commands/auth.ts +136 -71
  393. package/src/platforms/instagram/commands/chat.test.ts +21 -24
  394. package/src/platforms/instagram/commands/chat.ts +2 -0
  395. package/src/platforms/instagram/commands/message.test.ts +29 -24
  396. package/src/platforms/instagram/commands/message.ts +3 -4
  397. package/src/platforms/instagram/commands/shared.ts +2 -5
  398. package/src/platforms/instagram/commands/whoami.test.ts +4 -6
  399. package/src/platforms/instagram/credential-manager.ts +2 -6
  400. package/src/platforms/instagram/ensure-auth.test.ts +1 -4
  401. package/src/platforms/instagram/ensure-auth.ts +6 -3
  402. package/src/platforms/instagram/listener.test.ts +7 -3
  403. package/src/platforms/instagram/token-extractor.test.ts +4 -16
  404. package/src/platforms/instagram/token-extractor.ts +55 -309
  405. package/src/platforms/instagram/types.test.ts +2 -6
  406. package/src/platforms/instagram/types.ts +4 -2
  407. package/src/platforms/kakaotalk/auth/kakao-login.ts +30 -8
  408. package/src/platforms/kakaotalk/client.test.ts +37 -25
  409. package/src/platforms/kakaotalk/client.ts +23 -12
  410. package/src/platforms/kakaotalk/commands/auth.test.ts +6 -18
  411. package/src/platforms/kakaotalk/commands/auth.ts +101 -47
  412. package/src/platforms/kakaotalk/commands/chat.test.ts +8 -11
  413. package/src/platforms/kakaotalk/commands/message.test.ts +15 -24
  414. package/src/platforms/kakaotalk/commands/shared.ts +1 -0
  415. package/src/platforms/kakaotalk/commands/whoami.test.ts +6 -10
  416. package/src/platforms/kakaotalk/credential-manager.test.ts +1 -4
  417. package/src/platforms/kakaotalk/index.test.ts +1 -0
  418. package/src/platforms/kakaotalk/index.ts +0 -2
  419. package/src/platforms/kakaotalk/listener.test.ts +7 -1
  420. package/src/platforms/kakaotalk/protocol/connection.ts +4 -1
  421. package/src/platforms/kakaotalk/protocol/crypto.ts +1 -1
  422. package/src/platforms/kakaotalk/protocol/session.ts +12 -6
  423. package/src/platforms/kakaotalk/token-extractor.ts +5 -5
  424. package/src/platforms/kakaotalk/types.ts +8 -7
  425. package/src/platforms/line/cli.ts +1 -4
  426. package/src/platforms/line/client.ts +12 -20
  427. package/src/platforms/line/commands/auth.test.ts +2 -1
  428. package/src/platforms/line/commands/chat.test.ts +2 -1
  429. package/src/platforms/line/commands/chat.ts +1 -4
  430. package/src/platforms/line/commands/friend.test.ts +2 -1
  431. package/src/platforms/line/commands/message.test.ts +2 -1
  432. package/src/platforms/line/commands/message.ts +2 -9
  433. package/src/platforms/line/commands/whoami.test.ts +2 -1
  434. package/src/platforms/line/credential-manager.test.ts +1 -2
  435. package/src/platforms/line/index.test.ts +1 -0
  436. package/src/platforms/line/listener.ts +1 -1
  437. package/src/platforms/line/types.test.ts +1 -0
  438. package/src/platforms/slack/cli.ts +3 -1
  439. package/src/platforms/slack/client-mappers.ts +297 -0
  440. package/src/platforms/slack/client.test.ts +532 -17
  441. package/src/platforms/slack/client.ts +69 -458
  442. package/src/platforms/slack/commands/channel.ts +1 -4
  443. package/src/platforms/slack/commands/emoji.test.ts +6 -4
  444. package/src/platforms/slack/commands/emoji.ts +20 -22
  445. package/src/platforms/slack/commands/message.ts +6 -1
  446. package/src/platforms/slack/commands/pin.test.ts +14 -12
  447. package/src/platforms/slack/commands/reminder.ts +7 -6
  448. package/src/platforms/slack/commands/snapshot.test.ts +63 -8
  449. package/src/platforms/slack/commands/snapshot.ts +98 -66
  450. package/src/platforms/slack/commands/user.ts +6 -1
  451. package/src/platforms/slack/commands/usergroup.test.ts +3 -3
  452. package/src/platforms/slack/commands/usergroup.ts +10 -7
  453. package/src/platforms/slack/commands/whoami.test.ts +1 -1
  454. package/src/platforms/slack/commands/whoami.ts +2 -0
  455. package/src/platforms/slack/index.ts +0 -2
  456. package/src/platforms/slack/listener.test.ts +1 -0
  457. package/src/platforms/slack/token-extractor.test.ts +7 -12
  458. package/src/platforms/slack/token-extractor.ts +47 -255
  459. package/src/platforms/slackbot/cli.ts +8 -1
  460. package/src/platforms/slackbot/commands/auth.test.ts +3 -1
  461. package/src/platforms/teams/client.ts +1 -1
  462. package/src/platforms/teams/commands/auth.test.ts +1 -1
  463. package/src/platforms/teams/commands/auth.ts +4 -1
  464. package/src/platforms/teams/commands/snapshot.test.ts +1 -1
  465. package/src/platforms/teams/commands/snapshot.ts +53 -38
  466. package/src/platforms/teams/commands/whoami.test.ts +2 -4
  467. package/src/platforms/teams/commands/whoami.ts +2 -0
  468. package/src/platforms/teams/index.ts +0 -1
  469. package/src/platforms/teams/token-extractor.ts +82 -350
  470. package/src/platforms/telegram/app-config.test.ts +1 -0
  471. package/src/platforms/telegram/chat-utils.test.ts +5 -1
  472. package/src/platforms/telegram/cli.ts +2 -4
  473. package/src/platforms/telegram/client.test.ts +16 -3
  474. package/src/platforms/telegram/client.ts +14 -4
  475. package/src/platforms/telegram/commands/auth.test.ts +1 -0
  476. package/src/platforms/telegram/commands/auth.ts +3 -4
  477. package/src/platforms/telegram/commands/chat.test.ts +2 -5
  478. package/src/platforms/telegram/commands/chat.ts +1 -0
  479. package/src/platforms/telegram/commands/message.test.ts +2 -5
  480. package/src/platforms/telegram/commands/message.ts +1 -0
  481. package/src/platforms/telegram/commands/shared.test.ts +1 -0
  482. package/src/platforms/telegram/commands/whoami.test.ts +5 -7
  483. package/src/platforms/telegram/commands/whoami.ts +1 -1
  484. package/src/platforms/telegram/credential-manager.test.ts +1 -0
  485. package/src/platforms/telegram/credential-manager.ts +11 -2
  486. package/src/platforms/telegram/my-telegram-org.ts +6 -2
  487. package/src/platforms/telegram/types.test.ts +1 -0
  488. package/src/platforms/webex/app-config.test.ts +1 -0
  489. package/src/platforms/webex/cli.ts +1 -4
  490. package/src/platforms/webex/client.test.ts +4 -12
  491. package/src/platforms/webex/client.ts +14 -52
  492. package/src/platforms/webex/commands/auth.test.ts +7 -1
  493. package/src/platforms/webex/commands/auth.ts +12 -15
  494. package/src/platforms/webex/commands/member.test.ts +1 -3
  495. package/src/platforms/webex/commands/member.ts +14 -19
  496. package/src/platforms/webex/commands/message.ts +4 -15
  497. package/src/platforms/webex/commands/snapshot.test.ts +42 -4
  498. package/src/platforms/webex/commands/snapshot.ts +19 -11
  499. package/src/platforms/webex/commands/space.test.ts +3 -3
  500. package/src/platforms/webex/commands/space.ts +2 -9
  501. package/src/platforms/webex/commands/whoami.test.ts +12 -5
  502. package/src/platforms/webex/commands/whoami.ts +2 -0
  503. package/src/platforms/webex/credential-manager.ts +11 -2
  504. package/src/platforms/webex/ensure-auth.ts +1 -3
  505. package/src/platforms/webex/index.ts +1 -7
  506. package/src/platforms/webex/markdown-to-html.test.ts +6 -18
  507. package/src/platforms/webex/markdown-to-html.ts +8 -8
  508. package/src/platforms/webex/token-extractor.ts +6 -29
  509. package/src/platforms/wechatbot/client.test.ts +6 -2
  510. package/src/platforms/wechatbot/client.ts +6 -1
  511. package/src/platforms/wechatbot/commands/auth.test.ts +3 -7
  512. package/src/platforms/wechatbot/commands/message.test.ts +1 -4
  513. package/src/platforms/wechatbot/commands/message.ts +5 -1
  514. package/src/platforms/wechatbot/commands/template.test.ts +1 -4
  515. package/src/platforms/wechatbot/commands/user.test.ts +2 -7
  516. package/src/platforms/whatsapp/cli.ts +1 -4
  517. package/src/platforms/whatsapp/commands/auth.test.ts +19 -22
  518. package/src/platforms/whatsapp/commands/chat.test.ts +21 -24
  519. package/src/platforms/whatsapp/commands/chat.ts +2 -0
  520. package/src/platforms/whatsapp/commands/message.test.ts +22 -24
  521. package/src/platforms/whatsapp/commands/message.ts +3 -5
  522. package/src/platforms/whatsapp/commands/shared.ts +2 -5
  523. package/src/platforms/whatsapp/commands/whoami.test.ts +2 -2
  524. package/src/platforms/whatsapp/credential-manager.ts +2 -6
  525. package/src/platforms/whatsapp/ensure-auth.test.ts +1 -4
  526. package/src/platforms/whatsapp/ensure-auth.ts +14 -6
  527. package/src/platforms/whatsapp/index.ts +0 -2
  528. package/src/platforms/whatsappbot/client.test.ts +13 -7
  529. package/src/platforms/whatsappbot/client.ts +18 -4
  530. package/src/platforms/whatsappbot/commands/auth.ts +4 -1
  531. package/src/platforms/whatsappbot/commands/message.test.ts +12 -2
  532. package/src/platforms/whatsappbot/commands/message.ts +16 -3
  533. package/src/platforms/whatsappbot/commands/shared.ts +3 -1
  534. package/src/platforms/whatsappbot/commands/whoami.test.ts +1 -3
  535. package/src/platforms/whatsappbot/index.ts +0 -2
  536. package/src/shared/chromium/browsers.test.ts +274 -0
  537. package/src/shared/chromium/browsers.ts +86 -0
  538. package/src/shared/chromium/cookie-reader.test.ts +274 -0
  539. package/src/shared/chromium/cookie-reader.ts +111 -0
  540. package/src/shared/chromium/decryptor.test.ts +449 -0
  541. package/src/shared/chromium/decryptor.ts +227 -0
  542. package/src/shared/chromium/index.ts +11 -0
  543. package/src/shared/chromium/types.ts +11 -0
  544. package/src/shared/utils/derived-key-cache.ts +1 -1
  545. package/src/shared/utils/linux-keyring.ts +4 -4
  546. package/src/tui/adapters/kakaotalk-adapter.ts +6 -1
  547. package/src/tui/adapters/telegram-adapter.ts +1 -1
  548. package/src/tui/adapters/webex-adapter.ts +1 -1
  549. package/src/tui/app.ts +149 -59
  550. package/src/tui/utils.test.ts +144 -145
  551. package/src/tui/utils.ts +27 -29
  552. package/src/tui/views/channel-picker.ts +1 -1
  553. package/src/tui/views/workspace-picker.ts +1 -1
@@ -14,5 +14,3 @@ export {
14
14
  WhatsAppBotCredentialsSchema,
15
15
  WhatsAppBotError,
16
16
  } from './types'
17
-
18
-
@@ -0,0 +1,274 @@
1
+ import { afterEach, describe, expect, test } from 'bun:test'
2
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
+ import { tmpdir } from 'node:os'
4
+ import { join } from 'node:path'
5
+
6
+ import {
7
+ BROWSER_KEYCHAIN_VARIANTS,
8
+ CHROMIUM_BROWSERS,
9
+ discoverBrowserProfileDirs,
10
+ findLocalStatePath,
11
+ getBrowserBasePath,
12
+ } from './browsers'
13
+
14
+ describe('browsers', () => {
15
+ const tempDirs: string[] = []
16
+ const originalLocalAppData = process.env.LOCALAPPDATA
17
+
18
+ afterEach(() => {
19
+ process.env.LOCALAPPDATA = originalLocalAppData
20
+
21
+ for (const tempDir of tempDirs.splice(0)) {
22
+ if (existsSync(tempDir)) {
23
+ rmSync(tempDir, { recursive: true, force: true })
24
+ }
25
+ }
26
+ })
27
+
28
+ describe('CHROMIUM_BROWSERS', () => {
29
+ test('has 7 browsers', () => {
30
+ expect(CHROMIUM_BROWSERS).toHaveLength(7)
31
+ })
32
+
33
+ test('includes major supported browsers', () => {
34
+ const browserNames = CHROMIUM_BROWSERS.map((browser) => browser.name)
35
+
36
+ expect(browserNames).toEqual(expect.arrayContaining(['Chrome', 'Edge', 'Arc', 'Brave', 'Vivaldi', 'Chromium']))
37
+ })
38
+
39
+ test('Arc has empty linux path', () => {
40
+ expect(CHROMIUM_BROWSERS.find((browser) => browser.name === 'Arc')?.linux).toBe('')
41
+ })
42
+ })
43
+
44
+ describe('BROWSER_KEYCHAIN_VARIANTS', () => {
45
+ test('has 7 keychain variants', () => {
46
+ expect(BROWSER_KEYCHAIN_VARIANTS).toHaveLength(7)
47
+ })
48
+
49
+ test('each variant has service and account properties', () => {
50
+ for (const variant of BROWSER_KEYCHAIN_VARIANTS) {
51
+ expect(variant.service).toBeString()
52
+ expect(variant.account).toBeString()
53
+ }
54
+ })
55
+
56
+ test('includes known safe storage services', () => {
57
+ const services = BROWSER_KEYCHAIN_VARIANTS.map((variant) => variant.service)
58
+
59
+ expect(services).toEqual(expect.arrayContaining(['Chrome Safe Storage', 'Microsoft Edge Safe Storage']))
60
+ })
61
+ })
62
+
63
+ describe('getBrowserBasePath', () => {
64
+ test('returns darwin path with Library/Application Support prefix', () => {
65
+ // given
66
+ const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
67
+
68
+ // when
69
+ const path = getBrowserBasePath(chrome, 'darwin')
70
+
71
+ // then
72
+ expect(path).not.toBeNull()
73
+ expect(path).toContain(join('Library', 'Application Support'))
74
+ expect(path).toEndWith(join('Google', 'Chrome'))
75
+ })
76
+
77
+ test('returns linux path with .config prefix', () => {
78
+ // given
79
+ const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
80
+
81
+ // when
82
+ const path = getBrowserBasePath(chrome, 'linux')
83
+
84
+ // then
85
+ expect(path).not.toBeNull()
86
+ expect(path).toContain(join('.config', 'google-chrome'))
87
+ })
88
+
89
+ test('returns win32 path with LOCALAPPDATA prefix', () => {
90
+ // given
91
+ const localAppData = mkdtempSync(join(tmpdir(), 'browser-localappdata-'))
92
+ tempDirs.push(localAppData)
93
+ process.env.LOCALAPPDATA = localAppData
94
+ const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
95
+
96
+ // when
97
+ const path = getBrowserBasePath(chrome, 'win32')
98
+
99
+ // then
100
+ expect(path).toBe(join(localAppData, 'Google', 'Chrome', 'User Data'))
101
+ })
102
+
103
+ test('returns null for unsupported platform', () => {
104
+ // given
105
+ const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
106
+
107
+ // when
108
+ const path = getBrowserBasePath(chrome, 'freebsd' as NodeJS.Platform)
109
+
110
+ // then
111
+ expect(path).toBeNull()
112
+ })
113
+
114
+ test('returns null when browser has empty path for platform', () => {
115
+ // given
116
+ const arc = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Arc')!
117
+
118
+ // when
119
+ const path = getBrowserBasePath(arc, 'linux')
120
+
121
+ // then
122
+ expect(path).toBeNull()
123
+ })
124
+ })
125
+
126
+ describe('discoverBrowserProfileDirs', () => {
127
+ test('always includes Default dir even when base does not exist', () => {
128
+ // given
129
+ const browserBase = join(tmpdir(), `missing-browser-base-${Date.now()}-${Math.random().toString(36).slice(2)}`)
130
+
131
+ // when
132
+ const dirs = discoverBrowserProfileDirs(browserBase)
133
+
134
+ // then
135
+ expect(dirs).toEqual([join(browserBase, 'Default')])
136
+ })
137
+
138
+ test('discovers Profile 1 and Profile 2 dirs when they exist', () => {
139
+ // given
140
+ const browserBase = mkdtempSync(join(tmpdir(), 'browser-profiles-'))
141
+ tempDirs.push(browserBase)
142
+ mkdirSync(join(browserBase, 'Profile 1'))
143
+ mkdirSync(join(browserBase, 'Profile 2'))
144
+
145
+ // when
146
+ const dirs = discoverBrowserProfileDirs(browserBase)
147
+
148
+ // then
149
+ expect(dirs).toEqual([
150
+ join(browserBase, 'Default'),
151
+ join(browserBase, 'Profile 1'),
152
+ join(browserBase, 'Profile 2'),
153
+ ])
154
+ })
155
+
156
+ test('ignores non-profile directories', () => {
157
+ // given
158
+ const browserBase = mkdtempSync(join(tmpdir(), 'browser-non-profile-'))
159
+ tempDirs.push(browserBase)
160
+ mkdirSync(join(browserBase, 'Cache'))
161
+ mkdirSync(join(browserBase, 'Extensions'))
162
+ mkdirSync(join(browserBase, 'Profile 1'))
163
+
164
+ // when
165
+ const dirs = discoverBrowserProfileDirs(browserBase)
166
+
167
+ // then
168
+ expect(dirs).toEqual([join(browserBase, 'Default'), join(browserBase, 'Profile 1')])
169
+ })
170
+
171
+ test('ignores files that match profile pattern', () => {
172
+ // given
173
+ const browserBase = mkdtempSync(join(tmpdir(), 'browser-profile-files-'))
174
+ tempDirs.push(browserBase)
175
+ writeFileSync(join(browserBase, 'Profile 1'), '')
176
+ mkdirSync(join(browserBase, 'Profile 2'))
177
+
178
+ // when
179
+ const dirs = discoverBrowserProfileDirs(browserBase)
180
+
181
+ // then
182
+ expect(dirs).toEqual([join(browserBase, 'Default'), join(browserBase, 'Profile 2')])
183
+ })
184
+
185
+ test('returns only Default when base directory is empty', () => {
186
+ // given
187
+ const browserBase = mkdtempSync(join(tmpdir(), 'browser-empty-'))
188
+ tempDirs.push(browserBase)
189
+
190
+ // when
191
+ const dirs = discoverBrowserProfileDirs(browserBase)
192
+
193
+ // then
194
+ expect(dirs).toEqual([join(browserBase, 'Default')])
195
+ })
196
+ })
197
+
198
+ describe('findLocalStatePath', () => {
199
+ test('returns null when no Local State exists at any level', () => {
200
+ // given
201
+ const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-missing-'))
202
+ tempDirs.push(rootDir)
203
+ const cookiePath = join(rootDir, 'Browser', 'Default', 'Network', 'Cookies')
204
+ mkdirSync(join(rootDir, 'Browser', 'Default', 'Network'), { recursive: true })
205
+
206
+ // when
207
+ const path = findLocalStatePath(cookiePath)
208
+
209
+ // then
210
+ expect(path).toBeNull()
211
+ })
212
+
213
+ test('finds Local State 2 levels up from cookie path', () => {
214
+ // given
215
+ const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-two-'))
216
+ tempDirs.push(rootDir)
217
+ const profileDir = join(rootDir, 'Browser', 'Default')
218
+ const cookiePath = join(profileDir, 'Network', 'Cookies')
219
+ mkdirSync(join(profileDir, 'Network'), { recursive: true })
220
+ writeFileSync(join(profileDir, 'Local State'), '')
221
+
222
+ // when
223
+ const path = findLocalStatePath(cookiePath)
224
+
225
+ // then
226
+ expect(path).toBe(join(profileDir, 'Local State'))
227
+ })
228
+
229
+ test('finds Local State 3 levels up from cookie path', () => {
230
+ // given
231
+ const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-three-'))
232
+ tempDirs.push(rootDir)
233
+ const browserDir = join(rootDir, 'Browser')
234
+ const cookiePath = join(browserDir, 'Default', 'Network', 'Cookies')
235
+ mkdirSync(join(browserDir, 'Default', 'Network'), { recursive: true })
236
+ writeFileSync(join(browserDir, 'Local State'), '')
237
+
238
+ // when
239
+ const path = findLocalStatePath(cookiePath)
240
+
241
+ // then
242
+ expect(path).toBe(join(browserDir, 'Local State'))
243
+ })
244
+
245
+ test('returns null for path with too few segments', () => {
246
+ // given
247
+ const cookiePath = 'Cookies'
248
+
249
+ // when
250
+ const path = findLocalStatePath(cookiePath)
251
+
252
+ // then
253
+ expect(path).toBeNull()
254
+ })
255
+
256
+ test('finds the first match when multiple levels could match', () => {
257
+ // given
258
+ const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-first-'))
259
+ tempDirs.push(rootDir)
260
+ const browserDir = join(rootDir, 'Browser')
261
+ const profileDir = join(browserDir, 'Default')
262
+ const cookiePath = join(profileDir, 'Network', 'Cookies')
263
+ mkdirSync(join(profileDir, 'Network'), { recursive: true })
264
+ writeFileSync(join(profileDir, 'Local State'), '')
265
+ writeFileSync(join(browserDir, 'Local State'), '')
266
+
267
+ // when
268
+ const path = findLocalStatePath(cookiePath)
269
+
270
+ // then
271
+ expect(path).toBe(join(profileDir, 'Local State'))
272
+ })
273
+ })
274
+ })
@@ -0,0 +1,86 @@
1
+ import { existsSync, readdirSync } from 'node:fs'
2
+ import { homedir } from 'node:os'
3
+ import { join } from 'node:path'
4
+
5
+ import type { BrowserConfig, KeychainVariant } from './types'
6
+
7
+ export const CHROMIUM_BROWSERS: BrowserConfig[] = [
8
+ {
9
+ name: 'Chrome',
10
+ darwin: join('Google', 'Chrome'),
11
+ linux: 'google-chrome',
12
+ win32: join('Google', 'Chrome', 'User Data'),
13
+ },
14
+ {
15
+ name: 'Chrome Canary',
16
+ darwin: join('Google', 'Chrome Canary'),
17
+ linux: 'google-chrome-unstable',
18
+ win32: join('Google', 'Chrome SxS', 'User Data'),
19
+ },
20
+ { name: 'Edge', darwin: 'Microsoft Edge', linux: 'microsoft-edge', win32: join('Microsoft', 'Edge', 'User Data') },
21
+ { name: 'Arc', darwin: join('Arc', 'User Data'), linux: '', win32: join('Arc', 'User Data') },
22
+ {
23
+ name: 'Brave',
24
+ darwin: join('BraveSoftware', 'Brave-Browser'),
25
+ linux: join('BraveSoftware', 'Brave-Browser'),
26
+ win32: join('BraveSoftware', 'Brave-Browser', 'User Data'),
27
+ },
28
+ { name: 'Vivaldi', darwin: 'Vivaldi', linux: 'vivaldi', win32: join('Vivaldi', 'User Data') },
29
+ { name: 'Chromium', darwin: 'Chromium', linux: 'chromium', win32: join('Chromium', 'User Data') },
30
+ ]
31
+
32
+ export const BROWSER_KEYCHAIN_VARIANTS: KeychainVariant[] = [
33
+ { service: 'Chrome Safe Storage', account: 'Chrome' },
34
+ { service: 'Chrome Canary Safe Storage', account: 'Chrome Canary' },
35
+ { service: 'Microsoft Edge Safe Storage', account: 'Microsoft Edge' },
36
+ { service: 'Arc Safe Storage', account: 'Arc' },
37
+ { service: 'Brave Safe Storage', account: 'Brave' },
38
+ { service: 'Vivaldi Safe Storage', account: 'Vivaldi' },
39
+ { service: 'Chromium Safe Storage', account: 'Chromium' },
40
+ ]
41
+
42
+ export function getBrowserBasePath(browser: BrowserConfig, platform: NodeJS.Platform): string | null {
43
+ let relative: string
44
+ switch (platform) {
45
+ case 'darwin':
46
+ relative = browser.darwin
47
+ if (!relative) return null
48
+ return join(homedir(), 'Library', 'Application Support', relative)
49
+ case 'linux':
50
+ relative = browser.linux
51
+ if (!relative) return null
52
+ return join(homedir(), '.config', relative)
53
+ case 'win32':
54
+ relative = browser.win32
55
+ if (!relative) return null
56
+ return join(process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'), relative)
57
+ default:
58
+ return null
59
+ }
60
+ }
61
+
62
+ export function discoverBrowserProfileDirs(browserBase: string): string[] {
63
+ const dirs: string[] = []
64
+ dirs.push(join(browserBase, 'Default'))
65
+ if (!existsSync(browserBase)) return dirs
66
+ try {
67
+ const entries = readdirSync(browserBase, { withFileTypes: true })
68
+ for (const entry of entries) {
69
+ if (!entry.isDirectory()) continue
70
+ if (!/^Profile \d+$/i.test(entry.name)) continue
71
+ dirs.push(join(browserBase, entry.name))
72
+ }
73
+ } catch {}
74
+ return dirs
75
+ }
76
+
77
+ export function findLocalStatePath(cookieOrProfilePath: string): string | null {
78
+ const parts = cookieOrProfilePath.split(/[/\\]/)
79
+ for (let levels = 2; levels <= 4; levels++) {
80
+ if (parts.length < levels) break
81
+ const base = parts.slice(0, parts.length - levels).join('/')
82
+ const candidate = join(base, 'Local State')
83
+ if (existsSync(candidate)) return candidate
84
+ }
85
+ return null
86
+ }
@@ -0,0 +1,274 @@
1
+ import { Database } from 'bun:sqlite'
2
+ import { afterEach, describe, expect, test } from 'bun:test'
3
+ import { existsSync, mkdtempSync, rmSync } from 'node:fs'
4
+ import { tmpdir } from 'node:os'
5
+ import { join } from 'node:path'
6
+
7
+ import { ChromiumCookieReader } from './cookie-reader'
8
+
9
+ function createTestCookieDb(
10
+ dbPath: string,
11
+ rows: Array<{ name: string; value: string; encrypted_value: Buffer | null }>,
12
+ ): void {
13
+ const db = new Database(dbPath)
14
+ db.run('CREATE TABLE cookies (name TEXT, value TEXT, encrypted_value BLOB)')
15
+ const stmt = db.prepare('INSERT INTO cookies (name, value, encrypted_value) VALUES (?, ?, ?)')
16
+ for (const row of rows) {
17
+ stmt.run(row.name, row.value, row.encrypted_value)
18
+ }
19
+ db.close()
20
+ }
21
+
22
+ describe('ChromiumCookieReader', () => {
23
+ const tempDirs: string[] = []
24
+
25
+ afterEach(() => {
26
+ for (const tempDir of tempDirs.splice(0)) {
27
+ if (existsSync(tempDir)) {
28
+ rmSync(tempDir, { recursive: true, force: true })
29
+ }
30
+ }
31
+ })
32
+
33
+ describe('queryAll', () => {
34
+ test('returns all matching rows from a real SQLite database', async () => {
35
+ // given
36
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
37
+ tempDirs.push(tempDir)
38
+ const dbPath = join(tempDir, 'Cookies')
39
+ createTestCookieDb(dbPath, [
40
+ { name: 'session', value: 'abc123', encrypted_value: null },
41
+ { name: 'token', value: 'xyz789', encrypted_value: null },
42
+ ])
43
+ const reader = new ChromiumCookieReader()
44
+
45
+ // when
46
+ const result = await reader.queryAll<{ name: string; value: string }>(
47
+ dbPath,
48
+ 'SELECT name, value FROM cookies ORDER BY name ASC',
49
+ )
50
+
51
+ // then
52
+ expect(result).toEqual([
53
+ { name: 'session', value: 'abc123' },
54
+ { name: 'token', value: 'xyz789' },
55
+ ])
56
+ })
57
+
58
+ test('returns empty array when database file does not exist', async () => {
59
+ // given
60
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
61
+ tempDirs.push(tempDir)
62
+ const dbPath = join(tempDir, 'missing.db')
63
+ const reader = new ChromiumCookieReader()
64
+
65
+ // when
66
+ const result = await reader.queryAll<{ name: string }>(dbPath, 'SELECT name FROM cookies')
67
+
68
+ // then
69
+ expect(result).toEqual([])
70
+ })
71
+
72
+ test('returns empty array when query matches no rows', async () => {
73
+ // given
74
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
75
+ tempDirs.push(tempDir)
76
+ const dbPath = join(tempDir, 'Cookies')
77
+ createTestCookieDb(dbPath, [{ name: 'session', value: 'abc123', encrypted_value: null }])
78
+ const reader = new ChromiumCookieReader()
79
+
80
+ // when
81
+ const result = await reader.queryAll<{ name: string }>(dbPath, 'SELECT name FROM cookies WHERE name = ?', [
82
+ 'missing',
83
+ ])
84
+
85
+ // then
86
+ expect(result).toEqual([])
87
+ })
88
+
89
+ test('supports parameterized queries with params', async () => {
90
+ // given
91
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
92
+ tempDirs.push(tempDir)
93
+ const dbPath = join(tempDir, 'Cookies')
94
+ createTestCookieDb(dbPath, [
95
+ { name: 'session', value: 'abc123', encrypted_value: null },
96
+ { name: 'token', value: 'xyz789', encrypted_value: null },
97
+ ])
98
+ const reader = new ChromiumCookieReader()
99
+
100
+ // when
101
+ const result = await reader.queryAll<{ name: string; value: string }>(
102
+ dbPath,
103
+ 'SELECT name, value FROM cookies WHERE name = ?',
104
+ ['token'],
105
+ )
106
+
107
+ // then
108
+ expect(result).toEqual([{ name: 'token', value: 'xyz789' }])
109
+ })
110
+
111
+ test('cleans up temp file after query', async () => {
112
+ // given
113
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
114
+ tempDirs.push(tempDir)
115
+ const dbPath = join(tempDir, 'Cookies')
116
+ createTestCookieDb(dbPath, [{ name: 'session', value: 'abc123', encrypted_value: null }])
117
+ const reader = new ChromiumCookieReader()
118
+ const originalDateNow = Date.now
119
+ const originalMathRandom = Math.random
120
+ Date.now = () => 1234567890
121
+ Math.random = () => 0
122
+ const expectedTempPath = join(tmpdir(), 'chromium-cookies-1234567890-.db')
123
+
124
+ try {
125
+ // when
126
+ await reader.queryAll<{ name: string }>(dbPath, 'SELECT name FROM cookies')
127
+
128
+ // then
129
+ expect(existsSync(expectedTempPath)).toBe(false)
130
+ } finally {
131
+ Date.now = originalDateNow
132
+ Math.random = originalMathRandom
133
+ }
134
+ })
135
+ })
136
+
137
+ describe('queryFirst', () => {
138
+ test('returns first matching row from a real SQLite database', async () => {
139
+ // given
140
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
141
+ tempDirs.push(tempDir)
142
+ const dbPath = join(tempDir, 'Cookies')
143
+ createTestCookieDb(dbPath, [
144
+ { name: 'session', value: 'abc123', encrypted_value: null },
145
+ { name: 'token', value: 'xyz789', encrypted_value: null },
146
+ ])
147
+ const reader = new ChromiumCookieReader()
148
+
149
+ // when
150
+ const result = await reader.queryFirst<{ name: string; value: string }>(
151
+ dbPath,
152
+ 'SELECT name, value FROM cookies ORDER BY name ASC',
153
+ )
154
+
155
+ // then
156
+ expect(result).toEqual({ name: 'session', value: 'abc123' })
157
+ })
158
+
159
+ test('returns null when database file does not exist', async () => {
160
+ // given
161
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
162
+ tempDirs.push(tempDir)
163
+ const dbPath = join(tempDir, 'missing.db')
164
+ const reader = new ChromiumCookieReader()
165
+
166
+ // when
167
+ const result = await reader.queryFirst<{ name: string }>(dbPath, 'SELECT name FROM cookies')
168
+
169
+ // then
170
+ expect(result).toBeNull()
171
+ })
172
+
173
+ test('returns null when query matches no rows', async () => {
174
+ // given
175
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
176
+ tempDirs.push(tempDir)
177
+ const dbPath = join(tempDir, 'Cookies')
178
+ createTestCookieDb(dbPath, [{ name: 'session', value: 'abc123', encrypted_value: null }])
179
+ const reader = new ChromiumCookieReader()
180
+
181
+ // when
182
+ const result = await reader.queryFirst<{ name: string }>(dbPath, 'SELECT name FROM cookies WHERE name = ?', [
183
+ 'missing',
184
+ ])
185
+
186
+ // then
187
+ expect(result).toBeNull()
188
+ })
189
+
190
+ test('supports parameterized queries with params', async () => {
191
+ // given
192
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
193
+ tempDirs.push(tempDir)
194
+ const dbPath = join(tempDir, 'Cookies')
195
+ createTestCookieDb(dbPath, [
196
+ { name: 'session', value: 'abc123', encrypted_value: null },
197
+ { name: 'token', value: 'xyz789', encrypted_value: null },
198
+ ])
199
+ const reader = new ChromiumCookieReader()
200
+
201
+ // when
202
+ const result = await reader.queryFirst<{ name: string; value: string }>(
203
+ dbPath,
204
+ 'SELECT name, value FROM cookies WHERE name = ?',
205
+ ['token'],
206
+ )
207
+
208
+ // then
209
+ expect(result).toEqual({ name: 'token', value: 'xyz789' })
210
+ })
211
+ })
212
+
213
+ describe('edge cases', () => {
214
+ test('handles multiple calls to same reader instance', async () => {
215
+ // given
216
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
217
+ tempDirs.push(tempDir)
218
+ const dbPath = join(tempDir, 'Cookies')
219
+ createTestCookieDb(dbPath, [
220
+ { name: 'session', value: 'abc123', encrypted_value: null },
221
+ { name: 'token', value: 'xyz789', encrypted_value: null },
222
+ ])
223
+ const reader = new ChromiumCookieReader()
224
+
225
+ // when
226
+ const allRows = await reader.queryAll<{ name: string; value: string }>(
227
+ dbPath,
228
+ 'SELECT name, value FROM cookies ORDER BY name ASC',
229
+ )
230
+ const firstRow = await reader.queryFirst<{ name: string; value: string }>(
231
+ dbPath,
232
+ 'SELECT name, value FROM cookies WHERE name = ?',
233
+ ['token'],
234
+ )
235
+
236
+ // then
237
+ expect(allRows).toEqual([
238
+ { name: 'session', value: 'abc123' },
239
+ { name: 'token', value: 'xyz789' },
240
+ ])
241
+ expect(firstRow).toEqual({ name: 'token', value: 'xyz789' })
242
+ })
243
+
244
+ test('returns empty array for malformed SQL without throwing', async () => {
245
+ // given
246
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
247
+ tempDirs.push(tempDir)
248
+ const dbPath = join(tempDir, 'Cookies')
249
+ createTestCookieDb(dbPath, [{ name: 'session', value: 'abc123', encrypted_value: null }])
250
+ const reader = new ChromiumCookieReader()
251
+
252
+ // when
253
+ const result = await reader.queryAll<{ name: string }>(dbPath, 'SELECT FROM cookies')
254
+
255
+ // then
256
+ expect(result).toEqual([])
257
+ })
258
+
259
+ test('returns null for malformed SQL without throwing', async () => {
260
+ // given
261
+ const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
262
+ tempDirs.push(tempDir)
263
+ const dbPath = join(tempDir, 'Cookies')
264
+ createTestCookieDb(dbPath, [{ name: 'session', value: 'abc123', encrypted_value: null }])
265
+ const reader = new ChromiumCookieReader()
266
+
267
+ // when
268
+ const result = await reader.queryFirst<{ name: string }>(dbPath, 'SELECT FROM cookies')
269
+
270
+ // then
271
+ expect(result).toBeNull()
272
+ })
273
+ })
274
+ })