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.
- package/.claude-plugin/marketplace.json +27 -1
- package/.claude-plugin/plugin.json +17 -4
- package/.env.template +3 -0
- package/.github/workflows/release.yml +94 -0
- package/AGENTS.md +48 -0
- package/README.md +25 -20
- package/biome.json +15 -39
- package/bun.lock +69 -0
- package/dist/package.json +12 -4
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +1 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/platforms/discord/client.d.ts.map +1 -1
- package/dist/src/platforms/discord/client.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/commands/channel.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/channel.js.map +1 -1
- package/dist/src/platforms/discord/commands/dm.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/dm.js.map +1 -1
- package/dist/src/platforms/discord/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/file.js +1 -4
- package/dist/src/platforms/discord/commands/file.js.map +1 -1
- package/dist/src/platforms/discord/commands/friend.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/friend.js +1 -3
- package/dist/src/platforms/discord/commands/friend.js.map +1 -1
- package/dist/src/platforms/discord/commands/member.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/member.js.map +1 -1
- package/dist/src/platforms/discord/commands/mention.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/mention.js.map +1 -1
- package/dist/src/platforms/discord/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/message.js.map +1 -1
- package/dist/src/platforms/discord/commands/note.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/note.js.map +1 -1
- package/dist/src/platforms/discord/commands/profile.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/profile.js.map +1 -1
- package/dist/src/platforms/discord/commands/reaction.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/reaction.js.map +1 -1
- package/dist/src/platforms/discord/commands/server.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/server.js.map +1 -1
- package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/discord/commands/thread.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/thread.js.map +1 -1
- package/dist/src/platforms/discord/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/user.js.map +1 -1
- package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/discord/credential-manager.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +2 -7
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/slack/client.d.ts.map +1 -1
- package/dist/src/platforms/slack/client.js.map +1 -1
- package/dist/src/platforms/slack/commands/activity.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/activity.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/channel.js.map +1 -1
- package/dist/src/platforms/slack/commands/drafts.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/drafts.js.map +1 -1
- package/dist/src/platforms/slack/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/file.js +1 -4
- package/dist/src/platforms/slack/commands/file.js.map +1 -1
- package/dist/src/platforms/slack/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/message.js.map +1 -1
- package/dist/src/platforms/slack/commands/reaction.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/reaction.js.map +1 -1
- package/dist/src/platforms/slack/commands/saved.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/saved.js.map +1 -1
- package/dist/src/platforms/slack/commands/sections.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/sections.js.map +1 -1
- package/dist/src/platforms/slack/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/slack/commands/unread.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/unread.js.map +1 -1
- package/dist/src/platforms/slack/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/user.js.map +1 -1
- package/dist/src/platforms/slack/commands/workspace.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/workspace.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +4 -5
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/slackbot/cli.d.ts +5 -0
- package/dist/src/platforms/slackbot/cli.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/cli.js +19 -0
- package/dist/src/platforms/slackbot/cli.js.map +1 -0
- package/dist/src/platforms/slackbot/client.d.ts +43 -0
- package/dist/src/platforms/slackbot/client.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/client.js +347 -0
- package/dist/src/platforms/slackbot/client.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/auth.d.ts +35 -0
- package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/auth.js +185 -0
- package/dist/src/platforms/slackbot/commands/auth.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/channel.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/channel.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/channel.js +40 -0
- package/dist/src/platforms/slackbot/commands/channel.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts +6 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/index.js +6 -0
- package/dist/src/platforms/slackbot/commands/index.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/message.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/message.js +135 -0
- package/dist/src/platforms/slackbot/commands/message.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/reaction.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/reaction.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/reaction.js +43 -0
- package/dist/src/platforms/slackbot/commands/reaction.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/shared.d.ts +9 -0
- package/dist/src/platforms/slackbot/commands/shared.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/shared.js +13 -0
- package/dist/src/platforms/slackbot/commands/shared.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/user.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/user.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/user.js +40 -0
- package/dist/src/platforms/slackbot/commands/user.js.map +1 -0
- package/dist/src/platforms/slackbot/credential-manager.d.ts +18 -0
- package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/credential-manager.js +185 -0
- package/dist/src/platforms/slackbot/credential-manager.js.map +1 -0
- package/dist/src/platforms/slackbot/index.d.ts +4 -0
- package/dist/src/platforms/slackbot/index.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/index.js +4 -0
- package/dist/src/platforms/slackbot/index.js.map +1 -0
- package/dist/src/platforms/slackbot/types.d.ts +460 -0
- package/dist/src/platforms/slackbot/types.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/types.js +114 -0
- package/dist/src/platforms/slackbot/types.js.map +1 -0
- package/dist/src/platforms/teams/client.d.ts.map +1 -1
- package/dist/src/platforms/teams/client.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/channel.js.map +1 -1
- package/dist/src/platforms/teams/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/file.js.map +1 -1
- package/dist/src/platforms/teams/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/message.js.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
- package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/teams/commands/team.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/team.js +1 -4
- package/dist/src/platforms/teams/commands/team.js.map +1 -1
- package/dist/src/platforms/teams/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/user.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +3 -1
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/docs/content/docs/agent-skills.mdx +4 -4
- package/docs/content/docs/index.mdx +11 -18
- package/docs/content/docs/integrations/discord.mdx +65 -1
- package/docs/content/docs/integrations/meta.json +1 -1
- package/docs/content/docs/integrations/slack.mdx +51 -1
- package/docs/content/docs/integrations/slackbot.mdx +214 -0
- package/docs/content/docs/integrations/teams.mdx +4 -1
- package/docs/content/docs/quick-start.mdx +3 -2
- package/docs/src/app/icon.png +0 -0
- package/docs/src/app/layout.config.tsx +8 -1
- package/docs/src/app/page.tsx +18 -1
- package/e2e/config.ts +26 -0
- package/e2e/helpers.ts +6 -1
- package/e2e/slackbot.e2e.test.ts +306 -0
- package/package.json +16 -8
- package/scripts/prepublish.ts +11 -0
- package/skills/agent-slackbot/SKILL.md +285 -0
- package/skills/agent-slackbot/references/authentication.md +253 -0
- package/skills/agent-slackbot/references/common-patterns.md +218 -0
- package/skills/agent-slackbot/templates/monitor-channel.sh +98 -0
- package/skills/agent-slackbot/templates/post-message.sh +107 -0
- package/skills/agent-slackbot/templates/workspace-summary.sh +113 -0
- package/src/cli.ts +1 -4
- package/src/platforms/discord/client.test.ts +6 -14
- package/src/platforms/discord/client.ts +12 -34
- package/src/platforms/discord/commands/auth.test.ts +2 -7
- package/src/platforms/discord/commands/auth.ts +14 -19
- package/src/platforms/discord/commands/channel.test.ts +18 -20
- package/src/platforms/discord/commands/channel.ts +9 -18
- package/src/platforms/discord/commands/dm.test.ts +1 -3
- package/src/platforms/discord/commands/dm.ts +6 -10
- package/src/platforms/discord/commands/file.ts +10 -23
- package/src/platforms/discord/commands/friend.ts +33 -35
- package/src/platforms/discord/commands/member.ts +5 -7
- package/src/platforms/discord/commands/mention.ts +5 -11
- package/src/platforms/discord/commands/message.test.ts +1 -3
- package/src/platforms/discord/commands/message.ts +23 -61
- package/src/platforms/discord/commands/note.ts +7 -15
- package/src/platforms/discord/commands/profile.ts +4 -6
- package/src/platforms/discord/commands/reaction.test.ts +1 -3
- package/src/platforms/discord/commands/reaction.ts +19 -29
- package/src/platforms/discord/commands/server.test.ts +14 -18
- package/src/platforms/discord/commands/server.ts +9 -15
- package/src/platforms/discord/commands/snapshot.ts +5 -7
- package/src/platforms/discord/commands/thread.ts +8 -15
- package/src/platforms/discord/commands/user.ts +9 -20
- package/src/platforms/discord/credential-manager.test.ts +2 -2
- package/src/platforms/discord/credential-manager.ts +1 -3
- package/src/platforms/discord/token-extractor.test.ts +28 -57
- package/src/platforms/discord/token-extractor.ts +10 -30
- package/src/platforms/discord/types.ts +1 -1
- package/src/platforms/slack/client.test.ts +14 -20
- package/src/platforms/slack/client.ts +4 -11
- package/src/platforms/slack/commands/activity.test.ts +3 -9
- package/src/platforms/slack/commands/activity.ts +7 -12
- package/src/platforms/slack/commands/auth.test.ts +2 -2
- package/src/platforms/slack/commands/auth.ts +15 -31
- package/src/platforms/slack/commands/channel.ts +10 -32
- package/src/platforms/slack/commands/drafts.ts +5 -14
- package/src/platforms/slack/commands/file.ts +9 -29
- package/src/platforms/slack/commands/message.ts +23 -67
- package/src/platforms/slack/commands/reaction.ts +19 -48
- package/src/platforms/slack/commands/saved.ts +5 -14
- package/src/platforms/slack/commands/sections.ts +4 -11
- package/src/platforms/slack/commands/snapshot.test.ts +1 -3
- package/src/platforms/slack/commands/snapshot.ts +5 -10
- package/src/platforms/slack/commands/unread.test.ts +6 -8
- package/src/platforms/slack/commands/unread.ts +10 -33
- package/src/platforms/slack/commands/user.test.ts +1 -4
- package/src/platforms/slack/commands/user.ts +6 -8
- package/src/platforms/slack/commands/workspace.test.ts +1 -1
- package/src/platforms/slack/commands/workspace.ts +7 -12
- package/src/platforms/slack/token-extractor-node-test.ts +1 -1
- package/src/platforms/slack/token-extractor.ts +8 -17
- package/src/platforms/slack/types.ts +1 -1
- package/src/platforms/slackbot/cli.ts +24 -0
- package/src/platforms/slackbot/client.test.ts +282 -0
- package/src/platforms/slackbot/client.ts +394 -0
- package/src/platforms/slackbot/commands/auth.test.ts +245 -0
- package/src/platforms/slackbot/commands/auth.ts +240 -0
- package/src/platforms/slackbot/commands/channel.ts +46 -0
- package/src/platforms/slackbot/commands/index.ts +5 -0
- package/src/platforms/slackbot/commands/message.ts +169 -0
- package/src/platforms/slackbot/commands/reaction.ts +49 -0
- package/src/platforms/slackbot/commands/shared.ts +21 -0
- package/src/platforms/slackbot/commands/user.ts +46 -0
- package/src/platforms/slackbot/credential-manager.test.ts +264 -0
- package/src/platforms/slackbot/credential-manager.ts +213 -0
- package/src/platforms/slackbot/index.ts +19 -0
- package/src/platforms/slackbot/types.test.ts +90 -0
- package/src/platforms/slackbot/types.ts +222 -0
- package/src/platforms/teams/client.test.ts +15 -32
- package/src/platforms/teams/client.ts +18 -51
- package/src/platforms/teams/commands/auth.test.ts +6 -16
- package/src/platforms/teams/commands/auth.ts +16 -26
- package/src/platforms/teams/commands/channel.test.ts +2 -5
- package/src/platforms/teams/commands/channel.ts +10 -20
- package/src/platforms/teams/commands/file.test.ts +1 -4
- package/src/platforms/teams/commands/file.ts +11 -21
- package/src/platforms/teams/commands/message.test.ts +1 -3
- package/src/platforms/teams/commands/message.ts +15 -25
- package/src/platforms/teams/commands/reaction.test.ts +2 -7
- package/src/platforms/teams/commands/reaction.ts +12 -16
- package/src/platforms/teams/commands/snapshot.ts +6 -11
- package/src/platforms/teams/commands/team.test.ts +15 -26
- package/src/platforms/teams/commands/team.ts +10 -19
- package/src/platforms/teams/commands/user.ts +8 -14
- package/src/platforms/teams/credential-manager.test.ts +2 -5
- package/src/platforms/teams/token-extractor.test.ts +21 -50
- package/src/platforms/teams/token-extractor.ts +12 -20
- package/src/platforms/teams/types.ts +1 -1
- package/src/shared/utils/concurrency.test.ts +2 -2
- package/src/shared/utils/concurrency.ts +1 -1
- package/.claude/commands/release.md +0 -92
- package/dist/src/platforms/discord/commands/guild.d.ts +0 -15
- package/dist/src/platforms/discord/commands/guild.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/guild.js +0 -102
- 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 '
|
|
3
|
-
import { formatOutput } from '
|
|
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 '
|
|
3
|
-
import { formatOutput } from '
|
|
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 '
|
|
3
|
-
import { formatOutput } from '
|
|
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 '
|
|
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
|
-
|
|
563
|
-
|
|
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')
|
|
@@ -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
|
+
})
|