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
@@ -1,76 +1,39 @@
1
1
  import { execSync } from 'node:child_process'
2
- import { createDecipheriv, pbkdf2Sync } from 'node:crypto'
3
- import { copyFileSync, existsSync, readFileSync, readdirSync, unlinkSync } from 'node:fs'
4
- import { homedir, tmpdir } from 'node:os'
2
+ import { pbkdf2Sync } from 'node:crypto'
3
+ import { existsSync } from 'node:fs'
4
+ import { homedir } from 'node:os'
5
5
  import { join } from 'node:path'
6
6
 
7
+ import {
8
+ BROWSER_KEYCHAIN_VARIANTS,
9
+ CHROMIUM_BROWSERS,
10
+ ChromiumCookieDecryptor,
11
+ ChromiumCookieReader,
12
+ discoverBrowserProfileDirs,
13
+ findLocalStatePath,
14
+ getBrowserBasePath,
15
+ } from '@/shared/chromium'
16
+ import type { KeychainVariant } from '@/shared/chromium'
17
+
7
18
  import type { ExtractedChannelToken } from './types'
8
19
 
9
20
  type CookieRow = { name: string; value: string; encrypted_value: Uint8Array | Buffer }
10
21
 
11
- interface BrowserConfig {
12
- name: string
13
- darwin: string
14
- linux: string
15
- win32: string
16
- }
17
-
18
- interface KeychainVariant {
19
- service: string
20
- account: string
21
- }
22
-
23
- const BROWSERS: BrowserConfig[] = [
24
- {
25
- name: 'Chrome',
26
- darwin: join('Google', 'Chrome'),
27
- linux: 'google-chrome',
28
- win32: join('Google', 'Chrome', 'User Data'),
29
- },
30
- {
31
- name: 'Chrome Canary',
32
- darwin: join('Google', 'Chrome Canary'),
33
- linux: 'google-chrome-unstable',
34
- win32: join('Google', 'Chrome SxS', 'User Data'),
35
- },
36
- {
37
- name: 'Edge',
38
- darwin: 'Microsoft Edge',
39
- linux: 'microsoft-edge',
40
- win32: join('Microsoft', 'Edge', 'User Data'),
41
- },
42
- {
43
- name: 'Arc',
44
- darwin: join('Arc', 'User Data'),
45
- linux: '',
46
- win32: join('Arc', 'User Data'),
47
- },
48
- {
49
- name: 'Brave',
50
- darwin: join('BraveSoftware', 'Brave-Browser'),
51
- linux: join('BraveSoftware', 'Brave-Browser'),
52
- win32: join('BraveSoftware', 'Brave-Browser', 'User Data'),
53
- },
54
- {
55
- name: 'Vivaldi',
56
- darwin: 'Vivaldi',
57
- linux: 'vivaldi',
58
- win32: join('Vivaldi', 'User Data'),
59
- },
60
- {
61
- name: 'Chromium',
62
- darwin: 'Chromium',
63
- linux: 'chromium',
64
- win32: join('Chromium', 'User Data'),
65
- },
66
- ]
22
+ const COOKIE_QUERY = `
23
+ SELECT name, value, encrypted_value FROM cookies
24
+ WHERE name IN ('x-account', 'ch-session-1', 'ch-session')
25
+ AND host_key LIKE '%.channel.io%'
26
+ `
67
27
 
68
28
  export class ChannelTokenExtractor {
69
29
  private platform: NodeJS.Platform
70
- private cachedKey: Buffer | null = null
30
+ private decryptor: ChromiumCookieDecryptor
31
+ private cookieReader: ChromiumCookieReader
71
32
 
72
33
  constructor(platform?: NodeJS.Platform) {
73
34
  this.platform = platform ?? process.platform
35
+ this.cookieReader = new ChromiumCookieReader()
36
+ this.decryptor = new ChromiumCookieDecryptor({ platform: this.platform })
74
37
  }
75
38
 
76
39
  getAppDataDir(): string | null {
@@ -118,22 +81,14 @@ export class ChannelTokenExtractor {
118
81
  }
119
82
  }
120
83
 
121
- private getLocalStatePath(): string | null {
122
- const appDir = this.getAppDataDir()
123
- if (!appDir) return null
124
- const localStatePath = join(appDir, 'Local State')
125
- return existsSync(localStatePath) ? localStatePath : null
126
- }
127
-
128
84
  getBrowserCookiesPaths(): string[] {
129
85
  const paths: string[] = []
130
86
 
131
- for (const browser of BROWSERS) {
132
- const browserBase = this.getBrowserBasePath(browser)
87
+ for (const browser of CHROMIUM_BROWSERS) {
88
+ const browserBase = getBrowserBasePath(browser, this.platform)
133
89
  if (!browserBase) continue
134
90
 
135
- const profileDirs = this.discoverProfileDirs(browserBase)
136
- for (const profileDir of profileDirs) {
91
+ for (const profileDir of discoverBrowserProfileDirs(browserBase)) {
137
92
  paths.push(join(profileDir, 'Cookies'))
138
93
  paths.push(join(profileDir, 'Network', 'Cookies'))
139
94
  }
@@ -142,70 +97,8 @@ export class ChannelTokenExtractor {
142
97
  return paths
143
98
  }
144
99
 
145
- private getBrowserBasePath(browser: BrowserConfig): string | null {
146
- let relative: string
147
-
148
- switch (this.platform) {
149
- case 'darwin':
150
- relative = browser.darwin
151
- if (!relative) return null
152
- return join(homedir(), 'Library', 'Application Support', relative)
153
- case 'linux':
154
- relative = browser.linux
155
- if (!relative) return null
156
- return join(homedir(), '.config', relative)
157
- case 'win32':
158
- relative = browser.win32
159
- if (!relative) return null
160
- return join(
161
- process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'),
162
- relative,
163
- )
164
- default:
165
- return null
166
- }
167
- }
168
-
169
- private discoverProfileDirs(browserBase: string): string[] {
170
- const dirs: string[] = []
171
-
172
- dirs.push(join(browserBase, 'Default'))
173
-
174
- if (!existsSync(browserBase)) return dirs
175
-
176
- try {
177
- const entries = readdirSync(browserBase, { withFileTypes: true })
178
- for (const entry of entries) {
179
- if (!entry.isDirectory()) continue
180
- if (!/^Profile \d+$/i.test(entry.name)) continue
181
- dirs.push(join(browserBase, entry.name))
182
- }
183
- } catch {}
184
-
185
- return dirs
186
- }
187
-
188
- private findLocalStateForCookiePath(cookiePath: string): string | null {
189
- const parts = cookiePath.split(/[/\\]/)
190
- for (let levels = 2; levels <= 4; levels++) {
191
- if (parts.length < levels) break
192
- const base = parts.slice(0, parts.length - levels).join('/')
193
- const candidate = join(base, 'Local State')
194
- if (existsSync(candidate)) return candidate
195
- }
196
- return null
197
- }
198
-
199
100
  getKeychainVariants(): KeychainVariant[] {
200
- return [
201
- { service: 'Chrome Safe Storage', account: 'Chrome' },
202
- { service: 'Chrome Canary Safe Storage', account: 'Chrome Canary' },
203
- { service: 'Microsoft Edge Safe Storage', account: 'Microsoft Edge' },
204
- { service: 'Arc Safe Storage', account: 'Arc' },
205
- { service: 'Brave Safe Storage', account: 'Brave' },
206
- { service: 'Vivaldi Safe Storage', account: 'Vivaldi' },
207
- { service: 'Chromium Safe Storage', account: 'Chromium' },
208
- ]
101
+ return BROWSER_KEYCHAIN_VARIANTS
209
102
  }
210
103
 
211
104
  async extract(): Promise<ExtractedChannelToken[]> {
@@ -228,299 +121,154 @@ export class ChannelTokenExtractor {
228
121
  return results
229
122
  }
230
123
 
231
- private async extractAllFromBrowserPaths(): Promise<ExtractedChannelToken[]> {
232
- const results: ExtractedChannelToken[] = []
233
- const cookiePaths = this.getBrowserCookiesPaths()
234
-
235
- for (const cookiePath of cookiePaths) {
236
- if (!existsSync(cookiePath)) continue
237
- const result = await this.extractFromBrowserCookiePath(cookiePath)
238
- if (result) results.push(result)
239
- }
240
-
241
- return results
124
+ decryptDPAPI(encryptedBlob: Buffer): Buffer | null {
125
+ return this.decryptor.decryptDPAPI(encryptedBlob)
242
126
  }
243
127
 
244
- private async extractFromDesktopApp(): Promise<ExtractedChannelToken | null> {
245
- const cookiesPath = this.getCookiesPath()
246
- if (!cookiesPath) {
128
+ private execSecurityCommand(service: string, account: string): string | null {
129
+ try {
130
+ const safeService = service.replace(/"/g, '\\"')
131
+ const safeAccount = account.replace(/"/g, '\\"')
132
+ return (
133
+ execSync(`security find-generic-password -s "${safeService}" -a "${safeAccount}" -w 2>/dev/null`, {
134
+ encoding: 'utf8',
135
+ }).trim() || null
136
+ )
137
+ } catch {
247
138
  return null
248
139
  }
140
+ }
249
141
 
250
- const tempPath = join(tmpdir(), `channel-cookies-${Date.now()}`)
251
-
252
- try {
253
- copyFileSync(cookiesPath, tempPath)
254
- const rows = await this.queryCookieDB(tempPath)
142
+ private decryptBrowserCookie(encrypted: Buffer, cookiePath: string): string | null {
143
+ const prefix = encrypted.length > 3 ? encrypted.subarray(0, 3).toString('utf8') : ''
144
+
145
+ if (prefix === 'v10' || prefix === 'v11') {
146
+ if (this.platform === 'darwin') {
147
+ for (const variant of BROWSER_KEYCHAIN_VARIANTS) {
148
+ const password = this.execSecurityCommand(variant.service, variant.account)
149
+ if (!password) continue
150
+ const key = pbkdf2Sync(password, 'saltysalt', 1003, 16, 'sha1')
151
+ const buf = this.decryptor.decryptAESCBCRaw(encrypted, key)
152
+ if (buf) return ChromiumCookieDecryptor.stripIntegrityHash(buf).toString('utf8')
153
+ }
154
+ return null
155
+ }
255
156
 
256
- const accountCookie = this.getCookieValue(rows, 'x-account')
257
- const sessionCookie =
258
- this.getCookieValue(rows, 'ch-session-1') ??
259
- this.getCookieValue(rows, 'ch-session')
157
+ if (this.platform === 'linux') {
158
+ const key = pbkdf2Sync('peanuts', 'saltysalt', 1, 16, 'sha1')
159
+ const buf = this.decryptor.decryptAESCBCRaw(encrypted, key)
160
+ if (buf) return ChromiumCookieDecryptor.stripIntegrityHash(buf).toString('utf8')
161
+ return null
162
+ }
260
163
 
261
- return accountCookie ? { accountCookie, sessionCookie } : null
262
- } catch {
263
- return null
264
- } finally {
265
- try {
266
- if (existsSync(tempPath)) {
267
- unlinkSync(tempPath)
268
- }
269
- } catch {
270
- /* temp file cleanup failure is non-critical */
164
+ if (this.platform === 'win32') {
165
+ const localStatePath = findLocalStatePath(cookiePath) ?? undefined
166
+ const buf = this.decryptor.decryptWindowsCookieRaw(encrypted, localStatePath)
167
+ if (buf) return ChromiumCookieDecryptor.stripIntegrityHash(buf).toString('utf8')
168
+ return null
271
169
  }
272
170
  }
171
+
172
+ return null
173
+ }
174
+
175
+ private getLocalStatePath(): string | null {
176
+ const appDir = this.getAppDataDir()
177
+ if (!appDir) return null
178
+ const localStatePath = join(appDir, 'Local State')
179
+ return existsSync(localStatePath) ? localStatePath : null
273
180
  }
274
181
 
275
- private async extractFromBrowsers(): Promise<ExtractedChannelToken | null> {
182
+ private async extractAllFromBrowserPaths(): Promise<ExtractedChannelToken[]> {
183
+ const results: ExtractedChannelToken[] = []
276
184
  const cookiePaths = this.getBrowserCookiesPaths()
277
185
 
278
186
  for (const cookiePath of cookiePaths) {
279
187
  if (!existsSync(cookiePath)) continue
280
-
281
188
  const result = await this.extractFromBrowserCookiePath(cookiePath)
282
- if (result) return result
189
+ if (result) results.push(result)
283
190
  }
284
191
 
285
- return null
192
+ return results
286
193
  }
287
194
 
288
- private async extractFromBrowserCookiePath(cookiePath: string): Promise<ExtractedChannelToken | null> {
289
- const tempPath = join(tmpdir(), `channel-browser-cookies-${Date.now()}`)
290
-
291
- try {
292
- copyFileSync(cookiePath, tempPath)
293
- const rows = await this.queryCookieDB(tempPath)
294
-
295
- const accountCookie = this.getBrowserCookieValue(rows, 'x-account', cookiePath)
296
- const sessionCookie =
297
- this.getBrowserCookieValue(rows, 'ch-session-1', cookiePath) ??
298
- this.getBrowserCookieValue(rows, 'ch-session', cookiePath)
299
-
300
- return accountCookie ? { accountCookie, sessionCookie } : null
301
- } catch {
195
+ private async extractFromDesktopApp(): Promise<ExtractedChannelToken | null> {
196
+ const cookiesPath = this.getCookiesPath()
197
+ if (!cookiesPath) {
302
198
  return null
303
- } finally {
304
- try {
305
- if (existsSync(tempPath)) {
306
- unlinkSync(tempPath)
307
- }
308
- } catch {
309
- /* temp file cleanup failure is non-critical */
310
- }
311
199
  }
312
- }
313
200
 
314
- private async queryCookieDB(dbPath: string): Promise<CookieRow[]> {
315
- const sql = `
316
- SELECT name, value, encrypted_value FROM cookies
317
- WHERE name IN ('x-account', 'ch-session-1', 'ch-session')
318
- AND host_key LIKE '%.channel.io%'
319
- `
320
-
321
- if (typeof globalThis.Bun !== 'undefined') {
322
- return await (async () => {
323
- const { Database } = await import('bun:sqlite')
324
- const db = new Database(dbPath, { readonly: true })
325
- const result = db.query(sql).all() as CookieRow[]
326
- db.close()
327
- return result
328
- })()
329
- }
201
+ const rows = await this.cookieReader.queryAll<CookieRow>(cookiesPath, COOKIE_QUERY)
202
+ if (rows.length === 0) return null
330
203
 
331
- return await (async () => {
332
- const { createRequire } = await import('node:module')
333
- const req = createRequire(import.meta.url)
334
- const Database = req('better-sqlite3')
335
- const db = new Database(dbPath, { readonly: true })
336
- const result = db.prepare(sql).all() as CookieRow[]
337
- db.close()
338
- return result
339
- })()
340
- }
204
+ const localStatePath = this.getLocalStatePath() ?? undefined
205
+ const accountCookie = this.getDesktopCookieValue(rows, 'x-account', localStatePath)
206
+ const sessionCookie =
207
+ this.getDesktopCookieValue(rows, 'ch-session-1', localStatePath) ??
208
+ this.getDesktopCookieValue(rows, 'ch-session', localStatePath)
341
209
 
342
- private getCookieValue(rows: CookieRow[], name: string): string | undefined {
343
- const row = rows.find((r) => r.name === name)
344
- if (!row) return undefined
210
+ return accountCookie ? { accountCookie, sessionCookie } : null
211
+ }
345
212
 
346
- if (row.value && row.value.length > 0) {
347
- return row.value
348
- }
213
+ private async extractFromBrowserCookiePath(cookiePath: string): Promise<ExtractedChannelToken | null> {
214
+ const rows = await this.cookieReader.queryAll<CookieRow>(cookiePath, COOKIE_QUERY)
215
+ if (rows.length === 0) return null
349
216
 
350
- const encrypted = Buffer.from(row.encrypted_value)
351
- if (encrypted.length === 0) return undefined
217
+ const localStatePath = findLocalStatePath(cookiePath) ?? undefined
218
+ const accountCookie = this.getBrowserCookieValue(rows, 'x-account', localStatePath)
219
+ const sessionCookie =
220
+ this.getBrowserCookieValue(rows, 'ch-session-1', localStatePath) ??
221
+ this.getBrowserCookieValue(rows, 'ch-session', localStatePath)
352
222
 
353
- return this.decryptCookie(encrypted) ?? undefined
223
+ return accountCookie ? { accountCookie, sessionCookie } : null
354
224
  }
355
225
 
356
- private getBrowserCookieValue(rows: CookieRow[], name: string, dbPath: string): string | undefined {
357
- const row = rows.find((r) => r.name === name)
226
+ private getDesktopCookieValue(rows: CookieRow[], name: string, localStatePath?: string): string | undefined {
227
+ const row = rows.find((candidate) => candidate.name === name)
358
228
  if (!row) return undefined
359
229
 
360
230
  if (row.value && row.value.length > 0) {
361
231
  return row.value
362
232
  }
363
233
 
364
- const encrypted = Buffer.from(row.encrypted_value)
365
- if (encrypted.length === 0) return undefined
366
-
367
- return this.decryptBrowserCookie(encrypted, dbPath) ?? undefined
368
- }
234
+ const encryptedValue = Buffer.from(row.encrypted_value)
235
+ if (encryptedValue.length === 0) return undefined
369
236
 
370
- private decryptCookie(encryptedValue: Buffer): string | null {
371
- if (!this.isEncryptedValue(encryptedValue)) {
372
- return encryptedValue.toString('utf8')
237
+ if (this.platform === 'win32' && localStatePath && this.decryptor.isEncryptedValue(encryptedValue)) {
238
+ return this.decryptDesktopWindowsCookie(encryptedValue, localStatePath) ?? undefined
373
239
  }
374
240
 
375
- if (this.platform === 'win32') {
376
- return this.decryptWindowsCookie(encryptedValue)
377
- }
378
-
379
- return null
380
- }
381
-
382
- private decryptBrowserCookie(encryptedValue: Buffer, dbPath: string): string | null {
383
- if (!this.isEncryptedValue(encryptedValue)) {
384
- return encryptedValue.toString('utf8')
385
- }
386
-
387
- if (this.platform === 'win32') {
388
- const localStatePath = this.findLocalStateForCookiePath(dbPath)
389
- return this.decryptWindowsCookie(encryptedValue, localStatePath ?? undefined)
390
- } else if (this.platform === 'darwin') {
391
- return this.decryptMacCookie(encryptedValue)
392
- } else if (this.platform === 'linux') {
393
- return this.decryptLinuxCookie(encryptedValue)
394
- }
395
-
396
- return null
241
+ return this.decryptor.decryptCookie(encryptedValue, localStatePath) ?? undefined
397
242
  }
398
243
 
399
- private isEncryptedValue(value: Buffer): boolean {
400
- if (!value || value.length < 4) return false
401
- const prefix = value.subarray(0, 3).toString('utf8')
402
- return prefix === 'v10' || prefix === 'v11'
403
- }
404
-
405
- private decryptWindowsCookie(encryptedData: Buffer, localStatePath?: string): string | null {
244
+ private decryptDesktopWindowsCookie(encryptedData: Buffer, localStatePath: string): string | null {
406
245
  try {
407
- const statePath = localStatePath ?? this.getLocalStatePath()
408
- if (!statePath) return null
409
-
410
- const localState = JSON.parse(readFileSync(statePath, 'utf8'))
246
+ const { readFileSync } = require('node:fs') as typeof import('node:fs')
247
+ const localState = JSON.parse(readFileSync(localStatePath, 'utf8'))
411
248
  const encryptedKey = Buffer.from(localState.os_crypt.encrypted_key, 'base64')
412
-
413
249
  const dpapiBlobKey = encryptedKey.subarray(5)
414
250
  const masterKey = this.decryptDPAPI(dpapiBlobKey)
415
251
  if (!masterKey) return null
416
-
417
- return this.decryptAESGCM(encryptedData, masterKey)
252
+ return this.decryptor.decryptAESGCM(encryptedData, masterKey)
418
253
  } catch {
419
254
  return null
420
255
  }
421
256
  }
422
257
 
423
- private decryptMacCookie(encryptedData: Buffer): string | null {
424
- if (this.cachedKey) {
425
- const decrypted = this.decryptAESCBC(encryptedData, this.cachedKey)
426
- if (decrypted) return decrypted
427
- }
428
-
429
- for (const variant of this.getKeychainVariants()) {
430
- const password = this.execSecurityCommand(variant.service, variant.account)
431
- if (!password) continue
432
-
433
- const key = pbkdf2Sync(password, 'saltysalt', 1003, 16, 'sha1')
434
- const decrypted = this.decryptAESCBC(encryptedData, key)
435
- if (decrypted) {
436
- this.cachedKey = key
437
- return decrypted
438
- }
439
- }
440
-
441
- return null
442
- }
443
-
444
- private decryptLinuxCookie(encryptedData: Buffer): string | null {
445
- const key = pbkdf2Sync('peanuts', 'saltysalt', 1, 16, 'sha1')
446
- return this.decryptAESCBC(encryptedData, key)
447
- }
448
-
449
- private execSecurityCommand(service: string, account: string): string | null {
450
- try {
451
- const safeService = service.replace(/"/g, '\\"')
452
- const safeAccount = account.replace(/"/g, '\\"')
453
- const result = execSync(
454
- `security find-generic-password -s "${safeService}" -a "${safeAccount}" -w 2>/dev/null`,
455
- { encoding: 'utf8' },
456
- )
457
- return result.trim() || null
458
- } catch {
459
- return null
460
- }
461
- }
462
-
463
- private decryptAESCBC(encryptedData: Buffer, key: Buffer): string | null {
464
- try {
465
- const ciphertext = encryptedData.subarray(3)
466
- const iv = Buffer.alloc(16, 0x20)
467
-
468
- const decipher = createDecipheriv('aes-128-cbc', key, iv)
469
- decipher.setAutoPadding(true)
470
-
471
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
472
-
473
- // Chromium v130+ integrity hash: 32-byte non-printable prefix
474
- if (decrypted.length > 32) {
475
- const hasNonPrintablePrefix = decrypted.subarray(0, 32).some((b) => b < 0x20 || b > 0x7e)
476
- if (hasNonPrintablePrefix) {
477
- return decrypted.subarray(32).toString('utf8')
478
- }
479
- }
480
-
481
- return decrypted.toString('utf8')
482
- } catch {
483
- return null
484
- }
485
- }
258
+ private getBrowserCookieValue(rows: CookieRow[], name: string, localStatePath?: string): string | undefined {
259
+ const row = rows.find((candidate) => candidate.name === name)
260
+ if (!row) return undefined
486
261
 
487
- decryptDPAPI(encryptedBlob: Buffer): Buffer | null {
488
- if (this.platform !== 'win32') return null
489
- try {
490
- const b64 = encryptedBlob.toString('base64')
491
- const psScript = [
492
- 'Add-Type -AssemblyName System.Security',
493
- `$bytes = [Convert]::FromBase64String('${b64}')`,
494
- '$decrypted = [Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)',
495
- '[Convert]::ToBase64String($decrypted)',
496
- ].join('; ')
497
-
498
- const result = execSync(`powershell -NoProfile -NonInteractive -Command "${psScript}"`, {
499
- encoding: 'utf8',
500
- timeout: 10000,
501
- })
502
- return Buffer.from(result.trim(), 'base64')
503
- } catch {
504
- return null
262
+ if (row.value && row.value.length > 0) {
263
+ return row.value
505
264
  }
506
- }
507
265
 
508
- private decryptAESGCM(encryptedData: Buffer, key: Buffer): string | null {
509
- try {
510
- // Format: v10 (3 bytes) + IV (12 bytes) + ciphertext + auth tag (16 bytes)
511
- if (encryptedData.length < 3 + 12 + 16) return null
512
-
513
- const iv = encryptedData.subarray(3, 15)
514
- const authTag = encryptedData.subarray(-16)
515
- const ciphertext = encryptedData.subarray(15, -16)
266
+ const encryptedValue = Buffer.from(row.encrypted_value)
267
+ if (encryptedValue.length === 0) return undefined
516
268
 
517
- const decipher = createDecipheriv('aes-256-gcm', key, iv)
518
- decipher.setAuthTag(authTag)
269
+ const buf = this.decryptor.decryptCookieRaw(encryptedValue, localStatePath)
270
+ if (!buf) return undefined
519
271
 
520
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
521
- return decrypted.toString('utf8')
522
- } catch {
523
- return null
524
- }
272
+ return ChromiumCookieDecryptor.stripIntegrityHash(buf).toString('utf8')
525
273
  }
526
274
  }
@@ -141,9 +141,7 @@ describe('ChannelBotClient', () => {
141
141
  })
142
142
 
143
143
  test('wrapTextInBlocks returns a single text block with value', () => {
144
- expect(ChannelBotClient.wrapTextInBlocks('Hello world')).toEqual([
145
- { type: 'text', value: 'Hello world' },
146
- ])
144
+ expect(ChannelBotClient.wrapTextInBlocks('Hello world')).toEqual([{ type: 'text', value: 'Hello world' }])
147
145
  })
148
146
 
149
147
  test('sendUserChatMessage includes botName in query string', async () => {