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,164 @@
|
|
|
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 listAction(options: { pretty?: boolean }): Promise<void> {
|
|
8
|
+
try {
|
|
9
|
+
const credManager = new TeamsCredentialManager()
|
|
10
|
+
const config = await credManager.loadConfig()
|
|
11
|
+
const teams = config?.teams ? Object.values(config.teams) : []
|
|
12
|
+
|
|
13
|
+
const output = teams.map((team) => ({
|
|
14
|
+
id: team.team_id,
|
|
15
|
+
name: team.team_name,
|
|
16
|
+
current: team.team_id === config?.current_team,
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
console.log(formatOutput(output, options.pretty))
|
|
20
|
+
} catch (error) {
|
|
21
|
+
handleError(error as Error)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function infoAction(teamId: string, options: { pretty?: boolean }): Promise<void> {
|
|
26
|
+
try {
|
|
27
|
+
const credManager = new TeamsCredentialManager()
|
|
28
|
+
const config = await credManager.loadConfig()
|
|
29
|
+
|
|
30
|
+
if (!config?.token) {
|
|
31
|
+
console.log(
|
|
32
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
33
|
+
)
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
38
|
+
const team = await client.getTeam(teamId)
|
|
39
|
+
|
|
40
|
+
const output = {
|
|
41
|
+
id: team.id,
|
|
42
|
+
name: team.name,
|
|
43
|
+
description: team.description,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(formatOutput(output, options.pretty))
|
|
47
|
+
} catch (error) {
|
|
48
|
+
handleError(error as Error)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function switchAction(teamId: string, options: { pretty?: boolean }): Promise<void> {
|
|
53
|
+
try {
|
|
54
|
+
const credManager = new TeamsCredentialManager()
|
|
55
|
+
const config = await credManager.loadConfig()
|
|
56
|
+
|
|
57
|
+
if (!config?.teams?.[teamId]) {
|
|
58
|
+
console.log(formatOutput({ error: `Team not found: ${teamId}` }, options.pretty))
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const team = config.teams[teamId]
|
|
63
|
+
await credManager.setCurrentTeam(teamId, team.team_name)
|
|
64
|
+
console.log(formatOutput({ current: teamId }, options.pretty))
|
|
65
|
+
} catch (error) {
|
|
66
|
+
handleError(error as Error)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function currentAction(options: { pretty?: boolean }): Promise<void> {
|
|
71
|
+
try {
|
|
72
|
+
const credManager = new TeamsCredentialManager()
|
|
73
|
+
const config = await credManager.loadConfig()
|
|
74
|
+
|
|
75
|
+
if (!config?.current_team) {
|
|
76
|
+
console.log(
|
|
77
|
+
formatOutput({ error: 'No current team set. Run "auth extract" first.' }, options.pretty)
|
|
78
|
+
)
|
|
79
|
+
process.exit(1)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const team = config.teams[config.current_team]
|
|
83
|
+
|
|
84
|
+
if (!team) {
|
|
85
|
+
console.log(
|
|
86
|
+
formatOutput({ error: 'Current team not found in configuration.' }, options.pretty)
|
|
87
|
+
)
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const output = {
|
|
92
|
+
team_id: team.team_id,
|
|
93
|
+
team_name: team.team_name,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(formatOutput(output, options.pretty))
|
|
97
|
+
} catch (error) {
|
|
98
|
+
handleError(error as Error)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function removeAction(teamId: string, options: { pretty?: boolean }): Promise<void> {
|
|
103
|
+
try {
|
|
104
|
+
const credManager = new TeamsCredentialManager()
|
|
105
|
+
const config = await credManager.loadConfig()
|
|
106
|
+
|
|
107
|
+
if (!config) {
|
|
108
|
+
console.log(formatOutput({ error: 'No configuration found.' }, options.pretty))
|
|
109
|
+
process.exit(1)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!config.teams[teamId]) {
|
|
113
|
+
console.log(formatOutput({ error: `Team not found: ${teamId}` }, options.pretty))
|
|
114
|
+
process.exit(1)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
delete config.teams[teamId]
|
|
118
|
+
|
|
119
|
+
if (config.current_team === teamId) {
|
|
120
|
+
config.current_team = null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await credManager.saveConfig(config)
|
|
124
|
+
console.log(formatOutput({ removed: teamId }, options.pretty))
|
|
125
|
+
} catch (error) {
|
|
126
|
+
handleError(error as Error)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const teamCommand = new Command('team')
|
|
131
|
+
.description('Team management commands')
|
|
132
|
+
.addCommand(
|
|
133
|
+
new Command('list')
|
|
134
|
+
.description('List all teams')
|
|
135
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
136
|
+
.action(listAction)
|
|
137
|
+
)
|
|
138
|
+
.addCommand(
|
|
139
|
+
new Command('info')
|
|
140
|
+
.description('Get team info')
|
|
141
|
+
.argument('<team-id>', 'Team ID')
|
|
142
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
143
|
+
.action(infoAction)
|
|
144
|
+
)
|
|
145
|
+
.addCommand(
|
|
146
|
+
new Command('switch')
|
|
147
|
+
.description('Switch to team')
|
|
148
|
+
.argument('<team-id>', 'Team ID')
|
|
149
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
150
|
+
.action(switchAction)
|
|
151
|
+
)
|
|
152
|
+
.addCommand(
|
|
153
|
+
new Command('current')
|
|
154
|
+
.description('Show current team')
|
|
155
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
156
|
+
.action(currentAction)
|
|
157
|
+
)
|
|
158
|
+
.addCommand(
|
|
159
|
+
new Command('remove')
|
|
160
|
+
.description('Remove team from config')
|
|
161
|
+
.argument('<team-id>', 'Team ID')
|
|
162
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
163
|
+
.action(removeAction)
|
|
164
|
+
)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { expect, mock, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
// Mock TeamsClient
|
|
4
|
+
const mockClient = {
|
|
5
|
+
testAuth: mock(async () => ({
|
|
6
|
+
id: 'user123',
|
|
7
|
+
displayName: 'Test User',
|
|
8
|
+
email: 'test@example.com',
|
|
9
|
+
userPrincipalName: 'test@example.com',
|
|
10
|
+
})),
|
|
11
|
+
getUser: mock(async (userId: string) => ({
|
|
12
|
+
id: userId,
|
|
13
|
+
displayName: 'Test User',
|
|
14
|
+
email: 'test@example.com',
|
|
15
|
+
userPrincipalName: 'test@example.com',
|
|
16
|
+
})),
|
|
17
|
+
listUsers: mock(async (_teamId: string) => [
|
|
18
|
+
{
|
|
19
|
+
id: 'user1',
|
|
20
|
+
displayName: 'Alice',
|
|
21
|
+
email: 'alice@example.com',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'user2',
|
|
25
|
+
displayName: 'Bob',
|
|
26
|
+
email: 'bob@example.com',
|
|
27
|
+
},
|
|
28
|
+
]),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
test('me returns current user info', async () => {
|
|
32
|
+
// given: authenticated user
|
|
33
|
+
const user = await mockClient.testAuth()
|
|
34
|
+
|
|
35
|
+
// when: getting current user
|
|
36
|
+
const result = {
|
|
37
|
+
id: user.id,
|
|
38
|
+
displayName: user.displayName,
|
|
39
|
+
email: user.email,
|
|
40
|
+
userPrincipalName: user.userPrincipalName,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// then: returns user object
|
|
44
|
+
expect(result.id).toBe('user123')
|
|
45
|
+
expect(result.displayName).toBe('Test User')
|
|
46
|
+
expect(result.email).toBe('test@example.com')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('info returns user details by id', async () => {
|
|
50
|
+
// given: user id
|
|
51
|
+
const userId = 'user123'
|
|
52
|
+
|
|
53
|
+
// when: getting user info
|
|
54
|
+
const user = await mockClient.getUser(userId)
|
|
55
|
+
const result = {
|
|
56
|
+
id: user.id,
|
|
57
|
+
displayName: user.displayName,
|
|
58
|
+
email: user.email,
|
|
59
|
+
userPrincipalName: user.userPrincipalName,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// then: returns user object
|
|
63
|
+
expect(result.id).toBe('user123')
|
|
64
|
+
expect(result.displayName).toBe('Test User')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('list returns team members', async () => {
|
|
68
|
+
// given: team id
|
|
69
|
+
const teamId = 'team123'
|
|
70
|
+
|
|
71
|
+
// when: listing users
|
|
72
|
+
const users = await mockClient.listUsers(teamId)
|
|
73
|
+
const result = users.map((u) => ({
|
|
74
|
+
id: u.id,
|
|
75
|
+
displayName: u.displayName,
|
|
76
|
+
email: u.email,
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
// then: returns array of users
|
|
80
|
+
expect(result).toHaveLength(2)
|
|
81
|
+
expect(result[0].displayName).toBe('Alice')
|
|
82
|
+
expect(result[1].displayName).toBe('Bob')
|
|
83
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
async function listAction(teamId: string, options: { pretty?: boolean }): Promise<void> {
|
|
8
|
+
try {
|
|
9
|
+
const credManager = new TeamsCredentialManager()
|
|
10
|
+
const config = await credManager.loadConfig()
|
|
11
|
+
|
|
12
|
+
if (!config?.token) {
|
|
13
|
+
console.log(
|
|
14
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
15
|
+
)
|
|
16
|
+
process.exit(1)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
20
|
+
const users = await client.listUsers(teamId)
|
|
21
|
+
|
|
22
|
+
const output = users.map((user) => ({
|
|
23
|
+
id: user.id,
|
|
24
|
+
displayName: user.displayName,
|
|
25
|
+
email: user.email,
|
|
26
|
+
userPrincipalName: user.userPrincipalName,
|
|
27
|
+
}))
|
|
28
|
+
|
|
29
|
+
console.log(formatOutput(output, options.pretty))
|
|
30
|
+
} catch (error) {
|
|
31
|
+
handleError(error as Error)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function infoAction(userId: string, options: { pretty?: boolean }): Promise<void> {
|
|
36
|
+
try {
|
|
37
|
+
const credManager = new TeamsCredentialManager()
|
|
38
|
+
const config = await credManager.loadConfig()
|
|
39
|
+
|
|
40
|
+
if (!config?.token) {
|
|
41
|
+
console.log(
|
|
42
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
43
|
+
)
|
|
44
|
+
process.exit(1)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
48
|
+
const user = await client.getUser(userId)
|
|
49
|
+
|
|
50
|
+
const output = {
|
|
51
|
+
id: user.id,
|
|
52
|
+
displayName: user.displayName,
|
|
53
|
+
email: user.email,
|
|
54
|
+
userPrincipalName: user.userPrincipalName,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(formatOutput(output, options.pretty))
|
|
58
|
+
} catch (error) {
|
|
59
|
+
handleError(error as Error)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function meAction(options: { pretty?: boolean }): Promise<void> {
|
|
64
|
+
try {
|
|
65
|
+
const credManager = new TeamsCredentialManager()
|
|
66
|
+
const config = await credManager.loadConfig()
|
|
67
|
+
|
|
68
|
+
if (!config?.token) {
|
|
69
|
+
console.log(
|
|
70
|
+
formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty)
|
|
71
|
+
)
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const client = new TeamsClient(config.token, config.token_expires_at)
|
|
76
|
+
const user = await client.testAuth()
|
|
77
|
+
|
|
78
|
+
const output = {
|
|
79
|
+
id: user.id,
|
|
80
|
+
displayName: user.displayName,
|
|
81
|
+
email: user.email,
|
|
82
|
+
userPrincipalName: user.userPrincipalName,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(formatOutput(output, options.pretty))
|
|
86
|
+
} catch (error) {
|
|
87
|
+
handleError(error as Error)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const userCommand = new Command('user')
|
|
92
|
+
.description('User commands')
|
|
93
|
+
.addCommand(
|
|
94
|
+
new Command('list')
|
|
95
|
+
.description('List team members')
|
|
96
|
+
.argument('<team-id>', 'Team ID')
|
|
97
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
98
|
+
.action(listAction)
|
|
99
|
+
)
|
|
100
|
+
.addCommand(
|
|
101
|
+
new Command('info')
|
|
102
|
+
.description('Get user info')
|
|
103
|
+
.argument('<user-id>', 'User ID')
|
|
104
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
105
|
+
.action(infoAction)
|
|
106
|
+
)
|
|
107
|
+
.addCommand(
|
|
108
|
+
new Command('me')
|
|
109
|
+
.description('Show current authenticated user')
|
|
110
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
111
|
+
.action(meAction)
|
|
112
|
+
)
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
|
+
import { existsSync, rmSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { TeamsCredentialManager } from './credential-manager'
|
|
5
|
+
|
|
6
|
+
const testDirs: string[] = []
|
|
7
|
+
|
|
8
|
+
function setup(): TeamsCredentialManager {
|
|
9
|
+
const testConfigDir = join(
|
|
10
|
+
import.meta.dir,
|
|
11
|
+
`.test-teams-config-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
12
|
+
)
|
|
13
|
+
testDirs.push(testConfigDir)
|
|
14
|
+
return new TeamsCredentialManager(testConfigDir)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
afterAll(() => {
|
|
18
|
+
for (const dir of testDirs) {
|
|
19
|
+
rmSync(dir, { recursive: true, force: true })
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('TeamsCredentialManager', () => {
|
|
24
|
+
test('loadConfig returns null when file does not exist', async () => {
|
|
25
|
+
const manager = setup()
|
|
26
|
+
const config = await manager.loadConfig()
|
|
27
|
+
|
|
28
|
+
expect(config).toBeNull()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('saveConfig creates config file with correct permissions', async () => {
|
|
32
|
+
const testConfigDir = join(
|
|
33
|
+
import.meta.dir,
|
|
34
|
+
`.test-teams-config-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
35
|
+
)
|
|
36
|
+
testDirs.push(testConfigDir)
|
|
37
|
+
const manager = new TeamsCredentialManager(testConfigDir)
|
|
38
|
+
const config = {
|
|
39
|
+
token: 'test-token',
|
|
40
|
+
current_team: 'team-123',
|
|
41
|
+
teams: {
|
|
42
|
+
'team-123': { team_id: 'team-123', team_name: 'Test Team' },
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await manager.saveConfig(config)
|
|
47
|
+
|
|
48
|
+
const credentialsPath = join(testConfigDir, 'teams-credentials.json')
|
|
49
|
+
expect(existsSync(credentialsPath)).toBe(true)
|
|
50
|
+
|
|
51
|
+
const file = Bun.file(credentialsPath)
|
|
52
|
+
const content = await file.text()
|
|
53
|
+
const loaded = JSON.parse(content)
|
|
54
|
+
expect(loaded).toEqual(config)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('getToken returns null when not authenticated', async () => {
|
|
58
|
+
const manager = setup()
|
|
59
|
+
const token = await manager.getToken()
|
|
60
|
+
expect(token).toBeNull()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('setToken saves token to config', async () => {
|
|
64
|
+
const manager = setup()
|
|
65
|
+
await manager.setToken('test-token-123')
|
|
66
|
+
|
|
67
|
+
const token = await manager.getToken()
|
|
68
|
+
expect(token).toBe('test-token-123')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('setToken saves token with expiry', async () => {
|
|
72
|
+
const manager = setup()
|
|
73
|
+
const expiresAt = '2025-12-31T23:59:59Z'
|
|
74
|
+
await manager.setToken('test-token-123', expiresAt)
|
|
75
|
+
|
|
76
|
+
const config = await manager.loadConfig()
|
|
77
|
+
expect(config?.token).toBe('test-token-123')
|
|
78
|
+
expect(config?.token_expires_at).toBe(expiresAt)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('getCurrentTeam returns null when not set', async () => {
|
|
82
|
+
const manager = setup()
|
|
83
|
+
const team = await manager.getCurrentTeam()
|
|
84
|
+
expect(team).toBeNull()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('getCurrentTeam returns null when current_team is set but team not in teams record', async () => {
|
|
88
|
+
const manager = setup()
|
|
89
|
+
await manager.setToken('test-token')
|
|
90
|
+
const config = await manager.loadConfig()
|
|
91
|
+
if (config) {
|
|
92
|
+
config.current_team = 'non-existent-team'
|
|
93
|
+
await manager.saveConfig(config)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const team = await manager.getCurrentTeam()
|
|
97
|
+
expect(team).toBeNull()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('setCurrentTeam saves team info', async () => {
|
|
101
|
+
const manager = setup()
|
|
102
|
+
await manager.setToken('test-token')
|
|
103
|
+
await manager.setCurrentTeam('team-456', 'My Team')
|
|
104
|
+
|
|
105
|
+
const team = await manager.getCurrentTeam()
|
|
106
|
+
expect(team).toEqual({ team_id: 'team-456', team_name: 'My Team' })
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test('setCurrentTeam updates existing team', async () => {
|
|
110
|
+
const manager = setup()
|
|
111
|
+
await manager.setToken('test-token')
|
|
112
|
+
await manager.setCurrentTeam('team-1', 'Team One')
|
|
113
|
+
await manager.setCurrentTeam('team-2', 'Team Two')
|
|
114
|
+
|
|
115
|
+
const team = await manager.getCurrentTeam()
|
|
116
|
+
expect(team).toEqual({ team_id: 'team-2', team_name: 'Team Two' })
|
|
117
|
+
|
|
118
|
+
const config = await manager.loadConfig()
|
|
119
|
+
expect(config?.teams['team-1']).toEqual({ team_id: 'team-1', team_name: 'Team One' })
|
|
120
|
+
expect(config?.teams['team-2']).toEqual({ team_id: 'team-2', team_name: 'Team Two' })
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('clearCredentials removes all credentials', async () => {
|
|
124
|
+
const manager = setup()
|
|
125
|
+
await manager.setToken('test-token', '2025-12-31T23:59:59Z')
|
|
126
|
+
await manager.setCurrentTeam('team-123', 'Test Team')
|
|
127
|
+
|
|
128
|
+
await manager.clearCredentials()
|
|
129
|
+
|
|
130
|
+
const config = await manager.loadConfig()
|
|
131
|
+
expect(config).toBeNull()
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test('isTokenExpired returns true when no config exists', async () => {
|
|
135
|
+
const manager = setup()
|
|
136
|
+
const expired = await manager.isTokenExpired()
|
|
137
|
+
expect(expired).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('isTokenExpired returns true when no token_expires_at is set', async () => {
|
|
141
|
+
const manager = setup()
|
|
142
|
+
await manager.setToken('test-token')
|
|
143
|
+
|
|
144
|
+
const expired = await manager.isTokenExpired()
|
|
145
|
+
expect(expired).toBe(true)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
test('isTokenExpired returns true when token is expired', async () => {
|
|
149
|
+
const manager = setup()
|
|
150
|
+
const pastDate = new Date(Date.now() - 60000).toISOString()
|
|
151
|
+
await manager.setToken('test-token', pastDate)
|
|
152
|
+
|
|
153
|
+
const expired = await manager.isTokenExpired()
|
|
154
|
+
expect(expired).toBe(true)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('isTokenExpired returns false when token is not expired', async () => {
|
|
158
|
+
const manager = setup()
|
|
159
|
+
const futureDate = new Date(Date.now() + 3600000).toISOString()
|
|
160
|
+
await manager.setToken('test-token', futureDate)
|
|
161
|
+
|
|
162
|
+
const expired = await manager.isTokenExpired()
|
|
163
|
+
expect(expired).toBe(false)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('multiple operations preserve existing data', async () => {
|
|
167
|
+
const manager = setup()
|
|
168
|
+
await manager.setToken('token-1', '2025-12-31T23:59:59Z')
|
|
169
|
+
await manager.setCurrentTeam('team-1', 'Team One')
|
|
170
|
+
|
|
171
|
+
await manager.setToken('token-2')
|
|
172
|
+
|
|
173
|
+
const config = await manager.loadConfig()
|
|
174
|
+
expect(config?.token).toBe('token-2')
|
|
175
|
+
expect(config?.current_team).toBe('team-1')
|
|
176
|
+
expect(config?.teams['team-1']).toEqual({ team_id: 'team-1', team_name: 'Team One' })
|
|
177
|
+
})
|
|
178
|
+
})
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import type { TeamsConfig } from './types'
|
|
6
|
+
|
|
7
|
+
export class TeamsCredentialManager {
|
|
8
|
+
private configDir: string
|
|
9
|
+
private credentialsPath: string
|
|
10
|
+
|
|
11
|
+
constructor(configDir?: string) {
|
|
12
|
+
this.configDir = configDir ?? join(homedir(), '.config', 'agent-messenger')
|
|
13
|
+
this.credentialsPath = join(this.configDir, 'teams-credentials.json')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async loadConfig(): Promise<TeamsConfig | null> {
|
|
17
|
+
if (!existsSync(this.credentialsPath)) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const content = await readFile(this.credentialsPath, 'utf-8')
|
|
23
|
+
return JSON.parse(content) as TeamsConfig
|
|
24
|
+
} catch {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async saveConfig(config: TeamsConfig): Promise<void> {
|
|
30
|
+
await mkdir(this.configDir, { recursive: true })
|
|
31
|
+
await writeFile(this.credentialsPath, JSON.stringify(config, null, 2), { mode: 0o600 })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async getToken(): Promise<string | null> {
|
|
35
|
+
const config = await this.loadConfig()
|
|
36
|
+
return config?.token ?? null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async setToken(token: string, expiresAt?: string): Promise<void> {
|
|
40
|
+
let config = await this.loadConfig()
|
|
41
|
+
if (!config) {
|
|
42
|
+
config = {
|
|
43
|
+
token,
|
|
44
|
+
current_team: null,
|
|
45
|
+
teams: {},
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
config.token = token
|
|
49
|
+
if (expiresAt !== undefined) {
|
|
50
|
+
config.token_expires_at = expiresAt
|
|
51
|
+
}
|
|
52
|
+
await this.saveConfig(config)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getCurrentTeam(): Promise<{ team_id: string; team_name: string } | null> {
|
|
56
|
+
const config = await this.loadConfig()
|
|
57
|
+
if (!config?.current_team) {
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
return config.teams[config.current_team] ?? null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async setCurrentTeam(teamId: string, teamName: string): Promise<void> {
|
|
64
|
+
let config = await this.loadConfig()
|
|
65
|
+
if (!config) {
|
|
66
|
+
config = {
|
|
67
|
+
token: '',
|
|
68
|
+
current_team: null,
|
|
69
|
+
teams: {},
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
config.current_team = teamId
|
|
73
|
+
config.teams[teamId] = { team_id: teamId, team_name: teamName }
|
|
74
|
+
await this.saveConfig(config)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async clearCredentials(): Promise<void> {
|
|
78
|
+
if (existsSync(this.credentialsPath)) {
|
|
79
|
+
await rm(this.credentialsPath)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async isTokenExpired(): Promise<boolean> {
|
|
84
|
+
const config = await this.loadConfig()
|
|
85
|
+
if (!config?.token_expires_at) {
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const expiresAt = new Date(config.token_expires_at)
|
|
90
|
+
return expiresAt.getTime() <= Date.now()
|
|
91
|
+
}
|
|
92
|
+
}
|