agent-messenger 2.10.1 → 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 +9 -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 +109 -49
  180. package/src/platforms/teams/token-extractor.ts +7 -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
@@ -187,22 +187,43 @@ export class ChromiumCookieDecryptor {
187
187
  if (this.platform !== 'win32') return null
188
188
  try {
189
189
  const b64Input = encrypted.toString('base64')
190
+ // Silence progress/information/warning streams so PowerShell doesn't emit CLIXML
191
+ // ("#< CLIXML ...") alongside our base64 payload when modules auto-load on first use.
192
+ // Wrap the payload in explicit markers so we can recover it even if stray output leaks in.
190
193
  const script = [
194
+ "$ProgressPreference='SilentlyContinue'",
195
+ "$InformationPreference='SilentlyContinue'",
196
+ "$WarningPreference='SilentlyContinue'",
191
197
  'Add-Type -AssemblyName System.Security',
192
198
  `$d=[System.Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String("${b64Input}"),$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser)`,
193
- '[Convert]::ToBase64String($d)',
199
+ "Write-Host ('<<<B64>>>'+[Convert]::ToBase64String($d)+'<<<END>>>')",
194
200
  ].join(';')
195
201
  const encodedCommand = Buffer.from(script, 'utf16le').toString('base64')
196
- const result = execSync(`powershell -NoProfile -NonInteractive -EncodedCommand ${encodedCommand}`, {
197
- encoding: 'utf8',
198
- timeout: 10000,
199
- }).trim()
200
- return Buffer.from(result, 'base64')
202
+ const rawResult = execSync(
203
+ `powershell -NoProfile -NonInteractive -OutputFormat Text -EncodedCommand ${encodedCommand}`,
204
+ { encoding: 'utf8', timeout: 10000 },
205
+ )
206
+ const b64 = ChromiumCookieDecryptor.extractDPAPIPayload(rawResult)
207
+ if (!b64) return null
208
+ return Buffer.from(b64, 'base64')
201
209
  } catch {
202
210
  return null
203
211
  }
204
212
  }
205
213
 
214
+ /**
215
+ * Extract the base64-encoded DPAPI payload from PowerShell stdout, stripping any
216
+ * CLIXML progress-stream contamination or other stray output. Returns null if
217
+ * no valid payload is found.
218
+ */
219
+ static extractDPAPIPayload(stdout: string): string | null {
220
+ const match = stdout.match(/<<<B64>>>([A-Za-z0-9+/=\r\n]*)<<<END>>>/)
221
+ if (!match) return null
222
+ const b64 = match[1].replace(/\s+/g, '')
223
+ if (!b64) return null
224
+ return b64
225
+ }
226
+
206
227
  static stripIntegrityHash(decrypted: Buffer): Buffer {
207
228
  if (decrypted.length <= 32) return decrypted
208
229
  const hasNonPrintablePrefix = decrypted.subarray(0, 32).some((b) => b < 0x20 || b > 0x7e)
@@ -1,15 +1,15 @@
1
- import { describe, expect, test } from 'bun:test'
1
+ import { describe, expect, it } from 'bun:test'
2
2
 
3
3
  import { parallelMap } from './concurrency'
4
4
 
5
5
  describe('parallelMap', () => {
6
- test('processes items in parallel', async () => {
6
+ it('processes items in parallel', async () => {
7
7
  const items = [1, 2, 3, 4, 5]
8
8
  const results = await parallelMap(items, async (n) => n * 2)
9
9
  expect(results).toEqual([2, 4, 6, 8, 10])
10
10
  })
11
11
 
12
- test('maintains order of results', async () => {
12
+ it('maintains order of results', async () => {
13
13
  const items = [100, 50, 10]
14
14
  const results = await parallelMap(
15
15
  items,
@@ -22,7 +22,7 @@ describe('parallelMap', () => {
22
22
  expect(results).toEqual([100, 50, 10])
23
23
  })
24
24
 
25
- test('respects concurrency limit', async () => {
25
+ it('respects concurrency limit', async () => {
26
26
  let concurrent = 0
27
27
  let maxConcurrent = 0
28
28
  const items = [1, 2, 3, 4, 5, 6]
@@ -41,12 +41,12 @@ describe('parallelMap', () => {
41
41
  expect(maxConcurrent).toBe(2)
42
42
  })
43
43
 
44
- test('handles empty array', async () => {
44
+ it('handles empty array', async () => {
45
45
  const results = await parallelMap([], async (n: number) => n * 2)
46
46
  expect(results).toEqual([])
47
47
  })
48
48
 
49
- test('passes index to function', async () => {
49
+ it('passes index to function', async () => {
50
50
  const items = ['a', 'b', 'c']
51
51
  const results = await parallelMap(items, async (item, index) => `${item}${index}`)
52
52
  expect(results).toEqual(['a0', 'b1', 'c2'])
@@ -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 { existsSync, mkdirSync, rmSync } from 'node:fs'
3
3
  import { tmpdir } from 'node:os'
4
4
  import { join } from 'node:path'
@@ -22,12 +22,12 @@ describe('DerivedKeyCache', () => {
22
22
  })
23
23
 
24
24
  describe('get', () => {
25
- test('returns null when no cached key exists', async () => {
25
+ it('returns null when no cached key exists', async () => {
26
26
  const result = await cache.get('slack')
27
27
  expect(result).toBeNull()
28
28
  })
29
29
 
30
- test('returns cached key when it exists', async () => {
30
+ it('returns cached key when it exists', async () => {
31
31
  // given
32
32
  const key = Buffer.from('test-key-16bytes')
33
33
  await cache.set('slack', key)
@@ -39,7 +39,7 @@ describe('DerivedKeyCache', () => {
39
39
  expect(result).toEqual(key)
40
40
  })
41
41
 
42
- test('returns different keys for different platforms', async () => {
42
+ it('returns different keys for different platforms', async () => {
43
43
  // given
44
44
  const slackKey = Buffer.from('slack-key-16byte')
45
45
  const discordKey = Buffer.from('discord-key-16by')
@@ -53,7 +53,7 @@ describe('DerivedKeyCache', () => {
53
53
  })
54
54
 
55
55
  describe('set', () => {
56
- test('creates cache directory if it does not exist', async () => {
56
+ it('creates cache directory if it does not exist', async () => {
57
57
  // given
58
58
  const nestedDir = join(testDir, 'nested', 'cache')
59
59
  const nestedCache = new DerivedKeyCache(nestedDir)
@@ -65,7 +65,7 @@ describe('DerivedKeyCache', () => {
65
65
  expect(existsSync(nestedDir)).toBe(true)
66
66
  })
67
67
 
68
- test('overwrites existing cached key', async () => {
68
+ it('overwrites existing cached key', async () => {
69
69
  // given
70
70
  const oldKey = Buffer.from('old-key-16bytes!')
71
71
  const newKey = Buffer.from('new-key-16bytes!')
@@ -80,7 +80,7 @@ describe('DerivedKeyCache', () => {
80
80
  })
81
81
 
82
82
  describe('clear', () => {
83
- test('removes cached key for platform', async () => {
83
+ it('removes cached key for platform', async () => {
84
84
  // given
85
85
  await cache.set('slack', Buffer.from('test-key'))
86
86
 
@@ -91,7 +91,7 @@ describe('DerivedKeyCache', () => {
91
91
  expect(await cache.get('slack')).toBeNull()
92
92
  })
93
93
 
94
- test('does not affect other platforms', async () => {
94
+ it('does not affect other platforms', async () => {
95
95
  // given
96
96
  const discordKey = Buffer.from('discord-key')
97
97
  await cache.set('slack', Buffer.from('slack-key'))
@@ -105,13 +105,13 @@ describe('DerivedKeyCache', () => {
105
105
  expect(await cache.get('discord')).toEqual(discordKey)
106
106
  })
107
107
 
108
- test('does not throw when key does not exist', async () => {
108
+ it('does not throw when key does not exist', async () => {
109
109
  await expect(cache.clear('slack')).resolves.toBeUndefined()
110
110
  })
111
111
  })
112
112
 
113
113
  describe('clearAll', () => {
114
- test('removes all cached keys', async () => {
114
+ it('removes all cached keys', async () => {
115
115
  // given
116
116
  await cache.set('slack', Buffer.from('slack-key'))
117
117
  await cache.set('discord', Buffer.from('discord-key'))
@@ -126,7 +126,7 @@ describe('DerivedKeyCache', () => {
126
126
  expect(await cache.get('teams')).toBeNull()
127
127
  })
128
128
 
129
- test('does not throw when cache directory does not exist', async () => {
129
+ it('does not throw when cache directory does not exist', async () => {
130
130
  // given
131
131
  const emptyCache = new DerivedKeyCache(join(testDir, 'nonexistent'))
132
132
 
@@ -1,16 +1,16 @@
1
- import { describe, test, expect } from 'bun:test'
1
+ import { describe, it, expect } from 'bun:test'
2
2
 
3
3
  import { formatTimestamp, truncate, fuzzyMatch, stripHtml } from './utils'
4
4
 
5
5
  describe('formatTimestamp', () => {
6
- test("today's date returns HH:MM", () => {
6
+ it("returns HH:MM for today's date", () => {
7
7
  const now = new Date()
8
8
  const epochSeconds = (now.getTime() / 1000).toFixed(6)
9
9
  const result = formatTimestamp(epochSeconds)
10
10
  expect(result).toMatch(/^\d{2}:\d{2}$/)
11
11
  })
12
12
 
13
- test("yesterday's date returns MM/DD HH:MM", () => {
13
+ it("returns MM/DD HH:MM for yesterday's date", () => {
14
14
  const yesterday = new Date()
15
15
  yesterday.setDate(yesterday.getDate() - 1)
16
16
  const epochSeconds = (yesterday.getTime() / 1000).toFixed(6)
@@ -18,24 +18,24 @@ describe('formatTimestamp', () => {
18
18
  expect(result).toMatch(/^\d{2}\/\d{2} \d{2}:\d{2}$/)
19
19
  })
20
20
 
21
- test('ISO 8601 string for today returns HH:MM', () => {
21
+ it('ISO 8601 string for today returns HH:MM', () => {
22
22
  const now = new Date()
23
23
  const iso = now.toISOString()
24
24
  const result = formatTimestamp(iso)
25
25
  expect(result).toMatch(/^\d{2}:\d{2}$/)
26
26
  })
27
27
 
28
- test('ISO 8601 string for past date returns MM/DD HH:MM', () => {
28
+ it('ISO 8601 string for past date returns MM/DD HH:MM', () => {
29
29
  const result = formatTimestamp('2024-03-15T10:30:00Z')
30
30
  expect(result).toMatch(/^\d{2}\/\d{2} \d{2}:\d{2}$/)
31
31
  })
32
32
 
33
- test('invalid string returns original', () => {
33
+ it('invalid string returns original', () => {
34
34
  expect(formatTimestamp('not-a-date')).toBe('not-a-date')
35
35
  expect(formatTimestamp('abc123')).toBe('abc123')
36
36
  })
37
37
 
38
- test('Slack-style epoch with microseconds', () => {
38
+ it('formats Slack-style epoch with microseconds as HH:MM', () => {
39
39
  const now = new Date()
40
40
  const slackTs = `${Math.floor(now.getTime() / 1000)}.123456`
41
41
  const result = formatTimestamp(slackTs)
@@ -44,105 +44,105 @@ describe('formatTimestamp', () => {
44
44
  })
45
45
 
46
46
  describe('truncate', () => {
47
- test('short string returned unchanged', () => {
47
+ it('returns short string unchanged', () => {
48
48
  expect(truncate('hello', 10)).toBe('hello')
49
49
  })
50
50
 
51
- test('exact length returned unchanged', () => {
51
+ it('returns string unchanged when length equals maxLen', () => {
52
52
  expect(truncate('hello', 5)).toBe('hello')
53
53
  })
54
54
 
55
- test('long string gets truncated with ellipsis', () => {
55
+ it('long string gets truncated with ellipsis', () => {
56
56
  expect(truncate('hello world', 8)).toBe('hello...')
57
57
  })
58
58
 
59
- test('maxLen of 3 truncates without ellipsis', () => {
59
+ it('truncates without ellipsis when maxLen is 3', () => {
60
60
  expect(truncate('hello', 3)).toBe('hel')
61
61
  })
62
62
 
63
- test('maxLen of 1 truncates without ellipsis', () => {
63
+ it('truncates without ellipsis when maxLen is 1', () => {
64
64
  expect(truncate('hello', 1)).toBe('h')
65
65
  })
66
66
 
67
- test('maxLen of 0 returns empty string', () => {
67
+ it('returns empty string when maxLen is 0', () => {
68
68
  expect(truncate('hello', 0)).toBe('')
69
69
  })
70
70
 
71
- test('maxLen of 4 adds ellipsis', () => {
71
+ it('adds ellipsis when maxLen is 4', () => {
72
72
  expect(truncate('hello', 4)).toBe('h...')
73
73
  })
74
74
  })
75
75
 
76
76
  describe('fuzzyMatch', () => {
77
- test('exact match returns true', () => {
77
+ it('exact match returns true', () => {
78
78
  expect(fuzzyMatch('general', 'general')).toBe(true)
79
79
  })
80
80
 
81
- test('partial match in order returns true', () => {
81
+ it('partial match in order returns true', () => {
82
82
  expect(fuzzyMatch('gnrl', 'general')).toBe(true)
83
83
  })
84
84
 
85
- test('case insensitive match', () => {
85
+ it('matches case-insensitively', () => {
86
86
  expect(fuzzyMatch('GNRL', 'general')).toBe(true)
87
87
  expect(fuzzyMatch('gnrl', 'GENERAL')).toBe(true)
88
88
  })
89
89
 
90
- test('empty query returns true', () => {
90
+ it('empty query returns true', () => {
91
91
  expect(fuzzyMatch('', 'anything')).toBe(true)
92
92
  expect(fuzzyMatch('', '')).toBe(true)
93
93
  })
94
94
 
95
- test('no match returns false', () => {
95
+ it('no match returns false', () => {
96
96
  expect(fuzzyMatch('xyz', 'general')).toBe(false)
97
97
  })
98
98
 
99
- test('characters out of order returns false', () => {
99
+ it('characters out of order returns false', () => {
100
100
  expect(fuzzyMatch('lrng', 'general')).toBe(false)
101
101
  })
102
102
 
103
- test('query longer than text returns false', () => {
103
+ it('query longer than text returns false', () => {
104
104
  expect(fuzzyMatch('generalgeneral', 'general')).toBe(false)
105
105
  })
106
106
  })
107
107
 
108
108
  describe('stripHtml', () => {
109
- test('removes simple tags', () => {
109
+ it('removes simple tags', () => {
110
110
  expect(stripHtml('<p>hello</p>')).toBe('hello')
111
111
  })
112
112
 
113
- test('removes nested tags', () => {
113
+ it('removes nested tags', () => {
114
114
  expect(stripHtml('<div><p><strong>hello</strong></p></div>')).toBe('hello')
115
115
  })
116
116
 
117
- test('decodes &amp;', () => {
117
+ it('decodes &amp;', () => {
118
118
  expect(stripHtml('a &amp; b')).toBe('a & b')
119
119
  })
120
120
 
121
- test('decodes &lt; and &gt;', () => {
121
+ it('decodes &lt; and &gt;', () => {
122
122
  expect(stripHtml('&lt;tag&gt;')).toBe('<tag>')
123
123
  })
124
124
 
125
- test('decodes &quot;', () => {
125
+ it('decodes &quot;', () => {
126
126
  expect(stripHtml('say &quot;hello&quot;')).toBe('say "hello"')
127
127
  })
128
128
 
129
- test('decodes &#39;', () => {
129
+ it('decodes &#39;', () => {
130
130
  expect(stripHtml('it&#39;s')).toBe("it's")
131
131
  })
132
132
 
133
- test('collapses multiple whitespace', () => {
133
+ it('collapses multiple whitespace', () => {
134
134
  expect(stripHtml('hello world')).toBe('hello world')
135
135
  })
136
136
 
137
- test('trims leading and trailing whitespace', () => {
137
+ it('trims leading and trailing whitespace', () => {
138
138
  expect(stripHtml(' hello ')).toBe('hello')
139
139
  })
140
140
 
141
- test('handles multiple entities and tags together', () => {
141
+ it('handles multiple entities and tags together', () => {
142
142
  expect(stripHtml('<p>Hello &amp; <strong>World</strong></p>')).toBe('Hello & World')
143
143
  })
144
144
 
145
- test('whitespace from tag removal is collapsed', () => {
145
+ it('collapses whitespace left by tag removal', () => {
146
146
  expect(stripHtml('<p>hello</p> <p>world</p>')).toBe('hello world')
147
147
  })
148
148
  })