@jimiford/webex 0.1.1
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/LICENSE +21 -0
- package/README.md +314 -0
- package/dist/channel-plugin.d.ts +18 -0
- package/dist/channel-plugin.js +410 -0
- package/dist/channel.d.ts +98 -0
- package/dist/channel.js +224 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +32 -0
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.js +23 -0
- package/dist/send.d.ts +92 -0
- package/dist/send.js +304 -0
- package/dist/types.d.ts +223 -0
- package/dist/types.js +6 -0
- package/dist/webhook.d.ts +64 -0
- package/dist/webhook.js +297 -0
- package/openclaw.plugin.json +33 -0
- package/package.json +71 -0
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Webex Webhook Handler Module
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.WebhookValidationError = exports.WebexWebhookHandler = void 0;
|
|
43
|
+
const crypto = __importStar(require("crypto"));
|
|
44
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
45
|
+
const DEFAULT_API_BASE_URL = 'https://webexapis.com/v1';
|
|
46
|
+
class WebexWebhookHandler {
|
|
47
|
+
config;
|
|
48
|
+
apiBaseUrl;
|
|
49
|
+
botId = null;
|
|
50
|
+
constructor(config) {
|
|
51
|
+
this.config = config;
|
|
52
|
+
this.apiBaseUrl = config.apiBaseUrl || DEFAULT_API_BASE_URL;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Initialize the webhook handler (fetch bot info)
|
|
56
|
+
*/
|
|
57
|
+
async initialize() {
|
|
58
|
+
const botInfo = await this.getBotInfo();
|
|
59
|
+
this.botId = botInfo.id;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Handle an incoming webhook request
|
|
63
|
+
*/
|
|
64
|
+
async handleWebhook(payload, signature) {
|
|
65
|
+
// Verify webhook signature if secret is configured
|
|
66
|
+
if (this.config.webhookSecret && signature) {
|
|
67
|
+
if (!this.verifySignature(payload, signature)) {
|
|
68
|
+
throw new WebhookValidationError('Invalid webhook signature');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Only handle message created events
|
|
72
|
+
if (payload.resource !== 'messages' || payload.event !== 'created') {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
// Ignore messages from the bot itself
|
|
76
|
+
if (payload.data.personId === this.botId) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
// Check DM policy
|
|
80
|
+
if (payload.data.roomType === 'direct') {
|
|
81
|
+
if (!this.isAllowedSender(payload.data)) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Fetch full message details (webhook only contains IDs)
|
|
86
|
+
const message = await this.fetchMessage(payload.data.id);
|
|
87
|
+
// Normalize to OpenClaw envelope
|
|
88
|
+
return this.normalizeMessage(message);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Verify webhook signature using HMAC-SHA1
|
|
92
|
+
*/
|
|
93
|
+
verifySignature(payload, signature) {
|
|
94
|
+
if (!this.config.webhookSecret) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
const hmac = crypto.createHmac('sha1', this.config.webhookSecret);
|
|
98
|
+
hmac.update(JSON.stringify(payload));
|
|
99
|
+
const expectedSignature = hmac.digest('hex');
|
|
100
|
+
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Check if the sender is allowed based on DM policy
|
|
104
|
+
*/
|
|
105
|
+
isAllowedSender(data) {
|
|
106
|
+
switch (this.config.dmPolicy) {
|
|
107
|
+
case 'allow':
|
|
108
|
+
return true;
|
|
109
|
+
case 'deny':
|
|
110
|
+
return false;
|
|
111
|
+
case 'allowlisted':
|
|
112
|
+
if (!this.config.allowFrom || this.config.allowFrom.length === 0) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return this.config.allowFrom.includes(data.personId) ||
|
|
116
|
+
this.config.allowFrom.includes(data.personEmail);
|
|
117
|
+
default:
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Fetch full message details from Webex API
|
|
123
|
+
*/
|
|
124
|
+
async fetchMessage(messageId) {
|
|
125
|
+
const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/messages/${messageId}`, {
|
|
126
|
+
method: 'GET',
|
|
127
|
+
headers: {
|
|
128
|
+
'Authorization': `Bearer ${this.config.token}`,
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
throw new Error(`Failed to fetch message: ${response.status} ${response.statusText}`);
|
|
134
|
+
}
|
|
135
|
+
return response.json();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Normalize a Webex message to OpenClaw envelope format
|
|
139
|
+
*/
|
|
140
|
+
normalizeMessage(message) {
|
|
141
|
+
const attachments = [];
|
|
142
|
+
// Convert file attachments
|
|
143
|
+
if (message.files && message.files.length > 0) {
|
|
144
|
+
for (const fileUrl of message.files) {
|
|
145
|
+
attachments.push({
|
|
146
|
+
type: 'file',
|
|
147
|
+
url: fileUrl,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Convert card attachments
|
|
152
|
+
if (message.attachments && message.attachments.length > 0) {
|
|
153
|
+
for (const attachment of message.attachments) {
|
|
154
|
+
attachments.push({
|
|
155
|
+
type: 'card',
|
|
156
|
+
content: attachment.content,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
id: message.id,
|
|
162
|
+
channel: 'webex',
|
|
163
|
+
conversationId: message.roomId,
|
|
164
|
+
author: {
|
|
165
|
+
id: message.personId,
|
|
166
|
+
email: message.personEmail,
|
|
167
|
+
displayName: undefined, // Would need additional API call to get
|
|
168
|
+
isBot: false, // Messages from bot are filtered out earlier
|
|
169
|
+
},
|
|
170
|
+
content: {
|
|
171
|
+
text: message.text,
|
|
172
|
+
markdown: message.markdown,
|
|
173
|
+
attachments: attachments.length > 0 ? attachments : undefined,
|
|
174
|
+
},
|
|
175
|
+
metadata: {
|
|
176
|
+
roomType: message.roomType,
|
|
177
|
+
roomId: message.roomId,
|
|
178
|
+
timestamp: message.created,
|
|
179
|
+
mentions: message.mentionedPeople,
|
|
180
|
+
parentId: message.parentId,
|
|
181
|
+
raw: message,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Register webhooks with Webex
|
|
187
|
+
*/
|
|
188
|
+
async registerWebhooks() {
|
|
189
|
+
// First, list existing webhooks and remove duplicates
|
|
190
|
+
const existing = await this.listWebhooks();
|
|
191
|
+
const targetUrl = this.config.webhookUrl;
|
|
192
|
+
// Delete existing webhooks with the same target URL
|
|
193
|
+
for (const webhook of existing) {
|
|
194
|
+
if (webhook.targetUrl === targetUrl) {
|
|
195
|
+
await this.deleteWebhook(webhook.id);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Create new webhooks for messages
|
|
199
|
+
const webhooks = [];
|
|
200
|
+
// Webhook for new messages
|
|
201
|
+
const messageCreatedWebhook = await this.createWebhook({
|
|
202
|
+
name: 'OpenClaw Message Handler',
|
|
203
|
+
targetUrl,
|
|
204
|
+
resource: 'messages',
|
|
205
|
+
event: 'created',
|
|
206
|
+
secret: this.config.webhookSecret,
|
|
207
|
+
});
|
|
208
|
+
webhooks.push(messageCreatedWebhook);
|
|
209
|
+
return webhooks;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* List all webhooks
|
|
213
|
+
*/
|
|
214
|
+
async listWebhooks() {
|
|
215
|
+
const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/webhooks`, {
|
|
216
|
+
method: 'GET',
|
|
217
|
+
headers: {
|
|
218
|
+
'Authorization': `Bearer ${this.config.token}`,
|
|
219
|
+
'Content-Type': 'application/json',
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
if (!response.ok) {
|
|
223
|
+
throw new Error(`Failed to list webhooks: ${response.status} ${response.statusText}`);
|
|
224
|
+
}
|
|
225
|
+
const data = await response.json();
|
|
226
|
+
return data.items;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Create a webhook
|
|
230
|
+
*/
|
|
231
|
+
async createWebhook(request) {
|
|
232
|
+
const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/webhooks`, {
|
|
233
|
+
method: 'POST',
|
|
234
|
+
headers: {
|
|
235
|
+
'Authorization': `Bearer ${this.config.token}`,
|
|
236
|
+
'Content-Type': 'application/json',
|
|
237
|
+
},
|
|
238
|
+
body: JSON.stringify(request),
|
|
239
|
+
});
|
|
240
|
+
if (!response.ok) {
|
|
241
|
+
const errorText = await response.text();
|
|
242
|
+
throw new Error(`Failed to create webhook: ${response.status} ${response.statusText} - ${errorText}`);
|
|
243
|
+
}
|
|
244
|
+
return response.json();
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Delete a webhook
|
|
248
|
+
*/
|
|
249
|
+
async deleteWebhook(webhookId) {
|
|
250
|
+
const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/webhooks/${webhookId}`, {
|
|
251
|
+
method: 'DELETE',
|
|
252
|
+
headers: {
|
|
253
|
+
'Authorization': `Bearer ${this.config.token}`,
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
if (!response.ok && response.status !== 404) {
|
|
257
|
+
throw new Error(`Failed to delete webhook: ${response.status} ${response.statusText}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get bot information
|
|
262
|
+
*/
|
|
263
|
+
async getBotInfo() {
|
|
264
|
+
const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/people/me`, {
|
|
265
|
+
method: 'GET',
|
|
266
|
+
headers: {
|
|
267
|
+
'Authorization': `Bearer ${this.config.token}`,
|
|
268
|
+
'Content-Type': 'application/json',
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
if (!response.ok) {
|
|
272
|
+
throw new Error(`Failed to get bot info: ${response.status} ${response.statusText}`);
|
|
273
|
+
}
|
|
274
|
+
return response.json();
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get the bot ID (after initialization)
|
|
278
|
+
*/
|
|
279
|
+
getBotId() {
|
|
280
|
+
return this.botId;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
exports.WebexWebhookHandler = WebexWebhookHandler;
|
|
284
|
+
/**
|
|
285
|
+
* Custom error for webhook validation failures
|
|
286
|
+
*/
|
|
287
|
+
class WebhookValidationError extends Error {
|
|
288
|
+
constructor(message) {
|
|
289
|
+
super(message);
|
|
290
|
+
this.name = 'WebhookValidationError';
|
|
291
|
+
if (Error.captureStackTrace) {
|
|
292
|
+
Error.captureStackTrace(this, WebhookValidationError);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.WebhookValidationError = WebhookValidationError;
|
|
297
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViaG9vay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy93ZWJob29rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsK0NBQWlDO0FBQ2pDLDREQUErQjtBQWEvQixNQUFNLG9CQUFvQixHQUFHLDBCQUEwQixDQUFDO0FBRXhELE1BQWEsbUJBQW1CO0lBQ3RCLE1BQU0sQ0FBcUI7SUFDM0IsVUFBVSxDQUFTO0lBQ25CLEtBQUssR0FBa0IsSUFBSSxDQUFDO0lBRXBDLFlBQVksTUFBMEI7UUFDcEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxJQUFJLG9CQUFvQixDQUFDO0lBQzlELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDeEMsSUFBSSxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQ2pCLE9BQTRCLEVBQzVCLFNBQWtCO1FBRWxCLG1EQUFtRDtRQUNuRCxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzNDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUM5QyxNQUFNLElBQUksc0JBQXNCLENBQUMsMkJBQTJCLENBQUMsQ0FBQztZQUNoRSxDQUFDO1FBQ0gsQ0FBQztRQUVELHFDQUFxQztRQUNyQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLEtBQUssVUFBVSxJQUFJLE9BQU8sQ0FBQyxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFD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MkJBQTJCLFFBQVEsQ0FBQyxNQUFNLElBQUksUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDdkYsQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDLElBQUksRUFBb0UsQ0FBQztJQUMzRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRO1FBQ04sT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3BCLENBQUM7Q0FDRjtBQXRSRCxrREFzUkM7QUFFRDs7R0FFRztBQUNILE1BQWEsc0JBQXVCLFNBQVEsS0FBSztJQUMvQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyx3QkFBd0IsQ0FBQztRQUVyQyxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzVCLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUN4RCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBVEQsd0RBU0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFdlYmV4IFdlYmhvb2sgSGFuZGxlciBNb2R1bGVcbiAqL1xuXG5pbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCBmZXRjaCBmcm9tICdub2RlLWZldGNoJztcbmltcG9ydCB0eXBlIHtcbiAgV2ViZXhDaGFubmVsQ29uZmlnLFxuICBXZWJleFdlYmhvb2tQYXlsb2FkLFxuICBXZWJleFdlYmhvb2tEYXRhLFxuICBXZWJleE1lc3NhZ2UsXG4gIFdlYmV4V2ViaG9vayxcbiAgQ3JlYXRlV2ViaG9va1JlcXVlc3QsXG4gIE9wZW5DbGF3RW52ZWxvcGUsXG4gIE9wZW5DbGF3QXR0YWNobWVudCxcbiAgUGFnaW5hdGVkUmVzcG9uc2UsXG59IGZyb20gJy4vdHlwZXMnO1xuXG5jb25zdCBERUZBVUxUX0FQSV9CQVNFX1VSTCA9ICdodHRwczovL3dlYmV4YXBpcy5jb20vdjEnO1xuXG5leHBvcnQgY2xhc3MgV2ViZXhXZWJob29rSGFuZGxlciB7XG4gIHByaXZhdGUgY29uZmlnOiBXZWJleENoYW5uZWxDb25maWc7XG4gIHByaXZhdGUgYXBpQmFzZVVybDogc3RyaW5nO1xuICBwcml2YXRlIGJvdElkOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFdlYmV4Q2hhbm5lbENvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMuYXBpQmFzZVVybCA9IGNvbmZpZy5hcGlCYXNlVXJsIHx8IERFRkFVTFRfQVBJX0JBU0VfVVJMO1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIHdlYmhvb2sgaGFuZGxlciAoZmV0Y2ggYm90IGluZm8pXG4gICAqL1xuICBhc3luYyBpbml0aWFsaXplKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGJvdEluZm8gPSBhd2FpdCB0aGlzLmdldEJvdEluZm8oKTtcbiAgICB0aGlzLmJvdElkID0gYm90SW5mby5pZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGUgYW4gaW5jb21pbmcgd2ViaG9vayByZXF1ZXN0XG4gICAqL1xuICBhc3luYyBoYW5kbGVXZWJob29rKFxuICAgIHBheWxvYWQ6IFdlYmV4V2ViaG9va1BheWxvYWQsXG4gICAgc2lnbmF0dXJlPzogc3RyaW5nXG4gICk6IFByb21pc2U8T3BlbkNsYXdFbnZlbG9wZSB8IG51bGw+IHtcbiAgICAvLyBWZXJpZnkgd2ViaG9vayBzaWduYXR1cmUgaWYgc2VjcmV0IGlzIGNvbmZpZ3VyZWRcbiAgICBpZiAodGhpcy5jb25maWcud2ViaG9va1NlY3JldCAmJiBzaWduYXR1cmUpIHtcbiAgICAgIGlmICghdGhpcy52ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlKSkge1xuICAgICAgICB0aHJvdyBuZXcgV2ViaG9va1ZhbGlkYXRpb25FcnJvcignSW52YWxpZCB3ZWJob29rIHNpZ25hdHVyZScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE9ubHkgaGFuZGxlIG1lc3NhZ2UgY3JlYXRlZCBldmVudHNcbiAgICBpZiAocGF5bG9hZC5yZXNvdXJjZSAhPT0gJ21lc3NhZ2VzJyB8fCBwYXlsb2FkLmV2ZW50ICE9PSAnY3JlYXRlZCcpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIElnbm9yZSBtZXNzYWdlcyBmcm9tIHRoZSBib3QgaXRzZWxmXG4gICAgaWYgKHBheWxvYWQuZGF0YS5wZXJzb25JZCA9PT0gdGhpcy5ib3RJZCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgRE0gcG9saWN5XG4gICAgaWYgKHBheWxvYWQuZGF0YS5yb29tVHlwZSA9PT0gJ2RpcmVjdCcpIHtcbiAgICAgIGlmICghdGhpcy5pc0FsbG93ZWRTZW5kZXIocGF5bG9hZC5kYXRhKSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBGZXRjaCBmdWxsIG1lc3NhZ2UgZGV0YWlscyAod2ViaG9vayBvbmx5IGNvbnRhaW5zIElEcylcbiAgICBjb25zdCBtZXNzYWdlID0gYXdhaXQgdGhpcy5mZXRjaE1lc3NhZ2UocGF5bG9hZC5kYXRhLmlkKTtcblxuICAgIC8vIE5vcm1hbGl6ZSB0byBPcGVuQ2xhdyBlbnZlbG9wZVxuICAgIHJldHVybiB0aGlzLm5vcm1hbGl6ZU1lc3NhZ2UobWVzc2FnZSk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IHdlYmhvb2sgc2lnbmF0dXJlIHVzaW5nIEhNQUMtU0hBMVxuICAgKi9cbiAgdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQ6IFdlYmV4V2ViaG9va1BheWxvYWQsIHNpZ25hdHVyZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZy53ZWJob29rU2VjcmV0KSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBjb25zdCBobWFjID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTEnLCB0aGlzLmNvbmZpZy53ZWJob29rU2VjcmV0KTtcbiAgICBobWFjLnVwZGF0ZShKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgY29uc3QgZXhwZWN0ZWRTaWduYXR1cmUgPSBobWFjLmRpZ2VzdCgnaGV4Jyk7XG5cbiAgICByZXR1cm4gY3J5cHRvLnRpbWluZ1NhZmVFcXVhbChcbiAgICAgIEJ1ZmZlci5mcm9tKHNpZ25hdHVyZSksXG4gICAgICBCdWZmZXIuZnJvbShleHBlY3RlZFNpZ25hdHVyZSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIHRoZSBzZW5kZXIgaXMgYWxsb3dlZCBiYXNlZCBvbiBETSBwb2xpY3lcbiAgICovXG4gIHByaXZhdGUgaXNBbGxvd2VkU2VuZGVyKGRhdGE6IFdlYmV4V2ViaG9va0RhdGEpOiBib29sZWFuIHtcbiAgICBzd2l0Y2ggKHRoaXMuY29uZmlnLmRtUG9saWN5KSB7XG4gICAgICBjYXNlICdhbGxvdyc6XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgY2FzZSAnZGVueSc6XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIGNhc2UgJ2FsbG93bGlzdGVkJzpcbiAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5hbGxvd0Zyb20gfHwgdGhpcy5jb25maWcuYWxsb3dGcm9tLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWcuYWxsb3dGcm9tLmluY2x1ZGVzKGRhdGEucGVyc29uSWQpIHx8XG4gICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5hbGxvd0Zyb20uaW5jbHVkZXMoZGF0YS5wZXJzb25FbWFpbCk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIGZ1bGwgbWVzc2FnZSBkZXRhaWxzIGZyb20gV2ViZXggQVBJXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoTWVzc2FnZShtZXNzYWdlSWQ6IHN0cmluZyk6IFByb21pc2U8V2ViZXhNZXNzYWdlPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L21lc3NhZ2VzLyR7bWVzc2FnZUlkfWAsIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggbWVzc2FnZTogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpIGFzIFByb21pc2U8V2ViZXhNZXNzYWdlPjtcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpemUgYSBXZWJleCBtZXNzYWdlIHRvIE9wZW5DbGF3IGVudmVsb3BlIGZvcm1hdFxuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVNZXNzYWdlKG1lc3NhZ2U6IFdlYmV4TWVzc2FnZSk6IE9wZW5DbGF3RW52ZWxvcGUge1xuICAgIGNvbnN0IGF0dGFjaG1lbnRzOiBPcGVuQ2xhd0F0dGFjaG1lbnRbXSA9IFtdO1xuXG4gICAgLy8gQ29udmVydCBmaWxlIGF0dGFjaG1lbnRzXG4gICAgaWYgKG1lc3NhZ2UuZmlsZXMgJiYgbWVzc2FnZS5maWxlcy5sZW5ndGggPiAwKSB7XG4gICAgICBmb3IgKGNvbnN0IGZpbGVVcmwgb2YgbWVzc2FnZS5maWxlcykge1xuICAgICAgICBhdHRhY2htZW50cy5wdXNoKHtcbiAgICAgICAgICB0eXBlOiAnZmlsZScsXG4gICAgICAgICAgdXJsOiBmaWxlVXJsLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0IGNhcmQgYXR0YWNobWVudHNcbiAgICBpZiAobWVzc2FnZS5hdHRhY2htZW50cyAmJiBtZXNzYWdlLmF0dGFjaG1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGZvciAoY29uc3QgYXR0YWNobWVudCBvZiBtZXNzYWdlLmF0dGFjaG1lbnRzKSB7XG4gICAgICAgIGF0dGFjaG1lbnRzLnB1c2goe1xuICAgICAgICAgIHR5cGU6ICdjYXJkJyxcbiAgICAgICAgICBjb250ZW50OiBhdHRhY2htZW50LmNvbnRlbnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpZDogbWVzc2FnZS5pZCxcbiAgICAgIGNoYW5uZWw6ICd3ZWJleCcsXG4gICAgICBjb252ZXJzYXRpb25JZDogbWVzc2FnZS5yb29tSWQsXG4gICAgICBhdXRob3I6IHtcbiAgICAgICAgaWQ6IG1lc3NhZ2UucGVyc29uSWQsXG4gICAgICAgIGVtYWlsOiBtZXNzYWdlLnBlcnNvbkVtYWlsLFxuICAgICAgICBkaXNwbGF5TmFtZTogdW5kZWZpbmVkLCAvLyBXb3VsZCBuZWVkIGFkZGl0aW9uYWwgQVBJIGNhbGwgdG8gZ2V0XG4gICAgICAgIGlzQm90OiBmYWxzZSwgLy8gTWVzc2FnZXMgZnJvbSBib3QgYXJlIGZpbHRlcmVkIG91dCBlYXJsaWVyXG4gICAgICB9LFxuICAgICAgY29udGVudDoge1xuICAgICAgICB0ZXh0OiBtZXNzYWdlLnRleHQsXG4gICAgICAgIG1hcmtkb3duOiBtZXNzYWdlLm1hcmtkb3duLFxuICAgICAgICBhdHRhY2htZW50czogYXR0YWNobWVudHMubGVuZ3RoID4gMCA/IGF0dGFjaG1lbnRzIDogdW5kZWZpbmVkLFxuICAgICAgfSxcbiAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgIHJvb21UeXBlOiBtZXNzYWdlLnJvb21UeXBlLFxuICAgICAgICByb29tSWQ6IG1lc3NhZ2Uucm9vbUlkLFxuICAgICAgICB0aW1lc3RhbXA6IG1lc3NhZ2UuY3JlYXRlZCxcbiAgICAgICAgbWVudGlvbnM6IG1lc3NhZ2UubWVudGlvbmVkUGVvcGxlLFxuICAgICAgICBwYXJlbnRJZDogbWVzc2FnZS5wYXJlbnRJZCxcbiAgICAgICAgcmF3OiBtZXNzYWdlLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIHdlYmhvb2tzIHdpdGggV2ViZXhcbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyV2ViaG9va3MoKTogUHJvbWlzZTxXZWJleFdlYmhvb2tbXT4ge1xuICAgIC8vIEZpcnN0LCBsaXN0IGV4aXN0aW5nIHdlYmhvb2tzIGFuZCByZW1vdmUgZHVwbGljYXRlc1xuICAgIGNvbnN0IGV4aXN0aW5nID0gYXdhaXQgdGhpcy5saXN0V2ViaG9va3MoKTtcbiAgICBjb25zdCB0YXJnZXRVcmwgPSB0aGlzLmNvbmZpZy53ZWJob29rVXJsO1xuXG4gICAgLy8gRGVsZXRlIGV4aXN0aW5nIHdlYmhvb2tzIHdpdGggdGhlIHNhbWUgdGFyZ2V0IFVSTFxuICAgIGZvciAoY29uc3Qgd2ViaG9vayBvZiBleGlzdGluZykge1xuICAgICAgaWYgKHdlYmhvb2sudGFyZ2V0VXJsID09PSB0YXJnZXRVcmwpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGVXZWJob29rKHdlYmhvb2suaWQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBuZXcgd2ViaG9va3MgZm9yIG1lc3NhZ2VzXG4gICAgY29uc3Qgd2ViaG9va3M6IFdlYmV4V2ViaG9va1tdID0gW107XG5cbiAgICAvLyBXZWJob29rIGZvciBuZXcgbWVzc2FnZXNcbiAgICBjb25zdCBtZXNzYWdlQ3JlYXRlZFdlYmhvb2sgPSBhd2FpdCB0aGlzLmNyZWF0ZVdlYmhvb2soe1xuICAgICAgbmFtZTogJ09wZW5DbGF3IE1lc3NhZ2UgSGFuZGxlcicsXG4gICAgICB0YXJnZXRVcmwsXG4gICAgICByZXNvdXJjZTogJ21lc3NhZ2VzJyxcbiAgICAgIGV2ZW50OiAnY3JlYXRlZCcsXG4gICAgICBzZWNyZXQ6IHRoaXMuY29uZmlnLndlYmhvb2tTZWNyZXQsXG4gICAgfSk7XG4gICAgd2ViaG9va3MucHVzaChtZXNzYWdlQ3JlYXRlZFdlYmhvb2spO1xuXG4gICAgcmV0dXJuIHdlYmhvb2tzO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3QgYWxsIHdlYmhvb2tzXG4gICAqL1xuICBhc3luYyBsaXN0V2ViaG9va3MoKTogUHJvbWlzZTxXZWJleFdlYmhvb2tbXT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7dGhpcy5hcGlCYXNlVXJsfS93ZWJob29rc2AsIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gbGlzdCB3ZWJob29rczogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpIGFzIFBhZ2luYXRlZFJlc3BvbnNlPFdlYmV4V2ViaG9vaz47XG4gICAgcmV0dXJuIGRhdGEuaXRlbXM7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgd2ViaG9va1xuICAgKi9cbiAgYXN5bmMgY3JlYXRlV2ViaG9vayhyZXF1ZXN0OiBDcmVhdGVXZWJob29rUmVxdWVzdCk6IFByb21pc2U8V2ViZXhXZWJob29rPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L3dlYmhvb2tzYCwge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocmVxdWVzdCksXG4gICAgfSk7XG5cbiAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICBjb25zdCBlcnJvclRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBjcmVhdGUgd2ViaG9vazogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH0gLSAke2Vycm9yVGV4dH1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpIGFzIFByb21pc2U8V2ViZXhXZWJob29rPjtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYSB3ZWJob29rXG4gICAqL1xuICBhc3luYyBkZWxldGVXZWJob29rKHdlYmhvb2tJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L3dlYmhvb2tzLyR7d2ViaG9va0lkfWAsIHtcbiAgICAgIG1ldGhvZDogJ0RFTEVURScsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vayAmJiByZXNwb25zZS5zdGF0dXMgIT09IDQwNCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZGVsZXRlIHdlYmhvb2s6ICR7cmVzcG9uc2Uuc3RhdHVzfSAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBib3QgaW5mb3JtYXRpb25cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0Qm90SW5mbygpOiBQcm9taXNlPHsgaWQ6IHN0cmluZzsgZGlzcGxheU5hbWU6IHN0cmluZzsgZW1haWxzOiBzdHJpbmdbXSB9PiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L3Blb3BsZS9tZWAsIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZ2V0IGJvdCBpbmZvOiAke3Jlc3BvbnNlLnN0YXR1c30gJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS5qc29uKCkgYXMgUHJvbWlzZTx7IGlkOiBzdHJpbmc7IGRpc3BsYXlOYW1lOiBzdHJpbmc7IGVtYWlsczogc3RyaW5nW10gfT47XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBib3QgSUQgKGFmdGVyIGluaXRpYWxpemF0aW9uKVxuICAgKi9cbiAgZ2V0Qm90SWQoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuYm90SWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBDdXN0b20gZXJyb3IgZm9yIHdlYmhvb2sgdmFsaWRhdGlvbiBmYWlsdXJlc1xuICovXG5leHBvcnQgY2xhc3MgV2ViaG9va1ZhbGlkYXRpb25FcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ1dlYmhvb2tWYWxpZGF0aW9uRXJyb3InO1xuXG4gICAgaWYgKEVycm9yLmNhcHR1cmVTdGFja1RyYWNlKSB7XG4gICAgICBFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLCBXZWJob29rVmFsaWRhdGlvbkVycm9yKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "webex",
|
|
3
|
+
"name": "Webex Channel",
|
|
4
|
+
"description": "Cisco Webex messaging integration for OpenClaw",
|
|
5
|
+
"channels": ["webex"],
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {}
|
|
10
|
+
},
|
|
11
|
+
"uiHints": {
|
|
12
|
+
"token": {
|
|
13
|
+
"label": "Bot Access Token",
|
|
14
|
+
"sensitive": true,
|
|
15
|
+
"placeholder": "Your Webex bot token"
|
|
16
|
+
},
|
|
17
|
+
"webhookUrl": {
|
|
18
|
+
"label": "Webhook URL",
|
|
19
|
+
"placeholder": "https://your-domain.com/webhooks/webex"
|
|
20
|
+
},
|
|
21
|
+
"webhookSecret": {
|
|
22
|
+
"label": "Webhook Secret",
|
|
23
|
+
"sensitive": true,
|
|
24
|
+
"placeholder": "Optional secret for webhook verification"
|
|
25
|
+
},
|
|
26
|
+
"dmPolicy": {
|
|
27
|
+
"label": "DM Policy"
|
|
28
|
+
},
|
|
29
|
+
"allowFrom": {
|
|
30
|
+
"label": "Allowed Senders"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jimiford/webex",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "OpenClaw channel plugin for Cisco Webex messaging",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"openclaw.plugin.json"
|
|
10
|
+
],
|
|
11
|
+
"openclaw": {
|
|
12
|
+
"extensions": [
|
|
13
|
+
"./dist/plugin.js"
|
|
14
|
+
],
|
|
15
|
+
"channel": {
|
|
16
|
+
"id": "webex",
|
|
17
|
+
"label": "Webex",
|
|
18
|
+
"selectionLabel": "Cisco Webex",
|
|
19
|
+
"docsPath": "/channels/webex",
|
|
20
|
+
"blurb": "Cisco Webex messaging via bot webhooks.",
|
|
21
|
+
"aliases": [
|
|
22
|
+
"cisco-webex"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"install": {
|
|
26
|
+
"npmSpec": "@jimiford/channel-webex",
|
|
27
|
+
"defaultChoice": "npm"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"dev": "tsc --watch",
|
|
33
|
+
"lint": "eslint src --ext .ts",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"test:coverage": "vitest run --coverage",
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"openclaw",
|
|
41
|
+
"webex",
|
|
42
|
+
"cisco",
|
|
43
|
+
"channel",
|
|
44
|
+
"messaging",
|
|
45
|
+
"bot"
|
|
46
|
+
],
|
|
47
|
+
"author": "",
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@openclaw/core": "^1.0.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependenciesMeta": {
|
|
53
|
+
"@openclaw/core": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"node-fetch": "^2.7.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/node": "^20.10.0",
|
|
62
|
+
"@types/node-fetch": "^2.6.9",
|
|
63
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
64
|
+
"openclaw": "^2026.1.30",
|
|
65
|
+
"typescript": "^5.3.0",
|
|
66
|
+
"vitest": "^4.0.18"
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18.0.0"
|
|
70
|
+
}
|
|
71
|
+
}
|