agent-messenger 1.2.0 → 1.3.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 (80) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +1 -1
  3. package/dist/package.json +3 -2
  4. package/dist/src/platforms/slackbot/cli.d.ts +5 -0
  5. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -0
  6. package/dist/src/platforms/slackbot/cli.js +19 -0
  7. package/dist/src/platforms/slackbot/cli.js.map +1 -0
  8. package/dist/src/platforms/slackbot/client.d.ts +43 -0
  9. package/dist/src/platforms/slackbot/client.d.ts.map +1 -0
  10. package/dist/src/platforms/slackbot/client.js +347 -0
  11. package/dist/src/platforms/slackbot/client.js.map +1 -0
  12. package/dist/src/platforms/slackbot/commands/auth.d.ts +35 -0
  13. package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -0
  14. package/dist/src/platforms/slackbot/commands/auth.js +185 -0
  15. package/dist/src/platforms/slackbot/commands/auth.js.map +1 -0
  16. package/dist/src/platforms/slackbot/commands/channel.d.ts +3 -0
  17. package/dist/src/platforms/slackbot/commands/channel.d.ts.map +1 -0
  18. package/dist/src/platforms/slackbot/commands/channel.js +40 -0
  19. package/dist/src/platforms/slackbot/commands/channel.js.map +1 -0
  20. package/dist/src/platforms/slackbot/commands/index.d.ts +6 -0
  21. package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -0
  22. package/dist/src/platforms/slackbot/commands/index.js +6 -0
  23. package/dist/src/platforms/slackbot/commands/index.js.map +1 -0
  24. package/dist/src/platforms/slackbot/commands/message.d.ts +3 -0
  25. package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -0
  26. package/dist/src/platforms/slackbot/commands/message.js +135 -0
  27. package/dist/src/platforms/slackbot/commands/message.js.map +1 -0
  28. package/dist/src/platforms/slackbot/commands/reaction.d.ts +3 -0
  29. package/dist/src/platforms/slackbot/commands/reaction.d.ts.map +1 -0
  30. package/dist/src/platforms/slackbot/commands/reaction.js +43 -0
  31. package/dist/src/platforms/slackbot/commands/reaction.js.map +1 -0
  32. package/dist/src/platforms/slackbot/commands/shared.d.ts +9 -0
  33. package/dist/src/platforms/slackbot/commands/shared.d.ts.map +1 -0
  34. package/dist/src/platforms/slackbot/commands/shared.js +13 -0
  35. package/dist/src/platforms/slackbot/commands/shared.js.map +1 -0
  36. package/dist/src/platforms/slackbot/commands/user.d.ts +3 -0
  37. package/dist/src/platforms/slackbot/commands/user.d.ts.map +1 -0
  38. package/dist/src/platforms/slackbot/commands/user.js +40 -0
  39. package/dist/src/platforms/slackbot/commands/user.js.map +1 -0
  40. package/dist/src/platforms/slackbot/credential-manager.d.ts +18 -0
  41. package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -0
  42. package/dist/src/platforms/slackbot/credential-manager.js +187 -0
  43. package/dist/src/platforms/slackbot/credential-manager.js.map +1 -0
  44. package/dist/src/platforms/slackbot/index.d.ts +4 -0
  45. package/dist/src/platforms/slackbot/index.d.ts.map +1 -0
  46. package/dist/src/platforms/slackbot/index.js +4 -0
  47. package/dist/src/platforms/slackbot/index.js.map +1 -0
  48. package/dist/src/platforms/slackbot/types.d.ts +460 -0
  49. package/dist/src/platforms/slackbot/types.d.ts.map +1 -0
  50. package/dist/src/platforms/slackbot/types.js +114 -0
  51. package/dist/src/platforms/slackbot/types.js.map +1 -0
  52. package/docs/content/docs/integrations/meta.json +1 -1
  53. package/docs/content/docs/integrations/slackbot.mdx +204 -0
  54. package/docs/src/app/page.tsx +18 -1
  55. package/e2e/config.ts +26 -0
  56. package/e2e/helpers.ts +6 -1
  57. package/e2e/slackbot.e2e.test.ts +306 -0
  58. package/package.json +3 -2
  59. package/skills/agent-slackbot/SKILL.md +285 -0
  60. package/skills/agent-slackbot/references/authentication.md +253 -0
  61. package/skills/agent-slackbot/references/common-patterns.md +218 -0
  62. package/skills/agent-slackbot/templates/monitor-channel.sh +98 -0
  63. package/skills/agent-slackbot/templates/post-message.sh +107 -0
  64. package/skills/agent-slackbot/templates/workspace-summary.sh +113 -0
  65. package/src/platforms/slackbot/cli.ts +30 -0
  66. package/src/platforms/slackbot/client.test.ts +282 -0
  67. package/src/platforms/slackbot/client.ts +401 -0
  68. package/src/platforms/slackbot/commands/auth.test.ts +245 -0
  69. package/src/platforms/slackbot/commands/auth.ts +240 -0
  70. package/src/platforms/slackbot/commands/channel.ts +46 -0
  71. package/src/platforms/slackbot/commands/index.ts +5 -0
  72. package/src/platforms/slackbot/commands/message.ts +182 -0
  73. package/src/platforms/slackbot/commands/reaction.ts +59 -0
  74. package/src/platforms/slackbot/commands/shared.ts +23 -0
  75. package/src/platforms/slackbot/commands/user.ts +46 -0
  76. package/src/platforms/slackbot/credential-manager.test.ts +264 -0
  77. package/src/platforms/slackbot/credential-manager.ts +218 -0
  78. package/src/platforms/slackbot/index.ts +19 -0
  79. package/src/platforms/slackbot/types.test.ts +90 -0
  80. package/src/platforms/slackbot/types.ts +222 -0
@@ -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}"
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from 'commander'
4
+ import pkg from '../../../package.json'
5
+ import {
6
+ authCommand,
7
+ channelCommand,
8
+ messageCommand,
9
+ reactionCommand,
10
+ userCommand,
11
+ } from './commands/index'
12
+
13
+ const program = new Command()
14
+
15
+ program
16
+ .name('agent-slackbot')
17
+ .description('CLI tool for Slack bot integration using bot tokens (xoxb-)')
18
+ .version(pkg.version)
19
+ .option('--pretty', 'Pretty-print JSON output')
20
+ .option('--bot <id>', 'Use specific bot (default: current)')
21
+
22
+ program.addCommand(authCommand)
23
+ program.addCommand(messageCommand)
24
+ program.addCommand(channelCommand)
25
+ program.addCommand(userCommand)
26
+ program.addCommand(reactionCommand)
27
+
28
+ program.parse(process.argv)
29
+
30
+ 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
+ })