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
@@ -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 { SlackClient } from '../client'
5
5
  import { CredentialManager } from '../credential-manager'
6
6
 
@@ -10,12 +10,7 @@ export async function countsAction(options: { pretty?: boolean }): Promise<void>
10
10
  const workspace = await credManager.getWorkspace()
11
11
 
12
12
  if (!workspace) {
13
- console.log(
14
- formatOutput(
15
- { error: 'No current workspace set. Run "auth extract" first.' },
16
- options.pretty
17
- )
18
- )
13
+ console.log(formatOutput({ error: 'No current workspace set. Run "auth extract" first.' }, options.pretty))
19
14
  process.exit(1)
20
15
  }
21
16
 
@@ -39,22 +34,13 @@ export async function countsAction(options: { pretty?: boolean }): Promise<void>
39
34
  }
40
35
  }
41
36
 
42
- export async function threadsAction(
43
- channel: string,
44
- threadTs: string,
45
- options: { pretty?: boolean }
46
- ): Promise<void> {
37
+ export async function threadsAction(channel: string, threadTs: string, options: { pretty?: boolean }): Promise<void> {
47
38
  try {
48
39
  const credManager = new CredentialManager()
49
40
  const workspace = await credManager.getWorkspace()
50
41
 
51
42
  if (!workspace) {
52
- console.log(
53
- formatOutput(
54
- { error: 'No current workspace set. Run "auth extract" first.' },
55
- options.pretty
56
- )
57
- )
43
+ console.log(formatOutput({ error: 'No current workspace set. Run "auth extract" first.' }, options.pretty))
58
44
  process.exit(1)
59
45
  }
60
46
 
@@ -75,22 +61,13 @@ export async function threadsAction(
75
61
  }
76
62
  }
77
63
 
78
- export async function markAction(
79
- channel: string,
80
- ts: string,
81
- options: { pretty?: boolean }
82
- ): Promise<void> {
64
+ export async function markAction(channel: string, ts: string, options: { pretty?: boolean }): Promise<void> {
83
65
  try {
84
66
  const credManager = new CredentialManager()
85
67
  const workspace = await credManager.getWorkspace()
86
68
 
87
69
  if (!workspace) {
88
- console.log(
89
- formatOutput(
90
- { error: 'No current workspace set. Run "auth extract" first.' },
91
- options.pretty
92
- )
93
- )
70
+ console.log(formatOutput({ error: 'No current workspace set. Run "auth extract" first.' }, options.pretty))
94
71
  process.exit(1)
95
72
  }
96
73
 
@@ -109,7 +86,7 @@ export const unreadCommand = new Command('unread')
109
86
  new Command('counts')
110
87
  .description('Get unread counts for all channels')
111
88
  .option('--pretty', 'Pretty print JSON output')
112
- .action(countsAction)
89
+ .action(countsAction),
113
90
  )
114
91
  .addCommand(
115
92
  new Command('threads')
@@ -117,7 +94,7 @@ export const unreadCommand = new Command('unread')
117
94
  .argument('<channel>', 'Channel ID or name')
118
95
  .argument('<thread_ts>', 'Thread timestamp')
119
96
  .option('--pretty', 'Pretty print JSON output')
120
- .action(threadsAction)
97
+ .action(threadsAction),
121
98
  )
122
99
  .addCommand(
123
100
  new Command('mark')
@@ -125,5 +102,5 @@ export const unreadCommand = new Command('unread')
125
102
  .argument('<channel>', 'Channel ID or name')
126
103
  .argument('<ts>', 'Message timestamp to mark as read')
127
104
  .option('--pretty', 'Pretty print JSON output')
128
- .action(markAction)
105
+ .action(markAction),
129
106
  )
@@ -50,10 +50,7 @@ describe('User Commands', () => {
50
50
  } as unknown as SlackClient
51
51
 
52
52
  // When: Calling list with all users
53
- const result = await (userCommand as any).commands[0].action(
54
- { includeBots: false },
55
- userCommand
56
- )
53
+ const result = await (userCommand as any).commands[0].action({ includeBots: false }, userCommand)
57
54
 
58
55
  // Then: Should return users
59
56
  expect(result).toBeDefined()
@@ -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 { SlackClient } from '../client'
5
5
  import { CredentialManager } from '../credential-manager'
6
6
 
@@ -9,9 +9,7 @@ async function getClient(pretty?: boolean): Promise<SlackClient | null> {
9
9
  const workspace = await credManager.getWorkspace()
10
10
 
11
11
  if (!workspace) {
12
- console.log(
13
- formatOutput({ error: 'No current workspace set. Run "auth extract" first.' }, pretty)
14
- )
12
+ console.log(formatOutput({ error: 'No current workspace set. Run "auth extract" first.' }, pretty))
15
13
  return null
16
14
  }
17
15
 
@@ -49,7 +47,7 @@ export const userCommand = new Command('user')
49
47
  } catch (error) {
50
48
  handleError(error as Error)
51
49
  }
52
- })
50
+ }),
53
51
  )
54
52
  .addCommand(
55
53
  new Command('info')
@@ -78,7 +76,7 @@ export const userCommand = new Command('user')
78
76
  } catch (error) {
79
77
  handleError(error as Error)
80
78
  }
81
- })
79
+ }),
82
80
  )
83
81
  .addCommand(
84
82
  new Command('me')
@@ -106,5 +104,5 @@ export const userCommand = new Command('user')
106
104
  } catch (error) {
107
105
  handleError(error as Error)
108
106
  }
109
- })
107
+ }),
110
108
  )
@@ -9,7 +9,7 @@ const testDirs: string[] = []
9
9
  function setup(): CredentialManager {
10
10
  const testConfigDir = join(
11
11
  import.meta.dir,
12
- `.test-workspace-config-${Date.now()}-${Math.random().toString(36).slice(2)}`
12
+ `.test-workspace-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
13
13
  )
14
14
  testDirs.push(testConfigDir)
15
15
  return new CredentialManager(testConfigDir)
@@ -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 { CredentialManager } from '../credential-manager'
5
5
 
6
6
  async function listAction(options: { pretty?: boolean }): Promise<void> {
@@ -44,12 +44,7 @@ async function currentAction(options: { pretty?: boolean }): Promise<void> {
44
44
  const workspace = await credManager.getWorkspace()
45
45
 
46
46
  if (!workspace) {
47
- console.log(
48
- formatOutput(
49
- { error: 'No current workspace set. Run "auth extract" first.' },
50
- options.pretty
51
- )
52
- )
47
+ console.log(formatOutput({ error: 'No current workspace set. Run "auth extract" first.' }, options.pretty))
53
48
  process.exit(1)
54
49
  }
55
50
 
@@ -87,25 +82,25 @@ export const workspaceCommand = new Command('workspace')
87
82
  new Command('list')
88
83
  .description('List all workspaces')
89
84
  .option('--pretty', 'Pretty print JSON output')
90
- .action(listAction)
85
+ .action(listAction),
91
86
  )
92
87
  .addCommand(
93
88
  new Command('switch')
94
89
  .description('Switch to workspace')
95
90
  .argument('<id>', 'Workspace ID')
96
91
  .option('--pretty', 'Pretty print JSON output')
97
- .action(switchAction)
92
+ .action(switchAction),
98
93
  )
99
94
  .addCommand(
100
95
  new Command('current')
101
96
  .description('Show current workspace')
102
97
  .option('--pretty', 'Pretty print JSON output')
103
- .action(currentAction)
98
+ .action(currentAction),
104
99
  )
105
100
  .addCommand(
106
101
  new Command('remove')
107
102
  .description('Remove workspace')
108
103
  .argument('<id>', 'Workspace ID')
109
104
  .option('--pretty', 'Pretty print JSON output')
110
- .action(removeAction)
105
+ .action(removeAction),
111
106
  )
@@ -22,7 +22,7 @@ try {
22
22
  )
23
23
  `)
24
24
  db.prepare(
25
- "INSERT INTO cookies (name, value, host_key, last_access_utc) VALUES ('d', 'xoxd-test-cookie', '.slack.com', 1000)"
25
+ "INSERT INTO cookies (name, value, host_key, last_access_utc) VALUES ('d', 'xoxd-test-cookie', '.slack.com', 1000)",
26
26
  ).run()
27
27
  db.close()
28
28
 
@@ -5,7 +5,7 @@ import { createRequire } from 'node:module'
5
5
  import { homedir, tmpdir } from 'node:os'
6
6
  import { join } from 'node:path'
7
7
  import { ClassicLevel } from 'classic-level'
8
- import { DerivedKeyCache } from '../../shared/utils/derived-key-cache'
8
+ import { DerivedKeyCache } from '@/shared/utils/derived-key-cache'
9
9
 
10
10
  const require = createRequire(import.meta.url)
11
11
 
@@ -55,7 +55,7 @@ export class TokenExtractor {
55
55
  'Data',
56
56
  'Library',
57
57
  'Application Support',
58
- 'Slack'
58
+ 'Slack',
59
59
  )
60
60
  if (existsSync(sandboxedPath)) {
61
61
  return sandboxedPath
@@ -306,12 +306,7 @@ export class TokenExtractor {
306
306
  } else {
307
307
  // Check for 4-byte fragmentation marker pattern
308
308
  // Pattern: 0x19 0x0d 0xf0 0xNN (where NN varies)
309
- if (
310
- i + 3 < chunk.length &&
311
- chunk[i] === 0x19 &&
312
- chunk[i + 1] === 0x0d &&
313
- chunk[i + 2] === 0xf0
314
- ) {
309
+ if (i + 3 < chunk.length && chunk[i] === 0x19 && chunk[i + 1] === 0x0d && chunk[i + 2] === 0xf0) {
315
310
  // Skip the 4 garbage bytes and insert a hyphen
316
311
  result.push(0x2d) // hyphen
317
312
  i += 4
@@ -419,10 +414,7 @@ export class TokenExtractor {
419
414
  private readCookieFromDB(dbPath: string): string {
420
415
  // Copy the database to a temp file to avoid SQLite lock contention
421
416
  // when Slack is running and has a write lock on the Cookies database
422
- const tempDbPath = join(
423
- tmpdir(),
424
- `slack-cookies-${Date.now()}-${Math.random().toString(36).slice(2)}.db`
425
- )
417
+ const tempDbPath = join(tmpdir(), `slack-cookies-${Date.now()}-${Math.random().toString(36).slice(2)}.db`)
426
418
 
427
419
  try {
428
420
  copyFileSync(dbPath, tempDbPath)
@@ -555,13 +547,12 @@ export class TokenExtractor {
555
547
  try {
556
548
  password = execSync(
557
549
  'security find-generic-password -ga "Slack App Store Key" -s "Slack Safe Storage" -w 2>/dev/null',
558
- { encoding: 'utf8' }
550
+ { encoding: 'utf8' },
559
551
  ).trim()
560
552
  } catch {
561
- password = execSync(
562
- 'security find-generic-password -ga "Slack Key" -s "Slack Safe Storage" -w 2>/dev/null',
563
- { encoding: 'utf8' }
564
- ).trim()
553
+ password = execSync('security find-generic-password -ga "Slack Key" -s "Slack Safe Storage" -w 2>/dev/null', {
554
+ encoding: 'utf8',
555
+ }).trim()
565
556
  }
566
557
 
567
558
  return pbkdf2Sync(password, 'saltysalt', 1003, 16, 'sha1')
@@ -191,7 +191,7 @@ export const SlackMessageSchema = z.object({
191
191
  z.object({
192
192
  user: z.string(),
193
193
  ts: z.string(),
194
- })
194
+ }),
195
195
  )
196
196
  .optional(),
197
197
  edited: z
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from 'commander'
4
+ import pkg from '../../../package.json'
5
+ import { authCommand, channelCommand, messageCommand, reactionCommand, userCommand } from './commands/index'
6
+
7
+ const program = new Command()
8
+
9
+ program
10
+ .name('agent-slackbot')
11
+ .description('CLI tool for Slack bot integration using bot tokens (xoxb-)')
12
+ .version(pkg.version)
13
+ .option('--pretty', 'Pretty-print JSON output')
14
+ .option('--bot <id>', 'Use specific bot (default: current)')
15
+
16
+ program.addCommand(authCommand)
17
+ program.addCommand(messageCommand)
18
+ program.addCommand(channelCommand)
19
+ program.addCommand(userCommand)
20
+ program.addCommand(reactionCommand)
21
+
22
+ program.parse(process.argv)
23
+
24
+ export default program
@@ -0,0 +1,282 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+ import { SlackBotClient } from './client'
3
+ import { SlackBotError } from './types'
4
+
5
+ // Mock the @slack/web-api module
6
+ const mockAuth = {
7
+ test: mock(() =>
8
+ Promise.resolve({
9
+ ok: true,
10
+ user_id: 'U123',
11
+ team_id: 'T456',
12
+ bot_id: 'B789',
13
+ user: 'testbot',
14
+ team: 'Test Team',
15
+ }),
16
+ ),
17
+ }
18
+ const mockConversations = {
19
+ list: mock(() =>
20
+ Promise.resolve({
21
+ ok: true,
22
+ channels: [
23
+ {
24
+ id: 'C123',
25
+ name: 'general',
26
+ is_private: false,
27
+ is_archived: false,
28
+ created: 1234567890,
29
+ creator: 'U001',
30
+ },
31
+ ],
32
+ }),
33
+ ),
34
+ info: mock(() =>
35
+ Promise.resolve({
36
+ ok: true,
37
+ channel: {
38
+ id: 'C123',
39
+ name: 'general',
40
+ is_private: false,
41
+ is_archived: false,
42
+ created: 1234567890,
43
+ creator: 'U001',
44
+ },
45
+ }),
46
+ ),
47
+ history: mock(() =>
48
+ Promise.resolve({
49
+ ok: true,
50
+ messages: [{ ts: '1234567890.123456', text: 'Hello', type: 'message', user: 'U123' }],
51
+ }),
52
+ ),
53
+ }
54
+ const mockChat = {
55
+ postMessage: mock(() =>
56
+ Promise.resolve({
57
+ ok: true,
58
+ ts: '1234567890.123456',
59
+ message: { text: 'Hello', type: 'message' },
60
+ }),
61
+ ),
62
+ }
63
+ const mockReactions = {
64
+ add: mock(() => Promise.resolve({ ok: true })),
65
+ remove: mock(() => Promise.resolve({ ok: true })),
66
+ }
67
+ const mockUsers = {
68
+ list: mock(() =>
69
+ Promise.resolve({
70
+ ok: true,
71
+ members: [
72
+ {
73
+ id: 'U123',
74
+ name: 'testuser',
75
+ real_name: 'Test User',
76
+ is_admin: false,
77
+ is_owner: false,
78
+ is_bot: false,
79
+ is_app_user: false,
80
+ },
81
+ ],
82
+ }),
83
+ ),
84
+ info: mock(() =>
85
+ Promise.resolve({
86
+ ok: true,
87
+ user: {
88
+ id: 'U123',
89
+ name: 'testuser',
90
+ real_name: 'Test User',
91
+ is_admin: false,
92
+ is_owner: false,
93
+ is_bot: false,
94
+ is_app_user: false,
95
+ },
96
+ }),
97
+ ),
98
+ }
99
+
100
+ mock.module('@slack/web-api', () => ({
101
+ WebClient: class MockWebClient {
102
+ auth = mockAuth
103
+ conversations = mockConversations
104
+ chat = mockChat
105
+ reactions = mockReactions
106
+ users = mockUsers
107
+ },
108
+ }))
109
+
110
+ describe('SlackBotClient', () => {
111
+ beforeEach(() => {
112
+ // Reset mocks
113
+ mockAuth.test.mockClear()
114
+ mockConversations.list.mockClear()
115
+ mockConversations.info.mockClear()
116
+ mockConversations.history.mockClear()
117
+ mockChat.postMessage.mockClear()
118
+ mockReactions.add.mockClear()
119
+ mockReactions.remove.mockClear()
120
+ mockUsers.list.mockClear()
121
+ mockUsers.info.mockClear()
122
+ })
123
+
124
+ describe('constructor', () => {
125
+ test('accepts bot tokens (xoxb-)', () => {
126
+ // when/then: should not throw
127
+ const client = new SlackBotClient('xoxb-test-token')
128
+ expect(client).toBeDefined()
129
+ })
130
+
131
+ test('rejects user tokens (xoxp-)', () => {
132
+ // when/then
133
+ expect(() => new SlackBotClient('xoxp-user-token')).toThrow(SlackBotError)
134
+ })
135
+
136
+ test('rejects empty token', () => {
137
+ // when/then
138
+ expect(() => new SlackBotClient('')).toThrow(SlackBotError)
139
+ })
140
+
141
+ test('rejects non-bot tokens', () => {
142
+ // when/then
143
+ expect(() => new SlackBotClient('invalid-token')).toThrow(SlackBotError)
144
+ })
145
+ })
146
+
147
+ describe('testAuth', () => {
148
+ test('returns auth info for valid token', async () => {
149
+ // given
150
+ const client = new SlackBotClient('xoxb-test-token')
151
+
152
+ // when
153
+ const result = await client.testAuth()
154
+
155
+ // then
156
+ expect(result.user_id).toBe('U123')
157
+ expect(result.team_id).toBe('T456')
158
+ expect(result.bot_id).toBe('B789')
159
+ })
160
+ })
161
+
162
+ describe('postMessage', () => {
163
+ test('sends message and returns timestamp', async () => {
164
+ // given
165
+ const client = new SlackBotClient('xoxb-test-token')
166
+
167
+ // when
168
+ const result = await client.postMessage('C123', 'Hello')
169
+
170
+ // then
171
+ expect(result.ts).toBe('1234567890.123456')
172
+ expect(result.text).toBe('Hello')
173
+ })
174
+ })
175
+
176
+ describe('getConversationHistory', () => {
177
+ test('returns messages', async () => {
178
+ // given
179
+ const client = new SlackBotClient('xoxb-test-token')
180
+
181
+ // when
182
+ const messages = await client.getConversationHistory('C123')
183
+
184
+ // then
185
+ expect(messages.length).toBeGreaterThan(0)
186
+ expect(messages[0].ts).toBe('1234567890.123456')
187
+ })
188
+ })
189
+
190
+ describe('getMessage', () => {
191
+ test('returns single message', async () => {
192
+ // given
193
+ const client = new SlackBotClient('xoxb-test-token')
194
+
195
+ // when
196
+ const message = await client.getMessage('C123', '1234567890.123456')
197
+
198
+ // then
199
+ expect(message).not.toBeNull()
200
+ expect(message?.ts).toBe('1234567890.123456')
201
+ })
202
+ })
203
+
204
+ describe('addReaction', () => {
205
+ test('adds reaction to message', async () => {
206
+ // given
207
+ const client = new SlackBotClient('xoxb-test-token')
208
+
209
+ // when/then: should not throw
210
+ await client.addReaction('C123', '1234567890.123456', 'thumbsup')
211
+ expect(mockReactions.add).toHaveBeenCalled()
212
+ })
213
+ })
214
+
215
+ describe('removeReaction', () => {
216
+ test('removes reaction from message', async () => {
217
+ // given
218
+ const client = new SlackBotClient('xoxb-test-token')
219
+
220
+ // when/then: should not throw
221
+ await client.removeReaction('C123', '1234567890.123456', 'thumbsup')
222
+ expect(mockReactions.remove).toHaveBeenCalled()
223
+ })
224
+ })
225
+
226
+ describe('listChannels', () => {
227
+ test('returns list of channels', async () => {
228
+ // given
229
+ const client = new SlackBotClient('xoxb-test-token')
230
+
231
+ // when
232
+ const channels = await client.listChannels()
233
+
234
+ // then
235
+ expect(channels.length).toBeGreaterThan(0)
236
+ expect(channels[0].id).toBe('C123')
237
+ expect(channels[0].name).toBe('general')
238
+ })
239
+ })
240
+
241
+ describe('getChannelInfo', () => {
242
+ test('returns channel details', async () => {
243
+ // given
244
+ const client = new SlackBotClient('xoxb-test-token')
245
+
246
+ // when
247
+ const channel = await client.getChannelInfo('C123')
248
+
249
+ // then
250
+ expect(channel.id).toBe('C123')
251
+ expect(channel.name).toBe('general')
252
+ })
253
+ })
254
+
255
+ describe('listUsers', () => {
256
+ test('returns list of users', async () => {
257
+ // given
258
+ const client = new SlackBotClient('xoxb-test-token')
259
+
260
+ // when
261
+ const users = await client.listUsers()
262
+
263
+ // then
264
+ expect(users.length).toBeGreaterThan(0)
265
+ expect(users[0].id).toBe('U123')
266
+ })
267
+ })
268
+
269
+ describe('getUserInfo', () => {
270
+ test('returns user details', async () => {
271
+ // given
272
+ const client = new SlackBotClient('xoxb-test-token')
273
+
274
+ // when
275
+ const user = await client.getUserInfo('U123')
276
+
277
+ // then
278
+ expect(user.id).toBe('U123')
279
+ expect(user.name).toBe('testuser')
280
+ })
281
+ })
282
+ })