@wu529778790/open-im 1.8.3-beta.6 → 1.8.3-beta.8
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/config.d.ts +1 -22
- package/dist/config.js +7 -52
- package/dist/setup.js +30 -59
- package/dist/shared/ai-task.test.js +0 -4
- package/dist/wechat/client.d.ts +1 -5
- package/dist/wechat/client.js +5 -56
- package/dist/wechat/transport.d.ts +1 -3
- package/dist/wechat/transport.js +1 -2
- package/dist/wechat/workbuddy-transport.d.ts +6 -0
- package/dist/wechat/workbuddy-transport.js +82 -13
- package/package.json +1 -1
- package/dist/wechat/auth/device-bind.d.ts +0 -13
- package/dist/wechat/auth/device-bind.js +0 -75
- package/dist/wechat/auth/device-guid.d.ts +0 -5
- package/dist/wechat/auth/device-guid.js +0 -28
- package/dist/wechat/auth/environments.d.ts +0 -5
- package/dist/wechat/auth/environments.js +0 -21
- package/dist/wechat/auth/index.d.ts +0 -7
- package/dist/wechat/auth/index.js +0 -5
- package/dist/wechat/auth/qclaw-api.d.ts +0 -26
- package/dist/wechat/auth/qclaw-api.js +0 -100
- package/dist/wechat/auth/types.d.ts +0 -18
- package/dist/wechat/auth/types.js +0 -4
- package/dist/wechat/auth/wechat-login.d.ts +0 -17
- package/dist/wechat/auth/wechat-login.js +0 -168
- package/dist/wechat/qclaw-transport.d.ts +0 -66
- package/dist/wechat/qclaw-transport.js +0 -303
package/dist/config.d.ts
CHANGED
|
@@ -6,14 +6,8 @@ export interface Config {
|
|
|
6
6
|
telegramBotToken?: string;
|
|
7
7
|
feishuAppId?: string;
|
|
8
8
|
feishuAppSecret?: string;
|
|
9
|
-
|
|
10
|
-
wechatAppSecret?: string;
|
|
11
|
-
wechatToken?: string;
|
|
12
|
-
wechatJwtToken?: string;
|
|
13
|
-
wechatLoginKey?: string;
|
|
14
|
-
wechatGuid?: string;
|
|
9
|
+
/** WorkBuddy 用户 ID(可选,与 platforms.wechat.userId 二选一,环境变量 WECHAT_USER_ID) */
|
|
15
10
|
wechatUserId?: string;
|
|
16
|
-
wechatWsUrl?: string;
|
|
17
11
|
weworkCorpId?: string;
|
|
18
12
|
weworkSecret?: string;
|
|
19
13
|
weworkWsUrl?: string;
|
|
@@ -64,12 +58,6 @@ export interface Config {
|
|
|
64
58
|
wechat?: {
|
|
65
59
|
enabled: boolean;
|
|
66
60
|
aiCommand?: AiCommand;
|
|
67
|
-
loginMode?: 'qclaw' | 'workbuddy';
|
|
68
|
-
wsUrl?: string;
|
|
69
|
-
token?: string;
|
|
70
|
-
jwtToken?: string;
|
|
71
|
-
loginKey?: string;
|
|
72
|
-
guid?: string;
|
|
73
61
|
userId?: string;
|
|
74
62
|
allowedUserIds: string[];
|
|
75
63
|
workbuddyAccessToken?: string;
|
|
@@ -124,17 +112,8 @@ interface FilePlatformQQ {
|
|
|
124
112
|
}
|
|
125
113
|
interface FilePlatformWechat {
|
|
126
114
|
enabled?: boolean;
|
|
127
|
-
appId?: string;
|
|
128
|
-
appSecret?: string;
|
|
129
115
|
aiCommand?: AiCommand;
|
|
130
|
-
/** 连接模式:qclaw(QClaw JPRX 网关)或 workbuddy(Centrifuge) */
|
|
131
|
-
loginMode?: 'qclaw' | 'workbuddy';
|
|
132
|
-
token?: string;
|
|
133
|
-
jwtToken?: string;
|
|
134
|
-
loginKey?: string;
|
|
135
|
-
guid?: string;
|
|
136
116
|
userId?: string;
|
|
137
|
-
wsUrl?: string;
|
|
138
117
|
allowedUserIds?: string[];
|
|
139
118
|
workbuddyAccessToken?: string;
|
|
140
119
|
workbuddyRefreshToken?: string;
|
package/dist/config.js
CHANGED
|
@@ -179,10 +179,10 @@ export function needsSetup() {
|
|
|
179
179
|
return false;
|
|
180
180
|
if (process.env.QQ_BOT_APPID && process.env.QQ_BOT_SECRET)
|
|
181
181
|
return false;
|
|
182
|
-
if (process.env.
|
|
183
|
-
|
|
184
|
-
if (process.env.WECHAT_TOKEN && process.env.WECHAT_GUID && process.env.WECHAT_USER_ID)
|
|
182
|
+
if (process.env.WECHAT_WORKBUDDY_ACCESS_TOKEN &&
|
|
183
|
+
process.env.WECHAT_WORKBUDDY_REFRESH_TOKEN) {
|
|
185
184
|
return false;
|
|
185
|
+
}
|
|
186
186
|
if (process.env.WEWORK_CORP_ID && process.env.WEWORK_SECRET)
|
|
187
187
|
return false;
|
|
188
188
|
if (process.env.DINGTALK_CLIENT_ID && process.env.DINGTALK_CLIENT_SECRET)
|
|
@@ -197,8 +197,7 @@ export function needsSetup() {
|
|
|
197
197
|
const hasTelegram = !!tg?.botToken;
|
|
198
198
|
const hasFeishu = !!(fs?.appId && fs?.appSecret);
|
|
199
199
|
const hasQQ = !!(qq?.appId && qq?.secret);
|
|
200
|
-
|
|
201
|
-
const hasWechat = !!(wc?.token && wc?.guid && wc?.userId) || !!(wc?.appId && wc?.appSecret);
|
|
200
|
+
const hasWechat = !!(wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken);
|
|
202
201
|
// 企业微信只需要 corpId 和 secret
|
|
203
202
|
const hasWework = !!(ww?.corpId && ww?.secret);
|
|
204
203
|
const hasDingtalk = !!(dt?.clientId && dt?.clientSecret);
|
|
@@ -248,25 +247,8 @@ export function loadConfig() {
|
|
|
248
247
|
fileQQ?.appId;
|
|
249
248
|
const qqSecret = process.env.QQ_BOT_SECRET ??
|
|
250
249
|
fileQQ?.secret;
|
|
251
|
-
// 微信支持两种协议:
|
|
252
|
-
// 1. AGP 协议:token + guid + userId(推荐)
|
|
253
|
-
// 2. 标准协议:appId + appSecret
|
|
254
|
-
const wechatLoginMode = fileWechat?.loginMode ?? 'workbuddy';
|
|
255
|
-
const wechatToken = process.env.WECHAT_TOKEN ??
|
|
256
|
-
fileWechat?.token;
|
|
257
|
-
const wechatJwtToken = fileWechat?.jwtToken;
|
|
258
|
-
const wechatLoginKey = fileWechat?.loginKey;
|
|
259
|
-
const wechatGuid = process.env.WECHAT_GUID ??
|
|
260
|
-
fileWechat?.guid;
|
|
261
250
|
const wechatUserId = process.env.WECHAT_USER_ID ??
|
|
262
251
|
fileWechat?.userId;
|
|
263
|
-
const wechatAppId = process.env.WECHAT_APP_ID ??
|
|
264
|
-
fileWechat?.appId;
|
|
265
|
-
const wechatAppSecret = process.env.WECHAT_APP_SECRET ??
|
|
266
|
-
fileWechat?.appSecret;
|
|
267
|
-
const wechatWsUrl = process.env.WECHAT_WS_URL ??
|
|
268
|
-
fileWechat?.wsUrl;
|
|
269
|
-
// 微信 WorkBuddy 模式凭证(loginMode === 'workbuddy' 时使用)
|
|
270
252
|
const wechatWorkbuddyAccessToken = process.env.WECHAT_WORKBUDDY_ACCESS_TOKEN ??
|
|
271
253
|
fileWechat?.workbuddyAccessToken;
|
|
272
254
|
const wechatWorkbuddyRefreshToken = process.env.WECHAT_WORKBUDDY_REFRESH_TOKEN ??
|
|
@@ -312,15 +294,8 @@ export function loadConfig() {
|
|
|
312
294
|
const telegramEnabled = !!telegramBotToken && (telegramEnabledFlag !== false);
|
|
313
295
|
const feishuEnabled = !!(feishuAppId && feishuAppSecret) && (feishuEnabledFlag !== false);
|
|
314
296
|
const qqEnabled = !!(qqAppId && qqSecret) && (qqEnabledFlag !== false);
|
|
315
|
-
// 微信启用条件:
|
|
316
|
-
// - qclaw 模式:AGP 协议凭证(token + guid + userId)或 标准协议凭证(appId + appSecret)
|
|
317
|
-
// - workbuddy 模式:workbuddy OAuth 凭证
|
|
318
|
-
const hasWechatAGPCreds = !!(wechatToken && wechatGuid && wechatUserId);
|
|
319
|
-
const hasWechatStandardCreds = !!(wechatAppId && wechatAppSecret);
|
|
320
297
|
const hasWechatWorkbuddyCreds = !!(wechatWorkbuddyAccessToken && wechatWorkbuddyRefreshToken);
|
|
321
|
-
const wechatEnabled = (
|
|
322
|
-
? hasWechatWorkbuddyCreds
|
|
323
|
-
: (hasWechatAGPCreds || hasWechatStandardCreds)) && (wechatEnabledFlag !== false);
|
|
298
|
+
const wechatEnabled = hasWechatWorkbuddyCreds && (wechatEnabledFlag !== false);
|
|
324
299
|
// 企业微信只需要 corpId (botId) 和 secret
|
|
325
300
|
const weworkEnabled = !!(weworkCorpId && weworkSecret) && (weworkEnabledFlag !== false);
|
|
326
301
|
const dingtalkEnabled = !!(dingtalkClientId && dingtalkClientSecret) && (dingtalkEnabledFlag !== false);
|
|
@@ -573,12 +548,6 @@ export function loadConfig() {
|
|
|
573
548
|
? {
|
|
574
549
|
enabled: true,
|
|
575
550
|
aiCommand: normalizeAiCommand(file.platforms?.wechat?.aiCommand, aiCommand),
|
|
576
|
-
loginMode: wechatLoginMode,
|
|
577
|
-
wsUrl: wechatWsUrl,
|
|
578
|
-
token: wechatToken,
|
|
579
|
-
jwtToken: wechatJwtToken,
|
|
580
|
-
loginKey: wechatLoginKey,
|
|
581
|
-
guid: wechatGuid,
|
|
582
551
|
userId: wechatUserId,
|
|
583
552
|
allowedUserIds: wechatAllowedUserIds,
|
|
584
553
|
workbuddyAccessToken: wechatWorkbuddyAccessToken,
|
|
@@ -589,12 +558,6 @@ export function loadConfig() {
|
|
|
589
558
|
: {
|
|
590
559
|
enabled: false,
|
|
591
560
|
aiCommand: normalizeAiCommand(file.platforms?.wechat?.aiCommand, aiCommand),
|
|
592
|
-
loginMode: wechatLoginMode,
|
|
593
|
-
wsUrl: wechatWsUrl,
|
|
594
|
-
token: wechatToken,
|
|
595
|
-
jwtToken: wechatJwtToken,
|
|
596
|
-
loginKey: wechatLoginKey,
|
|
597
|
-
guid: wechatGuid,
|
|
598
561
|
userId: wechatUserId,
|
|
599
562
|
allowedUserIds: wechatAllowedUserIds,
|
|
600
563
|
workbuddyAccessToken: wechatWorkbuddyAccessToken,
|
|
@@ -657,14 +620,7 @@ export function loadConfig() {
|
|
|
657
620
|
feishuAppSecret: feishuAppSecret ?? '',
|
|
658
621
|
qqAppId: qqAppId ?? '',
|
|
659
622
|
qqSecret: qqSecret ?? '',
|
|
660
|
-
wechatAppId: wechatAppId ?? '',
|
|
661
|
-
wechatAppSecret: wechatAppSecret ?? '',
|
|
662
|
-
wechatToken: wechatToken,
|
|
663
|
-
wechatJwtToken: wechatJwtToken,
|
|
664
|
-
wechatLoginKey: wechatLoginKey,
|
|
665
|
-
wechatGuid: wechatGuid,
|
|
666
623
|
wechatUserId: wechatUserId,
|
|
667
|
-
wechatWsUrl: wechatWsUrl,
|
|
668
624
|
weworkCorpId: weworkCorpId ?? '',
|
|
669
625
|
weworkSecret: weworkSecret ?? '',
|
|
670
626
|
weworkWsUrl: weworkWsUrl,
|
|
@@ -707,9 +663,8 @@ export function getPlatformsWithCredentials(config) {
|
|
|
707
663
|
r.push('wework');
|
|
708
664
|
if (config.dingtalkClientId && config.dingtalkClientSecret)
|
|
709
665
|
r.push('dingtalk');
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
if (hasWechat)
|
|
666
|
+
const wc = config.platforms.wechat;
|
|
667
|
+
if (wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken)
|
|
713
668
|
r.push('wechat');
|
|
714
669
|
return r;
|
|
715
670
|
}
|
package/dist/setup.js
CHANGED
|
@@ -43,9 +43,8 @@ function getConfiguredPlatforms(existing) {
|
|
|
43
43
|
return !!(p.appId && p.appSecret);
|
|
44
44
|
if (k === "qq")
|
|
45
45
|
return !!(p.appId && p.secret);
|
|
46
|
-
// 微信支持 AGP 协议(token + guid + userId)或标准协议(appId + appSecret)
|
|
47
46
|
if (k === "wechat")
|
|
48
|
-
return !!(p.
|
|
47
|
+
return !!(p.workbuddyAccessToken && p.workbuddyRefreshToken);
|
|
49
48
|
if (k === "wework")
|
|
50
49
|
return !!(p.corpId && p.secret);
|
|
51
50
|
if (k === "dingtalk")
|
|
@@ -116,16 +115,16 @@ function printManualInstructions(configPath) {
|
|
|
116
115
|
},
|
|
117
116
|
"wechat": {
|
|
118
117
|
"enabled": false,
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
118
|
+
"workbuddyAccessToken": "(由 open-im init 在浏览器完成 WorkBuddy 登录后自动写入)",
|
|
119
|
+
"workbuddyRefreshToken": "",
|
|
120
|
+
"userId": "",
|
|
122
121
|
"allowedUserIds": ["允许访问的微信用户 ID(可选)"]
|
|
123
122
|
}
|
|
124
123
|
}
|
|
125
124
|
}`);
|
|
126
125
|
console.log("");
|
|
127
126
|
console.log("提示:至少需要配置 Telegram、Feishu、QQ、WeChat、WeWork 或 DingTalk 其中一个平台");
|
|
128
|
-
console.log("或设置环境变量: TELEGRAM_BOT_TOKEN=xxx、FEISHU_APP_ID=xxx、QQ_BOT_APPID=xxx、
|
|
127
|
+
console.log("或设置环境变量: TELEGRAM_BOT_TOKEN=xxx、FEISHU_APP_ID=xxx、QQ_BOT_APPID=xxx、WECHAT_WORKBUDDY_ACCESS_TOKEN=xxx、WEWORK_CORP_ID=xxx 或 DINGTALK_CLIENT_ID=xxx 后再运行");
|
|
129
128
|
console.log("");
|
|
130
129
|
}
|
|
131
130
|
const CLAUDE_SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
|
|
@@ -274,7 +273,7 @@ export async function runInteractiveSetup() {
|
|
|
274
273
|
const hasFs = !!(existing?.platforms?.feishu?.appId && existing?.platforms?.feishu?.appSecret);
|
|
275
274
|
const hasQq = !!(existing?.platforms?.qq?.appId && existing?.platforms?.qq?.secret);
|
|
276
275
|
const wc = existing?.platforms?.wechat;
|
|
277
|
-
const hasWc = !!(wc?.
|
|
276
|
+
const hasWc = !!(wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken);
|
|
278
277
|
const hasWw = !!(existing?.platforms?.wework?.corpId && existing?.platforms?.wework?.secret);
|
|
279
278
|
const hasDt = !!(existing?.platforms?.dingtalk?.clientId && existing?.platforms?.dingtalk?.clientSecret);
|
|
280
279
|
// 第一步:选择平台(在选项和提示中显示已配置项)
|
|
@@ -423,30 +422,25 @@ export async function runInteractiveSetup() {
|
|
|
423
422
|
}
|
|
424
423
|
if (selectedPlatforms.includes("wechat")) {
|
|
425
424
|
const wc = existing?.platforms?.wechat;
|
|
426
|
-
const hasToken = !!(wc?.token && wc?.guid && wc?.userId);
|
|
427
425
|
const hasWbCreds = !!(wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken);
|
|
428
426
|
const wechatModeResp = await prompts({
|
|
429
427
|
type: "select",
|
|
430
428
|
name: "mode",
|
|
431
|
-
message: "
|
|
429
|
+
message: "微信(WorkBuddy / CodeBuddy OAuth)",
|
|
432
430
|
choices: [
|
|
433
431
|
{
|
|
434
|
-
title: "
|
|
435
|
-
value: "
|
|
432
|
+
title: "在浏览器中完成 CodeBuddy 登录并绑定微信客服(推荐)",
|
|
433
|
+
value: "oauth",
|
|
436
434
|
},
|
|
437
435
|
{
|
|
438
|
-
title: "
|
|
439
|
-
value: "qr",
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
title: "使用已有配置" + (hasToken || hasWbCreds ? " ✓" : "(需已配置)"),
|
|
436
|
+
title: "使用已有 WorkBuddy 凭证" + (hasWbCreds ? " ✓" : ""),
|
|
443
437
|
value: "keep",
|
|
444
|
-
disabled: !
|
|
438
|
+
disabled: !hasWbCreds,
|
|
445
439
|
},
|
|
446
440
|
],
|
|
447
|
-
initial: hasWbCreds ?
|
|
441
|
+
initial: hasWbCreds ? 1 : 0,
|
|
448
442
|
}, { onCancel });
|
|
449
|
-
if (wechatModeResp.mode === "
|
|
443
|
+
if (wechatModeResp.mode === "oauth") {
|
|
450
444
|
console.log("\n正在启动 WorkBuddy OAuth 登录...\n");
|
|
451
445
|
try {
|
|
452
446
|
const { WorkBuddyOAuth } = await import("./workbuddy/oauth.js");
|
|
@@ -466,14 +460,16 @@ export async function runInteractiveSetup() {
|
|
|
466
460
|
// account info is optional
|
|
467
461
|
}
|
|
468
462
|
const userId = accountInfo?.uid?.toString() ?? "";
|
|
463
|
+
// Set oauth.userId so buildSessionId() produces the correct sessionId.
|
|
464
|
+
// Without this, the binding sessionId has an empty userId prefix, which
|
|
465
|
+
// won't match the sessionId the transport uses at runtime.
|
|
466
|
+
oauth.userId = userId;
|
|
469
467
|
config.platforms.wechat = {
|
|
470
|
-
loginMode: 'workbuddy',
|
|
471
468
|
enabled: true,
|
|
472
469
|
workbuddyAccessToken: tokenResult.accessToken,
|
|
473
470
|
workbuddyRefreshToken: tokenResult.refreshToken,
|
|
474
471
|
userId,
|
|
475
472
|
};
|
|
476
|
-
// Step 3: WeChat KF binding
|
|
477
473
|
console.log("\n正在获取微信客服绑定链接...");
|
|
478
474
|
const sessionId = oauth.buildSessionId();
|
|
479
475
|
const linkResult = await oauth.getWeChatKfLink(sessionId);
|
|
@@ -501,34 +497,7 @@ export async function runInteractiveSetup() {
|
|
|
501
497
|
return false;
|
|
502
498
|
}
|
|
503
499
|
}
|
|
504
|
-
else if (
|
|
505
|
-
console.log("\n正在启动微信扫码登录...\n");
|
|
506
|
-
try {
|
|
507
|
-
const { performWeChatLogin } = await import("./wechat/auth/index.js");
|
|
508
|
-
const credentials = await performWeChatLogin({
|
|
509
|
-
envName: "production",
|
|
510
|
-
appId: wc?.appId || undefined,
|
|
511
|
-
});
|
|
512
|
-
config.platforms.wechat = {
|
|
513
|
-
loginMode: 'qclaw',
|
|
514
|
-
appId: wc?.appId,
|
|
515
|
-
enabled: true,
|
|
516
|
-
token: credentials.channelToken,
|
|
517
|
-
jwtToken: credentials.jwtToken,
|
|
518
|
-
loginKey: credentials.loginKey,
|
|
519
|
-
guid: credentials.guid,
|
|
520
|
-
userId: credentials.userId,
|
|
521
|
-
wsUrl: "wss://mmgrcalltoken.3g.qq.com/agentwss",
|
|
522
|
-
};
|
|
523
|
-
console.log("\n✅ 微信登录成功,配置已获取");
|
|
524
|
-
}
|
|
525
|
-
catch (err) {
|
|
526
|
-
console.error("\n❌ 微信登录失败:", err instanceof Error ? err.message : String(err));
|
|
527
|
-
if (platform === "wechat")
|
|
528
|
-
return false;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
else if (hasToken || hasWbCreds) {
|
|
500
|
+
else if (hasWbCreds) {
|
|
532
501
|
config.platforms.wechat = {
|
|
533
502
|
...wc,
|
|
534
503
|
enabled: true,
|
|
@@ -918,19 +887,21 @@ export async function runInteractiveSetup() {
|
|
|
918
887
|
}
|
|
919
888
|
if (selectedPlatforms.includes("wechat")) {
|
|
920
889
|
const wcConfig = config.platforms?.wechat;
|
|
921
|
-
|
|
922
|
-
|
|
890
|
+
const baseWc = base?.platforms?.wechat;
|
|
891
|
+
const wbOut = {
|
|
923
892
|
enabled: true,
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
jwtToken: wcConfig?.jwtToken ?? base?.platforms?.wechat?.jwtToken,
|
|
928
|
-
loginKey: wcConfig?.loginKey ?? base?.platforms?.wechat?.loginKey,
|
|
929
|
-
guid: wcConfig?.guid ?? base?.platforms?.wechat?.guid,
|
|
930
|
-
userId: wcConfig?.userId ?? base?.platforms?.wechat?.userId,
|
|
931
|
-
wsUrl: wcConfig?.wsUrl ?? base?.platforms?.wechat?.wsUrl,
|
|
893
|
+
workbuddyAccessToken: wcConfig?.workbuddyAccessToken ?? baseWc?.workbuddyAccessToken,
|
|
894
|
+
workbuddyRefreshToken: wcConfig?.workbuddyRefreshToken ?? baseWc?.workbuddyRefreshToken,
|
|
895
|
+
userId: wcConfig?.userId ?? baseWc?.userId ?? "",
|
|
932
896
|
allowedUserIds: wechatIds,
|
|
933
897
|
};
|
|
898
|
+
const wbBaseUrl = wcConfig?.workbuddyBaseUrl ?? baseWc?.workbuddyBaseUrl;
|
|
899
|
+
const wbHostId = wcConfig?.workbuddyHostId ?? baseWc?.workbuddyHostId;
|
|
900
|
+
if (wbBaseUrl)
|
|
901
|
+
wbOut.workbuddyBaseUrl = wbBaseUrl;
|
|
902
|
+
if (wbHostId)
|
|
903
|
+
wbOut.workbuddyHostId = wbHostId;
|
|
904
|
+
out.platforms.wechat = wbOut;
|
|
934
905
|
}
|
|
935
906
|
else if (basePlatforms?.wechat) {
|
|
936
907
|
outPlatforms.wechat = {
|
|
@@ -40,11 +40,7 @@ describe("runAITask", () => {
|
|
|
40
40
|
codebuddyTimeoutMs: 600000,
|
|
41
41
|
claudeModel: "",
|
|
42
42
|
codexProxy: "",
|
|
43
|
-
wechatToken: "",
|
|
44
|
-
wechatGuid: "",
|
|
45
43
|
wechatUserId: "",
|
|
46
|
-
wechatAppId: "",
|
|
47
|
-
wechatAppSecret: "",
|
|
48
44
|
dingtalkClientId: "",
|
|
49
45
|
dingtalkClientSecret: "",
|
|
50
46
|
qqAppId: "",
|
package/dist/wechat/client.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WeChat Client
|
|
3
|
-
*
|
|
4
|
-
* 支持两种通道:
|
|
5
|
-
* - workbuddy: 通过 Centrifuge WebSocket 连接(默认)
|
|
6
|
-
* - qclaw: 直连腾讯 JPRX 网关
|
|
2
|
+
* WeChat Client — 通过 WorkBuddy(CodeBuddy OAuth + Centrifuge)连接微信
|
|
7
3
|
*/
|
|
8
4
|
import type { Config } from '../config.js';
|
|
9
5
|
import type { AGPEnvelope, WeChatChannelState, WeChatToken } from './types.js';
|
package/dist/wechat/client.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WeChat Client
|
|
3
|
-
*
|
|
4
|
-
* 支持两种通道:
|
|
5
|
-
* - workbuddy: 通过 Centrifuge WebSocket 连接(默认)
|
|
6
|
-
* - qclaw: 直连腾讯 JPRX 网关
|
|
2
|
+
* WeChat Client — 通过 WorkBuddy(CodeBuddy OAuth + Centrifuge)连接微信
|
|
7
3
|
*/
|
|
8
|
-
import { readFileSync,
|
|
4
|
+
import { readFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
9
5
|
import { join } from 'node:path';
|
|
10
6
|
import { createLogger } from '../logger.js';
|
|
11
|
-
import { QClawTransport } from './qclaw-transport.js';
|
|
12
7
|
import { WorkBuddyTransport } from './workbuddy-transport.js';
|
|
13
8
|
const log = createLogger('WeChat');
|
|
14
9
|
const TOKEN_FILE = 'wechat-token.json';
|
|
@@ -17,7 +12,6 @@ let transport = null;
|
|
|
17
12
|
let channelState = 'disconnected';
|
|
18
13
|
let currentToken = null;
|
|
19
14
|
let tokenStoragePath = null;
|
|
20
|
-
let isStopping = false;
|
|
21
15
|
// Event handlers
|
|
22
16
|
let messageHandler = null;
|
|
23
17
|
let stateChangeHandler = null;
|
|
@@ -27,7 +21,6 @@ let stateChangeHandler = null;
|
|
|
27
21
|
export async function dispatchIncomingAGPEnvelope(envelope, handler) {
|
|
28
22
|
switch (envelope.method) {
|
|
29
23
|
case 'ping':
|
|
30
|
-
// Respond to ping with pong via transport
|
|
31
24
|
if (transport) {
|
|
32
25
|
transport.send('ping', { timestamp: Date.now() }, envelope.msg_id);
|
|
33
26
|
}
|
|
@@ -64,25 +57,14 @@ export function getCurrentToken() {
|
|
|
64
57
|
export async function initWeChat(config, eventHandler, onStateChange) {
|
|
65
58
|
messageHandler = eventHandler;
|
|
66
59
|
stateChangeHandler = onStateChange ?? null;
|
|
67
|
-
isStopping = false;
|
|
68
|
-
// Set up token storage path
|
|
69
60
|
const baseDir = config.logDir ?? join(process.env.HOME ?? '', '.open-im');
|
|
70
61
|
tokenStoragePath = join(baseDir, 'data');
|
|
71
62
|
if (!existsSync(tokenStoragePath)) {
|
|
72
63
|
mkdirSync(tokenStoragePath, { recursive: true });
|
|
73
64
|
}
|
|
74
|
-
// Load existing token if available
|
|
75
65
|
await loadToken();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
log.info(`Initializing WeChat with loginMode: ${loginMode}`);
|
|
79
|
-
if (loginMode === 'workbuddy') {
|
|
80
|
-
transport = createWorkBuddyTransport(config);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
transport = createQClawTransport(config);
|
|
84
|
-
}
|
|
85
|
-
// Wire up transport callbacks
|
|
66
|
+
log.info('Initializing WeChat (WorkBuddy)');
|
|
67
|
+
transport = createWorkBuddyTransport(config);
|
|
86
68
|
transport.onMessage(async (envelope) => {
|
|
87
69
|
await dispatchIncomingAGPEnvelope(envelope, messageHandler);
|
|
88
70
|
});
|
|
@@ -93,25 +75,8 @@ export async function initWeChat(config, eventHandler, onStateChange) {
|
|
|
93
75
|
}
|
|
94
76
|
});
|
|
95
77
|
await transport.start();
|
|
96
|
-
log.info(
|
|
78
|
+
log.info('WeChat client initialized (WorkBuddy)');
|
|
97
79
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Create QClaw transport from config
|
|
100
|
-
*/
|
|
101
|
-
function createQClawTransport(config) {
|
|
102
|
-
const qclawConfig = {
|
|
103
|
-
channelToken: config.wechatToken,
|
|
104
|
-
jwtToken: config.wechatJwtToken ?? config.platforms.wechat?.jwtToken,
|
|
105
|
-
loginKey: config.wechatLoginKey ?? config.platforms.wechat?.loginKey,
|
|
106
|
-
guid: config.wechatGuid,
|
|
107
|
-
userId: config.wechatUserId,
|
|
108
|
-
wsUrl: config.wechatWsUrl,
|
|
109
|
-
};
|
|
110
|
-
return new QClawTransport(qclawConfig);
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Create WorkBuddy transport from config
|
|
114
|
-
*/
|
|
115
80
|
function createWorkBuddyTransport(config) {
|
|
116
81
|
const wp = config.platforms.wechat;
|
|
117
82
|
const workbuddyConfig = {
|
|
@@ -137,7 +102,6 @@ export function sendAGPMessage(method, payload, replyTo) {
|
|
|
137
102
|
* Stop WeChat client
|
|
138
103
|
*/
|
|
139
104
|
export function stopWeChat() {
|
|
140
|
-
isStopping = true;
|
|
141
105
|
if (transport) {
|
|
142
106
|
transport.stop();
|
|
143
107
|
transport = null;
|
|
@@ -170,18 +134,3 @@ async function loadToken() {
|
|
|
170
134
|
}
|
|
171
135
|
}
|
|
172
136
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Save token to storage
|
|
175
|
-
*/
|
|
176
|
-
function saveToken() {
|
|
177
|
-
if (!currentToken || !tokenStoragePath)
|
|
178
|
-
return;
|
|
179
|
-
try {
|
|
180
|
-
const tokenPath = join(tokenStoragePath, TOKEN_FILE);
|
|
181
|
-
writeFileSync(tokenPath, JSON.stringify(currentToken, null, 2), 'utf-8');
|
|
182
|
-
log.info('Token saved to storage');
|
|
183
|
-
}
|
|
184
|
-
catch (err) {
|
|
185
|
-
log.error('Error saving token:', err);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WeChat Transport Interface
|
|
3
|
-
* 抽象 QClaw 和 WorkBuddy 两种 WebSocket 传输方式
|
|
2
|
+
* WeChat Transport Interface — WorkBuddy Centrifuge 实现
|
|
4
3
|
*/
|
|
5
4
|
import type { AGPEnvelope } from './types.js';
|
|
6
5
|
import type { WeChatChannelState } from './types.js';
|
|
@@ -11,7 +10,6 @@ export type StateChangeHandler = (state: WeChatChannelState) => void;
|
|
|
11
10
|
/**
|
|
12
11
|
* WeChat 传输接口
|
|
13
12
|
*
|
|
14
|
-
* 所有传输方式(QClaw WebSocket、WorkBuddy Centrifuge)都实现此接口。
|
|
15
13
|
* client.ts 通过此接口与传输层交互,无需关心底层协议。
|
|
16
14
|
*/
|
|
17
15
|
export interface WeChatTransport {
|
package/dist/wechat/transport.js
CHANGED
|
@@ -20,10 +20,16 @@ export declare class WorkBuddyTransport implements WeChatTransport {
|
|
|
20
20
|
private state;
|
|
21
21
|
private centrifugeClient;
|
|
22
22
|
private oauth;
|
|
23
|
+
private stopped;
|
|
24
|
+
private reconnectAttempt;
|
|
25
|
+
private reconnectTimer;
|
|
26
|
+
private heartbeatTimer;
|
|
23
27
|
private messageHandler;
|
|
24
28
|
private stateChangeHandler;
|
|
25
29
|
constructor(config: WorkBuddyTransportConfig);
|
|
26
30
|
start(): Promise<void>;
|
|
31
|
+
private connect;
|
|
32
|
+
private scheduleReconnect;
|
|
27
33
|
stop(): void;
|
|
28
34
|
send(method: string, payload: unknown, replyTo?: string): void;
|
|
29
35
|
onMessage(handler: MessageHandler): void;
|