agent-messenger 1.0.0 → 1.2.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 (512) hide show
  1. package/.claude/commands/release.md +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.github/workflows/ci.yml +1 -1
  4. package/.github/workflows/e2e.yml.disabled +69 -0
  5. package/CONTRIBUTING.md +2 -2
  6. package/README.md +18 -15
  7. package/biome.json +34 -2
  8. package/bun.lock +63 -0
  9. package/dist/package.json +8 -4
  10. package/dist/src/cli.d.ts.map +1 -1
  11. package/dist/src/cli.js +4 -1
  12. package/dist/src/cli.js.map +1 -1
  13. package/dist/src/platforms/discord/cli.js +4 -4
  14. package/dist/src/platforms/discord/cli.js.map +1 -1
  15. package/dist/src/platforms/discord/client.d.ts +26 -5
  16. package/dist/src/platforms/discord/client.d.ts.map +1 -1
  17. package/dist/src/platforms/discord/client.js +115 -17
  18. package/dist/src/platforms/discord/client.js.map +1 -1
  19. package/dist/src/platforms/discord/commands/auth.js +16 -16
  20. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  21. package/dist/src/platforms/discord/commands/channel.js +4 -4
  22. package/dist/src/platforms/discord/commands/channel.js.map +1 -1
  23. package/dist/src/platforms/discord/commands/dm.d.ts +9 -0
  24. package/dist/src/platforms/discord/commands/dm.d.ts.map +1 -0
  25. package/dist/src/platforms/discord/commands/dm.js +68 -0
  26. package/dist/src/platforms/discord/commands/dm.js.map +1 -0
  27. package/dist/src/platforms/discord/commands/friend.d.ts +3 -0
  28. package/dist/src/platforms/discord/commands/friend.d.ts.map +1 -0
  29. package/dist/src/platforms/discord/commands/friend.js +39 -0
  30. package/dist/src/platforms/discord/commands/friend.js.map +1 -0
  31. package/dist/src/platforms/discord/commands/index.d.ts +1 -1
  32. package/dist/src/platforms/discord/commands/index.d.ts.map +1 -1
  33. package/dist/src/platforms/discord/commands/index.js +1 -1
  34. package/dist/src/platforms/discord/commands/index.js.map +1 -1
  35. package/dist/src/platforms/discord/commands/member.d.ts +3 -0
  36. package/dist/src/platforms/discord/commands/member.d.ts.map +1 -0
  37. package/dist/src/platforms/discord/commands/member.js +47 -0
  38. package/dist/src/platforms/discord/commands/member.js.map +1 -0
  39. package/dist/src/platforms/discord/commands/mention.d.ts +8 -0
  40. package/dist/src/platforms/discord/commands/mention.d.ts.map +1 -0
  41. package/dist/src/platforms/discord/commands/mention.js +47 -0
  42. package/dist/src/platforms/discord/commands/mention.js.map +1 -0
  43. package/dist/src/platforms/discord/commands/message.d.ts +13 -0
  44. package/dist/src/platforms/discord/commands/message.d.ts.map +1 -1
  45. package/dist/src/platforms/discord/commands/message.js +95 -1
  46. package/dist/src/platforms/discord/commands/message.js.map +1 -1
  47. package/dist/src/platforms/discord/commands/note.d.ts +3 -0
  48. package/dist/src/platforms/discord/commands/note.d.ts.map +1 -0
  49. package/dist/src/platforms/discord/commands/note.js +56 -0
  50. package/dist/src/platforms/discord/commands/note.js.map +1 -0
  51. package/dist/src/platforms/discord/commands/profile.d.ts +3 -0
  52. package/dist/src/platforms/discord/commands/profile.d.ts.map +1 -0
  53. package/dist/src/platforms/discord/commands/profile.js +47 -0
  54. package/dist/src/platforms/discord/commands/profile.js.map +1 -0
  55. package/dist/src/platforms/discord/commands/server.d.ts +15 -0
  56. package/dist/src/platforms/discord/commands/server.d.ts.map +1 -0
  57. package/dist/src/platforms/discord/commands/server.js +102 -0
  58. package/dist/src/platforms/discord/commands/server.js.map +1 -0
  59. package/dist/src/platforms/discord/commands/snapshot.js +10 -10
  60. package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
  61. package/dist/src/platforms/discord/commands/thread.d.ts +10 -0
  62. package/dist/src/platforms/discord/commands/thread.d.ts.map +1 -0
  63. package/dist/src/platforms/discord/commands/thread.js +67 -0
  64. package/dist/src/platforms/discord/commands/thread.js.map +1 -0
  65. package/dist/src/platforms/discord/commands/user.d.ts.map +1 -1
  66. package/dist/src/platforms/discord/commands/user.js +14 -5
  67. package/dist/src/platforms/discord/commands/user.js.map +1 -1
  68. package/dist/src/platforms/discord/credential-manager.d.ts +13 -13
  69. package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -1
  70. package/dist/src/platforms/discord/credential-manager.js +28 -22
  71. package/dist/src/platforms/discord/credential-manager.js.map +1 -1
  72. package/dist/src/platforms/discord/super-properties.d.ts +4 -0
  73. package/dist/src/platforms/discord/super-properties.d.ts.map +1 -0
  74. package/dist/src/platforms/discord/super-properties.js +50 -0
  75. package/dist/src/platforms/discord/super-properties.js.map +1 -0
  76. package/dist/src/platforms/discord/token-extractor.d.ts +6 -1
  77. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  78. package/dist/src/platforms/discord/token-extractor.js +27 -2
  79. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  80. package/dist/src/platforms/discord/types.d.ts +389 -22
  81. package/dist/src/platforms/discord/types.d.ts.map +1 -1
  82. package/dist/src/platforms/discord/types.js +46 -4
  83. package/dist/src/platforms/discord/types.js.map +1 -1
  84. package/dist/src/platforms/slack/cli.d.ts.map +1 -1
  85. package/dist/src/platforms/slack/cli.js +7 -2
  86. package/dist/src/platforms/slack/cli.js.map +1 -1
  87. package/dist/src/platforms/slack/client.d.ts +19 -1
  88. package/dist/src/platforms/slack/client.d.ts.map +1 -1
  89. package/dist/src/platforms/slack/client.js +134 -0
  90. package/dist/src/platforms/slack/client.js.map +1 -1
  91. package/dist/src/platforms/slack/commands/activity.d.ts +3 -0
  92. package/dist/src/platforms/slack/commands/activity.d.ts.map +1 -0
  93. package/dist/src/platforms/slack/commands/activity.js +40 -0
  94. package/dist/src/platforms/slack/commands/activity.js.map +1 -0
  95. package/dist/src/platforms/slack/commands/drafts.d.ts +3 -0
  96. package/dist/src/platforms/slack/commands/drafts.d.ts.map +1 -0
  97. package/dist/src/platforms/slack/commands/drafts.js +45 -0
  98. package/dist/src/platforms/slack/commands/drafts.js.map +1 -0
  99. package/dist/src/platforms/slack/commands/index.d.ts +5 -0
  100. package/dist/src/platforms/slack/commands/index.d.ts.map +1 -1
  101. package/dist/src/platforms/slack/commands/index.js +5 -0
  102. package/dist/src/platforms/slack/commands/index.js.map +1 -1
  103. package/dist/src/platforms/slack/commands/saved.d.ts +3 -0
  104. package/dist/src/platforms/slack/commands/saved.d.ts.map +1 -0
  105. package/dist/src/platforms/slack/commands/saved.js +54 -0
  106. package/dist/src/platforms/slack/commands/saved.js.map +1 -0
  107. package/dist/src/platforms/slack/commands/sections.d.ts +3 -0
  108. package/dist/src/platforms/slack/commands/sections.d.ts.map +1 -0
  109. package/dist/src/platforms/slack/commands/sections.js +37 -0
  110. package/dist/src/platforms/slack/commands/sections.js.map +1 -0
  111. package/dist/src/platforms/slack/commands/unread.d.ts +12 -0
  112. package/dist/src/platforms/slack/commands/unread.d.ts.map +1 -0
  113. package/dist/src/platforms/slack/commands/unread.js +89 -0
  114. package/dist/src/platforms/slack/commands/unread.js.map +1 -0
  115. package/dist/src/platforms/slack/credential-manager.d.ts.map +1 -1
  116. package/dist/src/platforms/slack/credential-manager.js +20 -6
  117. package/dist/src/platforms/slack/credential-manager.js.map +1 -1
  118. package/dist/src/platforms/slack/token-extractor.d.ts +8 -1
  119. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  120. package/dist/src/platforms/slack/token-extractor.js +83 -11
  121. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  122. package/dist/src/platforms/slack/types.d.ts +52 -0
  123. package/dist/src/platforms/slack/types.d.ts.map +1 -1
  124. package/dist/src/platforms/slack/types.js.map +1 -1
  125. package/dist/src/platforms/teams/cli.d.ts.map +1 -0
  126. package/dist/{cli.js → src/platforms/teams/cli.js} +11 -10
  127. package/dist/src/platforms/teams/cli.js.map +1 -0
  128. package/dist/src/platforms/teams/client.d.ts +32 -0
  129. package/dist/src/platforms/teams/client.d.ts.map +1 -0
  130. package/dist/src/platforms/teams/client.js +202 -0
  131. package/dist/src/platforms/teams/client.js.map +1 -0
  132. package/dist/src/platforms/teams/commands/auth.d.ts +14 -0
  133. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -0
  134. package/dist/src/platforms/teams/commands/auth.js +176 -0
  135. package/dist/src/platforms/teams/commands/auth.js.map +1 -0
  136. package/dist/src/platforms/teams/commands/channel.d.ts +13 -0
  137. package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -0
  138. package/dist/src/platforms/teams/commands/channel.js +97 -0
  139. package/dist/src/platforms/teams/commands/channel.js.map +1 -0
  140. package/dist/src/platforms/teams/commands/file.d.ts +12 -0
  141. package/dist/src/platforms/teams/commands/file.d.ts.map +1 -0
  142. package/dist/src/platforms/teams/commands/file.js +104 -0
  143. package/dist/src/platforms/teams/commands/file.js.map +1 -0
  144. package/dist/{commands → src/platforms/teams/commands}/index.d.ts +5 -2
  145. package/dist/src/platforms/teams/commands/index.d.ts.map +1 -0
  146. package/dist/{commands → src/platforms/teams/commands}/index.js +5 -2
  147. package/dist/src/platforms/teams/commands/index.js.map +1 -0
  148. package/dist/src/platforms/teams/commands/message.d.ts +17 -0
  149. package/dist/src/platforms/teams/commands/message.d.ts.map +1 -0
  150. package/dist/src/platforms/teams/commands/message.js +133 -0
  151. package/dist/src/platforms/teams/commands/message.js.map +1 -0
  152. package/dist/src/platforms/teams/commands/reaction.d.ts +9 -0
  153. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -0
  154. package/dist/src/platforms/teams/commands/reaction.js +68 -0
  155. package/dist/src/platforms/teams/commands/reaction.js.map +1 -0
  156. package/dist/src/platforms/teams/commands/snapshot.d.ts +10 -0
  157. package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -0
  158. package/dist/src/platforms/teams/commands/snapshot.js +85 -0
  159. package/dist/src/platforms/teams/commands/snapshot.js.map +1 -0
  160. package/dist/src/platforms/teams/commands/team.d.ts +18 -0
  161. package/dist/src/platforms/teams/commands/team.d.ts.map +1 -0
  162. package/dist/src/platforms/teams/commands/team.js +130 -0
  163. package/dist/src/platforms/teams/commands/team.js.map +1 -0
  164. package/dist/src/platforms/teams/commands/user.d.ts.map +1 -0
  165. package/dist/src/platforms/teams/commands/user.js +88 -0
  166. package/dist/src/platforms/teams/commands/user.js.map +1 -0
  167. package/dist/src/platforms/teams/credential-manager.d.ts +18 -0
  168. package/dist/src/platforms/teams/credential-manager.d.ts.map +1 -0
  169. package/dist/src/platforms/teams/credential-manager.js +81 -0
  170. package/dist/src/platforms/teams/credential-manager.js.map +1 -0
  171. package/dist/src/platforms/teams/index.d.ts +4 -0
  172. package/dist/src/platforms/teams/index.d.ts.map +1 -0
  173. package/dist/src/platforms/teams/index.js +6 -0
  174. package/dist/src/platforms/teams/index.js.map +1 -0
  175. package/dist/src/platforms/teams/token-extractor.d.ts +41 -0
  176. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -0
  177. package/dist/src/platforms/teams/token-extractor.js +360 -0
  178. package/dist/src/platforms/teams/token-extractor.js.map +1 -0
  179. package/dist/src/platforms/teams/types.d.ts +209 -0
  180. package/dist/src/platforms/teams/types.d.ts.map +1 -0
  181. package/dist/src/platforms/teams/types.js +65 -0
  182. package/dist/src/platforms/teams/types.js.map +1 -0
  183. package/dist/src/shared/utils/derived-key-cache.d.ts +20 -0
  184. package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -0
  185. package/dist/src/shared/utils/derived-key-cache.js +52 -0
  186. package/dist/src/shared/utils/derived-key-cache.js.map +1 -0
  187. package/docs/README.md +113 -0
  188. package/docs/biome.json +8 -0
  189. package/docs/bun.lock +1426 -0
  190. package/docs/content/docs/agent-skills.mdx +98 -0
  191. package/docs/content/docs/index.mdx +124 -0
  192. package/docs/{discord.md → content/docs/integrations/discord.mdx} +46 -21
  193. package/docs/content/docs/integrations/meta.json +5 -0
  194. package/docs/{slack.md → content/docs/integrations/slack.mdx} +5 -4
  195. package/docs/content/docs/integrations/teams.mdx +322 -0
  196. package/docs/content/docs/meta.json +8 -0
  197. package/docs/content/docs/quick-start.mdx +103 -0
  198. package/docs/eslint.config.mjs +30 -0
  199. package/docs/next.config.ts +10 -0
  200. package/docs/package.json +42 -0
  201. package/docs/postcss.config.mjs +7 -0
  202. package/docs/public/file.svg +1 -0
  203. package/docs/public/globe.svg +1 -0
  204. package/docs/public/next.svg +1 -0
  205. package/docs/public/vercel.svg +1 -0
  206. package/docs/public/window.svg +1 -0
  207. package/docs/source.config.ts +11 -0
  208. package/docs/src/app/api/search/route.ts +4 -0
  209. package/docs/src/app/docs/[[...slug]]/page.tsx +53 -0
  210. package/docs/src/app/docs/layout.tsx +21 -0
  211. package/docs/src/app/globals.css +10 -0
  212. package/docs/src/app/icon.png +0 -0
  213. package/docs/src/app/layout.config.tsx +7 -0
  214. package/docs/src/app/layout.tsx +35 -0
  215. package/docs/src/app/page.tsx +489 -0
  216. package/docs/src/lib/source.ts +15 -0
  217. package/docs/src/mdx-components.tsx +18 -0
  218. package/docs/tsconfig.json +36 -0
  219. package/e2e/README.md +256 -0
  220. package/e2e/config.ts +51 -0
  221. package/e2e/discord.e2e.test.ts +252 -0
  222. package/e2e/helpers.ts +107 -0
  223. package/e2e/slack.e2e.test.ts +309 -0
  224. package/package.json +8 -4
  225. package/scripts/postbuild.ts +15 -0
  226. package/skills/agent-discord/SKILL.md +96 -30
  227. package/skills/agent-discord/references/authentication.md +27 -27
  228. package/skills/agent-discord/references/common-patterns.md +15 -15
  229. package/skills/agent-discord/templates/post-message.sh +6 -6
  230. package/skills/agent-discord/templates/{guild-summary.sh → server-summary.sh} +20 -20
  231. package/skills/agent-slack/SKILL.md +53 -0
  232. package/skills/agent-teams/SKILL.md +292 -0
  233. package/skills/agent-teams/references/authentication.md +375 -0
  234. package/skills/agent-teams/references/common-patterns.md +596 -0
  235. package/skills/agent-teams/templates/monitor-channel.sh +239 -0
  236. package/skills/agent-teams/templates/post-message.sh +224 -0
  237. package/skills/agent-teams/templates/team-summary.sh +210 -0
  238. package/src/cli.ts +4 -0
  239. package/src/platforms/discord/cli.ts +3 -3
  240. package/src/platforms/discord/client.test.ts +15 -15
  241. package/src/platforms/discord/client.ts +163 -17
  242. package/src/platforms/discord/commands/auth.test.ts +53 -37
  243. package/src/platforms/discord/commands/auth.ts +16 -16
  244. package/src/platforms/discord/commands/channel.test.ts +58 -46
  245. package/src/platforms/discord/commands/channel.ts +4 -4
  246. package/src/platforms/discord/commands/dm.test.ts +146 -0
  247. package/src/platforms/discord/commands/dm.ts +85 -0
  248. package/src/platforms/discord/commands/file.test.ts +40 -53
  249. package/src/platforms/discord/commands/friend.test.ts +134 -0
  250. package/src/platforms/discord/commands/friend.ts +45 -0
  251. package/src/platforms/discord/commands/index.ts +1 -1
  252. package/src/platforms/discord/commands/member.test.ts +98 -0
  253. package/src/platforms/discord/commands/member.ts +59 -0
  254. package/src/platforms/discord/commands/mention.test.ts +129 -0
  255. package/src/platforms/discord/commands/mention.ts +59 -0
  256. package/src/platforms/discord/commands/message.test.ts +139 -44
  257. package/src/platforms/discord/commands/message.ts +134 -1
  258. package/src/platforms/discord/commands/note.test.ts +84 -0
  259. package/src/platforms/discord/commands/note.ts +73 -0
  260. package/src/platforms/discord/commands/profile.test.ts +107 -0
  261. package/src/platforms/discord/commands/profile.ts +55 -0
  262. package/src/platforms/discord/commands/reaction.test.ts +54 -42
  263. package/src/platforms/discord/commands/server.test.ts +137 -0
  264. package/src/platforms/discord/commands/{guild.ts → server.ts} +31 -31
  265. package/src/platforms/discord/commands/snapshot.test.ts +1 -1
  266. package/src/platforms/discord/commands/snapshot.ts +10 -10
  267. package/src/platforms/discord/commands/thread.test.ts +121 -0
  268. package/src/platforms/discord/commands/thread.ts +92 -0
  269. package/src/platforms/discord/commands/user.test.ts +8 -8
  270. package/src/platforms/discord/commands/user.ts +16 -5
  271. package/src/platforms/discord/credential-manager.test.ts +137 -136
  272. package/src/platforms/discord/credential-manager.ts +35 -26
  273. package/src/platforms/discord/super-properties.ts +55 -0
  274. package/src/platforms/discord/token-extractor.test.ts +133 -383
  275. package/src/platforms/discord/token-extractor.ts +37 -3
  276. package/src/platforms/discord/types.test.ts +8 -8
  277. package/src/platforms/discord/types.ts +144 -8
  278. package/{tests → src/platforms/slack}/cli.test.ts +3 -3
  279. package/src/platforms/slack/cli.ts +10 -0
  280. package/{tests/slack-client.test.ts → src/platforms/slack/client.test.ts} +1 -1
  281. package/src/platforms/slack/client.ts +172 -1
  282. package/src/platforms/slack/commands/activity.test.ts +147 -0
  283. package/src/platforms/slack/commands/activity.ts +65 -0
  284. package/{tests → src/platforms/slack}/commands/auth.test.ts +25 -13
  285. package/{tests → src/platforms/slack}/commands/channel.test.ts +2 -2
  286. package/src/platforms/slack/commands/drafts.test.ts +136 -0
  287. package/src/platforms/slack/commands/drafts.ts +62 -0
  288. package/{tests → src/platforms/slack}/commands/file.test.ts +2 -2
  289. package/src/platforms/slack/commands/index.ts +5 -0
  290. package/{tests → src/platforms/slack}/commands/message.test.ts +2 -2
  291. package/{tests → src/platforms/slack}/commands/reaction.test.ts +1 -1
  292. package/src/platforms/slack/commands/saved.test.ts +140 -0
  293. package/src/platforms/slack/commands/saved.ts +71 -0
  294. package/src/platforms/slack/commands/sections.test.ts +80 -0
  295. package/src/platforms/slack/commands/sections.ts +50 -0
  296. package/{tests → src/platforms/slack}/commands/snapshot.test.ts +117 -105
  297. package/src/platforms/slack/commands/unread.test.ts +139 -0
  298. package/src/platforms/slack/commands/unread.ts +129 -0
  299. package/{tests → src/platforms/slack}/commands/user.test.ts +3 -3
  300. package/{tests → src/platforms/slack}/commands/workspace.test.ts +44 -95
  301. package/{tests → src/platforms/slack}/credential-manager.test.ts +2 -2
  302. package/src/platforms/slack/credential-manager.ts +22 -7
  303. package/src/platforms/slack/token-extractor-node-test.ts +40 -0
  304. package/src/platforms/slack/token-extractor-node.test.ts +10 -0
  305. package/src/platforms/slack/token-extractor.ts +93 -12
  306. package/{tests → src/platforms/slack}/types.test.ts +1 -1
  307. package/src/platforms/slack/types.ts +58 -0
  308. package/src/platforms/teams/cli.ts +36 -0
  309. package/src/platforms/teams/client.test.ts +500 -0
  310. package/src/platforms/teams/client.ts +365 -0
  311. package/src/platforms/teams/commands/auth.test.ts +99 -0
  312. package/src/platforms/teams/commands/auth.ts +232 -0
  313. package/src/platforms/teams/commands/channel.test.ts +147 -0
  314. package/src/platforms/teams/commands/channel.ts +129 -0
  315. package/src/platforms/teams/commands/file.test.ts +88 -0
  316. package/src/platforms/teams/commands/file.ts +144 -0
  317. package/src/platforms/teams/commands/index.ts +12 -0
  318. package/src/platforms/teams/commands/message.test.ts +110 -0
  319. package/src/platforms/teams/commands/message.ts +188 -0
  320. package/src/platforms/teams/commands/reaction.test.ts +87 -0
  321. package/src/platforms/teams/commands/reaction.ts +104 -0
  322. package/src/platforms/teams/commands/snapshot.test.ts +35 -0
  323. package/src/platforms/teams/commands/snapshot.ts +115 -0
  324. package/src/platforms/teams/commands/team.test.ts +157 -0
  325. package/src/platforms/teams/commands/team.ts +164 -0
  326. package/src/platforms/teams/commands/user.test.ts +83 -0
  327. package/src/platforms/teams/commands/user.ts +112 -0
  328. package/src/platforms/teams/credential-manager.test.ts +178 -0
  329. package/src/platforms/teams/credential-manager.ts +92 -0
  330. package/src/platforms/teams/index.ts +5 -0
  331. package/src/platforms/teams/token-extractor.test.ts +429 -0
  332. package/src/platforms/teams/token-extractor.ts +490 -0
  333. package/src/platforms/teams/types.test.ts +226 -0
  334. package/src/platforms/teams/types.ts +140 -0
  335. package/src/shared/utils/derived-key-cache.test.ts +136 -0
  336. package/src/shared/utils/derived-key-cache.ts +63 -0
  337. package/tsconfig.json +1 -1
  338. package/dist/cli.d.ts.map +0 -1
  339. package/dist/cli.js.map +0 -1
  340. package/dist/commands/auth.d.ts +0 -3
  341. package/dist/commands/auth.d.ts.map +0 -1
  342. package/dist/commands/auth.js +0 -140
  343. package/dist/commands/auth.js.map +0 -1
  344. package/dist/commands/channel.d.ts +0 -3
  345. package/dist/commands/channel.d.ts.map +0 -1
  346. package/dist/commands/channel.js +0 -118
  347. package/dist/commands/channel.js.map +0 -1
  348. package/dist/commands/file.d.ts +0 -3
  349. package/dist/commands/file.d.ts.map +0 -1
  350. package/dist/commands/file.js +0 -113
  351. package/dist/commands/file.js.map +0 -1
  352. package/dist/commands/index.d.ts.map +0 -1
  353. package/dist/commands/index.js.map +0 -1
  354. package/dist/commands/message.d.ts +0 -3
  355. package/dist/commands/message.d.ts.map +0 -1
  356. package/dist/commands/message.js +0 -214
  357. package/dist/commands/message.js.map +0 -1
  358. package/dist/commands/reaction.d.ts +0 -3
  359. package/dist/commands/reaction.d.ts.map +0 -1
  360. package/dist/commands/reaction.js +0 -100
  361. package/dist/commands/reaction.js.map +0 -1
  362. package/dist/commands/snapshot.d.ts +0 -3
  363. package/dist/commands/snapshot.d.ts.map +0 -1
  364. package/dist/commands/snapshot.js +0 -88
  365. package/dist/commands/snapshot.js.map +0 -1
  366. package/dist/commands/user.d.ts.map +0 -1
  367. package/dist/commands/user.js +0 -96
  368. package/dist/commands/user.js.map +0 -1
  369. package/dist/commands/workspace.d.ts +0 -3
  370. package/dist/commands/workspace.d.ts.map +0 -1
  371. package/dist/commands/workspace.js +0 -89
  372. package/dist/commands/workspace.js.map +0 -1
  373. package/dist/lib/credential-manager.d.ts +0 -13
  374. package/dist/lib/credential-manager.d.ts.map +0 -1
  375. package/dist/lib/credential-manager.js +0 -58
  376. package/dist/lib/credential-manager.js.map +0 -1
  377. package/dist/lib/index.d.ts +0 -3
  378. package/dist/lib/index.d.ts.map +0 -1
  379. package/dist/lib/index.js +0 -3
  380. package/dist/lib/index.js.map +0 -1
  381. package/dist/lib/ref-manager.d.ts +0 -26
  382. package/dist/lib/ref-manager.d.ts.map +0 -1
  383. package/dist/lib/ref-manager.js +0 -92
  384. package/dist/lib/ref-manager.js.map +0 -1
  385. package/dist/lib/slack-client.d.ts +0 -37
  386. package/dist/lib/slack-client.d.ts.map +0 -1
  387. package/dist/lib/slack-client.js +0 -379
  388. package/dist/lib/slack-client.js.map +0 -1
  389. package/dist/lib/token-extractor.d.ts +0 -28
  390. package/dist/lib/token-extractor.d.ts.map +0 -1
  391. package/dist/lib/token-extractor.js +0 -401
  392. package/dist/lib/token-extractor.js.map +0 -1
  393. package/dist/src/platforms/discord/client.test.d.ts +0 -2
  394. package/dist/src/platforms/discord/client.test.d.ts.map +0 -1
  395. package/dist/src/platforms/discord/client.test.js +0 -367
  396. package/dist/src/platforms/discord/client.test.js.map +0 -1
  397. package/dist/src/platforms/discord/commands/auth.test.d.ts +0 -2
  398. package/dist/src/platforms/discord/commands/auth.test.d.ts.map +0 -1
  399. package/dist/src/platforms/discord/commands/auth.test.js +0 -65
  400. package/dist/src/platforms/discord/commands/auth.test.js.map +0 -1
  401. package/dist/src/platforms/discord/commands/channel.test.d.ts +0 -2
  402. package/dist/src/platforms/discord/commands/channel.test.d.ts.map +0 -1
  403. package/dist/src/platforms/discord/commands/channel.test.js +0 -136
  404. package/dist/src/platforms/discord/commands/channel.test.js.map +0 -1
  405. package/dist/src/platforms/discord/commands/file.test.d.ts +0 -2
  406. package/dist/src/platforms/discord/commands/file.test.d.ts.map +0 -1
  407. package/dist/src/platforms/discord/commands/file.test.js +0 -83
  408. package/dist/src/platforms/discord/commands/file.test.js.map +0 -1
  409. package/dist/src/platforms/discord/commands/guild.test.d.ts +0 -2
  410. package/dist/src/platforms/discord/commands/guild.test.d.ts.map +0 -1
  411. package/dist/src/platforms/discord/commands/guild.test.js +0 -100
  412. package/dist/src/platforms/discord/commands/guild.test.js.map +0 -1
  413. package/dist/src/platforms/discord/commands/message.test.d.ts +0 -2
  414. package/dist/src/platforms/discord/commands/message.test.d.ts.map +0 -1
  415. package/dist/src/platforms/discord/commands/message.test.js +0 -91
  416. package/dist/src/platforms/discord/commands/message.test.js.map +0 -1
  417. package/dist/src/platforms/discord/commands/reaction.test.d.ts +0 -2
  418. package/dist/src/platforms/discord/commands/reaction.test.d.ts.map +0 -1
  419. package/dist/src/platforms/discord/commands/reaction.test.js +0 -115
  420. package/dist/src/platforms/discord/commands/reaction.test.js.map +0 -1
  421. package/dist/src/platforms/discord/commands/snapshot.test.d.ts +0 -2
  422. package/dist/src/platforms/discord/commands/snapshot.test.d.ts.map +0 -1
  423. package/dist/src/platforms/discord/commands/snapshot.test.js +0 -25
  424. package/dist/src/platforms/discord/commands/snapshot.test.js.map +0 -1
  425. package/dist/src/platforms/discord/commands/user.test.d.ts +0 -2
  426. package/dist/src/platforms/discord/commands/user.test.d.ts.map +0 -1
  427. package/dist/src/platforms/discord/commands/user.test.js +0 -103
  428. package/dist/src/platforms/discord/commands/user.test.js.map +0 -1
  429. package/dist/src/platforms/discord/credential-manager.test.d.ts +0 -2
  430. package/dist/src/platforms/discord/credential-manager.test.d.ts.map +0 -1
  431. package/dist/src/platforms/discord/credential-manager.test.js +0 -136
  432. package/dist/src/platforms/discord/credential-manager.test.js.map +0 -1
  433. package/dist/src/platforms/discord/token-extractor.test.d.ts +0 -2
  434. package/dist/src/platforms/discord/token-extractor.test.d.ts.map +0 -1
  435. package/dist/src/platforms/discord/token-extractor.test.js +0 -789
  436. package/dist/src/platforms/discord/token-extractor.test.js.map +0 -1
  437. package/dist/src/platforms/discord/types.test.d.ts +0 -2
  438. package/dist/src/platforms/discord/types.test.d.ts.map +0 -1
  439. package/dist/src/platforms/discord/types.test.js +0 -211
  440. package/dist/src/platforms/discord/types.test.js.map +0 -1
  441. package/dist/src/shared/utils/concurrency.test.d.ts +0 -2
  442. package/dist/src/shared/utils/concurrency.test.d.ts.map +0 -1
  443. package/dist/src/shared/utils/concurrency.test.js +0 -39
  444. package/dist/src/shared/utils/concurrency.test.js.map +0 -1
  445. package/dist/tests/cli.test.d.ts +0 -2
  446. package/dist/tests/cli.test.d.ts.map +0 -1
  447. package/dist/tests/cli.test.js +0 -83
  448. package/dist/tests/cli.test.js.map +0 -1
  449. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/CURRENT +0 -1
  450. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOCK +0 -0
  451. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG +0 -3
  452. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG.old +0 -1
  453. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/MANIFEST-000004 +0 -0
  454. package/dist/tests/commands/auth.test.d.ts +0 -2
  455. package/dist/tests/commands/auth.test.d.ts.map +0 -1
  456. package/dist/tests/commands/auth.test.js +0 -304
  457. package/dist/tests/commands/auth.test.js.map +0 -1
  458. package/dist/tests/commands/channel.test.d.ts +0 -2
  459. package/dist/tests/commands/channel.test.d.ts.map +0 -1
  460. package/dist/tests/commands/channel.test.js +0 -166
  461. package/dist/tests/commands/channel.test.js.map +0 -1
  462. package/dist/tests/commands/file.test.d.ts +0 -2
  463. package/dist/tests/commands/file.test.d.ts.map +0 -1
  464. package/dist/tests/commands/file.test.js +0 -175
  465. package/dist/tests/commands/file.test.js.map +0 -1
  466. package/dist/tests/commands/message.test.d.ts +0 -2
  467. package/dist/tests/commands/message.test.d.ts.map +0 -1
  468. package/dist/tests/commands/message.test.js +0 -293
  469. package/dist/tests/commands/message.test.js.map +0 -1
  470. package/dist/tests/commands/reaction.test.d.ts +0 -2
  471. package/dist/tests/commands/reaction.test.d.ts.map +0 -1
  472. package/dist/tests/commands/reaction.test.js +0 -84
  473. package/dist/tests/commands/reaction.test.js.map +0 -1
  474. package/dist/tests/commands/snapshot.test.d.ts +0 -2
  475. package/dist/tests/commands/snapshot.test.d.ts.map +0 -1
  476. package/dist/tests/commands/snapshot.test.js +0 -280
  477. package/dist/tests/commands/snapshot.test.js.map +0 -1
  478. package/dist/tests/commands/user.test.d.ts +0 -2
  479. package/dist/tests/commands/user.test.d.ts.map +0 -1
  480. package/dist/tests/commands/user.test.js +0 -117
  481. package/dist/tests/commands/user.test.js.map +0 -1
  482. package/dist/tests/commands/workspace.test.d.ts +0 -2
  483. package/dist/tests/commands/workspace.test.d.ts.map +0 -1
  484. package/dist/tests/commands/workspace.test.js +0 -453
  485. package/dist/tests/commands/workspace.test.js.map +0 -1
  486. package/dist/tests/credential-manager.test.d.ts +0 -2
  487. package/dist/tests/credential-manager.test.d.ts.map +0 -1
  488. package/dist/tests/credential-manager.test.js +0 -199
  489. package/dist/tests/credential-manager.test.js.map +0 -1
  490. package/dist/tests/slack-client.test.d.ts +0 -2
  491. package/dist/tests/slack-client.test.d.ts.map +0 -1
  492. package/dist/tests/slack-client.test.js +0 -741
  493. package/dist/tests/slack-client.test.js.map +0 -1
  494. package/dist/tests/types.test.d.ts +0 -2
  495. package/dist/tests/types.test.d.ts.map +0 -1
  496. package/dist/tests/types.test.js +0 -215
  497. package/dist/tests/types.test.js.map +0 -1
  498. package/dist/types/index.d.ts +0 -369
  499. package/dist/types/index.d.ts.map +0 -1
  500. package/dist/types/index.js +0 -92
  501. package/dist/types/index.js.map +0 -1
  502. package/dist/utils/error-handler.d.ts +0 -2
  503. package/dist/utils/error-handler.d.ts.map +0 -1
  504. package/dist/utils/error-handler.js +0 -5
  505. package/dist/utils/error-handler.js.map +0 -1
  506. package/dist/utils/output.d.ts +0 -2
  507. package/dist/utils/output.d.ts.map +0 -1
  508. package/dist/utils/output.js +0 -4
  509. package/dist/utils/output.js.map +0 -1
  510. package/src/platforms/discord/commands/guild.test.ts +0 -117
  511. /package/dist/{cli.d.ts → src/platforms/teams/cli.d.ts} +0 -0
  512. /package/dist/{commands → src/platforms/teams/commands}/user.d.ts +0 -0
@@ -0,0 +1,59 @@
1
+ import { Command } from 'commander'
2
+ import { handleError } from '../../../shared/utils/error-handler'
3
+ import { formatOutput } from '../../../shared/utils/output'
4
+ import { DiscordClient } from '../client'
5
+ import { DiscordCredentialManager } from '../credential-manager'
6
+
7
+ async function searchAction(
8
+ guildId: string,
9
+ query: string,
10
+ options: { limit?: string; pretty?: boolean }
11
+ ): Promise<void> {
12
+ try {
13
+ const credManager = new DiscordCredentialManager()
14
+ const config = await credManager.load()
15
+
16
+ if (!config.token) {
17
+ console.log(
18
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
19
+ )
20
+ process.exit(1)
21
+ }
22
+
23
+ const client = new DiscordClient(config.token)
24
+ const limit = options.limit ? parseInt(options.limit, 10) : 10
25
+ const members = await client.searchMembers(guildId, query, limit)
26
+
27
+ const output = members.map((member) => ({
28
+ user: {
29
+ id: member.user.id,
30
+ username: member.user.username,
31
+ global_name: member.user.global_name,
32
+ avatar: member.user.avatar,
33
+ bot: member.user.bot,
34
+ },
35
+ nick: member.nick,
36
+ roles: member.roles,
37
+ joined_at: member.joined_at,
38
+ deaf: member.deaf,
39
+ mute: member.mute,
40
+ flags: member.flags,
41
+ }))
42
+
43
+ console.log(formatOutput(output, options.pretty))
44
+ } catch (error) {
45
+ handleError(error as Error)
46
+ }
47
+ }
48
+
49
+ export const memberCommand = new Command('member')
50
+ .description('Member commands')
51
+ .addCommand(
52
+ new Command('search')
53
+ .description('Search guild members')
54
+ .argument('<guild-id>', 'Guild ID')
55
+ .argument('<query>', 'Search query')
56
+ .option('--limit <number>', 'Maximum number of results (default: 10)')
57
+ .option('--pretty', 'Pretty print JSON output')
58
+ .action(searchAction)
59
+ )
@@ -0,0 +1,129 @@
1
+ import { afterEach, beforeEach, expect, spyOn, test } from 'bun:test'
2
+ import { DiscordClient } from '../client'
3
+ import { DiscordCredentialManager } from '../credential-manager'
4
+
5
+ let clientGetMentionsSpy: ReturnType<typeof spyOn>
6
+ let credManagerLoadSpy: ReturnType<typeof spyOn>
7
+
8
+ beforeEach(() => {
9
+ // Spy on DiscordClient.prototype methods
10
+ clientGetMentionsSpy = spyOn(DiscordClient.prototype, 'getMentions').mockResolvedValue([
11
+ {
12
+ id: 'msg-1',
13
+ channel_id: 'ch-1',
14
+ author: { id: 'user-1', username: 'alice' },
15
+ content: 'Hey @testuser check this out',
16
+ timestamp: '2024-01-29T10:00:00Z',
17
+ mention_everyone: false,
18
+ mentions: [{ id: 'user-me', username: 'testuser' }],
19
+ guild_id: 'guild-1',
20
+ },
21
+ {
22
+ id: 'msg-2',
23
+ channel_id: 'ch-2',
24
+ author: { id: 'user-2', username: 'bob' },
25
+ content: '@everyone important announcement',
26
+ timestamp: '2024-01-29T09:00:00Z',
27
+ mention_everyone: true,
28
+ mentions: [],
29
+ guild_id: 'guild-1',
30
+ },
31
+ ])
32
+
33
+ // Spy on DiscordCredentialManager.prototype methods
34
+ credManagerLoadSpy = spyOn(DiscordCredentialManager.prototype, 'load').mockResolvedValue({
35
+ token: 'test-token',
36
+ current_server: 'server-1',
37
+ servers: {
38
+ 'server-1': { server_id: 'server-1', server_name: 'Server One' },
39
+ },
40
+ })
41
+ })
42
+
43
+ afterEach(() => {
44
+ clientGetMentionsSpy?.mockRestore()
45
+ credManagerLoadSpy?.mockRestore()
46
+ })
47
+
48
+ test('getMentions: returns mentions', async () => {
49
+ // given: discord client
50
+ const client = new DiscordClient('test-token')
51
+
52
+ // when: getting mentions
53
+ const mentions = await client.getMentions()
54
+
55
+ // then: mentions are returned
56
+ expect(mentions).toBeDefined()
57
+ expect(mentions).toHaveLength(2)
58
+ expect(mentions[0].id).toBe('msg-1')
59
+ expect(mentions[0].author.username).toBe('alice')
60
+ expect(mentions[0].mentions).toHaveLength(1)
61
+ expect(mentions[1].mention_everyone).toBe(true)
62
+ })
63
+
64
+ test('getMentions: respects limit option', async () => {
65
+ // given: discord client with limit option
66
+ const client = new DiscordClient('test-token')
67
+ clientGetMentionsSpy.mockResolvedValue([
68
+ {
69
+ id: 'msg-1',
70
+ channel_id: 'ch-1',
71
+ author: { id: 'user-1', username: 'alice' },
72
+ content: 'Hey @testuser',
73
+ timestamp: '2024-01-29T10:00:00Z',
74
+ mention_everyone: false,
75
+ mentions: [{ id: 'user-me', username: 'testuser' }],
76
+ },
77
+ ])
78
+
79
+ // when: getting mentions with limit
80
+ const mentions = await client.getMentions({ limit: 1 })
81
+
82
+ // then: limit is respected
83
+ expect(mentions).toHaveLength(1)
84
+ expect(clientGetMentionsSpy).toHaveBeenCalledWith({ limit: 1 })
85
+ })
86
+
87
+ test('getMentions: respects guildId option', async () => {
88
+ // given: discord client with guildId option
89
+ const client = new DiscordClient('test-token')
90
+ clientGetMentionsSpy.mockResolvedValue([
91
+ {
92
+ id: 'msg-1',
93
+ channel_id: 'ch-1',
94
+ author: { id: 'user-1', username: 'alice' },
95
+ content: 'Hey @testuser',
96
+ timestamp: '2024-01-29T10:00:00Z',
97
+ mention_everyone: false,
98
+ mentions: [{ id: 'user-me', username: 'testuser' }],
99
+ guild_id: 'guild-1',
100
+ },
101
+ ])
102
+
103
+ // when: getting mentions with guildId
104
+ const mentions = await client.getMentions({ guildId: 'guild-1' })
105
+
106
+ // then: guildId is respected
107
+ expect(mentions).toHaveLength(1)
108
+ expect(mentions[0].guild_id).toBe('guild-1')
109
+ expect(clientGetMentionsSpy).toHaveBeenCalledWith({ guildId: 'guild-1' })
110
+ })
111
+
112
+ test('getMentions: includes mention metadata', async () => {
113
+ // given: discord client with mentions
114
+ const client = new DiscordClient('test-token')
115
+ const mentions = await client.getMentions()
116
+
117
+ // when: checking mention properties
118
+ const mention = mentions[0]
119
+
120
+ // then: mention has required fields
121
+ expect(mention.id).toBeDefined()
122
+ expect(mention.channel_id).toBeDefined()
123
+ expect(mention.author).toBeDefined()
124
+ expect(mention.author.username).toBeDefined()
125
+ expect(mention.content).toBeDefined()
126
+ expect(mention.timestamp).toBeDefined()
127
+ expect(mention.mention_everyone).toBeDefined()
128
+ expect(mention.mentions).toBeDefined()
129
+ })
@@ -0,0 +1,59 @@
1
+ import { Command } from 'commander'
2
+ import { handleError } from '../../../shared/utils/error-handler'
3
+ import { formatOutput } from '../../../shared/utils/output'
4
+ import { DiscordClient } from '../client'
5
+ import { DiscordCredentialManager } from '../credential-manager'
6
+
7
+ export async function listAction(options: {
8
+ limit?: number
9
+ guild?: string
10
+ pretty?: boolean
11
+ }): Promise<void> {
12
+ try {
13
+ const credManager = new DiscordCredentialManager()
14
+ const config = await credManager.load()
15
+
16
+ if (!config.token) {
17
+ console.log(
18
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
19
+ )
20
+ process.exit(1)
21
+ }
22
+
23
+ const client = new DiscordClient(config.token)
24
+ const mentions = await client.getMentions({
25
+ limit: options.limit,
26
+ guildId: options.guild,
27
+ })
28
+
29
+ const output = mentions.map((mention) => ({
30
+ id: mention.id,
31
+ channel_id: mention.channel_id,
32
+ author: mention.author.username,
33
+ content: mention.content,
34
+ timestamp: mention.timestamp,
35
+ mention_everyone: mention.mention_everyone,
36
+ mentioned_users: mention.mentions.map((u) => u.username),
37
+ guild_id: mention.guild_id || null,
38
+ }))
39
+
40
+ console.log(formatOutput(output, options.pretty))
41
+ } catch (error) {
42
+ handleError(error as Error)
43
+ }
44
+ }
45
+
46
+ export const mentionCommand = new Command('mention').description('Mention commands').addCommand(
47
+ new Command('list')
48
+ .description('List mentions')
49
+ .option('--limit <n>', 'Number of mentions to fetch', '25')
50
+ .option('--guild <guild-id>', 'Filter by guild ID')
51
+ .option('--pretty', 'Pretty print JSON output')
52
+ .action((options) => {
53
+ listAction({
54
+ limit: options.limit ? parseInt(options.limit, 10) : undefined,
55
+ guild: options.guild,
56
+ pretty: options.pretty,
57
+ })
58
+ })
59
+ )
@@ -1,64 +1,97 @@
1
- import { beforeEach, expect, mock, test } from 'bun:test'
2
- import { deleteAction, getAction, listAction, sendAction } from './message'
1
+ import { afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
2
+ import { DiscordClient } from '../client'
3
+ import { DiscordCredentialManager } from '../credential-manager'
4
+ import { ackAction, deleteAction, getAction, listAction, searchAction, sendAction } from './message'
5
+
6
+ let clientSendMessageSpy: ReturnType<typeof spyOn>
7
+ let clientGetMessagesSpy: ReturnType<typeof spyOn>
8
+ let clientGetMessageSpy: ReturnType<typeof spyOn>
9
+ let clientDeleteMessageSpy: ReturnType<typeof spyOn>
10
+ let clientAckMessageSpy: ReturnType<typeof spyOn>
11
+ let clientSearchMessagesSpy: ReturnType<typeof spyOn>
12
+ let credManagerLoadSpy: ReturnType<typeof spyOn>
3
13
 
4
- mock.module('../client', () => ({
5
- DiscordClient: mock(() => ({
6
- sendMessage: mock(async () => ({
14
+ beforeEach(() => {
15
+ // Spy on DiscordClient.prototype methods
16
+ clientSendMessageSpy = spyOn(DiscordClient.prototype, 'sendMessage').mockResolvedValue({
17
+ id: 'msg_123',
18
+ channel_id: 'ch_456',
19
+ author: { id: 'user_789', username: 'testuser' },
20
+ content: 'Hello world',
21
+ timestamp: '2025-01-29T10:00:00Z',
22
+ })
23
+
24
+ clientGetMessagesSpy = spyOn(DiscordClient.prototype, 'getMessages').mockResolvedValue([
25
+ {
7
26
  id: 'msg_123',
8
27
  channel_id: 'ch_456',
9
28
  author: { id: 'user_789', username: 'testuser' },
10
29
  content: 'Hello world',
11
30
  timestamp: '2025-01-29T10:00:00Z',
12
- })),
13
- getMessages: mock(async () => [
31
+ },
32
+ {
33
+ id: 'msg_124',
34
+ channel_id: 'ch_456',
35
+ author: { id: 'user_789', username: 'testuser' },
36
+ content: 'Second message',
37
+ timestamp: '2025-01-29T10:01:00Z',
38
+ },
39
+ ])
40
+
41
+ clientGetMessageSpy = spyOn(DiscordClient.prototype, 'getMessage').mockResolvedValue({
42
+ id: 'msg_123',
43
+ channel_id: 'ch_456',
44
+ author: { id: 'user_789', username: 'testuser' },
45
+ content: 'Hello world',
46
+ timestamp: '2025-01-29T10:00:00Z',
47
+ })
48
+
49
+ clientDeleteMessageSpy = spyOn(DiscordClient.prototype, 'deleteMessage').mockResolvedValue(
50
+ undefined
51
+ )
52
+
53
+ clientAckMessageSpy = spyOn(DiscordClient.prototype, 'ackMessage').mockResolvedValue(undefined)
54
+
55
+ clientSearchMessagesSpy = spyOn(DiscordClient.prototype, 'searchMessages').mockResolvedValue({
56
+ results: [
14
57
  {
15
- id: 'msg_123',
58
+ id: 'msg_search_1',
16
59
  channel_id: 'ch_456',
17
- author: { id: 'user_789', username: 'testuser' },
60
+ guild_id: 'server_123',
18
61
  content: 'Hello world',
62
+ author: { id: 'user_789', username: 'testuser' },
19
63
  timestamp: '2025-01-29T10:00:00Z',
64
+ hit: true,
20
65
  },
21
66
  {
22
- id: 'msg_124',
67
+ id: 'msg_search_2',
23
68
  channel_id: 'ch_456',
69
+ guild_id: 'server_123',
70
+ content: 'Hello again',
24
71
  author: { id: 'user_789', username: 'testuser' },
25
- content: 'Second message',
26
72
  timestamp: '2025-01-29T10:01:00Z',
73
+ hit: true,
27
74
  },
28
- ]),
29
- getMessage: mock(async () => ({
30
- id: 'msg_123',
31
- channel_id: 'ch_456',
32
- author: { id: 'user_789', username: 'testuser' },
33
- content: 'Hello world',
34
- timestamp: '2025-01-29T10:00:00Z',
35
- })),
36
- deleteMessage: mock(async () => undefined),
37
- })),
38
- }))
39
-
40
- mock.module('../credential-manager', () => ({
41
- DiscordCredentialManager: mock(() => ({
42
- load: mock(async () => ({
43
- token: 'test_token',
44
- current_guild: 'guild_123',
45
- guilds: {},
46
- })),
47
- })),
48
- }))
49
-
50
- mock.module('../../../shared/utils/output', () => ({
51
- formatOutput: (data: any, pretty?: boolean) => JSON.stringify(data, null, pretty ? 2 : 0),
52
- }))
53
-
54
- mock.module('../../../shared/utils/error-handler', () => ({
55
- handleError: (error: Error) => {
56
- console.error(error.message)
57
- },
58
- }))
75
+ ],
76
+ total: 2,
77
+ })
78
+
79
+ // Spy on DiscordCredentialManager.prototype methods
80
+ credManagerLoadSpy = spyOn(DiscordCredentialManager.prototype, 'load').mockResolvedValue({
81
+ token: 'test_token',
82
+ current_server: 'server_123',
83
+ servers: {},
84
+ })
85
+ })
59
86
 
60
- beforeEach(() => {
61
- mock.restore()
87
+ afterEach(() => {
88
+ clientSendMessageSpy?.mockRestore()
89
+ clientGetMessagesSpy?.mockRestore()
90
+ clientGetMessageSpy?.mockRestore()
91
+ clientDeleteMessageSpy?.mockRestore()
92
+ clientAckMessageSpy?.mockRestore()
93
+ clientSearchMessagesSpy?.mockRestore()
94
+ credManagerLoadSpy?.mockRestore()
62
95
  })
63
96
 
64
97
  test('send: returns message with id', async () => {
@@ -105,3 +138,65 @@ test('delete: returns success', async () => {
105
138
  const output = consoleSpy.mock.calls[0][0]
106
139
  expect(output).toContain('deleted')
107
140
  })
141
+
142
+ test('ack: returns success', async () => {
143
+ const consoleSpy = mock((_msg: string) => {})
144
+ console.log = consoleSpy
145
+
146
+ await ackAction('ch_456', 'msg_123', { pretty: false })
147
+
148
+ expect(consoleSpy).toHaveBeenCalled()
149
+ const output = consoleSpy.mock.calls[0][0]
150
+ expect(output).toContain('acknowledged')
151
+ })
152
+
153
+ test('search: returns search results with query', async () => {
154
+ const consoleSpy = mock((_msg: string) => {})
155
+ console.log = consoleSpy
156
+
157
+ await searchAction('Hello', { pretty: false })
158
+
159
+ expect(consoleSpy).toHaveBeenCalled()
160
+ const output = consoleSpy.mock.calls[0][0]
161
+ expect(output).toContain('msg_search_1')
162
+ expect(output).toContain('msg_search_2')
163
+ expect(output).toContain('Hello world')
164
+ })
165
+
166
+ test('search: includes total_results in output', async () => {
167
+ const consoleSpy = mock((_msg: string) => {})
168
+ console.log = consoleSpy
169
+
170
+ await searchAction('Hello', { pretty: false })
171
+
172
+ expect(consoleSpy).toHaveBeenCalled()
173
+ const output = consoleSpy.mock.calls[0][0]
174
+ expect(output).toContain('total_results')
175
+ expect(output).toContain('2')
176
+ })
177
+
178
+ test('search: passes options to client', async () => {
179
+ const consoleSpy = mock((_msg: string) => {})
180
+ console.log = consoleSpy
181
+
182
+ await searchAction('test', {
183
+ channel: 'ch_specific',
184
+ author: 'user_specific',
185
+ has: 'image',
186
+ sort: 'timestamp',
187
+ sortDir: 'asc',
188
+ limit: 10,
189
+ offset: 5,
190
+ pretty: false,
191
+ })
192
+
193
+ expect(clientSearchMessagesSpy).toHaveBeenCalledWith('server_123', 'test', {
194
+ channelId: 'ch_specific',
195
+ authorId: 'user_specific',
196
+ has: 'image',
197
+ sortBy: 'timestamp',
198
+ sortOrder: 'asc',
199
+ limit: 10,
200
+ offset: 5,
201
+ })
202
+ })
@@ -3,7 +3,7 @@ import { handleError } from '../../../shared/utils/error-handler'
3
3
  import { formatOutput } from '../../../shared/utils/output'
4
4
  import { DiscordClient } from '../client'
5
5
  import { DiscordCredentialManager } from '../credential-manager'
6
- import type { DiscordMessage } from '../types'
6
+ import type { DiscordMessage, DiscordSearchOptions } from '../types'
7
7
 
8
8
  export async function sendAction(
9
9
  channelId: string,
@@ -140,6 +140,106 @@ export async function deleteAction(
140
140
  }
141
141
  }
142
142
 
143
+ export async function ackAction(
144
+ channelId: string,
145
+ messageId: string,
146
+ options: { pretty?: boolean }
147
+ ): Promise<void> {
148
+ try {
149
+ const credManager = new DiscordCredentialManager()
150
+ const config = await credManager.load()
151
+
152
+ if (!config.token) {
153
+ console.log(
154
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
155
+ )
156
+ process.exit(1)
157
+ }
158
+
159
+ const client = new DiscordClient(config.token)
160
+ await client.ackMessage(channelId, messageId)
161
+
162
+ console.log(formatOutput({ acknowledged: messageId }, options.pretty))
163
+ } catch (error) {
164
+ handleError(error as Error)
165
+ }
166
+ }
167
+
168
+ export async function searchAction(
169
+ query: string,
170
+ options: {
171
+ channel?: string
172
+ author?: string
173
+ has?: string
174
+ sort?: string
175
+ sortDir?: string
176
+ limit?: number
177
+ offset?: number
178
+ pretty?: boolean
179
+ }
180
+ ): Promise<void> {
181
+ try {
182
+ const credManager = new DiscordCredentialManager()
183
+ const config = await credManager.load()
184
+
185
+ if (!config.token) {
186
+ console.log(
187
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
188
+ )
189
+ process.exit(1)
190
+ }
191
+
192
+ if (!config.current_server) {
193
+ console.log(
194
+ formatOutput(
195
+ { error: 'No server selected. Run "server switch <server-id>" first.' },
196
+ options.pretty
197
+ )
198
+ )
199
+ process.exit(1)
200
+ }
201
+
202
+ const client = new DiscordClient(config.token)
203
+
204
+ const searchOptions: DiscordSearchOptions = {}
205
+ if (options.channel) searchOptions.channelId = options.channel
206
+ if (options.author) searchOptions.authorId = options.author
207
+ if (options.has) {
208
+ searchOptions.has = options.has as DiscordSearchOptions['has']
209
+ }
210
+ if (options.sort) {
211
+ searchOptions.sortBy = options.sort as DiscordSearchOptions['sortBy']
212
+ }
213
+ if (options.sortDir) {
214
+ searchOptions.sortOrder = options.sortDir as DiscordSearchOptions['sortOrder']
215
+ }
216
+ if (options.limit !== undefined) searchOptions.limit = options.limit
217
+ if (options.offset !== undefined) searchOptions.offset = options.offset
218
+
219
+ const { results, total } = await client.searchMessages(
220
+ config.current_server,
221
+ query,
222
+ searchOptions
223
+ )
224
+
225
+ const output = {
226
+ total_results: total,
227
+ results: results.map((msg) => ({
228
+ id: msg.id,
229
+ content: msg.content,
230
+ author_id: msg.author.id,
231
+ author_username: msg.author.username,
232
+ channel_id: msg.channel_id,
233
+ timestamp: msg.timestamp,
234
+ })),
235
+ }
236
+
237
+ console.log(formatOutput(output, options.pretty))
238
+ } catch (error) {
239
+ handleError(error as Error)
240
+ }
241
+ }
242
+
143
243
  export const messageCommand = new Command('message')
144
244
  .description('Message commands')
145
245
  .addCommand(
@@ -180,3 +280,36 @@ export const messageCommand = new Command('message')
180
280
  .option('--pretty', 'Pretty print JSON output')
181
281
  .action(deleteAction)
182
282
  )
283
+ .addCommand(
284
+ new Command('ack')
285
+ .description('Mark message as read (acknowledge)')
286
+ .argument('<channel-id>', 'Channel ID')
287
+ .argument('<message-id>', 'Message ID')
288
+ .option('--pretty', 'Pretty print JSON output')
289
+ .action(ackAction)
290
+ )
291
+ .addCommand(
292
+ new Command('search')
293
+ .description('Search messages in current server')
294
+ .argument('<query>', 'Search query')
295
+ .option('--channel <id>', 'Filter by channel ID')
296
+ .option('--author <id>', 'Filter by author ID')
297
+ .option('--has <type>', 'Filter by attachment type: file, image, video, embed, link, sticker')
298
+ .option('--sort <type>', 'Sort by: timestamp, relevance (default: timestamp)')
299
+ .option('--sort-dir <dir>', 'Sort direction: asc, desc (default: desc)')
300
+ .option('--limit <n>', 'Number of results (max 25)', '25')
301
+ .option('--offset <n>', 'Offset for pagination', '0')
302
+ .option('--pretty', 'Pretty print JSON output')
303
+ .action((query: string, options: any) => {
304
+ searchAction(query, {
305
+ channel: options.channel,
306
+ author: options.author,
307
+ has: options.has,
308
+ sort: options.sort,
309
+ sortDir: options.sortDir,
310
+ limit: parseInt(options.limit, 10),
311
+ offset: parseInt(options.offset, 10),
312
+ pretty: options.pretty,
313
+ })
314
+ })
315
+ )
@@ -0,0 +1,84 @@
1
+ import { expect, mock, test } from 'bun:test'
2
+
3
+ // Mock DiscordClient
4
+ const mockClient = {
5
+ getUserNote: mock(async (userId: string) => {
6
+ if (userId === 'user_with_note') {
7
+ return {
8
+ user_id: 'current_user_id',
9
+ note_user_id: userId,
10
+ note: 'This is a test note',
11
+ }
12
+ }
13
+ return null
14
+ }),
15
+ setUserNote: mock(async (userId: string, note: string) => {
16
+ return {
17
+ user_id: 'current_user_id',
18
+ note_user_id: userId,
19
+ note,
20
+ }
21
+ }),
22
+ }
23
+
24
+ test('get returns note when it exists', async () => {
25
+ // given: user with a note
26
+ const userId = 'user_with_note'
27
+
28
+ // when: getting user note
29
+ const result = await mockClient.getUserNote(userId)
30
+
31
+ // then: returns note object
32
+ expect(result).not.toBeNull()
33
+ expect(result?.note_user_id).toBe('user_with_note')
34
+ expect(result?.note).toBe('This is a test note')
35
+ })
36
+
37
+ test('get returns null when note does not exist', async () => {
38
+ // given: user without a note
39
+ const userId = 'user_without_note'
40
+
41
+ // when: getting user note
42
+ const result = await mockClient.getUserNote(userId)
43
+
44
+ // then: returns null
45
+ expect(result).toBeNull()
46
+ })
47
+
48
+ test('set creates or updates note', async () => {
49
+ // given: user id and note content
50
+ const userId = 'user123'
51
+ const noteContent = 'Important person to remember'
52
+
53
+ // when: setting user note
54
+ const result = await mockClient.setUserNote(userId, noteContent)
55
+
56
+ // then: returns updated note object
57
+ expect(result.note_user_id).toBe('user123')
58
+ expect(result.note).toBe('Important person to remember')
59
+ })
60
+
61
+ test('set can update existing note', async () => {
62
+ // given: user with existing note
63
+ const userId = 'user_with_note'
64
+ const newNote = 'Updated note content'
65
+
66
+ // when: updating user note
67
+ const result = await mockClient.setUserNote(userId, newNote)
68
+
69
+ // then: returns updated note object
70
+ expect(result.note_user_id).toBe('user_with_note')
71
+ expect(result.note).toBe('Updated note content')
72
+ })
73
+
74
+ test('set can clear note with empty string', async () => {
75
+ // given: user with existing note
76
+ const userId = 'user_with_note'
77
+
78
+ // when: clearing note
79
+ const result = await mockClient.setUserNote(userId, '')
80
+
81
+ // then: returns note object with empty note
82
+ expect(result.note_user_id).toBe('user_with_note')
83
+ expect(result.note).toBe('')
84
+ })