@wecom/wecom-openclaw-plugin 1.0.0 → 1.0.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 +76 -78
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +76 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/src/message-sender.d.ts +1 -1
- package/dist/src/utils.d.ts +0 -22
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -81,73 +81,6 @@ const DEFAULT_MEDIA_MAX_MB = 5;
|
|
|
81
81
|
/** 文本分块大小上限 */
|
|
82
82
|
const TEXT_CHUNK_LIMIT = 4000;
|
|
83
83
|
|
|
84
|
-
/**
|
|
85
|
-
* 企业微信公共工具函数
|
|
86
|
-
*/
|
|
87
|
-
const DefaultWsUrl = "wss://openws.work.weixin.qq.com";
|
|
88
|
-
/**
|
|
89
|
-
* 解析企业微信账户配置
|
|
90
|
-
*/
|
|
91
|
-
function resolveWeComAccount(cfg) {
|
|
92
|
-
const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
93
|
-
return {
|
|
94
|
-
accountId: pluginSdk.DEFAULT_ACCOUNT_ID,
|
|
95
|
-
name: wecomConfig.name ?? "企业微信",
|
|
96
|
-
enabled: wecomConfig.enabled ?? false,
|
|
97
|
-
websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,
|
|
98
|
-
botId: wecomConfig.botId ?? "",
|
|
99
|
-
secret: wecomConfig.secret ?? "",
|
|
100
|
-
sendThinkingMessage: wecomConfig.sendThinkingMessage ?? true,
|
|
101
|
-
config: wecomConfig,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* 设置企业微信账户配置
|
|
106
|
-
*/
|
|
107
|
-
function setWeComAccount(cfg, account) {
|
|
108
|
-
const existing = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
109
|
-
const merged = {
|
|
110
|
-
enabled: account.enabled ?? existing?.enabled ?? true,
|
|
111
|
-
botId: account.botId ?? existing?.botId ?? "",
|
|
112
|
-
secret: account.secret ?? existing?.secret ?? "",
|
|
113
|
-
allowFrom: account.allowFrom ?? existing?.allowFrom,
|
|
114
|
-
dmPolicy: account.dmPolicy ?? existing?.dmPolicy,
|
|
115
|
-
// 以下字段仅在已有配置值或显式传入时才写入,onboarding 时不主动生成
|
|
116
|
-
...(account.websocketUrl || existing?.websocketUrl
|
|
117
|
-
? { websocketUrl: account.websocketUrl ?? existing?.websocketUrl }
|
|
118
|
-
: {}),
|
|
119
|
-
...(account.name || existing?.name
|
|
120
|
-
? { name: account.name ?? existing?.name }
|
|
121
|
-
: {}),
|
|
122
|
-
...(account.sendThinkingMessage !== undefined || existing?.sendThinkingMessage !== undefined
|
|
123
|
-
? { sendThinkingMessage: account.sendThinkingMessage ?? existing?.sendThinkingMessage }
|
|
124
|
-
: {}),
|
|
125
|
-
};
|
|
126
|
-
return {
|
|
127
|
-
...cfg,
|
|
128
|
-
channels: {
|
|
129
|
-
...cfg.channels,
|
|
130
|
-
[CHANNEL_ID]: merged,
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* 生成随机字符串
|
|
136
|
-
*/
|
|
137
|
-
function generateRandomString(length = 9) {
|
|
138
|
-
return Math.random().toString(36).substr(2, length);
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* 生成企业微信请求 ID
|
|
142
|
-
* @param prefix - 请求类型前缀(subscribe, ping, response 等)
|
|
143
|
-
* @returns 格式化的请求 ID
|
|
144
|
-
*/
|
|
145
|
-
function generateReqId(prefix) {
|
|
146
|
-
const timestamp = Date.now();
|
|
147
|
-
const random = generateRandomString();
|
|
148
|
-
return `${prefix}_${timestamp}_${random}`;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
84
|
/**
|
|
152
85
|
* 企业微信消息内容解析模块
|
|
153
86
|
*
|
|
@@ -286,7 +219,7 @@ async function sendWeComReply(params) {
|
|
|
286
219
|
if (!text) {
|
|
287
220
|
return "";
|
|
288
221
|
}
|
|
289
|
-
const streamId = existingStreamId || generateReqId("stream");
|
|
222
|
+
const streamId = existingStreamId || aibotNodeSdk.generateReqId("stream");
|
|
290
223
|
if (!wsClient.isConnected) {
|
|
291
224
|
runtime.error?.(`[WeCom] WSClient not connected, cannot send reply`);
|
|
292
225
|
throw new Error("WSClient not connected");
|
|
@@ -571,10 +504,14 @@ async function checkDmPolicy(params) {
|
|
|
571
504
|
if (dmPolicy === "open") {
|
|
572
505
|
return { allowed: true };
|
|
573
506
|
}
|
|
574
|
-
//
|
|
575
|
-
const
|
|
507
|
+
// OpenClaw <= 2026.2.19 signature: readAllowFromStore(channel, env?, accountId?)
|
|
508
|
+
const oldStoreAllowFrom = await core.channel.pairing.readAllowFromStore('wecom', undefined, account.accountId).catch(() => []);
|
|
509
|
+
// Compatibility fallback for newer OpenClaw implementations.
|
|
510
|
+
const newStoreAllowFrom = await core.channel.pairing
|
|
576
511
|
.readAllowFromStore({ channel: CHANNEL_ID, accountId: account.accountId })
|
|
577
512
|
.catch(() => []);
|
|
513
|
+
// 检查发送者是否在允许列表中
|
|
514
|
+
const storeAllowFrom = [...oldStoreAllowFrom, ...newStoreAllowFrom];
|
|
578
515
|
const effectiveAllowFrom = [...configAllowFrom, ...storeAllowFrom];
|
|
579
516
|
const senderAllowedResult = isSenderAllowed(senderId, effectiveAllowFrom);
|
|
580
517
|
if (senderAllowedResult) {
|
|
@@ -1080,7 +1017,7 @@ function buildMessageContext(frame, account, config, text, mediaList, quoteConte
|
|
|
1080
1017
|
MediaPaths: mediaPaths,
|
|
1081
1018
|
MediaTypes: mediaTypes,
|
|
1082
1019
|
MediaUrls: mediaPaths,
|
|
1083
|
-
|
|
1020
|
+
ReplyToBody: quoteContent,
|
|
1084
1021
|
});
|
|
1085
1022
|
}
|
|
1086
1023
|
// ============================================================================
|
|
@@ -1112,6 +1049,14 @@ async function sendThinkingReply(params) {
|
|
|
1112
1049
|
async function routeAndDispatchMessage(params) {
|
|
1113
1050
|
const { ctxPayload, config, wsClient, frame, state, runtime, onCleanup } = params;
|
|
1114
1051
|
const core = getWeComRuntime();
|
|
1052
|
+
// 防止 onCleanup 被多次调用(onError 回调与 catch 块可能重复触发)
|
|
1053
|
+
let cleanedUp = false;
|
|
1054
|
+
const safeCleanup = () => {
|
|
1055
|
+
if (!cleanedUp) {
|
|
1056
|
+
cleanedUp = true;
|
|
1057
|
+
onCleanup();
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1115
1060
|
try {
|
|
1116
1061
|
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
1117
1062
|
ctx: ctxPayload,
|
|
@@ -1132,7 +1077,7 @@ async function routeAndDispatchMessage(params) {
|
|
|
1132
1077
|
},
|
|
1133
1078
|
onError: (err, info) => {
|
|
1134
1079
|
runtime.error?.(`[WeCom] ${info.kind} reply failed: ${String(err)}`);
|
|
1135
|
-
|
|
1080
|
+
// 仅记录错误,不立即 cleanup,让外层 try/catch 统一处理最终回复和 cleanup
|
|
1136
1081
|
},
|
|
1137
1082
|
},
|
|
1138
1083
|
});
|
|
@@ -1147,11 +1092,11 @@ async function routeAndDispatchMessage(params) {
|
|
|
1147
1092
|
streamId: state.streamId,
|
|
1148
1093
|
});
|
|
1149
1094
|
}
|
|
1150
|
-
|
|
1095
|
+
safeCleanup();
|
|
1151
1096
|
}
|
|
1152
1097
|
catch (err) {
|
|
1153
1098
|
runtime.error?.(`[WeCom] Failed to process message: ${String(err)}`);
|
|
1154
|
-
|
|
1099
|
+
safeCleanup();
|
|
1155
1100
|
}
|
|
1156
1101
|
}
|
|
1157
1102
|
/**
|
|
@@ -1240,7 +1185,7 @@ async function processWeComMessage(params) {
|
|
|
1240
1185
|
const mediaList = [...imageMediaList, ...fileMediaList];
|
|
1241
1186
|
// Step 5: 初始化消息状态
|
|
1242
1187
|
setReqIdForChat(chatId, reqId, account.accountId);
|
|
1243
|
-
const streamId = generateReqId("stream");
|
|
1188
|
+
const streamId = aibotNodeSdk.generateReqId("stream");
|
|
1244
1189
|
const state = { accumulatedText: "", streamId };
|
|
1245
1190
|
setMessageState(messageId, state);
|
|
1246
1191
|
const cleanupState = () => {
|
|
@@ -1366,19 +1311,72 @@ async function monitorWeComProvider(options) {
|
|
|
1366
1311
|
runtime.error?.(`[${account.accountId}] Failed to process message: ${String(err)}`);
|
|
1367
1312
|
}
|
|
1368
1313
|
});
|
|
1369
|
-
// 启动前预热 reqId
|
|
1314
|
+
// 启动前预热 reqId 缓存,确保完成后再建立连接,避免 getSync 在预热完成前返回 undefined
|
|
1370
1315
|
warmupReqIdStore(account.accountId, (...args) => runtime.log?.(...args))
|
|
1371
1316
|
.then((count) => {
|
|
1372
1317
|
runtime.log?.(`[${account.accountId}] Warmed up ${count} reqId entries from disk`);
|
|
1373
1318
|
})
|
|
1374
1319
|
.catch((err) => {
|
|
1375
1320
|
runtime.error?.(`[${account.accountId}] Failed to warmup reqId store: ${String(err)}`);
|
|
1321
|
+
})
|
|
1322
|
+
.finally(() => {
|
|
1323
|
+
// 无论预热成功或失败,都建立连接
|
|
1324
|
+
wsClient.connect();
|
|
1376
1325
|
});
|
|
1377
|
-
// 建立连接
|
|
1378
|
-
wsClient.connect();
|
|
1379
1326
|
});
|
|
1380
1327
|
}
|
|
1381
1328
|
|
|
1329
|
+
/**
|
|
1330
|
+
* 企业微信公共工具函数
|
|
1331
|
+
*/
|
|
1332
|
+
const DefaultWsUrl = "wss://openws.work.weixin.qq.com";
|
|
1333
|
+
/**
|
|
1334
|
+
* 解析企业微信账户配置
|
|
1335
|
+
*/
|
|
1336
|
+
function resolveWeComAccount(cfg) {
|
|
1337
|
+
const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
1338
|
+
return {
|
|
1339
|
+
accountId: pluginSdk.DEFAULT_ACCOUNT_ID,
|
|
1340
|
+
name: wecomConfig.name ?? "企业微信",
|
|
1341
|
+
enabled: wecomConfig.enabled ?? false,
|
|
1342
|
+
websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,
|
|
1343
|
+
botId: wecomConfig.botId ?? "",
|
|
1344
|
+
secret: wecomConfig.secret ?? "",
|
|
1345
|
+
sendThinkingMessage: wecomConfig.sendThinkingMessage ?? true,
|
|
1346
|
+
config: wecomConfig,
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* 设置企业微信账户配置
|
|
1351
|
+
*/
|
|
1352
|
+
function setWeComAccount(cfg, account) {
|
|
1353
|
+
const existing = (cfg.channels?.[CHANNEL_ID] ?? {});
|
|
1354
|
+
const merged = {
|
|
1355
|
+
enabled: account.enabled ?? existing?.enabled ?? true,
|
|
1356
|
+
botId: account.botId ?? existing?.botId ?? "",
|
|
1357
|
+
secret: account.secret ?? existing?.secret ?? "",
|
|
1358
|
+
allowFrom: account.allowFrom ?? existing?.allowFrom,
|
|
1359
|
+
dmPolicy: account.dmPolicy ?? existing?.dmPolicy,
|
|
1360
|
+
// 以下字段仅在已有配置值或显式传入时才写入,onboarding 时不主动生成
|
|
1361
|
+
...(account.websocketUrl || existing?.websocketUrl
|
|
1362
|
+
? { websocketUrl: account.websocketUrl ?? existing?.websocketUrl }
|
|
1363
|
+
: {}),
|
|
1364
|
+
...(account.name || existing?.name
|
|
1365
|
+
? { name: account.name ?? existing?.name }
|
|
1366
|
+
: {}),
|
|
1367
|
+
...(account.sendThinkingMessage !== undefined || existing?.sendThinkingMessage !== undefined
|
|
1368
|
+
? { sendThinkingMessage: account.sendThinkingMessage ?? existing?.sendThinkingMessage }
|
|
1369
|
+
: {}),
|
|
1370
|
+
};
|
|
1371
|
+
return {
|
|
1372
|
+
...cfg,
|
|
1373
|
+
channels: {
|
|
1374
|
+
...cfg.channels,
|
|
1375
|
+
[CHANNEL_ID]: merged,
|
|
1376
|
+
},
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1382
1380
|
/**
|
|
1383
1381
|
* 企业微信 onboarding adapter for CLI setup wizard.
|
|
1384
1382
|
*/
|