@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 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
- let runtime = null;
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: core.DEFAULT_ACCOUNT_ID,
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
- * 企业微信 onboarding adapter for CLI setup wizard.
2210
- */
2211
- const channel = CHANNEL_ID;
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
- async function promptSecret(prompter, account) {
2236
- return String(await prompter.text({
2237
- message: "企业微信机器人 Secret",
2238
- initialValue: account?.secret ?? "",
2239
- validate: (value) => (value?.trim() ? undefined : "Required"),
2240
- })).trim();
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 或 group456",
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
- const wecomOnboardingAdapter = {
2284
- channel,
2285
- getStatus: async ({ cfg }) => {
2286
- const account = resolveWeComAccount(cfg);
2287
- const configured = Boolean(account.botId?.trim() &&
2288
- account.secret?.trim());
2289
- return {
2290
- channel,
2291
- configured,
2292
- statusLines: [`企业微信: ${configured ? "已配置" : "需要 Bot ID 和 Secret"}`],
2293
- selectionHint: configured ? "已配置" : "需要设置",
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
- configure: async ({ cfg, prompter, forceAllowFrom }) => {
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 (!account.botId?.trim() || !account.secret?.trim()) {
2299
- await noteWeComSetupHelp(prompter);
2300
- }
2301
- // 提示输入必要的配置信息:Bot ID 和 Secret
2302
- const botId = await promptBotId(prompter, account);
2303
- const secret = await promptSecret(prompter, account);
2304
- // 使用默认值配置其他选项
2305
- const cfgWithAccount = setWeComAccount(cfg, {
2306
- botId,
2307
- secret,
2308
- enabled: true,
2309
- dmPolicy: account.config.dmPolicy ?? "open",
2310
- allowFrom: account.config.allowFrom ?? [],
2311
- });
2312
- return { cfg: cfgWithAccount };
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 ?? core.DEFAULT_ACCOUNT_ID;
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
- onboarding: wecomOnboardingAdapter,
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: () => [core.DEFAULT_ACCOUNT_ID],
2466
+ listAccountIds: () => [DEFAULT_ACCOUNT_ID],
2388
2467
  // 解析账户配置
2389
2468
  resolveAccount: (cfg) => resolveWeComAccount(cfg),
2390
2469
  // 获取默认账户 ID
2391
- defaultAccountId: () => core.DEFAULT_ACCOUNT_ID,
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: core.formatPairingApproveHint(CHANNEL_ID),
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 ?? core.DEFAULT_ACCOUNT_ID;
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: core.DEFAULT_ACCOUNT_ID,
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 ?? core.DEFAULT_ACCOUNT_ID);
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(core.DEFAULT_ACCOUNT_ID);
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: core.emptyPluginConfigSchema(),
3542
+ configSchema: emptyPluginConfigSchema(),
3464
3543
  register(api) {
3465
3544
  setWeComRuntime(api.runtime);
3466
3545
  api.registerChannel({ plugin: wecomPlugin });