agent-messenger 2.0.0 → 2.2.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/marketplace.json +14 -1
- package/.claude-plugin/plugin.json +4 -2
- package/.env.template +35 -17
- package/README.md +37 -33
- package/bun.lock +6 -6
- package/dist/package.json +11 -3
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +3 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js +35 -28
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/ensure-auth.js +6 -6
- package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +23 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +299 -29
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js +57 -49
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/ensure-auth.js +3 -3
- package/dist/src/platforms/discord/ensure-auth.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +6 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +167 -14
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/instagram/client.d.ts +2 -0
- package/dist/src/platforms/instagram/client.d.ts.map +1 -1
- package/dist/src/platforms/instagram/client.js +2 -2
- package/dist/src/platforms/instagram/client.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js +107 -14
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/ensure-auth.js +57 -11
- package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
- package/dist/src/platforms/instagram/index.d.ts +1 -0
- package/dist/src/platforms/instagram/index.d.ts.map +1 -1
- package/dist/src/platforms/instagram/index.js +1 -0
- package/dist/src/platforms/instagram/index.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +44 -0
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -0
- package/dist/src/platforms/instagram/token-extractor.js +407 -0
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -0
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +2 -1
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/auth.js +14 -13
- package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.js +2 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
- package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/auth.js +6 -5
- package/dist/src/platforms/line/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js +11 -10
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +9 -0
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +300 -23
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +9 -8
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +2 -1
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +5 -0
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +161 -29
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/telegram/client.d.ts.map +1 -1
- package/dist/src/platforms/telegram/client.js +25 -7
- package/dist/src/platforms/telegram/client.js.map +1 -1
- package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/telegram/commands/auth.js +6 -5
- package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/app-config.d.ts +7 -0
- package/dist/src/platforms/webex/app-config.d.ts.map +1 -0
- package/dist/src/platforms/webex/app-config.js +20 -0
- package/dist/src/platforms/webex/app-config.js.map +1 -0
- package/dist/src/platforms/webex/cli.d.ts +5 -0
- package/dist/src/platforms/webex/cli.d.ts.map +1 -0
- package/dist/src/platforms/webex/cli.js +32 -0
- package/dist/src/platforms/webex/cli.js.map +1 -0
- package/dist/src/platforms/webex/client.d.ts +55 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -0
- package/dist/src/platforms/webex/client.js +299 -0
- package/dist/src/platforms/webex/client.js.map +1 -0
- package/dist/src/platforms/webex/commands/auth.d.ts +19 -0
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/auth.js +166 -0
- package/dist/src/platforms/webex/commands/auth.js.map +1 -0
- package/dist/src/platforms/webex/commands/index.d.ts +6 -0
- package/dist/src/platforms/webex/commands/index.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/index.js +6 -0
- package/dist/src/platforms/webex/commands/index.js.map +1 -0
- package/dist/src/platforms/webex/commands/member.d.ts +7 -0
- package/dist/src/platforms/webex/commands/member.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/member.js +34 -0
- package/dist/src/platforms/webex/commands/member.js.map +1 -0
- package/dist/src/platforms/webex/commands/message.d.ts +26 -0
- package/dist/src/platforms/webex/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/message.js +153 -0
- package/dist/src/platforms/webex/commands/message.js.map +1 -0
- package/dist/src/platforms/webex/commands/snapshot.d.ts +9 -0
- package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/snapshot.js +72 -0
- package/dist/src/platforms/webex/commands/snapshot.js.map +1 -0
- package/dist/src/platforms/webex/commands/space.d.ts +11 -0
- package/dist/src/platforms/webex/commands/space.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/space.js +59 -0
- package/dist/src/platforms/webex/commands/space.js.map +1 -0
- package/dist/src/platforms/webex/credential-manager.d.ts +23 -0
- package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/webex/credential-manager.js +148 -0
- package/dist/src/platforms/webex/credential-manager.js.map +1 -0
- package/dist/src/platforms/webex/ensure-auth.d.ts +2 -0
- package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -0
- package/dist/src/platforms/webex/ensure-auth.js +36 -0
- package/dist/src/platforms/webex/ensure-auth.js.map +1 -0
- package/dist/src/platforms/webex/index.d.ts +8 -0
- package/dist/src/platforms/webex/index.d.ts.map +1 -0
- package/dist/src/platforms/webex/index.js +6 -0
- package/dist/src/platforms/webex/index.js.map +1 -0
- package/dist/src/platforms/webex/token-extractor.d.ts +28 -0
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -0
- package/dist/src/platforms/webex/token-extractor.js +344 -0
- package/dist/src/platforms/webex/token-extractor.js.map +1 -0
- package/dist/src/platforms/webex/types.d.ts +127 -0
- package/dist/src/platforms/webex/types.d.ts.map +1 -0
- package/dist/src/platforms/webex/types.js +64 -0
- package/dist/src/platforms/webex/types.js.map +1 -0
- package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/client.js +6 -2
- package/dist/src/platforms/whatsapp/client.js.map +1 -1
- package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
- package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
- package/dist/src/shared/utils/error-handler.d.ts +1 -1
- package/dist/src/shared/utils/error-handler.d.ts.map +1 -1
- package/dist/src/shared/utils/error-handler.js +3 -2
- package/dist/src/shared/utils/error-handler.js.map +1 -1
- package/dist/src/shared/utils/stderr.d.ts +5 -0
- package/dist/src/shared/utils/stderr.d.ts.map +1 -0
- package/dist/src/shared/utils/stderr.js +18 -0
- package/dist/src/shared/utils/stderr.js.map +1 -0
- package/dist/src/tui/adapters/webex-adapter.d.ts +14 -0
- package/dist/src/tui/adapters/webex-adapter.d.ts.map +1 -0
- package/dist/src/tui/adapters/webex-adapter.js +79 -0
- package/dist/src/tui/adapters/webex-adapter.js.map +1 -0
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +2 -0
- package/dist/src/tui/app.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +7 -7
- package/docs/content/docs/cli/discord.mdx +3 -3
- package/docs/content/docs/cli/instagram.mdx +28 -6
- package/docs/content/docs/cli/meta.json +1 -0
- package/docs/content/docs/cli/slack.mdx +2 -2
- package/docs/content/docs/cli/teams.mdx +6 -4
- package/docs/content/docs/cli/webex.mdx +310 -0
- package/docs/content/docs/sdk/meta.json +1 -1
- package/docs/content/docs/sdk/webex.mdx +260 -0
- package/docs/content/docs/tui.mdx +4 -3
- package/docs/src/app/page.tsx +2 -2
- package/e2e/README.md +132 -8
- package/e2e/channeltalk.e2e.test.ts +2 -7
- package/e2e/channeltalkbot.e2e.test.ts +2 -6
- package/e2e/config.ts +172 -10
- package/e2e/helpers.ts +7 -0
- package/e2e/instagram.e2e.test.ts +97 -0
- package/e2e/kakaotalk.e2e.test.ts +74 -0
- package/e2e/line.e2e.test.ts +92 -0
- package/e2e/teams.e2e.test.ts +46 -1
- package/e2e/telegram.e2e.test.ts +84 -0
- package/e2e/webex.e2e.test.ts +190 -0
- package/e2e/whatsapp.e2e.test.ts +90 -0
- package/e2e/whatsappbot.e2e.test.ts +78 -0
- package/package.json +11 -3
- package/skills/agent-channeltalk/SKILL.md +9 -9
- package/skills/agent-channeltalk/references/authentication.md +21 -18
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +5 -5
- package/skills/agent-discord/references/authentication.md +8 -8
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +51 -9
- package/skills/agent-instagram/references/authentication.md +35 -3
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +5 -5
- package/skills/agent-slack/references/authentication.md +8 -8
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +6 -6
- package/skills/agent-teams/references/authentication.md +8 -8
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +406 -0
- package/skills/agent-webex/references/authentication.md +371 -0
- package/skills/agent-webex/references/common-patterns.md +726 -0
- package/skills/agent-webex/templates/monitor-space.sh +165 -0
- package/skills/agent-webex/templates/post-message.sh +170 -0
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/cli.ts +4 -0
- package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
- package/src/platforms/channeltalk/commands/auth.ts +38 -32
- package/src/platforms/channeltalk/ensure-auth.test.ts +6 -6
- package/src/platforms/channeltalk/ensure-auth.ts +6 -6
- package/src/platforms/channeltalk/token-extractor.test.ts +182 -15
- package/src/platforms/channeltalk/token-extractor.ts +344 -30
- package/src/platforms/discord/commands/auth.test.ts +3 -3
- package/src/platforms/discord/commands/auth.ts +58 -54
- package/src/platforms/discord/ensure-auth.test.ts +3 -3
- package/src/platforms/discord/ensure-auth.ts +3 -3
- package/src/platforms/discord/token-extractor.test.ts +199 -27
- package/src/platforms/discord/token-extractor.ts +190 -17
- package/src/platforms/instagram/client.ts +2 -2
- package/src/platforms/instagram/commands/auth.ts +133 -14
- package/src/platforms/instagram/ensure-auth.ts +63 -12
- package/src/platforms/instagram/index.ts +1 -0
- package/src/platforms/instagram/token-extractor.test.ts +424 -0
- package/src/platforms/instagram/token-extractor.ts +478 -0
- package/src/platforms/kakaotalk/client.ts +3 -1
- package/src/platforms/kakaotalk/commands/auth.ts +14 -13
- package/src/platforms/kakaotalk/protocol/connection.ts +3 -1
- package/src/platforms/line/commands/auth.ts +7 -6
- package/src/platforms/slack/cli.test.ts +6 -5
- package/src/platforms/slack/commands/auth.test.ts +11 -7
- package/src/platforms/slack/commands/auth.ts +11 -10
- package/src/platforms/slack/token-extractor.test.ts +98 -1
- package/src/platforms/slack/token-extractor.ts +338 -26
- package/src/platforms/teams/commands/auth.ts +9 -8
- package/src/platforms/teams/ensure-auth.ts +3 -1
- package/src/platforms/teams/token-extractor.test.ts +136 -17
- package/src/platforms/teams/token-extractor.ts +182 -31
- package/src/platforms/telegram/client.test.ts +134 -0
- package/src/platforms/telegram/client.ts +27 -6
- package/src/platforms/telegram/commands/auth.ts +6 -5
- package/src/platforms/webex/app-config.test.ts +98 -0
- package/src/platforms/webex/app-config.ts +31 -0
- package/src/platforms/webex/cli.test.ts +58 -0
- package/src/platforms/webex/cli.ts +39 -0
- package/src/platforms/webex/client.test.ts +743 -0
- package/src/platforms/webex/client.ts +405 -0
- package/src/platforms/webex/commands/auth.test.ts +222 -0
- package/src/platforms/webex/commands/auth.ts +243 -0
- package/src/platforms/webex/commands/index.ts +5 -0
- package/src/platforms/webex/commands/member.test.ts +112 -0
- package/src/platforms/webex/commands/member.ts +45 -0
- package/src/platforms/webex/commands/message.test.ts +235 -0
- package/src/platforms/webex/commands/message.ts +204 -0
- package/src/platforms/webex/commands/snapshot.test.ts +105 -0
- package/src/platforms/webex/commands/snapshot.ts +91 -0
- package/src/platforms/webex/commands/space.test.ts +216 -0
- package/src/platforms/webex/commands/space.ts +74 -0
- package/src/platforms/webex/credential-manager.test.ts +314 -0
- package/src/platforms/webex/credential-manager.ts +197 -0
- package/src/platforms/webex/ensure-auth.test.ts +89 -0
- package/src/platforms/webex/ensure-auth.ts +38 -0
- package/src/platforms/webex/index.test.ts +25 -0
- package/src/platforms/webex/index.ts +19 -0
- package/src/platforms/webex/token-extractor.test.ts +327 -0
- package/src/platforms/webex/token-extractor.ts +393 -0
- package/src/platforms/webex/types.test.ts +307 -0
- package/src/platforms/webex/types.ts +129 -0
- package/src/platforms/whatsapp/client.ts +11 -7
- package/src/shared/utils/derived-key-cache.ts +1 -1
- package/src/shared/utils/error-handler.ts +4 -2
- package/src/shared/utils/stderr.ts +22 -0
- package/src/tui/adapters/webex-adapter.ts +103 -0
- package/src/tui/app.ts +2 -0
|
@@ -16,6 +16,140 @@ const mockPaths: TelegramAccountPaths = {
|
|
|
16
16
|
files_dir: '/tmp/test-files',
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function createMockClient(sendHandler: (request: any, events: any[]) => void) {
|
|
20
|
+
const events: any[] = []
|
|
21
|
+
const createClientId = mock(() => 1)
|
|
22
|
+
const send = mock((_clientId: number, request: any) => sendHandler(request, events))
|
|
23
|
+
const receive = mock(() => events.shift() ?? null)
|
|
24
|
+
|
|
25
|
+
const client = new (TelegramTdlibClient as unknown as new (
|
|
26
|
+
account: TelegramAccount,
|
|
27
|
+
paths: TelegramAccountPaths,
|
|
28
|
+
tdjson: any,
|
|
29
|
+
) => TelegramTdlibClient)(mockAccount, mockPaths, {
|
|
30
|
+
createClientId,
|
|
31
|
+
send,
|
|
32
|
+
receive,
|
|
33
|
+
libraryPath: '/mock/lib',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return { client, events, send }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function pushAuthReady(events: any[], extra: string) {
|
|
40
|
+
events.push({
|
|
41
|
+
'@type': 'updateAuthorizationState',
|
|
42
|
+
authorization_state: { '@type': 'authorizationStateReady' },
|
|
43
|
+
'@extra': extra,
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe('listChats', () => {
|
|
48
|
+
test('loads chats across multiple loadChats calls until 404', async () => {
|
|
49
|
+
let loadChatsCallCount = 0
|
|
50
|
+
const allChatIds = [1, 2, 3, 4, 5]
|
|
51
|
+
|
|
52
|
+
const { client } = createMockClient((request, events) => {
|
|
53
|
+
if (request['@type'] === 'getAuthorizationState') {
|
|
54
|
+
pushAuthReady(events, request['@extra'])
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (request['@type'] === 'loadChats') {
|
|
59
|
+
loadChatsCallCount += 1
|
|
60
|
+
if (loadChatsCallCount <= 2) {
|
|
61
|
+
// given — first two calls succeed (simulate partial loading)
|
|
62
|
+
events.push({ '@type': 'ok', '@extra': request['@extra'] })
|
|
63
|
+
} else {
|
|
64
|
+
// given — third call returns 404 (all chats loaded)
|
|
65
|
+
events.push({ '@type': 'error', code: 404, message: 'Chat list has been loaded completely', '@extra': request['@extra'] })
|
|
66
|
+
}
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (request['@type'] === 'getChats') {
|
|
71
|
+
// when — after first two loadChats calls, return partial; after 404, return all
|
|
72
|
+
const returnCount = loadChatsCallCount >= 3 ? allChatIds.length : Math.min(loadChatsCallCount * 2, allChatIds.length)
|
|
73
|
+
events.push({
|
|
74
|
+
'@type': 'chats',
|
|
75
|
+
total_count: returnCount,
|
|
76
|
+
chat_ids: allChatIds.slice(0, returnCount),
|
|
77
|
+
'@extra': request['@extra'],
|
|
78
|
+
})
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (request['@type'] === 'getChat') {
|
|
83
|
+
const chatId = request.chat_id
|
|
84
|
+
const typeNames = ['chatTypePrivate', 'chatTypePrivate', 'chatTypeBasicGroup', 'chatTypeSupergroup', 'chatTypeSupergroup']
|
|
85
|
+
const idx = allChatIds.indexOf(chatId)
|
|
86
|
+
events.push({
|
|
87
|
+
'@type': 'chat',
|
|
88
|
+
id: chatId,
|
|
89
|
+
title: `Chat ${chatId}`,
|
|
90
|
+
type: { '@type': typeNames[idx] ?? 'chatTypePrivate' },
|
|
91
|
+
unread_count: 0,
|
|
92
|
+
'@extra': request['@extra'],
|
|
93
|
+
})
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const chats = await client.listChats(5)
|
|
99
|
+
|
|
100
|
+
// then — all 5 chats returned including groups
|
|
101
|
+
expect(chats).toHaveLength(5)
|
|
102
|
+
expect(chats.map((c) => c.type)).toEqual(['private', 'private', 'basicgroup', 'supergroup', 'supergroup'])
|
|
103
|
+
expect(loadChatsCallCount).toBe(3)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('stops loading when enough chats are cached before 404', async () => {
|
|
107
|
+
let loadChatsCallCount = 0
|
|
108
|
+
|
|
109
|
+
const { client } = createMockClient((request, events) => {
|
|
110
|
+
if (request['@type'] === 'getAuthorizationState') {
|
|
111
|
+
pushAuthReady(events, request['@extra'])
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (request['@type'] === 'loadChats') {
|
|
116
|
+
loadChatsCallCount += 1
|
|
117
|
+
events.push({ '@type': 'ok', '@extra': request['@extra'] })
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (request['@type'] === 'getChats') {
|
|
122
|
+
// given — always return 3 chats (enough for limit=3)
|
|
123
|
+
events.push({
|
|
124
|
+
'@type': 'chats',
|
|
125
|
+
total_count: 3,
|
|
126
|
+
chat_ids: [10, 20, 30],
|
|
127
|
+
'@extra': request['@extra'],
|
|
128
|
+
})
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (request['@type'] === 'getChat') {
|
|
133
|
+
events.push({
|
|
134
|
+
'@type': 'chat',
|
|
135
|
+
id: request.chat_id,
|
|
136
|
+
title: `Chat ${request.chat_id}`,
|
|
137
|
+
type: { '@type': 'chatTypeSupergroup' },
|
|
138
|
+
unread_count: 0,
|
|
139
|
+
'@extra': request['@extra'],
|
|
140
|
+
})
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const chats = await client.listChats(3)
|
|
146
|
+
|
|
147
|
+
// then — stops after first loop iteration since we have enough
|
|
148
|
+
expect(chats).toHaveLength(3)
|
|
149
|
+
expect(loadChatsCallCount).toBe(1)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
|
|
19
153
|
describe('sendMessage confirmation', () => {
|
|
20
154
|
test('returns confirmed message id when updateMessageSendSucceeded arrives', async () => {
|
|
21
155
|
const tempId = 100
|
|
@@ -162,16 +162,37 @@ export class TelegramTdlibClient {
|
|
|
162
162
|
async listChats(limit: number = 20): Promise<TelegramChatSummary[]> {
|
|
163
163
|
await this.ensureReady()
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
// loadChats may load fewer chats than requested per call. Loop until TDLib
|
|
166
|
+
// signals 404 ("chat list fully loaded") or we have enough cached entries.
|
|
167
|
+
for (;;) {
|
|
168
|
+
try {
|
|
169
|
+
await this.call({
|
|
170
|
+
'@type': 'loadChats',
|
|
171
|
+
chat_list: {
|
|
172
|
+
'@type': 'chatListMain',
|
|
173
|
+
},
|
|
174
|
+
limit,
|
|
175
|
+
})
|
|
176
|
+
} catch (error) {
|
|
177
|
+
// TDLib signals 404 when the entire chat list has been loaded.
|
|
178
|
+
if (error instanceof TelegramError && error.code === 404) {
|
|
179
|
+
break
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
break
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const partial = (await this.call({
|
|
186
|
+
'@type': 'getChats',
|
|
168
187
|
chat_list: {
|
|
169
188
|
'@type': 'chatListMain',
|
|
170
189
|
},
|
|
171
190
|
limit,
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
|
|
191
|
+
})) as TdChats
|
|
192
|
+
|
|
193
|
+
if ((partial.chat_ids ?? []).length >= limit) {
|
|
194
|
+
break
|
|
195
|
+
}
|
|
175
196
|
}
|
|
176
197
|
|
|
177
198
|
const response = (await this.call({
|
|
@@ -4,6 +4,7 @@ import { Command } from 'commander'
|
|
|
4
4
|
|
|
5
5
|
import { handleError } from '../../../shared/utils/error-handler'
|
|
6
6
|
import { formatOutput } from '../../../shared/utils/output'
|
|
7
|
+
import { info, error as stderrError } from '@/shared/utils/stderr'
|
|
7
8
|
import { getTelegramAppCredentials } from '../app-config'
|
|
8
9
|
import { TelegramTdlibClient } from '../client'
|
|
9
10
|
import { TelegramCredentialManager } from '../credential-manager'
|
|
@@ -126,8 +127,8 @@ async function fillMissingBootstrappingInputs(
|
|
|
126
127
|
if (!resolved.apiId && !existing?.api_id) {
|
|
127
128
|
if (shouldUseInteractivePrompts()) {
|
|
128
129
|
try {
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
info('No API credentials found. Provisioning via my.telegram.org...')
|
|
131
|
+
info('A verification code will be sent to your Telegram account.\n')
|
|
131
132
|
|
|
132
133
|
const phone = resolved.phone || (await promptText('Phone number (e.g. +14155551234)'))
|
|
133
134
|
if (!phone) {
|
|
@@ -148,10 +149,10 @@ async function fillMissingBootstrappingInputs(
|
|
|
148
149
|
|
|
149
150
|
resolved.apiId = String(app.api_id)
|
|
150
151
|
resolved.apiHash = app.api_hash
|
|
151
|
-
|
|
152
|
+
info(`\n✓ API credentials obtained (api_id: ${app.api_id})`)
|
|
152
153
|
} catch (error) {
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
stderrError(`\nAuto-provisioning failed: ${error instanceof Error ? error.message : error}`)
|
|
155
|
+
info('Enter your API credentials manually (from https://my.telegram.org/apps):\n')
|
|
155
156
|
resolved.apiId = await promptText('Telegram API ID')
|
|
156
157
|
resolved.apiHash = await promptHidden('Telegram API hash')
|
|
157
158
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
|
2
|
+
import { getWebexAppCredentials } from './app-config'
|
|
3
|
+
|
|
4
|
+
const ENV_KEYS = [
|
|
5
|
+
'AGENT_WEBEX_CLIENT_ID',
|
|
6
|
+
'AGENT_WEBEX_CLIENT_SECRET',
|
|
7
|
+
'AGENT_MESSENGER_WEBEX_CLIENT_ID',
|
|
8
|
+
'AGENT_MESSENGER_WEBEX_CLIENT_SECRET',
|
|
9
|
+
] as const
|
|
10
|
+
|
|
11
|
+
describe('webex app config', () => {
|
|
12
|
+
let savedEnv: Record<string, string | undefined> = {}
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
savedEnv = {}
|
|
16
|
+
for (const key of ENV_KEYS) {
|
|
17
|
+
savedEnv[key] = process.env[key]
|
|
18
|
+
delete process.env[key]
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
for (const key of ENV_KEYS) {
|
|
24
|
+
if (savedEnv[key] === undefined) {
|
|
25
|
+
delete process.env[key]
|
|
26
|
+
} else {
|
|
27
|
+
process.env[key] = savedEnv[key]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('returns env credentials when primary env vars are set', () => {
|
|
33
|
+
process.env.AGENT_WEBEX_CLIENT_ID = 'my-client-id'
|
|
34
|
+
process.env.AGENT_WEBEX_CLIENT_SECRET = 'my-client-secret'
|
|
35
|
+
|
|
36
|
+
expect(getWebexAppCredentials()).toEqual({
|
|
37
|
+
clientId: 'my-client-id',
|
|
38
|
+
clientSecret: 'my-client-secret',
|
|
39
|
+
source: 'env',
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('returns env credentials when legacy env vars are set', () => {
|
|
44
|
+
process.env.AGENT_MESSENGER_WEBEX_CLIENT_ID = 'legacy-client-id'
|
|
45
|
+
process.env.AGENT_MESSENGER_WEBEX_CLIENT_SECRET = 'legacy-client-secret'
|
|
46
|
+
|
|
47
|
+
expect(getWebexAppCredentials()).toEqual({
|
|
48
|
+
clientId: 'legacy-client-id',
|
|
49
|
+
clientSecret: 'legacy-client-secret',
|
|
50
|
+
source: 'env',
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('returns builtin credentials when nothing is configured', () => {
|
|
55
|
+
const result = getWebexAppCredentials()
|
|
56
|
+
expect(result.source).toBe('builtin')
|
|
57
|
+
expect(result.clientId).toBeTruthy()
|
|
58
|
+
expect(result.clientSecret).toBeTruthy()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('returns builtin when only clientId is set', () => {
|
|
62
|
+
process.env.AGENT_WEBEX_CLIENT_ID = 'my-client-id'
|
|
63
|
+
|
|
64
|
+
const result = getWebexAppCredentials()
|
|
65
|
+
expect(result.source).toBe('builtin')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('returns builtin when only clientSecret is set', () => {
|
|
69
|
+
process.env.AGENT_WEBEX_CLIENT_SECRET = 'my-client-secret'
|
|
70
|
+
|
|
71
|
+
const result = getWebexAppCredentials()
|
|
72
|
+
expect(result.source).toBe('builtin')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('trims whitespace from clientId and clientSecret', () => {
|
|
76
|
+
process.env.AGENT_WEBEX_CLIENT_ID = ' my-client-id '
|
|
77
|
+
process.env.AGENT_WEBEX_CLIENT_SECRET = ' my-client-secret '
|
|
78
|
+
|
|
79
|
+
expect(getWebexAppCredentials()).toEqual({
|
|
80
|
+
clientId: 'my-client-id',
|
|
81
|
+
clientSecret: 'my-client-secret',
|
|
82
|
+
source: 'env',
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('primary env takes precedence over legacy env', () => {
|
|
87
|
+
process.env.AGENT_WEBEX_CLIENT_ID = 'primary-id'
|
|
88
|
+
process.env.AGENT_WEBEX_CLIENT_SECRET = 'primary-secret'
|
|
89
|
+
process.env.AGENT_MESSENGER_WEBEX_CLIENT_ID = 'legacy-id'
|
|
90
|
+
process.env.AGENT_MESSENGER_WEBEX_CLIENT_SECRET = 'legacy-secret'
|
|
91
|
+
|
|
92
|
+
expect(getWebexAppCredentials()).toEqual({
|
|
93
|
+
clientId: 'primary-id',
|
|
94
|
+
clientSecret: 'primary-secret',
|
|
95
|
+
source: 'env',
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const BUILTIN_CLIENT_ID = 'C720341c19d8dfb4cab8a5db78be4bc6d5c3983fbe84df94be34c8aa69a695583'
|
|
2
|
+
const BUILTIN_CLIENT_SECRET = 'e90806657443a7f16093c0846690aeeea96cd2b3ed9b79cf544297c526b4f9af'
|
|
3
|
+
|
|
4
|
+
export interface WebexAppCredentials {
|
|
5
|
+
clientId: string
|
|
6
|
+
clientSecret: string
|
|
7
|
+
source: 'env' | 'builtin'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function parseTrimmed(value: string | undefined): string | undefined {
|
|
11
|
+
const normalized = value?.trim()
|
|
12
|
+
return normalized ? normalized : undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getWebexAppCredentials(): WebexAppCredentials {
|
|
16
|
+
const envClientId = parseTrimmed(process.env.AGENT_WEBEX_CLIENT_ID)
|
|
17
|
+
const envClientSecret = parseTrimmed(process.env.AGENT_WEBEX_CLIENT_SECRET)
|
|
18
|
+
|
|
19
|
+
if (envClientId && envClientSecret) {
|
|
20
|
+
return { clientId: envClientId, clientSecret: envClientSecret, source: 'env' }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const legacyClientId = parseTrimmed(process.env.AGENT_MESSENGER_WEBEX_CLIENT_ID)
|
|
24
|
+
const legacyClientSecret = parseTrimmed(process.env.AGENT_MESSENGER_WEBEX_CLIENT_SECRET)
|
|
25
|
+
|
|
26
|
+
if (legacyClientId && legacyClientSecret) {
|
|
27
|
+
return { clientId: legacyClientId, clientSecret: legacyClientSecret, source: 'env' }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { clientId: BUILTIN_CLIENT_ID, clientSecret: BUILTIN_CLIENT_SECRET, source: 'builtin' }
|
|
31
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'bun'
|
|
4
|
+
|
|
5
|
+
import pkg from '../../../package.json' with { type: 'json' }
|
|
6
|
+
|
|
7
|
+
describe('Webex CLI program structure', () => {
|
|
8
|
+
test('--help shows all commands', async () => {
|
|
9
|
+
const proc = spawn(['bun', 'run', './src/platforms/webex/cli.ts', '--help'], {
|
|
10
|
+
cwd: process.cwd(),
|
|
11
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const output = await new Response(proc.stdout).text()
|
|
15
|
+
|
|
16
|
+
expect(output).toContain('auth')
|
|
17
|
+
expect(output).toContain('member')
|
|
18
|
+
expect(output).toContain('message')
|
|
19
|
+
expect(output).toContain('snapshot')
|
|
20
|
+
expect(output).toContain('space')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('--version shows package version', async () => {
|
|
24
|
+
const proc = spawn(['bun', 'run', './src/platforms/webex/cli.ts', '--version'], {
|
|
25
|
+
cwd: process.cwd(),
|
|
26
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const output = await new Response(proc.stdout).text()
|
|
30
|
+
expect(output.trim()).toBe(pkg.version)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('auth login --help shows Device Grant options', async () => {
|
|
34
|
+
const proc = spawn(['bun', 'run', './src/platforms/webex/cli.ts', 'auth', 'login', '--help'], {
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const output = await new Response(proc.stdout).text()
|
|
40
|
+
|
|
41
|
+
expect(output).toContain('--token')
|
|
42
|
+
expect(output).toContain('--client-id')
|
|
43
|
+
expect(output).toContain('--client-secret')
|
|
44
|
+
expect(output).toContain('--pretty')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('message dm --help shows email argument', async () => {
|
|
48
|
+
const proc = spawn(['bun', 'run', './src/platforms/webex/cli.ts', 'message', 'dm', '--help'], {
|
|
49
|
+
cwd: process.cwd(),
|
|
50
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const output = await new Response(proc.stdout).text()
|
|
54
|
+
|
|
55
|
+
expect(output).toContain('email')
|
|
56
|
+
expect(output).toContain('--markdown')
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import type { Command as CommandType } from 'commander'
|
|
4
|
+
import { Command } from 'commander'
|
|
5
|
+
|
|
6
|
+
import pkg from '../../../package.json' with { type: 'json' }
|
|
7
|
+
import { authCommand, memberCommand, messageCommand, snapshotCommand, spaceCommand } from './commands'
|
|
8
|
+
import { ensureWebexAuth } from './ensure-auth'
|
|
9
|
+
|
|
10
|
+
function isAuthCommand(command: CommandType): boolean {
|
|
11
|
+
let cmd: CommandType | null = command
|
|
12
|
+
while (cmd) {
|
|
13
|
+
if (cmd.name() === 'auth') return true
|
|
14
|
+
cmd = cmd.parent
|
|
15
|
+
}
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const program = new Command()
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name('agent-webex')
|
|
23
|
+
.description('CLI tool for Cisco Webex communication')
|
|
24
|
+
.version(pkg.version)
|
|
25
|
+
|
|
26
|
+
program.hook('preAction', async (_thisCommand, actionCommand) => {
|
|
27
|
+
if (isAuthCommand(actionCommand)) return
|
|
28
|
+
await ensureWebexAuth()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
program.addCommand(authCommand)
|
|
32
|
+
program.addCommand(memberCommand)
|
|
33
|
+
program.addCommand(messageCommand)
|
|
34
|
+
program.addCommand(snapshotCommand)
|
|
35
|
+
program.addCommand(spaceCommand)
|
|
36
|
+
|
|
37
|
+
program.parse(process.argv)
|
|
38
|
+
|
|
39
|
+
export default program
|