@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 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
- let runtime = null;
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: core.DEFAULT_ACCOUNT_ID,
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 ?? core.DEFAULT_ACCOUNT_ID;
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: () => [core.DEFAULT_ACCOUNT_ID],
2231
+ listAccountIds: () => [DEFAULT_ACCOUNT_ID],
2341
2232
  // 解析账户配置
2342
2233
  resolveAccount: (cfg) => resolveWeComAccount(cfg),
2343
2234
  // 获取默认账户 ID
2344
- defaultAccountId: () => core.DEFAULT_ACCOUNT_ID,
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: core.formatPairingApproveHint(CHANNEL_ID),
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 ?? core.DEFAULT_ACCOUNT_ID;
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: core.DEFAULT_ACCOUNT_ID,
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 ?? core.DEFAULT_ACCOUNT_ID);
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(core.DEFAULT_ACCOUNT_ID);
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: core.emptyPluginConfigSchema(),
3307
+ configSchema: emptyPluginConfigSchema(),
3417
3308
  register(api) {
3418
3309
  setWeComRuntime(api.runtime);
3419
3310
  api.registerChannel({ plugin: wecomPlugin });