agent-messenger 1.0.0 → 1.1.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/commands/release.md +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/e2e.yml.disabled +69 -0
- package/README.md +16 -14
- package/biome.json +33 -1
- package/bun.lock +63 -0
- package/dist/package.json +8 -4
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +4 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/platforms/discord/cli.js +1 -1
- package/dist/src/platforms/discord/client.d.ts.map +1 -1
- package/dist/src/platforms/discord/client.js +3 -3
- package/dist/src/platforms/discord/client.js.map +1 -1
- package/dist/src/platforms/discord/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/user.js +10 -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 +18 -12
- package/dist/src/platforms/discord/credential-manager.js.map +1 -1
- package/dist/src/platforms/slack/cli.js +1 -1
- package/dist/src/platforms/slack/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slack/credential-manager.js +20 -6
- package/dist/src/platforms/slack/credential-manager.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +34 -9
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/teams/cli.d.ts.map +1 -0
- package/dist/{cli.js → src/platforms/teams/cli.js} +11 -10
- package/dist/src/platforms/teams/cli.js.map +1 -0
- package/dist/src/platforms/teams/client.d.ts +32 -0
- package/dist/src/platforms/teams/client.d.ts.map +1 -0
- package/dist/src/platforms/teams/client.js +202 -0
- package/dist/src/platforms/teams/client.js.map +1 -0
- package/dist/src/platforms/teams/commands/auth.d.ts +14 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/auth.js +176 -0
- package/dist/src/platforms/teams/commands/auth.js.map +1 -0
- package/dist/src/platforms/teams/commands/channel.d.ts +13 -0
- package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/channel.js +97 -0
- package/dist/src/platforms/teams/commands/channel.js.map +1 -0
- package/dist/src/platforms/teams/commands/file.d.ts +12 -0
- package/dist/src/platforms/teams/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/file.js +104 -0
- package/dist/src/platforms/teams/commands/file.js.map +1 -0
- package/dist/{commands → src/platforms/teams/commands}/index.d.ts +5 -2
- package/dist/src/platforms/teams/commands/index.d.ts.map +1 -0
- package/dist/{commands → src/platforms/teams/commands}/index.js +5 -2
- package/dist/src/platforms/teams/commands/index.js.map +1 -0
- package/dist/src/platforms/teams/commands/message.d.ts +17 -0
- package/dist/src/platforms/teams/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/message.js +133 -0
- package/dist/src/platforms/teams/commands/message.js.map +1 -0
- package/dist/src/platforms/teams/commands/reaction.d.ts +9 -0
- package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/reaction.js +68 -0
- package/dist/src/platforms/teams/commands/reaction.js.map +1 -0
- package/dist/src/platforms/teams/commands/snapshot.d.ts +10 -0
- package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/snapshot.js +85 -0
- package/dist/src/platforms/teams/commands/snapshot.js.map +1 -0
- package/dist/src/platforms/teams/commands/team.d.ts +18 -0
- package/dist/src/platforms/teams/commands/team.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/team.js +130 -0
- package/dist/src/platforms/teams/commands/team.js.map +1 -0
- package/dist/src/platforms/teams/commands/user.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/user.js +88 -0
- package/dist/src/platforms/teams/commands/user.js.map +1 -0
- package/dist/src/platforms/teams/credential-manager.d.ts +18 -0
- package/dist/src/platforms/teams/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/teams/credential-manager.js +81 -0
- package/dist/src/platforms/teams/credential-manager.js.map +1 -0
- package/dist/src/platforms/teams/index.d.ts +4 -0
- package/dist/src/platforms/teams/index.d.ts.map +1 -0
- package/dist/src/platforms/teams/index.js +6 -0
- package/dist/src/platforms/teams/index.js.map +1 -0
- package/dist/src/platforms/teams/token-extractor.d.ts +36 -0
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -0
- package/dist/src/platforms/teams/token-extractor.js +335 -0
- package/dist/src/platforms/teams/token-extractor.js.map +1 -0
- package/dist/src/platforms/teams/types.d.ts +209 -0
- package/dist/src/platforms/teams/types.d.ts.map +1 -0
- package/dist/src/platforms/teams/types.js +65 -0
- package/dist/src/platforms/teams/types.js.map +1 -0
- package/docs/teams.md +321 -0
- package/e2e/README.md +256 -0
- package/e2e/config.ts +45 -0
- package/e2e/discord.e2e.test.ts +252 -0
- package/e2e/helpers.ts +107 -0
- package/e2e/slack.e2e.test.ts +309 -0
- package/package.json +8 -4
- package/scripts/postbuild.ts +15 -0
- package/skills/agent-teams/SKILL.md +292 -0
- package/skills/agent-teams/references/authentication.md +375 -0
- package/skills/agent-teams/references/common-patterns.md +596 -0
- package/skills/agent-teams/templates/monitor-channel.sh +239 -0
- package/skills/agent-teams/templates/post-message.sh +224 -0
- package/skills/agent-teams/templates/team-summary.sh +210 -0
- package/src/cli.ts +4 -0
- package/src/platforms/discord/client.ts +3 -3
- package/src/platforms/discord/commands/auth.test.ts +48 -32
- package/src/platforms/discord/commands/channel.test.ts +54 -42
- package/src/platforms/discord/commands/file.test.ts +40 -53
- package/src/platforms/discord/commands/guild.test.ts +47 -27
- package/src/platforms/discord/commands/message.test.ts +54 -51
- package/src/platforms/discord/commands/reaction.test.ts +54 -42
- package/src/platforms/discord/commands/user.ts +12 -1
- package/src/platforms/discord/credential-manager.test.ts +137 -136
- package/src/platforms/discord/credential-manager.ts +20 -13
- package/src/platforms/discord/token-extractor.test.ts +133 -383
- package/{tests → src/platforms/slack}/cli.test.ts +3 -3
- package/{tests/slack-client.test.ts → src/platforms/slack/client.test.ts} +1 -1
- package/{tests → src/platforms/slack}/commands/auth.test.ts +25 -13
- package/{tests → src/platforms/slack}/commands/channel.test.ts +2 -2
- package/{tests → src/platforms/slack}/commands/file.test.ts +2 -2
- package/{tests → src/platforms/slack}/commands/message.test.ts +2 -2
- package/{tests → src/platforms/slack}/commands/reaction.test.ts +1 -1
- package/{tests → src/platforms/slack}/commands/snapshot.test.ts +117 -105
- package/{tests → src/platforms/slack}/commands/user.test.ts +3 -3
- package/{tests → src/platforms/slack}/commands/workspace.test.ts +44 -95
- package/{tests → src/platforms/slack}/credential-manager.test.ts +2 -2
- package/src/platforms/slack/credential-manager.ts +22 -7
- package/src/platforms/slack/token-extractor-node-test.ts +40 -0
- package/src/platforms/slack/token-extractor-node.test.ts +10 -0
- package/src/platforms/slack/token-extractor.ts +36 -10
- package/{tests → src/platforms/slack}/types.test.ts +1 -1
- package/src/platforms/teams/cli.ts +36 -0
- package/src/platforms/teams/client.test.ts +500 -0
- package/src/platforms/teams/client.ts +365 -0
- package/src/platforms/teams/commands/auth.test.ts +99 -0
- package/src/platforms/teams/commands/auth.ts +232 -0
- package/src/platforms/teams/commands/channel.test.ts +147 -0
- package/src/platforms/teams/commands/channel.ts +129 -0
- package/src/platforms/teams/commands/file.test.ts +88 -0
- package/src/platforms/teams/commands/file.ts +144 -0
- package/src/platforms/teams/commands/index.ts +12 -0
- package/src/platforms/teams/commands/message.test.ts +110 -0
- package/src/platforms/teams/commands/message.ts +188 -0
- package/src/platforms/teams/commands/reaction.test.ts +87 -0
- package/src/platforms/teams/commands/reaction.ts +104 -0
- package/src/platforms/teams/commands/snapshot.test.ts +35 -0
- package/src/platforms/teams/commands/snapshot.ts +115 -0
- package/src/platforms/teams/commands/team.test.ts +157 -0
- package/src/platforms/teams/commands/team.ts +164 -0
- package/src/platforms/teams/commands/user.test.ts +83 -0
- package/src/platforms/teams/commands/user.ts +112 -0
- package/src/platforms/teams/credential-manager.test.ts +178 -0
- package/src/platforms/teams/credential-manager.ts +92 -0
- package/src/platforms/teams/index.ts +5 -0
- package/src/platforms/teams/token-extractor.test.ts +429 -0
- package/src/platforms/teams/token-extractor.ts +462 -0
- package/src/platforms/teams/types.test.ts +226 -0
- package/src/platforms/teams/types.ts +140 -0
- package/tsconfig.json +1 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/auth.d.ts +0 -3
- package/dist/commands/auth.d.ts.map +0 -1
- package/dist/commands/auth.js +0 -140
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/channel.d.ts +0 -3
- package/dist/commands/channel.d.ts.map +0 -1
- package/dist/commands/channel.js +0 -118
- package/dist/commands/channel.js.map +0 -1
- package/dist/commands/file.d.ts +0 -3
- package/dist/commands/file.d.ts.map +0 -1
- package/dist/commands/file.js +0 -113
- package/dist/commands/file.js.map +0 -1
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/message.d.ts +0 -3
- package/dist/commands/message.d.ts.map +0 -1
- package/dist/commands/message.js +0 -214
- package/dist/commands/message.js.map +0 -1
- package/dist/commands/reaction.d.ts +0 -3
- package/dist/commands/reaction.d.ts.map +0 -1
- package/dist/commands/reaction.js +0 -100
- package/dist/commands/reaction.js.map +0 -1
- package/dist/commands/snapshot.d.ts +0 -3
- package/dist/commands/snapshot.d.ts.map +0 -1
- package/dist/commands/snapshot.js +0 -88
- package/dist/commands/snapshot.js.map +0 -1
- package/dist/commands/user.d.ts.map +0 -1
- package/dist/commands/user.js +0 -96
- package/dist/commands/user.js.map +0 -1
- package/dist/commands/workspace.d.ts +0 -3
- package/dist/commands/workspace.d.ts.map +0 -1
- package/dist/commands/workspace.js +0 -89
- package/dist/commands/workspace.js.map +0 -1
- package/dist/lib/credential-manager.d.ts +0 -13
- package/dist/lib/credential-manager.d.ts.map +0 -1
- package/dist/lib/credential-manager.js +0 -58
- package/dist/lib/credential-manager.js.map +0 -1
- package/dist/lib/index.d.ts +0 -3
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js +0 -3
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/ref-manager.d.ts +0 -26
- package/dist/lib/ref-manager.d.ts.map +0 -1
- package/dist/lib/ref-manager.js +0 -92
- package/dist/lib/ref-manager.js.map +0 -1
- package/dist/lib/slack-client.d.ts +0 -37
- package/dist/lib/slack-client.d.ts.map +0 -1
- package/dist/lib/slack-client.js +0 -379
- package/dist/lib/slack-client.js.map +0 -1
- package/dist/lib/token-extractor.d.ts +0 -28
- package/dist/lib/token-extractor.d.ts.map +0 -1
- package/dist/lib/token-extractor.js +0 -401
- package/dist/lib/token-extractor.js.map +0 -1
- package/dist/src/platforms/discord/client.test.d.ts +0 -2
- package/dist/src/platforms/discord/client.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/client.test.js +0 -367
- package/dist/src/platforms/discord/client.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/auth.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/auth.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/auth.test.js +0 -65
- package/dist/src/platforms/discord/commands/auth.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/channel.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/channel.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/channel.test.js +0 -136
- package/dist/src/platforms/discord/commands/channel.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/file.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/file.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/file.test.js +0 -83
- package/dist/src/platforms/discord/commands/file.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/guild.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/guild.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/guild.test.js +0 -100
- package/dist/src/platforms/discord/commands/guild.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/message.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/message.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/message.test.js +0 -91
- package/dist/src/platforms/discord/commands/message.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/reaction.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/reaction.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/reaction.test.js +0 -115
- package/dist/src/platforms/discord/commands/reaction.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/snapshot.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/snapshot.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/snapshot.test.js +0 -25
- package/dist/src/platforms/discord/commands/snapshot.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/user.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/user.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/user.test.js +0 -103
- package/dist/src/platforms/discord/commands/user.test.js.map +0 -1
- package/dist/src/platforms/discord/credential-manager.test.d.ts +0 -2
- package/dist/src/platforms/discord/credential-manager.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/credential-manager.test.js +0 -136
- package/dist/src/platforms/discord/credential-manager.test.js.map +0 -1
- package/dist/src/platforms/discord/token-extractor.test.d.ts +0 -2
- package/dist/src/platforms/discord/token-extractor.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/token-extractor.test.js +0 -789
- package/dist/src/platforms/discord/token-extractor.test.js.map +0 -1
- package/dist/src/platforms/discord/types.test.d.ts +0 -2
- package/dist/src/platforms/discord/types.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/types.test.js +0 -211
- package/dist/src/platforms/discord/types.test.js.map +0 -1
- package/dist/src/shared/utils/concurrency.test.d.ts +0 -2
- package/dist/src/shared/utils/concurrency.test.d.ts.map +0 -1
- package/dist/src/shared/utils/concurrency.test.js +0 -39
- package/dist/src/shared/utils/concurrency.test.js.map +0 -1
- package/dist/tests/cli.test.d.ts +0 -2
- package/dist/tests/cli.test.d.ts.map +0 -1
- package/dist/tests/cli.test.js +0 -83
- package/dist/tests/cli.test.js.map +0 -1
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/CURRENT +0 -1
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOCK +0 -0
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG +0 -3
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG.old +0 -1
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/MANIFEST-000004 +0 -0
- package/dist/tests/commands/auth.test.d.ts +0 -2
- package/dist/tests/commands/auth.test.d.ts.map +0 -1
- package/dist/tests/commands/auth.test.js +0 -304
- package/dist/tests/commands/auth.test.js.map +0 -1
- package/dist/tests/commands/channel.test.d.ts +0 -2
- package/dist/tests/commands/channel.test.d.ts.map +0 -1
- package/dist/tests/commands/channel.test.js +0 -166
- package/dist/tests/commands/channel.test.js.map +0 -1
- package/dist/tests/commands/file.test.d.ts +0 -2
- package/dist/tests/commands/file.test.d.ts.map +0 -1
- package/dist/tests/commands/file.test.js +0 -175
- package/dist/tests/commands/file.test.js.map +0 -1
- package/dist/tests/commands/message.test.d.ts +0 -2
- package/dist/tests/commands/message.test.d.ts.map +0 -1
- package/dist/tests/commands/message.test.js +0 -293
- package/dist/tests/commands/message.test.js.map +0 -1
- package/dist/tests/commands/reaction.test.d.ts +0 -2
- package/dist/tests/commands/reaction.test.d.ts.map +0 -1
- package/dist/tests/commands/reaction.test.js +0 -84
- package/dist/tests/commands/reaction.test.js.map +0 -1
- package/dist/tests/commands/snapshot.test.d.ts +0 -2
- package/dist/tests/commands/snapshot.test.d.ts.map +0 -1
- package/dist/tests/commands/snapshot.test.js +0 -280
- package/dist/tests/commands/snapshot.test.js.map +0 -1
- package/dist/tests/commands/user.test.d.ts +0 -2
- package/dist/tests/commands/user.test.d.ts.map +0 -1
- package/dist/tests/commands/user.test.js +0 -117
- package/dist/tests/commands/user.test.js.map +0 -1
- package/dist/tests/commands/workspace.test.d.ts +0 -2
- package/dist/tests/commands/workspace.test.d.ts.map +0 -1
- package/dist/tests/commands/workspace.test.js +0 -453
- package/dist/tests/commands/workspace.test.js.map +0 -1
- package/dist/tests/credential-manager.test.d.ts +0 -2
- package/dist/tests/credential-manager.test.d.ts.map +0 -1
- package/dist/tests/credential-manager.test.js +0 -199
- package/dist/tests/credential-manager.test.js.map +0 -1
- package/dist/tests/slack-client.test.d.ts +0 -2
- package/dist/tests/slack-client.test.d.ts.map +0 -1
- package/dist/tests/slack-client.test.js +0 -741
- package/dist/tests/slack-client.test.js.map +0 -1
- package/dist/tests/types.test.d.ts +0 -2
- package/dist/tests/types.test.d.ts.map +0 -1
- package/dist/tests/types.test.js +0 -215
- package/dist/tests/types.test.js.map +0 -1
- package/dist/types/index.d.ts +0 -369
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -92
- package/dist/types/index.js.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -2
- package/dist/utils/error-handler.d.ts.map +0 -1
- package/dist/utils/error-handler.js +0 -5
- package/dist/utils/error-handler.js.map +0 -1
- package/dist/utils/output.d.ts +0 -2
- package/dist/utils/output.d.ts.map +0 -1
- package/dist/utils/output.js +0 -4
- package/dist/utils/output.js.map +0 -1
- /package/dist/{cli.d.ts → src/platforms/teams/cli.d.ts} +0 -0
- /package/dist/{commands → src/platforms/teams/commands}/user.d.ts +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { handleError } from '../../../shared/utils/error-handler'
|
|
3
|
+
import { formatOutput } from '../../../shared/utils/output'
|
|
4
|
+
import { TeamsClient } from '../client'
|
|
5
|
+
import { TeamsCredentialManager } from '../credential-manager'
|
|
6
|
+
import type { TeamsMessage } from '../types'
|
|
7
|
+
|
|
8
|
+
export async function sendAction(
|
|
9
|
+
teamId: string,
|
|
10
|
+
channelId: string,
|
|
11
|
+
content: string,
|
|
12
|
+
options: { pretty?: boolean }
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
try {
|
|
15
|
+
const credManager = new TeamsCredentialManager()
|
|
16
|
+
const config = await credManager.loadConfig()
|
|
17
|
+
|
|
18
|
+
if (!config?.token) {
|
|
19
|
+
console.log(
|
|
20
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
21
|
+
)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
26
|
+
const message = await client.sendMessage(teamId, channelId, content)
|
|
27
|
+
|
|
28
|
+
const output = {
|
|
29
|
+
id: message.id,
|
|
30
|
+
content: message.content,
|
|
31
|
+
author: message.author.displayName,
|
|
32
|
+
timestamp: message.timestamp,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log(formatOutput(output, options.pretty))
|
|
36
|
+
} catch (error) {
|
|
37
|
+
handleError(error as Error)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function listAction(
|
|
42
|
+
teamId: string,
|
|
43
|
+
channelId: string,
|
|
44
|
+
options: { limit?: number; pretty?: boolean }
|
|
45
|
+
): Promise<void> {
|
|
46
|
+
try {
|
|
47
|
+
const credManager = new TeamsCredentialManager()
|
|
48
|
+
const config = await credManager.loadConfig()
|
|
49
|
+
|
|
50
|
+
if (!config?.token) {
|
|
51
|
+
console.log(
|
|
52
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
53
|
+
)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
58
|
+
const limit = options.limit || 50
|
|
59
|
+
const messages = await client.getMessages(teamId, channelId, limit)
|
|
60
|
+
|
|
61
|
+
const output = messages.map((msg: TeamsMessage) => ({
|
|
62
|
+
id: msg.id,
|
|
63
|
+
content: msg.content,
|
|
64
|
+
author: msg.author.displayName,
|
|
65
|
+
timestamp: msg.timestamp,
|
|
66
|
+
}))
|
|
67
|
+
|
|
68
|
+
console.log(formatOutput(output, options.pretty))
|
|
69
|
+
} catch (error) {
|
|
70
|
+
handleError(error as Error)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function getAction(
|
|
75
|
+
teamId: string,
|
|
76
|
+
channelId: string,
|
|
77
|
+
messageId: string,
|
|
78
|
+
options: { pretty?: boolean }
|
|
79
|
+
): Promise<void> {
|
|
80
|
+
try {
|
|
81
|
+
const credManager = new TeamsCredentialManager()
|
|
82
|
+
const config = await credManager.loadConfig()
|
|
83
|
+
|
|
84
|
+
if (!config?.token) {
|
|
85
|
+
console.log(
|
|
86
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
87
|
+
)
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
92
|
+
const message = await client.getMessage(teamId, channelId, messageId)
|
|
93
|
+
|
|
94
|
+
if (!message) {
|
|
95
|
+
console.log(formatOutput({ error: `Message not found: ${messageId}` }, options.pretty))
|
|
96
|
+
process.exit(1)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const output = {
|
|
100
|
+
id: message.id,
|
|
101
|
+
content: message.content,
|
|
102
|
+
author: message.author.displayName,
|
|
103
|
+
timestamp: message.timestamp,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log(formatOutput(output, options.pretty))
|
|
107
|
+
} catch (error) {
|
|
108
|
+
handleError(error as Error)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function deleteAction(
|
|
113
|
+
teamId: string,
|
|
114
|
+
channelId: string,
|
|
115
|
+
messageId: string,
|
|
116
|
+
options: { force?: boolean; pretty?: boolean }
|
|
117
|
+
): Promise<void> {
|
|
118
|
+
try {
|
|
119
|
+
const credManager = new TeamsCredentialManager()
|
|
120
|
+
const config = await credManager.loadConfig()
|
|
121
|
+
|
|
122
|
+
if (!config?.token) {
|
|
123
|
+
console.log(
|
|
124
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
125
|
+
)
|
|
126
|
+
process.exit(1)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!options.force) {
|
|
130
|
+
console.log(
|
|
131
|
+
formatOutput({ warning: 'Use --force to confirm deletion', messageId }, options.pretty)
|
|
132
|
+
)
|
|
133
|
+
process.exit(0)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
137
|
+
await client.deleteMessage(teamId, channelId, messageId)
|
|
138
|
+
|
|
139
|
+
console.log(formatOutput({ deleted: messageId }, options.pretty))
|
|
140
|
+
} catch (error) {
|
|
141
|
+
handleError(error as Error)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export const messageCommand = new Command('message')
|
|
146
|
+
.description('Message commands')
|
|
147
|
+
.addCommand(
|
|
148
|
+
new Command('send')
|
|
149
|
+
.description('Send message to channel')
|
|
150
|
+
.argument('<team-id>', 'Team ID')
|
|
151
|
+
.argument('<channel-id>', 'Channel ID')
|
|
152
|
+
.argument('<content>', 'Message content')
|
|
153
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
154
|
+
.action(sendAction)
|
|
155
|
+
)
|
|
156
|
+
.addCommand(
|
|
157
|
+
new Command('list')
|
|
158
|
+
.description('List messages from channel')
|
|
159
|
+
.argument('<team-id>', 'Team ID')
|
|
160
|
+
.argument('<channel-id>', 'Channel ID')
|
|
161
|
+
.option('--limit <n>', 'Number of messages to retrieve', '50')
|
|
162
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
163
|
+
.action((teamId: string, channelId: string, options: any) => {
|
|
164
|
+
return listAction(teamId, channelId, {
|
|
165
|
+
limit: parseInt(options.limit, 10),
|
|
166
|
+
pretty: options.pretty,
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
)
|
|
170
|
+
.addCommand(
|
|
171
|
+
new Command('get')
|
|
172
|
+
.description('Get a single message by ID')
|
|
173
|
+
.argument('<team-id>', 'Team ID')
|
|
174
|
+
.argument('<channel-id>', 'Channel ID')
|
|
175
|
+
.argument('<message-id>', 'Message ID')
|
|
176
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
177
|
+
.action(getAction)
|
|
178
|
+
)
|
|
179
|
+
.addCommand(
|
|
180
|
+
new Command('delete')
|
|
181
|
+
.description('Delete message')
|
|
182
|
+
.argument('<team-id>', 'Team ID')
|
|
183
|
+
.argument('<channel-id>', 'Channel ID')
|
|
184
|
+
.argument('<message-id>', 'Message ID')
|
|
185
|
+
.option('--force', 'Skip confirmation')
|
|
186
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
187
|
+
.action(deleteAction)
|
|
188
|
+
)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
|
|
2
|
+
import { TeamsClient } from '../client'
|
|
3
|
+
import { TeamsCredentialManager } from '../credential-manager'
|
|
4
|
+
import { addAction, removeAction } from './reaction'
|
|
5
|
+
|
|
6
|
+
let clientAddReactionSpy: ReturnType<typeof spyOn>
|
|
7
|
+
let clientRemoveReactionSpy: ReturnType<typeof spyOn>
|
|
8
|
+
let credManagerLoadConfigSpy: ReturnType<typeof spyOn>
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
clientAddReactionSpy = spyOn(TeamsClient.prototype, 'addReaction').mockResolvedValue(undefined)
|
|
12
|
+
clientRemoveReactionSpy = spyOn(TeamsClient.prototype, 'removeReaction').mockResolvedValue(
|
|
13
|
+
undefined
|
|
14
|
+
)
|
|
15
|
+
credManagerLoadConfigSpy = spyOn(
|
|
16
|
+
TeamsCredentialManager.prototype,
|
|
17
|
+
'loadConfig'
|
|
18
|
+
).mockResolvedValue({
|
|
19
|
+
token: 'test-token',
|
|
20
|
+
current_team: null,
|
|
21
|
+
teams: {},
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
clientAddReactionSpy?.mockRestore()
|
|
27
|
+
clientRemoveReactionSpy?.mockRestore()
|
|
28
|
+
credManagerLoadConfigSpy?.mockRestore()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('add: sends correct POST request with emoji', async () => {
|
|
32
|
+
const consoleSpy = mock((_msg: string) => {})
|
|
33
|
+
const originalLog = console.log
|
|
34
|
+
console.log = consoleSpy
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await addAction('team123', 'ch123', 'msg123', 'like', { pretty: false })
|
|
38
|
+
expect(consoleSpy).toHaveBeenCalled()
|
|
39
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
40
|
+
expect(output.success).toBe(true)
|
|
41
|
+
expect(output.team_id).toBe('team123')
|
|
42
|
+
expect(output.channel_id).toBe('ch123')
|
|
43
|
+
expect(output.message_id).toBe('msg123')
|
|
44
|
+
expect(output.emoji).toBe('like')
|
|
45
|
+
} finally {
|
|
46
|
+
console.log = originalLog
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('remove: sends correct DELETE request with emoji', async () => {
|
|
51
|
+
const consoleSpy = mock((_msg: string) => {})
|
|
52
|
+
const originalLog = console.log
|
|
53
|
+
console.log = consoleSpy
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await removeAction('team123', 'ch123', 'msg123', 'like', { pretty: false })
|
|
57
|
+
expect(consoleSpy).toHaveBeenCalled()
|
|
58
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
59
|
+
expect(output.success).toBe(true)
|
|
60
|
+
expect(output.team_id).toBe('team123')
|
|
61
|
+
expect(output.channel_id).toBe('ch123')
|
|
62
|
+
expect(output.message_id).toBe('msg123')
|
|
63
|
+
expect(output.emoji).toBe('like')
|
|
64
|
+
} finally {
|
|
65
|
+
console.log = originalLog
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('add: handles missing token gracefully', async () => {
|
|
70
|
+
credManagerLoadConfigSpy?.mockResolvedValue(null)
|
|
71
|
+
|
|
72
|
+
const consoleSpy = mock((_msg: string) => {})
|
|
73
|
+
const originalLog = console.log
|
|
74
|
+
const originalExit = process.exit
|
|
75
|
+
process.exit = mock(() => {}) as any
|
|
76
|
+
console.log = consoleSpy
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await addAction('team123', 'ch123', 'msg123', 'like', { pretty: false })
|
|
80
|
+
expect(consoleSpy).toHaveBeenCalled()
|
|
81
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
82
|
+
expect(output.error).toBeDefined()
|
|
83
|
+
} finally {
|
|
84
|
+
console.log = originalLog
|
|
85
|
+
process.exit = originalExit
|
|
86
|
+
}
|
|
87
|
+
})
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { handleError } from '../../../shared/utils/error-handler'
|
|
3
|
+
import { formatOutput } from '../../../shared/utils/output'
|
|
4
|
+
import { TeamsClient } from '../client'
|
|
5
|
+
import { TeamsCredentialManager } from '../credential-manager'
|
|
6
|
+
|
|
7
|
+
export async function addAction(
|
|
8
|
+
teamId: string,
|
|
9
|
+
channelId: string,
|
|
10
|
+
messageId: string,
|
|
11
|
+
emoji: string,
|
|
12
|
+
options: { pretty?: boolean }
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
try {
|
|
15
|
+
const credManager = new TeamsCredentialManager()
|
|
16
|
+
const config = await credManager.loadConfig()
|
|
17
|
+
|
|
18
|
+
if (!config?.token) {
|
|
19
|
+
console.log(
|
|
20
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
21
|
+
)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
26
|
+
await client.addReaction(teamId, channelId, messageId, emoji)
|
|
27
|
+
|
|
28
|
+
console.log(
|
|
29
|
+
formatOutput(
|
|
30
|
+
{
|
|
31
|
+
success: true,
|
|
32
|
+
team_id: teamId,
|
|
33
|
+
channel_id: channelId,
|
|
34
|
+
message_id: messageId,
|
|
35
|
+
emoji,
|
|
36
|
+
},
|
|
37
|
+
options.pretty
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
} catch (error) {
|
|
41
|
+
handleError(error as Error)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function removeAction(
|
|
46
|
+
teamId: string,
|
|
47
|
+
channelId: string,
|
|
48
|
+
messageId: string,
|
|
49
|
+
emoji: string,
|
|
50
|
+
options: { pretty?: boolean }
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
try {
|
|
53
|
+
const credManager = new TeamsCredentialManager()
|
|
54
|
+
const config = await credManager.loadConfig()
|
|
55
|
+
|
|
56
|
+
if (!config?.token) {
|
|
57
|
+
console.log(
|
|
58
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
59
|
+
)
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
64
|
+
await client.removeReaction(teamId, channelId, messageId, emoji)
|
|
65
|
+
|
|
66
|
+
console.log(
|
|
67
|
+
formatOutput(
|
|
68
|
+
{
|
|
69
|
+
success: true,
|
|
70
|
+
team_id: teamId,
|
|
71
|
+
channel_id: channelId,
|
|
72
|
+
message_id: messageId,
|
|
73
|
+
emoji,
|
|
74
|
+
},
|
|
75
|
+
options.pretty
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
} catch (error) {
|
|
79
|
+
handleError(error as Error)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const reactionCommand = new Command('reaction')
|
|
84
|
+
.description('Reaction commands')
|
|
85
|
+
.addCommand(
|
|
86
|
+
new Command('add')
|
|
87
|
+
.description('Add emoji reaction to message')
|
|
88
|
+
.argument('<team-id>', 'Team ID')
|
|
89
|
+
.argument('<channel-id>', 'Channel ID')
|
|
90
|
+
.argument('<message-id>', 'Message ID')
|
|
91
|
+
.argument('<emoji>', 'Emoji name')
|
|
92
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
93
|
+
.action(addAction)
|
|
94
|
+
)
|
|
95
|
+
.addCommand(
|
|
96
|
+
new Command('remove')
|
|
97
|
+
.description('Remove emoji reaction from message')
|
|
98
|
+
.argument('<team-id>', 'Team ID')
|
|
99
|
+
.argument('<channel-id>', 'Channel ID')
|
|
100
|
+
.argument('<message-id>', 'Message ID')
|
|
101
|
+
.argument('<emoji>', 'Emoji name')
|
|
102
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
103
|
+
.action(removeAction)
|
|
104
|
+
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { snapshotCommand } from './snapshot'
|
|
3
|
+
|
|
4
|
+
test('snapshot: command is defined', () => {
|
|
5
|
+
expect(snapshotCommand).toBeDefined()
|
|
6
|
+
expect(snapshotCommand.name()).toBe('snapshot')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test('snapshot: command has correct description', () => {
|
|
10
|
+
expect(snapshotCommand.description()).toContain('team state')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('snapshot: command has --channels-only option', () => {
|
|
14
|
+
const options = snapshotCommand.options
|
|
15
|
+
const channelsOnlyOption = options.find((opt) => opt.long === '--channels-only')
|
|
16
|
+
expect(channelsOnlyOption).toBeDefined()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('snapshot: command has --users-only option', () => {
|
|
20
|
+
const options = snapshotCommand.options
|
|
21
|
+
const usersOnlyOption = options.find((opt) => opt.long === '--users-only')
|
|
22
|
+
expect(usersOnlyOption).toBeDefined()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('snapshot: command has --limit option', () => {
|
|
26
|
+
const options = snapshotCommand.options
|
|
27
|
+
const limitOption = options.find((opt) => opt.long === '--limit')
|
|
28
|
+
expect(limitOption).toBeDefined()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('snapshot: command has --team-id option', () => {
|
|
32
|
+
const options = snapshotCommand.options
|
|
33
|
+
const teamIdOption = options.find((opt) => opt.long === '--team-id')
|
|
34
|
+
expect(teamIdOption).toBeDefined()
|
|
35
|
+
})
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { parallelMap } from '../../../shared/utils/concurrency'
|
|
3
|
+
import { handleError } from '../../../shared/utils/error-handler'
|
|
4
|
+
import { formatOutput } from '../../../shared/utils/output'
|
|
5
|
+
import { TeamsClient } from '../client'
|
|
6
|
+
import { TeamsCredentialManager } from '../credential-manager'
|
|
7
|
+
import type { TeamsChannel } from '../types'
|
|
8
|
+
|
|
9
|
+
export async function snapshotAction(options: {
|
|
10
|
+
channelsOnly?: boolean
|
|
11
|
+
usersOnly?: boolean
|
|
12
|
+
limit?: number
|
|
13
|
+
teamId?: string
|
|
14
|
+
pretty?: boolean
|
|
15
|
+
}): Promise<void> {
|
|
16
|
+
try {
|
|
17
|
+
const credManager = new TeamsCredentialManager()
|
|
18
|
+
const config = await credManager.loadConfig()
|
|
19
|
+
|
|
20
|
+
if (!config?.token) {
|
|
21
|
+
console.log(
|
|
22
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
23
|
+
)
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const teamId = options.teamId || config.current_team
|
|
28
|
+
if (!teamId) {
|
|
29
|
+
console.log(
|
|
30
|
+
formatOutput(
|
|
31
|
+
{ error: 'No current team set. Run "team switch" first or use --team-id.' },
|
|
32
|
+
options.pretty
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
39
|
+
const messageLimit = options.limit || 20
|
|
40
|
+
|
|
41
|
+
const snapshot: Record<string, unknown> = {}
|
|
42
|
+
|
|
43
|
+
const team = await client.getTeam(teamId)
|
|
44
|
+
snapshot.team = {
|
|
45
|
+
id: team.id,
|
|
46
|
+
name: team.name,
|
|
47
|
+
description: team.description,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!options.usersOnly) {
|
|
51
|
+
const channels = await client.listChannels(teamId)
|
|
52
|
+
|
|
53
|
+
snapshot.channels = channels.map((ch) => ({
|
|
54
|
+
id: ch.id,
|
|
55
|
+
name: ch.name,
|
|
56
|
+
type: ch.type,
|
|
57
|
+
}))
|
|
58
|
+
|
|
59
|
+
if (!options.channelsOnly) {
|
|
60
|
+
const channelMessages = await parallelMap(
|
|
61
|
+
channels,
|
|
62
|
+
async (channel: TeamsChannel) => {
|
|
63
|
+
const messages = await client.getMessages(teamId, channel.id, messageLimit)
|
|
64
|
+
return messages.map((msg) => ({
|
|
65
|
+
...msg,
|
|
66
|
+
channel_name: channel.name,
|
|
67
|
+
}))
|
|
68
|
+
},
|
|
69
|
+
5
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
snapshot.recent_messages = channelMessages.flat().map((msg) => ({
|
|
73
|
+
channel_id: msg.channel_id,
|
|
74
|
+
channel_name: msg.channel_name,
|
|
75
|
+
id: msg.id,
|
|
76
|
+
author: msg.author.displayName,
|
|
77
|
+
content: msg.content,
|
|
78
|
+
timestamp: msg.timestamp,
|
|
79
|
+
}))
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!options.channelsOnly) {
|
|
84
|
+
const users = await client.listUsers(teamId)
|
|
85
|
+
|
|
86
|
+
snapshot.members = users.map((u) => ({
|
|
87
|
+
id: u.id,
|
|
88
|
+
displayName: u.displayName,
|
|
89
|
+
email: u.email || null,
|
|
90
|
+
}))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log(formatOutput(snapshot, options.pretty))
|
|
94
|
+
} catch (error) {
|
|
95
|
+
handleError(error as Error)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const snapshotCommand = new Command()
|
|
100
|
+
.name('snapshot')
|
|
101
|
+
.description('Get comprehensive team state for AI agents')
|
|
102
|
+
.option('--channels-only', 'Include only channels (exclude messages and members)')
|
|
103
|
+
.option('--users-only', 'Include only members (exclude channels and messages)')
|
|
104
|
+
.option('--limit <n>', 'Number of recent messages per channel (default: 20)', '20')
|
|
105
|
+
.option('--team-id <id>', 'Team ID (defaults to current team)')
|
|
106
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
107
|
+
.action(async (options) => {
|
|
108
|
+
await snapshotAction({
|
|
109
|
+
channelsOnly: options.channelsOnly,
|
|
110
|
+
usersOnly: options.usersOnly,
|
|
111
|
+
limit: parseInt(options.limit, 10),
|
|
112
|
+
teamId: options.teamId,
|
|
113
|
+
pretty: options.pretty,
|
|
114
|
+
})
|
|
115
|
+
})
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { afterEach, beforeEach, expect, spyOn, test } from 'bun:test'
|
|
2
|
+
import { TeamsClient } from '../client'
|
|
3
|
+
import { TeamsCredentialManager } from '../credential-manager'
|
|
4
|
+
|
|
5
|
+
let clientListTeamsSpy: ReturnType<typeof spyOn>
|
|
6
|
+
let clientGetTeamSpy: ReturnType<typeof spyOn>
|
|
7
|
+
let credManagerLoadConfigSpy: ReturnType<typeof spyOn>
|
|
8
|
+
let credManagerSetCurrentTeamSpy: ReturnType<typeof spyOn>
|
|
9
|
+
let credManagerGetCurrentTeamSpy: ReturnType<typeof spyOn>
|
|
10
|
+
let credManagerSaveConfigSpy: ReturnType<typeof spyOn>
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
clientListTeamsSpy = spyOn(TeamsClient.prototype, 'listTeams').mockResolvedValue([
|
|
14
|
+
{ id: 'team-1', name: 'Team One', description: 'First team' },
|
|
15
|
+
{ id: 'team-2', name: 'Team Two', description: 'Second team' },
|
|
16
|
+
])
|
|
17
|
+
|
|
18
|
+
clientGetTeamSpy = spyOn(TeamsClient.prototype, 'getTeam').mockImplementation(
|
|
19
|
+
async (teamId: string) => {
|
|
20
|
+
if (teamId === 'team-1') {
|
|
21
|
+
return { id: 'team-1', name: 'Team One', description: 'First team' }
|
|
22
|
+
}
|
|
23
|
+
if (teamId === 'team-2') {
|
|
24
|
+
return { id: 'team-2', name: 'Team Two', description: 'Second team' }
|
|
25
|
+
}
|
|
26
|
+
throw new Error('Team not found')
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
credManagerLoadConfigSpy = spyOn(
|
|
31
|
+
TeamsCredentialManager.prototype,
|
|
32
|
+
'loadConfig'
|
|
33
|
+
).mockResolvedValue({
|
|
34
|
+
token: 'test-token',
|
|
35
|
+
current_team: 'team-1',
|
|
36
|
+
teams: {
|
|
37
|
+
'team-1': { team_id: 'team-1', team_name: 'Team One' },
|
|
38
|
+
'team-2': { team_id: 'team-2', team_name: 'Team Two' },
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
credManagerSetCurrentTeamSpy = spyOn(
|
|
43
|
+
TeamsCredentialManager.prototype,
|
|
44
|
+
'setCurrentTeam'
|
|
45
|
+
).mockResolvedValue(undefined)
|
|
46
|
+
|
|
47
|
+
credManagerGetCurrentTeamSpy = spyOn(
|
|
48
|
+
TeamsCredentialManager.prototype,
|
|
49
|
+
'getCurrentTeam'
|
|
50
|
+
).mockResolvedValue({ team_id: 'team-1', team_name: 'Team One' })
|
|
51
|
+
|
|
52
|
+
credManagerSaveConfigSpy = spyOn(
|
|
53
|
+
TeamsCredentialManager.prototype,
|
|
54
|
+
'saveConfig'
|
|
55
|
+
).mockResolvedValue(undefined)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
clientListTeamsSpy?.mockRestore()
|
|
60
|
+
clientGetTeamSpy?.mockRestore()
|
|
61
|
+
credManagerLoadConfigSpy?.mockRestore()
|
|
62
|
+
credManagerSetCurrentTeamSpy?.mockRestore()
|
|
63
|
+
credManagerGetCurrentTeamSpy?.mockRestore()
|
|
64
|
+
credManagerSaveConfigSpy?.mockRestore()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('list: returns teams with current marker', async () => {
|
|
68
|
+
// given: credential manager with teams
|
|
69
|
+
const credManager = new TeamsCredentialManager()
|
|
70
|
+
const config = await credManager.loadConfig()
|
|
71
|
+
|
|
72
|
+
// when: checking teams
|
|
73
|
+
expect(config?.teams).toBeDefined()
|
|
74
|
+
expect(Object.keys(config!.teams)).toHaveLength(2)
|
|
75
|
+
|
|
76
|
+
// then: teams are returned
|
|
77
|
+
expect(config!.teams['team-1']).toBeDefined()
|
|
78
|
+
expect(config!.teams['team-2']).toBeDefined()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('list: marks current team', async () => {
|
|
82
|
+
// given: credential manager with current team set
|
|
83
|
+
const credManager = new TeamsCredentialManager()
|
|
84
|
+
const config = await credManager.loadConfig()
|
|
85
|
+
const current = await credManager.getCurrentTeam()
|
|
86
|
+
|
|
87
|
+
// when: checking current team
|
|
88
|
+
expect(current?.team_id).toBe('team-1')
|
|
89
|
+
|
|
90
|
+
// then: current team is marked
|
|
91
|
+
expect(config!.current_team).toBe('team-1')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('info: returns team details', async () => {
|
|
95
|
+
// given: teams client with team data
|
|
96
|
+
const client = new TeamsClient('test-token')
|
|
97
|
+
const team = await client.getTeam('team-1')
|
|
98
|
+
|
|
99
|
+
// when: getting team info
|
|
100
|
+
expect(team).toBeDefined()
|
|
101
|
+
|
|
102
|
+
// then: team details are returned
|
|
103
|
+
expect(team.id).toBe('team-1')
|
|
104
|
+
expect(team.name).toBe('Team One')
|
|
105
|
+
expect(team.description).toBe('First team')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
test('info: throws error for non-existent team', async () => {
|
|
109
|
+
// given: teams client
|
|
110
|
+
const client = new TeamsClient('test-token')
|
|
111
|
+
|
|
112
|
+
// when: getting non-existent team
|
|
113
|
+
// then: error is thrown
|
|
114
|
+
try {
|
|
115
|
+
await client.getTeam('non-existent')
|
|
116
|
+
expect(true).toBe(false)
|
|
117
|
+
} catch (error) {
|
|
118
|
+
expect((error as Error).message).toContain('Team not found')
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('switch: updates current team', async () => {
|
|
123
|
+
// given: credential manager
|
|
124
|
+
const credManager = new TeamsCredentialManager()
|
|
125
|
+
|
|
126
|
+
// when: switching team
|
|
127
|
+
await credManager.setCurrentTeam('team-2', 'Team Two')
|
|
128
|
+
|
|
129
|
+
// then: setCurrentTeam is called
|
|
130
|
+
expect(credManager.setCurrentTeam).toHaveBeenCalledWith('team-2', 'Team Two')
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test('current: returns current team info', async () => {
|
|
134
|
+
// given: credential manager with current team
|
|
135
|
+
const credManager = new TeamsCredentialManager()
|
|
136
|
+
const config = await credManager.loadConfig()
|
|
137
|
+
|
|
138
|
+
// when: getting current team
|
|
139
|
+
const current = await credManager.getCurrentTeam()
|
|
140
|
+
|
|
141
|
+
// then: current team is returned
|
|
142
|
+
expect(current?.team_id).toBe('team-1')
|
|
143
|
+
expect(config!.current_team).toBe('team-1')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('remove: removes team from config', async () => {
|
|
147
|
+
// given: credential manager with teams
|
|
148
|
+
const credManager = new TeamsCredentialManager()
|
|
149
|
+
const config = await credManager.loadConfig()
|
|
150
|
+
|
|
151
|
+
// when: removing team
|
|
152
|
+
delete config!.teams['team-2']
|
|
153
|
+
await credManager.saveConfig(config!)
|
|
154
|
+
|
|
155
|
+
// then: saveConfig is called
|
|
156
|
+
expect(credManager.saveConfig).toHaveBeenCalled()
|
|
157
|
+
})
|