agent-messenger 2.10.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.env.template +4 -1
  3. package/README.md +77 -27
  4. package/bun.lock +26 -0
  5. package/dist/package.json +14 -1
  6. package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
  7. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  8. package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
  9. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
  11. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  12. package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
  13. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  14. package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
  15. package/dist/src/platforms/channeltalkbot/cli.js +11 -1
  16. package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
  17. package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
  18. package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
  19. package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
  20. package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
  21. package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
  22. package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
  23. package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
  24. package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
  25. package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
  26. package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
  27. package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
  28. package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
  29. package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
  30. package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
  31. package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
  32. package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
  33. package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
  34. package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
  35. package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
  36. package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
  37. package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
  38. package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
  39. package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
  40. package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
  41. package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
  42. package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
  43. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  44. package/dist/src/platforms/discord/commands/auth.js +3 -1
  45. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  46. package/dist/src/platforms/discord/listener.d.ts +2 -0
  47. package/dist/src/platforms/discord/listener.d.ts.map +1 -1
  48. package/dist/src/platforms/discord/listener.js +51 -21
  49. package/dist/src/platforms/discord/listener.js.map +1 -1
  50. package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
  51. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  52. package/dist/src/platforms/discord/token-extractor.js +21 -6
  53. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  54. package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
  55. package/dist/src/platforms/discordbot/cli.js +12 -1
  56. package/dist/src/platforms/discordbot/cli.js.map +1 -1
  57. package/dist/src/platforms/discordbot/client.d.ts +3 -0
  58. package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
  59. package/dist/src/platforms/discordbot/client.js +3 -0
  60. package/dist/src/platforms/discordbot/client.js.map +1 -1
  61. package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
  62. package/dist/src/platforms/discordbot/commands/auth.js +1 -5
  63. package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
  64. package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
  65. package/dist/src/platforms/discordbot/commands/message.js +1 -6
  66. package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
  67. package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
  68. package/dist/src/platforms/discordbot/commands/server.js +1 -4
  69. package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
  70. package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
  71. package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
  72. package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
  73. package/dist/src/platforms/discordbot/index.d.ts +3 -1
  74. package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
  75. package/dist/src/platforms/discordbot/index.js +2 -1
  76. package/dist/src/platforms/discordbot/index.js.map +1 -1
  77. package/dist/src/platforms/discordbot/listener.d.ts +43 -0
  78. package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
  79. package/dist/src/platforms/discordbot/listener.js +292 -0
  80. package/dist/src/platforms/discordbot/listener.js.map +1 -0
  81. package/dist/src/platforms/discordbot/types.d.ts +161 -0
  82. package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
  83. package/dist/src/platforms/discordbot/types.js +34 -0
  84. package/dist/src/platforms/discordbot/types.js.map +1 -1
  85. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  86. package/dist/src/platforms/instagram/commands/auth.js +3 -1
  87. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  88. package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
  89. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
  90. package/dist/src/platforms/instagram/token-extractor.js +11 -2
  91. package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
  92. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  93. package/dist/src/platforms/slack/commands/auth.js +4 -2
  94. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  95. package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
  96. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  97. package/dist/src/platforms/slack/token-extractor.js +64 -15
  98. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  99. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  100. package/dist/src/platforms/slackbot/cli.js +15 -3
  101. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  102. package/dist/src/platforms/slackbot/client.d.ts +22 -1
  103. package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
  104. package/dist/src/platforms/slackbot/client.js +104 -1
  105. package/dist/src/platforms/slackbot/client.js.map +1 -1
  106. package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
  107. package/dist/src/platforms/slackbot/commands/auth.js +1 -5
  108. package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
  109. package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
  110. package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
  111. package/dist/src/platforms/slackbot/commands/file.js +164 -0
  112. package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
  113. package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
  114. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
  115. package/dist/src/platforms/slackbot/commands/index.js +1 -0
  116. package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
  117. package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
  118. package/dist/src/platforms/slackbot/commands/message.js +19 -0
  119. package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
  120. package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
  121. package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
  122. package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
  123. package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
  124. package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
  125. package/dist/src/platforms/slackbot/credential-manager.js +30 -2
  126. package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
  127. package/dist/src/platforms/slackbot/index.d.ts +4 -1
  128. package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
  129. package/dist/src/platforms/slackbot/index.js +1 -0
  130. package/dist/src/platforms/slackbot/index.js.map +1 -1
  131. package/dist/src/platforms/slackbot/listener.d.ts +44 -0
  132. package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
  133. package/dist/src/platforms/slackbot/listener.js +313 -0
  134. package/dist/src/platforms/slackbot/listener.js.map +1 -0
  135. package/dist/src/platforms/slackbot/types.d.ts +196 -1
  136. package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
  137. package/dist/src/platforms/slackbot/types.js +4 -1
  138. package/dist/src/platforms/slackbot/types.js.map +1 -1
  139. package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
  140. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  141. package/dist/src/platforms/teams/commands/auth.js +37 -6
  142. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  143. package/dist/src/platforms/teams/ensure-auth.js +31 -9
  144. package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
  145. package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
  146. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  147. package/dist/src/platforms/teams/token-extractor.js +80 -31
  148. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  149. package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
  150. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  151. package/dist/src/platforms/webex/commands/auth.js +3 -1
  152. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  153. package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
  154. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  155. package/dist/src/platforms/webex/token-extractor.js +16 -2
  156. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  157. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
  158. package/dist/src/platforms/wechatbot/cli.js +11 -1
  159. package/dist/src/platforms/wechatbot/cli.js.map +1 -1
  160. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
  161. package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
  162. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
  163. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
  164. package/dist/src/platforms/wechatbot/commands/message.js +1 -6
  165. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
  166. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
  167. package/dist/src/platforms/wechatbot/commands/template.js +1 -6
  168. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
  169. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
  170. package/dist/src/platforms/wechatbot/commands/user.js +1 -6
  171. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
  172. package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
  173. package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
  174. package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
  175. package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
  176. package/dist/src/platforms/whatsappbot/cli.js +11 -1
  177. package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
  178. package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
  179. package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
  180. package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
  181. package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
  182. package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
  183. package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
  184. package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
  185. package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
  186. package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
  187. package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
  188. package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
  189. package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
  190. package/dist/src/shared/chromium/browsers.d.ts +8 -0
  191. package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
  192. package/dist/src/shared/chromium/browsers.js +58 -3
  193. package/dist/src/shared/chromium/browsers.js.map +1 -1
  194. package/dist/src/shared/chromium/cli-options.d.ts +5 -0
  195. package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
  196. package/dist/src/shared/chromium/cli-options.js +8 -0
  197. package/dist/src/shared/chromium/cli-options.js.map +1 -0
  198. package/dist/src/shared/chromium/decryptor.d.ts +6 -0
  199. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
  200. package/dist/src/shared/chromium/decryptor.js +26 -6
  201. package/dist/src/shared/chromium/decryptor.js.map +1 -1
  202. package/dist/src/shared/chromium/index.d.ts +3 -1
  203. package/dist/src/shared/chromium/index.d.ts.map +1 -1
  204. package/dist/src/shared/chromium/index.js +2 -1
  205. package/dist/src/shared/chromium/index.js.map +1 -1
  206. package/dist/src/shared/utils/cli-output.d.ts +7 -0
  207. package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
  208. package/dist/src/shared/utils/cli-output.js +7 -0
  209. package/dist/src/shared/utils/cli-output.js.map +1 -0
  210. package/dist/src/tui/app.d.ts.map +1 -1
  211. package/dist/src/tui/app.js +73 -20
  212. package/dist/src/tui/app.js.map +1 -1
  213. package/docs/content/docs/cli/channeltalk.mdx +4 -0
  214. package/docs/content/docs/cli/discord.mdx +5 -0
  215. package/docs/content/docs/cli/instagram.mdx +3 -0
  216. package/docs/content/docs/cli/slack.mdx +5 -0
  217. package/docs/content/docs/cli/slackbot.mdx +60 -22
  218. package/docs/content/docs/cli/teams.mdx +5 -0
  219. package/docs/content/docs/cli/webex.mdx +3 -0
  220. package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
  221. package/docs/content/docs/sdk/discordbot.mdx +501 -0
  222. package/docs/content/docs/sdk/meta.json +2 -0
  223. package/docs/content/docs/sdk/slackbot.mdx +576 -0
  224. package/e2e/README.md +1 -1
  225. package/e2e/channeltalk.e2e.test.ts +13 -13
  226. package/e2e/channeltalkbot.e2e.test.ts +13 -13
  227. package/e2e/config.ts +9 -4
  228. package/e2e/discord.e2e.test.ts +24 -24
  229. package/e2e/discordbot.e2e.test.ts +16 -16
  230. package/e2e/instagram.e2e.test.ts +10 -10
  231. package/e2e/kakaotalk.e2e.test.ts +7 -7
  232. package/e2e/line.e2e.test.ts +8 -8
  233. package/e2e/slack.e2e.test.ts +34 -34
  234. package/e2e/slackbot.e2e.test.ts +14 -14
  235. package/e2e/teams.e2e.test.ts +23 -23
  236. package/e2e/telegram.e2e.test.ts +8 -8
  237. package/e2e/webex.e2e.test.ts +14 -14
  238. package/e2e/whatsapp.e2e.test.ts +8 -8
  239. package/e2e/whatsappbot.e2e.test.ts +6 -6
  240. package/examples/discordbot-listen.ts +65 -0
  241. package/examples/slackbot-listen.ts +65 -0
  242. package/package.json +14 -1
  243. package/skills/agent-channeltalk/SKILL.md +5 -1
  244. package/skills/agent-channeltalk/references/authentication.md +5 -1
  245. package/skills/agent-channeltalkbot/SKILL.md +17 -3
  246. package/skills/agent-channeltalkbot/references/authentication.md +7 -5
  247. package/skills/agent-discord/SKILL.md +5 -1
  248. package/skills/agent-discord/references/authentication.md +7 -1
  249. package/skills/agent-discordbot/SKILL.md +13 -2
  250. package/skills/agent-discordbot/references/common-patterns.md +1 -1
  251. package/skills/agent-instagram/SKILL.md +7 -1
  252. package/skills/agent-instagram/references/authentication.md +6 -0
  253. package/skills/agent-kakaotalk/SKILL.md +1 -1
  254. package/skills/agent-line/SKILL.md +1 -1
  255. package/skills/agent-slack/SKILL.md +5 -1
  256. package/skills/agent-slack/references/authentication.md +7 -1
  257. package/skills/agent-slackbot/SKILL.md +56 -4
  258. package/skills/agent-slackbot/references/authentication.md +4 -0
  259. package/skills/agent-teams/SKILL.md +5 -1
  260. package/skills/agent-teams/references/authentication.md +7 -1
  261. package/skills/agent-telegram/SKILL.md +1 -1
  262. package/skills/agent-webex/SKILL.md +7 -1
  263. package/skills/agent-webex/references/authentication.md +6 -0
  264. package/skills/agent-wechatbot/SKILL.md +16 -1
  265. package/skills/agent-wechatbot/references/authentication.md +219 -0
  266. package/skills/agent-wechatbot/references/common-patterns.md +358 -0
  267. package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
  268. package/skills/agent-wechatbot/templates/post-message.sh +122 -0
  269. package/skills/agent-wechatbot/templates/send-template.sh +152 -0
  270. package/skills/agent-whatsapp/SKILL.md +1 -1
  271. package/skills/agent-whatsappbot/SKILL.md +30 -1
  272. package/src/platforms/channeltalk/client.test.ts +26 -26
  273. package/src/platforms/channeltalk/commands/auth.test.ts +31 -19
  274. package/src/platforms/channeltalk/commands/auth.ts +15 -5
  275. package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
  276. package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
  277. package/src/platforms/channeltalk/commands/group.test.ts +4 -4
  278. package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
  279. package/src/platforms/channeltalk/commands/message.test.ts +17 -17
  280. package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
  281. package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
  282. package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
  283. package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
  284. package/src/platforms/channeltalk/index.test.ts +23 -23
  285. package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
  286. package/src/platforms/channeltalk/token-extractor.ts +24 -5
  287. package/src/platforms/channeltalk/types.test.ts +12 -12
  288. package/src/platforms/channeltalkbot/cli.ts +9 -0
  289. package/src/platforms/channeltalkbot/client.test.ts +14 -14
  290. package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
  291. package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
  292. package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
  293. package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
  294. package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
  295. package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
  296. package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
  297. package/src/platforms/channeltalkbot/commands/group.ts +1 -6
  298. package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
  299. package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
  300. package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
  301. package/src/platforms/channeltalkbot/commands/message.ts +1 -6
  302. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
  303. package/src/platforms/channeltalkbot/commands/whoami.test.ts +6 -4
  304. package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
  305. package/src/platforms/channeltalkbot/credential-manager.test.ts +123 -29
  306. package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
  307. package/src/platforms/channeltalkbot/index.test.ts +15 -15
  308. package/src/platforms/discord/client.test.ts +28 -28
  309. package/src/platforms/discord/commands/auth.test.ts +7 -7
  310. package/src/platforms/discord/commands/auth.ts +13 -2
  311. package/src/platforms/discord/commands/channel.test.ts +7 -7
  312. package/src/platforms/discord/commands/dm.test.ts +4 -4
  313. package/src/platforms/discord/commands/file.test.ts +4 -4
  314. package/src/platforms/discord/commands/friend.test.ts +6 -6
  315. package/src/platforms/discord/commands/member.test.ts +5 -5
  316. package/src/platforms/discord/commands/mention.test.ts +5 -5
  317. package/src/platforms/discord/commands/message.test.ts +9 -9
  318. package/src/platforms/discord/commands/note.test.ts +6 -6
  319. package/src/platforms/discord/commands/profile.test.ts +4 -4
  320. package/src/platforms/discord/commands/reaction.test.ts +5 -5
  321. package/src/platforms/discord/commands/server.test.ts +7 -7
  322. package/src/platforms/discord/commands/snapshot.test.ts +6 -6
  323. package/src/platforms/discord/commands/thread.test.ts +6 -6
  324. package/src/platforms/discord/commands/user.test.ts +5 -5
  325. package/src/platforms/discord/commands/whoami.test.ts +6 -6
  326. package/src/platforms/discord/credential-manager.test.ts +16 -16
  327. package/src/platforms/discord/ensure-auth.test.ts +8 -8
  328. package/src/platforms/discord/index.test.ts +17 -17
  329. package/src/platforms/discord/listener.test.ts +92 -34
  330. package/src/platforms/discord/listener.ts +43 -19
  331. package/src/platforms/discord/token-extractor.test.ts +53 -53
  332. package/src/platforms/discord/token-extractor.ts +30 -6
  333. package/src/platforms/discord/types.test.ts +26 -26
  334. package/src/platforms/discordbot/cli.ts +10 -0
  335. package/src/platforms/discordbot/client.test.ts +31 -31
  336. package/src/platforms/discordbot/client.ts +4 -0
  337. package/src/platforms/discordbot/commands/auth.test.ts +18 -18
  338. package/src/platforms/discordbot/commands/auth.ts +1 -5
  339. package/src/platforms/discordbot/commands/channel.test.ts +11 -11
  340. package/src/platforms/discordbot/commands/file.test.ts +7 -7
  341. package/src/platforms/discordbot/commands/message.test.ts +25 -25
  342. package/src/platforms/discordbot/commands/message.ts +1 -6
  343. package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
  344. package/src/platforms/discordbot/commands/server.test.ts +12 -12
  345. package/src/platforms/discordbot/commands/server.ts +1 -5
  346. package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
  347. package/src/platforms/discordbot/commands/thread.test.ts +10 -10
  348. package/src/platforms/discordbot/commands/user.test.ts +9 -9
  349. package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
  350. package/src/platforms/discordbot/commands/whoami.ts +1 -6
  351. package/src/platforms/discordbot/credential-manager.test.ts +28 -28
  352. package/src/platforms/discordbot/index.test.ts +82 -0
  353. package/src/platforms/discordbot/index.ts +27 -9
  354. package/src/platforms/discordbot/listener.test.ts +1002 -0
  355. package/src/platforms/discordbot/listener.ts +321 -0
  356. package/src/platforms/discordbot/types.ts +163 -0
  357. package/src/platforms/instagram/client.test.ts +18 -18
  358. package/src/platforms/instagram/commands/auth.test.ts +11 -11
  359. package/src/platforms/instagram/commands/auth.ts +9 -1
  360. package/src/platforms/instagram/commands/chat.test.ts +6 -6
  361. package/src/platforms/instagram/commands/message.test.ts +11 -11
  362. package/src/platforms/instagram/commands/shared.test.ts +12 -12
  363. package/src/platforms/instagram/commands/whoami.test.ts +3 -3
  364. package/src/platforms/instagram/credential-manager.test.ts +21 -21
  365. package/src/platforms/instagram/ensure-auth.test.ts +4 -4
  366. package/src/platforms/instagram/index.test.ts +9 -9
  367. package/src/platforms/instagram/listener.test.ts +8 -8
  368. package/src/platforms/instagram/token-extractor.test.ts +35 -35
  369. package/src/platforms/instagram/token-extractor.ts +13 -1
  370. package/src/platforms/kakaotalk/client.test.ts +33 -33
  371. package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
  372. package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
  373. package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
  374. package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
  375. package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
  376. package/src/platforms/kakaotalk/index.test.ts +15 -15
  377. package/src/platforms/kakaotalk/listener.test.ts +17 -17
  378. package/src/platforms/line/client.test.ts +17 -17
  379. package/src/platforms/line/commands/auth.test.ts +8 -8
  380. package/src/platforms/line/commands/chat.test.ts +7 -7
  381. package/src/platforms/line/commands/friend.test.ts +6 -6
  382. package/src/platforms/line/commands/message.test.ts +7 -7
  383. package/src/platforms/line/commands/whoami.test.ts +6 -6
  384. package/src/platforms/line/credential-manager.test.ts +17 -17
  385. package/src/platforms/line/index.test.ts +10 -10
  386. package/src/platforms/line/listener.test.ts +15 -15
  387. package/src/platforms/line/types.test.ts +14 -14
  388. package/src/platforms/slack/cli.test.ts +8 -8
  389. package/src/platforms/slack/client.test.ts +151 -151
  390. package/src/platforms/slack/commands/activity.test.ts +13 -13
  391. package/src/platforms/slack/commands/auth.test.ts +34 -34
  392. package/src/platforms/slack/commands/auth.ts +11 -2
  393. package/src/platforms/slack/commands/bookmark.test.ts +9 -9
  394. package/src/platforms/slack/commands/channel.test.ts +17 -17
  395. package/src/platforms/slack/commands/drafts.test.ts +7 -7
  396. package/src/platforms/slack/commands/emoji.test.ts +3 -3
  397. package/src/platforms/slack/commands/file.test.ts +12 -12
  398. package/src/platforms/slack/commands/message.test.ts +19 -19
  399. package/src/platforms/slack/commands/pin.test.ts +7 -7
  400. package/src/platforms/slack/commands/reaction.test.ts +10 -10
  401. package/src/platforms/slack/commands/reminder.test.ts +9 -9
  402. package/src/platforms/slack/commands/saved.test.ts +7 -7
  403. package/src/platforms/slack/commands/sections.test.ts +5 -5
  404. package/src/platforms/slack/commands/snapshot.test.ts +13 -13
  405. package/src/platforms/slack/commands/unread.test.ts +6 -6
  406. package/src/platforms/slack/commands/user.test.ts +10 -10
  407. package/src/platforms/slack/commands/usergroup.test.ts +15 -15
  408. package/src/platforms/slack/commands/whoami.test.ts +6 -6
  409. package/src/platforms/slack/commands/workspace.test.ts +26 -26
  410. package/src/platforms/slack/credential-manager.test.ts +14 -14
  411. package/src/platforms/slack/ensure-auth.test.ts +21 -21
  412. package/src/platforms/slack/index.test.ts +12 -12
  413. package/src/platforms/slack/listener.test.ts +17 -17
  414. package/src/platforms/slack/token-extractor-node.test.ts +2 -2
  415. package/src/platforms/slack/token-extractor.test.ts +133 -37
  416. package/src/platforms/slack/token-extractor.ts +76 -13
  417. package/src/platforms/slack/types.test.ts +21 -21
  418. package/src/platforms/slackbot/cli.ts +13 -1
  419. package/src/platforms/slackbot/client.test.ts +296 -22
  420. package/src/platforms/slackbot/client.ts +130 -2
  421. package/src/platforms/slackbot/commands/auth.test.ts +14 -14
  422. package/src/platforms/slackbot/commands/auth.ts +1 -5
  423. package/src/platforms/slackbot/commands/channel.test.ts +7 -7
  424. package/src/platforms/slackbot/commands/file.test.ts +201 -0
  425. package/src/platforms/slackbot/commands/file.ts +212 -0
  426. package/src/platforms/slackbot/commands/index.ts +1 -0
  427. package/src/platforms/slackbot/commands/message.test.ts +13 -13
  428. package/src/platforms/slackbot/commands/message.ts +22 -0
  429. package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
  430. package/src/platforms/slackbot/commands/user.test.ts +7 -7
  431. package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
  432. package/src/platforms/slackbot/commands/whoami.ts +1 -6
  433. package/src/platforms/slackbot/credential-manager.test.ts +83 -23
  434. package/src/platforms/slackbot/credential-manager.ts +32 -2
  435. package/src/platforms/slackbot/index.test.ts +59 -0
  436. package/src/platforms/slackbot/index.ts +31 -7
  437. package/src/platforms/slackbot/listener.test.ts +1012 -0
  438. package/src/platforms/slackbot/listener.ts +362 -0
  439. package/src/platforms/slackbot/types.test.ts +7 -7
  440. package/src/platforms/slackbot/types.ts +224 -1
  441. package/src/platforms/teams/client.test.ts +30 -30
  442. package/src/platforms/teams/commands/auth.test.ts +9 -9
  443. package/src/platforms/teams/commands/auth.ts +66 -7
  444. package/src/platforms/teams/commands/channel.test.ts +7 -7
  445. package/src/platforms/teams/commands/file.test.ts +4 -4
  446. package/src/platforms/teams/commands/message.test.ts +5 -5
  447. package/src/platforms/teams/commands/reaction.test.ts +4 -4
  448. package/src/platforms/teams/commands/snapshot.test.ts +7 -7
  449. package/src/platforms/teams/commands/team.test.ts +8 -8
  450. package/src/platforms/teams/commands/user.test.ts +4 -4
  451. package/src/platforms/teams/commands/whoami.test.ts +6 -6
  452. package/src/platforms/teams/credential-manager.test.ts +17 -17
  453. package/src/platforms/teams/ensure-auth.test.ts +69 -18
  454. package/src/platforms/teams/ensure-auth.ts +39 -11
  455. package/src/platforms/teams/index.test.ts +15 -15
  456. package/src/platforms/teams/token-extractor.test.ts +251 -69
  457. package/src/platforms/teams/token-extractor.ts +94 -31
  458. package/src/platforms/teams/types.test.ts +26 -26
  459. package/src/platforms/telegram/app-config.test.ts +4 -4
  460. package/src/platforms/telegram/chat-utils.test.ts +12 -12
  461. package/src/platforms/telegram/client.test.ts +4 -4
  462. package/src/platforms/telegram/commands/auth.test.ts +16 -16
  463. package/src/platforms/telegram/commands/chat.test.ts +9 -9
  464. package/src/platforms/telegram/commands/message.test.ts +6 -6
  465. package/src/platforms/telegram/commands/shared.test.ts +3 -3
  466. package/src/platforms/telegram/commands/whoami.test.ts +3 -3
  467. package/src/platforms/telegram/credential-manager.test.ts +10 -10
  468. package/src/platforms/telegram/types.test.ts +6 -6
  469. package/src/platforms/webex/app-config.test.ts +8 -8
  470. package/src/platforms/webex/cli.test.ts +5 -5
  471. package/src/platforms/webex/client.test.ts +65 -65
  472. package/src/platforms/webex/commands/auth.test.ts +18 -18
  473. package/src/platforms/webex/commands/auth.ts +13 -2
  474. package/src/platforms/webex/commands/member.test.ts +5 -5
  475. package/src/platforms/webex/commands/message.test.ts +12 -12
  476. package/src/platforms/webex/commands/snapshot.test.ts +5 -5
  477. package/src/platforms/webex/commands/space.test.ts +10 -10
  478. package/src/platforms/webex/commands/whoami.test.ts +6 -6
  479. package/src/platforms/webex/credential-manager.test.ts +22 -22
  480. package/src/platforms/webex/encryption.test.ts +4 -4
  481. package/src/platforms/webex/ensure-auth.test.ts +5 -5
  482. package/src/platforms/webex/index.test.ts +5 -5
  483. package/src/platforms/webex/markdown-to-html.test.ts +33 -33
  484. package/src/platforms/webex/token-extractor.test.ts +23 -23
  485. package/src/platforms/webex/token-extractor.ts +25 -3
  486. package/src/platforms/webex/types.test.ts +27 -27
  487. package/src/platforms/wechatbot/cli.ts +9 -0
  488. package/src/platforms/wechatbot/client.test.ts +27 -27
  489. package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
  490. package/src/platforms/wechatbot/commands/auth.ts +1 -5
  491. package/src/platforms/wechatbot/commands/message.test.ts +8 -8
  492. package/src/platforms/wechatbot/commands/message.ts +1 -6
  493. package/src/platforms/wechatbot/commands/template.test.ts +9 -9
  494. package/src/platforms/wechatbot/commands/template.ts +1 -6
  495. package/src/platforms/wechatbot/commands/user.test.ts +7 -7
  496. package/src/platforms/wechatbot/commands/user.ts +1 -6
  497. package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
  498. package/src/platforms/wechatbot/commands/whoami.ts +1 -6
  499. package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
  500. package/src/platforms/wechatbot/index.test.ts +10 -10
  501. package/src/platforms/wechatbot/types.test.ts +25 -25
  502. package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
  503. package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
  504. package/src/platforms/whatsapp/commands/message.test.ts +10 -10
  505. package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
  506. package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
  507. package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
  508. package/src/platforms/whatsapp/index.test.ts +8 -8
  509. package/src/platforms/whatsapp/types.test.ts +42 -42
  510. package/src/platforms/whatsappbot/cli.ts +9 -0
  511. package/src/platforms/whatsappbot/client.test.ts +27 -27
  512. package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
  513. package/src/platforms/whatsappbot/commands/auth.ts +1 -5
  514. package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
  515. package/src/platforms/whatsappbot/commands/message.ts +1 -6
  516. package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
  517. package/src/platforms/whatsappbot/commands/template.ts +1 -6
  518. package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
  519. package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
  520. package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
  521. package/src/platforms/whatsappbot/index.test.ts +7 -7
  522. package/src/platforms/whatsappbot/types.test.ts +18 -18
  523. package/src/shared/chromium/browsers.test.ts +102 -22
  524. package/src/shared/chromium/browsers.ts +72 -3
  525. package/src/shared/chromium/cli-options.test.ts +22 -0
  526. package/src/shared/chromium/cli-options.ts +12 -0
  527. package/src/shared/chromium/cookie-reader.test.ts +13 -13
  528. package/src/shared/chromium/decryptor.test.ts +97 -32
  529. package/src/shared/chromium/decryptor.ts +27 -6
  530. package/src/shared/chromium/index.ts +3 -0
  531. package/src/shared/utils/cli-output.test.ts +57 -0
  532. package/src/shared/utils/cli-output.ts +8 -0
  533. package/src/shared/utils/concurrency.test.ts +6 -6
  534. package/src/shared/utils/derived-key-cache.test.ts +11 -11
  535. package/src/tui/app.ts +129 -20
  536. package/src/tui/utils.test.ts +31 -31
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, spyOn, test } from 'bun:test'
1
+ import { beforeEach, describe, expect, spyOn, it } from 'bun:test'
2
2
  import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
3
  import { homedir, tmpdir } from 'node:os'
4
4
  import { join } from 'node:path'
@@ -13,7 +13,7 @@ describe('TeamsTokenExtractor', () => {
13
13
  })
14
14
 
15
15
  describe('getDesktopCookiesPaths', () => {
16
- test('returns darwin desktop paths on macOS', () => {
16
+ it('returns darwin desktop paths on macOS', () => {
17
17
  const darwinExtractor = new TeamsTokenExtractor('darwin')
18
18
  const paths = darwinExtractor.getDesktopCookiesPaths()
19
19
 
@@ -30,20 +30,33 @@ describe('TeamsTokenExtractor', () => {
30
30
  'EBWebView',
31
31
  )
32
32
  expect(paths).toEqual([
33
- { path: join(darwinEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work' },
34
- { path: join(darwinEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'), accountType: 'work' },
35
- { path: join(darwinEbWebView, 'WV2Profile_tfl', 'Cookies'), accountType: 'personal' },
36
- { path: join(darwinEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'), accountType: 'personal' },
37
- { path: join(darwinEbWebView, 'Default', 'Cookies'), accountType: 'work' },
38
- { path: join(darwinEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work' },
33
+ { path: join(darwinEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work', accountTypeKnown: true },
34
+ {
35
+ path: join(darwinEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'),
36
+ accountType: 'work',
37
+ accountTypeKnown: true,
38
+ },
39
+ {
40
+ path: join(darwinEbWebView, 'WV2Profile_tfl', 'Cookies'),
41
+ accountType: 'personal',
42
+ accountTypeKnown: true,
43
+ },
44
+ {
45
+ path: join(darwinEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'),
46
+ accountType: 'personal',
47
+ accountTypeKnown: true,
48
+ },
49
+ { path: join(darwinEbWebView, 'Default', 'Cookies'), accountType: 'work', accountTypeKnown: false },
50
+ { path: join(darwinEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work', accountTypeKnown: false },
39
51
  {
40
52
  path: join(homedir(), 'Library', 'Application Support', 'Microsoft', 'Teams', 'Cookies'),
41
53
  accountType: 'work',
54
+ accountTypeKnown: false,
42
55
  },
43
56
  ])
44
57
  })
45
58
 
46
- test('returns linux desktop path on Linux', () => {
59
+ it('returns linux desktop path on Linux', () => {
47
60
  const linuxExtractor = new TeamsTokenExtractor('linux')
48
61
  const paths = linuxExtractor.getDesktopCookiesPaths()
49
62
 
@@ -51,11 +64,12 @@ describe('TeamsTokenExtractor', () => {
51
64
  {
52
65
  path: join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Cookies'),
53
66
  accountType: 'work',
67
+ accountTypeKnown: false,
54
68
  },
55
69
  ])
56
70
  })
57
71
 
58
- test('returns win32 desktop paths on Windows', () => {
72
+ it('returns win32 desktop paths on Windows', () => {
59
73
  const winExtractor = new TeamsTokenExtractor('win32')
60
74
  const paths = winExtractor.getDesktopCookiesPaths()
61
75
 
@@ -71,24 +85,32 @@ describe('TeamsTokenExtractor', () => {
71
85
  'EBWebView',
72
86
  )
73
87
  expect(paths).toEqual([
74
- { path: join(winEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work' },
75
- { path: join(winEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'), accountType: 'work' },
76
- { path: join(winEbWebView, 'WV2Profile_tfl', 'Cookies'), accountType: 'personal' },
77
- { path: join(winEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'), accountType: 'personal' },
78
- { path: join(winEbWebView, 'Default', 'Cookies'), accountType: 'work' },
79
- { path: join(winEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work' },
80
- { path: join(appdata, 'Microsoft', 'Teams', 'Cookies'), accountType: 'work' },
88
+ { path: join(winEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work', accountTypeKnown: true },
89
+ {
90
+ path: join(winEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'),
91
+ accountType: 'work',
92
+ accountTypeKnown: true,
93
+ },
94
+ { path: join(winEbWebView, 'WV2Profile_tfl', 'Cookies'), accountType: 'personal', accountTypeKnown: true },
95
+ {
96
+ path: join(winEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'),
97
+ accountType: 'personal',
98
+ accountTypeKnown: true,
99
+ },
100
+ { path: join(winEbWebView, 'Default', 'Cookies'), accountType: 'work', accountTypeKnown: false },
101
+ { path: join(winEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work', accountTypeKnown: false },
102
+ { path: join(appdata, 'Microsoft', 'Teams', 'Cookies'), accountType: 'work', accountTypeKnown: false },
81
103
  ])
82
104
  })
83
105
 
84
- test('returns empty array for unsupported platform', () => {
106
+ it('returns empty array for unsupported platform', () => {
85
107
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
86
108
  expect(unsupportedExtractor.getDesktopCookiesPaths()).toEqual([])
87
109
  })
88
110
  })
89
111
 
90
112
  describe('getBrowserCookiesPaths', () => {
91
- test('returns browser cookie paths on macOS (at least Default profile per browser)', () => {
113
+ it('returns browser cookie paths on macOS (at least Default profile per browser)', () => {
92
114
  const darwinExtractor = new TeamsTokenExtractor('darwin')
93
115
  const paths = darwinExtractor.getBrowserCookiesPaths()
94
116
 
@@ -96,14 +118,16 @@ describe('TeamsTokenExtractor', () => {
96
118
  expect(paths).toContainEqual({
97
119
  path: join(chromeBase, 'Default', 'Cookies'),
98
120
  accountType: 'work',
121
+ accountTypeKnown: false,
99
122
  })
100
123
  expect(paths).toContainEqual({
101
124
  path: join(chromeBase, 'Default', 'Network', 'Cookies'),
102
125
  accountType: 'work',
126
+ accountTypeKnown: false,
103
127
  })
104
128
  })
105
129
 
106
- test('returns browser cookie paths on Linux', () => {
130
+ it('returns browser cookie paths on Linux', () => {
107
131
  const linuxExtractor = new TeamsTokenExtractor('linux')
108
132
  const paths = linuxExtractor.getBrowserCookiesPaths()
109
133
 
@@ -111,10 +135,11 @@ describe('TeamsTokenExtractor', () => {
111
135
  expect(paths).toContainEqual({
112
136
  path: join(chromeBase, 'Default', 'Cookies'),
113
137
  accountType: 'work',
138
+ accountTypeKnown: false,
114
139
  })
115
140
  })
116
141
 
117
- test('returns browser cookie paths on Windows', () => {
142
+ it('returns browser cookie paths on Windows', () => {
118
143
  const winExtractor = new TeamsTokenExtractor('win32')
119
144
  const paths = winExtractor.getBrowserCookiesPaths()
120
145
 
@@ -123,23 +148,28 @@ describe('TeamsTokenExtractor', () => {
123
148
  expect(paths).toContainEqual({
124
149
  path: join(chromeBase, 'Default', 'Cookies'),
125
150
  accountType: 'work',
151
+ accountTypeKnown: false,
126
152
  })
127
153
  })
128
154
 
129
- test('returns empty array for unsupported platform', () => {
155
+ it('returns empty array for unsupported platform', () => {
130
156
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
131
157
  expect(unsupportedExtractor.getBrowserCookiesPaths()).toEqual([])
132
158
  })
133
159
 
134
- test('all browser paths have accountType work', () => {
160
+ // Regression for #163: browser paths must not assert accountType confidently because
161
+ // Chromium profile paths don't encode work vs personal. Desktop WV2Profile_tfw/_tfl
162
+ // paths are authoritative; browsers must be probed at validation time.
163
+ it('browser paths have accountTypeKnown=false so they get probed at validation', () => {
135
164
  const darwinExtractor = new TeamsTokenExtractor('darwin')
136
165
  const paths = darwinExtractor.getBrowserCookiesPaths()
137
- expect(paths.every((p) => p.accountType === 'work')).toBe(true)
166
+ expect(paths.length).toBeGreaterThan(0)
167
+ expect(paths.every((p) => p.accountTypeKnown === false)).toBe(true)
138
168
  })
139
169
  })
140
170
 
141
171
  describe('getTeamsCookiesPaths', () => {
142
- test('returns darwin paths on macOS with desktop paths first', () => {
172
+ it('returns darwin paths on macOS with desktop paths first', () => {
143
173
  const darwinExtractor = new TeamsTokenExtractor('darwin')
144
174
  const paths = darwinExtractor.getTeamsCookiesPaths()
145
175
  const desktopPaths = darwinExtractor.getDesktopCookiesPaths()
@@ -147,7 +177,7 @@ describe('TeamsTokenExtractor', () => {
147
177
  expect(paths.slice(0, desktopPaths.length)).toEqual(desktopPaths)
148
178
  })
149
179
 
150
- test('browser paths come after desktop paths on macOS', () => {
180
+ it('browser paths come after desktop paths on macOS', () => {
151
181
  const darwinExtractor = new TeamsTokenExtractor('darwin')
152
182
  const paths = darwinExtractor.getTeamsCookiesPaths()
153
183
  const desktopPaths = darwinExtractor.getDesktopCookiesPaths()
@@ -157,7 +187,7 @@ describe('TeamsTokenExtractor', () => {
157
187
  expect(paths.slice(desktopPaths.length)).toEqual(browserPaths)
158
188
  })
159
189
 
160
- test('returns linux paths with desktop first then browser paths', () => {
190
+ it('returns linux paths with desktop first then browser paths', () => {
161
191
  const linuxExtractor = new TeamsTokenExtractor('linux')
162
192
  const paths = linuxExtractor.getTeamsCookiesPaths()
163
193
  const desktopPaths = linuxExtractor.getDesktopCookiesPaths()
@@ -166,12 +196,13 @@ describe('TeamsTokenExtractor', () => {
166
196
  {
167
197
  path: join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Cookies'),
168
198
  accountType: 'work',
199
+ accountTypeKnown: false,
169
200
  },
170
201
  ])
171
202
  expect(paths.length).toBeGreaterThan(desktopPaths.length)
172
203
  })
173
204
 
174
- test('returns win32 paths with desktop first then browser paths', () => {
205
+ it('returns win32 paths with desktop first then browser paths', () => {
175
206
  const winExtractor = new TeamsTokenExtractor('win32')
176
207
  const paths = winExtractor.getTeamsCookiesPaths()
177
208
  const desktopPaths = winExtractor.getDesktopCookiesPaths()
@@ -180,7 +211,7 @@ describe('TeamsTokenExtractor', () => {
180
211
  expect(paths.length).toBeGreaterThan(desktopPaths.length)
181
212
  })
182
213
 
183
- test('returns empty array for unsupported platform', () => {
214
+ it('returns empty array for unsupported platform', () => {
184
215
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
185
216
  const paths = unsupportedExtractor.getTeamsCookiesPaths()
186
217
 
@@ -189,21 +220,21 @@ describe('TeamsTokenExtractor', () => {
189
220
  })
190
221
 
191
222
  describe('getLocalStatePath', () => {
192
- test('returns darwin Local State path on macOS', () => {
223
+ it('returns darwin Local State path on macOS', () => {
193
224
  const darwinExtractor = new TeamsTokenExtractor('darwin')
194
225
  const path = darwinExtractor.getLocalStatePath()
195
226
 
196
227
  expect(path).toBe(join(homedir(), 'Library', 'Application Support', 'Microsoft', 'Teams', 'Local State'))
197
228
  })
198
229
 
199
- test('returns linux Local State path on Linux', () => {
230
+ it('returns linux Local State path on Linux', () => {
200
231
  const linuxExtractor = new TeamsTokenExtractor('linux')
201
232
  const path = linuxExtractor.getLocalStatePath()
202
233
 
203
234
  expect(path).toBe(join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Local State'))
204
235
  })
205
236
 
206
- test('returns win32 Local State path on Windows', () => {
237
+ it('returns win32 Local State path on Windows', () => {
207
238
  const winExtractor = new TeamsTokenExtractor('win32')
208
239
  const path = winExtractor.getLocalStatePath()
209
240
 
@@ -213,7 +244,7 @@ describe('TeamsTokenExtractor', () => {
213
244
  })
214
245
 
215
246
  describe('getKeychainVariants', () => {
216
- test('includes Teams-specific keychain entries', () => {
247
+ it('includes Teams-specific keychain entries', () => {
217
248
  const macExtractor = new TeamsTokenExtractor('darwin')
218
249
  const variants = macExtractor.getKeychainVariants()
219
250
 
@@ -226,7 +257,7 @@ describe('TeamsTokenExtractor', () => {
226
257
  expect(variants).toContainEqual({ service: 'Teams Safe Storage', account: 'Teams' })
227
258
  })
228
259
 
229
- test('includes browser keychain entries appended after Teams entries', () => {
260
+ it('includes browser keychain entries appended after Teams entries', () => {
230
261
  const macExtractor = new TeamsTokenExtractor('darwin')
231
262
  const variants = macExtractor.getKeychainVariants()
232
263
 
@@ -238,7 +269,7 @@ describe('TeamsTokenExtractor', () => {
238
269
  expect(variants).toContainEqual({ service: 'Chromium Safe Storage', account: 'Chromium' })
239
270
  })
240
271
 
241
- test('Teams entries come before browser entries', () => {
272
+ it('Teams entries come before browser entries', () => {
242
273
  const macExtractor = new TeamsTokenExtractor('darwin')
243
274
  const variants = macExtractor.getKeychainVariants()
244
275
 
@@ -249,59 +280,81 @@ describe('TeamsTokenExtractor', () => {
249
280
  })
250
281
 
251
282
  describe('isValidSkypeToken', () => {
252
- test('validates JWT-like skype token format', () => {
283
+ it('validates JWT-like skype token format', () => {
253
284
  const validToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature'
254
285
  expect(extractor.isValidSkypeToken(validToken)).toBe(true)
255
286
  })
256
287
 
257
- test('validates long base64 token format', () => {
288
+ it('validates long base64 token format', () => {
258
289
  const validToken = 'a'.repeat(100)
259
290
  expect(extractor.isValidSkypeToken(validToken)).toBe(true)
260
291
  })
261
292
 
262
- test('rejects empty tokens', () => {
293
+ it('rejects empty tokens', () => {
263
294
  expect(extractor.isValidSkypeToken('')).toBe(false)
264
295
  })
265
296
 
266
- test('rejects short tokens', () => {
297
+ it('rejects short tokens', () => {
267
298
  expect(extractor.isValidSkypeToken('short')).toBe(false)
268
299
  })
269
300
 
270
- test('rejects null/undefined', () => {
301
+ it('rejects null/undefined', () => {
271
302
  expect(extractor.isValidSkypeToken(null as unknown as string)).toBe(false)
272
303
  expect(extractor.isValidSkypeToken(undefined as unknown as string)).toBe(false)
273
304
  })
305
+
306
+ // Regression for #156: PowerShell CLIXML leaks into DPAPI output on Windows.
307
+ it('rejects CLIXML progress-stream contamination', () => {
308
+ // given: the exact shape of the leak reported in #156
309
+ const clixml =
310
+ '#< CLIXML\r\n<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">' +
311
+ '<Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T>' +
312
+ '<T>System.Object</T></TN><MS><I64 N="SourceId">1</I64></MS></Obj></Objs>'
313
+
314
+ // then
315
+ expect(extractor.isValidSkypeToken(clixml)).toBe(false)
316
+ })
317
+
318
+ it('rejects anything containing angle brackets or whitespace', () => {
319
+ expect(extractor.isValidSkypeToken('a'.repeat(60) + '<div>')).toBe(false)
320
+ expect(extractor.isValidSkypeToken('a'.repeat(40) + ' ' + 'b'.repeat(40))).toBe(false)
321
+ expect(extractor.isValidSkypeToken('a'.repeat(40) + '\n' + 'b'.repeat(40))).toBe(false)
322
+ })
323
+
324
+ it('rejects a bare 36-char UUID', () => {
325
+ expect(extractor.isValidSkypeToken('12345678-1234-1234-1234-123456789012')).toBe(false)
326
+ })
274
327
  })
275
328
 
276
329
  describe('isEncryptedValue', () => {
277
- test('detects v10 encrypted values', () => {
330
+ it('detects v10 encrypted values', () => {
278
331
  const encrypted = Buffer.from('v10encrypted_data')
279
332
  expect(extractor.isEncryptedValue(encrypted)).toBe(true)
280
333
  })
281
334
 
282
- test('detects v11 encrypted values', () => {
335
+ it('detects v11 encrypted values', () => {
283
336
  const encrypted = Buffer.from('v11encrypted_data')
284
337
  expect(extractor.isEncryptedValue(encrypted)).toBe(true)
285
338
  })
286
339
 
287
- test('rejects non-encrypted values', () => {
340
+ it('rejects non-encrypted values', () => {
288
341
  const plain = Buffer.from('plain_text')
289
342
  expect(extractor.isEncryptedValue(plain)).toBe(false)
290
343
  })
291
344
 
292
- test('rejects empty buffers', () => {
345
+ it('rejects empty buffers', () => {
293
346
  const empty = Buffer.alloc(0)
294
347
  expect(extractor.isEncryptedValue(empty)).toBe(false)
295
348
  })
296
349
 
297
- test('rejects short buffers', () => {
350
+ it('rejects short buffers', () => {
298
351
  const short = Buffer.from('v1')
299
352
  expect(extractor.isEncryptedValue(short)).toBe(false)
300
353
  })
301
354
  })
302
355
 
303
356
  describe('extract', () => {
304
- test('returns null when cookies path does not exist', async () => {
357
+ it('returns null when cookies path does not exist', async () => {
305
358
  const linuxExtractor = new TeamsTokenExtractor('linux')
306
359
  const extractFromCookiesDBSpy = spyOn(linuxExtractor as any, 'extractFromCookiesDB').mockResolvedValue([])
307
360
 
@@ -311,12 +364,12 @@ describe('TeamsTokenExtractor', () => {
311
364
  extractFromCookiesDBSpy.mockRestore()
312
365
  })
313
366
 
314
- test('extracts token from cookies database when available', async () => {
367
+ it('extracts token from cookies database when available', async () => {
315
368
  const mockToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature_here'
316
369
 
317
370
  const linuxExtractor = new TeamsTokenExtractor('linux')
318
371
  const extractFromCookiesDBSpy = spyOn(linuxExtractor as any, 'extractFromCookiesDB').mockResolvedValue([
319
- { token: mockToken, accountType: 'work' },
372
+ { token: mockToken, accountType: 'work', accountTypeKnown: true },
320
373
  ])
321
374
 
322
375
  const result = await linuxExtractor.extract()
@@ -327,7 +380,7 @@ describe('TeamsTokenExtractor', () => {
327
380
  extractFromCookiesDBSpy.mockRestore()
328
381
  })
329
382
 
330
- test('returns null when extraction fails', async () => {
383
+ it('returns null when extraction fails', async () => {
331
384
  const darwinExtractor = new TeamsTokenExtractor('darwin')
332
385
  const extractFromCookiesDBSpy = spyOn(darwinExtractor as any, 'extractFromCookiesDB').mockResolvedValue([])
333
386
 
@@ -349,7 +402,7 @@ describe('TeamsTokenExtractor', () => {
349
402
  const cleanup = () => rmSync(workDir, { recursive: true, force: true })
350
403
 
351
404
  // Regression for #156: if only Network/Cookies exists, missing sibling must not poison accountType.
352
- test('falls through to Network/Cookies when Cookies is missing', async () => {
405
+ it('falls through to Network/Cookies when Cookies is missing', async () => {
353
406
  // given: only Network/Cookies exists on disk for WV2Profile_tfl
354
407
  const profileDir = join(workDir, 'WV2Profile_tfl')
355
408
  const networkDir = join(profileDir, 'Network')
@@ -360,8 +413,8 @@ describe('TeamsTokenExtractor', () => {
360
413
 
361
414
  const winExtractor = new TeamsTokenExtractor('win32')
362
415
  const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
363
- { path: cookiesPath, accountType: 'personal' },
364
- { path: networkCookiesPath, accountType: 'personal' },
416
+ { path: cookiesPath, accountType: 'personal', accountTypeKnown: true },
417
+ { path: networkCookiesPath, accountType: 'personal', accountTypeKnown: true },
365
418
  ])
366
419
  const tried: string[] = []
367
420
  const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockImplementation(async (...args) => {
@@ -376,14 +429,143 @@ describe('TeamsTokenExtractor', () => {
376
429
  // then: the Cookies path was skipped (never passed to copyAndExtract),
377
430
  // the Network/Cookies sibling was tried, and the token was returned.
378
431
  expect(tried).toEqual([networkCookiesPath])
379
- expect(results).toEqual([{ token: mockToken, accountType: 'personal' }])
432
+ expect(results).toEqual([{ token: mockToken, accountType: 'personal', accountTypeKnown: true }])
433
+
434
+ getPathsSpy.mockRestore()
435
+ copyAndExtractSpy.mockRestore()
436
+ cleanup()
437
+ })
438
+
439
+ // Regression for #156: CLIXML-contaminated decrypt output must not short-circuit
440
+ // the work account, leaving other valid paths unvisited.
441
+ it('does not mark accountType seen when the first path yields CLIXML garbage', async () => {
442
+ // given: first work path returns CLIXML garbage, second work path returns a real token
443
+ const clixmlGarbage =
444
+ '#< CLIXML\r\n<Objs xmlns="http://schemas.microsoft.com/powershell/2004/04">' +
445
+ '<Obj S="progress"><TN><T>Progress</T></TN></Obj></Objs>\r\n' +
446
+ 'a'.repeat(80)
447
+ const realToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature_here'
448
+
449
+ const winExtractor = new TeamsTokenExtractor('win32')
450
+ const firstPath = join(workDir, 'WV2Profile_tfw', 'Cookies')
451
+ const secondPath = join(workDir, 'Default', 'Network', 'Cookies')
452
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
453
+ { path: firstPath, accountType: 'work', accountTypeKnown: true },
454
+ { path: secondPath, accountType: 'work', accountTypeKnown: true },
455
+ ])
456
+ mkdirSync(join(workDir, 'WV2Profile_tfw'), { recursive: true })
457
+ mkdirSync(join(workDir, 'Default', 'Network'), { recursive: true })
458
+ writeFileSync(firstPath, '')
459
+ writeFileSync(secondPath, '')
460
+
461
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract')
462
+ .mockResolvedValueOnce(clixmlGarbage)
463
+ .mockResolvedValueOnce(realToken)
464
+
465
+ // when
466
+ const results = await (winExtractor as any).extractFromCookiesDB()
467
+
468
+ // then: garbage was rejected, loop continued to the real token
469
+ expect(copyAndExtractSpy).toHaveBeenCalledTimes(2)
470
+ expect(results).toEqual([{ token: realToken, accountType: 'work', accountTypeKnown: true }])
471
+
472
+ getPathsSpy.mockRestore()
473
+ copyAndExtractSpy.mockRestore()
474
+ cleanup()
475
+ })
476
+
477
+ // Regression for #163: browser-sourced tokens carry accountTypeKnown=false so that
478
+ // the auth command can probe both endpoints. The extraction loop must preserve the
479
+ // flag and must not dedupe an unknown-type browser token by its guessed accountType.
480
+ it('propagates accountTypeKnown=false for browser-sourced tokens', async () => {
481
+ // given: a browser Cookies path returning a valid token, guessed as work
482
+ const browserPath = join(workDir, 'Chrome', 'Default', 'Cookies')
483
+ mkdirSync(join(workDir, 'Chrome', 'Default'), { recursive: true })
484
+ writeFileSync(browserPath, '')
485
+
486
+ const winExtractor = new TeamsTokenExtractor('win32')
487
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
488
+ { path: browserPath, accountType: 'work', accountTypeKnown: false },
489
+ ])
490
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
491
+
492
+ // when
493
+ const results = await (winExtractor as any).extractFromCookiesDB()
494
+
495
+ // then: the flag is passed through so callers can probe
496
+ expect(results).toEqual([{ token: mockToken, accountType: 'work', accountTypeKnown: false }])
497
+
498
+ getPathsSpy.mockRestore()
499
+ copyAndExtractSpy.mockRestore()
500
+ cleanup()
501
+ })
502
+
503
+ // Regression for #163: when a desktop path (known=true) for 'work' already succeeded,
504
+ // a subsequent browser path (known=false) guessed as 'work' must still be explored —
505
+ // it might be a personal account misguessed as work. The dedup only kicks in for
506
+ // confidently labeled paths.
507
+ it('does not skip unknown-type path just because a known-type same-label succeeded', async () => {
508
+ const desktopPath = join(workDir, 'WV2Profile_tfw', 'Network', 'Cookies')
509
+ const browserPath = join(workDir, 'Chrome', 'Default', 'Cookies')
510
+ mkdirSync(join(workDir, 'WV2Profile_tfw', 'Network'), { recursive: true })
511
+ mkdirSync(join(workDir, 'Chrome', 'Default'), { recursive: true })
512
+ writeFileSync(desktopPath, '')
513
+ writeFileSync(browserPath, '')
514
+
515
+ const desktopToken = mockToken
516
+ const browserToken = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJicm93c2VyIn0.different_signature_here_abc'
517
+
518
+ const winExtractor = new TeamsTokenExtractor('win32')
519
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
520
+ { path: desktopPath, accountType: 'work', accountTypeKnown: true },
521
+ { path: browserPath, accountType: 'work', accountTypeKnown: false },
522
+ ])
523
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract')
524
+ .mockResolvedValueOnce(desktopToken)
525
+ .mockResolvedValueOnce(browserToken)
526
+
527
+ // when
528
+ const results = await (winExtractor as any).extractFromCookiesDB()
529
+
530
+ // then: both tokens returned; browser token keeps accountTypeKnown=false for probing
531
+ expect(results).toEqual([
532
+ { token: desktopToken, accountType: 'work', accountTypeKnown: true },
533
+ { token: browserToken, accountType: 'work', accountTypeKnown: false },
534
+ ])
535
+
536
+ getPathsSpy.mockRestore()
537
+ copyAndExtractSpy.mockRestore()
538
+ cleanup()
539
+ })
540
+
541
+ it('dedupes identical tokens extracted from multiple paths', async () => {
542
+ const path1 = join(workDir, 'Chrome', 'Default', 'Cookies')
543
+ const path2 = join(workDir, 'Edge', 'Default', 'Cookies')
544
+ mkdirSync(join(workDir, 'Chrome', 'Default'), { recursive: true })
545
+ mkdirSync(join(workDir, 'Edge', 'Default'), { recursive: true })
546
+ writeFileSync(path1, '')
547
+ writeFileSync(path2, '')
548
+
549
+ const winExtractor = new TeamsTokenExtractor('win32')
550
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
551
+ { path: path1, accountType: 'work', accountTypeKnown: false },
552
+ { path: path2, accountType: 'work', accountTypeKnown: false },
553
+ ])
554
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
555
+
556
+ // when
557
+ const results = await (winExtractor as any).extractFromCookiesDB()
558
+
559
+ // then: only one result despite two paths returning the same token
560
+ expect(results).toHaveLength(1)
561
+ expect(results[0].token).toBe(mockToken)
380
562
 
381
563
  getPathsSpy.mockRestore()
382
564
  copyAndExtractSpy.mockRestore()
383
565
  cleanup()
384
566
  })
385
567
 
386
- test('a missing path does not mark the account type as seen', async () => {
568
+ it('a missing path does not mark the account type as seen', async () => {
387
569
  // given: work account has Cookies missing but Network/Cookies present
388
570
  const workProfile = join(workDir, 'WV2Profile_tfw')
389
571
  const workNetworkDir = join(workProfile, 'Network')
@@ -394,8 +576,8 @@ describe('TeamsTokenExtractor', () => {
394
576
 
395
577
  const winExtractor = new TeamsTokenExtractor('win32')
396
578
  const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
397
- { path: workCookies, accountType: 'work' },
398
- { path: workNetworkCookies, accountType: 'work' },
579
+ { path: workCookies, accountType: 'work', accountTypeKnown: true },
580
+ { path: workNetworkCookies, accountType: 'work', accountTypeKnown: true },
399
581
  ])
400
582
  const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
401
583
 
@@ -415,7 +597,7 @@ describe('TeamsTokenExtractor', () => {
415
597
  })
416
598
 
417
599
  describe('copyAndExtract', () => {
418
- test('attempts to copy database to temp location', async () => {
600
+ it('attempts to copy database to temp location', async () => {
419
601
  const darwinExtractor = new TeamsTokenExtractor('darwin')
420
602
 
421
603
  const copyFileSpy = spyOn(darwinExtractor as any, 'copyDatabaseToTemp').mockReturnValue('/tmp/test-cookies')
@@ -434,7 +616,7 @@ describe('TeamsTokenExtractor', () => {
434
616
  cleanupSpy.mockRestore()
435
617
  })
436
618
 
437
- test('returns null when copy fails (file locked)', async () => {
619
+ it('returns null when copy fails (file locked)', async () => {
438
620
  const darwinExtractor = new TeamsTokenExtractor('darwin')
439
621
 
440
622
  const copyFileSpy = spyOn(darwinExtractor as any, 'copyDatabaseToTemp').mockImplementation(() => {
@@ -451,7 +633,7 @@ describe('TeamsTokenExtractor', () => {
451
633
 
452
634
  describe('decryption', () => {
453
635
  describe('decryptAESGCM', () => {
454
- test('returns null for invalid encrypted data', () => {
636
+ it('returns null for invalid encrypted data', () => {
455
637
  const darwinExtractor = new TeamsTokenExtractor('darwin')
456
638
  const invalidData = Buffer.from('too_short')
457
639
  const key = Buffer.alloc(32, 0)
@@ -460,7 +642,7 @@ describe('TeamsTokenExtractor', () => {
460
642
  expect(result).toBeNull()
461
643
  })
462
644
 
463
- test('returns null when decryption fails', () => {
645
+ it('returns null when decryption fails', () => {
464
646
  const darwinExtractor = new TeamsTokenExtractor('darwin')
465
647
  const fakeEncrypted = Buffer.concat([
466
648
  Buffer.from('v10'),
@@ -476,7 +658,7 @@ describe('TeamsTokenExtractor', () => {
476
658
  })
477
659
 
478
660
  describe('getKeychainPassword (macOS)', () => {
479
- test('tries multiple keychain variants', async () => {
661
+ it('tries multiple keychain variants', async () => {
480
662
  const darwinExtractor = new TeamsTokenExtractor('darwin')
481
663
  const execSyncSpy = spyOn(darwinExtractor as any, 'execSecurityCommand')
482
664
  .mockReturnValueOnce(null)
@@ -490,7 +672,7 @@ describe('TeamsTokenExtractor', () => {
490
672
  execSyncSpy.mockRestore()
491
673
  })
492
674
 
493
- test('returns null when all keychain variants fail', async () => {
675
+ it('returns null when all keychain variants fail', async () => {
494
676
  const darwinExtractor = new TeamsTokenExtractor('darwin')
495
677
  const execSyncSpy = spyOn(darwinExtractor as any, 'execSecurityCommand').mockReturnValue(null)
496
678
 
@@ -505,7 +687,7 @@ describe('TeamsTokenExtractor', () => {
505
687
 
506
688
  describe('process management', () => {
507
689
  describe('isTeamsRunning', () => {
508
- test('returns true when Teams process is found', async () => {
690
+ it('returns true when Teams process is found', async () => {
509
691
  const darwinExtractor = new TeamsTokenExtractor('darwin')
510
692
  const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(true)
511
693
 
@@ -515,7 +697,7 @@ describe('TeamsTokenExtractor', () => {
515
697
  checkProcessRunningSpy.mockRestore()
516
698
  })
517
699
 
518
- test('returns false when no Teams process is found', async () => {
700
+ it('returns false when no Teams process is found', async () => {
519
701
  const darwinExtractor = new TeamsTokenExtractor('darwin')
520
702
  const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(false)
521
703
 
@@ -527,17 +709,17 @@ describe('TeamsTokenExtractor', () => {
527
709
  })
528
710
 
529
711
  describe('getProcessName', () => {
530
- test('returns correct process name for macOS', () => {
712
+ it('returns correct process name for macOS', () => {
531
713
  const darwinExtractor = new TeamsTokenExtractor('darwin')
532
714
  expect((darwinExtractor as any).getProcessName()).toBe('Microsoft Teams')
533
715
  })
534
716
 
535
- test('returns correct process name for Windows', () => {
717
+ it('returns correct process name for Windows', () => {
536
718
  const winExtractor = new TeamsTokenExtractor('win32')
537
719
  expect((winExtractor as any).getProcessName()).toBe('Teams.exe')
538
720
  })
539
721
 
540
- test('returns correct process name for Linux', () => {
722
+ it('returns correct process name for Linux', () => {
541
723
  const linuxExtractor = new TeamsTokenExtractor('linux')
542
724
  expect((linuxExtractor as any).getProcessName()).toBe('teams')
543
725
  })
@@ -545,7 +727,7 @@ describe('TeamsTokenExtractor', () => {
545
727
  })
546
728
 
547
729
  describe('SQLite extraction', () => {
548
- test('returns null when database path does not exist', async () => {
730
+ it('returns null when database path does not exist', async () => {
549
731
  const darwinExtractor = new TeamsTokenExtractor('darwin')
550
732
 
551
733
  const result = await (darwinExtractor as any).extractFromSQLite('/nonexistent/path')
@@ -553,7 +735,7 @@ describe('TeamsTokenExtractor', () => {
553
735
  expect(result).toBeNull()
554
736
  })
555
737
 
556
- test('returns null when extraction throws', async () => {
738
+ it('returns null when extraction throws', async () => {
557
739
  const darwinExtractor = new TeamsTokenExtractor('darwin')
558
740
 
559
741
  const result = await (darwinExtractor as any).extractFromSQLite('/dev/null')