agent-messenger 2.10.0 → 2.10.2

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 (239) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/package.json +1 -1
  3. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  4. package/dist/src/platforms/teams/token-extractor.js +15 -2
  5. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  6. package/dist/src/shared/chromium/decryptor.d.ts +6 -0
  7. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
  8. package/dist/src/shared/chromium/decryptor.js +26 -6
  9. package/dist/src/shared/chromium/decryptor.js.map +1 -1
  10. package/e2e/channeltalk.e2e.test.ts +13 -13
  11. package/e2e/channeltalkbot.e2e.test.ts +13 -13
  12. package/e2e/discord.e2e.test.ts +24 -24
  13. package/e2e/discordbot.e2e.test.ts +16 -16
  14. package/e2e/instagram.e2e.test.ts +10 -10
  15. package/e2e/kakaotalk.e2e.test.ts +7 -7
  16. package/e2e/line.e2e.test.ts +8 -8
  17. package/e2e/slack.e2e.test.ts +34 -34
  18. package/e2e/slackbot.e2e.test.ts +14 -14
  19. package/e2e/teams.e2e.test.ts +23 -23
  20. package/e2e/telegram.e2e.test.ts +8 -8
  21. package/e2e/webex.e2e.test.ts +14 -14
  22. package/e2e/whatsapp.e2e.test.ts +8 -8
  23. package/e2e/whatsappbot.e2e.test.ts +6 -6
  24. package/package.json +1 -1
  25. package/skills/agent-channeltalk/SKILL.md +1 -1
  26. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  27. package/skills/agent-discord/SKILL.md +1 -1
  28. package/skills/agent-discordbot/SKILL.md +1 -1
  29. package/skills/agent-instagram/SKILL.md +1 -1
  30. package/skills/agent-kakaotalk/SKILL.md +1 -1
  31. package/skills/agent-line/SKILL.md +1 -1
  32. package/skills/agent-slack/SKILL.md +1 -1
  33. package/skills/agent-slackbot/SKILL.md +1 -1
  34. package/skills/agent-teams/SKILL.md +1 -1
  35. package/skills/agent-telegram/SKILL.md +1 -1
  36. package/skills/agent-webex/SKILL.md +1 -1
  37. package/skills/agent-wechatbot/SKILL.md +1 -1
  38. package/skills/agent-whatsapp/SKILL.md +1 -1
  39. package/skills/agent-whatsappbot/SKILL.md +1 -1
  40. package/src/platforms/channeltalk/client.test.ts +26 -26
  41. package/src/platforms/channeltalk/commands/auth.test.ts +16 -16
  42. package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
  43. package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
  44. package/src/platforms/channeltalk/commands/group.test.ts +4 -4
  45. package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
  46. package/src/platforms/channeltalk/commands/message.test.ts +17 -17
  47. package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
  48. package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
  49. package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
  50. package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
  51. package/src/platforms/channeltalk/index.test.ts +23 -23
  52. package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
  53. package/src/platforms/channeltalk/types.test.ts +12 -12
  54. package/src/platforms/channeltalkbot/client.test.ts +14 -14
  55. package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
  56. package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
  57. package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
  58. package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
  59. package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
  60. package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
  61. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
  62. package/src/platforms/channeltalkbot/commands/whoami.test.ts +4 -4
  63. package/src/platforms/channeltalkbot/credential-manager.test.ts +27 -27
  64. package/src/platforms/channeltalkbot/index.test.ts +15 -15
  65. package/src/platforms/discord/client.test.ts +28 -28
  66. package/src/platforms/discord/commands/auth.test.ts +7 -7
  67. package/src/platforms/discord/commands/channel.test.ts +7 -7
  68. package/src/platforms/discord/commands/dm.test.ts +4 -4
  69. package/src/platforms/discord/commands/file.test.ts +4 -4
  70. package/src/platforms/discord/commands/friend.test.ts +6 -6
  71. package/src/platforms/discord/commands/member.test.ts +5 -5
  72. package/src/platforms/discord/commands/mention.test.ts +5 -5
  73. package/src/platforms/discord/commands/message.test.ts +9 -9
  74. package/src/platforms/discord/commands/note.test.ts +6 -6
  75. package/src/platforms/discord/commands/profile.test.ts +4 -4
  76. package/src/platforms/discord/commands/reaction.test.ts +5 -5
  77. package/src/platforms/discord/commands/server.test.ts +7 -7
  78. package/src/platforms/discord/commands/snapshot.test.ts +6 -6
  79. package/src/platforms/discord/commands/thread.test.ts +6 -6
  80. package/src/platforms/discord/commands/user.test.ts +5 -5
  81. package/src/platforms/discord/commands/whoami.test.ts +6 -6
  82. package/src/platforms/discord/credential-manager.test.ts +16 -16
  83. package/src/platforms/discord/ensure-auth.test.ts +8 -8
  84. package/src/platforms/discord/index.test.ts +17 -17
  85. package/src/platforms/discord/listener.test.ts +33 -33
  86. package/src/platforms/discord/token-extractor.test.ts +53 -53
  87. package/src/platforms/discord/types.test.ts +26 -26
  88. package/src/platforms/discordbot/client.test.ts +31 -31
  89. package/src/platforms/discordbot/commands/auth.test.ts +18 -18
  90. package/src/platforms/discordbot/commands/channel.test.ts +11 -11
  91. package/src/platforms/discordbot/commands/file.test.ts +7 -7
  92. package/src/platforms/discordbot/commands/message.test.ts +25 -25
  93. package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
  94. package/src/platforms/discordbot/commands/server.test.ts +12 -12
  95. package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
  96. package/src/platforms/discordbot/commands/thread.test.ts +10 -10
  97. package/src/platforms/discordbot/commands/user.test.ts +9 -9
  98. package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
  99. package/src/platforms/discordbot/credential-manager.test.ts +28 -28
  100. package/src/platforms/instagram/client.test.ts +18 -18
  101. package/src/platforms/instagram/commands/auth.test.ts +11 -11
  102. package/src/platforms/instagram/commands/chat.test.ts +6 -6
  103. package/src/platforms/instagram/commands/message.test.ts +11 -11
  104. package/src/platforms/instagram/commands/shared.test.ts +12 -12
  105. package/src/platforms/instagram/commands/whoami.test.ts +3 -3
  106. package/src/platforms/instagram/credential-manager.test.ts +21 -21
  107. package/src/platforms/instagram/ensure-auth.test.ts +4 -4
  108. package/src/platforms/instagram/index.test.ts +9 -9
  109. package/src/platforms/instagram/listener.test.ts +8 -8
  110. package/src/platforms/instagram/token-extractor.test.ts +35 -35
  111. package/src/platforms/kakaotalk/client.test.ts +33 -33
  112. package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
  113. package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
  114. package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
  115. package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
  116. package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
  117. package/src/platforms/kakaotalk/index.test.ts +15 -15
  118. package/src/platforms/kakaotalk/listener.test.ts +17 -17
  119. package/src/platforms/line/client.test.ts +17 -17
  120. package/src/platforms/line/commands/auth.test.ts +8 -8
  121. package/src/platforms/line/commands/chat.test.ts +7 -7
  122. package/src/platforms/line/commands/friend.test.ts +6 -6
  123. package/src/platforms/line/commands/message.test.ts +7 -7
  124. package/src/platforms/line/commands/whoami.test.ts +6 -6
  125. package/src/platforms/line/credential-manager.test.ts +17 -17
  126. package/src/platforms/line/index.test.ts +10 -10
  127. package/src/platforms/line/listener.test.ts +15 -15
  128. package/src/platforms/line/types.test.ts +14 -14
  129. package/src/platforms/slack/cli.test.ts +8 -8
  130. package/src/platforms/slack/client.test.ts +151 -151
  131. package/src/platforms/slack/commands/activity.test.ts +13 -13
  132. package/src/platforms/slack/commands/auth.test.ts +34 -34
  133. package/src/platforms/slack/commands/bookmark.test.ts +9 -9
  134. package/src/platforms/slack/commands/channel.test.ts +17 -17
  135. package/src/platforms/slack/commands/drafts.test.ts +7 -7
  136. package/src/platforms/slack/commands/emoji.test.ts +3 -3
  137. package/src/platforms/slack/commands/file.test.ts +12 -12
  138. package/src/platforms/slack/commands/message.test.ts +19 -19
  139. package/src/platforms/slack/commands/pin.test.ts +7 -7
  140. package/src/platforms/slack/commands/reaction.test.ts +10 -10
  141. package/src/platforms/slack/commands/reminder.test.ts +9 -9
  142. package/src/platforms/slack/commands/saved.test.ts +7 -7
  143. package/src/platforms/slack/commands/sections.test.ts +5 -5
  144. package/src/platforms/slack/commands/snapshot.test.ts +13 -13
  145. package/src/platforms/slack/commands/unread.test.ts +6 -6
  146. package/src/platforms/slack/commands/user.test.ts +10 -10
  147. package/src/platforms/slack/commands/usergroup.test.ts +15 -15
  148. package/src/platforms/slack/commands/whoami.test.ts +6 -6
  149. package/src/platforms/slack/commands/workspace.test.ts +26 -26
  150. package/src/platforms/slack/credential-manager.test.ts +14 -14
  151. package/src/platforms/slack/ensure-auth.test.ts +21 -21
  152. package/src/platforms/slack/index.test.ts +12 -12
  153. package/src/platforms/slack/listener.test.ts +17 -17
  154. package/src/platforms/slack/token-extractor-node.test.ts +2 -2
  155. package/src/platforms/slack/token-extractor.test.ts +37 -37
  156. package/src/platforms/slack/types.test.ts +21 -21
  157. package/src/platforms/slackbot/client.test.ts +22 -22
  158. package/src/platforms/slackbot/commands/auth.test.ts +14 -14
  159. package/src/platforms/slackbot/commands/channel.test.ts +7 -7
  160. package/src/platforms/slackbot/commands/message.test.ts +13 -13
  161. package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
  162. package/src/platforms/slackbot/commands/user.test.ts +7 -7
  163. package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
  164. package/src/platforms/slackbot/credential-manager.test.ts +22 -22
  165. package/src/platforms/slackbot/types.test.ts +7 -7
  166. package/src/platforms/teams/client.test.ts +30 -30
  167. package/src/platforms/teams/commands/auth.test.ts +8 -8
  168. package/src/platforms/teams/commands/channel.test.ts +7 -7
  169. package/src/platforms/teams/commands/file.test.ts +4 -4
  170. package/src/platforms/teams/commands/message.test.ts +5 -5
  171. package/src/platforms/teams/commands/reaction.test.ts +4 -4
  172. package/src/platforms/teams/commands/snapshot.test.ts +7 -7
  173. package/src/platforms/teams/commands/team.test.ts +8 -8
  174. package/src/platforms/teams/commands/user.test.ts +4 -4
  175. package/src/platforms/teams/commands/whoami.test.ts +6 -6
  176. package/src/platforms/teams/credential-manager.test.ts +17 -17
  177. package/src/platforms/teams/ensure-auth.test.ts +13 -13
  178. package/src/platforms/teams/index.test.ts +15 -15
  179. package/src/platforms/teams/token-extractor.test.ts +219 -145
  180. package/src/platforms/teams/token-extractor.ts +13 -2
  181. package/src/platforms/teams/types.test.ts +26 -26
  182. package/src/platforms/telegram/app-config.test.ts +4 -4
  183. package/src/platforms/telegram/chat-utils.test.ts +12 -12
  184. package/src/platforms/telegram/client.test.ts +4 -4
  185. package/src/platforms/telegram/commands/auth.test.ts +16 -16
  186. package/src/platforms/telegram/commands/chat.test.ts +9 -9
  187. package/src/platforms/telegram/commands/message.test.ts +6 -6
  188. package/src/platforms/telegram/commands/shared.test.ts +3 -3
  189. package/src/platforms/telegram/commands/whoami.test.ts +3 -3
  190. package/src/platforms/telegram/credential-manager.test.ts +10 -10
  191. package/src/platforms/telegram/types.test.ts +6 -6
  192. package/src/platforms/webex/app-config.test.ts +8 -8
  193. package/src/platforms/webex/cli.test.ts +5 -5
  194. package/src/platforms/webex/client.test.ts +65 -65
  195. package/src/platforms/webex/commands/auth.test.ts +18 -18
  196. package/src/platforms/webex/commands/member.test.ts +5 -5
  197. package/src/platforms/webex/commands/message.test.ts +12 -12
  198. package/src/platforms/webex/commands/snapshot.test.ts +5 -5
  199. package/src/platforms/webex/commands/space.test.ts +10 -10
  200. package/src/platforms/webex/commands/whoami.test.ts +6 -6
  201. package/src/platforms/webex/credential-manager.test.ts +22 -22
  202. package/src/platforms/webex/encryption.test.ts +4 -4
  203. package/src/platforms/webex/ensure-auth.test.ts +5 -5
  204. package/src/platforms/webex/index.test.ts +5 -5
  205. package/src/platforms/webex/markdown-to-html.test.ts +33 -33
  206. package/src/platforms/webex/token-extractor.test.ts +23 -23
  207. package/src/platforms/webex/types.test.ts +27 -27
  208. package/src/platforms/wechatbot/client.test.ts +27 -27
  209. package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
  210. package/src/platforms/wechatbot/commands/message.test.ts +8 -8
  211. package/src/platforms/wechatbot/commands/template.test.ts +9 -9
  212. package/src/platforms/wechatbot/commands/user.test.ts +7 -7
  213. package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
  214. package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
  215. package/src/platforms/wechatbot/index.test.ts +10 -10
  216. package/src/platforms/wechatbot/types.test.ts +25 -25
  217. package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
  218. package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
  219. package/src/platforms/whatsapp/commands/message.test.ts +10 -10
  220. package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
  221. package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
  222. package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
  223. package/src/platforms/whatsapp/index.test.ts +8 -8
  224. package/src/platforms/whatsapp/types.test.ts +42 -42
  225. package/src/platforms/whatsappbot/client.test.ts +27 -27
  226. package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
  227. package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
  228. package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
  229. package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
  230. package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
  231. package/src/platforms/whatsappbot/index.test.ts +7 -7
  232. package/src/platforms/whatsappbot/types.test.ts +18 -18
  233. package/src/shared/chromium/browsers.test.ts +22 -22
  234. package/src/shared/chromium/cookie-reader.test.ts +13 -13
  235. package/src/shared/chromium/decryptor.test.ts +97 -32
  236. package/src/shared/chromium/decryptor.ts +27 -6
  237. package/src/shared/utils/concurrency.test.ts +6 -6
  238. package/src/shared/utils/derived-key-cache.test.ts +11 -11
  239. package/src/tui/utils.test.ts +31 -31
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from 'bun:test'
1
+ import { describe, expect, it } from 'bun:test'
2
2
 
3
3
  import * as jose from 'node-jose'
4
4
 
@@ -23,7 +23,7 @@ const createKeyring = async (keyUri: string) => {
23
23
  describe('WebexEncryptionService', () => {
24
24
  const keyUri = 'kms://kms-aore.wbx2.com/keys/7819829b-5e0d-4139-9cad-1b6fe7aee533'
25
25
 
26
- test('encryptText emits JWE with alg, enc, and kid JOSE headers', async () => {
26
+ it('encryptText emits JWE with alg, enc, and kid JOSE headers', async () => {
27
27
  const service = await createKeyring(keyUri)
28
28
 
29
29
  const jwe = await service.encryptText(keyUri, 'hello world')
@@ -35,7 +35,7 @@ describe('WebexEncryptionService', () => {
35
35
  expect(header.kid).toBe(keyUri)
36
36
  })
37
37
 
38
- test('encryptText returns null when key is unknown', async () => {
38
+ it('encryptText returns null when key is unknown', async () => {
39
39
  const service = await createKeyring(keyUri)
40
40
 
41
41
  const jwe = await service.encryptText('kms://other/keys/missing', 'hello')
@@ -43,7 +43,7 @@ describe('WebexEncryptionService', () => {
43
43
  expect(jwe).toBeNull()
44
44
  })
45
45
 
46
- test('decryptText round-trips plaintext encrypted by encryptText', async () => {
46
+ it('decryptText round-trips plaintext encrypted by encryptText', async () => {
47
47
  const service = await createKeyring(keyUri)
48
48
 
49
49
  const jwe = await service.encryptText(keyUri, 'round trip')
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, spyOn, it } from 'bun:test'
2
2
 
3
3
  import { WebexClient } from './client'
4
4
  import { WebexCredentialManager } from './credential-manager'
@@ -33,7 +33,7 @@ afterEach(() => {
33
33
  })
34
34
 
35
35
  describe('ensureWebexAuth', () => {
36
- test('does nothing when no config stored', async () => {
36
+ it('does nothing when no config stored', async () => {
37
37
  // given
38
38
  loadConfigSpy.mockResolvedValue(null)
39
39
 
@@ -45,7 +45,7 @@ describe('ensureWebexAuth', () => {
45
45
  expect(testAuthSpy).not.toHaveBeenCalled()
46
46
  })
47
47
 
48
- test('validates token when stored', async () => {
48
+ it('validates token when stored', async () => {
49
49
  // given
50
50
  loadConfigSpy.mockResolvedValue({
51
51
  accessToken: 'test-webex-token',
@@ -65,7 +65,7 @@ describe('ensureWebexAuth', () => {
65
65
  expect(testAuthSpy).toHaveBeenCalled()
66
66
  })
67
67
 
68
- test('does not throw when token validation fails', async () => {
68
+ it('does not throw when token validation fails', async () => {
69
69
  // given
70
70
  loadConfigSpy.mockResolvedValue({
71
71
  accessToken: 'invalid-token',
@@ -79,7 +79,7 @@ describe('ensureWebexAuth', () => {
79
79
  await expect(ensureWebexAuth()).resolves.toBeUndefined()
80
80
  })
81
81
 
82
- test('does not throw when credential manager fails', async () => {
82
+ it('does not throw when credential manager fails', async () => {
83
83
  // given
84
84
  getTokenSpy.mockRejectedValue(new Error('Disk read error'))
85
85
 
@@ -1,21 +1,21 @@
1
- import { describe, expect, test } from 'bun:test'
1
+ import { describe, expect, it } from 'bun:test'
2
2
 
3
3
  import * as webex from './index'
4
4
 
5
5
  describe('webex barrel exports', () => {
6
- test('exports WebexClient', () => {
6
+ it('exports WebexClient', () => {
7
7
  expect(webex.WebexClient).toBeDefined()
8
8
  })
9
9
 
10
- test('exports WebexCredentialManager', () => {
10
+ it('exports WebexCredentialManager', () => {
11
11
  expect(webex.WebexCredentialManager).toBeDefined()
12
12
  })
13
13
 
14
- test('exports WebexError', () => {
14
+ it('exports WebexError', () => {
15
15
  expect(webex.WebexError).toBeDefined()
16
16
  })
17
17
 
18
- test('exports Zod schemas', () => {
18
+ it('exports Zod schemas', () => {
19
19
  expect(webex.WebexSpaceSchema).toBeDefined()
20
20
  expect(webex.WebexMessageSchema).toBeDefined()
21
21
  expect(webex.WebexPersonSchema).toBeDefined()
@@ -1,141 +1,141 @@
1
- import { describe, expect, test } from 'bun:test'
1
+ import { describe, expect, it } from 'bun:test'
2
2
 
3
3
  import { markdownToHtml, stripMarkdown } from './markdown-to-html'
4
4
 
5
5
  describe('markdownToHtml', () => {
6
- test('converts bold text', () => {
6
+ it('converts bold text', () => {
7
7
  expect(markdownToHtml('**bold**')).toBe('<strong>bold</strong>')
8
8
  })
9
9
 
10
- test('converts italic text', () => {
10
+ it('converts italic text', () => {
11
11
  expect(markdownToHtml('_italic_')).toBe('<em>italic</em>')
12
12
  })
13
13
 
14
- test('does not italicize mid-word underscores', () => {
14
+ it('does not italicize mid-word underscores', () => {
15
15
  expect(markdownToHtml('some_variable_name')).toBe('some_variable_name')
16
16
  })
17
17
 
18
- test('converts bold and italic text', () => {
18
+ it('converts bold and italic text', () => {
19
19
  expect(markdownToHtml('***both***')).toBe('<strong><em>both</em></strong>')
20
20
  })
21
21
 
22
- test('converts inline code', () => {
22
+ it('converts inline code', () => {
23
23
  expect(markdownToHtml('Use `code` here')).toBe('Use <code>code</code> here')
24
24
  })
25
25
 
26
- test('converts code blocks with language', () => {
26
+ it('converts code blocks with language', () => {
27
27
  expect(markdownToHtml('```ts\nconst x = 1 < 2\n```')).toBe(
28
28
  '<pre><code class="language-ts">const x = 1 &lt; 2</code></pre>',
29
29
  )
30
30
  })
31
31
 
32
- test('converts code blocks without language', () => {
32
+ it('converts code blocks without language', () => {
33
33
  expect(markdownToHtml('```\nconst x = 1 & 2\n```')).toBe('<pre><code>const x = 1 &amp; 2</code></pre>')
34
34
  })
35
35
 
36
- test('does not process markdown inside code blocks', () => {
36
+ it('does not process markdown inside code blocks', () => {
37
37
  expect(markdownToHtml('```\n**bold** _italic_\n```')).toBe('<pre><code>**bold** _italic_</code></pre>')
38
38
  })
39
39
 
40
- test('converts links', () => {
40
+ it('converts links', () => {
41
41
  expect(markdownToHtml('[Webex](https://example.com?a=1&b=2)')).toBe(
42
42
  '<a href="https://example.com?a=1&amp;b=2">Webex</a>',
43
43
  )
44
44
  })
45
45
 
46
- test('strips unsafe javascript: URLs to plain text', () => {
46
+ it('strips unsafe javascript: URLs to plain text', () => {
47
47
  expect(markdownToHtml('[click](javascript:void)')).toBe('click')
48
48
  })
49
49
 
50
- test('strips unsafe data: URLs to plain text', () => {
50
+ it('strips unsafe data: URLs to plain text', () => {
51
51
  expect(markdownToHtml('[x](data:text/html,payload)')).toBe('x')
52
52
  })
53
53
 
54
- test('allows mailto: links', () => {
54
+ it('allows mailto: links', () => {
55
55
  expect(markdownToHtml('[email](mailto:a@b.com)')).toBe('<a href="mailto:a@b.com">email</a>')
56
56
  })
57
57
 
58
- test('escapes quotes in URLs to prevent attribute breakout', () => {
58
+ it('escapes quotes in URLs to prevent attribute breakout', () => {
59
59
  expect(markdownToHtml('[x](https://a.com?q="test")')).toBe('<a href="https://a.com?q=&quot;test&quot;">x</a>')
60
60
  })
61
61
 
62
- test('converts unordered lists', () => {
62
+ it('converts unordered lists', () => {
63
63
  expect(markdownToHtml('- one\n- two')).toBe('<ul><li>one</li><li>two</li></ul>')
64
64
  })
65
65
 
66
- test('converts ordered lists', () => {
66
+ it('converts ordered lists', () => {
67
67
  expect(markdownToHtml('1. one\n2. two')).toBe('<ol><li>one</li><li>two</li></ol>')
68
68
  })
69
69
 
70
- test('converts blockquotes', () => {
70
+ it('converts blockquotes', () => {
71
71
  expect(markdownToHtml('> one\n> two')).toBe('<blockquote>one<br/>two</blockquote>')
72
72
  })
73
73
 
74
- test('converts headings', () => {
74
+ it('converts headings', () => {
75
75
  expect(markdownToHtml('# one\n###### six')).toBe('<h1>one</h1><br/><br/><h6>six</h6>')
76
76
  })
77
77
 
78
- test('converts horizontal rules', () => {
78
+ it('converts horizontal rules', () => {
79
79
  expect(markdownToHtml('before\n---\nafter')).toBe('before<br/><br/><hr><br/><br/>after')
80
80
  })
81
81
 
82
- test('converts paragraph newlines to br', () => {
82
+ it('converts paragraph newlines to br', () => {
83
83
  expect(markdownToHtml('one\ntwo')).toBe('one<br/>two')
84
84
  })
85
85
 
86
- test('supports nested formatting', () => {
86
+ it('supports nested formatting', () => {
87
87
  expect(markdownToHtml('**bold _and italic_**')).toBe('<strong>bold <em>and italic</em></strong>')
88
88
  })
89
89
 
90
- test('escapes html special characters in text', () => {
90
+ it('escapes html special characters in text', () => {
91
91
  expect(markdownToHtml('5 < 7 & 8 > 3')).toBe('5 &lt; 7 &amp; 8 &gt; 3')
92
92
  })
93
93
 
94
- test('separates multiple paragraphs with br', () => {
94
+ it('separates multiple paragraphs with br', () => {
95
95
  expect(markdownToHtml('first\n\nsecond')).toBe('first<br/><br/>second')
96
96
  })
97
97
 
98
- test('renders mixed content', () => {
98
+ it('renders mixed content', () => {
99
99
  expect(markdownToHtml('Hello **team**\n\n- one\n- two\n\n```js\nconst x = 1\n```')).toBe(
100
100
  'Hello <strong>team</strong><br/><br/><ul><li>one</li><li>two</li></ul><br/><br/><pre><code class="language-js">const x = 1</code></pre>',
101
101
  )
102
102
  })
103
103
 
104
- test('returns empty string for empty input', () => {
104
+ it('returns empty string for empty input', () => {
105
105
  expect(markdownToHtml('')).toBe('')
106
106
  })
107
107
 
108
- test('returns plain text when there is no markdown', () => {
108
+ it('returns plain text when there is no markdown', () => {
109
109
  expect(markdownToHtml('hello world')).toBe('hello world')
110
110
  })
111
111
 
112
- test('preserves whitespace-only input', () => {
112
+ it('preserves whitespace-only input', () => {
113
113
  expect(markdownToHtml(' ')).toBe(' ')
114
114
  })
115
115
  })
116
116
 
117
117
  describe('stripMarkdown', () => {
118
- test('strips inline markdown syntax', () => {
118
+ it('strips inline markdown syntax', () => {
119
119
  expect(stripMarkdown('**bold** _italic_ `code`')).toBe('bold italic code')
120
120
  })
121
121
 
122
- test('strips links to their labels', () => {
122
+ it('strips links to their labels', () => {
123
123
  expect(stripMarkdown('[Webex](https://example.com)')).toBe('Webex')
124
124
  })
125
125
 
126
- test('strips block markdown syntax', () => {
126
+ it('strips block markdown syntax', () => {
127
127
  expect(stripMarkdown('# Title\n> quote\n- item\n1. first\n---')).toBe('Title\nquote\nitem\nfirst\n')
128
128
  })
129
129
 
130
- test('keeps code block content', () => {
130
+ it('keeps code block content', () => {
131
131
  expect(stripMarkdown('```ts\nconst x = 1\n```')).toBe('const x = 1')
132
132
  })
133
133
 
134
- test('handles nested formatting', () => {
134
+ it('handles nested formatting', () => {
135
135
  expect(stripMarkdown('**bold _and italic_**')).toBe('bold and italic')
136
136
  })
137
137
 
138
- test('returns plain text unchanged', () => {
138
+ it('returns plain text unchanged', () => {
139
139
  expect(stripMarkdown('hello world')).toBe('hello world')
140
140
  })
141
141
  })
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
2
2
  import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
3
  import { tmpdir } from 'node:os'
4
4
  import { join } from 'node:path'
@@ -49,7 +49,7 @@ describe('WebexTokenExtractor', () => {
49
49
  })
50
50
 
51
51
  describe('getBrowserProfileDirs', () => {
52
- test('returns correct paths for darwin', () => {
52
+ it('returns correct paths for darwin', () => {
53
53
  const extractor = new WebexTokenExtractor('darwin')
54
54
  const dirs = extractor.getBrowserProfileDirs()
55
55
 
@@ -60,12 +60,12 @@ describe('WebexTokenExtractor', () => {
60
60
  }
61
61
  })
62
62
 
63
- test('returns empty array for unsupported platform', () => {
63
+ it('returns empty array for unsupported platform', () => {
64
64
  const extractor = new WebexTokenExtractor('freebsd' as NodeJS.Platform)
65
65
  expect(extractor.getBrowserProfileDirs()).toEqual([])
66
66
  })
67
67
 
68
- test('discovers Default and Profile N directories', () => {
68
+ it('discovers Default and Profile N directories', () => {
69
69
  const defaultDir = createLevelDBDir(tempDir, 'Default')
70
70
  const profile1Dir = createLevelDBDir(tempDir, 'Profile 1')
71
71
  const profile2Dir = createLevelDBDir(tempDir, 'Profile 2')
@@ -78,7 +78,7 @@ describe('WebexTokenExtractor', () => {
78
78
  expect(dirs).toContain(profile2Dir)
79
79
  })
80
80
 
81
- test('skips non-profile directories', () => {
81
+ it('skips non-profile directories', () => {
82
82
  createLevelDBDir(tempDir, 'Default')
83
83
  mkdirSync(join(tempDir, 'Extensions', 'Local Storage', 'leveldb'), { recursive: true })
84
84
  mkdirSync(join(tempDir, 'Crashpad'), { recursive: true })
@@ -90,14 +90,14 @@ describe('WebexTokenExtractor', () => {
90
90
  expect(dirs[0]).toContain('Default')
91
91
  })
92
92
 
93
- test('returns empty when base dir does not exist', () => {
93
+ it('returns empty when base dir does not exist', () => {
94
94
  const extractor = new WebexTokenExtractor('darwin', undefined, join(tempDir, 'nonexistent'))
95
95
  expect(extractor.getBrowserProfileDirs()).toEqual([])
96
96
  })
97
97
  })
98
98
 
99
99
  describe('extract', () => {
100
- test('finds token from .log file', async () => {
100
+ it('finds token from .log file', async () => {
101
101
  const leveldbDir = createLevelDBDir(tempDir)
102
102
  const webexJson = makeWebexStorageJson()
103
103
  const entry = `_https://web.webex.com\x00webex-storage${webexJson}`
@@ -113,7 +113,7 @@ describe('WebexTokenExtractor', () => {
113
113
  expect(result!.deviceUrl).toBe('https://wdm-r.wbx2.com/wdm/api/v1/devices/test-device-id')
114
114
  })
115
115
 
116
- test('finds token from .ldb file', async () => {
116
+ it('finds token from .ldb file', async () => {
117
117
  const leveldbDir = createLevelDBDir(tempDir)
118
118
  const webexJson = makeWebexStorageJson()
119
119
  writeFileSync(join(leveldbDir, '000005.ldb'), `\x00\x00${webexJson}\x00\x00`)
@@ -125,12 +125,12 @@ describe('WebexTokenExtractor', () => {
125
125
  expect(result!.accessToken).toBe('ZDI3MGEyYzQtNmFlNS00NDNh_PF84_1eb65fdf-userId_orgId')
126
126
  })
127
127
 
128
- test('returns null when no browser dirs exist', async () => {
128
+ it('returns null when no browser dirs exist', async () => {
129
129
  const extractor = new WebexTokenExtractor('darwin', undefined, join(tempDir, 'nonexistent'))
130
130
  expect(await extractor.extract()).toBeNull()
131
131
  })
132
132
 
133
- test('returns null when LevelDB has no webex-storage data', async () => {
133
+ it('returns null when LevelDB has no webex-storage data', async () => {
134
134
  const leveldbDir = createLevelDBDir(tempDir)
135
135
  writeFileSync(join(leveldbDir, '000003.log'), 'some random data without webex tokens')
136
136
 
@@ -138,7 +138,7 @@ describe('WebexTokenExtractor', () => {
138
138
  expect(await extractor.extract()).toBeNull()
139
139
  })
140
140
 
141
- test('handles malformed JSON gracefully', async () => {
141
+ it('handles malformed JSON gracefully', async () => {
142
142
  const leveldbDir = createLevelDBDir(tempDir)
143
143
  writeFileSync(join(leveldbDir, '000003.log'), '{"Credentials": {"@": {"supertoken": {broken json')
144
144
 
@@ -146,7 +146,7 @@ describe('WebexTokenExtractor', () => {
146
146
  expect(await extractor.extract()).toBeNull()
147
147
  })
148
148
 
149
- test('extracts all fields from nested Credentials structure', async () => {
149
+ it('extracts all fields from nested Credentials structure', async () => {
150
150
  const expires = Date.now() + 7200000
151
151
  const leveldbDir = createLevelDBDir(tempDir)
152
152
  const webexJson = makeWebexStorageJson({
@@ -167,7 +167,7 @@ describe('WebexTokenExtractor', () => {
167
167
  expect(result!.deviceUrl).toBe('https://wdm-a.wbx2.com/wdm/api/v1/devices/abc-123')
168
168
  })
169
169
 
170
- test('extracts deviceUrl when Device field is present', async () => {
170
+ it('extracts deviceUrl when Device field is present', async () => {
171
171
  const leveldbDir = createLevelDBDir(tempDir)
172
172
  const webexJson = makeWebexStorageJson({
173
173
  deviceUrl: 'https://wdm-eu.wbx2.com/wdm/api/v1/devices/eu-device-id',
@@ -181,7 +181,7 @@ describe('WebexTokenExtractor', () => {
181
181
  expect(result!.deviceUrl).toBe('https://wdm-eu.wbx2.com/wdm/api/v1/devices/eu-device-id')
182
182
  })
183
183
 
184
- test('returns token without deviceUrl when Device field is absent', async () => {
184
+ it('returns token without deviceUrl when Device field is absent', async () => {
185
185
  const leveldbDir = createLevelDBDir(tempDir)
186
186
  const webexJson = JSON.stringify({
187
187
  Credentials: {
@@ -204,7 +204,7 @@ describe('WebexTokenExtractor', () => {
204
204
  expect(result!.deviceUrl).toBeUndefined()
205
205
  })
206
206
 
207
- test('skips profiles without leveldb directory', async () => {
207
+ it('skips profiles without leveldb directory', async () => {
208
208
  mkdirSync(join(tempDir, 'Default', 'Local Storage'), { recursive: true })
209
209
  const profile1Dir = createLevelDBDir(tempDir, 'Profile 1')
210
210
  const webexJson = makeWebexStorageJson()
@@ -216,7 +216,7 @@ describe('WebexTokenExtractor', () => {
216
216
  expect(result).not.toBeNull()
217
217
  })
218
218
 
219
- test('prefers token with latest expiry across profiles', async () => {
219
+ it('prefers token with latest expiry across profiles', async () => {
220
220
  const dir1 = createLevelDBDir(tempDir, 'Default')
221
221
  const dir2 = createLevelDBDir(tempDir, 'Profile 1')
222
222
 
@@ -238,7 +238,7 @@ describe('WebexTokenExtractor', () => {
238
238
  expect(result!.accessToken).toBe('fresh-token-longer-than-twenty-chars-xxx')
239
239
  })
240
240
 
241
- test('returns first token when all have same expiry', async () => {
241
+ it('returns first token when all have same expiry', async () => {
242
242
  const dir1 = createLevelDBDir(tempDir, 'Default')
243
243
  const dir2 = createLevelDBDir(tempDir, 'Profile 1')
244
244
 
@@ -261,7 +261,7 @@ describe('WebexTokenExtractor', () => {
261
261
  expect(result!.accessToken).toBe('first-valid-token-longer-than-twenty-chars')
262
262
  })
263
263
 
264
- test('prefers .log files over .ldb files in same directory', async () => {
264
+ it('prefers .log files over .ldb files in same directory', async () => {
265
265
  const leveldbDir = createLevelDBDir(tempDir)
266
266
 
267
267
  const logToken = makeWebexStorageJson({ accessToken: 'from-log-file-token-at-least-twenty-chars' })
@@ -276,7 +276,7 @@ describe('WebexTokenExtractor', () => {
276
276
  expect(result!.accessToken).toBe('from-log-file-token-at-least-twenty-chars')
277
277
  })
278
278
 
279
- test('rejects tokens shorter than 20 characters', async () => {
279
+ it('rejects tokens shorter than 20 characters', async () => {
280
280
  const leveldbDir = createLevelDBDir(tempDir)
281
281
  const webexJson = makeWebexStorageJson({ accessToken: 'short' })
282
282
  writeFileSync(join(leveldbDir, '000003.log'), webexJson)
@@ -285,7 +285,7 @@ describe('WebexTokenExtractor', () => {
285
285
  expect(await extractor.extract()).toBeNull()
286
286
  })
287
287
 
288
- test('handles binary framing around JSON', async () => {
288
+ it('handles binary framing around JSON', async () => {
289
289
  const leveldbDir = createLevelDBDir(tempDir)
290
290
  const webexJson = makeWebexStorageJson()
291
291
  const binaryFrame = Buffer.concat([
@@ -303,7 +303,7 @@ describe('WebexTokenExtractor', () => {
303
303
  expect(result!.accessToken).toBe('ZDI3MGEyYzQtNmFlNS00NDNh_PF84_1eb65fdf-userId_orgId')
304
304
  })
305
305
 
306
- test('handles supertoken at top level', async () => {
306
+ it('handles supertoken at top level', async () => {
307
307
  const leveldbDir = createLevelDBDir(tempDir)
308
308
  const directJson = JSON.stringify({
309
309
  supertoken: {
@@ -321,7 +321,7 @@ describe('WebexTokenExtractor', () => {
321
321
  expect(result!.accessToken).toBe('direct-supertoken-access-value-at-least-twenty')
322
322
  })
323
323
 
324
- test('handles expires_in instead of expires', async () => {
324
+ it('handles expires_in instead of expires', async () => {
325
325
  const leveldbDir = createLevelDBDir(tempDir)
326
326
  const now = Date.now()
327
327
  const webexJson = JSON.stringify({
@@ -345,7 +345,7 @@ describe('WebexTokenExtractor', () => {
345
345
  expect(result!.expiresAt).toBeLessThanOrEqual(now + 3700000)
346
346
  })
347
347
 
348
- test('calls debug log when provided', async () => {
348
+ it('calls debug log when provided', async () => {
349
349
  const logs: string[] = []
350
350
  const extractor = new WebexTokenExtractor('darwin', (msg) => logs.push(msg), join(tempDir, 'nonexistent'))
351
351
  await extractor.extract()