agent-messenger 1.3.6 → 1.5.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.
- package/.claude-plugin/README.md +38 -14
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/ci.yml +3 -0
- package/CONTRIBUTING.md +24 -1
- package/README.md +12 -8
- package/dist/package.json +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +3 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/platforms/discord/cli.d.ts +2 -2
- package/dist/src/platforms/discord/cli.d.ts.map +1 -1
- package/dist/src/platforms/discord/cli.js +23 -1
- package/dist/src/platforms/discord/cli.js.map +1 -1
- package/dist/src/platforms/discord/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/file.js +13 -7
- 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 +30 -30
- package/dist/src/platforms/discord/commands/friend.js.map +1 -1
- package/dist/src/platforms/discord/commands/index.d.ts +7 -0
- package/dist/src/platforms/discord/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/index.js +7 -0
- package/dist/src/platforms/discord/commands/index.js.map +1 -1
- package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/snapshot.js +1 -2
- package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/discord/ensure-auth.d.ts +2 -0
- package/dist/src/platforms/discord/ensure-auth.d.ts.map +1 -0
- package/dist/src/platforms/discord/ensure-auth.js +31 -0
- package/dist/src/platforms/discord/ensure-auth.js.map +1 -0
- package/dist/src/platforms/slack/cli.d.ts +2 -2
- package/dist/src/platforms/slack/cli.d.ts.map +1 -1
- package/dist/src/platforms/slack/cli.js +15 -0
- package/dist/src/platforms/slack/cli.js.map +1 -1
- package/dist/src/platforms/slack/client.d.ts +1 -0
- package/dist/src/platforms/slack/client.d.ts.map +1 -1
- package/dist/src/platforms/slack/client.js +13 -0
- package/dist/src/platforms/slack/client.js.map +1 -1
- package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/channel.js +2 -0
- package/dist/src/platforms/slack/commands/channel.js.map +1 -1
- package/dist/src/platforms/slack/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/file.js +13 -5
- 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 +12 -6
- 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 +3 -0
- package/dist/src/platforms/slack/commands/reaction.js.map +1 -1
- package/dist/src/platforms/slack/commands/sections.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/sections.js +5 -6
- 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 +1 -2
- 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 +2 -0
- package/dist/src/platforms/slack/commands/unread.js.map +1 -1
- package/dist/src/platforms/slack/commands/user.js +8 -8
- package/dist/src/platforms/slack/ensure-auth.d.ts +2 -0
- package/dist/src/platforms/slack/ensure-auth.d.ts.map +1 -0
- package/dist/src/platforms/slack/ensure-auth.js +30 -0
- package/dist/src/platforms/slack/ensure-auth.js.map +1 -0
- package/dist/src/platforms/slackbot/client.d.ts +1 -0
- package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/client.js +13 -0
- package/dist/src/platforms/slackbot/client.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/channel.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/channel.js +3 -2
- package/dist/src/platforms/slackbot/commands/channel.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.js +18 -12
- package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/reaction.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/reaction.js +8 -6
- package/dist/src/platforms/slackbot/commands/reaction.js.map +1 -1
- package/dist/src/platforms/teams/cli.d.ts +2 -2
- package/dist/src/platforms/teams/cli.d.ts.map +1 -1
- package/dist/src/platforms/teams/cli.js +15 -0
- package/dist/src/platforms/teams/cli.js.map +1 -1
- package/dist/src/platforms/teams/commands/file.js +12 -12
- package/dist/src/platforms/teams/commands/file.js.map +1 -1
- package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/snapshot.js +1 -2
- package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.d.ts +2 -0
- package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -0
- package/dist/src/platforms/teams/ensure-auth.js +32 -0
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -0
- package/e2e/README.md +1 -1
- package/package.json +1 -1
- package/skills/agent-discord/SKILL.md +22 -22
- package/skills/agent-slack/SKILL.md +28 -40
- package/skills/agent-teams/SKILL.md +41 -65
- package/skills/agent-teams/references/common-patterns.md +63 -49
- package/src/cli.ts +4 -0
- package/src/platforms/discord/cli.ts +30 -0
- package/src/platforms/discord/commands/file.ts +13 -7
- package/src/platforms/discord/commands/friend.ts +34 -34
- package/src/platforms/discord/commands/index.ts +7 -0
- package/src/platforms/discord/commands/snapshot.ts +1 -2
- package/src/platforms/discord/ensure-auth.test.ts +123 -0
- package/src/platforms/discord/ensure-auth.ts +31 -0
- package/src/platforms/slack/cli.ts +16 -0
- package/src/platforms/slack/client.test.ts +101 -0
- package/src/platforms/slack/client.ts +22 -0
- package/src/platforms/slack/commands/channel.ts +2 -0
- package/src/platforms/slack/commands/file.ts +15 -5
- package/src/platforms/slack/commands/message.ts +17 -6
- package/src/platforms/slack/commands/reaction.ts +3 -0
- package/src/platforms/slack/commands/sections.ts +8 -9
- package/src/platforms/slack/commands/snapshot.ts +1 -2
- package/src/platforms/slack/commands/unread.ts +2 -0
- package/src/platforms/slack/commands/user.ts +8 -8
- package/src/platforms/slack/ensure-auth.test.ts +186 -0
- package/src/platforms/slack/ensure-auth.ts +30 -0
- package/src/platforms/slackbot/client.test.ts +87 -0
- package/src/platforms/slackbot/client.ts +21 -0
- package/src/platforms/slackbot/commands/channel.ts +3 -2
- package/src/platforms/slackbot/commands/message.ts +18 -12
- package/src/platforms/slackbot/commands/reaction.ts +8 -6
- package/src/platforms/teams/cli.ts +16 -0
- package/src/platforms/teams/commands/file.ts +12 -12
- package/src/platforms/teams/commands/snapshot.ts +1 -2
- package/src/platforms/teams/ensure-auth.test.ts +167 -0
- package/src/platforms/teams/ensure-auth.ts +34 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
|
|
2
|
+
import { TeamsClient } from './client'
|
|
3
|
+
import { TeamsCredentialManager } from './credential-manager'
|
|
4
|
+
import { ensureTeamsAuth } from './ensure-auth'
|
|
5
|
+
import { TeamsTokenExtractor } from './token-extractor'
|
|
6
|
+
|
|
7
|
+
let loadConfigSpy: ReturnType<typeof spyOn>
|
|
8
|
+
let isTokenExpiredSpy: ReturnType<typeof spyOn>
|
|
9
|
+
let extractSpy: ReturnType<typeof spyOn>
|
|
10
|
+
let testAuthSpy: ReturnType<typeof spyOn>
|
|
11
|
+
let listTeamsSpy: ReturnType<typeof spyOn>
|
|
12
|
+
let saveConfigSpy: ReturnType<typeof spyOn>
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
loadConfigSpy = spyOn(TeamsCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
|
|
16
|
+
|
|
17
|
+
isTokenExpiredSpy = spyOn(TeamsCredentialManager.prototype, 'isTokenExpired').mockResolvedValue(true)
|
|
18
|
+
|
|
19
|
+
extractSpy = spyOn(TeamsTokenExtractor.prototype, 'extract').mockResolvedValue({
|
|
20
|
+
token: 'test-teams-token',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
testAuthSpy = spyOn(TeamsClient.prototype, 'testAuth').mockResolvedValue({
|
|
24
|
+
id: 'user-123',
|
|
25
|
+
displayName: 'Test User',
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
listTeamsSpy = spyOn(TeamsClient.prototype, 'listTeams').mockResolvedValue([
|
|
29
|
+
{ id: 'team-1', name: 'Team One' },
|
|
30
|
+
{ id: 'team-2', name: 'Team Two' },
|
|
31
|
+
])
|
|
32
|
+
|
|
33
|
+
saveConfigSpy = spyOn(TeamsCredentialManager.prototype, 'saveConfig').mockResolvedValue(undefined)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
loadConfigSpy?.mockRestore()
|
|
38
|
+
isTokenExpiredSpy?.mockRestore()
|
|
39
|
+
extractSpy?.mockRestore()
|
|
40
|
+
testAuthSpy?.mockRestore()
|
|
41
|
+
listTeamsSpy?.mockRestore()
|
|
42
|
+
saveConfigSpy?.mockRestore()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('ensureTeamsAuth', () => {
|
|
46
|
+
test('skips extraction when token exists and not expired', async () => {
|
|
47
|
+
// given
|
|
48
|
+
loadConfigSpy.mockResolvedValue({
|
|
49
|
+
token: 'existing-token',
|
|
50
|
+
current_team: 'team-1',
|
|
51
|
+
teams: { 'team-1': { team_id: 'team-1', team_name: 'Team One' } },
|
|
52
|
+
})
|
|
53
|
+
isTokenExpiredSpy.mockResolvedValue(false)
|
|
54
|
+
|
|
55
|
+
// when
|
|
56
|
+
await ensureTeamsAuth()
|
|
57
|
+
|
|
58
|
+
// then
|
|
59
|
+
expect(extractSpy).not.toHaveBeenCalled()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('extracts when no config exists', async () => {
|
|
63
|
+
// given
|
|
64
|
+
loadConfigSpy.mockResolvedValue(null)
|
|
65
|
+
|
|
66
|
+
// when
|
|
67
|
+
await ensureTeamsAuth()
|
|
68
|
+
|
|
69
|
+
// then
|
|
70
|
+
expect(extractSpy).toHaveBeenCalled()
|
|
71
|
+
expect(testAuthSpy).toHaveBeenCalled()
|
|
72
|
+
expect(saveConfigSpy).toHaveBeenCalledWith(
|
|
73
|
+
expect.objectContaining({
|
|
74
|
+
token: 'test-teams-token',
|
|
75
|
+
current_team: 'team-1',
|
|
76
|
+
teams: {
|
|
77
|
+
'team-1': { team_id: 'team-1', team_name: 'Team One' },
|
|
78
|
+
'team-2': { team_id: 'team-2', team_name: 'Team Two' },
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('re-extracts when token is expired', async () => {
|
|
85
|
+
// given
|
|
86
|
+
loadConfigSpy.mockResolvedValue({
|
|
87
|
+
token: 'expired-token',
|
|
88
|
+
current_team: 'team-1',
|
|
89
|
+
teams: { 'team-1': { team_id: 'team-1', team_name: 'Team One' } },
|
|
90
|
+
token_expires_at: new Date(Date.now() - 3600000).toISOString(),
|
|
91
|
+
})
|
|
92
|
+
isTokenExpiredSpy.mockResolvedValue(true)
|
|
93
|
+
|
|
94
|
+
// when
|
|
95
|
+
await ensureTeamsAuth()
|
|
96
|
+
|
|
97
|
+
// then
|
|
98
|
+
expect(extractSpy).toHaveBeenCalled()
|
|
99
|
+
expect(saveConfigSpy).toHaveBeenCalledWith(expect.objectContaining({ token: 'test-teams-token' }))
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('sets first team as current', async () => {
|
|
103
|
+
// when
|
|
104
|
+
await ensureTeamsAuth()
|
|
105
|
+
|
|
106
|
+
// then
|
|
107
|
+
expect(saveConfigSpy).toHaveBeenCalledWith(expect.objectContaining({ current_team: 'team-1' }))
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('saves token_expires_at', async () => {
|
|
111
|
+
// when
|
|
112
|
+
const before = Date.now()
|
|
113
|
+
await ensureTeamsAuth()
|
|
114
|
+
const after = Date.now()
|
|
115
|
+
|
|
116
|
+
// then
|
|
117
|
+
const savedConfig = saveConfigSpy.mock.calls[0][0]
|
|
118
|
+
const expiresAt = new Date(savedConfig.token_expires_at).getTime()
|
|
119
|
+
expect(expiresAt).toBeGreaterThanOrEqual(before + 60 * 60 * 1000 - 1)
|
|
120
|
+
expect(expiresAt).toBeLessThanOrEqual(after + 60 * 60 * 1000 + 1)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('does not save when extraction returns null', async () => {
|
|
124
|
+
// given
|
|
125
|
+
extractSpy.mockResolvedValue(null)
|
|
126
|
+
|
|
127
|
+
// when
|
|
128
|
+
await ensureTeamsAuth()
|
|
129
|
+
|
|
130
|
+
// then
|
|
131
|
+
expect(testAuthSpy).not.toHaveBeenCalled()
|
|
132
|
+
expect(saveConfigSpy).not.toHaveBeenCalled()
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('does not save when no teams found', async () => {
|
|
136
|
+
// given
|
|
137
|
+
listTeamsSpy.mockResolvedValue([])
|
|
138
|
+
|
|
139
|
+
// when
|
|
140
|
+
await ensureTeamsAuth()
|
|
141
|
+
|
|
142
|
+
// then
|
|
143
|
+
expect(saveConfigSpy).not.toHaveBeenCalled()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('silently handles extraction failure', async () => {
|
|
147
|
+
// given
|
|
148
|
+
extractSpy.mockRejectedValue(new Error('Teams not found'))
|
|
149
|
+
|
|
150
|
+
// when
|
|
151
|
+
await ensureTeamsAuth()
|
|
152
|
+
|
|
153
|
+
// then
|
|
154
|
+
expect(saveConfigSpy).not.toHaveBeenCalled()
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('silently handles auth validation failure', async () => {
|
|
158
|
+
// given
|
|
159
|
+
testAuthSpy.mockRejectedValue(new Error('401 Unauthorized'))
|
|
160
|
+
|
|
161
|
+
// when
|
|
162
|
+
await ensureTeamsAuth()
|
|
163
|
+
|
|
164
|
+
// then
|
|
165
|
+
expect(saveConfigSpy).not.toHaveBeenCalled()
|
|
166
|
+
})
|
|
167
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TeamsClient } from './client'
|
|
2
|
+
import { TeamsCredentialManager } from './credential-manager'
|
|
3
|
+
import { TeamsTokenExtractor } from './token-extractor'
|
|
4
|
+
|
|
5
|
+
export async function ensureTeamsAuth(): Promise<void> {
|
|
6
|
+
try {
|
|
7
|
+
const credManager = new TeamsCredentialManager()
|
|
8
|
+
const config = await credManager.loadConfig()
|
|
9
|
+
|
|
10
|
+
if (config?.token && !(await credManager.isTokenExpired())) return
|
|
11
|
+
|
|
12
|
+
const extractor = new TeamsTokenExtractor()
|
|
13
|
+
const extracted = await extractor.extract()
|
|
14
|
+
if (!extracted) return
|
|
15
|
+
|
|
16
|
+
const client = new TeamsClient(extracted.token)
|
|
17
|
+
await client.testAuth()
|
|
18
|
+
|
|
19
|
+
const teams = await client.listTeams()
|
|
20
|
+
if (teams.length === 0) return
|
|
21
|
+
|
|
22
|
+
const teamMap: Record<string, { team_id: string; team_name: string }> = {}
|
|
23
|
+
for (const team of teams) {
|
|
24
|
+
teamMap[team.id] = { team_id: team.id, team_name: team.name }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await credManager.saveConfig({
|
|
28
|
+
token: extracted.token,
|
|
29
|
+
current_team: teams[0].id,
|
|
30
|
+
teams: teamMap,
|
|
31
|
+
token_expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
|
32
|
+
})
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|