agent-messenger 2.23.1 → 2.23.3
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/dist/package.json +1 -1
- package/dist/src/platforms/webex/client.d.ts +18 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +202 -49
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +9 -6
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/commands/member.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/member.js +2 -0
- package/dist/src/platforms/webex/commands/member.js.map +1 -1
- package/dist/src/platforms/webex/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/message.js +2 -0
- package/dist/src/platforms/webex/commands/message.js.map +1 -1
- package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/snapshot.js +3 -1
- package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/webex/commands/space.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/space.js +5 -0
- package/dist/src/platforms/webex/commands/space.js.map +1 -1
- package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/whoami.js +2 -0
- package/dist/src/platforms/webex/commands/whoami.js.map +1 -1
- package/dist/src/platforms/webex/id-normalizer.d.ts +11 -0
- package/dist/src/platforms/webex/id-normalizer.d.ts.map +1 -1
- package/dist/src/platforms/webex/id-normalizer.js +102 -20
- package/dist/src/platforms/webex/id-normalizer.js.map +1 -1
- package/dist/src/platforms/webex/index.d.ts +2 -2
- package/dist/src/platforms/webex/index.d.ts.map +1 -1
- package/dist/src/platforms/webex/index.js +1 -1
- package/dist/src/platforms/webex/index.js.map +1 -1
- package/dist/src/platforms/webex/types.d.ts +20 -0
- package/dist/src/platforms/webex/types.d.ts.map +1 -1
- package/dist/src/platforms/webex/types.js +10 -0
- package/dist/src/platforms/webex/types.js.map +1 -1
- package/dist/src/platforms/webexbot/client.d.ts +0 -4
- package/dist/src/platforms/webexbot/client.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/client.js +8 -65
- package/dist/src/platforms/webexbot/client.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/file.d.ts +2 -0
- package/dist/src/platforms/webexbot/commands/file.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/file.js +2 -0
- package/dist/src/platforms/webexbot/commands/file.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/member.d.ts +2 -0
- package/dist/src/platforms/webexbot/commands/member.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/member.js +2 -0
- package/dist/src/platforms/webexbot/commands/member.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/message.d.ts +4 -0
- package/dist/src/platforms/webexbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/message.js +6 -0
- package/dist/src/platforms/webexbot/commands/message.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/snapshot.d.ts +2 -0
- package/dist/src/platforms/webexbot/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/snapshot.js +10 -2
- package/dist/src/platforms/webexbot/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/space.d.ts +4 -0
- package/dist/src/platforms/webexbot/commands/space.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/space.js +5 -0
- package/dist/src/platforms/webexbot/commands/space.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/user.d.ts +3 -0
- package/dist/src/platforms/webexbot/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/user.js +3 -0
- package/dist/src/platforms/webexbot/commands/user.js.map +1 -1
- package/dist/src/platforms/webexbot/commands/whoami.d.ts +2 -0
- package/dist/src/platforms/webexbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/commands/whoami.js +2 -0
- package/dist/src/platforms/webexbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/webexbot/index.d.ts +2 -2
- package/dist/src/platforms/webexbot/index.d.ts.map +1 -1
- package/dist/src/platforms/webexbot/index.js +1 -1
- package/dist/src/platforms/webexbot/index.js.map +1 -1
- package/dist/src/tui/adapters/types.d.ts +3 -0
- package/dist/src/tui/adapters/types.d.ts.map +1 -1
- package/dist/src/tui/adapters/webex-adapter.d.ts.map +1 -1
- package/dist/src/tui/adapters/webex-adapter.js +4 -0
- package/dist/src/tui/adapters/webex-adapter.js.map +1 -1
- package/docs/content/docs/cli/webex.mdx +2 -2
- 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-telegrambot/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +3 -3
- package/skills/agent-webexbot/SKILL.md +2 -2
- package/skills/agent-webexbot/references/common-patterns.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/webex/client.test.ts +94 -6
- package/src/platforms/webex/client.ts +226 -44
- package/src/platforms/webex/commands/auth.test.ts +3 -1
- package/src/platforms/webex/commands/auth.ts +12 -7
- package/src/platforms/webex/commands/member.test.ts +24 -8
- package/src/platforms/webex/commands/member.ts +2 -0
- package/src/platforms/webex/commands/message.test.ts +37 -23
- package/src/platforms/webex/commands/message.ts +2 -0
- package/src/platforms/webex/commands/snapshot.test.ts +18 -10
- package/src/platforms/webex/commands/snapshot.ts +3 -1
- package/src/platforms/webex/commands/space.test.ts +36 -17
- package/src/platforms/webex/commands/space.ts +5 -0
- package/src/platforms/webex/commands/whoami.test.ts +16 -6
- package/src/platforms/webex/commands/whoami.ts +2 -0
- package/src/platforms/webex/id-normalizer.test.ts +282 -2
- package/src/platforms/webex/id-normalizer.ts +112 -20
- package/src/platforms/webex/index.ts +2 -2
- package/src/platforms/webex/listener.test.ts +3 -0
- package/src/platforms/webex/types.test.ts +20 -0
- package/src/platforms/webex/types.ts +20 -0
- package/src/platforms/webex/typings/webex-message-handler.d.ts +40 -2
- package/src/platforms/webexbot/client.ts +8 -74
- package/src/platforms/webexbot/commands/file.ts +4 -0
- package/src/platforms/webexbot/commands/member.ts +4 -0
- package/src/platforms/webexbot/commands/message.ts +10 -0
- package/src/platforms/webexbot/commands/snapshot.ts +12 -2
- package/src/platforms/webexbot/commands/space.ts +9 -0
- package/src/platforms/webexbot/commands/user.test.ts +15 -5
- package/src/platforms/webexbot/commands/user.ts +6 -0
- package/src/platforms/webexbot/commands/whoami.ts +4 -0
- package/src/platforms/webexbot/index.ts +2 -2
- package/src/tui/adapters/types.ts +3 -0
- package/src/tui/adapters/webex-adapter.ts +4 -0
|
@@ -13,21 +13,27 @@ export interface WebexSpace {
|
|
|
13
13
|
|
|
14
14
|
export interface WebexMessage {
|
|
15
15
|
id: string
|
|
16
|
+
ref: string
|
|
16
17
|
roomId: string
|
|
18
|
+
roomRef: string
|
|
17
19
|
roomType: 'group' | 'direct'
|
|
18
20
|
text?: string
|
|
19
21
|
markdown?: string
|
|
20
22
|
html?: string
|
|
21
23
|
files?: string[]
|
|
22
24
|
personId: string
|
|
25
|
+
personRef: string
|
|
23
26
|
personEmail: string
|
|
24
27
|
created: string
|
|
25
28
|
parentId?: string
|
|
29
|
+
parentRef?: string
|
|
26
30
|
mentionedPeople?: string[]
|
|
31
|
+
mentionedPeopleRefs?: string[]
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
export interface WebexPerson {
|
|
30
35
|
id: string
|
|
36
|
+
ref: string
|
|
31
37
|
emails: string[]
|
|
32
38
|
displayName: string
|
|
33
39
|
nickName?: string
|
|
@@ -35,14 +41,18 @@ export interface WebexPerson {
|
|
|
35
41
|
lastName?: string
|
|
36
42
|
avatar?: string
|
|
37
43
|
orgId: string
|
|
44
|
+
orgRef: string
|
|
38
45
|
type: 'person' | 'bot'
|
|
39
46
|
created: string
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
export interface WebexMembership {
|
|
43
50
|
id: string
|
|
51
|
+
ref: string
|
|
44
52
|
roomId: string
|
|
53
|
+
roomRef: string
|
|
45
54
|
personId: string
|
|
55
|
+
personRef: string
|
|
46
56
|
personEmail: string
|
|
47
57
|
personDisplayName: string
|
|
48
58
|
isModerator: boolean
|
|
@@ -84,21 +94,27 @@ export const WebexSpaceSchema = z.object({
|
|
|
84
94
|
|
|
85
95
|
export const WebexMessageSchema = z.object({
|
|
86
96
|
id: z.string(),
|
|
97
|
+
ref: z.string(),
|
|
87
98
|
roomId: z.string(),
|
|
99
|
+
roomRef: z.string(),
|
|
88
100
|
roomType: z.enum(['group', 'direct']),
|
|
89
101
|
text: z.string().optional(),
|
|
90
102
|
markdown: z.string().optional(),
|
|
91
103
|
html: z.string().optional(),
|
|
92
104
|
files: z.array(z.string()).optional(),
|
|
93
105
|
personId: z.string(),
|
|
106
|
+
personRef: z.string(),
|
|
94
107
|
personEmail: z.string(),
|
|
95
108
|
created: z.string(),
|
|
96
109
|
parentId: z.string().optional(),
|
|
110
|
+
parentRef: z.string().optional(),
|
|
97
111
|
mentionedPeople: z.array(z.string()).optional(),
|
|
112
|
+
mentionedPeopleRefs: z.array(z.string()).optional(),
|
|
98
113
|
})
|
|
99
114
|
|
|
100
115
|
export const WebexPersonSchema = z.object({
|
|
101
116
|
id: z.string(),
|
|
117
|
+
ref: z.string(),
|
|
102
118
|
emails: z.array(z.string()),
|
|
103
119
|
displayName: z.string(),
|
|
104
120
|
nickName: z.string().optional(),
|
|
@@ -106,14 +122,18 @@ export const WebexPersonSchema = z.object({
|
|
|
106
122
|
lastName: z.string().optional(),
|
|
107
123
|
avatar: z.string().optional(),
|
|
108
124
|
orgId: z.string(),
|
|
125
|
+
orgRef: z.string(),
|
|
109
126
|
type: z.enum(['person', 'bot']),
|
|
110
127
|
created: z.string(),
|
|
111
128
|
})
|
|
112
129
|
|
|
113
130
|
export const WebexMembershipSchema = z.object({
|
|
114
131
|
id: z.string(),
|
|
132
|
+
ref: z.string(),
|
|
115
133
|
roomId: z.string(),
|
|
134
|
+
roomRef: z.string(),
|
|
116
135
|
personId: z.string(),
|
|
136
|
+
personRef: z.string(),
|
|
117
137
|
personEmail: z.string(),
|
|
118
138
|
personDisplayName: z.string(),
|
|
119
139
|
isModerator: z.boolean(),
|
|
@@ -155,6 +155,8 @@ declare module 'webex-message-handler' {
|
|
|
155
155
|
export interface DecryptedMessage {
|
|
156
156
|
/** Mercury activity UUID. Works as parentId for threaded replies. */
|
|
157
157
|
id: string
|
|
158
|
+
/** Raw UUID ref for `id`. */
|
|
159
|
+
ref: string
|
|
158
160
|
/**
|
|
159
161
|
* Full Conversation-service activity URL, when present on the raw Mercury
|
|
160
162
|
* activity (e.g. for an outbound "acknowledge" read-receipt). Undefined if
|
|
@@ -163,8 +165,14 @@ declare module 'webex-message-handler' {
|
|
|
163
165
|
url?: string
|
|
164
166
|
/** Parent activity UUID for threaded replies. Undefined if not a thread reply. */
|
|
165
167
|
parentId?: string
|
|
168
|
+
/** Raw UUID ref for `parentId`. Undefined when `parentId` is absent. */
|
|
169
|
+
parentRef?: string
|
|
166
170
|
roomId: string
|
|
171
|
+
/** Raw UUID ref for `roomId`. */
|
|
172
|
+
roomRef: string
|
|
167
173
|
personId: string
|
|
174
|
+
/** Raw UUID ref for `personId`. */
|
|
175
|
+
personRef: string
|
|
168
176
|
personEmail: string
|
|
169
177
|
text: string
|
|
170
178
|
html?: string
|
|
@@ -172,6 +180,8 @@ declare module 'webex-message-handler' {
|
|
|
172
180
|
roomType?: string
|
|
173
181
|
/** Person UUIDs mentioned via @mention in the message. */
|
|
174
182
|
mentionedPeople: string[]
|
|
183
|
+
/** Raw UUID refs for `mentionedPeople`, index-aligned. */
|
|
184
|
+
mentionedPeopleRefs: string[]
|
|
175
185
|
/** Group mention types (e.g. "all") in the message. */
|
|
176
186
|
mentionedGroups: string[]
|
|
177
187
|
/** File URLs attached to the message. Empty if no files. */
|
|
@@ -181,19 +191,33 @@ declare module 'webex-message-handler' {
|
|
|
181
191
|
|
|
182
192
|
export interface DeletedMessage {
|
|
183
193
|
messageId: string
|
|
194
|
+
/** Raw UUID ref for `messageId`. */
|
|
195
|
+
messageRef: string
|
|
184
196
|
roomId: string
|
|
197
|
+
/** Raw UUID ref for `roomId`. */
|
|
198
|
+
roomRef: string
|
|
185
199
|
personId: string
|
|
200
|
+
/** Raw UUID ref for `personId`. */
|
|
201
|
+
personRef: string
|
|
186
202
|
}
|
|
187
203
|
|
|
188
204
|
export interface MembershipActivity {
|
|
189
|
-
/** Activity ID. */
|
|
205
|
+
/** Activity ID (raw Mercury activity UUID). */
|
|
190
206
|
id: string
|
|
207
|
+
/** Raw UUID ref for `id`. Equal to `id` since the activity id is already raw. */
|
|
208
|
+
ref: string
|
|
191
209
|
/** ID of the person who performed the action. */
|
|
192
210
|
actorId: string
|
|
211
|
+
/** Raw UUID ref for `actorId`. */
|
|
212
|
+
actorRef: string
|
|
193
213
|
/** ID of the member affected. */
|
|
194
214
|
personId: string
|
|
215
|
+
/** Raw UUID ref for `personId`. */
|
|
216
|
+
personRef: string
|
|
195
217
|
/** Conversation/space ID. */
|
|
196
218
|
roomId: string
|
|
219
|
+
/** Raw UUID ref for `roomId`. */
|
|
220
|
+
roomRef: string
|
|
197
221
|
/** Membership action: "add", "leave", "assignModerator", or "unassignModerator". */
|
|
198
222
|
action: string
|
|
199
223
|
/** ISO 8601 timestamp. */
|
|
@@ -207,14 +231,22 @@ declare module 'webex-message-handler' {
|
|
|
207
231
|
export interface AttachmentAction {
|
|
208
232
|
/** Activity ID. */
|
|
209
233
|
id: string
|
|
234
|
+
/** Raw UUID ref for `id`. */
|
|
235
|
+
ref: string
|
|
210
236
|
/** ID of the message the card was attached to. */
|
|
211
237
|
messageId: string
|
|
238
|
+
/** Raw UUID ref for `messageId`. Empty when `messageId` is empty. */
|
|
239
|
+
messageRef: string
|
|
212
240
|
/** ID of the person who submitted the card. */
|
|
213
241
|
personId: string
|
|
242
|
+
/** Raw UUID ref for `personId`. */
|
|
243
|
+
personRef: string
|
|
214
244
|
/** Email of the person who submitted the card. */
|
|
215
245
|
personEmail: string
|
|
216
246
|
/** Conversation/space ID. */
|
|
217
247
|
roomId: string
|
|
248
|
+
/** Raw UUID ref for `roomId`. */
|
|
249
|
+
roomRef: string
|
|
218
250
|
/** Card form input values. */
|
|
219
251
|
inputs: Record<string, unknown>
|
|
220
252
|
/** ISO 8601 timestamp. */
|
|
@@ -224,12 +256,18 @@ declare module 'webex-message-handler' {
|
|
|
224
256
|
}
|
|
225
257
|
|
|
226
258
|
export interface RoomActivity {
|
|
227
|
-
/** Activity ID. */
|
|
259
|
+
/** Activity ID (raw Mercury activity UUID). */
|
|
228
260
|
id: string
|
|
261
|
+
/** Raw UUID ref for `id`. Equal to `id` since the activity id is already raw. */
|
|
262
|
+
ref: string
|
|
229
263
|
/** Conversation/space ID. */
|
|
230
264
|
roomId: string
|
|
265
|
+
/** Raw UUID ref for `roomId`. */
|
|
266
|
+
roomRef: string
|
|
231
267
|
/** ID of the person who performed the action. */
|
|
232
268
|
actorId: string
|
|
269
|
+
/** Raw UUID ref for `actorId`. */
|
|
270
|
+
actorRef: string
|
|
233
271
|
/** Room action: "created" or "updated". */
|
|
234
272
|
action: string
|
|
235
273
|
/** ISO 8601 timestamp. */
|
|
@@ -2,33 +2,10 @@ import { WebexClient } from '../webex/client'
|
|
|
2
2
|
import type { WebexMembership, WebexMessage, WebexPerson, WebexSpace } from '../webex/types'
|
|
3
3
|
import { WebexBotError } from './types'
|
|
4
4
|
|
|
5
|
-
interface DecodedWebexId {
|
|
6
|
-
cluster: string
|
|
7
|
-
type: string
|
|
8
|
-
uuid: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// Webex REST ids are base64(url) of `ciscospark://<cluster>/<TYPE>/<uuid>`; the
|
|
12
|
-
// cluster correction needs all three parts, not just the <uuid> `fromRestId` returns.
|
|
13
|
-
function decodeWebexId(restId: string): DecodedWebexId | null {
|
|
14
|
-
if (!restId) return null
|
|
15
|
-
const decoded = Buffer.from(restId, 'base64').toString('utf-8')
|
|
16
|
-
const match = decoded.match(/^ciscospark:\/\/([^/]+)\/([^/]+)\/(.+)$/)
|
|
17
|
-
if (!match) return null
|
|
18
|
-
return { cluster: match[1], type: match[2], uuid: match[3] }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
5
|
export class WebexBotClient {
|
|
22
|
-
private client = new WebexClient()
|
|
6
|
+
private client = new WebexClient({ roomResolutionWarningPrefix: '[webexbot]' })
|
|
23
7
|
private token: string | null = null
|
|
24
8
|
|
|
25
|
-
// The listener flattens room ids to `ciscospark://us/ROOM/<uuid>`, but team/group
|
|
26
|
-
// rooms live on `ciscospark://urn:TEAM:<cluster>/ROOM/<uuid>` — a cluster the bare
|
|
27
|
-
// uuid cannot recover. Cache the real clustered id per uuid and dedupe concurrent
|
|
28
|
-
// lookups so a burst of calls triggers a single `listSpaces`.
|
|
29
|
-
private clusteredRoomIds = new Map<string, string>()
|
|
30
|
-
private roomIdLookups = new Map<string, Promise<string>>()
|
|
31
|
-
|
|
32
9
|
async login(credentials?: { token: string }): Promise<this> {
|
|
33
10
|
if (credentials) {
|
|
34
11
|
if (!credentials.token) {
|
|
@@ -64,7 +41,7 @@ export class WebexBotClient {
|
|
|
64
41
|
}
|
|
65
42
|
|
|
66
43
|
async getSpace(spaceId: string): Promise<WebexSpace> {
|
|
67
|
-
return this.client.getSpace(
|
|
44
|
+
return this.client.getSpace(spaceId)
|
|
68
45
|
}
|
|
69
46
|
|
|
70
47
|
async sendMessage(
|
|
@@ -72,7 +49,7 @@ export class WebexBotClient {
|
|
|
72
49
|
text: string,
|
|
73
50
|
options?: { markdown?: boolean; parentId?: string; files?: string[] },
|
|
74
51
|
): Promise<WebexMessage> {
|
|
75
|
-
return this.client.sendMessage(
|
|
52
|
+
return this.client.sendMessage(roomId, text, options)
|
|
76
53
|
}
|
|
77
54
|
|
|
78
55
|
async sendDirectMessage(personEmail: string, text: string, options?: { markdown?: boolean }): Promise<WebexMessage> {
|
|
@@ -80,14 +57,14 @@ export class WebexBotClient {
|
|
|
80
57
|
}
|
|
81
58
|
|
|
82
59
|
async listMessages(roomId: string, options?: { max?: number; parentId?: string }): Promise<WebexMessage[]> {
|
|
83
|
-
const resolvedRoomId = await this.resolveRoomId(roomId)
|
|
60
|
+
const resolvedRoomId = await this.client.resolveRoomId(roomId)
|
|
84
61
|
const space = await this.client.getSpace(resolvedRoomId)
|
|
85
62
|
const messageOptions = space.type === 'group' ? { ...options, mentionedPeople: 'me' } : options
|
|
86
63
|
return this.client.listMessages(resolvedRoomId, messageOptions)
|
|
87
64
|
}
|
|
88
65
|
|
|
89
66
|
async listReplies(roomId: string, parentId: string, options?: { max?: number }): Promise<WebexMessage[]> {
|
|
90
|
-
return this.client.listMessages(
|
|
67
|
+
return this.client.listMessages(roomId, { ...options, parentId })
|
|
91
68
|
}
|
|
92
69
|
|
|
93
70
|
async getMessage(messageId: string): Promise<WebexMessage> {
|
|
@@ -108,7 +85,7 @@ export class WebexBotClient {
|
|
|
108
85
|
text: string,
|
|
109
86
|
options?: { markdown?: boolean },
|
|
110
87
|
): Promise<WebexMessage> {
|
|
111
|
-
return this.client.editMessage(messageId,
|
|
88
|
+
return this.client.editMessage(messageId, roomId, text, options)
|
|
112
89
|
}
|
|
113
90
|
|
|
114
91
|
async listPeople(options?: { email?: string; displayName?: string; max?: number }): Promise<WebexPerson[]> {
|
|
@@ -124,7 +101,7 @@ export class WebexBotClient {
|
|
|
124
101
|
}
|
|
125
102
|
|
|
126
103
|
async listMemberships(roomId: string, options?: { max?: number }): Promise<WebexMembership[]> {
|
|
127
|
-
return this.client.listMemberships(
|
|
104
|
+
return this.client.listMemberships(roomId, options)
|
|
128
105
|
}
|
|
129
106
|
|
|
130
107
|
async uploadFile(
|
|
@@ -132,53 +109,10 @@ export class WebexBotClient {
|
|
|
132
109
|
file: { content: Blob; filename: string },
|
|
133
110
|
options?: { text?: string; markdown?: boolean; parentId?: string },
|
|
134
111
|
): Promise<WebexMessage> {
|
|
135
|
-
return this.client.uploadFile(
|
|
112
|
+
return this.client.uploadFile(roomId, file, options)
|
|
136
113
|
}
|
|
137
114
|
|
|
138
115
|
async downloadContent(contentRef: string): Promise<{ data: ArrayBuffer; filename: string; contentType: string }> {
|
|
139
116
|
return this.client.downloadContent(contentRef)
|
|
140
117
|
}
|
|
141
|
-
|
|
142
|
-
private async resolveRoomId(roomId: string): Promise<string> {
|
|
143
|
-
const decoded = decodeWebexId(roomId)
|
|
144
|
-
// Already cluster-qualified or undecodable: nothing to correct.
|
|
145
|
-
if (!decoded || decoded.cluster.startsWith('urn:')) return roomId
|
|
146
|
-
|
|
147
|
-
const { uuid } = decoded
|
|
148
|
-
const cached = this.clusteredRoomIds.get(uuid)
|
|
149
|
-
if (cached) return cached
|
|
150
|
-
|
|
151
|
-
const inFlight = this.roomIdLookups.get(uuid)
|
|
152
|
-
if (inFlight) return inFlight
|
|
153
|
-
|
|
154
|
-
const lookup = this.lookupRoomId(uuid, roomId)
|
|
155
|
-
this.roomIdLookups.set(uuid, lookup)
|
|
156
|
-
try {
|
|
157
|
-
return await lookup
|
|
158
|
-
} finally {
|
|
159
|
-
this.roomIdLookups.delete(uuid)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private async lookupRoomId(uuid: string, fallback: string): Promise<string> {
|
|
164
|
-
try {
|
|
165
|
-
// Page through every room the bot belongs to (largest page size, following
|
|
166
|
-
// `Link` pages), stopping as soon as the trailing UUID matches.
|
|
167
|
-
for await (const room of this.client.iterateSpaces({ max: 1000 })) {
|
|
168
|
-
if (decodeWebexId(room.id)?.uuid === uuid) {
|
|
169
|
-
this.clusteredRoomIds.set(uuid, room.id)
|
|
170
|
-
return room.id
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
} catch {
|
|
174
|
-
// Network/auth failure: fail open to the un-corrected id rather than block the call.
|
|
175
|
-
return fallback
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
console.warn(
|
|
179
|
-
`[webexbot] Could not resolve clustered room id for ${uuid}; falling back to the un-clustered id. ` +
|
|
180
|
-
'Room-scoped calls may fail if this room lives on a non-default Webex cluster.',
|
|
181
|
-
)
|
|
182
|
-
return fallback
|
|
183
|
-
}
|
|
184
118
|
}
|
|
@@ -10,7 +10,9 @@ import { getClient } from './shared'
|
|
|
10
10
|
|
|
11
11
|
interface FileResult {
|
|
12
12
|
id?: string
|
|
13
|
+
ref?: string
|
|
13
14
|
roomId?: string
|
|
15
|
+
roomRef?: string
|
|
14
16
|
files?: string[]
|
|
15
17
|
created?: string
|
|
16
18
|
downloaded?: string
|
|
@@ -37,7 +39,9 @@ export async function uploadAction(
|
|
|
37
39
|
|
|
38
40
|
return {
|
|
39
41
|
id: message.id,
|
|
42
|
+
ref: message.ref,
|
|
40
43
|
roomId: message.roomId,
|
|
44
|
+
roomRef: message.roomRef,
|
|
41
45
|
files: message.files,
|
|
42
46
|
created: message.created,
|
|
43
47
|
}
|
|
@@ -8,7 +8,9 @@ import { getClient } from './shared'
|
|
|
8
8
|
interface MemberResult {
|
|
9
9
|
members?: Array<{
|
|
10
10
|
id: string
|
|
11
|
+
ref: string
|
|
11
12
|
personId: string
|
|
13
|
+
personRef: string
|
|
12
14
|
personEmail: string
|
|
13
15
|
personDisplayName: string
|
|
14
16
|
isModerator: boolean
|
|
@@ -26,7 +28,9 @@ export async function listAction(space: string, options: BotOption & { max?: str
|
|
|
26
28
|
return {
|
|
27
29
|
members: members.map((m) => ({
|
|
28
30
|
id: m.id,
|
|
31
|
+
ref: m.ref,
|
|
29
32
|
personId: m.personId,
|
|
33
|
+
personRef: m.personRef,
|
|
30
34
|
personEmail: m.personEmail,
|
|
31
35
|
personDisplayName: m.personDisplayName,
|
|
32
36
|
isModerator: m.isModerator,
|
|
@@ -8,7 +8,9 @@ import { getClient } from './shared'
|
|
|
8
8
|
|
|
9
9
|
interface MessageResult {
|
|
10
10
|
id?: string
|
|
11
|
+
ref?: string
|
|
11
12
|
roomId?: string
|
|
13
|
+
roomRef?: string
|
|
12
14
|
text?: string
|
|
13
15
|
markdown?: string
|
|
14
16
|
html?: string
|
|
@@ -16,7 +18,9 @@ interface MessageResult {
|
|
|
16
18
|
created?: string
|
|
17
19
|
messages?: Array<{
|
|
18
20
|
id: string
|
|
21
|
+
ref: string
|
|
19
22
|
roomId: string
|
|
23
|
+
roomRef: string
|
|
20
24
|
text?: string
|
|
21
25
|
personEmail: string
|
|
22
26
|
created: string
|
|
@@ -28,7 +32,9 @@ interface MessageResult {
|
|
|
28
32
|
function formatMessage(message: WebexMessage): MessageResult {
|
|
29
33
|
return {
|
|
30
34
|
id: message.id,
|
|
35
|
+
ref: message.ref,
|
|
31
36
|
roomId: message.roomId,
|
|
37
|
+
roomRef: message.roomRef,
|
|
32
38
|
text: message.text,
|
|
33
39
|
markdown: message.markdown,
|
|
34
40
|
html: message.html,
|
|
@@ -81,7 +87,9 @@ export async function repliesAction(
|
|
|
81
87
|
return {
|
|
82
88
|
messages: messages.map((msg) => ({
|
|
83
89
|
id: msg.id,
|
|
90
|
+
ref: msg.ref,
|
|
84
91
|
roomId: msg.roomId,
|
|
92
|
+
roomRef: msg.roomRef,
|
|
85
93
|
text: msg.text,
|
|
86
94
|
personEmail: msg.personEmail,
|
|
87
95
|
created: msg.created,
|
|
@@ -116,7 +124,9 @@ export async function listAction(space: string, options: BotOption & { max?: str
|
|
|
116
124
|
return {
|
|
117
125
|
messages: messages.map((msg) => ({
|
|
118
126
|
id: msg.id,
|
|
127
|
+
ref: msg.ref,
|
|
119
128
|
roomId: msg.roomId,
|
|
129
|
+
roomRef: msg.roomRef,
|
|
120
130
|
text: msg.text,
|
|
121
131
|
personEmail: msg.personEmail,
|
|
122
132
|
created: msg.created,
|
|
@@ -2,17 +2,20 @@ import { Command } from 'commander'
|
|
|
2
2
|
|
|
3
3
|
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
4
|
|
|
5
|
+
import { toRef } from '../../webex/id-normalizer'
|
|
5
6
|
import type { BotOption } from './shared'
|
|
6
7
|
import { getClient } from './shared'
|
|
7
8
|
|
|
8
9
|
interface SnapshotResult {
|
|
9
10
|
bot?: {
|
|
10
11
|
id: string
|
|
12
|
+
ref: string
|
|
11
13
|
displayName: string
|
|
12
14
|
emails: string[]
|
|
13
15
|
}
|
|
14
16
|
spaces?: Array<{
|
|
15
17
|
id: string
|
|
18
|
+
ref: string
|
|
16
19
|
title: string
|
|
17
20
|
type?: 'group' | 'direct'
|
|
18
21
|
lastActivity?: string
|
|
@@ -31,12 +34,19 @@ export async function snapshotAction(options: BotOption & { full?: boolean; max?
|
|
|
31
34
|
const result: SnapshotResult = {
|
|
32
35
|
bot: {
|
|
33
36
|
id: me.id,
|
|
37
|
+
ref: me.ref,
|
|
34
38
|
displayName: me.displayName,
|
|
35
39
|
emails: me.emails,
|
|
36
40
|
},
|
|
37
41
|
spaces: options.full
|
|
38
|
-
? spaces.map((s) => ({
|
|
39
|
-
|
|
42
|
+
? spaces.map((s) => ({
|
|
43
|
+
id: s.id,
|
|
44
|
+
ref: toRef(s.id),
|
|
45
|
+
title: s.title,
|
|
46
|
+
type: s.type,
|
|
47
|
+
lastActivity: s.lastActivity,
|
|
48
|
+
}))
|
|
49
|
+
: spaces.map((s) => ({ id: s.id, ref: toRef(s.id), title: s.title })),
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
if (!options.full) {
|
|
@@ -2,20 +2,25 @@ import { Command } from 'commander'
|
|
|
2
2
|
|
|
3
3
|
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
4
|
|
|
5
|
+
import { toRef } from '../../webex/id-normalizer'
|
|
5
6
|
import type { BotOption } from './shared'
|
|
6
7
|
import { getClient } from './shared'
|
|
7
8
|
|
|
8
9
|
interface SpaceResult {
|
|
9
10
|
id?: string
|
|
11
|
+
ref?: string
|
|
10
12
|
title?: string
|
|
11
13
|
type?: 'group' | 'direct'
|
|
12
14
|
isLocked?: boolean
|
|
13
15
|
teamId?: string | null
|
|
16
|
+
teamRef?: string | null
|
|
14
17
|
lastActivity?: string
|
|
15
18
|
created?: string
|
|
16
19
|
creatorId?: string
|
|
20
|
+
creatorRef?: string
|
|
17
21
|
spaces?: Array<{
|
|
18
22
|
id: string
|
|
23
|
+
ref: string
|
|
19
24
|
title: string
|
|
20
25
|
type: 'group' | 'direct'
|
|
21
26
|
lastActivity: string
|
|
@@ -33,6 +38,7 @@ export async function listAction(options: BotOption & { max?: string; type?: str
|
|
|
33
38
|
return {
|
|
34
39
|
spaces: spaces.map((s) => ({
|
|
35
40
|
id: s.id,
|
|
41
|
+
ref: toRef(s.id),
|
|
36
42
|
title: s.title,
|
|
37
43
|
type: s.type,
|
|
38
44
|
lastActivity: s.lastActivity,
|
|
@@ -50,13 +56,16 @@ export async function infoAction(spaceId: string, options: BotOption): Promise<S
|
|
|
50
56
|
const space = await client.getSpace(spaceId)
|
|
51
57
|
return {
|
|
52
58
|
id: space.id,
|
|
59
|
+
ref: toRef(space.id),
|
|
53
60
|
title: space.title,
|
|
54
61
|
type: space.type,
|
|
55
62
|
isLocked: space.isLocked,
|
|
56
63
|
teamId: space.teamId || null,
|
|
64
|
+
teamRef: space.teamId ? toRef(space.teamId) : null,
|
|
57
65
|
lastActivity: space.lastActivity,
|
|
58
66
|
created: space.created,
|
|
59
67
|
creatorId: space.creatorId,
|
|
68
|
+
creatorRef: toRef(space.creatorId),
|
|
60
69
|
}
|
|
61
70
|
} catch (error) {
|
|
62
71
|
return { error: (error as Error).message }
|
|
@@ -4,13 +4,19 @@ import { mkdir } from 'node:fs/promises'
|
|
|
4
4
|
import { tmpdir } from 'node:os'
|
|
5
5
|
import { join } from 'node:path'
|
|
6
6
|
|
|
7
|
+
const restId = (type: string, ref: string) => Buffer.from(`ciscospark://us/${type}/${ref}`).toString('base64url')
|
|
8
|
+
const personId = restId('PEOPLE', 'p1')
|
|
9
|
+
const orgId = restId('ORGANIZATION', 'o1')
|
|
10
|
+
|
|
7
11
|
const mockListPeople = mock(() =>
|
|
8
12
|
Promise.resolve([
|
|
9
13
|
{
|
|
10
|
-
id:
|
|
14
|
+
id: personId,
|
|
15
|
+
ref: 'p1',
|
|
11
16
|
emails: ['alice@example.com'],
|
|
12
17
|
displayName: 'Alice',
|
|
13
|
-
orgId
|
|
18
|
+
orgId,
|
|
19
|
+
orgRef: 'o1',
|
|
14
20
|
type: 'person' as const,
|
|
15
21
|
created: '',
|
|
16
22
|
},
|
|
@@ -19,10 +25,12 @@ const mockListPeople = mock(() =>
|
|
|
19
25
|
|
|
20
26
|
const mockGetPerson = mock(() =>
|
|
21
27
|
Promise.resolve({
|
|
22
|
-
id:
|
|
28
|
+
id: personId,
|
|
29
|
+
ref: 'p1',
|
|
23
30
|
emails: ['alice@example.com'],
|
|
24
31
|
displayName: 'Alice',
|
|
25
|
-
orgId
|
|
32
|
+
orgId,
|
|
33
|
+
orgRef: 'o1',
|
|
26
34
|
type: 'person' as const,
|
|
27
35
|
created: '2024-01-01T00:00:00Z',
|
|
28
36
|
}),
|
|
@@ -65,13 +73,15 @@ describe('webexbot user commands', () => {
|
|
|
65
73
|
|
|
66
74
|
expect(result.users).toHaveLength(1)
|
|
67
75
|
expect(result.users?.[0].displayName).toBe('Alice')
|
|
76
|
+
expect(result.users?.[0].ref).toBe('p1')
|
|
68
77
|
expect(mockListPeople).toHaveBeenCalled()
|
|
69
78
|
})
|
|
70
79
|
|
|
71
80
|
it('gets a person by id', async () => {
|
|
72
81
|
const result = await infoAction('p1', { _credManager: manager })
|
|
73
82
|
|
|
74
|
-
expect(result.id).toBe(
|
|
83
|
+
expect(result.id).toBe(personId)
|
|
84
|
+
expect(result.ref).toBe('p1')
|
|
75
85
|
expect(result.displayName).toBe('Alice')
|
|
76
86
|
})
|
|
77
87
|
})
|
|
@@ -8,6 +8,7 @@ import { getClient } from './shared'
|
|
|
8
8
|
|
|
9
9
|
interface UserResult {
|
|
10
10
|
id?: string
|
|
11
|
+
ref?: string
|
|
11
12
|
emails?: string[]
|
|
12
13
|
displayName?: string
|
|
13
14
|
nickName?: string
|
|
@@ -15,10 +16,12 @@ interface UserResult {
|
|
|
15
16
|
lastName?: string
|
|
16
17
|
avatar?: string
|
|
17
18
|
orgId?: string
|
|
19
|
+
orgRef?: string
|
|
18
20
|
type?: 'person' | 'bot'
|
|
19
21
|
created?: string
|
|
20
22
|
users?: Array<{
|
|
21
23
|
id: string
|
|
24
|
+
ref: string
|
|
22
25
|
emails: string[]
|
|
23
26
|
displayName: string
|
|
24
27
|
type: 'person' | 'bot'
|
|
@@ -29,6 +32,7 @@ interface UserResult {
|
|
|
29
32
|
function formatPerson(person: WebexPerson): UserResult {
|
|
30
33
|
return {
|
|
31
34
|
id: person.id,
|
|
35
|
+
ref: person.ref,
|
|
32
36
|
emails: person.emails,
|
|
33
37
|
displayName: person.displayName,
|
|
34
38
|
nickName: person.nickName,
|
|
@@ -36,6 +40,7 @@ function formatPerson(person: WebexPerson): UserResult {
|
|
|
36
40
|
lastName: person.lastName,
|
|
37
41
|
avatar: person.avatar,
|
|
38
42
|
orgId: person.orgId,
|
|
43
|
+
orgRef: person.orgRef,
|
|
39
44
|
type: person.type,
|
|
40
45
|
created: person.created,
|
|
41
46
|
}
|
|
@@ -52,6 +57,7 @@ export async function listAction(
|
|
|
52
57
|
return {
|
|
53
58
|
users: people.map((p) => ({
|
|
54
59
|
id: p.id,
|
|
60
|
+
ref: p.ref,
|
|
55
61
|
emails: p.emails,
|
|
56
62
|
displayName: p.displayName,
|
|
57
63
|
type: p.type,
|
|
@@ -7,10 +7,12 @@ import { getClient } from './shared'
|
|
|
7
7
|
|
|
8
8
|
interface WhoamiResult {
|
|
9
9
|
id?: string
|
|
10
|
+
ref?: string
|
|
10
11
|
emails?: string[]
|
|
11
12
|
displayName?: string
|
|
12
13
|
avatar?: string
|
|
13
14
|
orgId?: string
|
|
15
|
+
orgRef?: string
|
|
14
16
|
type?: 'person' | 'bot'
|
|
15
17
|
created?: string
|
|
16
18
|
error?: string
|
|
@@ -22,10 +24,12 @@ export async function whoamiAction(options: BotOption): Promise<WhoamiResult> {
|
|
|
22
24
|
const info = await client.testAuth()
|
|
23
25
|
return {
|
|
24
26
|
id: info.id,
|
|
27
|
+
ref: info.ref,
|
|
25
28
|
emails: info.emails,
|
|
26
29
|
displayName: info.displayName,
|
|
27
30
|
avatar: info.avatar,
|
|
28
31
|
orgId: info.orgId,
|
|
32
|
+
orgRef: info.orgRef,
|
|
29
33
|
type: info.type,
|
|
30
34
|
created: info.created,
|
|
31
35
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { WebexBotClient } from './client'
|
|
2
2
|
export { WebexBotCredentialManager } from './credential-manager'
|
|
3
|
-
export { fromRestId, toRestId } from '../webex/id-normalizer'
|
|
4
|
-
export type { WebexRestIdType } from '../webex/id-normalizer'
|
|
3
|
+
export { decodeWebexId, fromRestId, toRef, toRestId } from '../webex/id-normalizer'
|
|
4
|
+
export type { DecodedWebexId, WebexRestIdType } from '../webex/id-normalizer'
|
|
5
5
|
export { WebexBotListener } from './listener'
|
|
6
6
|
export type { WebexBotListenerOptions } from './listener'
|
|
7
7
|
export type { WebexBotConfig, WebexBotCredentials, WebexBotEntry, WebexBotListenerEventMap } from './types'
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
export interface UnifiedChannel {
|
|
2
2
|
id: string
|
|
3
|
+
ref?: string
|
|
3
4
|
name: string
|
|
4
5
|
parentId?: string
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
export interface UnifiedMessage {
|
|
8
9
|
id: string
|
|
10
|
+
ref?: string
|
|
9
11
|
channelId: string
|
|
12
|
+
channelRef?: string
|
|
10
13
|
author: string
|
|
11
14
|
content: string
|
|
12
15
|
timestamp: string
|