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
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
import { afterAll,
|
|
1
|
+
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
2
|
import { rmSync } from 'node:fs'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
|
-
import { CredentialManager } from '
|
|
5
|
-
import type { WorkspaceCredentials } from '
|
|
6
|
-
|
|
7
|
-
const
|
|
4
|
+
import { CredentialManager } from '@/platforms/slack/credential-manager'
|
|
5
|
+
import type { WorkspaceCredentials } from '@/platforms/slack/types'
|
|
6
|
+
|
|
7
|
+
const testDirs: string[] = []
|
|
8
|
+
|
|
9
|
+
function setup(): CredentialManager {
|
|
10
|
+
const testConfigDir = join(
|
|
11
|
+
import.meta.dir,
|
|
12
|
+
`.test-workspace-config-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
13
|
+
)
|
|
14
|
+
testDirs.push(testConfigDir)
|
|
15
|
+
return new CredentialManager(testConfigDir)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
afterAll(() => {
|
|
19
|
+
for (const dir of testDirs) {
|
|
20
|
+
rmSync(dir, { recursive: true, force: true })
|
|
21
|
+
}
|
|
22
|
+
})
|
|
8
23
|
|
|
9
24
|
describe('Workspace Commands', () => {
|
|
10
|
-
let credManager: CredentialManager
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
rmSync(testConfigDir, { recursive: true, force: true })
|
|
14
|
-
credManager = new CredentialManager(testConfigDir)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
afterAll(() => {
|
|
18
|
-
rmSync(testConfigDir, { recursive: true, force: true })
|
|
19
|
-
})
|
|
20
|
-
|
|
21
25
|
describe('workspace list', () => {
|
|
22
26
|
test('returns empty list when no workspaces exist', async () => {
|
|
23
|
-
|
|
24
|
-
// When: Loading config
|
|
27
|
+
const credManager = setup()
|
|
25
28
|
const config = await credManager.load()
|
|
26
|
-
|
|
27
|
-
// Then: Should have empty workspaces
|
|
28
29
|
expect(Object.keys(config.workspaces)).toHaveLength(0)
|
|
29
30
|
})
|
|
30
31
|
|
|
31
32
|
test('lists all workspaces with current marker', async () => {
|
|
32
|
-
|
|
33
|
+
const credManager = setup()
|
|
33
34
|
const ws1: WorkspaceCredentials = {
|
|
34
35
|
workspace_id: 'T123',
|
|
35
36
|
workspace_name: 'acme-corp',
|
|
@@ -47,11 +48,9 @@ describe('Workspace Commands', () => {
|
|
|
47
48
|
await credManager.setWorkspace(ws2)
|
|
48
49
|
await credManager.setCurrentWorkspace('T123')
|
|
49
50
|
|
|
50
|
-
// When: Loading config
|
|
51
51
|
const config = await credManager.load()
|
|
52
52
|
const workspaces = Object.values(config.workspaces)
|
|
53
53
|
|
|
54
|
-
// Then: Should list all workspaces
|
|
55
54
|
expect(workspaces).toHaveLength(2)
|
|
56
55
|
expect(workspaces.map((w) => w.workspace_id)).toContain('T123')
|
|
57
56
|
expect(workspaces.map((w) => w.workspace_id)).toContain('T456')
|
|
@@ -59,7 +58,7 @@ describe('Workspace Commands', () => {
|
|
|
59
58
|
})
|
|
60
59
|
|
|
61
60
|
test('shows current marker for active workspace', async () => {
|
|
62
|
-
|
|
61
|
+
const credManager = setup()
|
|
63
62
|
const ws: WorkspaceCredentials = {
|
|
64
63
|
workspace_id: 'T789',
|
|
65
64
|
workspace_name: 'current-ws',
|
|
@@ -69,16 +68,14 @@ describe('Workspace Commands', () => {
|
|
|
69
68
|
await credManager.setWorkspace(ws)
|
|
70
69
|
await credManager.setCurrentWorkspace('T789')
|
|
71
70
|
|
|
72
|
-
// When: Loading config
|
|
73
71
|
const config = await credManager.load()
|
|
74
72
|
|
|
75
|
-
// Then: Current workspace should match
|
|
76
73
|
expect(config.current_workspace).toBe('T789')
|
|
77
74
|
expect(config.workspaces.T789).toBeDefined()
|
|
78
75
|
})
|
|
79
76
|
|
|
80
77
|
test('handles list with no current workspace', async () => {
|
|
81
|
-
|
|
78
|
+
const credManager = setup()
|
|
82
79
|
const ws: WorkspaceCredentials = {
|
|
83
80
|
workspace_id: 'T999',
|
|
84
81
|
workspace_name: 'no-current',
|
|
@@ -87,10 +84,8 @@ describe('Workspace Commands', () => {
|
|
|
87
84
|
}
|
|
88
85
|
await credManager.setWorkspace(ws)
|
|
89
86
|
|
|
90
|
-
// When: Loading config
|
|
91
87
|
const config = await credManager.load()
|
|
92
88
|
|
|
93
|
-
// Then: current_workspace should be null
|
|
94
89
|
expect(config.current_workspace).toBeNull()
|
|
95
90
|
expect(config.workspaces.T999).toBeDefined()
|
|
96
91
|
})
|
|
@@ -98,7 +93,7 @@ describe('Workspace Commands', () => {
|
|
|
98
93
|
|
|
99
94
|
describe('workspace switch', () => {
|
|
100
95
|
test('switches to existing workspace', async () => {
|
|
101
|
-
|
|
96
|
+
const credManager = setup()
|
|
102
97
|
const ws1: WorkspaceCredentials = {
|
|
103
98
|
workspace_id: 'T111',
|
|
104
99
|
workspace_name: 'first',
|
|
@@ -115,25 +110,20 @@ describe('Workspace Commands', () => {
|
|
|
115
110
|
await credManager.setWorkspace(ws2)
|
|
116
111
|
await credManager.setCurrentWorkspace('T111')
|
|
117
112
|
|
|
118
|
-
// When: Switching to second workspace
|
|
119
113
|
await credManager.setCurrentWorkspace('T222')
|
|
120
114
|
|
|
121
|
-
// Then: Current should be updated
|
|
122
115
|
const config = await credManager.load()
|
|
123
116
|
expect(config.current_workspace).toBe('T222')
|
|
124
117
|
})
|
|
125
118
|
|
|
126
119
|
test('fails when workspace does not exist', async () => {
|
|
127
|
-
|
|
128
|
-
// When: Trying to get non-existent workspace
|
|
120
|
+
const credManager = setup()
|
|
129
121
|
const ws = await credManager.getWorkspace('nonexistent')
|
|
130
|
-
|
|
131
|
-
// Then: Should return null
|
|
132
122
|
expect(ws).toBeNull()
|
|
133
123
|
})
|
|
134
124
|
|
|
135
125
|
test('validates workspace exists before switching', async () => {
|
|
136
|
-
|
|
126
|
+
const credManager = setup()
|
|
137
127
|
const ws: WorkspaceCredentials = {
|
|
138
128
|
workspace_id: 'T333',
|
|
139
129
|
workspace_name: 'only-one',
|
|
@@ -143,16 +133,14 @@ describe('Workspace Commands', () => {
|
|
|
143
133
|
await credManager.setWorkspace(ws)
|
|
144
134
|
await credManager.setCurrentWorkspace('T333')
|
|
145
135
|
|
|
146
|
-
// When: Trying to switch to non-existent workspace
|
|
147
136
|
const config = await credManager.load()
|
|
148
137
|
const targetExists = 'T999' in config.workspaces
|
|
149
138
|
|
|
150
|
-
// Then: Should not exist
|
|
151
139
|
expect(targetExists).toBe(false)
|
|
152
140
|
})
|
|
153
141
|
|
|
154
142
|
test('preserves workspace credentials when switching', async () => {
|
|
155
|
-
|
|
143
|
+
const credManager = setup()
|
|
156
144
|
const ws1: WorkspaceCredentials = {
|
|
157
145
|
workspace_id: 'T444',
|
|
158
146
|
workspace_name: 'first',
|
|
@@ -168,7 +156,6 @@ describe('Workspace Commands', () => {
|
|
|
168
156
|
await credManager.setWorkspace(ws1)
|
|
169
157
|
await credManager.setWorkspace(ws2)
|
|
170
158
|
|
|
171
|
-
// When: Switching between workspaces
|
|
172
159
|
await credManager.setCurrentWorkspace('T444')
|
|
173
160
|
let config = await credManager.load()
|
|
174
161
|
expect(config.current_workspace).toBe('T444')
|
|
@@ -176,7 +163,6 @@ describe('Workspace Commands', () => {
|
|
|
176
163
|
await credManager.setCurrentWorkspace('T555')
|
|
177
164
|
config = await credManager.load()
|
|
178
165
|
|
|
179
|
-
// Then: Both workspaces should still have their credentials
|
|
180
166
|
expect(config.workspaces.T444.token).toBe('token-444')
|
|
181
167
|
expect(config.workspaces.T555.token).toBe('token-555')
|
|
182
168
|
expect(config.current_workspace).toBe('T555')
|
|
@@ -185,7 +171,7 @@ describe('Workspace Commands', () => {
|
|
|
185
171
|
|
|
186
172
|
describe('workspace current', () => {
|
|
187
173
|
test('returns current workspace details', async () => {
|
|
188
|
-
|
|
174
|
+
const credManager = setup()
|
|
189
175
|
const ws: WorkspaceCredentials = {
|
|
190
176
|
workspace_id: 'T666',
|
|
191
177
|
workspace_name: 'current-workspace',
|
|
@@ -195,10 +181,8 @@ describe('Workspace Commands', () => {
|
|
|
195
181
|
await credManager.setWorkspace(ws)
|
|
196
182
|
await credManager.setCurrentWorkspace('T666')
|
|
197
183
|
|
|
198
|
-
// When: Getting current workspace
|
|
199
184
|
const current = await credManager.getWorkspace()
|
|
200
185
|
|
|
201
|
-
// Then: Should return workspace details
|
|
202
186
|
expect(current).not.toBeNull()
|
|
203
187
|
expect(current?.workspace_id).toBe('T666')
|
|
204
188
|
expect(current?.workspace_name).toBe('current-workspace')
|
|
@@ -207,16 +191,13 @@ describe('Workspace Commands', () => {
|
|
|
207
191
|
})
|
|
208
192
|
|
|
209
193
|
test('returns null when no current workspace set', async () => {
|
|
210
|
-
|
|
211
|
-
// When: Getting current workspace
|
|
194
|
+
const credManager = setup()
|
|
212
195
|
const current = await credManager.getWorkspace()
|
|
213
|
-
|
|
214
|
-
// Then: Should return null
|
|
215
196
|
expect(current).toBeNull()
|
|
216
197
|
})
|
|
217
198
|
|
|
218
199
|
test('returns null when current workspace is deleted', async () => {
|
|
219
|
-
|
|
200
|
+
const credManager = setup()
|
|
220
201
|
const ws: WorkspaceCredentials = {
|
|
221
202
|
workspace_id: 'T777',
|
|
222
203
|
workspace_name: 'to-delete',
|
|
@@ -226,16 +207,14 @@ describe('Workspace Commands', () => {
|
|
|
226
207
|
await credManager.setWorkspace(ws)
|
|
227
208
|
await credManager.setCurrentWorkspace('T777')
|
|
228
209
|
|
|
229
|
-
// When: Workspace is removed
|
|
230
210
|
await credManager.removeWorkspace('T777')
|
|
231
211
|
|
|
232
|
-
// Then: Current should be null
|
|
233
212
|
const current = await credManager.getWorkspace()
|
|
234
213
|
expect(current).toBeNull()
|
|
235
214
|
})
|
|
236
215
|
|
|
237
216
|
test('shows correct workspace after switching', async () => {
|
|
238
|
-
|
|
217
|
+
const credManager = setup()
|
|
239
218
|
const ws1: WorkspaceCredentials = {
|
|
240
219
|
workspace_id: 'T888',
|
|
241
220
|
workspace_name: 'first',
|
|
@@ -252,11 +231,9 @@ describe('Workspace Commands', () => {
|
|
|
252
231
|
await credManager.setWorkspace(ws2)
|
|
253
232
|
await credManager.setCurrentWorkspace('T888')
|
|
254
233
|
|
|
255
|
-
// When: Switching to second workspace
|
|
256
234
|
await credManager.setCurrentWorkspace('T999')
|
|
257
235
|
const current = await credManager.getWorkspace()
|
|
258
236
|
|
|
259
|
-
// Then: Should return second workspace
|
|
260
237
|
expect(current?.workspace_id).toBe('T999')
|
|
261
238
|
expect(current?.workspace_name).toBe('second')
|
|
262
239
|
})
|
|
@@ -264,7 +241,7 @@ describe('Workspace Commands', () => {
|
|
|
264
241
|
|
|
265
242
|
describe('workspace remove', () => {
|
|
266
243
|
test('removes workspace by id', async () => {
|
|
267
|
-
|
|
244
|
+
const credManager = setup()
|
|
268
245
|
const ws: WorkspaceCredentials = {
|
|
269
246
|
workspace_id: 'T-remove',
|
|
270
247
|
workspace_name: 'to-remove',
|
|
@@ -273,16 +250,14 @@ describe('Workspace Commands', () => {
|
|
|
273
250
|
}
|
|
274
251
|
await credManager.setWorkspace(ws)
|
|
275
252
|
|
|
276
|
-
// When: Workspace is removed
|
|
277
253
|
await credManager.removeWorkspace('T-remove')
|
|
278
254
|
|
|
279
|
-
// Then: Workspace should not exist
|
|
280
255
|
const retrieved = await credManager.getWorkspace('T-remove')
|
|
281
256
|
expect(retrieved).toBeNull()
|
|
282
257
|
})
|
|
283
258
|
|
|
284
259
|
test('removes current workspace and clears current', async () => {
|
|
285
|
-
|
|
260
|
+
const credManager = setup()
|
|
286
261
|
const ws: WorkspaceCredentials = {
|
|
287
262
|
workspace_id: 'T-current-remove',
|
|
288
263
|
workspace_name: 'current-to-remove',
|
|
@@ -292,16 +267,14 @@ describe('Workspace Commands', () => {
|
|
|
292
267
|
await credManager.setWorkspace(ws)
|
|
293
268
|
await credManager.setCurrentWorkspace('T-current-remove')
|
|
294
269
|
|
|
295
|
-
// When: Current workspace is removed
|
|
296
270
|
await credManager.removeWorkspace('T-current-remove')
|
|
297
271
|
|
|
298
|
-
// Then: Current should be null
|
|
299
272
|
const config = await credManager.load()
|
|
300
273
|
expect(config.current_workspace).toBeNull()
|
|
301
274
|
})
|
|
302
275
|
|
|
303
276
|
test('removes workspace without affecting others', async () => {
|
|
304
|
-
|
|
277
|
+
const credManager = setup()
|
|
305
278
|
const ws1: WorkspaceCredentials = {
|
|
306
279
|
workspace_id: 'T-keep',
|
|
307
280
|
workspace_name: 'keep',
|
|
@@ -318,10 +291,8 @@ describe('Workspace Commands', () => {
|
|
|
318
291
|
await credManager.setWorkspace(ws2)
|
|
319
292
|
await credManager.setCurrentWorkspace('T-keep')
|
|
320
293
|
|
|
321
|
-
// When: One workspace is removed
|
|
322
294
|
await credManager.removeWorkspace('T-remove-one')
|
|
323
295
|
|
|
324
|
-
// Then: Other workspace should remain
|
|
325
296
|
const config = await credManager.load()
|
|
326
297
|
expect(config.workspaces['T-keep']).toBeDefined()
|
|
327
298
|
expect(config.workspaces['T-remove-one']).toBeUndefined()
|
|
@@ -329,17 +300,15 @@ describe('Workspace Commands', () => {
|
|
|
329
300
|
})
|
|
330
301
|
|
|
331
302
|
test('handles removing non-existent workspace gracefully', async () => {
|
|
332
|
-
|
|
333
|
-
// When: Trying to remove non-existent workspace
|
|
303
|
+
const credManager = setup()
|
|
334
304
|
await credManager.removeWorkspace('nonexistent')
|
|
335
305
|
|
|
336
|
-
// Then: Should not throw error
|
|
337
306
|
const config = await credManager.load()
|
|
338
307
|
expect(config.workspaces).toEqual({})
|
|
339
308
|
})
|
|
340
309
|
|
|
341
310
|
test('clears current only if removed workspace was current', async () => {
|
|
342
|
-
|
|
311
|
+
const credManager = setup()
|
|
343
312
|
const ws1: WorkspaceCredentials = {
|
|
344
313
|
workspace_id: 'T-current-1',
|
|
345
314
|
workspace_name: 'current-1',
|
|
@@ -356,10 +325,8 @@ describe('Workspace Commands', () => {
|
|
|
356
325
|
await credManager.setWorkspace(ws2)
|
|
357
326
|
await credManager.setCurrentWorkspace('T-current-1')
|
|
358
327
|
|
|
359
|
-
// When: Non-current workspace is removed
|
|
360
328
|
await credManager.removeWorkspace('T-other')
|
|
361
329
|
|
|
362
|
-
// Then: Current should remain unchanged
|
|
363
330
|
const config = await credManager.load()
|
|
364
331
|
expect(config.current_workspace).toBe('T-current-1')
|
|
365
332
|
})
|
|
@@ -367,7 +334,7 @@ describe('Workspace Commands', () => {
|
|
|
367
334
|
|
|
368
335
|
describe('Output Formatting', () => {
|
|
369
336
|
test('formats list output correctly', async () => {
|
|
370
|
-
|
|
337
|
+
const credManager = setup()
|
|
371
338
|
const ws1: WorkspaceCredentials = {
|
|
372
339
|
workspace_id: 'T-format-1',
|
|
373
340
|
workspace_name: 'format-1',
|
|
@@ -384,7 +351,6 @@ describe('Workspace Commands', () => {
|
|
|
384
351
|
await credManager.setWorkspace(ws2)
|
|
385
352
|
await credManager.setCurrentWorkspace('T-format-1')
|
|
386
353
|
|
|
387
|
-
// When: Creating list output
|
|
388
354
|
const config = await credManager.load()
|
|
389
355
|
const output = Object.values(config.workspaces).map((ws) => ({
|
|
390
356
|
id: ws.workspace_id,
|
|
@@ -392,7 +358,6 @@ describe('Workspace Commands', () => {
|
|
|
392
358
|
current: ws.workspace_id === config.current_workspace,
|
|
393
359
|
}))
|
|
394
360
|
|
|
395
|
-
// Then: Should be valid JSON
|
|
396
361
|
const json = JSON.stringify(output)
|
|
397
362
|
const parsed = JSON.parse(json)
|
|
398
363
|
expect(parsed).toHaveLength(2)
|
|
@@ -401,7 +366,7 @@ describe('Workspace Commands', () => {
|
|
|
401
366
|
})
|
|
402
367
|
|
|
403
368
|
test('formats switch output correctly', async () => {
|
|
404
|
-
|
|
369
|
+
const credManager = setup()
|
|
405
370
|
const ws: WorkspaceCredentials = {
|
|
406
371
|
workspace_id: 'T-switch-format',
|
|
407
372
|
workspace_name: 'switch-format',
|
|
@@ -411,17 +376,15 @@ describe('Workspace Commands', () => {
|
|
|
411
376
|
await credManager.setWorkspace(ws)
|
|
412
377
|
await credManager.setCurrentWorkspace('T-switch-format')
|
|
413
378
|
|
|
414
|
-
// When: Creating switch output
|
|
415
379
|
const output = { current: 'T-switch-format' }
|
|
416
380
|
|
|
417
|
-
// Then: Should be valid JSON
|
|
418
381
|
const json = JSON.stringify(output)
|
|
419
382
|
const parsed = JSON.parse(json)
|
|
420
383
|
expect(parsed.current).toBe('T-switch-format')
|
|
421
384
|
})
|
|
422
385
|
|
|
423
386
|
test('formats current output correctly', async () => {
|
|
424
|
-
|
|
387
|
+
const credManager = setup()
|
|
425
388
|
const ws: WorkspaceCredentials = {
|
|
426
389
|
workspace_id: 'T-current-format',
|
|
427
390
|
workspace_name: 'current-format',
|
|
@@ -431,14 +394,12 @@ describe('Workspace Commands', () => {
|
|
|
431
394
|
await credManager.setWorkspace(ws)
|
|
432
395
|
await credManager.setCurrentWorkspace('T-current-format')
|
|
433
396
|
|
|
434
|
-
// When: Creating current output
|
|
435
397
|
const current = await credManager.getWorkspace()
|
|
436
398
|
const output = {
|
|
437
399
|
workspace_id: current?.workspace_id,
|
|
438
400
|
workspace_name: current?.workspace_name,
|
|
439
401
|
}
|
|
440
402
|
|
|
441
|
-
// Then: Should be valid JSON
|
|
442
403
|
const json = JSON.stringify(output)
|
|
443
404
|
const parsed = JSON.parse(json)
|
|
444
405
|
expect(parsed.workspace_id).toBe('T-current-format')
|
|
@@ -446,7 +407,7 @@ describe('Workspace Commands', () => {
|
|
|
446
407
|
})
|
|
447
408
|
|
|
448
409
|
test('formats remove output correctly', async () => {
|
|
449
|
-
|
|
410
|
+
const credManager = setup()
|
|
450
411
|
const ws: WorkspaceCredentials = {
|
|
451
412
|
workspace_id: 'T-remove-format',
|
|
452
413
|
workspace_name: 'remove-format',
|
|
@@ -455,27 +416,22 @@ describe('Workspace Commands', () => {
|
|
|
455
416
|
}
|
|
456
417
|
await credManager.setWorkspace(ws)
|
|
457
418
|
|
|
458
|
-
// When: Creating remove output
|
|
459
419
|
const output = { removed: 'T-remove-format' }
|
|
460
420
|
|
|
461
|
-
// Then: Should be valid JSON
|
|
462
421
|
const json = JSON.stringify(output)
|
|
463
422
|
const parsed = JSON.parse(json)
|
|
464
423
|
expect(parsed.removed).toBe('T-remove-format')
|
|
465
424
|
})
|
|
466
425
|
|
|
467
426
|
test('pretty prints JSON correctly', async () => {
|
|
468
|
-
// Given: Output data
|
|
469
427
|
const output = {
|
|
470
428
|
id: 'T123',
|
|
471
429
|
name: 'test',
|
|
472
430
|
current: true,
|
|
473
431
|
}
|
|
474
432
|
|
|
475
|
-
// When: Pretty printing
|
|
476
433
|
const pretty = JSON.stringify(output, null, 2)
|
|
477
434
|
|
|
478
|
-
// Then: Should contain newlines and indentation
|
|
479
435
|
expect(pretty).toContain('\n')
|
|
480
436
|
expect(pretty).toContain(' ')
|
|
481
437
|
})
|
|
@@ -483,26 +439,21 @@ describe('Workspace Commands', () => {
|
|
|
483
439
|
|
|
484
440
|
describe('Error Handling', () => {
|
|
485
441
|
test('handles missing workspace gracefully', async () => {
|
|
486
|
-
|
|
487
|
-
// When: Trying to get workspace
|
|
442
|
+
const credManager = setup()
|
|
488
443
|
const ws = await credManager.getWorkspace('missing')
|
|
489
|
-
|
|
490
|
-
// Then: Should return null
|
|
491
444
|
expect(ws).toBeNull()
|
|
492
445
|
})
|
|
493
446
|
|
|
494
447
|
test('handles corrupted config gracefully', async () => {
|
|
495
|
-
|
|
496
|
-
// When: Loading from empty directory
|
|
448
|
+
const credManager = setup()
|
|
497
449
|
const config = await credManager.load()
|
|
498
450
|
|
|
499
|
-
// Then: Should return default config
|
|
500
451
|
expect(config.current_workspace).toBeNull()
|
|
501
452
|
expect(config.workspaces).toEqual({})
|
|
502
453
|
})
|
|
503
454
|
|
|
504
455
|
test('handles concurrent operations', async () => {
|
|
505
|
-
|
|
456
|
+
const credManager = setup()
|
|
506
457
|
const ws1: WorkspaceCredentials = {
|
|
507
458
|
workspace_id: 'T-concurrent-1',
|
|
508
459
|
workspace_name: 'concurrent-1',
|
|
@@ -516,11 +467,9 @@ describe('Workspace Commands', () => {
|
|
|
516
467
|
cookie: 'cookie-2',
|
|
517
468
|
}
|
|
518
469
|
|
|
519
|
-
// When: Setting workspaces sequentially
|
|
520
470
|
await credManager.setWorkspace(ws1)
|
|
521
471
|
await credManager.setWorkspace(ws2)
|
|
522
472
|
|
|
523
|
-
// Then: Both should be saved
|
|
524
473
|
const config = await credManager.load()
|
|
525
474
|
expect(Object.keys(config.workspaces)).toHaveLength(2)
|
|
526
475
|
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { afterAll, beforeEach, describe, expect, test } from 'bun:test'
|
|
2
2
|
import { existsSync, rmSync } from 'node:fs'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
|
-
import { CredentialManager } from '
|
|
5
|
-
import type { Config, WorkspaceCredentials } from '
|
|
4
|
+
import { CredentialManager } from '@/platforms/slack/credential-manager'
|
|
5
|
+
import type { Config, WorkspaceCredentials } from '@/platforms/slack/types'
|
|
6
6
|
|
|
7
7
|
const testConfigDir = join(import.meta.dir, '.test-config')
|
|
8
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { mkdir } from 'node:fs/promises'
|
|
2
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
3
|
import { homedir } from 'node:os'
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
import type { Config, WorkspaceCredentials } from './types'
|
|
@@ -21,21 +21,36 @@ export class CredentialManager {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
const content = await file.text()
|
|
24
|
+
const content = await readFile(this.credentialsPath, 'utf-8')
|
|
26
25
|
return JSON.parse(content) as Config
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
async save(config: Config): Promise<void> {
|
|
30
29
|
await mkdir(this.configDir, { recursive: true })
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
await
|
|
34
|
-
|
|
35
|
-
await Bun.spawn(['chmod', '0600', this.credentialsPath]).exited
|
|
31
|
+
await writeFile(this.credentialsPath, JSON.stringify(config, null, 2))
|
|
32
|
+
await chmod(this.credentialsPath, 0o600)
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
async getWorkspace(id?: string): Promise<WorkspaceCredentials | null> {
|
|
36
|
+
// Check env vars first (take precedence over file-based credentials)
|
|
37
|
+
// Only use env credentials if no specific id requested, or id matches env workspace
|
|
38
|
+
const envToken = process.env.E2E_SLACK_TOKEN
|
|
39
|
+
const envCookie = process.env.E2E_SLACK_COOKIE
|
|
40
|
+
const envWorkspaceId = process.env.E2E_SLACK_WORKSPACE_ID
|
|
41
|
+
const envWorkspaceName = process.env.E2E_SLACK_WORKSPACE_NAME
|
|
42
|
+
|
|
43
|
+
if (envToken && envCookie && envWorkspaceId && envWorkspaceName) {
|
|
44
|
+
if (!id || id === envWorkspaceId) {
|
|
45
|
+
return {
|
|
46
|
+
token: envToken,
|
|
47
|
+
cookie: envCookie,
|
|
48
|
+
workspace_id: envWorkspaceId,
|
|
49
|
+
workspace_name: envWorkspaceName,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
const config = await this.load()
|
|
40
55
|
|
|
41
56
|
if (id) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import Database from 'better-sqlite3'
|
|
5
|
+
import { TokenExtractor } from './token-extractor'
|
|
6
|
+
|
|
7
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'token-extractor-test-'))
|
|
8
|
+
const slackDir = join(tempDir, 'Slack')
|
|
9
|
+
mkdirSync(slackDir)
|
|
10
|
+
|
|
11
|
+
const dbPath = join(slackDir, 'Cookies')
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const db = new Database(dbPath)
|
|
15
|
+
db.exec(`
|
|
16
|
+
CREATE TABLE cookies (
|
|
17
|
+
name TEXT,
|
|
18
|
+
value TEXT,
|
|
19
|
+
encrypted_value BLOB,
|
|
20
|
+
host_key TEXT,
|
|
21
|
+
last_access_utc INTEGER
|
|
22
|
+
)
|
|
23
|
+
`)
|
|
24
|
+
db.prepare(
|
|
25
|
+
"INSERT INTO cookies (name, value, host_key, last_access_utc) VALUES ('d', 'xoxd-test-cookie', '.slack.com', 1000)"
|
|
26
|
+
).run()
|
|
27
|
+
db.close()
|
|
28
|
+
|
|
29
|
+
const extractor = new TokenExtractor(process.platform, slackDir)
|
|
30
|
+
const result = (extractor as any).readCookieFromDB(dbPath)
|
|
31
|
+
|
|
32
|
+
if (result !== 'xoxd-test-cookie') {
|
|
33
|
+
console.error('Expected xoxd-test-cookie, got:', result)
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('ok')
|
|
38
|
+
} finally {
|
|
39
|
+
rmSync(tempDir, { recursive: true })
|
|
40
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { execSync } from 'node:child_process'
|
|
3
|
+
|
|
4
|
+
test('TokenExtractor works in Node.js', () => {
|
|
5
|
+
const result = execSync('bun tsx src/platforms/slack/token-extractor-node-test.ts', {
|
|
6
|
+
cwd: process.cwd(),
|
|
7
|
+
encoding: 'utf-8',
|
|
8
|
+
})
|
|
9
|
+
expect(result.trim()).toBe('ok')
|
|
10
|
+
})
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { Database } from 'bun:sqlite'
|
|
2
1
|
import { execSync } from 'node:child_process'
|
|
3
2
|
import { createDecipheriv, pbkdf2Sync } from 'node:crypto'
|
|
4
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
5
|
-
import {
|
|
3
|
+
import { copyFileSync, existsSync, readdirSync, readFileSync, rmSync } from 'node:fs'
|
|
4
|
+
import { createRequire } from 'node:module'
|
|
5
|
+
import { homedir, tmpdir } from 'node:os'
|
|
6
6
|
import { join } from 'node:path'
|
|
7
7
|
import { ClassicLevel } from 'classic-level'
|
|
8
8
|
|
|
9
|
+
const require = createRequire(import.meta.url)
|
|
10
|
+
|
|
9
11
|
export interface ExtractedWorkspace {
|
|
10
12
|
workspace_id: string
|
|
11
13
|
workspace_name: string
|
|
@@ -395,20 +397,40 @@ export class TokenExtractor {
|
|
|
395
397
|
}
|
|
396
398
|
|
|
397
399
|
private readCookieFromDB(dbPath: string): string {
|
|
400
|
+
// Copy the database to a temp file to avoid SQLite lock contention
|
|
401
|
+
// when Slack is running and has a write lock on the Cookies database
|
|
402
|
+
const tempDbPath = join(
|
|
403
|
+
tmpdir(),
|
|
404
|
+
`slack-cookies-${Date.now()}-${Math.random().toString(36).slice(2)}.db`
|
|
405
|
+
)
|
|
406
|
+
|
|
398
407
|
try {
|
|
399
|
-
|
|
408
|
+
copyFileSync(dbPath, tempDbPath)
|
|
409
|
+
} catch {
|
|
410
|
+
return ''
|
|
411
|
+
}
|
|
400
412
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
`SELECT value, encrypted_value
|
|
413
|
+
try {
|
|
414
|
+
const sql = `SELECT value, encrypted_value
|
|
404
415
|
FROM cookies
|
|
405
416
|
WHERE name = 'd' AND host_key LIKE '%slack.com%'
|
|
406
417
|
ORDER BY last_access_utc DESC
|
|
407
418
|
LIMIT 1`
|
|
408
|
-
)
|
|
409
|
-
.get() as { value?: string; encrypted_value?: Uint8Array } | null
|
|
410
419
|
|
|
411
|
-
|
|
420
|
+
type CookieRow = { value?: string; encrypted_value?: Uint8Array | Buffer } | null
|
|
421
|
+
|
|
422
|
+
let row: CookieRow
|
|
423
|
+
if (typeof globalThis.Bun !== 'undefined') {
|
|
424
|
+
const { Database } = require('bun:sqlite')
|
|
425
|
+
const db = new Database(tempDbPath, { readonly: true })
|
|
426
|
+
row = db.query(sql).get() as CookieRow
|
|
427
|
+
db.close()
|
|
428
|
+
} else {
|
|
429
|
+
const Database = require('better-sqlite3')
|
|
430
|
+
const db = new Database(tempDbPath, { readonly: true })
|
|
431
|
+
row = db.prepare(sql).get() as CookieRow
|
|
432
|
+
db.close()
|
|
433
|
+
}
|
|
412
434
|
|
|
413
435
|
if (!row) {
|
|
414
436
|
return ''
|
|
@@ -428,6 +450,10 @@ export class TokenExtractor {
|
|
|
428
450
|
return ''
|
|
429
451
|
} catch {
|
|
430
452
|
return ''
|
|
453
|
+
} finally {
|
|
454
|
+
try {
|
|
455
|
+
rmSync(tempDbPath, { force: true })
|
|
456
|
+
} catch {}
|
|
431
457
|
}
|
|
432
458
|
}
|
|
433
459
|
|