agent-messenger 2.11.1 → 2.12.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/plugin.json +1 -1
- package/README.md +11 -0
- package/dist/package.json +1 -1
- package/dist/src/platforms/channeltalk/credential-manager.js +2 -2
- package/dist/src/platforms/channeltalk/credential-manager.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.js +2 -2
- package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/discord/credential-manager.js +2 -2
- package/dist/src/platforms/discord/credential-manager.js.map +1 -1
- package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/client.js +3 -2
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/discordbot/credential-manager.js +2 -2
- package/dist/src/platforms/discordbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/instagram/credential-manager.js +2 -2
- package/dist/src/platforms/instagram/credential-manager.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +3 -4
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/credential-manager.js +2 -2
- package/dist/src/platforms/kakaotalk/credential-manager.js.map +1 -1
- package/dist/src/platforms/line/client.js +2 -2
- package/dist/src/platforms/line/client.js.map +1 -1
- package/dist/src/platforms/line/credential-manager.js +2 -2
- package/dist/src/platforms/line/credential-manager.js.map +1 -1
- package/dist/src/platforms/slack/credential-manager.js +2 -2
- package/dist/src/platforms/slack/credential-manager.js.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.js +20 -14
- package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/teams/credential-manager.js +2 -2
- package/dist/src/platforms/teams/credential-manager.js.map +1 -1
- package/dist/src/platforms/telegram/credential-manager.js +2 -2
- package/dist/src/platforms/telegram/credential-manager.js.map +1 -1
- package/dist/src/platforms/webex/credential-manager.js +2 -2
- package/dist/src/platforms/webex/credential-manager.js.map +1 -1
- package/dist/src/platforms/wechatbot/credential-manager.js +2 -2
- package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.js +2 -2
- package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
- package/dist/src/platforms/whatsappbot/credential-manager.js +2 -2
- package/dist/src/platforms/whatsappbot/credential-manager.js.map +1 -1
- package/dist/src/shared/utils/config-dir.d.ts +14 -0
- package/dist/src/shared/utils/config-dir.d.ts.map +1 -0
- package/dist/src/shared/utils/config-dir.js +22 -0
- package/dist/src/shared/utils/config-dir.js.map +1 -0
- package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
- package/dist/src/shared/utils/derived-key-cache.js +2 -2
- package/dist/src/shared/utils/derived-key-cache.js.map +1 -1
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/channeltalk/credential-manager.ts +2 -2
- package/src/platforms/channeltalkbot/credential-manager.ts +2 -2
- package/src/platforms/discord/credential-manager.ts +3 -2
- package/src/platforms/discordbot/client.test.ts +19 -0
- package/src/platforms/discordbot/client.ts +3 -2
- package/src/platforms/discordbot/credential-manager.ts +2 -2
- package/src/platforms/instagram/credential-manager.ts +2 -2
- package/src/platforms/kakaotalk/client.ts +3 -5
- package/src/platforms/kakaotalk/credential-manager.ts +2 -2
- package/src/platforms/line/client.ts +2 -2
- package/src/platforms/line/credential-manager.ts +2 -2
- package/src/platforms/slack/credential-manager.ts +2 -2
- package/src/platforms/slackbot/credential-manager.ts +18 -14
- package/src/platforms/teams/credential-manager.ts +2 -2
- package/src/platforms/telegram/commands/whoami.test.ts +1 -0
- package/src/platforms/telegram/credential-manager.ts +2 -2
- package/src/platforms/webex/credential-manager.ts +2 -2
- package/src/platforms/wechatbot/credential-manager.ts +2 -2
- package/src/platforms/whatsapp/credential-manager.ts +2 -2
- package/src/platforms/whatsappbot/credential-manager.ts +2 -2
- package/src/shared/utils/config-dir.test.ts +41 -0
- package/src/shared/utils/config-dir.ts +23 -0
- package/src/shared/utils/derived-key-cache.ts +3 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { ChannelConfig, ChannelCredentials, ChannelWorkspaceEntry } from './types'
|
|
7
7
|
import { ChannelConfigSchema } from './types'
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ export class ChannelCredentialManager {
|
|
|
11
11
|
private credentialsPath: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'channel-credentials.json')
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { ChannelBotConfig, ChannelBotCredentials, ChannelBotWorkspaceEntry } from './types'
|
|
7
7
|
import { ChannelBotConfigSchema } from './types'
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ export class ChannelBotCredentialManager {
|
|
|
17
17
|
protected renameFile: typeof rename = rename
|
|
18
18
|
|
|
19
19
|
constructor(configDir?: string) {
|
|
20
|
-
this.configDir = configDir ??
|
|
20
|
+
this.configDir = configDir ?? getConfigDir()
|
|
21
21
|
this.credentialsPath = join(this.configDir, CREDENTIALS_FILENAME)
|
|
22
22
|
this.legacyPath = join(this.configDir, LEGACY_FILENAME)
|
|
23
23
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
|
+
|
|
6
7
|
export interface DiscordConfig {
|
|
7
8
|
token: string | null
|
|
8
9
|
current_server: string | null
|
|
@@ -14,7 +15,7 @@ export class DiscordCredentialManager {
|
|
|
14
15
|
private credentialsPath: string
|
|
15
16
|
|
|
16
17
|
constructor(configDir?: string) {
|
|
17
|
-
this.configDir = configDir ??
|
|
18
|
+
this.configDir = configDir ?? getConfigDir()
|
|
18
19
|
this.credentialsPath = join(this.configDir, 'discord-credentials.json')
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -290,6 +290,25 @@ describe('DiscordBotClient', () => {
|
|
|
290
290
|
const headers = fetchCalls[0].options?.headers as Record<string, string>
|
|
291
291
|
expect(headers.Authorization).toBe('Bot bot-token')
|
|
292
292
|
})
|
|
293
|
+
|
|
294
|
+
it('throws when response has no attachments', async () => {
|
|
295
|
+
const { tmpdir } = await import('node:os')
|
|
296
|
+
const { join } = await import('node:path')
|
|
297
|
+
const tempFile = join(tmpdir(), 'test-discordbot-upload-empty.txt')
|
|
298
|
+
await Bun.write(tempFile, 'test content')
|
|
299
|
+
|
|
300
|
+
mockResponse({
|
|
301
|
+
id: 'msg1',
|
|
302
|
+
channel_id: 'ch1',
|
|
303
|
+
author: { id: '123', username: 'bot' },
|
|
304
|
+
content: '',
|
|
305
|
+
timestamp: '2024-01-01T00:00:00.000Z',
|
|
306
|
+
attachments: [],
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
310
|
+
await expect(client.uploadFile('ch1', tempFile)).rejects.toThrow('Upload succeeded but no attachments returned')
|
|
311
|
+
})
|
|
293
312
|
})
|
|
294
313
|
|
|
295
314
|
describe('listFiles', () => {
|
|
@@ -307,11 +307,12 @@ export class DiscordBotClient {
|
|
|
307
307
|
}
|
|
308
308
|
const message = await this.requestFormData<MessageWithAttachments>(`/channels/${channelId}/messages`, formData)
|
|
309
309
|
|
|
310
|
-
|
|
310
|
+
const first = message.attachments?.[0]
|
|
311
|
+
if (!first) {
|
|
311
312
|
throw new DiscordBotError('Upload succeeded but no attachments returned', 'no_attachments')
|
|
312
313
|
}
|
|
313
314
|
|
|
314
|
-
return
|
|
315
|
+
return first
|
|
315
316
|
}
|
|
316
317
|
|
|
317
318
|
async listFiles(channelId: string): Promise<DiscordFile[]> {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { DiscordBotConfig, DiscordBotCredentials } from './types'
|
|
7
7
|
import { DiscordBotConfigSchema } from './types'
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ export class DiscordBotCredentialManager {
|
|
|
11
11
|
private credentialsPath: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'discordbot-credentials.json')
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import { createAccountId, type InstagramAccount, type InstagramAccountPaths, type InstagramConfig } from './types'
|
|
7
7
|
|
|
8
8
|
export class InstagramCredentialManager {
|
|
@@ -11,7 +11,7 @@ export class InstagramCredentialManager {
|
|
|
11
11
|
private instagramRootDir: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'instagram-credentials.json')
|
|
16
16
|
this.instagramRootDir = join(this.configDir, 'instagram')
|
|
17
17
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
6
5
|
import { Long } from 'bson'
|
|
7
6
|
|
|
7
|
+
import { getConfigDir } from '@/shared/utils/config-dir'
|
|
8
8
|
import { warn } from '@/shared/utils/stderr'
|
|
9
9
|
|
|
10
10
|
import { LANG, PC_OS_NAME, getLocoDeviceConfig } from './protocol/config'
|
|
@@ -105,10 +105,8 @@ function wrapError(error: unknown, code: string): KakaoTalkError {
|
|
|
105
105
|
|
|
106
106
|
const MAX_PAGES = 50
|
|
107
107
|
|
|
108
|
-
const CONFIG_DIR = join(homedir(), '.config', 'agent-messenger')
|
|
109
|
-
|
|
110
108
|
function syncStatePath(deviceUuid: string): string {
|
|
111
|
-
return join(
|
|
109
|
+
return join(getConfigDir(), `kakaotalk-sync-state-${deviceUuid}.json`)
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
async function loadSyncState(deviceUuid: string): Promise<SyncState | undefined> {
|
|
@@ -133,7 +131,7 @@ async function loadSyncState(deviceUuid: string): Promise<SyncState | undefined>
|
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
async function saveSyncState(deviceUuid: string, state: SyncState): Promise<void> {
|
|
136
|
-
await mkdir(
|
|
134
|
+
await mkdir(getConfigDir(), { recursive: true })
|
|
137
135
|
const path = syncStatePath(deviceUuid)
|
|
138
136
|
await writeFile(path, JSON.stringify(state, null, 2))
|
|
139
137
|
await chmod(path, 0o600)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { KakaoAccountCredentials, KakaoConfig, KakaoDeviceType } from './types'
|
|
7
7
|
|
|
8
8
|
export interface PendingLoginState {
|
|
@@ -18,7 +18,7 @@ export class KakaoCredentialManager {
|
|
|
18
18
|
private pendingLoginPath: string
|
|
19
19
|
|
|
20
20
|
constructor(configDir?: string) {
|
|
21
|
-
this.configDir = configDir ??
|
|
21
|
+
this.configDir = configDir ?? getConfigDir()
|
|
22
22
|
this.credentialsPath = join(this.configDir, 'kakaotalk-credentials.json')
|
|
23
23
|
this.pendingLoginPath = join(this.configDir, 'kakaotalk-pending-login.json')
|
|
24
24
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdirSync } from 'node:fs'
|
|
2
|
-
import { homedir } from 'node:os'
|
|
3
2
|
import { join } from 'node:path'
|
|
4
3
|
|
|
4
|
+
import { getConfigDir } from '@/shared/utils/config-dir'
|
|
5
5
|
import { FileStorage } from '@/vendor/linejs/base/storage/mod.js'
|
|
6
6
|
import {
|
|
7
7
|
loginWithQR as linejsLoginWithQR,
|
|
@@ -41,7 +41,7 @@ function getDefaultDevice(): LineDevice {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function createStorage(accountId?: string): FileStorage {
|
|
44
|
-
const dir = join(
|
|
44
|
+
const dir = join(getConfigDir(), 'line-storage')
|
|
45
45
|
mkdirSync(dir, { recursive: true })
|
|
46
46
|
return new FileStorage(join(dir, `${accountId ?? 'default'}.json`))
|
|
47
47
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, rm, writeFile, readFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { LineAccountCredentials, LineConfig } from './types'
|
|
7
7
|
|
|
8
8
|
export class LineCredentialManager {
|
|
@@ -10,7 +10,7 @@ export class LineCredentialManager {
|
|
|
10
10
|
private credentialsPath: string
|
|
11
11
|
|
|
12
12
|
constructor(configDir?: string) {
|
|
13
|
-
this.configDir = configDir ??
|
|
13
|
+
this.configDir = configDir ?? getConfigDir()
|
|
14
14
|
this.credentialsPath = join(this.configDir, 'line-credentials.json')
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { Config, WorkspaceCredentials } from './types'
|
|
7
7
|
|
|
8
8
|
export class SlackCredentialManager {
|
|
@@ -10,7 +10,7 @@ export class SlackCredentialManager {
|
|
|
10
10
|
private credentialsPath: string
|
|
11
11
|
|
|
12
12
|
constructor(configDir?: string) {
|
|
13
|
-
this.configDir = configDir ??
|
|
13
|
+
this.configDir = configDir ?? getConfigDir()
|
|
14
14
|
this.credentialsPath = join(this.configDir, 'slack-credentials.json')
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { SlackBotConfig, SlackBotCredentials, SlackBotWorkspace } from './types'
|
|
7
7
|
import { SlackBotConfigSchema } from './types'
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ export class SlackBotCredentialManager {
|
|
|
11
11
|
private credentialsPath: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'slackbot-credentials.json')
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -103,6 +103,7 @@ export class SlackBotCredentialManager {
|
|
|
103
103
|
// Try "workspace_id/bot_id" format first
|
|
104
104
|
if (botId.includes('/')) {
|
|
105
105
|
const [workspaceId, id] = botId.split('/')
|
|
106
|
+
if (!workspaceId || !id) return null
|
|
106
107
|
const workspace = config.workspaces[workspaceId]
|
|
107
108
|
if (!workspace) return null
|
|
108
109
|
const bot = workspace.bots[id]
|
|
@@ -131,22 +132,24 @@ export class SlackBotCredentialManager {
|
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
const [onlyMatch, ...rest] = matches
|
|
136
|
+
if (onlyMatch && rest.length === 0) return onlyMatch
|
|
135
137
|
return null
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
async setCredentials(creds: SlackBotCredentials): Promise<void> {
|
|
139
141
|
const config = await this.load()
|
|
140
142
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
const existing = config.workspaces[creds.workspace_id]
|
|
144
|
+
const workspace: SlackBotWorkspace = existing ?? {
|
|
145
|
+
workspace_id: creds.workspace_id,
|
|
146
|
+
workspace_name: creds.workspace_name,
|
|
147
|
+
bots: {},
|
|
148
|
+
}
|
|
149
|
+
if (!existing) {
|
|
150
|
+
config.workspaces[creds.workspace_id] = workspace
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
const workspace = config.workspaces[creds.workspace_id]
|
|
150
153
|
workspace.workspace_name = creds.workspace_name
|
|
151
154
|
workspace.bots[creds.bot_id] = {
|
|
152
155
|
bot_id: creds.bot_id,
|
|
@@ -167,6 +170,7 @@ export class SlackBotCredentialManager {
|
|
|
167
170
|
|
|
168
171
|
if (botId.includes('/')) {
|
|
169
172
|
const [workspaceId, id] = botId.split('/')
|
|
173
|
+
if (!workspaceId || !id) return false
|
|
170
174
|
const workspace = config.workspaces[workspaceId]
|
|
171
175
|
if (!workspace || !workspace.bots[id]) return false
|
|
172
176
|
|
|
@@ -183,16 +187,16 @@ export class SlackBotCredentialManager {
|
|
|
183
187
|
return true
|
|
184
188
|
}
|
|
185
189
|
|
|
186
|
-
const matches:
|
|
190
|
+
const matches: SlackBotWorkspace[] = []
|
|
187
191
|
for (const workspace of Object.values(config.workspaces)) {
|
|
188
192
|
if (workspace.bots[botId]) {
|
|
189
|
-
matches.push(
|
|
193
|
+
matches.push(workspace)
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
196
|
|
|
193
|
-
|
|
197
|
+
const [workspace, ...rest] = matches
|
|
198
|
+
if (!workspace || rest.length > 0) return false
|
|
194
199
|
|
|
195
|
-
const { workspace } = matches[0]
|
|
196
200
|
delete workspace.bots[botId]
|
|
197
201
|
if (Object.keys(workspace.bots).length === 0) {
|
|
198
202
|
delete config.workspaces[workspace.workspace_id]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { TeamsAccount, TeamsAccountType, TeamsConfig, TeamsConfigLegacy, TeamsRegion } from './types'
|
|
7
7
|
|
|
8
8
|
export class TeamsCredentialManager {
|
|
@@ -12,7 +12,7 @@ export class TeamsCredentialManager {
|
|
|
12
12
|
private credentialsPath: string
|
|
13
13
|
|
|
14
14
|
constructor(configDir?: string) {
|
|
15
|
-
this.configDir = configDir ??
|
|
15
|
+
this.configDir = configDir ?? getConfigDir()
|
|
16
16
|
this.credentialsPath = join(this.configDir, 'teams-credentials.json')
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import {
|
|
7
7
|
createAccountId,
|
|
8
8
|
type TelegramAccount,
|
|
@@ -21,7 +21,7 @@ export class TelegramCredentialManager {
|
|
|
21
21
|
private tdlibRootDir: string
|
|
22
22
|
|
|
23
23
|
constructor(configDir?: string) {
|
|
24
|
-
this.configDir = configDir ??
|
|
24
|
+
this.configDir = configDir ?? getConfigDir()
|
|
25
25
|
this.credentialsPath = join(this.configDir, 'telegram-credentials.json')
|
|
26
26
|
this.provisioningStatePath = join(this.configDir, 'telegram-provisioning-state.json')
|
|
27
27
|
this.tdlibRootDir = join(this.configDir, 'telegram')
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import { getWebexAppCredentials } from './app-config'
|
|
7
7
|
import type { WebexConfig } from './types'
|
|
8
8
|
import { WebexConfigSchema } from './types'
|
|
@@ -19,7 +19,7 @@ export class WebexCredentialManager {
|
|
|
19
19
|
private credentialsPath: string
|
|
20
20
|
|
|
21
21
|
constructor(configDir?: string) {
|
|
22
|
-
this.configDir = configDir ??
|
|
22
|
+
this.configDir = configDir ?? getConfigDir()
|
|
23
23
|
this.credentialsPath = join(this.configDir, 'webex-credentials.json')
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { WeChatBotAccountEntry, WeChatBotConfig, WeChatBotCredentials } from './types'
|
|
7
7
|
import { WeChatBotConfigSchema } from './types'
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ export class WeChatBotCredentialManager {
|
|
|
11
11
|
private credentialsPath: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'wechatbot-credentials.json')
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import { createAccountId, type WhatsAppAccount, type WhatsAppAccountPaths, type WhatsAppConfig } from './types'
|
|
7
7
|
|
|
8
8
|
export class WhatsAppCredentialManager {
|
|
@@ -11,7 +11,7 @@ export class WhatsAppCredentialManager {
|
|
|
11
11
|
private baileysRootDir: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'whatsapp-credentials.json')
|
|
16
16
|
this.baileysRootDir = join(this.configDir, 'whatsapp')
|
|
17
17
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from '../../shared/utils/config-dir'
|
|
6
6
|
import type { WhatsAppBotAccountEntry, WhatsAppBotConfig, WhatsAppBotCredentials } from './types'
|
|
7
7
|
import { WhatsAppBotConfigSchema } from './types'
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ export class WhatsAppBotCredentialManager {
|
|
|
11
11
|
private credentialsPath: string
|
|
12
12
|
|
|
13
13
|
constructor(configDir?: string) {
|
|
14
|
-
this.configDir = configDir ??
|
|
14
|
+
this.configDir = configDir ?? getConfigDir()
|
|
15
15
|
this.credentialsPath = join(this.configDir, 'whatsappbot-credentials.json')
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
|
|
2
|
+
import { homedir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { CONFIG_DIR_ENV_VAR, getConfigDir } from './config-dir'
|
|
6
|
+
|
|
7
|
+
describe('getConfigDir', () => {
|
|
8
|
+
let original: string | undefined
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
original = process.env[CONFIG_DIR_ENV_VAR]
|
|
12
|
+
delete process.env[CONFIG_DIR_ENV_VAR]
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
if (original === undefined) {
|
|
17
|
+
delete process.env[CONFIG_DIR_ENV_VAR]
|
|
18
|
+
} else {
|
|
19
|
+
process.env[CONFIG_DIR_ENV_VAR] = original
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('returns the default path when the env var is unset', () => {
|
|
24
|
+
expect(getConfigDir()).toBe(join(homedir(), '.config', 'agent-messenger'))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('returns the env var value when set', () => {
|
|
28
|
+
process.env[CONFIG_DIR_ENV_VAR] = '/tmp/custom-config-dir'
|
|
29
|
+
expect(getConfigDir()).toBe('/tmp/custom-config-dir')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('falls back to the default when the env var is empty', () => {
|
|
33
|
+
process.env[CONFIG_DIR_ENV_VAR] = ''
|
|
34
|
+
expect(getConfigDir()).toBe(join(homedir(), '.config', 'agent-messenger'))
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('does not append agent-messenger to the override path', () => {
|
|
38
|
+
process.env[CONFIG_DIR_ENV_VAR] = '/var/lib/messenger'
|
|
39
|
+
expect(getConfigDir()).toBe('/var/lib/messenger')
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { homedir } from 'node:os'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const CONFIG_DIR_ENV_VAR = 'AGENT_MESSENGER_CONFIG_DIR'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the directory used to persist agent-messenger configuration and
|
|
8
|
+
* credentials.
|
|
9
|
+
*
|
|
10
|
+
* Resolution order:
|
|
11
|
+
* 1. `AGENT_MESSENGER_CONFIG_DIR` environment variable (if set and non-empty)
|
|
12
|
+
* 2. Default: `~/.config/agent-messenger`
|
|
13
|
+
*
|
|
14
|
+
* Used by every platform credential manager so that a single env var override
|
|
15
|
+
* relocates all stored credentials, sync state, and derived-key caches.
|
|
16
|
+
*/
|
|
17
|
+
export function getConfigDir(): string {
|
|
18
|
+
const override = process.env[CONFIG_DIR_ENV_VAR]
|
|
19
|
+
if (override && override.length > 0) {
|
|
20
|
+
return override
|
|
21
|
+
}
|
|
22
|
+
return join(homedir(), '.config', 'agent-messenger')
|
|
23
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
3
|
import { join } from 'node:path'
|
|
5
4
|
|
|
5
|
+
import { getConfigDir } from './config-dir'
|
|
6
|
+
|
|
6
7
|
export type Platform = 'slack' | 'discord' | 'teams' | 'instagram' | 'channeltalk'
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -18,7 +19,7 @@ export class DerivedKeyCache {
|
|
|
18
19
|
private cacheDir: string
|
|
19
20
|
|
|
20
21
|
constructor(cacheDir?: string) {
|
|
21
|
-
this.cacheDir = cacheDir ?? join(
|
|
22
|
+
this.cacheDir = cacheDir ?? join(getConfigDir(), '.derived-keys')
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
private getKeyPath(platform: Platform): string {
|