@wecom/wecom-openclaw-plugin 2026.3.24-beta.1 → 2026.3.24-beta.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/dist/index.cjs.js +62 -171
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.esm.js +50 -159
- package/dist/index.esm.js.map +1 -1
- package/dist/src/openclaw-compat.d.ts +48 -0
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -2,17 +2,15 @@
|
|
|
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
|
-
var setup = require('openclaw/plugin-sdk/setup');
|
|
16
14
|
|
|
17
15
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
18
16
|
function _interopNamespaceDefault(e) {
|
|
@@ -32,22 +30,11 @@ function _interopNamespaceDefault(e) {
|
|
|
32
30
|
return Object.freeze(n);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
var os__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(os$1);
|
|
36
|
-
var path__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(path$1);
|
|
37
33
|
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
38
34
|
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
39
35
|
var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
function setWeComRuntime(r) {
|
|
43
|
-
runtime = r;
|
|
44
|
-
}
|
|
45
|
-
function getWeComRuntime() {
|
|
46
|
-
if (!runtime) {
|
|
47
|
-
throw new Error("WeCom runtime not initialized - plugin not registered");
|
|
48
|
-
}
|
|
49
|
-
return runtime;
|
|
50
|
-
}
|
|
36
|
+
var os__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(os$1);
|
|
37
|
+
var path__namespace$1 = /*#__PURE__*/_interopNamespaceDefault(path$1);
|
|
51
38
|
|
|
52
39
|
/**
|
|
53
40
|
* openclaw plugin-sdk 高版本方法兼容层
|
|
@@ -58,6 +45,7 @@ function getWeComRuntime() {
|
|
|
58
45
|
* 本模块在加载时一次性探测 SDK 导出,存在则直接 re-export SDK 版本,
|
|
59
46
|
* 不存在则导出 fallback 实现。其他模块统一从本文件导入,无需关心底层兼容细节。
|
|
60
47
|
*/
|
|
48
|
+
const DEFAULT_ACCOUNT_ID = "default";
|
|
61
49
|
const _sdkReady = import('openclaw/plugin-sdk/core')
|
|
62
50
|
.then((sdk) => {
|
|
63
51
|
const exports$1 = {};
|
|
@@ -70,12 +58,30 @@ const _sdkReady = import('openclaw/plugin-sdk/core')
|
|
|
70
58
|
if (typeof sdk.getDefaultMediaLocalRoots === "function") {
|
|
71
59
|
exports$1.getDefaultMediaLocalRoots = sdk.getDefaultMediaLocalRoots;
|
|
72
60
|
}
|
|
61
|
+
if (typeof sdk.addWildcardAllowFrom === "function") {
|
|
62
|
+
exports$1.addWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
63
|
+
}
|
|
73
64
|
return exports$1;
|
|
74
65
|
})
|
|
75
66
|
.catch(() => {
|
|
76
67
|
// openclaw/plugin-sdk 不可用或版本过低,全部使用 fallback
|
|
77
68
|
return {};
|
|
78
69
|
});
|
|
70
|
+
// 同时尝试从 plugin-sdk/setup 模块探测(缓存同步可用的引用)
|
|
71
|
+
let _cachedAddWildcardAllowFrom;
|
|
72
|
+
import('openclaw/plugin-sdk/setup')
|
|
73
|
+
.then((sdk) => {
|
|
74
|
+
if (typeof sdk.addWildcardAllowFrom === "function") {
|
|
75
|
+
_cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
.catch(() => { });
|
|
79
|
+
// 同时也从 core 模块的结果中缓存
|
|
80
|
+
_sdkReady.then((sdk) => {
|
|
81
|
+
if (!_cachedAddWildcardAllowFrom && sdk.addWildcardAllowFrom) {
|
|
82
|
+
_cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
79
85
|
// ============================================================================
|
|
80
86
|
// detectMime —— 检测 MIME 类型
|
|
81
87
|
// ============================================================================
|
|
@@ -352,6 +358,34 @@ async function getDefaultMediaLocalRoots() {
|
|
|
352
358
|
path__namespace.join(stateDir, "sandboxes"),
|
|
353
359
|
];
|
|
354
360
|
}
|
|
361
|
+
function emptyPluginConfigSchema() {
|
|
362
|
+
return {
|
|
363
|
+
type: 'object',
|
|
364
|
+
additionalProperties: false,
|
|
365
|
+
properties: {},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* 格式化配对审批提示信息(参考 moltbot 实现)
|
|
370
|
+
* @param channelId 频道ID
|
|
371
|
+
* @returns 配对审批提示字符串
|
|
372
|
+
*/
|
|
373
|
+
function formatPairingApproveHint(channelId) {
|
|
374
|
+
const listCmd = `openclaw pairing list ${channelId}`;
|
|
375
|
+
const approveCmd = `openclaw pairing approve ${channelId} <code>`;
|
|
376
|
+
return `向 ${channelId} 机器人发送消息以完成配对审批(命令行:${listCmd} / ${approveCmd})`;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
let runtime = null;
|
|
380
|
+
function setWeComRuntime(r) {
|
|
381
|
+
runtime = r;
|
|
382
|
+
}
|
|
383
|
+
function getWeComRuntime() {
|
|
384
|
+
if (!runtime) {
|
|
385
|
+
throw new Error("WeCom runtime not initialized - plugin not registered");
|
|
386
|
+
}
|
|
387
|
+
return runtime;
|
|
388
|
+
}
|
|
355
389
|
|
|
356
390
|
/**
|
|
357
391
|
* 企业微信渠道常量定义
|
|
@@ -2117,7 +2151,7 @@ const DefaultWsUrl = "wss://openws.work.weixin.qq.com";
|
|
|
2117
2151
|
function resolveWeComAccount(cfg) {
|
|
2118
2152
|
const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
2119
2153
|
return {
|
|
2120
|
-
accountId:
|
|
2154
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
2121
2155
|
name: wecomConfig.name ?? "企业微信",
|
|
2122
2156
|
enabled: wecomConfig.enabled ?? false,
|
|
2123
2157
|
websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,
|
|
@@ -2127,155 +2161,13 @@ function resolveWeComAccount(cfg) {
|
|
|
2127
2161
|
config: wecomConfig,
|
|
2128
2162
|
};
|
|
2129
2163
|
}
|
|
2130
|
-
/**
|
|
2131
|
-
* 设置企业微信账户配置
|
|
2132
|
-
*/
|
|
2133
|
-
function setWeComAccount(cfg, account) {
|
|
2134
|
-
const existing = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
2135
|
-
const merged = {
|
|
2136
|
-
enabled: account.enabled ?? existing?.enabled ?? true,
|
|
2137
|
-
botId: account.botId ?? existing?.botId ?? "",
|
|
2138
|
-
secret: account.secret ?? existing?.secret ?? "",
|
|
2139
|
-
allowFrom: account.allowFrom ?? existing?.allowFrom,
|
|
2140
|
-
dmPolicy: account.dmPolicy ?? existing?.dmPolicy,
|
|
2141
|
-
// 以下字段仅在已有配置值或显式传入时才写入,onboarding 时不主动生成
|
|
2142
|
-
...(account.websocketUrl || existing?.websocketUrl
|
|
2143
|
-
? { websocketUrl: account.websocketUrl ?? existing?.websocketUrl }
|
|
2144
|
-
: {}),
|
|
2145
|
-
...(account.name || existing?.name
|
|
2146
|
-
? { name: account.name ?? existing?.name }
|
|
2147
|
-
: {}),
|
|
2148
|
-
...(account.sendThinkingMessage !== undefined || existing?.sendThinkingMessage !== undefined
|
|
2149
|
-
? { sendThinkingMessage: account.sendThinkingMessage ?? existing?.sendThinkingMessage }
|
|
2150
|
-
: {}),
|
|
2151
|
-
};
|
|
2152
|
-
return {
|
|
2153
|
-
...cfg,
|
|
2154
|
-
channels: {
|
|
2155
|
-
...cfg.channels,
|
|
2156
|
-
[CHANNEL_ID]: merged,
|
|
2157
|
-
},
|
|
2158
|
-
};
|
|
2159
|
-
}
|
|
2160
|
-
|
|
2161
|
-
/**
|
|
2162
|
-
* 企业微信 onboarding adapter for CLI setup wizard.
|
|
2163
|
-
*/
|
|
2164
|
-
const channel = CHANNEL_ID;
|
|
2165
|
-
/**
|
|
2166
|
-
* 企业微信设置帮助说明
|
|
2167
|
-
*/
|
|
2168
|
-
async function noteWeComSetupHelp(prompter) {
|
|
2169
|
-
await prompter.note([
|
|
2170
|
-
"企业微信机器人需要以下配置信息:",
|
|
2171
|
-
"1. Bot ID: 企业微信机器人id",
|
|
2172
|
-
"2. Secret: 企业微信机器人密钥",
|
|
2173
|
-
].join("\n"), "企业微信设置");
|
|
2174
|
-
}
|
|
2175
|
-
/**
|
|
2176
|
-
* 提示输入 Bot ID
|
|
2177
|
-
*/
|
|
2178
|
-
async function promptBotId(prompter, account) {
|
|
2179
|
-
return String(await prompter.text({
|
|
2180
|
-
message: "企业微信机器人 Bot ID",
|
|
2181
|
-
initialValue: account?.botId ?? "",
|
|
2182
|
-
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
2183
|
-
})).trim();
|
|
2184
|
-
}
|
|
2185
|
-
/**
|
|
2186
|
-
* 提示输入 Secret
|
|
2187
|
-
*/
|
|
2188
|
-
async function promptSecret(prompter, account) {
|
|
2189
|
-
return String(await prompter.text({
|
|
2190
|
-
message: "企业微信机器人 Secret",
|
|
2191
|
-
initialValue: account?.secret ?? "",
|
|
2192
|
-
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
2193
|
-
})).trim();
|
|
2194
|
-
}
|
|
2195
|
-
/**
|
|
2196
|
-
* 设置企业微信 dmPolicy
|
|
2197
|
-
*/
|
|
2198
|
-
function setWeComDmPolicy(cfg, dmPolicy) {
|
|
2199
|
-
const account = resolveWeComAccount(cfg);
|
|
2200
|
-
const existingAllowFrom = account.config.allowFrom ?? [];
|
|
2201
|
-
const allowFrom = dmPolicy === "open"
|
|
2202
|
-
? setup.addWildcardAllowFrom(existingAllowFrom.map((x) => String(x)))
|
|
2203
|
-
: existingAllowFrom.map((x) => String(x));
|
|
2204
|
-
return setWeComAccount(cfg, {
|
|
2205
|
-
dmPolicy,
|
|
2206
|
-
allowFrom,
|
|
2207
|
-
});
|
|
2208
|
-
}
|
|
2209
|
-
const dmPolicy = {
|
|
2210
|
-
label: "企业微信",
|
|
2211
|
-
channel,
|
|
2212
|
-
policyKey: `channels.${CHANNEL_ID}.dmPolicy`,
|
|
2213
|
-
allowFromKey: `channels.${CHANNEL_ID}.allowFrom`,
|
|
2214
|
-
getCurrent: (cfg) => {
|
|
2215
|
-
const account = resolveWeComAccount(cfg);
|
|
2216
|
-
return account.config.dmPolicy ?? "open";
|
|
2217
|
-
},
|
|
2218
|
-
setPolicy: (cfg, policy) => {
|
|
2219
|
-
return setWeComDmPolicy(cfg, policy);
|
|
2220
|
-
},
|
|
2221
|
-
promptAllowFrom: async ({ cfg, prompter }) => {
|
|
2222
|
-
const account = resolveWeComAccount(cfg);
|
|
2223
|
-
const existingAllowFrom = account.config.allowFrom ?? [];
|
|
2224
|
-
const entry = await prompter.text({
|
|
2225
|
-
message: "企业微信允许来源(用户ID或群组ID,每行一个,推荐用于安全控制)",
|
|
2226
|
-
placeholder: "user123 或 group456",
|
|
2227
|
-
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
|
2228
|
-
});
|
|
2229
|
-
const allowFrom = String(entry ?? "")
|
|
2230
|
-
.split(/[\n,;]+/g)
|
|
2231
|
-
.map((s) => s.trim())
|
|
2232
|
-
.filter(Boolean);
|
|
2233
|
-
return setWeComAccount(cfg, { allowFrom });
|
|
2234
|
-
},
|
|
2235
|
-
};
|
|
2236
|
-
const wecomOnboardingAdapter = {
|
|
2237
|
-
channel,
|
|
2238
|
-
getStatus: async ({ cfg }) => {
|
|
2239
|
-
const account = resolveWeComAccount(cfg);
|
|
2240
|
-
const configured = Boolean(account.botId?.trim() &&
|
|
2241
|
-
account.secret?.trim());
|
|
2242
|
-
return {
|
|
2243
|
-
channel,
|
|
2244
|
-
configured,
|
|
2245
|
-
statusLines: [`企业微信: ${configured ? "已配置" : "需要 Bot ID 和 Secret"}`],
|
|
2246
|
-
selectionHint: configured ? "已配置" : "需要设置",
|
|
2247
|
-
};
|
|
2248
|
-
},
|
|
2249
|
-
configure: async ({ cfg, prompter, forceAllowFrom }) => {
|
|
2250
|
-
const account = resolveWeComAccount(cfg);
|
|
2251
|
-
if (!account.botId?.trim() || !account.secret?.trim()) {
|
|
2252
|
-
await noteWeComSetupHelp(prompter);
|
|
2253
|
-
}
|
|
2254
|
-
// 提示输入必要的配置信息:Bot ID 和 Secret
|
|
2255
|
-
const botId = await promptBotId(prompter, account);
|
|
2256
|
-
const secret = await promptSecret(prompter, account);
|
|
2257
|
-
// 使用默认值配置其他选项
|
|
2258
|
-
const cfgWithAccount = setWeComAccount(cfg, {
|
|
2259
|
-
botId,
|
|
2260
|
-
secret,
|
|
2261
|
-
enabled: true,
|
|
2262
|
-
dmPolicy: account.config.dmPolicy ?? "open",
|
|
2263
|
-
allowFrom: account.config.allowFrom ?? [],
|
|
2264
|
-
});
|
|
2265
|
-
return { cfg: cfgWithAccount };
|
|
2266
|
-
},
|
|
2267
|
-
dmPolicy,
|
|
2268
|
-
disable: (cfg) => {
|
|
2269
|
-
return setWeComAccount(cfg, { enabled: false });
|
|
2270
|
-
},
|
|
2271
|
-
};
|
|
2272
2164
|
|
|
2273
2165
|
/**
|
|
2274
2166
|
* 使用 SDK 的 sendMessage 主动发送企业微信消息
|
|
2275
2167
|
* 无需依赖 reqId,直接向指定会话推送消息
|
|
2276
2168
|
*/
|
|
2277
2169
|
async function sendWeComMessage({ to, content, accountId, }) {
|
|
2278
|
-
const resolvedAccountId = accountId ??
|
|
2170
|
+
const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
2279
2171
|
// 从 to 中提取 chatId(格式是 "${CHANNEL_ID}:chatId" 或直接是 chatId)
|
|
2280
2172
|
const channelPrefix = new RegExp(`^${CHANNEL_ID}:`, "i");
|
|
2281
2173
|
const chatId = to.replace(channelPrefix, "");
|
|
@@ -2325,7 +2217,6 @@ const wecomPlugin = {
|
|
|
2325
2217
|
// Pairing approved for user
|
|
2326
2218
|
},
|
|
2327
2219
|
},
|
|
2328
|
-
onboarding: wecomOnboardingAdapter,
|
|
2329
2220
|
capabilities: {
|
|
2330
2221
|
chatTypes: ["direct", "group"],
|
|
2331
2222
|
reactions: false,
|
|
@@ -2337,11 +2228,11 @@ const wecomPlugin = {
|
|
|
2337
2228
|
reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },
|
|
2338
2229
|
config: {
|
|
2339
2230
|
// 列出所有账户 ID(最小实现只支持默认账户)
|
|
2340
|
-
listAccountIds: () => [
|
|
2231
|
+
listAccountIds: () => [DEFAULT_ACCOUNT_ID],
|
|
2341
2232
|
// 解析账户配置
|
|
2342
2233
|
resolveAccount: (cfg) => resolveWeComAccount(cfg),
|
|
2343
2234
|
// 获取默认账户 ID
|
|
2344
|
-
defaultAccountId: () =>
|
|
2235
|
+
defaultAccountId: () => DEFAULT_ACCOUNT_ID,
|
|
2345
2236
|
// 设置账户启用状态
|
|
2346
2237
|
setAccountEnabled: ({ cfg, enabled }) => {
|
|
2347
2238
|
const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
@@ -2397,7 +2288,7 @@ const wecomPlugin = {
|
|
|
2397
2288
|
allowFrom: account.config.allowFrom ?? [],
|
|
2398
2289
|
policyPath: `${basePath}dmPolicy`,
|
|
2399
2290
|
allowFromPath: basePath,
|
|
2400
|
-
approveHint:
|
|
2291
|
+
approveHint: formatPairingApproveHint(CHANNEL_ID),
|
|
2401
2292
|
normalizeEntry: (raw) => raw.replace(new RegExp(`^${CHANNEL_ID}:`, "i"), "").trim(),
|
|
2402
2293
|
};
|
|
2403
2294
|
},
|
|
@@ -2453,7 +2344,7 @@ const wecomPlugin = {
|
|
|
2453
2344
|
return sendWeComMessage({ to, content: text, accountId: accountId ?? undefined });
|
|
2454
2345
|
},
|
|
2455
2346
|
sendMedia: async ({ to, text, mediaUrl, mediaLocalRoots, accountId }) => {
|
|
2456
|
-
const resolvedAccountId = accountId ??
|
|
2347
|
+
const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
2457
2348
|
const channelPrefix = new RegExp(`^${CHANNEL_ID}:`, "i");
|
|
2458
2349
|
const chatId = to.replace(channelPrefix, "");
|
|
2459
2350
|
// 获取 WSClient 实例
|
|
@@ -2498,14 +2389,14 @@ const wecomPlugin = {
|
|
|
2498
2389
|
},
|
|
2499
2390
|
status: {
|
|
2500
2391
|
defaultRuntime: {
|
|
2501
|
-
accountId:
|
|
2392
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
2502
2393
|
running: false,
|
|
2503
2394
|
lastStartAt: null,
|
|
2504
2395
|
lastStopAt: null,
|
|
2505
2396
|
lastError: null,
|
|
2506
2397
|
},
|
|
2507
2398
|
collectStatusIssues: (accounts) => accounts.flatMap((entry) => {
|
|
2508
|
-
const accountId = String(entry.accountId ??
|
|
2399
|
+
const accountId = String(entry.accountId ?? DEFAULT_ACCOUNT_ID);
|
|
2509
2400
|
const enabled = entry.enabled !== false;
|
|
2510
2401
|
const configured = entry.configured === true;
|
|
2511
2402
|
if (!enabled) {
|
|
@@ -2672,7 +2563,7 @@ const inflightInitRequests = new Map();
|
|
|
2672
2563
|
* @returns 完整的 response.body 配置对象(至少包含 url 字段)
|
|
2673
2564
|
*/
|
|
2674
2565
|
async function fetchMcpConfig(category) {
|
|
2675
|
-
const wsClient = getWeComWebSocket(
|
|
2566
|
+
const wsClient = getWeComWebSocket(DEFAULT_ACCOUNT_ID);
|
|
2676
2567
|
if (!wsClient) {
|
|
2677
2568
|
throw new Error("WSClient 未连接,无法拉取 MCP 配置");
|
|
2678
2569
|
}
|
|
@@ -3413,7 +3304,7 @@ const plugin = {
|
|
|
3413
3304
|
id: "wecom-openclaw-plugin",
|
|
3414
3305
|
name: "企业微信",
|
|
3415
3306
|
description: "企业微信 OpenClaw 插件",
|
|
3416
|
-
configSchema:
|
|
3307
|
+
configSchema: emptyPluginConfigSchema(),
|
|
3417
3308
|
register(api) {
|
|
3418
3309
|
setWeComRuntime(api.runtime);
|
|
3419
3310
|
api.registerChannel({ plugin: wecomPlugin });
|