agent-messenger 1.2.0 → 1.3.1

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 (271) hide show
  1. package/.claude-plugin/marketplace.json +27 -1
  2. package/.claude-plugin/plugin.json +17 -4
  3. package/.env.template +3 -0
  4. package/.github/workflows/release.yml +94 -0
  5. package/AGENTS.md +48 -0
  6. package/README.md +25 -20
  7. package/biome.json +15 -39
  8. package/bun.lock +69 -0
  9. package/dist/package.json +12 -4
  10. package/dist/src/cli.d.ts.map +1 -1
  11. package/dist/src/cli.js +1 -4
  12. package/dist/src/cli.js.map +1 -1
  13. package/dist/src/platforms/discord/client.d.ts.map +1 -1
  14. package/dist/src/platforms/discord/client.js.map +1 -1
  15. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  16. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  17. package/dist/src/platforms/discord/commands/channel.d.ts.map +1 -1
  18. package/dist/src/platforms/discord/commands/channel.js.map +1 -1
  19. package/dist/src/platforms/discord/commands/dm.d.ts.map +1 -1
  20. package/dist/src/platforms/discord/commands/dm.js.map +1 -1
  21. package/dist/src/platforms/discord/commands/file.d.ts.map +1 -1
  22. package/dist/src/platforms/discord/commands/file.js +1 -4
  23. package/dist/src/platforms/discord/commands/file.js.map +1 -1
  24. package/dist/src/platforms/discord/commands/friend.d.ts.map +1 -1
  25. package/dist/src/platforms/discord/commands/friend.js +1 -3
  26. package/dist/src/platforms/discord/commands/friend.js.map +1 -1
  27. package/dist/src/platforms/discord/commands/member.d.ts.map +1 -1
  28. package/dist/src/platforms/discord/commands/member.js.map +1 -1
  29. package/dist/src/platforms/discord/commands/mention.d.ts.map +1 -1
  30. package/dist/src/platforms/discord/commands/mention.js.map +1 -1
  31. package/dist/src/platforms/discord/commands/message.d.ts.map +1 -1
  32. package/dist/src/platforms/discord/commands/message.js.map +1 -1
  33. package/dist/src/platforms/discord/commands/note.d.ts.map +1 -1
  34. package/dist/src/platforms/discord/commands/note.js.map +1 -1
  35. package/dist/src/platforms/discord/commands/profile.d.ts.map +1 -1
  36. package/dist/src/platforms/discord/commands/profile.js.map +1 -1
  37. package/dist/src/platforms/discord/commands/reaction.d.ts.map +1 -1
  38. package/dist/src/platforms/discord/commands/reaction.js.map +1 -1
  39. package/dist/src/platforms/discord/commands/server.d.ts.map +1 -1
  40. package/dist/src/platforms/discord/commands/server.js.map +1 -1
  41. package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -1
  42. package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
  43. package/dist/src/platforms/discord/commands/thread.d.ts.map +1 -1
  44. package/dist/src/platforms/discord/commands/thread.js.map +1 -1
  45. package/dist/src/platforms/discord/commands/user.d.ts.map +1 -1
  46. package/dist/src/platforms/discord/commands/user.js.map +1 -1
  47. package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -1
  48. package/dist/src/platforms/discord/credential-manager.js.map +1 -1
  49. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  50. package/dist/src/platforms/discord/token-extractor.js +2 -7
  51. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  52. package/dist/src/platforms/slack/client.d.ts.map +1 -1
  53. package/dist/src/platforms/slack/client.js.map +1 -1
  54. package/dist/src/platforms/slack/commands/activity.d.ts.map +1 -1
  55. package/dist/src/platforms/slack/commands/activity.js.map +1 -1
  56. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  57. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  58. package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
  59. package/dist/src/platforms/slack/commands/channel.js.map +1 -1
  60. package/dist/src/platforms/slack/commands/drafts.d.ts.map +1 -1
  61. package/dist/src/platforms/slack/commands/drafts.js.map +1 -1
  62. package/dist/src/platforms/slack/commands/file.d.ts.map +1 -1
  63. package/dist/src/platforms/slack/commands/file.js +1 -4
  64. package/dist/src/platforms/slack/commands/file.js.map +1 -1
  65. package/dist/src/platforms/slack/commands/message.d.ts.map +1 -1
  66. package/dist/src/platforms/slack/commands/message.js.map +1 -1
  67. package/dist/src/platforms/slack/commands/reaction.d.ts.map +1 -1
  68. package/dist/src/platforms/slack/commands/reaction.js.map +1 -1
  69. package/dist/src/platforms/slack/commands/saved.d.ts.map +1 -1
  70. package/dist/src/platforms/slack/commands/saved.js.map +1 -1
  71. package/dist/src/platforms/slack/commands/sections.d.ts.map +1 -1
  72. package/dist/src/platforms/slack/commands/sections.js.map +1 -1
  73. package/dist/src/platforms/slack/commands/snapshot.d.ts.map +1 -1
  74. package/dist/src/platforms/slack/commands/snapshot.js.map +1 -1
  75. package/dist/src/platforms/slack/commands/unread.d.ts.map +1 -1
  76. package/dist/src/platforms/slack/commands/unread.js.map +1 -1
  77. package/dist/src/platforms/slack/commands/user.d.ts.map +1 -1
  78. package/dist/src/platforms/slack/commands/user.js.map +1 -1
  79. package/dist/src/platforms/slack/commands/workspace.d.ts.map +1 -1
  80. package/dist/src/platforms/slack/commands/workspace.js.map +1 -1
  81. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  82. package/dist/src/platforms/slack/token-extractor.js +4 -5
  83. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  84. package/dist/src/platforms/slackbot/cli.d.ts +5 -0
  85. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -0
  86. package/dist/src/platforms/slackbot/cli.js +19 -0
  87. package/dist/src/platforms/slackbot/cli.js.map +1 -0
  88. package/dist/src/platforms/slackbot/client.d.ts +43 -0
  89. package/dist/src/platforms/slackbot/client.d.ts.map +1 -0
  90. package/dist/src/platforms/slackbot/client.js +347 -0
  91. package/dist/src/platforms/slackbot/client.js.map +1 -0
  92. package/dist/src/platforms/slackbot/commands/auth.d.ts +35 -0
  93. package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -0
  94. package/dist/src/platforms/slackbot/commands/auth.js +185 -0
  95. package/dist/src/platforms/slackbot/commands/auth.js.map +1 -0
  96. package/dist/src/platforms/slackbot/commands/channel.d.ts +3 -0
  97. package/dist/src/platforms/slackbot/commands/channel.d.ts.map +1 -0
  98. package/dist/src/platforms/slackbot/commands/channel.js +40 -0
  99. package/dist/src/platforms/slackbot/commands/channel.js.map +1 -0
  100. package/dist/src/platforms/slackbot/commands/index.d.ts +6 -0
  101. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -0
  102. package/dist/src/platforms/slackbot/commands/index.js +6 -0
  103. package/dist/src/platforms/slackbot/commands/index.js.map +1 -0
  104. package/dist/src/platforms/slackbot/commands/message.d.ts +3 -0
  105. package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -0
  106. package/dist/src/platforms/slackbot/commands/message.js +135 -0
  107. package/dist/src/platforms/slackbot/commands/message.js.map +1 -0
  108. package/dist/src/platforms/slackbot/commands/reaction.d.ts +3 -0
  109. package/dist/src/platforms/slackbot/commands/reaction.d.ts.map +1 -0
  110. package/dist/src/platforms/slackbot/commands/reaction.js +43 -0
  111. package/dist/src/platforms/slackbot/commands/reaction.js.map +1 -0
  112. package/dist/src/platforms/slackbot/commands/shared.d.ts +9 -0
  113. package/dist/src/platforms/slackbot/commands/shared.d.ts.map +1 -0
  114. package/dist/src/platforms/slackbot/commands/shared.js +13 -0
  115. package/dist/src/platforms/slackbot/commands/shared.js.map +1 -0
  116. package/dist/src/platforms/slackbot/commands/user.d.ts +3 -0
  117. package/dist/src/platforms/slackbot/commands/user.d.ts.map +1 -0
  118. package/dist/src/platforms/slackbot/commands/user.js +40 -0
  119. package/dist/src/platforms/slackbot/commands/user.js.map +1 -0
  120. package/dist/src/platforms/slackbot/credential-manager.d.ts +18 -0
  121. package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -0
  122. package/dist/src/platforms/slackbot/credential-manager.js +185 -0
  123. package/dist/src/platforms/slackbot/credential-manager.js.map +1 -0
  124. package/dist/src/platforms/slackbot/index.d.ts +4 -0
  125. package/dist/src/platforms/slackbot/index.d.ts.map +1 -0
  126. package/dist/src/platforms/slackbot/index.js +4 -0
  127. package/dist/src/platforms/slackbot/index.js.map +1 -0
  128. package/dist/src/platforms/slackbot/types.d.ts +460 -0
  129. package/dist/src/platforms/slackbot/types.d.ts.map +1 -0
  130. package/dist/src/platforms/slackbot/types.js +114 -0
  131. package/dist/src/platforms/slackbot/types.js.map +1 -0
  132. package/dist/src/platforms/teams/client.d.ts.map +1 -1
  133. package/dist/src/platforms/teams/client.js.map +1 -1
  134. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  135. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  136. package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -1
  137. package/dist/src/platforms/teams/commands/channel.js.map +1 -1
  138. package/dist/src/platforms/teams/commands/file.d.ts.map +1 -1
  139. package/dist/src/platforms/teams/commands/file.js.map +1 -1
  140. package/dist/src/platforms/teams/commands/message.d.ts.map +1 -1
  141. package/dist/src/platforms/teams/commands/message.js.map +1 -1
  142. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
  143. package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
  144. package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
  145. package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
  146. package/dist/src/platforms/teams/commands/team.d.ts.map +1 -1
  147. package/dist/src/platforms/teams/commands/team.js +1 -4
  148. package/dist/src/platforms/teams/commands/team.js.map +1 -1
  149. package/dist/src/platforms/teams/commands/user.d.ts.map +1 -1
  150. package/dist/src/platforms/teams/commands/user.js.map +1 -1
  151. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  152. package/dist/src/platforms/teams/token-extractor.js +3 -1
  153. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  154. package/docs/content/docs/agent-skills.mdx +4 -4
  155. package/docs/content/docs/index.mdx +11 -18
  156. package/docs/content/docs/integrations/discord.mdx +65 -1
  157. package/docs/content/docs/integrations/meta.json +1 -1
  158. package/docs/content/docs/integrations/slack.mdx +51 -1
  159. package/docs/content/docs/integrations/slackbot.mdx +214 -0
  160. package/docs/content/docs/integrations/teams.mdx +4 -1
  161. package/docs/content/docs/quick-start.mdx +3 -2
  162. package/docs/src/app/icon.png +0 -0
  163. package/docs/src/app/layout.config.tsx +8 -1
  164. package/docs/src/app/page.tsx +18 -1
  165. package/e2e/config.ts +26 -0
  166. package/e2e/helpers.ts +6 -1
  167. package/e2e/slackbot.e2e.test.ts +306 -0
  168. package/package.json +16 -8
  169. package/scripts/prepublish.ts +11 -0
  170. package/skills/agent-slackbot/SKILL.md +285 -0
  171. package/skills/agent-slackbot/references/authentication.md +253 -0
  172. package/skills/agent-slackbot/references/common-patterns.md +218 -0
  173. package/skills/agent-slackbot/templates/monitor-channel.sh +98 -0
  174. package/skills/agent-slackbot/templates/post-message.sh +107 -0
  175. package/skills/agent-slackbot/templates/workspace-summary.sh +113 -0
  176. package/src/cli.ts +1 -4
  177. package/src/platforms/discord/client.test.ts +6 -14
  178. package/src/platforms/discord/client.ts +12 -34
  179. package/src/platforms/discord/commands/auth.test.ts +2 -7
  180. package/src/platforms/discord/commands/auth.ts +14 -19
  181. package/src/platforms/discord/commands/channel.test.ts +18 -20
  182. package/src/platforms/discord/commands/channel.ts +9 -18
  183. package/src/platforms/discord/commands/dm.test.ts +1 -3
  184. package/src/platforms/discord/commands/dm.ts +6 -10
  185. package/src/platforms/discord/commands/file.ts +10 -23
  186. package/src/platforms/discord/commands/friend.ts +33 -35
  187. package/src/platforms/discord/commands/member.ts +5 -7
  188. package/src/platforms/discord/commands/mention.ts +5 -11
  189. package/src/platforms/discord/commands/message.test.ts +1 -3
  190. package/src/platforms/discord/commands/message.ts +23 -61
  191. package/src/platforms/discord/commands/note.ts +7 -15
  192. package/src/platforms/discord/commands/profile.ts +4 -6
  193. package/src/platforms/discord/commands/reaction.test.ts +1 -3
  194. package/src/platforms/discord/commands/reaction.ts +19 -29
  195. package/src/platforms/discord/commands/server.test.ts +14 -18
  196. package/src/platforms/discord/commands/server.ts +9 -15
  197. package/src/platforms/discord/commands/snapshot.ts +5 -7
  198. package/src/platforms/discord/commands/thread.ts +8 -15
  199. package/src/platforms/discord/commands/user.ts +9 -20
  200. package/src/platforms/discord/credential-manager.test.ts +2 -2
  201. package/src/platforms/discord/credential-manager.ts +1 -3
  202. package/src/platforms/discord/token-extractor.test.ts +28 -57
  203. package/src/platforms/discord/token-extractor.ts +10 -30
  204. package/src/platforms/discord/types.ts +1 -1
  205. package/src/platforms/slack/client.test.ts +14 -20
  206. package/src/platforms/slack/client.ts +4 -11
  207. package/src/platforms/slack/commands/activity.test.ts +3 -9
  208. package/src/platforms/slack/commands/activity.ts +7 -12
  209. package/src/platforms/slack/commands/auth.test.ts +2 -2
  210. package/src/platforms/slack/commands/auth.ts +15 -31
  211. package/src/platforms/slack/commands/channel.ts +10 -32
  212. package/src/platforms/slack/commands/drafts.ts +5 -14
  213. package/src/platforms/slack/commands/file.ts +9 -29
  214. package/src/platforms/slack/commands/message.ts +23 -67
  215. package/src/platforms/slack/commands/reaction.ts +19 -48
  216. package/src/platforms/slack/commands/saved.ts +5 -14
  217. package/src/platforms/slack/commands/sections.ts +4 -11
  218. package/src/platforms/slack/commands/snapshot.test.ts +1 -3
  219. package/src/platforms/slack/commands/snapshot.ts +5 -10
  220. package/src/platforms/slack/commands/unread.test.ts +6 -8
  221. package/src/platforms/slack/commands/unread.ts +10 -33
  222. package/src/platforms/slack/commands/user.test.ts +1 -4
  223. package/src/platforms/slack/commands/user.ts +6 -8
  224. package/src/platforms/slack/commands/workspace.test.ts +1 -1
  225. package/src/platforms/slack/commands/workspace.ts +7 -12
  226. package/src/platforms/slack/token-extractor-node-test.ts +1 -1
  227. package/src/platforms/slack/token-extractor.ts +8 -17
  228. package/src/platforms/slack/types.ts +1 -1
  229. package/src/platforms/slackbot/cli.ts +24 -0
  230. package/src/platforms/slackbot/client.test.ts +282 -0
  231. package/src/platforms/slackbot/client.ts +394 -0
  232. package/src/platforms/slackbot/commands/auth.test.ts +245 -0
  233. package/src/platforms/slackbot/commands/auth.ts +240 -0
  234. package/src/platforms/slackbot/commands/channel.ts +46 -0
  235. package/src/platforms/slackbot/commands/index.ts +5 -0
  236. package/src/platforms/slackbot/commands/message.ts +169 -0
  237. package/src/platforms/slackbot/commands/reaction.ts +49 -0
  238. package/src/platforms/slackbot/commands/shared.ts +21 -0
  239. package/src/platforms/slackbot/commands/user.ts +46 -0
  240. package/src/platforms/slackbot/credential-manager.test.ts +264 -0
  241. package/src/platforms/slackbot/credential-manager.ts +213 -0
  242. package/src/platforms/slackbot/index.ts +19 -0
  243. package/src/platforms/slackbot/types.test.ts +90 -0
  244. package/src/platforms/slackbot/types.ts +222 -0
  245. package/src/platforms/teams/client.test.ts +15 -32
  246. package/src/platforms/teams/client.ts +18 -51
  247. package/src/platforms/teams/commands/auth.test.ts +6 -16
  248. package/src/platforms/teams/commands/auth.ts +16 -26
  249. package/src/platforms/teams/commands/channel.test.ts +2 -5
  250. package/src/platforms/teams/commands/channel.ts +10 -20
  251. package/src/platforms/teams/commands/file.test.ts +1 -4
  252. package/src/platforms/teams/commands/file.ts +11 -21
  253. package/src/platforms/teams/commands/message.test.ts +1 -3
  254. package/src/platforms/teams/commands/message.ts +15 -25
  255. package/src/platforms/teams/commands/reaction.test.ts +2 -7
  256. package/src/platforms/teams/commands/reaction.ts +12 -16
  257. package/src/platforms/teams/commands/snapshot.ts +6 -11
  258. package/src/platforms/teams/commands/team.test.ts +15 -26
  259. package/src/platforms/teams/commands/team.ts +10 -19
  260. package/src/platforms/teams/commands/user.ts +8 -14
  261. package/src/platforms/teams/credential-manager.test.ts +2 -5
  262. package/src/platforms/teams/token-extractor.test.ts +21 -50
  263. package/src/platforms/teams/token-extractor.ts +12 -20
  264. package/src/platforms/teams/types.ts +1 -1
  265. package/src/shared/utils/concurrency.test.ts +2 -2
  266. package/src/shared/utils/concurrency.ts +1 -1
  267. package/.claude/commands/release.md +0 -92
  268. package/dist/src/platforms/discord/commands/guild.d.ts +0 -15
  269. package/dist/src/platforms/discord/commands/guild.d.ts.map +0 -1
  270. package/dist/src/platforms/discord/commands/guild.js +0 -102
  271. package/dist/src/platforms/discord/commands/guild.js.map +0 -1
@@ -0,0 +1,113 @@
1
+ #!/bin/bash
2
+ #
3
+ # workspace-summary.sh - Generate a workspace summary via bot token
4
+ #
5
+ # Usage:
6
+ # ./workspace-summary.sh [--json]
7
+ #
8
+ # Options:
9
+ # --json Output raw JSON instead of formatted text
10
+ #
11
+ # Example:
12
+ # ./workspace-summary.sh
13
+ # ./workspace-summary.sh --json > summary.json
14
+
15
+ set -euo pipefail
16
+
17
+ OUTPUT_JSON=false
18
+ if [ $# -gt 0 ] && [ "$1" = "--json" ]; then
19
+ OUTPUT_JSON=true
20
+ fi
21
+
22
+ RED='\033[0;31m'
23
+ GREEN='\033[0;32m'
24
+ YELLOW='\033[1;33m'
25
+ BLUE='\033[0;34m'
26
+ CYAN='\033[0;36m'
27
+ BOLD='\033[1m'
28
+ NC='\033[0m'
29
+
30
+ if ! command -v agent-slackbot &> /dev/null; then
31
+ echo -e "${RED}Error: agent-slackbot not found${NC}" >&2
32
+ echo "Install: npm install -g agent-messenger" >&2
33
+ exit 1
34
+ fi
35
+
36
+ AUTH_STATUS=$(agent-slackbot auth status 2>&1)
37
+ VALID=$(echo "$AUTH_STATUS" | jq -r '.valid // false')
38
+
39
+ if [ "$VALID" != "true" ]; then
40
+ echo -e "${RED}Not authenticated! Run: agent-slackbot auth set xoxb-your-token${NC}" >&2
41
+ exit 1
42
+ fi
43
+
44
+ WORKSPACE=$(echo "$AUTH_STATUS" | jq -r '.workspace_name // "Unknown"')
45
+ WORKSPACE_ID=$(echo "$AUTH_STATUS" | jq -r '.workspace_id // "Unknown"')
46
+ BOT_NAME=$(echo "$AUTH_STATUS" | jq -r '.user // "Unknown"')
47
+
48
+ echo -e "${YELLOW}Fetching workspace data...${NC}" >&2
49
+
50
+ CHANNELS=$(agent-slackbot channel list 2>&1)
51
+ CHANNEL_COUNT=$(echo "$CHANNELS" | jq 'length')
52
+ PUBLIC_COUNT=$(echo "$CHANNELS" | jq '[.[] | select(.is_private == false)] | length')
53
+ PRIVATE_COUNT=$(echo "$CHANNELS" | jq '[.[] | select(.is_private == true)] | length')
54
+
55
+ USERS=$(agent-slackbot user list 2>&1)
56
+ USER_COUNT=$(echo "$USERS" | jq 'length')
57
+
58
+ if [ "$OUTPUT_JSON" = true ]; then
59
+ jq -n \
60
+ --arg workspace "$WORKSPACE" \
61
+ --arg workspace_id "$WORKSPACE_ID" \
62
+ --arg bot "$BOT_NAME" \
63
+ --argjson channels "$CHANNELS" \
64
+ --argjson users "$USERS" \
65
+ '{
66
+ workspace: { name: $workspace, id: $workspace_id, bot: $bot },
67
+ channels: $channels,
68
+ users: $users
69
+ }'
70
+ exit 0
71
+ fi
72
+
73
+ echo ""
74
+ echo -e "${BOLD}${BLUE}Workspace Summary${NC}"
75
+ echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
76
+ echo ""
77
+ echo -e "${BOLD}Workspace:${NC} $WORKSPACE"
78
+ echo -e "${BOLD}ID:${NC} $WORKSPACE_ID"
79
+ echo -e "${BOLD}Bot:${NC} $BOT_NAME"
80
+ echo ""
81
+
82
+ echo -e "${BOLD}${CYAN}Channels (${CHANNEL_COUNT} total)${NC}"
83
+ echo -e " Public: $PUBLIC_COUNT"
84
+ echo -e " Private: $PRIVATE_COUNT"
85
+ echo ""
86
+
87
+ echo -e "${BOLD}${CYAN}Channel List:${NC}"
88
+ echo "$CHANNELS" | jq -r '.[0:10] | .[] | " #\(.name) (\(.id))"'
89
+ if [ "$CHANNEL_COUNT" -gt 10 ]; then
90
+ echo " ... and $((CHANNEL_COUNT - 10)) more"
91
+ fi
92
+ echo ""
93
+
94
+ echo -e "${BOLD}${CYAN}Users (${USER_COUNT} total)${NC}"
95
+ echo ""
96
+ echo "$USERS" | jq -r '.[0:10] | .[] | " \(.name) - \(.real_name // "N/A") (\(.id))"'
97
+ if [ "$USER_COUNT" -gt 10 ]; then
98
+ echo " ... and $((USER_COUNT - 10)) more"
99
+ fi
100
+ echo ""
101
+
102
+ echo -e "${BOLD}${CYAN}Quick Actions:${NC}"
103
+ echo ""
104
+ FIRST_CHANNEL=$(echo "$CHANNELS" | jq -r '.[0].id // "C123"')
105
+ FIRST_CHANNEL_NAME=$(echo "$CHANNELS" | jq -r '.[0].name // "general"')
106
+ echo -e " ${GREEN}# Send message to #$FIRST_CHANNEL_NAME${NC}"
107
+ echo -e " agent-slackbot message send $FIRST_CHANNEL \"Hello!\""
108
+ echo ""
109
+ echo -e " ${GREEN}# List recent messages${NC}"
110
+ echo -e " agent-slackbot message list $FIRST_CHANNEL --limit 10"
111
+ echo ""
112
+
113
+ echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
package/src/cli.ts CHANGED
@@ -10,10 +10,7 @@ const __dirname = dirname(__filename)
10
10
 
11
11
  const program = new Command()
12
12
 
13
- program
14
- .name('agent-messenger')
15
- .description('Multi-platform messaging CLI for AI agents')
16
- .version(pkg.version)
13
+ program.name('agent-messenger').description('Multi-platform messaging CLI for AI agents').version(pkg.version)
17
14
 
18
15
  // Use absolute paths for CWD-independence
19
16
  program.command('slack', 'Interact with Slack workspaces', {
@@ -11,10 +11,7 @@ describe('DiscordClient', () => {
11
11
  fetchCalls = []
12
12
  fetchResponses = []
13
13
  fetchIndex = 0
14
- ;(globalThis as any).fetch = async (
15
- url: string | URL | Request,
16
- options?: RequestInit
17
- ): Promise<Response> => {
14
+ ;(globalThis as any).fetch = async (url: string | URL | Request, options?: RequestInit): Promise<Response> => {
18
15
  fetchCalls.push({ url: url.toString(), options })
19
16
  const response = fetchResponses[fetchIndex]
20
17
  fetchIndex++
@@ -45,7 +42,7 @@ describe('DiscordClient', () => {
45
42
  new Response(body === null ? null : JSON.stringify(body), {
46
43
  status,
47
44
  headers: defaultHeaders,
48
- })
45
+ }),
49
46
  )
50
47
  }
51
48
 
@@ -236,7 +233,7 @@ describe('DiscordClient', () => {
236
233
  await client.addReaction('ch1', 'msg1', '👍')
237
234
 
238
235
  expect(fetchCalls[0].url).toBe(
239
- 'https://discord.com/api/v10/channels/ch1/messages/msg1/reactions/%F0%9F%91%8D/@me'
236
+ 'https://discord.com/api/v10/channels/ch1/messages/msg1/reactions/%F0%9F%91%8D/@me',
240
237
  )
241
238
  expect(fetchCalls[0].options?.method).toBe('PUT')
242
239
  })
@@ -250,7 +247,7 @@ describe('DiscordClient', () => {
250
247
  await client.removeReaction('ch1', 'msg1', '👍')
251
248
 
252
249
  expect(fetchCalls[0].url).toBe(
253
- 'https://discord.com/api/v10/channels/ch1/messages/msg1/reactions/%F0%9F%91%8D/@me'
250
+ 'https://discord.com/api/v10/channels/ch1/messages/msg1/reactions/%F0%9F%91%8D/@me',
254
251
  )
255
252
  expect(fetchCalls[0].options?.method).toBe('DELETE')
256
253
  })
@@ -258,10 +255,7 @@ describe('DiscordClient', () => {
258
255
 
259
256
  describe('listUsers', () => {
260
257
  test('returns list of server members', async () => {
261
- mockResponse([
262
- { user: { id: 'u1', username: 'user1' } },
263
- { user: { id: 'u2', username: 'user2' } },
264
- ])
258
+ mockResponse([{ user: { id: 'u1', username: 'user1' } }, { user: { id: 'u2', username: 'user2' } }])
265
259
 
266
260
  const client = new DiscordClient('test-token')
267
261
  const users = await client.listUsers('111')
@@ -324,9 +318,7 @@ describe('DiscordClient', () => {
324
318
  author: { id: '123', username: 'user1' },
325
319
  content: '',
326
320
  timestamp: '2024-01-01T00:00:00.000Z',
327
- attachments: [
328
- { id: 'att1', filename: 'file1.txt', size: 100, url: 'https://example.com/file1.txt' },
329
- ],
321
+ attachments: [{ id: 'att1', filename: 'file1.txt', size: 100, url: 'https://example.com/file1.txt' }],
330
322
  },
331
323
  {
332
324
  id: 'msg2',
@@ -143,7 +143,7 @@ export class DiscordClient {
143
143
  const errorBody = await response.json().catch(() => ({}))
144
144
  throw new DiscordError(
145
145
  (errorBody as any).message || `HTTP ${response.status}`,
146
- (errorBody as any).code?.toString() || `http_${response.status}`
146
+ (errorBody as any).code?.toString() || `http_${response.status}`,
147
147
  )
148
148
  }
149
149
 
@@ -176,7 +176,7 @@ export class DiscordClient {
176
176
  const errorBody = await response.json().catch(() => ({}))
177
177
  throw new DiscordError(
178
178
  (errorBody as any).message || `HTTP ${response.status}`,
179
- (errorBody as any).code?.toString() || `http_${response.status}`
179
+ (errorBody as any).code?.toString() || `http_${response.status}`,
180
180
  )
181
181
  }
182
182
 
@@ -221,18 +221,12 @@ export class DiscordClient {
221
221
 
222
222
  async addReaction(channelId: string, messageId: string, emoji: string): Promise<void> {
223
223
  const encodedEmoji = encodeURIComponent(emoji)
224
- return this.request<void>(
225
- 'PUT',
226
- `/channels/${channelId}/messages/${messageId}/reactions/${encodedEmoji}/@me`
227
- )
224
+ return this.request<void>('PUT', `/channels/${channelId}/messages/${messageId}/reactions/${encodedEmoji}/@me`)
228
225
  }
229
226
 
230
227
  async removeReaction(channelId: string, messageId: string, emoji: string): Promise<void> {
231
228
  const encodedEmoji = encodeURIComponent(emoji)
232
- return this.request<void>(
233
- 'DELETE',
234
- `/channels/${channelId}/messages/${messageId}/reactions/${encodedEmoji}/@me`
235
- )
229
+ return this.request<void>('DELETE', `/channels/${channelId}/messages/${messageId}/reactions/${encodedEmoji}/@me`)
236
230
  }
237
231
 
238
232
  async ackMessage(channelId: string, messageId: string): Promise<void> {
@@ -245,10 +239,7 @@ export class DiscordClient {
245
239
  interface GuildMember {
246
240
  user: DiscordUser
247
241
  }
248
- const members = await this.request<GuildMember[]>(
249
- 'GET',
250
- `/guilds/${serverId}/members?limit=1000`
251
- )
242
+ const members = await this.request<GuildMember[]>('GET', `/guilds/${serverId}/members?limit=1000`)
252
243
  return members.map((m) => m.user)
253
244
  }
254
245
 
@@ -266,10 +257,7 @@ export class DiscordClient {
266
257
  interface MessageWithAttachments extends DiscordMessage {
267
258
  attachments: DiscordFile[]
268
259
  }
269
- const message = await this.requestFormData<MessageWithAttachments>(
270
- `/channels/${channelId}/messages`,
271
- formData
272
- )
260
+ const message = await this.requestFormData<MessageWithAttachments>(`/channels/${channelId}/messages`, formData)
273
261
 
274
262
  return message.attachments[0]
275
263
  }
@@ -278,10 +266,7 @@ export class DiscordClient {
278
266
  interface MessageWithAttachments extends DiscordMessage {
279
267
  attachments: DiscordFile[]
280
268
  }
281
- const messages = await this.request<MessageWithAttachments[]>(
282
- 'GET',
283
- `/channels/${channelId}/messages?limit=100`
284
- )
269
+ const messages = await this.request<MessageWithAttachments[]>('GET', `/channels/${channelId}/messages?limit=100`)
285
270
 
286
271
  const files: DiscordFile[] = []
287
272
  for (const msg of messages) {
@@ -334,25 +319,18 @@ export class DiscordClient {
334
319
  return this.request<DiscordRelationship[]>('GET', '/users/@me/relationships')
335
320
  }
336
321
 
337
- async searchMembers(
338
- guildId: string,
339
- query: string,
340
- limit: number = 10
341
- ): Promise<DiscordGuildMember[]> {
322
+ async searchMembers(guildId: string, query: string, limit: number = 10): Promise<DiscordGuildMember[]> {
342
323
  const params = new URLSearchParams()
343
324
  params.set('query', query)
344
325
  params.set('limit', limit.toString())
345
326
 
346
- return this.request<DiscordGuildMember[]>(
347
- 'GET',
348
- `/guilds/${guildId}/members/search?${params.toString()}`
349
- )
327
+ return this.request<DiscordGuildMember[]>('GET', `/guilds/${guildId}/members/search?${params.toString()}`)
350
328
  }
351
329
 
352
330
  async searchMessages(
353
331
  guildId: string,
354
332
  query: string,
355
- options: DiscordSearchOptions = {}
333
+ options: DiscordSearchOptions = {},
356
334
  ): Promise<{ results: DiscordSearchResult[]; total: number }> {
357
335
  const params = new URLSearchParams()
358
336
  params.set('content', query)
@@ -381,7 +359,7 @@ export class DiscordClient {
381
359
 
382
360
  const response = await this.request<DiscordSearchResponse>(
383
361
  'GET',
384
- `/guilds/${guildId}/messages/search?${params.toString()}`
362
+ `/guilds/${guildId}/messages/search?${params.toString()}`,
385
363
  )
386
364
 
387
365
  const results = response.messages
@@ -413,7 +391,7 @@ export class DiscordClient {
413
391
  options?: {
414
392
  auto_archive_duration?: number
415
393
  rate_limit_per_user?: number
416
- }
394
+ },
417
395
  ): Promise<DiscordChannel> {
418
396
  return this.request<DiscordChannel>('POST', `/channels/${channelId}/threads`, {
419
397
  name,
@@ -34,14 +34,9 @@ beforeEach(() => {
34
34
  servers: {},
35
35
  })
36
36
 
37
- credManagerSaveSpy = spyOn(DiscordCredentialManager.prototype, 'save').mockResolvedValue(
38
- undefined
39
- )
37
+ credManagerSaveSpy = spyOn(DiscordCredentialManager.prototype, 'save').mockResolvedValue(undefined)
40
38
 
41
- credManagerClearTokenSpy = spyOn(
42
- DiscordCredentialManager.prototype,
43
- 'clearToken'
44
- ).mockResolvedValue(undefined)
39
+ credManagerClearTokenSpy = spyOn(DiscordCredentialManager.prototype, 'clearToken').mockResolvedValue(undefined)
45
40
  })
46
41
 
47
42
  afterEach(() => {
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander'
2
- import { handleError } from '../../../shared/utils/error-handler'
3
- import { formatOutput } from '../../../shared/utils/output'
2
+ import { handleError } from '@/shared/utils/error-handler'
3
+ import { formatOutput } from '@/shared/utils/output'
4
4
  import { DiscordClient } from '../client'
5
5
  import { DiscordCredentialManager } from '../credential-manager'
6
6
  import { DiscordTokenExtractor } from '../token-extractor'
@@ -36,12 +36,11 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
36
36
  console.log(
37
37
  formatOutput(
38
38
  {
39
- error:
40
- 'No Discord token found. Make sure Discord desktop app is installed and logged in.',
39
+ error: 'No Discord token found. Make sure Discord desktop app is installed and logged in.',
41
40
  hint: options.debug ? undefined : 'Run with --debug for more info.',
42
41
  },
43
- options.pretty
44
- )
42
+ options.pretty,
43
+ ),
45
44
  )
46
45
  process.exit(1)
47
46
  }
@@ -76,8 +75,8 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
76
75
  {
77
76
  error: 'No servers found. Make sure you are a member of at least one Discord server.',
78
77
  },
79
- options.pretty
80
- )
78
+ options.pretty,
79
+ ),
81
80
  )
82
81
  process.exit(1)
83
82
  }
@@ -117,8 +116,8 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
117
116
  error: `Token validation failed: ${(error as Error).message}`,
118
117
  hint: 'Make sure your Discord token is valid and has not expired.',
119
118
  },
120
- options.pretty
121
- )
119
+ options.pretty,
120
+ ),
122
121
  )
123
122
  process.exit(1)
124
123
  }
@@ -133,9 +132,7 @@ export async function logoutAction(options: { pretty?: boolean }): Promise<void>
133
132
  const config = await credManager.load()
134
133
 
135
134
  if (!config.token) {
136
- console.log(
137
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
138
- )
135
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
139
136
  process.exit(1)
140
137
  }
141
138
 
@@ -153,9 +150,7 @@ export async function statusAction(options: { pretty?: boolean }): Promise<void>
153
150
  const config = await credManager.load()
154
151
 
155
152
  if (!config.token) {
156
- console.log(
157
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
158
- )
153
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
159
154
  process.exit(1)
160
155
  }
161
156
 
@@ -190,17 +185,17 @@ export const authCommand = new Command('auth')
190
185
  .description('Extract token from Discord desktop app')
191
186
  .option('--pretty', 'Pretty print JSON output')
192
187
  .option('--debug', 'Show debug output for troubleshooting')
193
- .action(extractAction)
188
+ .action(extractAction),
194
189
  )
195
190
  .addCommand(
196
191
  new Command('logout')
197
192
  .description('Logout from Discord')
198
193
  .option('--pretty', 'Pretty print JSON output')
199
- .action(logoutAction)
194
+ .action(logoutAction),
200
195
  )
201
196
  .addCommand(
202
197
  new Command('status')
203
198
  .description('Show authentication status')
204
199
  .option('--pretty', 'Pretty print JSON output')
205
- .action(statusAction)
200
+ .action(statusAction),
206
201
  )
@@ -15,29 +15,27 @@ beforeEach(() => {
15
15
  { id: 'ch-3', guild_id: 'guild-1', name: 'voice-channel', type: 2, topic: undefined },
16
16
  ])
17
17
 
18
- clientGetChannelSpy = spyOn(DiscordClient.prototype, 'getChannel').mockImplementation(
19
- async (channelId: string) => {
20
- if (channelId === 'ch-1') {
21
- return {
22
- id: 'ch-1',
23
- guild_id: 'guild-1',
24
- name: 'general',
25
- type: 0,
26
- topic: 'General discussion',
27
- }
18
+ clientGetChannelSpy = spyOn(DiscordClient.prototype, 'getChannel').mockImplementation(async (channelId: string) => {
19
+ if (channelId === 'ch-1') {
20
+ return {
21
+ id: 'ch-1',
22
+ guild_id: 'guild-1',
23
+ name: 'general',
24
+ type: 0,
25
+ topic: 'General discussion',
28
26
  }
29
- if (channelId === 'ch-2') {
30
- return {
31
- id: 'ch-2',
32
- guild_id: 'guild-1',
33
- name: 'announcements',
34
- type: 0,
35
- topic: 'Announcements',
36
- }
27
+ }
28
+ if (channelId === 'ch-2') {
29
+ return {
30
+ id: 'ch-2',
31
+ guild_id: 'guild-1',
32
+ name: 'announcements',
33
+ type: 0,
34
+ topic: 'Announcements',
37
35
  }
38
- throw new Error('Channel not found')
39
36
  }
40
- )
37
+ throw new Error('Channel not found')
38
+ })
41
39
 
42
40
  clientGetMessagesSpy = spyOn(DiscordClient.prototype, 'getMessages').mockResolvedValue([
43
41
  {
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander'
2
- import { handleError } from '../../../shared/utils/error-handler'
3
- import { formatOutput } from '../../../shared/utils/output'
2
+ import { handleError } from '@/shared/utils/error-handler'
3
+ import { formatOutput } from '@/shared/utils/output'
4
4
  import { DiscordClient } from '../client'
5
5
  import { DiscordCredentialManager } from '../credential-manager'
6
6
 
@@ -10,9 +10,7 @@ export async function listAction(options: { pretty?: boolean }): Promise<void> {
10
10
  const config = await credManager.load()
11
11
 
12
12
  if (!config.token || !config.current_server) {
13
- console.log(
14
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
15
- )
13
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
16
14
  process.exit(1)
17
15
  }
18
16
 
@@ -41,9 +39,7 @@ export async function infoAction(channelId: string, options: { pretty?: boolean
41
39
  const config = await credManager.load()
42
40
 
43
41
  if (!config.token) {
44
- console.log(
45
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
46
- )
42
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
47
43
  process.exit(1)
48
44
  }
49
45
 
@@ -65,18 +61,13 @@ export async function infoAction(channelId: string, options: { pretty?: boolean
65
61
  }
66
62
  }
67
63
 
68
- export async function historyAction(
69
- channelId: string,
70
- options: { limit?: number; pretty?: boolean }
71
- ): Promise<void> {
64
+ export async function historyAction(channelId: string, options: { limit?: number; pretty?: boolean }): Promise<void> {
72
65
  try {
73
66
  const credManager = new DiscordCredentialManager()
74
67
  const config = await credManager.load()
75
68
 
76
69
  if (!config.token) {
77
- console.log(
78
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
79
- )
70
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
80
71
  process.exit(1)
81
72
  }
82
73
 
@@ -103,14 +94,14 @@ export const channelCommand = new Command('channel')
103
94
  new Command('list')
104
95
  .description('List channels in current server')
105
96
  .option('--pretty', 'Pretty print JSON output')
106
- .action(listAction)
97
+ .action(listAction),
107
98
  )
108
99
  .addCommand(
109
100
  new Command('info')
110
101
  .description('Get channel info')
111
102
  .argument('<channel-id>', 'Channel ID')
112
103
  .option('--pretty', 'Pretty print JSON output')
113
- .action(infoAction)
104
+ .action(infoAction),
114
105
  )
115
106
  .addCommand(
116
107
  new Command('history')
@@ -123,5 +114,5 @@ export const channelCommand = new Command('channel')
123
114
  limit: parseInt(options.limit, 10),
124
115
  pretty: options.pretty,
125
116
  })
126
- })
117
+ }),
127
118
  )
@@ -37,9 +37,7 @@ const mockChannels: DiscordDMChannel[] = [
37
37
  ]
38
38
 
39
39
  beforeEach(() => {
40
- clientListDMChannelsSpy = spyOn(DiscordClient.prototype, 'listDMChannels').mockResolvedValue(
41
- mockChannels
42
- )
40
+ clientListDMChannelsSpy = spyOn(DiscordClient.prototype, 'listDMChannels').mockResolvedValue(mockChannels)
43
41
 
44
42
  clientCreateDMSpy = spyOn(DiscordClient.prototype, 'createDM').mockResolvedValue({
45
43
  id: '999',
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander'
2
- import { handleError } from '../../../shared/utils/error-handler'
3
- import { formatOutput } from '../../../shared/utils/output'
2
+ import { handleError } from '@/shared/utils/error-handler'
3
+ import { formatOutput } from '@/shared/utils/output'
4
4
  import { DiscordClient } from '../client'
5
5
  import { DiscordCredentialManager } from '../credential-manager'
6
6
  import type { DiscordDMChannel } from '../types'
@@ -11,9 +11,7 @@ export async function listAction(options: { pretty?: boolean }): Promise<void> {
11
11
  const config = await credManager.load()
12
12
 
13
13
  if (!config.token) {
14
- console.log(
15
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
16
- )
14
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
17
15
  process.exit(1)
18
16
  }
19
17
 
@@ -43,9 +41,7 @@ export async function createAction(userId: string, options: { pretty?: boolean }
43
41
  const config = await credManager.load()
44
42
 
45
43
  if (!config.token) {
46
- console.log(
47
- formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
48
- )
44
+ console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
49
45
  process.exit(1)
50
46
  }
51
47
 
@@ -74,12 +70,12 @@ export const dmCommand = new Command('dm')
74
70
  new Command('list')
75
71
  .description('List DM channels')
76
72
  .option('--pretty', 'Pretty print JSON output')
77
- .action(listAction)
73
+ .action(listAction),
78
74
  )
79
75
  .addCommand(
80
76
  new Command('create')
81
77
  .description('Create a DM channel')
82
78
  .argument('<user-id>', 'User ID to create DM with')
83
79
  .option('--pretty', 'Pretty print JSON output')
84
- .action(createAction)
80
+ .action(createAction),
85
81
  )