@wecom/wecom-openclaw-plugin 2026.3.24-beta.2 → 2026.3.24-beta.4
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/dist/index.cjs.js +170 -91
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.esm.js +158 -79
- package/dist/index.esm.js.map +1 -1
- package/dist/src/onboarding.d.ts +7 -3
- package/dist/src/openclaw-compat.d.ts +38 -0
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var core = require('openclaw/plugin-sdk/core');
|
|
6
|
-
var os$1 = require('os');
|
|
7
|
-
var path$1 = require('path');
|
|
8
|
-
var aibotNodeSdk = require('@wecom/aibot-node-sdk');
|
|
9
5
|
var fs = require('node:fs/promises');
|
|
10
6
|
var path = require('node:path');
|
|
11
7
|
var os = require('node:os');
|
|
12
8
|
var node_url = require('node:url');
|
|
9
|
+
var os$1 = require('os');
|
|
10
|
+
var path$1 = require('path');
|
|
11
|
+
var aibotNodeSdk = require('@wecom/aibot-node-sdk');
|
|
13
12
|
var fileType = require('file-type');
|
|
14
13
|
var node_fs = require('node:fs');
|
|
15
14
|
|
|
@@ -31,22 +30,11 @@ function _interopNamespaceDefault(e) {
|
|
|
31
30
|
return Object.freeze(n);
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
var os__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(os$1);
|
|
35
|
-
var path__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(path$1);
|
|
36
33
|
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
37
34
|
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
38
35
|
var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function setWeComRuntime(r) {
|
|
42
|
-
runtime = r;
|
|
43
|
-
}
|
|
44
|
-
function getWeComRuntime() {
|
|
45
|
-
if (!runtime) {
|
|
46
|
-
throw new Error("WeCom runtime not initialized - plugin not registered");
|
|
47
|
-
}
|
|
48
|
-
return runtime;
|
|
49
|
-
}
|
|
36
|
+
var os__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(os$1);
|
|
37
|
+
var path__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(path$1);
|
|
50
38
|
|
|
51
39
|
/**
|
|
52
40
|
* openclaw plugin-sdk 高版本方法兼容层
|
|
@@ -57,6 +45,7 @@ function getWeComRuntime() {
|
|
|
57
45
|
* 本模块在加载时一次性探测 SDK 导出,存在则直接 re-export SDK 版本,
|
|
58
46
|
* 不存在则导出 fallback 实现。其他模块统一从本文件导入,无需关心底层兼容细节。
|
|
59
47
|
*/
|
|
48
|
+
const DEFAULT_ACCOUNT_ID = "default";
|
|
60
49
|
const _sdkReady = import('openclaw/plugin-sdk/core')
|
|
61
50
|
.then((sdk) => {
|
|
62
51
|
const exports$1 = {};
|
|
@@ -399,6 +388,34 @@ async function getDefaultMediaLocalRoots() {
|
|
|
399
388
|
path__namespace.join(stateDir, "sandboxes"),
|
|
400
389
|
];
|
|
401
390
|
}
|
|
391
|
+
function emptyPluginConfigSchema() {
|
|
392
|
+
return {
|
|
393
|
+
type: 'object',
|
|
394
|
+
additionalProperties: false,
|
|
395
|
+
properties: {},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* 格式化配对审批提示信息(参考 moltbot 实现)
|
|
400
|
+
* @param channelId 频道ID
|
|
401
|
+
* @returns 配对审批提示字符串
|
|
402
|
+
*/
|
|
403
|
+
function formatPairingApproveHint(channelId) {
|
|
404
|
+
const listCmd = `openclaw pairing list ${channelId}`;
|
|
405
|
+
const approveCmd = `openclaw pairing approve ${channelId} <code>`;
|
|
406
|
+
return `向 ${channelId} 机器人发送消息以完成配对审批(命令行:${listCmd} / ${approveCmd})`;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
let runtime = null;
|
|
410
|
+
function setWeComRuntime(r) {
|
|
411
|
+
runtime = r;
|
|
412
|
+
}
|
|
413
|
+
function getWeComRuntime() {
|
|
414
|
+
if (!runtime) {
|
|
415
|
+
throw new Error("WeCom runtime not initialized - plugin not registered");
|
|
416
|
+
}
|
|
417
|
+
return runtime;
|
|
418
|
+
}
|
|
402
419
|
|
|
403
420
|
/**
|
|
404
421
|
* 企业微信渠道常量定义
|
|
@@ -2164,7 +2181,7 @@ const DefaultWsUrl = "wss://openws.work.weixin.qq.com";
|
|
|
2164
2181
|
function resolveWeComAccount(cfg) {
|
|
2165
2182
|
const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
2166
2183
|
return {
|
|
2167
|
-
accountId:
|
|
2184
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
2168
2185
|
name: wecomConfig.name ?? "企业微信",
|
|
2169
2186
|
enabled: wecomConfig.enabled ?? false,
|
|
2170
2187
|
websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,
|
|
@@ -2206,39 +2223,33 @@ function setWeComAccount(cfg, account) {
|
|
|
2206
2223
|
}
|
|
2207
2224
|
|
|
2208
2225
|
/**
|
|
2209
|
-
* 企业微信
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
/**
|
|
2213
|
-
* 企业微信设置帮助说明
|
|
2214
|
-
*/
|
|
2215
|
-
async function noteWeComSetupHelp(prompter) {
|
|
2216
|
-
await prompter.note([
|
|
2217
|
-
"企业微信机器人需要以下配置信息:",
|
|
2218
|
-
"1. Bot ID: 企业微信机器人id",
|
|
2219
|
-
"2. Secret: 企业微信机器人密钥",
|
|
2220
|
-
].join("\n"), "企业微信设置");
|
|
2221
|
-
}
|
|
2222
|
-
/**
|
|
2223
|
-
* 提示输入 Bot ID
|
|
2224
|
-
*/
|
|
2225
|
-
async function promptBotId(prompter, account) {
|
|
2226
|
-
return String(await prompter.text({
|
|
2227
|
-
message: "企业微信机器人 Bot ID",
|
|
2228
|
-
initialValue: account?.botId ?? "",
|
|
2229
|
-
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
2230
|
-
})).trim();
|
|
2231
|
-
}
|
|
2232
|
-
/**
|
|
2233
|
-
* 提示输入 Secret
|
|
2226
|
+
* 企业微信 setupWizard — 声明式 CLI setup wizard 配置。
|
|
2227
|
+
*
|
|
2228
|
+
* 框架通过 plugin.setupWizard 字段识别并驱动 channel 的引导配置流程。
|
|
2234
2229
|
*/
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2230
|
+
// ============================================================================
|
|
2231
|
+
// ChannelSetupAdapter — 框架用于应用配置输入的适配器
|
|
2232
|
+
// ============================================================================
|
|
2233
|
+
const wecomSetupAdapter = {
|
|
2234
|
+
applyAccountConfig: ({ cfg, input }) => {
|
|
2235
|
+
const patch = {};
|
|
2236
|
+
if (input.token !== undefined) {
|
|
2237
|
+
patch.botId = String(input.token).trim();
|
|
2238
|
+
}
|
|
2239
|
+
if (input.privateKey !== undefined) {
|
|
2240
|
+
patch.secret = String(input.privateKey).trim();
|
|
2241
|
+
}
|
|
2242
|
+
// 如果是首次配置,默认启用
|
|
2243
|
+
const account = resolveWeComAccount(cfg);
|
|
2244
|
+
if (!account.botId && !account.secret) {
|
|
2245
|
+
patch.enabled = true;
|
|
2246
|
+
}
|
|
2247
|
+
return setWeComAccount(cfg, patch);
|
|
2248
|
+
},
|
|
2249
|
+
};
|
|
2250
|
+
// ============================================================================
|
|
2251
|
+
// DM Policy 配置
|
|
2252
|
+
// ============================================================================
|
|
2242
2253
|
/**
|
|
2243
2254
|
* 设置企业微信 dmPolicy
|
|
2244
2255
|
*/
|
|
@@ -2255,7 +2266,7 @@ function setWeComDmPolicy(cfg, dmPolicy) {
|
|
|
2255
2266
|
}
|
|
2256
2267
|
const dmPolicy = {
|
|
2257
2268
|
label: "企业微信",
|
|
2258
|
-
channel,
|
|
2269
|
+
channel: CHANNEL_ID,
|
|
2259
2270
|
policyKey: `channels.${CHANNEL_ID}.dmPolicy`,
|
|
2260
2271
|
allowFromKey: `channels.${CHANNEL_ID}.allowFrom`,
|
|
2261
2272
|
getCurrent: (cfg) => {
|
|
@@ -2269,8 +2280,8 @@ const dmPolicy = {
|
|
|
2269
2280
|
const account = resolveWeComAccount(cfg);
|
|
2270
2281
|
const existingAllowFrom = account.config.allowFrom ?? [];
|
|
2271
2282
|
const entry = await prompter.text({
|
|
2272
|
-
message: "企业微信允许来源(用户ID或群组ID
|
|
2273
|
-
placeholder: "user123
|
|
2283
|
+
message: "企业微信允许来源(用户ID或群组ID,逗号分隔)",
|
|
2284
|
+
placeholder: "user123, group456",
|
|
2274
2285
|
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
|
2275
2286
|
});
|
|
2276
2287
|
const allowFrom = String(entry ?? "")
|
|
@@ -2280,38 +2291,105 @@ const dmPolicy = {
|
|
|
2280
2291
|
return setWeComAccount(cfg, { allowFrom });
|
|
2281
2292
|
},
|
|
2282
2293
|
};
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2294
|
+
// ============================================================================
|
|
2295
|
+
// ChannelSetupWizard — 声明式 setup wizard 配置
|
|
2296
|
+
// ============================================================================
|
|
2297
|
+
const wecomSetupWizard = {
|
|
2298
|
+
channel: CHANNEL_ID,
|
|
2299
|
+
// ── 状态 ──────────────────────────────────────────────────────────────
|
|
2300
|
+
status: {
|
|
2301
|
+
configuredLabel: "已配置 ✓",
|
|
2302
|
+
unconfiguredLabel: "需要 Bot ID 和 Secret",
|
|
2303
|
+
configuredHint: "已配置",
|
|
2304
|
+
unconfiguredHint: "需要设置",
|
|
2305
|
+
resolveConfigured: ({ cfg }) => {
|
|
2306
|
+
const account = resolveWeComAccount(cfg);
|
|
2307
|
+
return Boolean(account.botId?.trim() && account.secret?.trim());
|
|
2308
|
+
},
|
|
2309
|
+
resolveStatusLines: ({ cfg, configured }) => {
|
|
2310
|
+
return [`企业微信: ${configured ? "已配置" : "需要 Bot ID 和 Secret"}`];
|
|
2311
|
+
},
|
|
2312
|
+
},
|
|
2313
|
+
// ── 引导说明 ──────────────────────────────────────────────────────────
|
|
2314
|
+
introNote: {
|
|
2315
|
+
title: "企业微信设置",
|
|
2316
|
+
lines: [
|
|
2317
|
+
"企业微信机器人需要以下配置信息:",
|
|
2318
|
+
"1. Bot ID: 企业微信机器人 ID",
|
|
2319
|
+
"2. Secret: 企业微信机器人密钥",
|
|
2320
|
+
],
|
|
2321
|
+
shouldShow: ({ cfg }) => {
|
|
2322
|
+
const account = resolveWeComAccount(cfg);
|
|
2323
|
+
return !account.botId?.trim() || !account.secret?.trim();
|
|
2324
|
+
},
|
|
2295
2325
|
},
|
|
2296
|
-
|
|
2326
|
+
// ── 凭据输入 ──────────────────────────────────────────────────────────
|
|
2327
|
+
credentials: [
|
|
2328
|
+
{
|
|
2329
|
+
inputKey: "token",
|
|
2330
|
+
providerHint: "企业微信",
|
|
2331
|
+
credentialLabel: "Bot ID",
|
|
2332
|
+
envPrompt: "使用环境变量中的 Bot ID?",
|
|
2333
|
+
keepPrompt: "Bot ID 已配置,保留当前值?",
|
|
2334
|
+
inputPrompt: "企业微信机器人 Bot ID",
|
|
2335
|
+
inspect: ({ cfg }) => {
|
|
2336
|
+
const account = resolveWeComAccount(cfg);
|
|
2337
|
+
const hasValue = Boolean(account.botId?.trim());
|
|
2338
|
+
return {
|
|
2339
|
+
accountConfigured: hasValue,
|
|
2340
|
+
hasConfiguredValue: hasValue,
|
|
2341
|
+
resolvedValue: account.botId || undefined,
|
|
2342
|
+
};
|
|
2343
|
+
},
|
|
2344
|
+
applySet: ({ cfg, resolvedValue }) => {
|
|
2345
|
+
return setWeComAccount(cfg, { botId: resolvedValue });
|
|
2346
|
+
},
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
inputKey: "privateKey",
|
|
2350
|
+
providerHint: "企业微信",
|
|
2351
|
+
credentialLabel: "Secret",
|
|
2352
|
+
envPrompt: "使用环境变量中的 Secret?",
|
|
2353
|
+
keepPrompt: "Secret 已配置,保留当前值?",
|
|
2354
|
+
inputPrompt: "企业微信机器人 Secret",
|
|
2355
|
+
inspect: ({ cfg }) => {
|
|
2356
|
+
const account = resolveWeComAccount(cfg);
|
|
2357
|
+
const hasValue = Boolean(account.secret?.trim());
|
|
2358
|
+
return {
|
|
2359
|
+
accountConfigured: hasValue,
|
|
2360
|
+
hasConfiguredValue: hasValue,
|
|
2361
|
+
resolvedValue: account.secret || undefined,
|
|
2362
|
+
};
|
|
2363
|
+
},
|
|
2364
|
+
applySet: ({ cfg, resolvedValue }) => {
|
|
2365
|
+
return setWeComAccount(cfg, { secret: resolvedValue });
|
|
2366
|
+
},
|
|
2367
|
+
},
|
|
2368
|
+
],
|
|
2369
|
+
// ── 完成后的最终处理 ──────────────────────────────────────────────────
|
|
2370
|
+
finalize: async ({ cfg }) => {
|
|
2371
|
+
// 确保配置完成后 channel 处于启用状态
|
|
2297
2372
|
const account = resolveWeComAccount(cfg);
|
|
2298
|
-
if (
|
|
2299
|
-
|
|
2300
|
-
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2373
|
+
if (account.botId?.trim() && account.secret?.trim() && !account.enabled) {
|
|
2374
|
+
return { cfg: setWeComAccount(cfg, { enabled: true }) };
|
|
2375
|
+
}
|
|
2376
|
+
return undefined;
|
|
2377
|
+
},
|
|
2378
|
+
// ── 完成提示 ──────────────────────────────────────────────────────────
|
|
2379
|
+
completionNote: {
|
|
2380
|
+
title: "企业微信配置完成",
|
|
2381
|
+
lines: [
|
|
2382
|
+
"企业微信机器人已配置完成。",
|
|
2383
|
+
"运行 `openclaw start` 启动服务。",
|
|
2384
|
+
],
|
|
2385
|
+
shouldShow: ({ cfg }) => {
|
|
2386
|
+
const account = resolveWeComAccount(cfg);
|
|
2387
|
+
return Boolean(account.botId?.trim() && account.secret?.trim());
|
|
2388
|
+
},
|
|
2313
2389
|
},
|
|
2390
|
+
// ── DM 策略 ──────────────────────────────────────────────────────────
|
|
2314
2391
|
dmPolicy,
|
|
2392
|
+
// ── 禁用 ─────────────────────────────────────────────────────────────
|
|
2315
2393
|
disable: (cfg) => {
|
|
2316
2394
|
return setWeComAccount(cfg, { enabled: false });
|
|
2317
2395
|
},
|
|
@@ -2322,7 +2400,7 @@ const wecomOnboardingAdapter = {
|
|
|
2322
2400
|
* 无需依赖 reqId,直接向指定会话推送消息
|
|
2323
2401
|
*/
|
|
2324
2402
|
async function sendWeComMessage({ to, content, accountId, }) {
|
|
2325
|
-
const resolvedAccountId = accountId ??
|
|
2403
|
+
const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
2326
2404
|
// 从 to 中提取 chatId(格式是 "${CHANNEL_ID}:chatId" 或直接是 chatId)
|
|
2327
2405
|
const channelPrefix = new RegExp(`^${CHANNEL_ID}:`, "i");
|
|
2328
2406
|
const chatId = to.replace(channelPrefix, "");
|
|
@@ -2372,7 +2450,8 @@ const wecomPlugin = {
|
|
|
2372
2450
|
// Pairing approved for user
|
|
2373
2451
|
},
|
|
2374
2452
|
},
|
|
2375
|
-
|
|
2453
|
+
setupWizard: wecomSetupWizard,
|
|
2454
|
+
setup: wecomSetupAdapter,
|
|
2376
2455
|
capabilities: {
|
|
2377
2456
|
chatTypes: ["direct", "group"],
|
|
2378
2457
|
reactions: false,
|
|
@@ -2384,11 +2463,11 @@ const wecomPlugin = {
|
|
|
2384
2463
|
reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },
|
|
2385
2464
|
config: {
|
|
2386
2465
|
// 列出所有账户 ID(最小实现只支持默认账户)
|
|
2387
|
-
listAccountIds: () => [
|
|
2466
|
+
listAccountIds: () => [DEFAULT_ACCOUNT_ID],
|
|
2388
2467
|
// 解析账户配置
|
|
2389
2468
|
resolveAccount: (cfg) => resolveWeComAccount(cfg),
|
|
2390
2469
|
// 获取默认账户 ID
|
|
2391
|
-
defaultAccountId: () =>
|
|
2470
|
+
defaultAccountId: () => DEFAULT_ACCOUNT_ID,
|
|
2392
2471
|
// 设置账户启用状态
|
|
2393
2472
|
setAccountEnabled: ({ cfg, enabled }) => {
|
|
2394
2473
|
const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
@@ -2444,7 +2523,7 @@ const wecomPlugin = {
|
|
|
2444
2523
|
allowFrom: account.config.allowFrom ?? [],
|
|
2445
2524
|
policyPath: `${basePath}dmPolicy`,
|
|
2446
2525
|
allowFromPath: basePath,
|
|
2447
|
-
approveHint:
|
|
2526
|
+
approveHint: formatPairingApproveHint(CHANNEL_ID),
|
|
2448
2527
|
normalizeEntry: (raw) => raw.replace(new RegExp(`^${CHANNEL_ID}:`, "i"), "").trim(),
|
|
2449
2528
|
};
|
|
2450
2529
|
},
|
|
@@ -2500,7 +2579,7 @@ const wecomPlugin = {
|
|
|
2500
2579
|
return sendWeComMessage({ to, content: text, accountId: accountId ?? undefined });
|
|
2501
2580
|
},
|
|
2502
2581
|
sendMedia: async ({ to, text, mediaUrl, mediaLocalRoots, accountId }) => {
|
|
2503
|
-
const resolvedAccountId = accountId ??
|
|
2582
|
+
const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
2504
2583
|
const channelPrefix = new RegExp(`^${CHANNEL_ID}:`, "i");
|
|
2505
2584
|
const chatId = to.replace(channelPrefix, "");
|
|
2506
2585
|
// 获取 WSClient 实例
|
|
@@ -2545,14 +2624,14 @@ const wecomPlugin = {
|
|
|
2545
2624
|
},
|
|
2546
2625
|
status: {
|
|
2547
2626
|
defaultRuntime: {
|
|
2548
|
-
accountId:
|
|
2627
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
2549
2628
|
running: false,
|
|
2550
2629
|
lastStartAt: null,
|
|
2551
2630
|
lastStopAt: null,
|
|
2552
2631
|
lastError: null,
|
|
2553
2632
|
},
|
|
2554
2633
|
collectStatusIssues: (accounts) => accounts.flatMap((entry) => {
|
|
2555
|
-
const accountId = String(entry.accountId ??
|
|
2634
|
+
const accountId = String(entry.accountId ?? DEFAULT_ACCOUNT_ID);
|
|
2556
2635
|
const enabled = entry.enabled !== false;
|
|
2557
2636
|
const configured = entry.configured === true;
|
|
2558
2637
|
if (!enabled) {
|
|
@@ -2719,7 +2798,7 @@ const inflightInitRequests = new Map();
|
|
|
2719
2798
|
* @returns 完整的 response.body 配置对象(至少包含 url 字段)
|
|
2720
2799
|
*/
|
|
2721
2800
|
async function fetchMcpConfig(category) {
|
|
2722
|
-
const wsClient = getWeComWebSocket(
|
|
2801
|
+
const wsClient = getWeComWebSocket(DEFAULT_ACCOUNT_ID);
|
|
2723
2802
|
if (!wsClient) {
|
|
2724
2803
|
throw new Error("WSClient 未连接,无法拉取 MCP 配置");
|
|
2725
2804
|
}
|
|
@@ -3460,7 +3539,7 @@ const plugin = {
|
|
|
3460
3539
|
id: "wecom-openclaw-plugin",
|
|
3461
3540
|
name: "企业微信",
|
|
3462
3541
|
description: "企业微信 OpenClaw 插件",
|
|
3463
|
-
configSchema:
|
|
3542
|
+
configSchema: emptyPluginConfigSchema(),
|
|
3464
3543
|
register(api) {
|
|
3465
3544
|
setWeComRuntime(api.runtime);
|
|
3466
3545
|
api.registerChannel({ plugin: wecomPlugin });
|