agent-messenger 1.4.0 → 1.6.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/platforms/discord/cli.d.ts.map +1 -1
- package/dist/src/platforms/discord/cli.js +8 -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/slack/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/file.js +10 -4
- package/dist/src/platforms/slack/commands/file.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/user.js +8 -8
- package/dist/src/platforms/slackbot/commands/reaction.js +2 -2
- package/dist/src/platforms/slackbot/commands/reaction.js.map +1 -1
- package/dist/src/platforms/teams/cli.d.ts.map +1 -1
- package/dist/src/platforms/teams/cli.js +7 -1
- package/dist/src/platforms/teams/cli.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts +3 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +208 -107
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/commands/channel.js +9 -9
- package/dist/src/platforms/teams/commands/channel.js.map +1 -1
- package/dist/src/platforms/teams/commands/file.js +21 -21
- package/dist/src/platforms/teams/commands/file.js.map +1 -1
- package/dist/src/platforms/teams/commands/message.js +12 -12
- package/dist/src/platforms/teams/commands/message.js.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.js +6 -6
- package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
- package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/snapshot.js +6 -6
- package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/teams/commands/team.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/team.js +21 -25
- package/dist/src/platforms/teams/commands/team.js.map +1 -1
- package/dist/src/platforms/teams/commands/user.js +9 -9
- package/dist/src/platforms/teams/commands/user.js.map +1 -1
- package/dist/src/platforms/teams/credential-manager.d.ts +15 -2
- package/dist/src/platforms/teams/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/teams/credential-manager.js +110 -28
- package/dist/src/platforms/teams/credential-manager.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +46 -16
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +8 -2
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +36 -24
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/teams/types.d.ts +121 -0
- package/dist/src/platforms/teams/types.d.ts.map +1 -1
- package/dist/src/platforms/teams/types.js +16 -0
- package/dist/src/platforms/teams/types.js.map +1 -1
- package/e2e/README.md +1 -1
- package/package.json +1 -1
- package/skills/agent-discord/SKILL.md +5 -0
- package/skills/agent-slack/SKILL.md +11 -17
- package/skills/agent-teams/SKILL.md +21 -24
- package/skills/agent-teams/references/common-patterns.md +63 -49
- package/src/platforms/discord/cli.ts +14 -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/slack/commands/file.ts +12 -4
- package/src/platforms/slack/commands/sections.ts +8 -9
- package/src/platforms/slack/commands/snapshot.ts +1 -2
- package/src/platforms/slack/commands/user.ts +8 -8
- package/src/platforms/slackbot/commands/reaction.ts +2 -2
- package/src/platforms/teams/cli.ts +7 -0
- package/src/platforms/teams/commands/auth.test.ts +6 -5
- package/src/platforms/teams/commands/auth.ts +283 -120
- package/src/platforms/teams/commands/channel.test.ts +10 -4
- package/src/platforms/teams/commands/channel.ts +9 -9
- package/src/platforms/teams/commands/file.test.ts +9 -3
- package/src/platforms/teams/commands/file.ts +21 -21
- package/src/platforms/teams/commands/message.test.ts +9 -3
- package/src/platforms/teams/commands/message.ts +12 -12
- package/src/platforms/teams/commands/reaction.test.ts +9 -3
- package/src/platforms/teams/commands/reaction.ts +6 -6
- package/src/platforms/teams/commands/snapshot.ts +6 -6
- package/src/platforms/teams/commands/team.test.ts +19 -12
- package/src/platforms/teams/commands/team.ts +22 -28
- package/src/platforms/teams/commands/user.ts +9 -9
- package/src/platforms/teams/credential-manager.test.ts +30 -24
- package/src/platforms/teams/credential-manager.ts +106 -31
- package/src/platforms/teams/ensure-auth.test.ts +125 -26
- package/src/platforms/teams/ensure-auth.ts +47 -15
- package/src/platforms/teams/token-extractor.test.ts +116 -85
- package/src/platforms/teams/token-extractor.ts +65 -97
- package/src/platforms/teams/types.test.ts +31 -13
- package/src/platforms/teams/types.ts +45 -0
|
@@ -4,140 +4,235 @@ import { formatOutput } from '@/shared/utils/output'
|
|
|
4
4
|
import { TeamsClient } from '../client'
|
|
5
5
|
import { TeamsCredentialManager } from '../credential-manager'
|
|
6
6
|
import { TeamsTokenExtractor } from '../token-extractor'
|
|
7
|
+
import type { TeamsAccount, TeamsAccountType, TeamsConfig } from '../types'
|
|
7
8
|
|
|
8
9
|
export async function extractAction(options: { pretty?: boolean; debug?: boolean; token?: string }): Promise<void> {
|
|
9
10
|
try {
|
|
10
|
-
let token: string
|
|
11
|
-
|
|
12
11
|
if (options.token) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
} else {
|
|
18
|
-
const extractor = new TeamsTokenExtractor()
|
|
19
|
-
|
|
20
|
-
if (process.platform === 'darwin') {
|
|
21
|
-
console.log('')
|
|
22
|
-
console.log(' Extracting your Microsoft Teams credentials...')
|
|
23
|
-
console.log('')
|
|
24
|
-
console.log(' Your Mac may ask for your password to access Keychain.')
|
|
25
|
-
console.log(' This is required because Teams encrypts your login token')
|
|
26
|
-
console.log(' using macOS Keychain for security.')
|
|
27
|
-
console.log('')
|
|
28
|
-
console.log(' What happens:')
|
|
29
|
-
console.log(" 1. We read the encrypted token from Teams' cookies")
|
|
30
|
-
console.log(' 2. macOS Keychain decrypts it (requires your password)')
|
|
31
|
-
console.log(' 3. The token is stored locally in ~/.config/agent-messenger/')
|
|
32
|
-
console.log('')
|
|
33
|
-
console.log(' Your password is never stored or transmitted anywhere.')
|
|
34
|
-
console.log('')
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (options.debug) {
|
|
38
|
-
console.error(`[debug] Extracting Teams token...`)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const extracted = await extractor.extract()
|
|
12
|
+
await extractManualToken(options.token, options)
|
|
13
|
+
return
|
|
14
|
+
}
|
|
42
15
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
16
|
+
const extractor = new TeamsTokenExtractor()
|
|
17
|
+
|
|
18
|
+
if (process.platform === 'darwin') {
|
|
19
|
+
console.log('')
|
|
20
|
+
console.log(' Extracting your Microsoft Teams credentials...')
|
|
21
|
+
console.log('')
|
|
22
|
+
console.log(' Your Mac may ask for your password to access Keychain.')
|
|
23
|
+
console.log(' This is required because Teams encrypts your login token')
|
|
24
|
+
console.log(' using macOS Keychain for security.')
|
|
25
|
+
console.log('')
|
|
26
|
+
console.log(' What happens:')
|
|
27
|
+
console.log(" 1. We read the encrypted token from Teams' cookies")
|
|
28
|
+
console.log(' 2. macOS Keychain decrypts it (requires your password)')
|
|
29
|
+
console.log(' 3. The token is stored locally in ~/.config/agent-messenger/')
|
|
30
|
+
console.log('')
|
|
31
|
+
console.log(' Your password is never stored or transmitted anywhere.')
|
|
32
|
+
console.log('')
|
|
56
33
|
}
|
|
57
34
|
|
|
58
35
|
if (options.debug) {
|
|
59
|
-
console.error(
|
|
36
|
+
console.error('[debug] Extracting Teams tokens from all accounts...')
|
|
60
37
|
}
|
|
61
38
|
|
|
62
|
-
|
|
63
|
-
const client = new TeamsClient(token)
|
|
39
|
+
const extracted = await extractor.extract()
|
|
64
40
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
41
|
+
if (extracted.length === 0) {
|
|
42
|
+
console.log(
|
|
43
|
+
formatOutput(
|
|
44
|
+
{
|
|
45
|
+
error: 'No Teams token found. Make sure Microsoft Teams desktop app is installed and logged in.',
|
|
46
|
+
hint: 'Run with --token <token> to manually provide a token, or --debug for more info.',
|
|
47
|
+
},
|
|
48
|
+
options.pretty,
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
68
53
|
|
|
69
|
-
|
|
54
|
+
if (options.debug) {
|
|
55
|
+
console.error(`[debug] Found ${extracted.length} account(s)`)
|
|
56
|
+
}
|
|
70
57
|
|
|
58
|
+
const credManager = new TeamsCredentialManager()
|
|
59
|
+
const config: TeamsConfig = { current_account: null, accounts: {} }
|
|
60
|
+
const outputAccounts: Array<{
|
|
61
|
+
account_type: TeamsAccountType
|
|
62
|
+
user: string
|
|
63
|
+
teams: string[]
|
|
64
|
+
}> = []
|
|
65
|
+
|
|
66
|
+
for (const { token, accountType } of extracted) {
|
|
71
67
|
if (options.debug) {
|
|
72
|
-
console.error(`[debug]
|
|
73
|
-
console.error(`[debug] Discovering teams...`)
|
|
68
|
+
console.error(`[debug] Validating ${accountType} account token...`)
|
|
74
69
|
}
|
|
75
70
|
|
|
76
|
-
|
|
71
|
+
try {
|
|
72
|
+
const client = new TeamsClient(token)
|
|
73
|
+
const authInfo = await client.testAuth()
|
|
74
|
+
const teams = await client.listTeams()
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
if (options.debug) {
|
|
77
|
+
console.error(`[debug] ✓ ${accountType}: ${authInfo.displayName} (${teams.length} team(s))`)
|
|
78
|
+
}
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
error: 'No teams found. Make sure you are a member of at least one Microsoft Teams team.',
|
|
87
|
-
},
|
|
88
|
-
options.pretty,
|
|
89
|
-
),
|
|
90
|
-
)
|
|
91
|
-
process.exit(1)
|
|
92
|
-
}
|
|
80
|
+
const teamMap: Record<string, { team_id: string; team_name: string }> = {}
|
|
81
|
+
for (const team of teams) {
|
|
82
|
+
teamMap[team.id] = { team_id: team.id, team_name: team.name }
|
|
83
|
+
}
|
|
93
84
|
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
const account: TeamsAccount = {
|
|
86
|
+
token,
|
|
87
|
+
token_expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
|
88
|
+
account_type: accountType,
|
|
89
|
+
user_name: authInfo.displayName,
|
|
90
|
+
current_team: teams[0]?.id ?? null,
|
|
91
|
+
teams: teamMap,
|
|
92
|
+
}
|
|
96
93
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
team_name: team.name,
|
|
94
|
+
config.accounts[accountType] = account
|
|
95
|
+
if (!config.current_account) {
|
|
96
|
+
config.current_account = accountType
|
|
101
97
|
}
|
|
102
|
-
}
|
|
103
98
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
outputAccounts.push({
|
|
100
|
+
account_type: accountType,
|
|
101
|
+
user: authInfo.displayName,
|
|
102
|
+
teams: teams.map((t) => `${t.id}/${t.name}`),
|
|
103
|
+
})
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const errorMessage = (error as Error).message
|
|
106
|
+
const is401 = errorMessage.includes('401') || errorMessage.includes('Unauthorized')
|
|
107
|
+
if (options.debug) {
|
|
108
|
+
console.error(`[debug] ✗ ${accountType}: ${errorMessage}`)
|
|
109
|
+
}
|
|
110
|
+
if (extracted.length === 1) {
|
|
111
|
+
console.log(
|
|
112
|
+
formatOutput(
|
|
113
|
+
{
|
|
114
|
+
error: `Token validation failed: ${errorMessage}`,
|
|
115
|
+
hint: is401
|
|
116
|
+
? 'Token expired. Open Microsoft Teams, send a message to refresh your session, then run "auth extract" again.'
|
|
117
|
+
: 'Make sure Microsoft Teams desktop app is running and you are logged in.',
|
|
118
|
+
},
|
|
119
|
+
options.pretty,
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
process.exit(1)
|
|
123
|
+
}
|
|
109
124
|
}
|
|
125
|
+
}
|
|
110
126
|
|
|
111
|
-
|
|
127
|
+
if (Object.keys(config.accounts).length === 0) {
|
|
128
|
+
console.log(
|
|
129
|
+
formatOutput(
|
|
130
|
+
{ error: 'All extracted tokens failed validation. Make sure Microsoft Teams is running and logged in.' },
|
|
131
|
+
options.pretty,
|
|
132
|
+
),
|
|
133
|
+
)
|
|
134
|
+
process.exit(1)
|
|
135
|
+
}
|
|
112
136
|
|
|
113
|
-
|
|
114
|
-
console.error(`[debug] ✓ Credentials saved`)
|
|
115
|
-
}
|
|
137
|
+
await credManager.saveConfig(config)
|
|
116
138
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
139
|
+
if (options.debug) {
|
|
140
|
+
console.error('[debug] ✓ Credentials saved')
|
|
141
|
+
}
|
|
121
142
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
console.log(
|
|
144
|
+
formatOutput(
|
|
145
|
+
{
|
|
146
|
+
accounts: outputAccounts,
|
|
147
|
+
current_account: config.current_account,
|
|
148
|
+
},
|
|
149
|
+
options.pretty,
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
} catch (error) {
|
|
153
|
+
handleError(error as Error)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function extractManualToken(token: string, options: { pretty?: boolean; debug?: boolean }): Promise<void> {
|
|
158
|
+
if (options.debug) {
|
|
159
|
+
console.error(`[debug] Using provided token: ${token.substring(0, 20)}...`)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
const client = new TeamsClient(token)
|
|
164
|
+
const authInfo = await client.testAuth()
|
|
165
|
+
const teams = await client.listTeams()
|
|
166
|
+
|
|
167
|
+
if (teams.length === 0) {
|
|
126
168
|
console.log(
|
|
127
169
|
formatOutput(
|
|
128
|
-
{
|
|
129
|
-
error: `Token validation failed: ${errorMessage}`,
|
|
130
|
-
hint: is401
|
|
131
|
-
? 'Token expired. Open Microsoft Teams, send a message to refresh your session, then run "auth extract" again.'
|
|
132
|
-
: 'Make sure Microsoft Teams desktop app is running and you are logged in.',
|
|
133
|
-
},
|
|
170
|
+
{ error: 'No teams found. Make sure you are a member of at least one Microsoft Teams team.' },
|
|
134
171
|
options.pretty,
|
|
135
172
|
),
|
|
136
173
|
)
|
|
137
174
|
process.exit(1)
|
|
138
175
|
}
|
|
176
|
+
|
|
177
|
+
const credManager = new TeamsCredentialManager()
|
|
178
|
+
const accountType: TeamsAccountType = 'work'
|
|
179
|
+
|
|
180
|
+
const teamMap: Record<string, { team_id: string; team_name: string }> = {}
|
|
181
|
+
for (const team of teams) {
|
|
182
|
+
teamMap[team.id] = { team_id: team.id, team_name: team.name }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const account: TeamsAccount = {
|
|
186
|
+
token,
|
|
187
|
+
token_expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
|
188
|
+
account_type: accountType,
|
|
189
|
+
user_name: authInfo.displayName,
|
|
190
|
+
current_team: teams[0].id,
|
|
191
|
+
teams: teamMap,
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const existingConfig = await credManager.loadConfig()
|
|
195
|
+
const config: TeamsConfig = existingConfig ?? { current_account: accountType, accounts: {} }
|
|
196
|
+
config.accounts[accountType] = account
|
|
197
|
+
if (!config.current_account) {
|
|
198
|
+
config.current_account = accountType
|
|
199
|
+
}
|
|
200
|
+
await credManager.saveConfig(config)
|
|
201
|
+
|
|
202
|
+
if (options.debug) {
|
|
203
|
+
console.error('[debug] ✓ Credentials saved')
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
console.log(
|
|
207
|
+
formatOutput(
|
|
208
|
+
{
|
|
209
|
+
accounts: [
|
|
210
|
+
{
|
|
211
|
+
account_type: accountType,
|
|
212
|
+
user: authInfo.displayName,
|
|
213
|
+
teams: teams.map((t) => `${t.id}/${t.name}`),
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
current_account: accountType,
|
|
217
|
+
},
|
|
218
|
+
options.pretty,
|
|
219
|
+
),
|
|
220
|
+
)
|
|
139
221
|
} catch (error) {
|
|
140
|
-
|
|
222
|
+
const errorMessage = (error as Error).message
|
|
223
|
+
const is401 = errorMessage.includes('401') || errorMessage.includes('Unauthorized')
|
|
224
|
+
console.log(
|
|
225
|
+
formatOutput(
|
|
226
|
+
{
|
|
227
|
+
error: `Token validation failed: ${errorMessage}`,
|
|
228
|
+
hint: is401
|
|
229
|
+
? 'Token expired. Open Microsoft Teams, send a message to refresh your session, then run "auth extract" again.'
|
|
230
|
+
: 'Make sure Microsoft Teams desktop app is running and you are logged in.',
|
|
231
|
+
},
|
|
232
|
+
options.pretty,
|
|
233
|
+
),
|
|
234
|
+
)
|
|
235
|
+
process.exit(1)
|
|
141
236
|
}
|
|
142
237
|
}
|
|
143
238
|
|
|
@@ -146,7 +241,7 @@ export async function logoutAction(options: { pretty?: boolean }): Promise<void>
|
|
|
146
241
|
const credManager = new TeamsCredentialManager()
|
|
147
242
|
const config = await credManager.loadConfig()
|
|
148
243
|
|
|
149
|
-
if (!config
|
|
244
|
+
if (!config || Object.keys(config.accounts).length === 0) {
|
|
150
245
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
151
246
|
process.exit(1)
|
|
152
247
|
}
|
|
@@ -164,35 +259,96 @@ export async function statusAction(options: { pretty?: boolean }): Promise<void>
|
|
|
164
259
|
const credManager = new TeamsCredentialManager()
|
|
165
260
|
const config = await credManager.loadConfig()
|
|
166
261
|
|
|
167
|
-
if (!config
|
|
262
|
+
if (!config || Object.keys(config.accounts).length === 0) {
|
|
168
263
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
169
264
|
process.exit(1)
|
|
170
265
|
}
|
|
171
266
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
267
|
+
const accountStatuses: Array<{
|
|
268
|
+
account_type: string
|
|
269
|
+
authenticated: boolean
|
|
270
|
+
user: string | null
|
|
271
|
+
teams_count: number
|
|
272
|
+
token_expires_at: string | null
|
|
273
|
+
token_expired: boolean
|
|
274
|
+
current: boolean
|
|
275
|
+
}> = []
|
|
276
|
+
|
|
277
|
+
for (const [key, account] of Object.entries(config.accounts)) {
|
|
278
|
+
const isExpired = account.token_expires_at ? new Date(account.token_expires_at).getTime() <= Date.now() : true
|
|
279
|
+
|
|
280
|
+
let displayName: string | null = account.user_name ?? null
|
|
281
|
+
let valid = false
|
|
282
|
+
|
|
283
|
+
if (!isExpired) {
|
|
284
|
+
try {
|
|
285
|
+
const client = new TeamsClient(account.token, account.token_expires_at)
|
|
286
|
+
const authInfo = await client.testAuth()
|
|
287
|
+
displayName = authInfo.displayName
|
|
288
|
+
valid = true
|
|
289
|
+
} catch {
|
|
290
|
+
valid = false
|
|
291
|
+
}
|
|
183
292
|
}
|
|
293
|
+
|
|
294
|
+
accountStatuses.push({
|
|
295
|
+
account_type: key,
|
|
296
|
+
authenticated: valid,
|
|
297
|
+
user: displayName,
|
|
298
|
+
teams_count: Object.keys(account.teams).length,
|
|
299
|
+
token_expires_at: account.token_expires_at ?? null,
|
|
300
|
+
token_expired: isExpired,
|
|
301
|
+
current: key === config.current_account,
|
|
302
|
+
})
|
|
184
303
|
}
|
|
185
304
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
305
|
+
console.log(
|
|
306
|
+
formatOutput(
|
|
307
|
+
{
|
|
308
|
+
current_account: config.current_account,
|
|
309
|
+
accounts: accountStatuses,
|
|
310
|
+
},
|
|
311
|
+
options.pretty,
|
|
312
|
+
),
|
|
313
|
+
)
|
|
314
|
+
} catch (error) {
|
|
315
|
+
handleError(error as Error)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export async function switchAccountAction(accountType: string, options: { pretty?: boolean }): Promise<void> {
|
|
320
|
+
try {
|
|
321
|
+
const credManager = new TeamsCredentialManager()
|
|
322
|
+
const config = await credManager.loadConfig()
|
|
323
|
+
|
|
324
|
+
if (!config || !config.accounts[accountType]) {
|
|
325
|
+
const available = config ? Object.keys(config.accounts).join(', ') : 'none'
|
|
326
|
+
console.log(
|
|
327
|
+
formatOutput(
|
|
328
|
+
{
|
|
329
|
+
error: `Account not found: ${accountType}`,
|
|
330
|
+
available,
|
|
331
|
+
hint: 'Run "auth extract" to discover all accounts.',
|
|
332
|
+
},
|
|
333
|
+
options.pretty,
|
|
334
|
+
),
|
|
335
|
+
)
|
|
336
|
+
process.exit(1)
|
|
193
337
|
}
|
|
194
338
|
|
|
195
|
-
|
|
339
|
+
await credManager.setCurrentAccount(accountType as TeamsAccountType)
|
|
340
|
+
const account = config.accounts[accountType]
|
|
341
|
+
|
|
342
|
+
console.log(
|
|
343
|
+
formatOutput(
|
|
344
|
+
{
|
|
345
|
+
current_account: accountType,
|
|
346
|
+
user: account.user_name,
|
|
347
|
+
teams_count: Object.keys(account.teams).length,
|
|
348
|
+
},
|
|
349
|
+
options.pretty,
|
|
350
|
+
),
|
|
351
|
+
)
|
|
196
352
|
} catch (error) {
|
|
197
353
|
handleError(error as Error)
|
|
198
354
|
}
|
|
@@ -220,3 +376,10 @@ export const authCommand = new Command('auth')
|
|
|
220
376
|
.option('--pretty', 'Pretty print JSON output')
|
|
221
377
|
.action(statusAction),
|
|
222
378
|
)
|
|
379
|
+
.addCommand(
|
|
380
|
+
new Command('switch-account')
|
|
381
|
+
.description('Switch active account (work or personal)')
|
|
382
|
+
.argument('<account-type>', 'Account type: work or personal')
|
|
383
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
384
|
+
.action(switchAccountAction),
|
|
385
|
+
)
|
|
@@ -43,10 +43,16 @@ beforeEach(() => {
|
|
|
43
43
|
])
|
|
44
44
|
|
|
45
45
|
credManagerLoadConfigSpy = spyOn(TeamsCredentialManager.prototype, 'loadConfig').mockResolvedValue({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
current_account: 'work',
|
|
47
|
+
accounts: {
|
|
48
|
+
work: {
|
|
49
|
+
token: 'test-token',
|
|
50
|
+
account_type: 'work' as const,
|
|
51
|
+
current_team: 'team-1',
|
|
52
|
+
teams: {
|
|
53
|
+
'team-1': { team_id: 'team-1', team_name: 'Team One' },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
50
56
|
},
|
|
51
57
|
})
|
|
52
58
|
})
|
|
@@ -7,14 +7,14 @@ import { TeamsCredentialManager } from '../credential-manager'
|
|
|
7
7
|
export async function listAction(teamId: string, options: { pretty?: boolean }): Promise<void> {
|
|
8
8
|
try {
|
|
9
9
|
const credManager = new TeamsCredentialManager()
|
|
10
|
-
const
|
|
10
|
+
const cred = await credManager.getTokenWithExpiry()
|
|
11
11
|
|
|
12
|
-
if (!
|
|
12
|
+
if (!cred) {
|
|
13
13
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
14
14
|
process.exit(1)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const client = new TeamsClient(
|
|
17
|
+
const client = new TeamsClient(cred.token, cred.tokenExpiresAt)
|
|
18
18
|
const channels = await client.listChannels(teamId)
|
|
19
19
|
|
|
20
20
|
const output = channels.map((ch) => ({
|
|
@@ -33,14 +33,14 @@ export async function listAction(teamId: string, options: { pretty?: boolean }):
|
|
|
33
33
|
export async function infoAction(teamId: string, channelId: string, options: { pretty?: boolean }): Promise<void> {
|
|
34
34
|
try {
|
|
35
35
|
const credManager = new TeamsCredentialManager()
|
|
36
|
-
const
|
|
36
|
+
const cred = await credManager.getTokenWithExpiry()
|
|
37
37
|
|
|
38
|
-
if (!
|
|
38
|
+
if (!cred) {
|
|
39
39
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
40
40
|
process.exit(1)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const client = new TeamsClient(
|
|
43
|
+
const client = new TeamsClient(cred.token, cred.tokenExpiresAt)
|
|
44
44
|
const channel = await client.getChannel(teamId, channelId)
|
|
45
45
|
|
|
46
46
|
const output = {
|
|
@@ -63,14 +63,14 @@ export async function historyAction(
|
|
|
63
63
|
): Promise<void> {
|
|
64
64
|
try {
|
|
65
65
|
const credManager = new TeamsCredentialManager()
|
|
66
|
-
const
|
|
66
|
+
const cred = await credManager.getTokenWithExpiry()
|
|
67
67
|
|
|
68
|
-
if (!
|
|
68
|
+
if (!cred) {
|
|
69
69
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
70
70
|
process.exit(1)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const client = new TeamsClient(
|
|
73
|
+
const client = new TeamsClient(cred.token, cred.tokenExpiresAt)
|
|
74
74
|
const messages = await client.getMessages(teamId, channelId, options.limit || 50)
|
|
75
75
|
|
|
76
76
|
const output = messages.map((msg) => ({
|
|
@@ -35,9 +35,15 @@ beforeEach(() => {
|
|
|
35
35
|
])
|
|
36
36
|
|
|
37
37
|
credManagerLoadConfigSpy = spyOn(TeamsCredentialManager.prototype, 'loadConfig').mockResolvedValue({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
current_account: 'work',
|
|
39
|
+
accounts: {
|
|
40
|
+
work: {
|
|
41
|
+
token: 'test_token',
|
|
42
|
+
account_type: 'work' as const,
|
|
43
|
+
current_team: 'team_123',
|
|
44
|
+
teams: { team_123: { team_id: 'team_123', team_name: 'Test Team' } },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
41
47
|
})
|
|
42
48
|
})
|
|
43
49
|
|
|
@@ -14,14 +14,14 @@ export async function uploadAction(
|
|
|
14
14
|
): Promise<void> {
|
|
15
15
|
try {
|
|
16
16
|
const credManager = new TeamsCredentialManager()
|
|
17
|
-
const
|
|
17
|
+
const cred = await credManager.getTokenWithExpiry()
|
|
18
18
|
|
|
19
|
-
if (!
|
|
19
|
+
if (!cred) {
|
|
20
20
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
21
21
|
process.exit(1)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const client = new TeamsClient(
|
|
24
|
+
const client = new TeamsClient(cred.token, cred.tokenExpiresAt)
|
|
25
25
|
const filePath = resolve(path)
|
|
26
26
|
const file = await client.uploadFile(teamId, channelId, filePath)
|
|
27
27
|
|
|
@@ -42,14 +42,14 @@ export async function uploadAction(
|
|
|
42
42
|
export async function listAction(teamId: string, channelId: string, options: { pretty?: boolean }): Promise<void> {
|
|
43
43
|
try {
|
|
44
44
|
const credManager = new TeamsCredentialManager()
|
|
45
|
-
const
|
|
45
|
+
const cred = await credManager.getTokenWithExpiry()
|
|
46
46
|
|
|
47
|
-
if (!
|
|
47
|
+
if (!cred) {
|
|
48
48
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
49
49
|
process.exit(1)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const client = new TeamsClient(
|
|
52
|
+
const client = new TeamsClient(cred.token, cred.tokenExpiresAt)
|
|
53
53
|
const files = await client.listFiles(teamId, channelId)
|
|
54
54
|
|
|
55
55
|
const output = files.map((file: TeamsFile) => ({
|
|
@@ -74,14 +74,14 @@ export async function infoAction(
|
|
|
74
74
|
): Promise<void> {
|
|
75
75
|
try {
|
|
76
76
|
const credManager = new TeamsCredentialManager()
|
|
77
|
-
const
|
|
77
|
+
const cred = await credManager.getTokenWithExpiry()
|
|
78
78
|
|
|
79
|
-
if (!
|
|
79
|
+
if (!cred) {
|
|
80
80
|
console.log(formatOutput({ error: 'Not authenticated. Run "auth extract" first.' }, options.pretty))
|
|
81
81
|
process.exit(1)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const client = new TeamsClient(
|
|
84
|
+
const client = new TeamsClient(cred.token, cred.tokenExpiresAt)
|
|
85
85
|
const files = await client.listFiles(teamId, channelId)
|
|
86
86
|
const fileData = files.find((f) => f.id === fileId)
|
|
87
87
|
|
|
@@ -105,30 +105,30 @@ export async function infoAction(
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
export const fileCommand = new Command('file')
|
|
108
|
-
.description('
|
|
108
|
+
.description('File commands')
|
|
109
109
|
.addCommand(
|
|
110
110
|
new Command('upload')
|
|
111
|
-
.description('
|
|
112
|
-
.argument('<team>', '
|
|
113
|
-
.argument('<channel>', '
|
|
114
|
-
.argument('<path>', '
|
|
111
|
+
.description('Upload file to channel')
|
|
112
|
+
.argument('<team-id>', 'Team ID')
|
|
113
|
+
.argument('<channel-id>', 'Channel ID')
|
|
114
|
+
.argument('<path>', 'File path')
|
|
115
115
|
.option('--pretty', 'Pretty print JSON output')
|
|
116
116
|
.action(uploadAction),
|
|
117
117
|
)
|
|
118
118
|
.addCommand(
|
|
119
119
|
new Command('list')
|
|
120
|
-
.description('
|
|
121
|
-
.argument('<team>', '
|
|
122
|
-
.argument('<channel>', '
|
|
120
|
+
.description('List files in channel')
|
|
121
|
+
.argument('<team-id>', 'Team ID')
|
|
122
|
+
.argument('<channel-id>', 'Channel ID')
|
|
123
123
|
.option('--pretty', 'Pretty print JSON output')
|
|
124
124
|
.action(listAction),
|
|
125
125
|
)
|
|
126
126
|
.addCommand(
|
|
127
127
|
new Command('info')
|
|
128
|
-
.description('
|
|
129
|
-
.argument('<team>', '
|
|
130
|
-
.argument('<channel>', '
|
|
131
|
-
.argument('<file>', '
|
|
128
|
+
.description('Show file details')
|
|
129
|
+
.argument('<team-id>', 'Team ID')
|
|
130
|
+
.argument('<channel-id>', 'Channel ID')
|
|
131
|
+
.argument('<file-id>', 'File ID')
|
|
132
132
|
.option('--pretty', 'Pretty print JSON output')
|
|
133
133
|
.action(infoAction),
|
|
134
134
|
)
|