agent-messenger 2.20.5 → 2.22.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 +8 -5
- package/dist/package.json +9 -1
- 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/webex/client.d.ts +19 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +81 -1
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webexbot/cli.d.ts +5 -0
- package/dist/src/platforms/webexbot/cli.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/cli.js +33 -0
- package/dist/src/platforms/webexbot/cli.js.map +1 -0
- package/dist/src/platforms/webexbot/client.d.ts +61 -0
- package/dist/src/platforms/webexbot/client.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/client.js +80 -0
- package/dist/src/platforms/webexbot/client.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/auth.d.ts +28 -0
- package/dist/src/platforms/webexbot/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/auth.js +166 -0
- package/dist/src/platforms/webexbot/commands/auth.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/file.d.ts +22 -0
- package/dist/src/platforms/webexbot/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/file.js +64 -0
- package/dist/src/platforms/webexbot/commands/file.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/index.d.ts +10 -0
- package/dist/src/platforms/webexbot/commands/index.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/index.js +10 -0
- package/dist/src/platforms/webexbot/commands/index.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/listen.d.ts +12 -0
- package/dist/src/platforms/webexbot/commands/listen.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/listen.js +85 -0
- package/dist/src/platforms/webexbot/commands/listen.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/member.d.ts +19 -0
- package/dist/src/platforms/webexbot/commands/member.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/member.js +33 -0
- package/dist/src/platforms/webexbot/commands/member.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/message.d.ts +44 -0
- package/dist/src/platforms/webexbot/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/message.js +193 -0
- package/dist/src/platforms/webexbot/commands/message.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/shared.d.ts +9 -0
- package/dist/src/platforms/webexbot/commands/shared.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/shared.js +13 -0
- package/dist/src/platforms/webexbot/commands/shared.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/snapshot.d.ts +24 -0
- package/dist/src/platforms/webexbot/commands/snapshot.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/snapshot.js +37 -0
- package/dist/src/platforms/webexbot/commands/snapshot.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/space.d.ts +28 -0
- package/dist/src/platforms/webexbot/commands/space.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/space.js +61 -0
- package/dist/src/platforms/webexbot/commands/space.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/user.d.ts +30 -0
- package/dist/src/platforms/webexbot/commands/user.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/user.js +66 -0
- package/dist/src/platforms/webexbot/commands/user.js.map +1 -0
- package/dist/src/platforms/webexbot/commands/whoami.d.ts +16 -0
- package/dist/src/platforms/webexbot/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/commands/whoami.js +29 -0
- package/dist/src/platforms/webexbot/commands/whoami.js.map +1 -0
- package/dist/src/platforms/webexbot/credential-manager.d.ts +17 -0
- package/dist/src/platforms/webexbot/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/credential-manager.js +120 -0
- package/dist/src/platforms/webexbot/credential-manager.js.map +1 -0
- package/dist/src/platforms/webexbot/index.d.ts +9 -0
- package/dist/src/platforms/webexbot/index.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/index.js +6 -0
- package/dist/src/platforms/webexbot/index.js.map +1 -0
- package/dist/src/platforms/webexbot/listener.d.ts +44 -0
- package/dist/src/platforms/webexbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/listener.js +214 -0
- package/dist/src/platforms/webexbot/listener.js.map +1 -0
- package/dist/src/platforms/webexbot/types.d.ts +60 -0
- package/dist/src/platforms/webexbot/types.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/types.js +28 -0
- package/dist/src/platforms/webexbot/types.js.map +1 -0
- package/dist/src/platforms/webexbot/wdm-discovery.d.ts +4 -0
- package/dist/src/platforms/webexbot/wdm-discovery.d.ts.map +1 -0
- package/dist/src/platforms/webexbot/wdm-discovery.js +36 -0
- package/dist/src/platforms/webexbot/wdm-discovery.js.map +1 -0
- package/docs/content/docs/cli/meta.json +1 -0
- package/docs/content/docs/cli/webexbot.mdx +292 -0
- package/docs/content/docs/sdk/meta.json +1 -0
- package/docs/content/docs/sdk/webexbot.mdx +342 -0
- package/docs/src/app/page.tsx +115 -19
- package/package.json +9 -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-telegrambot/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-webexbot/SKILL.md +414 -0
- package/skills/agent-webexbot/references/authentication.md +225 -0
- package/skills/agent-webexbot/references/common-patterns.md +708 -0
- 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/cli.ts +4 -0
- package/src/platforms/webex/client.test.ts +10 -0
- package/src/platforms/webex/client.ts +97 -3
- package/src/platforms/webex/typings/webex-message-handler.d.ts +360 -29
- package/src/platforms/webexbot/cli.ts +48 -0
- package/src/platforms/webexbot/client.test.ts +198 -0
- package/src/platforms/webexbot/client.ts +113 -0
- package/src/platforms/webexbot/commands/auth.test.ts +185 -0
- package/src/platforms/webexbot/commands/auth.ts +210 -0
- package/src/platforms/webexbot/commands/file.ts +104 -0
- package/src/platforms/webexbot/commands/index.ts +9 -0
- package/src/platforms/webexbot/commands/listen.test.ts +20 -0
- package/src/platforms/webexbot/commands/listen.ts +104 -0
- package/src/platforms/webexbot/commands/member.ts +51 -0
- package/src/platforms/webexbot/commands/message.ts +263 -0
- package/src/platforms/webexbot/commands/shared.ts +22 -0
- package/src/platforms/webexbot/commands/snapshot.ts +60 -0
- package/src/platforms/webexbot/commands/space.ts +88 -0
- package/src/platforms/webexbot/commands/user.test.ts +77 -0
- package/src/platforms/webexbot/commands/user.ts +98 -0
- package/src/platforms/webexbot/commands/whoami.ts +43 -0
- package/src/platforms/webexbot/credential-manager.test.ts +182 -0
- package/src/platforms/webexbot/credential-manager.ts +149 -0
- package/src/platforms/webexbot/index.ts +8 -0
- package/src/platforms/webexbot/listener.test.ts +234 -0
- package/src/platforms/webexbot/listener.ts +255 -0
- package/src/platforms/webexbot/types.test.ts +87 -0
- package/src/platforms/webexbot/types.ts +72 -0
- package/src/platforms/webexbot/wdm-discovery.test.ts +97 -0
- package/src/platforms/webexbot/wdm-discovery.ts +43 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
|
+
|
|
5
|
+
import type { WebexMessage } from '../../webex/types'
|
|
6
|
+
import type { BotOption } from './shared'
|
|
7
|
+
import { getClient } from './shared'
|
|
8
|
+
|
|
9
|
+
interface MessageResult {
|
|
10
|
+
id?: string
|
|
11
|
+
roomId?: string
|
|
12
|
+
text?: string
|
|
13
|
+
markdown?: string
|
|
14
|
+
html?: string
|
|
15
|
+
personEmail?: string
|
|
16
|
+
created?: string
|
|
17
|
+
messages?: Array<{
|
|
18
|
+
id: string
|
|
19
|
+
roomId: string
|
|
20
|
+
text?: string
|
|
21
|
+
personEmail: string
|
|
22
|
+
created: string
|
|
23
|
+
}>
|
|
24
|
+
deleted?: string
|
|
25
|
+
error?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function formatMessage(message: WebexMessage): MessageResult {
|
|
29
|
+
return {
|
|
30
|
+
id: message.id,
|
|
31
|
+
roomId: message.roomId,
|
|
32
|
+
text: message.text,
|
|
33
|
+
markdown: message.markdown,
|
|
34
|
+
html: message.html,
|
|
35
|
+
personEmail: message.personEmail,
|
|
36
|
+
created: message.created,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function sendAction(
|
|
41
|
+
space: string,
|
|
42
|
+
text: string,
|
|
43
|
+
options: BotOption & { markdown?: boolean; parent?: string },
|
|
44
|
+
): Promise<MessageResult> {
|
|
45
|
+
try {
|
|
46
|
+
const client = await getClient(options)
|
|
47
|
+
const message = await client.sendMessage(space, text, { markdown: options.markdown, parentId: options.parent })
|
|
48
|
+
|
|
49
|
+
return formatMessage(message)
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return { error: (error as Error).message }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function replyAction(
|
|
56
|
+
space: string,
|
|
57
|
+
parentId: string,
|
|
58
|
+
text: string,
|
|
59
|
+
options: BotOption & { markdown?: boolean },
|
|
60
|
+
): Promise<MessageResult> {
|
|
61
|
+
try {
|
|
62
|
+
const client = await getClient(options)
|
|
63
|
+
const message = await client.sendMessage(space, text, { markdown: options.markdown, parentId })
|
|
64
|
+
|
|
65
|
+
return formatMessage(message)
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return { error: (error as Error).message }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function repliesAction(
|
|
72
|
+
space: string,
|
|
73
|
+
parentId: string,
|
|
74
|
+
options: BotOption & { max?: string },
|
|
75
|
+
): Promise<MessageResult> {
|
|
76
|
+
try {
|
|
77
|
+
const client = await getClient(options)
|
|
78
|
+
const max = options.max ? parseInt(options.max, 10) : 50
|
|
79
|
+
const messages = await client.listReplies(space, parentId, { max })
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
messages: messages.map((msg) => ({
|
|
83
|
+
id: msg.id,
|
|
84
|
+
roomId: msg.roomId,
|
|
85
|
+
text: msg.text,
|
|
86
|
+
personEmail: msg.personEmail,
|
|
87
|
+
created: msg.created,
|
|
88
|
+
})),
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return { error: (error as Error).message }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function dmAction(
|
|
96
|
+
email: string,
|
|
97
|
+
text: string,
|
|
98
|
+
options: BotOption & { markdown?: boolean },
|
|
99
|
+
): Promise<MessageResult> {
|
|
100
|
+
try {
|
|
101
|
+
const client = await getClient(options)
|
|
102
|
+
const message = await client.sendDirectMessage(email, text, { markdown: options.markdown })
|
|
103
|
+
|
|
104
|
+
return formatMessage(message)
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return { error: (error as Error).message }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function listAction(space: string, options: BotOption & { max?: string }): Promise<MessageResult> {
|
|
111
|
+
try {
|
|
112
|
+
const client = await getClient(options)
|
|
113
|
+
const max = options.max ? parseInt(options.max, 10) : 50
|
|
114
|
+
const messages = await client.listMessages(space, { max })
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
messages: messages.map((msg) => ({
|
|
118
|
+
id: msg.id,
|
|
119
|
+
roomId: msg.roomId,
|
|
120
|
+
text: msg.text,
|
|
121
|
+
personEmail: msg.personEmail,
|
|
122
|
+
created: msg.created,
|
|
123
|
+
})),
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
return { error: (error as Error).message }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function getAction(messageId: string, options: BotOption): Promise<MessageResult> {
|
|
131
|
+
try {
|
|
132
|
+
const client = await getClient(options)
|
|
133
|
+
const message = await client.getMessage(messageId)
|
|
134
|
+
|
|
135
|
+
return formatMessage(message)
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return { error: (error as Error).message }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function deleteAction(messageId: string, options: BotOption): Promise<MessageResult> {
|
|
142
|
+
try {
|
|
143
|
+
const client = await getClient(options)
|
|
144
|
+
await client.deleteMessage(messageId)
|
|
145
|
+
|
|
146
|
+
return { deleted: messageId }
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return { error: (error as Error).message }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function editAction(
|
|
153
|
+
messageId: string,
|
|
154
|
+
space: string,
|
|
155
|
+
text: string,
|
|
156
|
+
options: BotOption & { markdown?: boolean },
|
|
157
|
+
): Promise<MessageResult> {
|
|
158
|
+
try {
|
|
159
|
+
const client = await getClient(options)
|
|
160
|
+
const message = await client.editMessage(messageId, space, text, { markdown: options.markdown })
|
|
161
|
+
|
|
162
|
+
return formatMessage(message)
|
|
163
|
+
} catch (error) {
|
|
164
|
+
return { error: (error as Error).message }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export const messageCommand = new Command('message')
|
|
169
|
+
.description('Message commands')
|
|
170
|
+
.addCommand(
|
|
171
|
+
new Command('send')
|
|
172
|
+
.description('Send a message to a space')
|
|
173
|
+
.argument('<space>', 'Space/Room ID')
|
|
174
|
+
.argument('<text>', 'Message text')
|
|
175
|
+
.option('--markdown', 'Send as markdown')
|
|
176
|
+
.option('--parent <id>', 'Reply within a thread (parent message ID)')
|
|
177
|
+
.option('--bot <id>', 'Use specific bot')
|
|
178
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
179
|
+
.action(async (space: string, text: string, opts: BotOption & { markdown?: boolean; parent?: string }) => {
|
|
180
|
+
cliOutput(await sendAction(space, text, opts), opts.pretty)
|
|
181
|
+
}),
|
|
182
|
+
)
|
|
183
|
+
.addCommand(
|
|
184
|
+
new Command('reply')
|
|
185
|
+
.description('Reply to a message in a thread')
|
|
186
|
+
.argument('<space>', 'Space/Room ID')
|
|
187
|
+
.argument('<parent>', 'Parent message ID')
|
|
188
|
+
.argument('<text>', 'Reply text')
|
|
189
|
+
.option('--markdown', 'Send as markdown')
|
|
190
|
+
.option('--bot <id>', 'Use specific bot')
|
|
191
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
192
|
+
.action(async (space: string, parent: string, text: string, opts: BotOption & { markdown?: boolean }) => {
|
|
193
|
+
cliOutput(await replyAction(space, parent, text, opts), opts.pretty)
|
|
194
|
+
}),
|
|
195
|
+
)
|
|
196
|
+
.addCommand(
|
|
197
|
+
new Command('replies')
|
|
198
|
+
.description('List replies in a thread')
|
|
199
|
+
.argument('<space>', 'Space/Room ID')
|
|
200
|
+
.argument('<parent>', 'Parent message ID')
|
|
201
|
+
.option('--max <n>', 'Number of replies to fetch', '50')
|
|
202
|
+
.option('--bot <id>', 'Use specific bot')
|
|
203
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
204
|
+
.action(async (space: string, parent: string, opts: BotOption & { max?: string }) => {
|
|
205
|
+
cliOutput(await repliesAction(space, parent, opts), opts.pretty)
|
|
206
|
+
}),
|
|
207
|
+
)
|
|
208
|
+
.addCommand(
|
|
209
|
+
new Command('dm')
|
|
210
|
+
.description('Send a direct message by recipient email')
|
|
211
|
+
.argument('<email>', 'Recipient email address')
|
|
212
|
+
.argument('<text>', 'Message text')
|
|
213
|
+
.option('--markdown', 'Send as markdown')
|
|
214
|
+
.option('--bot <id>', 'Use specific bot')
|
|
215
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
216
|
+
.action(async (email: string, text: string, opts: BotOption & { markdown?: boolean }) => {
|
|
217
|
+
cliOutput(await dmAction(email, text, opts), opts.pretty)
|
|
218
|
+
}),
|
|
219
|
+
)
|
|
220
|
+
.addCommand(
|
|
221
|
+
new Command('list')
|
|
222
|
+
.description('List messages in a space')
|
|
223
|
+
.argument('<space>', 'Space/Room ID')
|
|
224
|
+
.option('--max <n>', 'Number of messages to fetch', '50')
|
|
225
|
+
.option('--bot <id>', 'Use specific bot')
|
|
226
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
227
|
+
.action(async (space: string, opts: BotOption & { max?: string }) => {
|
|
228
|
+
cliOutput(await listAction(space, opts), opts.pretty)
|
|
229
|
+
}),
|
|
230
|
+
)
|
|
231
|
+
.addCommand(
|
|
232
|
+
new Command('get')
|
|
233
|
+
.description('Get a single message')
|
|
234
|
+
.argument('<id>', 'Message ID')
|
|
235
|
+
.option('--bot <id>', 'Use specific bot')
|
|
236
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
237
|
+
.action(async (messageId: string, opts: BotOption) => {
|
|
238
|
+
cliOutput(await getAction(messageId, opts), opts.pretty)
|
|
239
|
+
}),
|
|
240
|
+
)
|
|
241
|
+
.addCommand(
|
|
242
|
+
new Command('delete')
|
|
243
|
+
.description('Delete a message')
|
|
244
|
+
.argument('<id>', 'Message ID')
|
|
245
|
+
.option('--bot <id>', 'Use specific bot')
|
|
246
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
247
|
+
.action(async (messageId: string, opts: BotOption) => {
|
|
248
|
+
cliOutput(await deleteAction(messageId, opts), opts.pretty)
|
|
249
|
+
}),
|
|
250
|
+
)
|
|
251
|
+
.addCommand(
|
|
252
|
+
new Command('edit')
|
|
253
|
+
.description('Edit a message')
|
|
254
|
+
.argument('<id>', 'Message ID')
|
|
255
|
+
.argument('<space>', 'Space/Room ID')
|
|
256
|
+
.argument('<text>', 'New message text')
|
|
257
|
+
.option('--markdown', 'Send as markdown')
|
|
258
|
+
.option('--bot <id>', 'Use specific bot')
|
|
259
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
260
|
+
.action(async (messageId: string, space: string, text: string, opts: BotOption & { markdown?: boolean }) => {
|
|
261
|
+
cliOutput(await editAction(messageId, space, text, opts), opts.pretty)
|
|
262
|
+
}),
|
|
263
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { formatOutput } from '@/shared/utils/output'
|
|
2
|
+
|
|
3
|
+
import { WebexBotClient } from '../client'
|
|
4
|
+
import { WebexBotCredentialManager } from '../credential-manager'
|
|
5
|
+
|
|
6
|
+
export interface BotOption {
|
|
7
|
+
bot?: string
|
|
8
|
+
pretty?: boolean
|
|
9
|
+
_credManager?: WebexBotCredentialManager
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function getClient(options: BotOption): Promise<WebexBotClient> {
|
|
13
|
+
const credManager = options._credManager ?? new WebexBotCredentialManager()
|
|
14
|
+
const creds = await credManager.getCredentials(options.bot)
|
|
15
|
+
|
|
16
|
+
if (!creds) {
|
|
17
|
+
console.log(formatOutput({ error: 'No credentials. Run "auth set <token>" first.' }, options.pretty))
|
|
18
|
+
process.exit(1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return new WebexBotClient().login({ token: creds.token })
|
|
22
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
|
+
|
|
5
|
+
import type { BotOption } from './shared'
|
|
6
|
+
import { getClient } from './shared'
|
|
7
|
+
|
|
8
|
+
interface SnapshotResult {
|
|
9
|
+
bot?: {
|
|
10
|
+
id: string
|
|
11
|
+
displayName: string
|
|
12
|
+
emails: string[]
|
|
13
|
+
}
|
|
14
|
+
spaces?: Array<{
|
|
15
|
+
id: string
|
|
16
|
+
title: string
|
|
17
|
+
type?: 'group' | 'direct'
|
|
18
|
+
lastActivity?: string
|
|
19
|
+
}>
|
|
20
|
+
hint?: string
|
|
21
|
+
error?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function snapshotAction(options: BotOption & { full?: boolean; max?: string }): Promise<SnapshotResult> {
|
|
25
|
+
try {
|
|
26
|
+
const client = await getClient(options)
|
|
27
|
+
const max = options.max ? parseInt(options.max, 10) : 100
|
|
28
|
+
|
|
29
|
+
const [me, spaces] = await Promise.all([client.testAuth(), client.listSpaces({ max })])
|
|
30
|
+
|
|
31
|
+
const result: SnapshotResult = {
|
|
32
|
+
bot: {
|
|
33
|
+
id: me.id,
|
|
34
|
+
displayName: me.displayName,
|
|
35
|
+
emails: me.emails,
|
|
36
|
+
},
|
|
37
|
+
spaces: options.full
|
|
38
|
+
? spaces.map((s) => ({ id: s.id, title: s.title, type: s.type, lastActivity: s.lastActivity }))
|
|
39
|
+
: spaces.map((s) => ({ id: s.id, title: s.title })),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!options.full) {
|
|
43
|
+
result.hint = "Use 'message list <space>' for messages, 'space info <space>' for details."
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return result
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return { error: (error as Error).message }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const snapshotCommand = new Command('snapshot')
|
|
53
|
+
.description('Workspace overview for AI agents (brief by default, --full for details)')
|
|
54
|
+
.option('--full', 'Include full space details')
|
|
55
|
+
.option('--max <n>', 'Number of spaces to retrieve', '100')
|
|
56
|
+
.option('--bot <id>', 'Use specific bot')
|
|
57
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
58
|
+
.action(async (opts: BotOption & { full?: boolean; max?: string }) => {
|
|
59
|
+
cliOutput(await snapshotAction(opts), opts.pretty)
|
|
60
|
+
})
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
|
+
|
|
5
|
+
import type { BotOption } from './shared'
|
|
6
|
+
import { getClient } from './shared'
|
|
7
|
+
|
|
8
|
+
interface SpaceResult {
|
|
9
|
+
id?: string
|
|
10
|
+
title?: string
|
|
11
|
+
type?: 'group' | 'direct'
|
|
12
|
+
isLocked?: boolean
|
|
13
|
+
teamId?: string | null
|
|
14
|
+
lastActivity?: string
|
|
15
|
+
created?: string
|
|
16
|
+
creatorId?: string
|
|
17
|
+
spaces?: Array<{
|
|
18
|
+
id: string
|
|
19
|
+
title: string
|
|
20
|
+
type: 'group' | 'direct'
|
|
21
|
+
lastActivity: string
|
|
22
|
+
created: string
|
|
23
|
+
}>
|
|
24
|
+
error?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function listAction(options: BotOption & { max?: string; type?: string }): Promise<SpaceResult> {
|
|
28
|
+
try {
|
|
29
|
+
const client = await getClient(options)
|
|
30
|
+
const max = options.max ? parseInt(options.max, 10) : 50
|
|
31
|
+
const spaces = await client.listSpaces({ type: options.type, max })
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
spaces: spaces.map((s) => ({
|
|
35
|
+
id: s.id,
|
|
36
|
+
title: s.title,
|
|
37
|
+
type: s.type,
|
|
38
|
+
lastActivity: s.lastActivity,
|
|
39
|
+
created: s.created,
|
|
40
|
+
})),
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
return { error: (error as Error).message }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function infoAction(spaceId: string, options: BotOption): Promise<SpaceResult> {
|
|
48
|
+
try {
|
|
49
|
+
const client = await getClient(options)
|
|
50
|
+
const space = await client.getSpace(spaceId)
|
|
51
|
+
return {
|
|
52
|
+
id: space.id,
|
|
53
|
+
title: space.title,
|
|
54
|
+
type: space.type,
|
|
55
|
+
isLocked: space.isLocked,
|
|
56
|
+
teamId: space.teamId || null,
|
|
57
|
+
lastActivity: space.lastActivity,
|
|
58
|
+
created: space.created,
|
|
59
|
+
creatorId: space.creatorId,
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return { error: (error as Error).message }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const spaceCommand = new Command('space')
|
|
67
|
+
.description('Space commands')
|
|
68
|
+
.addCommand(
|
|
69
|
+
new Command('list')
|
|
70
|
+
.description('List spaces')
|
|
71
|
+
.option('--max <n>', 'Number of spaces to retrieve', '50')
|
|
72
|
+
.option('--type <type>', 'Filter by type (group or direct)')
|
|
73
|
+
.option('--bot <id>', 'Use specific bot')
|
|
74
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
75
|
+
.action(async (opts: BotOption & { max?: string; type?: string }) => {
|
|
76
|
+
cliOutput(await listAction(opts), opts.pretty)
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
.addCommand(
|
|
80
|
+
new Command('info')
|
|
81
|
+
.description('Get space details')
|
|
82
|
+
.argument('<id>', 'Space ID')
|
|
83
|
+
.option('--bot <id>', 'Use specific bot')
|
|
84
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
85
|
+
.action(async (spaceId: string, opts: BotOption) => {
|
|
86
|
+
cliOutput(await infoAction(spaceId, opts), opts.pretty)
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test'
|
|
2
|
+
import { existsSync, rmSync } from 'node:fs'
|
|
3
|
+
import { mkdir } from 'node:fs/promises'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import { join } from 'node:path'
|
|
6
|
+
|
|
7
|
+
const mockListPeople = mock(() =>
|
|
8
|
+
Promise.resolve([
|
|
9
|
+
{
|
|
10
|
+
id: 'p1',
|
|
11
|
+
emails: ['alice@example.com'],
|
|
12
|
+
displayName: 'Alice',
|
|
13
|
+
orgId: 'o1',
|
|
14
|
+
type: 'person' as const,
|
|
15
|
+
created: '',
|
|
16
|
+
},
|
|
17
|
+
]),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const mockGetPerson = mock(() =>
|
|
21
|
+
Promise.resolve({
|
|
22
|
+
id: 'p1',
|
|
23
|
+
emails: ['alice@example.com'],
|
|
24
|
+
displayName: 'Alice',
|
|
25
|
+
orgId: 'o1',
|
|
26
|
+
type: 'person' as const,
|
|
27
|
+
created: '2024-01-01T00:00:00Z',
|
|
28
|
+
}),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
mock.module('../client', () => ({
|
|
32
|
+
WebexBotClient: class MockWebexBotClient {
|
|
33
|
+
async login(): Promise<this> {
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
listPeople = mockListPeople
|
|
37
|
+
getPerson = mockGetPerson
|
|
38
|
+
},
|
|
39
|
+
}))
|
|
40
|
+
|
|
41
|
+
import { WebexBotCredentialManager } from '../credential-manager'
|
|
42
|
+
import { infoAction, listAction } from './user'
|
|
43
|
+
|
|
44
|
+
describe('webexbot user commands', () => {
|
|
45
|
+
let tempDir: string
|
|
46
|
+
let manager: WebexBotCredentialManager
|
|
47
|
+
|
|
48
|
+
beforeEach(async () => {
|
|
49
|
+
tempDir = join(tmpdir(), `webexbot-user-test-${Date.now()}`)
|
|
50
|
+
await mkdir(tempDir, { recursive: true })
|
|
51
|
+
manager = new WebexBotCredentialManager(tempDir)
|
|
52
|
+
await manager.setCredentials({ token: 'token123', bot_id: 'bot1', bot_name: 'Bot' })
|
|
53
|
+
mockListPeople.mockClear()
|
|
54
|
+
mockGetPerson.mockClear()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
if (existsSync(tempDir)) {
|
|
59
|
+
rmSync(tempDir, { recursive: true })
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('lists people by email', async () => {
|
|
64
|
+
const result = await listAction({ _credManager: manager, email: 'alice@example.com' })
|
|
65
|
+
|
|
66
|
+
expect(result.users).toHaveLength(1)
|
|
67
|
+
expect(result.users?.[0].displayName).toBe('Alice')
|
|
68
|
+
expect(mockListPeople).toHaveBeenCalled()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('gets a person by id', async () => {
|
|
72
|
+
const result = await infoAction('p1', { _credManager: manager })
|
|
73
|
+
|
|
74
|
+
expect(result.id).toBe('p1')
|
|
75
|
+
expect(result.displayName).toBe('Alice')
|
|
76
|
+
})
|
|
77
|
+
})
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
|
+
|
|
5
|
+
import type { WebexPerson } from '../../webex/types'
|
|
6
|
+
import type { BotOption } from './shared'
|
|
7
|
+
import { getClient } from './shared'
|
|
8
|
+
|
|
9
|
+
interface UserResult {
|
|
10
|
+
id?: string
|
|
11
|
+
emails?: string[]
|
|
12
|
+
displayName?: string
|
|
13
|
+
nickName?: string
|
|
14
|
+
firstName?: string
|
|
15
|
+
lastName?: string
|
|
16
|
+
avatar?: string
|
|
17
|
+
orgId?: string
|
|
18
|
+
type?: 'person' | 'bot'
|
|
19
|
+
created?: string
|
|
20
|
+
users?: Array<{
|
|
21
|
+
id: string
|
|
22
|
+
emails: string[]
|
|
23
|
+
displayName: string
|
|
24
|
+
type: 'person' | 'bot'
|
|
25
|
+
}>
|
|
26
|
+
error?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function formatPerson(person: WebexPerson): UserResult {
|
|
30
|
+
return {
|
|
31
|
+
id: person.id,
|
|
32
|
+
emails: person.emails,
|
|
33
|
+
displayName: person.displayName,
|
|
34
|
+
nickName: person.nickName,
|
|
35
|
+
firstName: person.firstName,
|
|
36
|
+
lastName: person.lastName,
|
|
37
|
+
avatar: person.avatar,
|
|
38
|
+
orgId: person.orgId,
|
|
39
|
+
type: person.type,
|
|
40
|
+
created: person.created,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function listAction(
|
|
45
|
+
options: BotOption & { email?: string; displayName?: string; max?: string },
|
|
46
|
+
): Promise<UserResult> {
|
|
47
|
+
try {
|
|
48
|
+
const client = await getClient(options)
|
|
49
|
+
const max = options.max ? parseInt(options.max, 10) : undefined
|
|
50
|
+
const people = await client.listPeople({ email: options.email, displayName: options.displayName, max })
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
users: people.map((p) => ({
|
|
54
|
+
id: p.id,
|
|
55
|
+
emails: p.emails,
|
|
56
|
+
displayName: p.displayName,
|
|
57
|
+
type: p.type,
|
|
58
|
+
})),
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return { error: (error as Error).message }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function infoAction(personId: string, options: BotOption): Promise<UserResult> {
|
|
66
|
+
try {
|
|
67
|
+
const client = await getClient(options)
|
|
68
|
+
const person = await client.getPerson(personId)
|
|
69
|
+
return formatPerson(person)
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return { error: (error as Error).message }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const userCommand = new Command('user')
|
|
76
|
+
.description('User commands')
|
|
77
|
+
.addCommand(
|
|
78
|
+
new Command('list')
|
|
79
|
+
.description('Search people by email or display name')
|
|
80
|
+
.option('--email <email>', 'Filter by exact email')
|
|
81
|
+
.option('--display-name <name>', 'Filter by display name prefix')
|
|
82
|
+
.option('--max <n>', 'Number of users to retrieve')
|
|
83
|
+
.option('--bot <id>', 'Use specific bot')
|
|
84
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
85
|
+
.action(async (opts: BotOption & { email?: string; displayName?: string; max?: string }) => {
|
|
86
|
+
cliOutput(await listAction(opts), opts.pretty)
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
.addCommand(
|
|
90
|
+
new Command('info')
|
|
91
|
+
.description('Get details for a person')
|
|
92
|
+
.argument('<id>', 'Person ID')
|
|
93
|
+
.option('--bot <id>', 'Use specific bot')
|
|
94
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
95
|
+
.action(async (personId: string, opts: BotOption) => {
|
|
96
|
+
cliOutput(await infoAction(personId, opts), opts.pretty)
|
|
97
|
+
}),
|
|
98
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
|
+
|
|
5
|
+
import type { BotOption } from './shared'
|
|
6
|
+
import { getClient } from './shared'
|
|
7
|
+
|
|
8
|
+
interface WhoamiResult {
|
|
9
|
+
id?: string
|
|
10
|
+
emails?: string[]
|
|
11
|
+
displayName?: string
|
|
12
|
+
avatar?: string
|
|
13
|
+
orgId?: string
|
|
14
|
+
type?: 'person' | 'bot'
|
|
15
|
+
created?: string
|
|
16
|
+
error?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function whoamiAction(options: BotOption): Promise<WhoamiResult> {
|
|
20
|
+
try {
|
|
21
|
+
const client = await getClient(options)
|
|
22
|
+
const info = await client.testAuth()
|
|
23
|
+
return {
|
|
24
|
+
id: info.id,
|
|
25
|
+
emails: info.emails,
|
|
26
|
+
displayName: info.displayName,
|
|
27
|
+
avatar: info.avatar,
|
|
28
|
+
orgId: info.orgId,
|
|
29
|
+
type: info.type,
|
|
30
|
+
created: info.created,
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return { error: (error as Error).message }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const whoamiCommand = new Command('whoami')
|
|
38
|
+
.description('Show current authenticated bot')
|
|
39
|
+
.option('--bot <id>', 'Bot ID to use')
|
|
40
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
41
|
+
.action(async (opts: BotOption) => {
|
|
42
|
+
cliOutput(await whoamiAction(opts), opts.pretty)
|
|
43
|
+
})
|