agent-messenger 1.0.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 (394) hide show
  1. package/.claude/commands/release.md +92 -0
  2. package/.claude-plugin/README.md +144 -0
  3. package/.claude-plugin/marketplace.json +37 -0
  4. package/.claude-plugin/plugin.json +17 -0
  5. package/.github/workflows/ci.yml +30 -0
  6. package/CLAUDE.md +106 -0
  7. package/CONTRIBUTING.md +131 -0
  8. package/README.md +140 -0
  9. package/biome.json +34 -0
  10. package/bun.lock +252 -0
  11. package/dist/cli.d.ts +5 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +21 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/commands/auth.d.ts +3 -0
  16. package/dist/commands/auth.d.ts.map +1 -0
  17. package/dist/commands/auth.js +140 -0
  18. package/dist/commands/auth.js.map +1 -0
  19. package/dist/commands/channel.d.ts +3 -0
  20. package/dist/commands/channel.d.ts.map +1 -0
  21. package/dist/commands/channel.js +118 -0
  22. package/dist/commands/channel.js.map +1 -0
  23. package/dist/commands/file.d.ts +3 -0
  24. package/dist/commands/file.d.ts.map +1 -0
  25. package/dist/commands/file.js +113 -0
  26. package/dist/commands/file.js.map +1 -0
  27. package/dist/commands/index.d.ts +9 -0
  28. package/dist/commands/index.d.ts.map +1 -0
  29. package/dist/commands/index.js +9 -0
  30. package/dist/commands/index.js.map +1 -0
  31. package/dist/commands/message.d.ts +3 -0
  32. package/dist/commands/message.d.ts.map +1 -0
  33. package/dist/commands/message.js +214 -0
  34. package/dist/commands/message.js.map +1 -0
  35. package/dist/commands/reaction.d.ts +3 -0
  36. package/dist/commands/reaction.d.ts.map +1 -0
  37. package/dist/commands/reaction.js +100 -0
  38. package/dist/commands/reaction.js.map +1 -0
  39. package/dist/commands/snapshot.d.ts +3 -0
  40. package/dist/commands/snapshot.d.ts.map +1 -0
  41. package/dist/commands/snapshot.js +88 -0
  42. package/dist/commands/snapshot.js.map +1 -0
  43. package/dist/commands/user.d.ts +3 -0
  44. package/dist/commands/user.d.ts.map +1 -0
  45. package/dist/commands/user.js +96 -0
  46. package/dist/commands/user.js.map +1 -0
  47. package/dist/commands/workspace.d.ts +3 -0
  48. package/dist/commands/workspace.d.ts.map +1 -0
  49. package/dist/commands/workspace.js +89 -0
  50. package/dist/commands/workspace.js.map +1 -0
  51. package/dist/lib/credential-manager.d.ts +13 -0
  52. package/dist/lib/credential-manager.d.ts.map +1 -0
  53. package/dist/lib/credential-manager.js +58 -0
  54. package/dist/lib/credential-manager.js.map +1 -0
  55. package/dist/lib/index.d.ts +3 -0
  56. package/dist/lib/index.d.ts.map +1 -0
  57. package/dist/lib/index.js +3 -0
  58. package/dist/lib/index.js.map +1 -0
  59. package/dist/lib/ref-manager.d.ts +26 -0
  60. package/dist/lib/ref-manager.d.ts.map +1 -0
  61. package/dist/lib/ref-manager.js +92 -0
  62. package/dist/lib/ref-manager.js.map +1 -0
  63. package/dist/lib/slack-client.d.ts +37 -0
  64. package/dist/lib/slack-client.d.ts.map +1 -0
  65. package/dist/lib/slack-client.js +379 -0
  66. package/dist/lib/slack-client.js.map +1 -0
  67. package/dist/lib/token-extractor.d.ts +28 -0
  68. package/dist/lib/token-extractor.d.ts.map +1 -0
  69. package/dist/lib/token-extractor.js +401 -0
  70. package/dist/lib/token-extractor.js.map +1 -0
  71. package/dist/package.json +37 -0
  72. package/dist/src/cli.d.ts +5 -0
  73. package/dist/src/cli.d.ts.map +1 -0
  74. package/dist/src/cli.js +22 -0
  75. package/dist/src/cli.js.map +1 -0
  76. package/dist/src/platforms/discord/cli.d.ts +5 -0
  77. package/dist/src/platforms/discord/cli.d.ts.map +1 -0
  78. package/dist/src/platforms/discord/cli.js +22 -0
  79. package/dist/src/platforms/discord/cli.js.map +1 -0
  80. package/dist/src/platforms/discord/client.d.ts +34 -0
  81. package/dist/src/platforms/discord/client.d.ts.map +1 -0
  82. package/dist/src/platforms/discord/client.js +187 -0
  83. package/dist/src/platforms/discord/client.js.map +1 -0
  84. package/dist/src/platforms/discord/client.test.d.ts +2 -0
  85. package/dist/src/platforms/discord/client.test.d.ts.map +1 -0
  86. package/dist/src/platforms/discord/client.test.js +367 -0
  87. package/dist/src/platforms/discord/client.test.js.map +1 -0
  88. package/dist/src/platforms/discord/commands/auth.d.ts +13 -0
  89. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -0
  90. package/dist/src/platforms/discord/commands/auth.js +155 -0
  91. package/dist/src/platforms/discord/commands/auth.js.map +1 -0
  92. package/dist/src/platforms/discord/commands/auth.test.d.ts +2 -0
  93. package/dist/src/platforms/discord/commands/auth.test.d.ts.map +1 -0
  94. package/dist/src/platforms/discord/commands/auth.test.js +65 -0
  95. package/dist/src/platforms/discord/commands/auth.test.js.map +1 -0
  96. package/dist/src/platforms/discord/commands/channel.d.ts +13 -0
  97. package/dist/src/platforms/discord/commands/channel.d.ts.map +1 -0
  98. package/dist/src/platforms/discord/commands/channel.js +99 -0
  99. package/dist/src/platforms/discord/commands/channel.js.map +1 -0
  100. package/dist/src/platforms/discord/commands/channel.test.d.ts +2 -0
  101. package/dist/src/platforms/discord/commands/channel.test.d.ts.map +1 -0
  102. package/dist/src/platforms/discord/commands/channel.test.js +136 -0
  103. package/dist/src/platforms/discord/commands/channel.test.js.map +1 -0
  104. package/dist/src/platforms/discord/commands/file.d.ts +13 -0
  105. package/dist/src/platforms/discord/commands/file.d.ts.map +1 -0
  106. package/dist/src/platforms/discord/commands/file.js +99 -0
  107. package/dist/src/platforms/discord/commands/file.js.map +1 -0
  108. package/dist/src/platforms/discord/commands/file.test.d.ts +2 -0
  109. package/dist/src/platforms/discord/commands/file.test.d.ts.map +1 -0
  110. package/dist/src/platforms/discord/commands/file.test.js +83 -0
  111. package/dist/src/platforms/discord/commands/file.test.js.map +1 -0
  112. package/dist/src/platforms/discord/commands/guild.d.ts +15 -0
  113. package/dist/src/platforms/discord/commands/guild.d.ts.map +1 -0
  114. package/dist/src/platforms/discord/commands/guild.js +102 -0
  115. package/dist/src/platforms/discord/commands/guild.js.map +1 -0
  116. package/dist/src/platforms/discord/commands/guild.test.d.ts +2 -0
  117. package/dist/src/platforms/discord/commands/guild.test.d.ts.map +1 -0
  118. package/dist/src/platforms/discord/commands/guild.test.js +100 -0
  119. package/dist/src/platforms/discord/commands/guild.test.js.map +1 -0
  120. package/dist/src/platforms/discord/commands/index.d.ts +9 -0
  121. package/dist/src/platforms/discord/commands/index.d.ts.map +1 -0
  122. package/dist/src/platforms/discord/commands/index.js +9 -0
  123. package/dist/src/platforms/discord/commands/index.js.map +1 -0
  124. package/dist/src/platforms/discord/commands/message.d.ts +17 -0
  125. package/dist/src/platforms/discord/commands/message.d.ts.map +1 -0
  126. package/dist/src/platforms/discord/commands/message.js +131 -0
  127. package/dist/src/platforms/discord/commands/message.js.map +1 -0
  128. package/dist/src/platforms/discord/commands/message.test.d.ts +2 -0
  129. package/dist/src/platforms/discord/commands/message.test.d.ts.map +1 -0
  130. package/dist/src/platforms/discord/commands/message.test.js +91 -0
  131. package/dist/src/platforms/discord/commands/message.test.js.map +1 -0
  132. package/dist/src/platforms/discord/commands/reaction.d.ts +12 -0
  133. package/dist/src/platforms/discord/commands/reaction.d.ts.map +1 -0
  134. package/dist/src/platforms/discord/commands/reaction.js +99 -0
  135. package/dist/src/platforms/discord/commands/reaction.js.map +1 -0
  136. package/dist/src/platforms/discord/commands/reaction.test.d.ts +2 -0
  137. package/dist/src/platforms/discord/commands/reaction.test.d.ts.map +1 -0
  138. package/dist/src/platforms/discord/commands/reaction.test.js +115 -0
  139. package/dist/src/platforms/discord/commands/reaction.test.js.map +1 -0
  140. package/dist/src/platforms/discord/commands/snapshot.d.ts +9 -0
  141. package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -0
  142. package/dist/src/platforms/discord/commands/snapshot.js +80 -0
  143. package/dist/src/platforms/discord/commands/snapshot.js.map +1 -0
  144. package/dist/src/platforms/discord/commands/snapshot.test.d.ts +2 -0
  145. package/dist/src/platforms/discord/commands/snapshot.test.d.ts.map +1 -0
  146. package/dist/src/platforms/discord/commands/snapshot.test.js +25 -0
  147. package/dist/src/platforms/discord/commands/snapshot.test.js.map +1 -0
  148. package/dist/src/platforms/discord/commands/user.d.ts +3 -0
  149. package/dist/src/platforms/discord/commands/user.d.ts.map +1 -0
  150. package/dist/src/platforms/discord/commands/user.js +94 -0
  151. package/dist/src/platforms/discord/commands/user.js.map +1 -0
  152. package/dist/src/platforms/discord/commands/user.test.d.ts +2 -0
  153. package/dist/src/platforms/discord/commands/user.test.d.ts.map +1 -0
  154. package/dist/src/platforms/discord/commands/user.test.js +103 -0
  155. package/dist/src/platforms/discord/commands/user.test.js.map +1 -0
  156. package/dist/src/platforms/discord/credential-manager.d.ts +33 -0
  157. package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -0
  158. package/dist/src/platforms/discord/credential-manager.js +73 -0
  159. package/dist/src/platforms/discord/credential-manager.js.map +1 -0
  160. package/dist/src/platforms/discord/credential-manager.test.d.ts +2 -0
  161. package/dist/src/platforms/discord/credential-manager.test.d.ts.map +1 -0
  162. package/dist/src/platforms/discord/credential-manager.test.js +136 -0
  163. package/dist/src/platforms/discord/credential-manager.test.js.map +1 -0
  164. package/dist/src/platforms/discord/token-extractor.d.ts +55 -0
  165. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -0
  166. package/dist/src/platforms/discord/token-extractor.js +462 -0
  167. package/dist/src/platforms/discord/token-extractor.js.map +1 -0
  168. package/dist/src/platforms/discord/token-extractor.test.d.ts +2 -0
  169. package/dist/src/platforms/discord/token-extractor.test.d.ts.map +1 -0
  170. package/dist/src/platforms/discord/token-extractor.test.js +789 -0
  171. package/dist/src/platforms/discord/token-extractor.test.js.map +1 -0
  172. package/dist/src/platforms/discord/types.d.ts +251 -0
  173. package/dist/src/platforms/discord/types.d.ts.map +1 -0
  174. package/dist/src/platforms/discord/types.js +74 -0
  175. package/dist/src/platforms/discord/types.js.map +1 -0
  176. package/dist/src/platforms/discord/types.test.d.ts +2 -0
  177. package/dist/src/platforms/discord/types.test.d.ts.map +1 -0
  178. package/dist/src/platforms/discord/types.test.js +211 -0
  179. package/dist/src/platforms/discord/types.test.js.map +1 -0
  180. package/dist/src/platforms/slack/cli.d.ts +5 -0
  181. package/dist/src/platforms/slack/cli.d.ts.map +1 -0
  182. package/dist/src/platforms/slack/cli.js +22 -0
  183. package/dist/src/platforms/slack/cli.js.map +1 -0
  184. package/dist/src/platforms/slack/client.d.ts +47 -0
  185. package/dist/src/platforms/slack/client.d.ts.map +1 -0
  186. package/dist/src/platforms/slack/client.js +412 -0
  187. package/dist/src/platforms/slack/client.js.map +1 -0
  188. package/dist/src/platforms/slack/commands/auth.d.ts +3 -0
  189. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -0
  190. package/dist/src/platforms/slack/commands/auth.js +156 -0
  191. package/dist/src/platforms/slack/commands/auth.js.map +1 -0
  192. package/dist/src/platforms/slack/commands/channel.d.ts +3 -0
  193. package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -0
  194. package/dist/src/platforms/slack/commands/channel.js +118 -0
  195. package/dist/src/platforms/slack/commands/channel.js.map +1 -0
  196. package/dist/src/platforms/slack/commands/file.d.ts +3 -0
  197. package/dist/src/platforms/slack/commands/file.d.ts.map +1 -0
  198. package/dist/src/platforms/slack/commands/file.js +113 -0
  199. package/dist/src/platforms/slack/commands/file.js.map +1 -0
  200. package/dist/src/platforms/slack/commands/index.d.ts +9 -0
  201. package/dist/src/platforms/slack/commands/index.d.ts.map +1 -0
  202. package/dist/src/platforms/slack/commands/index.js +9 -0
  203. package/dist/src/platforms/slack/commands/index.js.map +1 -0
  204. package/dist/src/platforms/slack/commands/message.d.ts +3 -0
  205. package/dist/src/platforms/slack/commands/message.d.ts.map +1 -0
  206. package/dist/src/platforms/slack/commands/message.js +263 -0
  207. package/dist/src/platforms/slack/commands/message.js.map +1 -0
  208. package/dist/src/platforms/slack/commands/reaction.d.ts +3 -0
  209. package/dist/src/platforms/slack/commands/reaction.d.ts.map +1 -0
  210. package/dist/src/platforms/slack/commands/reaction.js +100 -0
  211. package/dist/src/platforms/slack/commands/reaction.js.map +1 -0
  212. package/dist/src/platforms/slack/commands/snapshot.d.ts +3 -0
  213. package/dist/src/platforms/slack/commands/snapshot.d.ts.map +1 -0
  214. package/dist/src/platforms/slack/commands/snapshot.js +87 -0
  215. package/dist/src/platforms/slack/commands/snapshot.js.map +1 -0
  216. package/dist/src/platforms/slack/commands/user.d.ts +3 -0
  217. package/dist/src/platforms/slack/commands/user.d.ts.map +1 -0
  218. package/dist/src/platforms/slack/commands/user.js +96 -0
  219. package/dist/src/platforms/slack/commands/user.js.map +1 -0
  220. package/dist/src/platforms/slack/commands/workspace.d.ts +3 -0
  221. package/dist/src/platforms/slack/commands/workspace.d.ts.map +1 -0
  222. package/dist/src/platforms/slack/commands/workspace.js +89 -0
  223. package/dist/src/platforms/slack/commands/workspace.js.map +1 -0
  224. package/dist/src/platforms/slack/credential-manager.d.ts +13 -0
  225. package/dist/src/platforms/slack/credential-manager.d.ts.map +1 -0
  226. package/dist/src/platforms/slack/credential-manager.js +58 -0
  227. package/dist/src/platforms/slack/credential-manager.js.map +1 -0
  228. package/dist/src/platforms/slack/index.d.ts +3 -0
  229. package/dist/src/platforms/slack/index.d.ts.map +1 -0
  230. package/dist/src/platforms/slack/index.js +3 -0
  231. package/dist/src/platforms/slack/index.js.map +1 -0
  232. package/dist/src/platforms/slack/token-extractor.d.ts +28 -0
  233. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -0
  234. package/dist/src/platforms/slack/token-extractor.js +401 -0
  235. package/dist/src/platforms/slack/token-extractor.js.map +1 -0
  236. package/dist/src/platforms/slack/types.d.ts +369 -0
  237. package/dist/src/platforms/slack/types.d.ts.map +1 -0
  238. package/dist/src/platforms/slack/types.js +92 -0
  239. package/dist/src/platforms/slack/types.js.map +1 -0
  240. package/dist/src/shared/utils/concurrency.d.ts +2 -0
  241. package/dist/src/shared/utils/concurrency.d.ts.map +1 -0
  242. package/dist/src/shared/utils/concurrency.js +14 -0
  243. package/dist/src/shared/utils/concurrency.js.map +1 -0
  244. package/dist/src/shared/utils/concurrency.test.d.ts +2 -0
  245. package/dist/src/shared/utils/concurrency.test.d.ts.map +1 -0
  246. package/dist/src/shared/utils/concurrency.test.js +39 -0
  247. package/dist/src/shared/utils/concurrency.test.js.map +1 -0
  248. package/dist/src/shared/utils/error-handler.d.ts +2 -0
  249. package/dist/src/shared/utils/error-handler.d.ts.map +1 -0
  250. package/dist/src/shared/utils/error-handler.js +5 -0
  251. package/dist/src/shared/utils/error-handler.js.map +1 -0
  252. package/dist/src/shared/utils/output.d.ts +2 -0
  253. package/dist/src/shared/utils/output.d.ts.map +1 -0
  254. package/dist/src/shared/utils/output.js +4 -0
  255. package/dist/src/shared/utils/output.js.map +1 -0
  256. package/dist/tests/cli.test.d.ts +2 -0
  257. package/dist/tests/cli.test.d.ts.map +1 -0
  258. package/dist/tests/cli.test.js +83 -0
  259. package/dist/tests/cli.test.js.map +1 -0
  260. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/CURRENT +1 -0
  261. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOCK +0 -0
  262. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG +3 -0
  263. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG.old +1 -0
  264. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/MANIFEST-000004 +0 -0
  265. package/dist/tests/commands/auth.test.d.ts +2 -0
  266. package/dist/tests/commands/auth.test.d.ts.map +1 -0
  267. package/dist/tests/commands/auth.test.js +304 -0
  268. package/dist/tests/commands/auth.test.js.map +1 -0
  269. package/dist/tests/commands/channel.test.d.ts +2 -0
  270. package/dist/tests/commands/channel.test.d.ts.map +1 -0
  271. package/dist/tests/commands/channel.test.js +166 -0
  272. package/dist/tests/commands/channel.test.js.map +1 -0
  273. package/dist/tests/commands/file.test.d.ts +2 -0
  274. package/dist/tests/commands/file.test.d.ts.map +1 -0
  275. package/dist/tests/commands/file.test.js +175 -0
  276. package/dist/tests/commands/file.test.js.map +1 -0
  277. package/dist/tests/commands/message.test.d.ts +2 -0
  278. package/dist/tests/commands/message.test.d.ts.map +1 -0
  279. package/dist/tests/commands/message.test.js +293 -0
  280. package/dist/tests/commands/message.test.js.map +1 -0
  281. package/dist/tests/commands/reaction.test.d.ts +2 -0
  282. package/dist/tests/commands/reaction.test.d.ts.map +1 -0
  283. package/dist/tests/commands/reaction.test.js +84 -0
  284. package/dist/tests/commands/reaction.test.js.map +1 -0
  285. package/dist/tests/commands/snapshot.test.d.ts +2 -0
  286. package/dist/tests/commands/snapshot.test.d.ts.map +1 -0
  287. package/dist/tests/commands/snapshot.test.js +280 -0
  288. package/dist/tests/commands/snapshot.test.js.map +1 -0
  289. package/dist/tests/commands/user.test.d.ts +2 -0
  290. package/dist/tests/commands/user.test.d.ts.map +1 -0
  291. package/dist/tests/commands/user.test.js +117 -0
  292. package/dist/tests/commands/user.test.js.map +1 -0
  293. package/dist/tests/commands/workspace.test.d.ts +2 -0
  294. package/dist/tests/commands/workspace.test.d.ts.map +1 -0
  295. package/dist/tests/commands/workspace.test.js +453 -0
  296. package/dist/tests/commands/workspace.test.js.map +1 -0
  297. package/dist/tests/credential-manager.test.d.ts +2 -0
  298. package/dist/tests/credential-manager.test.d.ts.map +1 -0
  299. package/dist/tests/credential-manager.test.js +199 -0
  300. package/dist/tests/credential-manager.test.js.map +1 -0
  301. package/dist/tests/slack-client.test.d.ts +2 -0
  302. package/dist/tests/slack-client.test.d.ts.map +1 -0
  303. package/dist/tests/slack-client.test.js +741 -0
  304. package/dist/tests/slack-client.test.js.map +1 -0
  305. package/dist/tests/types.test.d.ts +2 -0
  306. package/dist/tests/types.test.d.ts.map +1 -0
  307. package/dist/tests/types.test.js +215 -0
  308. package/dist/tests/types.test.js.map +1 -0
  309. package/dist/types/index.d.ts +369 -0
  310. package/dist/types/index.d.ts.map +1 -0
  311. package/dist/types/index.js +92 -0
  312. package/dist/types/index.js.map +1 -0
  313. package/dist/utils/error-handler.d.ts +2 -0
  314. package/dist/utils/error-handler.d.ts.map +1 -0
  315. package/dist/utils/error-handler.js +5 -0
  316. package/dist/utils/error-handler.js.map +1 -0
  317. package/dist/utils/output.d.ts +2 -0
  318. package/dist/utils/output.d.ts.map +1 -0
  319. package/dist/utils/output.js +4 -0
  320. package/dist/utils/output.js.map +1 -0
  321. package/docs/discord.md +182 -0
  322. package/docs/slack.md +160 -0
  323. package/package.json +37 -0
  324. package/skills/agent-discord/SKILL.md +273 -0
  325. package/skills/agent-discord/references/authentication.md +294 -0
  326. package/skills/agent-discord/references/common-patterns.md +455 -0
  327. package/skills/agent-discord/templates/guild-summary.sh +167 -0
  328. package/skills/agent-discord/templates/monitor-channel.sh +180 -0
  329. package/skills/agent-discord/templates/post-message.sh +173 -0
  330. package/skills/agent-slack/SKILL.md +268 -0
  331. package/skills/agent-slack/references/authentication.md +332 -0
  332. package/skills/agent-slack/references/common-patterns.md +527 -0
  333. package/skills/agent-slack/templates/monitor-channel.sh +186 -0
  334. package/skills/agent-slack/templates/post-message.sh +130 -0
  335. package/skills/agent-slack/templates/workspace-summary.sh +149 -0
  336. package/src/cli.ts +29 -0
  337. package/src/platforms/discord/cli.ts +36 -0
  338. package/src/platforms/discord/client.test.ts +456 -0
  339. package/src/platforms/discord/client.ts +281 -0
  340. package/src/platforms/discord/commands/auth.test.ts +72 -0
  341. package/src/platforms/discord/commands/auth.ts +206 -0
  342. package/src/platforms/discord/commands/channel.test.ts +153 -0
  343. package/src/platforms/discord/commands/channel.ts +127 -0
  344. package/src/platforms/discord/commands/file.test.ts +98 -0
  345. package/src/platforms/discord/commands/file.ts +134 -0
  346. package/src/platforms/discord/commands/guild.test.ts +117 -0
  347. package/src/platforms/discord/commands/guild.ts +129 -0
  348. package/src/platforms/discord/commands/index.ts +8 -0
  349. package/src/platforms/discord/commands/message.test.ts +107 -0
  350. package/src/platforms/discord/commands/message.ts +182 -0
  351. package/src/platforms/discord/commands/reaction.test.ts +123 -0
  352. package/src/platforms/discord/commands/reaction.ts +156 -0
  353. package/src/platforms/discord/commands/snapshot.test.ts +29 -0
  354. package/src/platforms/discord/commands/snapshot.ts +104 -0
  355. package/src/platforms/discord/commands/user.test.ts +115 -0
  356. package/src/platforms/discord/commands/user.ts +124 -0
  357. package/src/platforms/discord/credential-manager.test.ts +173 -0
  358. package/src/platforms/discord/credential-manager.ts +95 -0
  359. package/src/platforms/discord/token-extractor.test.ts +918 -0
  360. package/src/platforms/discord/token-extractor.ts +549 -0
  361. package/src/platforms/discord/types.test.ts +245 -0
  362. package/src/platforms/discord/types.ts +158 -0
  363. package/src/platforms/slack/cli.ts +36 -0
  364. package/src/platforms/slack/client.ts +466 -0
  365. package/src/platforms/slack/commands/auth.ts +211 -0
  366. package/src/platforms/slack/commands/channel.ts +158 -0
  367. package/src/platforms/slack/commands/file.ts +153 -0
  368. package/src/platforms/slack/commands/index.ts +8 -0
  369. package/src/platforms/slack/commands/message.ts +369 -0
  370. package/src/platforms/slack/commands/reaction.ts +166 -0
  371. package/src/platforms/slack/commands/snapshot.ts +114 -0
  372. package/src/platforms/slack/commands/user.ts +110 -0
  373. package/src/platforms/slack/commands/workspace.ts +111 -0
  374. package/src/platforms/slack/credential-manager.ts +74 -0
  375. package/src/platforms/slack/index.ts +2 -0
  376. package/src/platforms/slack/token-extractor.ts +496 -0
  377. package/src/platforms/slack/types.ts +193 -0
  378. package/src/shared/utils/concurrency.test.ts +53 -0
  379. package/src/shared/utils/concurrency.ts +20 -0
  380. package/src/shared/utils/error-handler.ts +4 -0
  381. package/src/shared/utils/output.ts +3 -0
  382. package/tests/cli.test.ts +94 -0
  383. package/tests/commands/auth.test.ts +383 -0
  384. package/tests/commands/channel.test.ts +185 -0
  385. package/tests/commands/file.test.ts +204 -0
  386. package/tests/commands/message.test.ts +344 -0
  387. package/tests/commands/reaction.test.ts +101 -0
  388. package/tests/commands/snapshot.test.ts +308 -0
  389. package/tests/commands/user.test.ts +138 -0
  390. package/tests/commands/workspace.test.ts +528 -0
  391. package/tests/credential-manager.test.ts +241 -0
  392. package/tests/slack-client.test.ts +916 -0
  393. package/tests/types.test.ts +241 -0
  394. package/tsconfig.json +36 -0
@@ -0,0 +1,107 @@
1
+ import { beforeEach, expect, mock, test } from 'bun:test'
2
+ import { deleteAction, getAction, listAction, sendAction } from './message'
3
+
4
+ mock.module('../client', () => ({
5
+ DiscordClient: mock(() => ({
6
+ sendMessage: mock(async () => ({
7
+ id: 'msg_123',
8
+ channel_id: 'ch_456',
9
+ author: { id: 'user_789', username: 'testuser' },
10
+ content: 'Hello world',
11
+ timestamp: '2025-01-29T10:00:00Z',
12
+ })),
13
+ getMessages: mock(async () => [
14
+ {
15
+ id: 'msg_123',
16
+ channel_id: 'ch_456',
17
+ author: { id: 'user_789', username: 'testuser' },
18
+ content: 'Hello world',
19
+ timestamp: '2025-01-29T10:00:00Z',
20
+ },
21
+ {
22
+ id: 'msg_124',
23
+ channel_id: 'ch_456',
24
+ author: { id: 'user_789', username: 'testuser' },
25
+ content: 'Second message',
26
+ timestamp: '2025-01-29T10:01:00Z',
27
+ },
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
+ }))
59
+
60
+ beforeEach(() => {
61
+ mock.restore()
62
+ })
63
+
64
+ test('send: returns message with id', async () => {
65
+ const consoleSpy = mock((_msg: string) => {})
66
+ console.log = consoleSpy
67
+
68
+ await sendAction('ch_456', 'Hello world', { pretty: false })
69
+
70
+ expect(consoleSpy).toHaveBeenCalled()
71
+ const output = consoleSpy.mock.calls[0][0]
72
+ expect(output).toContain('msg_123')
73
+ })
74
+
75
+ test('list: returns array of messages', async () => {
76
+ const consoleSpy = mock((_msg: string) => {})
77
+ console.log = consoleSpy
78
+
79
+ await listAction('ch_456', { limit: 50, pretty: false })
80
+
81
+ expect(consoleSpy).toHaveBeenCalled()
82
+ const output = consoleSpy.mock.calls[0][0]
83
+ expect(output).toContain('msg_123')
84
+ expect(output).toContain('msg_124')
85
+ })
86
+
87
+ test('get: returns single message', async () => {
88
+ const consoleSpy = mock((_msg: string) => {})
89
+ console.log = consoleSpy
90
+
91
+ await getAction('ch_456', 'msg_123', { pretty: false })
92
+
93
+ expect(consoleSpy).toHaveBeenCalled()
94
+ const output = consoleSpy.mock.calls[0][0]
95
+ expect(output).toContain('msg_123')
96
+ })
97
+
98
+ test('delete: returns success', async () => {
99
+ const consoleSpy = mock((_msg: string) => {})
100
+ console.log = consoleSpy
101
+
102
+ await deleteAction('ch_456', 'msg_123', { force: true, pretty: false })
103
+
104
+ expect(consoleSpy).toHaveBeenCalled()
105
+ const output = consoleSpy.mock.calls[0][0]
106
+ expect(output).toContain('deleted')
107
+ })
@@ -0,0 +1,182 @@
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
+ import type { DiscordMessage } from '../types'
7
+
8
+ export async function sendAction(
9
+ channelId: string,
10
+ content: string,
11
+ options: { pretty?: boolean }
12
+ ): Promise<void> {
13
+ try {
14
+ const credManager = new DiscordCredentialManager()
15
+ const config = await credManager.load()
16
+
17
+ if (!config.token) {
18
+ console.log(
19
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
20
+ )
21
+ process.exit(1)
22
+ }
23
+
24
+ const client = new DiscordClient(config.token)
25
+ const message = await client.sendMessage(channelId, content)
26
+
27
+ const output = {
28
+ id: message.id,
29
+ content: message.content,
30
+ author: message.author.username,
31
+ timestamp: message.timestamp,
32
+ }
33
+
34
+ console.log(formatOutput(output, options.pretty))
35
+ } catch (error) {
36
+ handleError(error as Error)
37
+ }
38
+ }
39
+
40
+ export async function listAction(
41
+ channelId: string,
42
+ options: { limit?: number; pretty?: boolean }
43
+ ): Promise<void> {
44
+ try {
45
+ const credManager = new DiscordCredentialManager()
46
+ const config = await credManager.load()
47
+
48
+ if (!config.token) {
49
+ console.log(
50
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
51
+ )
52
+ process.exit(1)
53
+ }
54
+
55
+ const client = new DiscordClient(config.token)
56
+ const limit = options.limit || 50
57
+ const messages = await client.getMessages(channelId, limit)
58
+
59
+ const output = messages.map((msg: DiscordMessage) => ({
60
+ id: msg.id,
61
+ content: msg.content,
62
+ author: msg.author.username,
63
+ timestamp: msg.timestamp,
64
+ thread_id: msg.thread_id || null,
65
+ }))
66
+
67
+ console.log(formatOutput(output, options.pretty))
68
+ } catch (error) {
69
+ handleError(error as Error)
70
+ }
71
+ }
72
+
73
+ export async function getAction(
74
+ channelId: string,
75
+ messageId: string,
76
+ options: { pretty?: boolean }
77
+ ): Promise<void> {
78
+ try {
79
+ const credManager = new DiscordCredentialManager()
80
+ const config = await credManager.load()
81
+
82
+ if (!config.token) {
83
+ console.log(
84
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
85
+ )
86
+ process.exit(1)
87
+ }
88
+
89
+ const client = new DiscordClient(config.token)
90
+ const message = await client.getMessage(channelId, messageId)
91
+
92
+ if (!message) {
93
+ console.log(formatOutput({ error: `Message not found: ${messageId}` }, options.pretty))
94
+ process.exit(1)
95
+ }
96
+
97
+ const output = {
98
+ id: message.id,
99
+ content: message.content,
100
+ author: message.author.username,
101
+ timestamp: message.timestamp,
102
+ thread_id: message.thread_id || null,
103
+ }
104
+
105
+ console.log(formatOutput(output, options.pretty))
106
+ } catch (error) {
107
+ handleError(error as Error)
108
+ }
109
+ }
110
+
111
+ export async function deleteAction(
112
+ channelId: string,
113
+ messageId: string,
114
+ options: { force?: boolean; pretty?: boolean }
115
+ ): Promise<void> {
116
+ try {
117
+ const credManager = new DiscordCredentialManager()
118
+ const config = await credManager.load()
119
+
120
+ if (!config.token) {
121
+ console.log(
122
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
123
+ )
124
+ process.exit(1)
125
+ }
126
+
127
+ if (!options.force) {
128
+ console.log(
129
+ formatOutput({ warning: 'Use --force to confirm deletion', messageId }, options.pretty)
130
+ )
131
+ process.exit(0)
132
+ }
133
+
134
+ const client = new DiscordClient(config.token)
135
+ await client.deleteMessage(channelId, messageId)
136
+
137
+ console.log(formatOutput({ deleted: messageId }, options.pretty))
138
+ } catch (error) {
139
+ handleError(error as Error)
140
+ }
141
+ }
142
+
143
+ export const messageCommand = new Command('message')
144
+ .description('Message commands')
145
+ .addCommand(
146
+ new Command('send')
147
+ .description('Send message to channel')
148
+ .argument('<channel-id>', 'Channel ID')
149
+ .argument('<content>', 'Message content')
150
+ .option('--pretty', 'Pretty print JSON output')
151
+ .action(sendAction)
152
+ )
153
+ .addCommand(
154
+ new Command('list')
155
+ .description('List messages from channel')
156
+ .argument('<channel-id>', 'Channel ID')
157
+ .option('--limit <n>', 'Number of messages to retrieve', '50')
158
+ .option('--pretty', 'Pretty print JSON output')
159
+ .action((channelId: string, options: any) => {
160
+ listAction(channelId, {
161
+ limit: parseInt(options.limit, 10),
162
+ pretty: options.pretty,
163
+ })
164
+ })
165
+ )
166
+ .addCommand(
167
+ new Command('get')
168
+ .description('Get a single message by ID')
169
+ .argument('<channel-id>', 'Channel ID')
170
+ .argument('<message-id>', 'Message ID')
171
+ .option('--pretty', 'Pretty print JSON output')
172
+ .action(getAction)
173
+ )
174
+ .addCommand(
175
+ new Command('delete')
176
+ .description('Delete message')
177
+ .argument('<channel-id>', 'Channel ID')
178
+ .argument('<message-id>', 'Message ID')
179
+ .option('--force', 'Skip confirmation')
180
+ .option('--pretty', 'Pretty print JSON output')
181
+ .action(deleteAction)
182
+ )
@@ -0,0 +1,123 @@
1
+ import { expect, mock, test } from 'bun:test'
2
+ import { addAction, listAction, removeAction } from './reaction'
3
+
4
+ // Mock modules
5
+ mock.module('../client', () => ({
6
+ DiscordClient: mock(() => ({
7
+ addReaction: mock(async () => {}),
8
+ removeReaction: mock(async () => {}),
9
+ getMessage: mock(async () => ({
10
+ id: 'msg123',
11
+ channel_id: 'ch123',
12
+ author: { id: 'user123', username: 'testuser' },
13
+ content: 'test message',
14
+ timestamp: '2024-01-01T00:00:00Z',
15
+ reactions: [
16
+ {
17
+ emoji: { name: 'thumbsup', id: undefined },
18
+ count: 2,
19
+ },
20
+ {
21
+ emoji: { name: 'heart', id: undefined },
22
+ count: 1,
23
+ },
24
+ ],
25
+ })),
26
+ })),
27
+ }))
28
+
29
+ mock.module('../credential-manager', () => ({
30
+ DiscordCredentialManager: mock(() => ({
31
+ load: mock(async () => ({
32
+ token: 'test-token',
33
+ })),
34
+ })),
35
+ }))
36
+
37
+ test('add: sends correct PUT request with emoji', async () => {
38
+ const consoleSpy = mock((_msg: string) => {})
39
+ const originalLog = console.log
40
+ console.log = consoleSpy
41
+
42
+ try {
43
+ await addAction('ch123', 'msg123', 'thumbsup', { pretty: false })
44
+ expect(consoleSpy).toHaveBeenCalled()
45
+ const output = JSON.parse(consoleSpy.mock.calls[0][0])
46
+ expect(output.success).toBe(true)
47
+ expect(output.channel_id).toBe('ch123')
48
+ expect(output.message_id).toBe('msg123')
49
+ expect(output.emoji).toBe('thumbsup')
50
+ } finally {
51
+ console.log = originalLog
52
+ }
53
+ })
54
+
55
+ test('remove: sends correct DELETE request with emoji', async () => {
56
+ const consoleSpy = mock((_msg: string) => {})
57
+ const originalLog = console.log
58
+ console.log = consoleSpy
59
+
60
+ try {
61
+ await removeAction('ch123', 'msg123', 'thumbsup', { pretty: false })
62
+ expect(consoleSpy).toHaveBeenCalled()
63
+ const output = JSON.parse(consoleSpy.mock.calls[0][0])
64
+ expect(output.success).toBe(true)
65
+ expect(output.channel_id).toBe('ch123')
66
+ expect(output.message_id).toBe('msg123')
67
+ expect(output.emoji).toBe('thumbsup')
68
+ } finally {
69
+ console.log = originalLog
70
+ }
71
+ })
72
+
73
+ test('list: extracts reactions from message', async () => {
74
+ const consoleSpy = mock((_msg: string) => {})
75
+ const originalLog = console.log
76
+ console.log = consoleSpy
77
+
78
+ try {
79
+ await listAction('ch123', 'msg123', { pretty: false })
80
+ expect(consoleSpy).toHaveBeenCalled()
81
+ const output = JSON.parse(consoleSpy.mock.calls[0][0])
82
+ expect(output.channel_id).toBe('ch123')
83
+ expect(output.message_id).toBe('msg123')
84
+ expect(Array.isArray(output.reactions)).toBe(true)
85
+ expect(output.reactions.length).toBe(2)
86
+ expect(output.reactions[0].emoji.name).toBe('thumbsup')
87
+ expect(output.reactions[0].count).toBe(2)
88
+ } finally {
89
+ console.log = originalLog
90
+ }
91
+ })
92
+
93
+ test('add: handles missing token gracefully', async () => {
94
+ const credManagerMock = mock(() => ({
95
+ load: mock(async () => ({
96
+ token: null,
97
+ })),
98
+ }))
99
+
100
+ mock.module('../credential-manager', () => ({
101
+ DiscordCredentialManager: credManagerMock,
102
+ }))
103
+
104
+ const consoleSpy = mock((_msg: string) => {})
105
+ const originalLog = console.log
106
+ const originalExit = process.exit
107
+ let _exitCode = 0
108
+ process.exit = mock((code: number) => {
109
+ _exitCode = code
110
+ }) as any
111
+
112
+ console.log = consoleSpy
113
+
114
+ try {
115
+ await addAction('ch123', 'msg123', 'thumbsup', { pretty: false })
116
+ expect(consoleSpy).toHaveBeenCalled()
117
+ const output = JSON.parse(consoleSpy.mock.calls[0][0])
118
+ expect(output.error).toBeDefined()
119
+ } finally {
120
+ console.log = originalLog
121
+ process.exit = originalExit
122
+ }
123
+ })
@@ -0,0 +1,156 @@
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 addAction(
8
+ channelId: string,
9
+ messageId: string,
10
+ emoji: string,
11
+ options: { pretty?: boolean }
12
+ ): Promise<void> {
13
+ try {
14
+ const credManager = new DiscordCredentialManager()
15
+ const config = await credManager.load()
16
+
17
+ if (!config.token) {
18
+ console.log(
19
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
20
+ )
21
+ process.exit(1)
22
+ }
23
+
24
+ const client = new DiscordClient(config.token)
25
+ await client.addReaction(channelId, messageId, emoji)
26
+
27
+ console.log(
28
+ formatOutput(
29
+ {
30
+ success: true,
31
+ channel_id: channelId,
32
+ message_id: messageId,
33
+ emoji,
34
+ },
35
+ options.pretty
36
+ )
37
+ )
38
+ } catch (error) {
39
+ handleError(error as Error)
40
+ }
41
+ }
42
+
43
+ export async function removeAction(
44
+ channelId: string,
45
+ messageId: string,
46
+ emoji: string,
47
+ options: { pretty?: boolean }
48
+ ): Promise<void> {
49
+ try {
50
+ const credManager = new DiscordCredentialManager()
51
+ const config = await credManager.load()
52
+
53
+ if (!config.token) {
54
+ console.log(
55
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
56
+ )
57
+ process.exit(1)
58
+ }
59
+
60
+ const client = new DiscordClient(config.token)
61
+ await client.removeReaction(channelId, messageId, emoji)
62
+
63
+ console.log(
64
+ formatOutput(
65
+ {
66
+ success: true,
67
+ channel_id: channelId,
68
+ message_id: messageId,
69
+ emoji,
70
+ },
71
+ options.pretty
72
+ )
73
+ )
74
+ } catch (error) {
75
+ handleError(error as Error)
76
+ }
77
+ }
78
+
79
+ export async function listAction(
80
+ channelId: string,
81
+ messageId: string,
82
+ options: { pretty?: boolean }
83
+ ): Promise<void> {
84
+ try {
85
+ const credManager = new DiscordCredentialManager()
86
+ const config = await credManager.load()
87
+
88
+ if (!config.token) {
89
+ console.log(
90
+ formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
91
+ )
92
+ process.exit(1)
93
+ }
94
+
95
+ const client = new DiscordClient(config.token)
96
+ const message = await client.getMessage(channelId, messageId)
97
+
98
+ if (!message) {
99
+ console.log(
100
+ formatOutput(
101
+ {
102
+ error: 'Message not found',
103
+ channel_id: channelId,
104
+ message_id: messageId,
105
+ },
106
+ options.pretty
107
+ )
108
+ )
109
+ process.exit(1)
110
+ }
111
+
112
+ const reactions = (message as any).reactions || []
113
+
114
+ console.log(
115
+ formatOutput(
116
+ {
117
+ channel_id: channelId,
118
+ message_id: messageId,
119
+ reactions,
120
+ },
121
+ options.pretty
122
+ )
123
+ )
124
+ } catch (error) {
125
+ handleError(error as Error)
126
+ }
127
+ }
128
+
129
+ export const reactionCommand = new Command('reaction')
130
+ .description('Reaction commands')
131
+ .addCommand(
132
+ new Command('add')
133
+ .description('Add emoji reaction to message')
134
+ .argument('<channel-id>', 'Channel ID')
135
+ .argument('<message-id>', 'Message ID')
136
+ .argument('<emoji>', 'Emoji name (without colons)')
137
+ .option('--pretty', 'Pretty print JSON output')
138
+ .action(addAction)
139
+ )
140
+ .addCommand(
141
+ new Command('remove')
142
+ .description('Remove emoji reaction from message')
143
+ .argument('<channel-id>', 'Channel ID')
144
+ .argument('<message-id>', 'Message ID')
145
+ .argument('<emoji>', 'Emoji name (without colons)')
146
+ .option('--pretty', 'Pretty print JSON output')
147
+ .action(removeAction)
148
+ )
149
+ .addCommand(
150
+ new Command('list')
151
+ .description('List reactions on a message')
152
+ .argument('<channel-id>', 'Channel ID')
153
+ .argument('<message-id>', 'Message ID')
154
+ .option('--pretty', 'Pretty print JSON output')
155
+ .action(listAction)
156
+ )
@@ -0,0 +1,29 @@
1
+ import { expect, test } from 'bun:test'
2
+ import { snapshotCommand } from './snapshot'
3
+
4
+ test('snapshot: command is defined', () => {
5
+ expect(snapshotCommand).toBeDefined()
6
+ expect(snapshotCommand.name()).toBe('snapshot')
7
+ })
8
+
9
+ test('snapshot: command has correct description', () => {
10
+ expect(snapshotCommand.description()).toContain('guild state')
11
+ })
12
+
13
+ test('snapshot: command has --channels-only option', () => {
14
+ const options = snapshotCommand.options
15
+ const channelsOnlyOption = options.find((opt) => opt.long === '--channels-only')
16
+ expect(channelsOnlyOption).toBeDefined()
17
+ })
18
+
19
+ test('snapshot: command has --users-only option', () => {
20
+ const options = snapshotCommand.options
21
+ const usersOnlyOption = options.find((opt) => opt.long === '--users-only')
22
+ expect(usersOnlyOption).toBeDefined()
23
+ })
24
+
25
+ test('snapshot: command has --limit option', () => {
26
+ const options = snapshotCommand.options
27
+ const limitOption = options.find((opt) => opt.long === '--limit')
28
+ expect(limitOption).toBeDefined()
29
+ })
@@ -0,0 +1,104 @@
1
+ import { Command } from 'commander'
2
+ import { parallelMap } from '../../../shared/utils/concurrency'
3
+ import { handleError } from '../../../shared/utils/error-handler'
4
+ import { formatOutput } from '../../../shared/utils/output'
5
+ import { DiscordClient } from '../client'
6
+ import { DiscordCredentialManager } from '../credential-manager'
7
+ import type { DiscordChannel } from '../types'
8
+
9
+ export async function snapshotAction(options: {
10
+ channelsOnly?: boolean
11
+ usersOnly?: boolean
12
+ limit?: number
13
+ pretty?: boolean
14
+ }): Promise<void> {
15
+ try {
16
+ const credManager = new DiscordCredentialManager()
17
+ const config = await credManager.load()
18
+
19
+ if (!config.token || !config.current_guild) {
20
+ console.log(
21
+ formatOutput({ error: 'No current guild set. Run "guild switch" first.' }, options.pretty)
22
+ )
23
+ process.exit(1)
24
+ }
25
+
26
+ const client = new DiscordClient(config.token as string)
27
+ const guildId = config.current_guild as string
28
+ const messageLimit = options.limit || 20
29
+
30
+ const snapshot: Record<string, any> = {}
31
+
32
+ const guild = await client.getGuild(guildId)
33
+ snapshot.guild = {
34
+ id: guild.id,
35
+ name: guild.name,
36
+ }
37
+
38
+ if (!options.usersOnly) {
39
+ const channels = await client.listChannels(guildId)
40
+
41
+ snapshot.channels = channels.map((ch) => ({
42
+ id: ch.id,
43
+ name: ch.name,
44
+ type: ch.type,
45
+ topic: ch.topic,
46
+ }))
47
+
48
+ if (!options.channelsOnly) {
49
+ const isTextChannel = (ch: DiscordChannel) => ch.type === 0 || ch.type === 5
50
+ const textChannels = channels.filter(isTextChannel)
51
+
52
+ const channelMessages = await parallelMap(
53
+ textChannels,
54
+ async (channel: DiscordChannel) => {
55
+ const messages = await client.getMessages(channel.id, messageLimit)
56
+ return messages.map((msg) => ({
57
+ ...msg,
58
+ channel_name: channel.name,
59
+ }))
60
+ },
61
+ 5
62
+ )
63
+
64
+ snapshot.recent_messages = channelMessages.flat().map((msg) => ({
65
+ channel_id: msg.channel_id,
66
+ channel_name: msg.channel_name,
67
+ id: msg.id,
68
+ author: msg.author.username,
69
+ content: msg.content,
70
+ timestamp: msg.timestamp,
71
+ }))
72
+ }
73
+ }
74
+
75
+ if (!options.channelsOnly) {
76
+ const users = await client.listUsers(guildId)
77
+
78
+ snapshot.members = users.map((u) => ({
79
+ id: u.id,
80
+ username: u.username,
81
+ global_name: u.global_name || null,
82
+ }))
83
+ }
84
+
85
+ console.log(formatOutput(snapshot, options.pretty))
86
+ } catch (error) {
87
+ handleError(error as Error)
88
+ }
89
+ }
90
+
91
+ export const snapshotCommand = new Command()
92
+ .name('snapshot')
93
+ .description('Get comprehensive guild state for AI agents')
94
+ .option('--channels-only', 'Include only channels (exclude messages and members)')
95
+ .option('--users-only', 'Include only members (exclude channels and messages)')
96
+ .option('--limit <n>', 'Number of recent messages per channel (default: 20)', '20')
97
+ .action(async (options) => {
98
+ await snapshotAction({
99
+ channelsOnly: options.channelsOnly,
100
+ usersOnly: options.usersOnly,
101
+ limit: parseInt(options.limit, 10),
102
+ pretty: options.pretty,
103
+ })
104
+ })