@wu529778790/open-im 1.8.3-beta.7 → 1.8.3-beta.9
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/channels/capabilities.js +0 -5
- package/dist/channels/capabilities.test.js +1 -1
- package/dist/commands/handler.d.ts +2 -2
- package/dist/config-web.js +0 -1
- package/dist/config.d.ts +2 -15
- package/dist/config.js +20 -53
- package/dist/index.js +0 -22
- package/dist/setup.js +47 -49
- package/dist/workbuddy/centrifuge-client.js +13 -5
- package/dist/workbuddy/client.d.ts +4 -16
- package/dist/workbuddy/client.js +133 -93
- package/dist/workbuddy/oauth.d.ts +1 -1
- package/dist/workbuddy/oauth.js +4 -3
- package/package.json +1 -1
- package/dist/wechat/client.d.ts +0 -29
- package/dist/wechat/client.js +0 -136
- package/dist/wechat/client.test.d.ts +0 -1
- package/dist/wechat/client.test.js +0 -30
- package/dist/wechat/event-handler.d.ts +0 -11
- package/dist/wechat/event-handler.js +0 -286
- package/dist/wechat/message-sender.d.ts +0 -11
- package/dist/wechat/message-sender.js +0 -151
- package/dist/wechat/message-sender.test.d.ts +0 -1
- package/dist/wechat/message-sender.test.js +0 -35
- package/dist/wechat/transport.d.ts +0 -39
- package/dist/wechat/transport.js +0 -4
- package/dist/wechat/types.d.ts +0 -94
- package/dist/wechat/types.js +0 -5
- package/dist/wechat/workbuddy-transport.d.ts +0 -33
- package/dist/wechat/workbuddy-transport.js +0 -154
|
@@ -2,7 +2,6 @@ const PLATFORM_LABELS = {
|
|
|
2
2
|
telegram: "Telegram",
|
|
3
3
|
feishu: "Feishu",
|
|
4
4
|
qq: "QQ",
|
|
5
|
-
wechat: "微信",
|
|
6
5
|
wework: "企业微信",
|
|
7
6
|
dingtalk: "钉钉",
|
|
8
7
|
workbuddy: "WorkBuddy",
|
|
@@ -20,10 +19,6 @@ export const CHANNEL_CAPABILITIES = {
|
|
|
20
19
|
inbound: { text: "native", image: "fallback", file: "fallback", voice: "fallback", video: "fallback" },
|
|
21
20
|
outbound: { streamEdit: "none", streamPush: "none", image: "fallback", card: "fallback", typing: "fallback" },
|
|
22
21
|
},
|
|
23
|
-
wechat: {
|
|
24
|
-
inbound: { text: "native", image: "fallback", file: "fallback", voice: "fallback", video: "fallback" },
|
|
25
|
-
outbound: { streamEdit: "native", streamPush: "fallback", image: "fallback", card: "native", typing: "native" },
|
|
26
|
-
},
|
|
27
22
|
wework: {
|
|
28
23
|
inbound: { text: "native", image: "fallback", file: "fallback", voice: "fallback", video: "fallback" },
|
|
29
24
|
outbound: { streamEdit: "native", streamPush: "fallback", image: "native", card: "native", typing: "native" },
|
|
@@ -10,7 +10,7 @@ describe("channel capabilities", () => {
|
|
|
10
10
|
expect(CHANNEL_CAPABILITIES.qq.inbound.video).toBe("fallback");
|
|
11
11
|
expect(CHANNEL_CAPABILITIES.qq.outbound.streamEdit).toBe("none");
|
|
12
12
|
expect(CHANNEL_CAPABILITIES.qq.outbound.streamPush).toBe("none");
|
|
13
|
-
expect(CHANNEL_CAPABILITIES.
|
|
13
|
+
expect(CHANNEL_CAPABILITIES.wework.inbound.image).toBe("fallback");
|
|
14
14
|
expect(CHANNEL_CAPABILITIES.wework.inbound.video).toBe("fallback");
|
|
15
15
|
expect(CHANNEL_CAPABILITIES.wework.outbound.image).toBe("native");
|
|
16
16
|
expect(CHANNEL_CAPABILITIES.dingtalk.inbound.file).toBe("fallback");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Config } from '../config.js';
|
|
1
|
+
import { type Config, type Platform } from '../config.js';
|
|
2
2
|
import type { SessionManager } from '../session/session-manager.js';
|
|
3
3
|
import type { RequestQueue } from '../queue/request-queue.js';
|
|
4
4
|
import type { ThreadContext } from '../shared/types.js';
|
|
@@ -18,7 +18,7 @@ export type ClaudeRequestHandler = (userId: string, chatId: string, prompt: stri
|
|
|
18
18
|
export declare class CommandHandler {
|
|
19
19
|
private deps;
|
|
20
20
|
constructor(deps: CommandHandlerDeps);
|
|
21
|
-
dispatch(text: string, chatId: string, userId: string, platform:
|
|
21
|
+
dispatch(text: string, chatId: string, userId: string, platform: Platform, handleClaudeRequest: ClaudeRequestHandler): Promise<boolean>;
|
|
22
22
|
private handleHelp;
|
|
23
23
|
private handleNew;
|
|
24
24
|
private handlePwd;
|
package/dist/config-web.js
CHANGED
package/dist/config.d.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { type LogLevel } from './logger.js';
|
|
2
|
-
export type Platform = 'dingtalk' | 'feishu' | 'qq' | 'telegram' | '
|
|
2
|
+
export type Platform = 'dingtalk' | 'feishu' | 'qq' | 'telegram' | 'wework' | 'workbuddy';
|
|
3
3
|
export type AiCommand = 'claude' | 'codex' | 'codebuddy';
|
|
4
4
|
export interface Config {
|
|
5
5
|
enabledPlatforms: Platform[];
|
|
6
6
|
telegramBotToken?: string;
|
|
7
7
|
feishuAppId?: string;
|
|
8
8
|
feishuAppSecret?: string;
|
|
9
|
-
/** WorkBuddy 用户 ID(可选,与 platforms.wechat.userId 二选一,环境变量 WECHAT_USER_ID) */
|
|
10
|
-
wechatUserId?: string;
|
|
11
9
|
weworkCorpId?: string;
|
|
12
10
|
weworkSecret?: string;
|
|
13
11
|
weworkWsUrl?: string;
|
|
@@ -20,7 +18,6 @@ export interface Config {
|
|
|
20
18
|
telegramAllowedUserIds: string[];
|
|
21
19
|
feishuAllowedUserIds: string[];
|
|
22
20
|
qqAllowedUserIds: string[];
|
|
23
|
-
wechatAllowedUserIds: string[];
|
|
24
21
|
weworkAllowedUserIds: string[];
|
|
25
22
|
dingtalkAllowedUserIds: string[];
|
|
26
23
|
workbuddyAllowedUserIds: string[];
|
|
@@ -55,16 +52,6 @@ export interface Config {
|
|
|
55
52
|
aiCommand?: AiCommand;
|
|
56
53
|
allowedUserIds: string[];
|
|
57
54
|
};
|
|
58
|
-
wechat?: {
|
|
59
|
-
enabled: boolean;
|
|
60
|
-
aiCommand?: AiCommand;
|
|
61
|
-
userId?: string;
|
|
62
|
-
allowedUserIds: string[];
|
|
63
|
-
workbuddyAccessToken?: string;
|
|
64
|
-
workbuddyRefreshToken?: string;
|
|
65
|
-
workbuddyBaseUrl?: string;
|
|
66
|
-
workbuddyHostId?: string;
|
|
67
|
-
};
|
|
68
55
|
wework?: {
|
|
69
56
|
enabled: boolean;
|
|
70
57
|
aiCommand?: AiCommand;
|
|
@@ -206,7 +193,7 @@ export declare function hasClaudeCredentials(): boolean;
|
|
|
206
193
|
/** 检测是否需要交互式配置(无 token 且无环境变量) */
|
|
207
194
|
export declare function needsSetup(): boolean;
|
|
208
195
|
export declare function loadConfig(): Config;
|
|
209
|
-
/**
|
|
196
|
+
/** 获取已配置凭证的平台列表 */
|
|
210
197
|
export declare function getPlatformsWithCredentials(config: Config): Platform[];
|
|
211
198
|
export declare function resolvePlatformAiCommand(config: Config, platform: Platform): AiCommand;
|
|
212
199
|
export declare function getConfiguredAiCommands(config: Config): AiCommand[];
|
package/dist/config.js
CHANGED
|
@@ -191,17 +191,19 @@ export function needsSetup() {
|
|
|
191
191
|
const tg = file.platforms?.telegram;
|
|
192
192
|
const fs = file.platforms?.feishu;
|
|
193
193
|
const qq = file.platforms?.qq;
|
|
194
|
-
const wc = file.platforms?.wechat;
|
|
195
194
|
const ww = file.platforms?.wework;
|
|
196
195
|
const dt = file.platforms?.dingtalk;
|
|
196
|
+
const wb = file.platforms?.workbuddy;
|
|
197
|
+
// Also check legacy platforms.wechat for migration path
|
|
198
|
+
const legacyWc = file.platforms?.wechat;
|
|
197
199
|
const hasTelegram = !!tg?.botToken;
|
|
198
200
|
const hasFeishu = !!(fs?.appId && fs?.appSecret);
|
|
199
201
|
const hasQQ = !!(qq?.appId && qq?.secret);
|
|
200
|
-
const hasWechat = !!(wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken);
|
|
201
|
-
// 企业微信只需要 corpId 和 secret
|
|
202
202
|
const hasWework = !!(ww?.corpId && ww?.secret);
|
|
203
203
|
const hasDingtalk = !!(dt?.clientId && dt?.clientSecret);
|
|
204
|
-
|
|
204
|
+
const hasWorkBuddy = !!(wb?.accessToken && wb?.refreshToken && wb?.userId);
|
|
205
|
+
const hasLegacyWechat = !!(legacyWc?.workbuddyAccessToken && legacyWc?.workbuddyRefreshToken);
|
|
206
|
+
return !hasTelegram && !hasFeishu && !hasQQ && !hasWework && !hasDingtalk && !hasWorkBuddy && !hasLegacyWechat;
|
|
205
207
|
}
|
|
206
208
|
function parseCommaSeparated(value) {
|
|
207
209
|
return value.split(',').map((s) => s.trim()).filter(Boolean);
|
|
@@ -229,10 +231,18 @@ export function loadConfig() {
|
|
|
229
231
|
const fileTelegram = file.platforms?.telegram;
|
|
230
232
|
const fileFeishu = file.platforms?.feishu;
|
|
231
233
|
const fileQQ = file.platforms?.qq;
|
|
232
|
-
const fileWechat = file.platforms?.wechat;
|
|
233
234
|
const fileWework = file.platforms?.wework;
|
|
234
235
|
const fileDingtalk = file.platforms?.dingtalk;
|
|
235
|
-
|
|
236
|
+
// Auto-migrate legacy platforms.wechat WorkBuddy credentials → platforms.workbuddy
|
|
237
|
+
const legacyWechat = file.platforms?.wechat;
|
|
238
|
+
const fileWorkBuddy = file.platforms?.workbuddy ?? (legacyWechat?.workbuddyAccessToken && legacyWechat?.workbuddyRefreshToken
|
|
239
|
+
? {
|
|
240
|
+
accessToken: legacyWechat.workbuddyAccessToken,
|
|
241
|
+
refreshToken: legacyWechat.workbuddyRefreshToken,
|
|
242
|
+
userId: legacyWechat.userId,
|
|
243
|
+
baseUrl: legacyWechat.workbuddyBaseUrl,
|
|
244
|
+
}
|
|
245
|
+
: undefined);
|
|
236
246
|
// 1. 加载各平台凭证(env 优先,其次新结构,最后旧字段)
|
|
237
247
|
const telegramBotToken = process.env.TELEGRAM_BOT_TOKEN ??
|
|
238
248
|
fileTelegram?.botToken ??
|
|
@@ -247,16 +257,6 @@ export function loadConfig() {
|
|
|
247
257
|
fileQQ?.appId;
|
|
248
258
|
const qqSecret = process.env.QQ_BOT_SECRET ??
|
|
249
259
|
fileQQ?.secret;
|
|
250
|
-
const wechatUserId = process.env.WECHAT_USER_ID ??
|
|
251
|
-
fileWechat?.userId;
|
|
252
|
-
const wechatWorkbuddyAccessToken = process.env.WECHAT_WORKBUDDY_ACCESS_TOKEN ??
|
|
253
|
-
fileWechat?.workbuddyAccessToken;
|
|
254
|
-
const wechatWorkbuddyRefreshToken = process.env.WECHAT_WORKBUDDY_REFRESH_TOKEN ??
|
|
255
|
-
fileWechat?.workbuddyRefreshToken;
|
|
256
|
-
const wechatWorkbuddyBaseUrl = process.env.WECHAT_WORKBUDDY_BASE_URL ??
|
|
257
|
-
fileWechat?.workbuddyBaseUrl;
|
|
258
|
-
const wechatWorkbuddyHostId = process.env.WECHAT_WORKBUDDY_HOST_ID ??
|
|
259
|
-
fileWechat?.workbuddyHostId;
|
|
260
260
|
const weworkCorpId = process.env.WEWORK_CORP_ID ??
|
|
261
261
|
fileWework?.corpId;
|
|
262
262
|
const weworkSecret = process.env.WEWORK_SECRET ??
|
|
@@ -287,19 +287,14 @@ export function loadConfig() {
|
|
|
287
287
|
const telegramEnabledFlag = fileTelegram?.enabled;
|
|
288
288
|
const feishuEnabledFlag = fileFeishu?.enabled;
|
|
289
289
|
const qqEnabledFlag = fileQQ?.enabled;
|
|
290
|
-
const wechatEnabledFlag = fileWechat?.enabled;
|
|
291
290
|
const weworkEnabledFlag = fileWework?.enabled;
|
|
292
291
|
const dingtalkEnabledFlag = fileDingtalk?.enabled;
|
|
293
292
|
const workbuddyEnabledFlag = fileWorkBuddy?.enabled;
|
|
294
293
|
const telegramEnabled = !!telegramBotToken && (telegramEnabledFlag !== false);
|
|
295
294
|
const feishuEnabled = !!(feishuAppId && feishuAppSecret) && (feishuEnabledFlag !== false);
|
|
296
295
|
const qqEnabled = !!(qqAppId && qqSecret) && (qqEnabledFlag !== false);
|
|
297
|
-
const hasWechatWorkbuddyCreds = !!(wechatWorkbuddyAccessToken && wechatWorkbuddyRefreshToken);
|
|
298
|
-
const wechatEnabled = hasWechatWorkbuddyCreds && (wechatEnabledFlag !== false);
|
|
299
|
-
// 企业微信只需要 corpId (botId) 和 secret
|
|
300
296
|
const weworkEnabled = !!(weworkCorpId && weworkSecret) && (weworkEnabledFlag !== false);
|
|
301
297
|
const dingtalkEnabled = !!(dingtalkClientId && dingtalkClientSecret) && (dingtalkEnabledFlag !== false);
|
|
302
|
-
// WorkBuddy 需要 OAuth 凭证
|
|
303
298
|
const workbuddyEnabled = !!(workbuddyAccessToken && workbuddyRefreshToken && workbuddyUserId) && (workbuddyEnabledFlag !== false);
|
|
304
299
|
if (telegramEnabled)
|
|
305
300
|
enabledPlatforms.push('telegram');
|
|
@@ -307,8 +302,6 @@ export function loadConfig() {
|
|
|
307
302
|
enabledPlatforms.push('feishu');
|
|
308
303
|
if (qqEnabled)
|
|
309
304
|
enabledPlatforms.push('qq');
|
|
310
|
-
if (wechatEnabled)
|
|
311
|
-
enabledPlatforms.push('wechat');
|
|
312
305
|
if (weworkEnabled)
|
|
313
306
|
enabledPlatforms.push('wework');
|
|
314
307
|
if (dingtalkEnabled)
|
|
@@ -332,9 +325,6 @@ export function loadConfig() {
|
|
|
332
325
|
const qqAllowedUserIds = process.env.QQ_ALLOWED_USER_IDS !== undefined
|
|
333
326
|
? parseCommaSeparated(process.env.QQ_ALLOWED_USER_IDS)
|
|
334
327
|
: fileQQ?.allowedUserIds ?? allowedUserIds;
|
|
335
|
-
const wechatAllowedUserIds = process.env.WECHAT_ALLOWED_USER_IDS !== undefined
|
|
336
|
-
? parseCommaSeparated(process.env.WECHAT_ALLOWED_USER_IDS)
|
|
337
|
-
: fileWechat?.allowedUserIds ?? allowedUserIds;
|
|
338
328
|
const weworkAllowedUserIds = process.env.WEWORK_ALLOWED_USER_IDS !== undefined
|
|
339
329
|
? parseCommaSeparated(process.env.WEWORK_ALLOWED_USER_IDS)
|
|
340
330
|
: fileWework?.allowedUserIds ?? allowedUserIds;
|
|
@@ -544,27 +534,6 @@ export function loadConfig() {
|
|
|
544
534
|
aiCommand: normalizeAiCommand(file.platforms?.qq?.aiCommand, aiCommand),
|
|
545
535
|
allowedUserIds: qqAllowedUserIds,
|
|
546
536
|
},
|
|
547
|
-
wechat: wechatEnabled
|
|
548
|
-
? {
|
|
549
|
-
enabled: true,
|
|
550
|
-
aiCommand: normalizeAiCommand(file.platforms?.wechat?.aiCommand, aiCommand),
|
|
551
|
-
userId: wechatUserId,
|
|
552
|
-
allowedUserIds: wechatAllowedUserIds,
|
|
553
|
-
workbuddyAccessToken: wechatWorkbuddyAccessToken,
|
|
554
|
-
workbuddyRefreshToken: wechatWorkbuddyRefreshToken,
|
|
555
|
-
workbuddyBaseUrl: wechatWorkbuddyBaseUrl,
|
|
556
|
-
workbuddyHostId: wechatWorkbuddyHostId,
|
|
557
|
-
}
|
|
558
|
-
: {
|
|
559
|
-
enabled: false,
|
|
560
|
-
aiCommand: normalizeAiCommand(file.platforms?.wechat?.aiCommand, aiCommand),
|
|
561
|
-
userId: wechatUserId,
|
|
562
|
-
allowedUserIds: wechatAllowedUserIds,
|
|
563
|
-
workbuddyAccessToken: wechatWorkbuddyAccessToken,
|
|
564
|
-
workbuddyRefreshToken: wechatWorkbuddyRefreshToken,
|
|
565
|
-
workbuddyBaseUrl: wechatWorkbuddyBaseUrl,
|
|
566
|
-
workbuddyHostId: wechatWorkbuddyHostId,
|
|
567
|
-
},
|
|
568
537
|
wework: weworkEnabled
|
|
569
538
|
? {
|
|
570
539
|
enabled: true,
|
|
@@ -620,7 +589,6 @@ export function loadConfig() {
|
|
|
620
589
|
feishuAppSecret: feishuAppSecret ?? '',
|
|
621
590
|
qqAppId: qqAppId ?? '',
|
|
622
591
|
qqSecret: qqSecret ?? '',
|
|
623
|
-
wechatUserId: wechatUserId,
|
|
624
592
|
weworkCorpId: weworkCorpId ?? '',
|
|
625
593
|
weworkSecret: weworkSecret ?? '',
|
|
626
594
|
weworkWsUrl: weworkWsUrl,
|
|
@@ -631,7 +599,6 @@ export function loadConfig() {
|
|
|
631
599
|
telegramAllowedUserIds,
|
|
632
600
|
feishuAllowedUserIds,
|
|
633
601
|
qqAllowedUserIds,
|
|
634
|
-
wechatAllowedUserIds,
|
|
635
602
|
weworkAllowedUserIds,
|
|
636
603
|
dingtalkAllowedUserIds,
|
|
637
604
|
workbuddyAllowedUserIds,
|
|
@@ -650,7 +617,7 @@ export function loadConfig() {
|
|
|
650
617
|
platforms,
|
|
651
618
|
};
|
|
652
619
|
}
|
|
653
|
-
/**
|
|
620
|
+
/** 获取已配置凭证的平台列表 */
|
|
654
621
|
export function getPlatformsWithCredentials(config) {
|
|
655
622
|
const r = [];
|
|
656
623
|
if (config.telegramBotToken)
|
|
@@ -663,9 +630,9 @@ export function getPlatformsWithCredentials(config) {
|
|
|
663
630
|
r.push('wework');
|
|
664
631
|
if (config.dingtalkClientId && config.dingtalkClientSecret)
|
|
665
632
|
r.push('dingtalk');
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
668
|
-
r.push('
|
|
633
|
+
const wb = config.platforms.workbuddy;
|
|
634
|
+
if (wb?.accessToken && wb?.refreshToken)
|
|
635
|
+
r.push('workbuddy');
|
|
669
636
|
return r;
|
|
670
637
|
}
|
|
671
638
|
export function resolvePlatformAiCommand(config, platform) {
|
package/dist/index.js
CHANGED
|
@@ -15,9 +15,6 @@ import { sendTextReply as sendFeishuTextReply } from "./feishu/message-sender.js
|
|
|
15
15
|
import { initQQ, stopQQ } from "./qq/client.js";
|
|
16
16
|
import { setupQQHandlers } from "./qq/event-handler.js";
|
|
17
17
|
import { sendTextReply as sendQQTextReply } from "./qq/message-sender.js";
|
|
18
|
-
import { initWeChat, stopWeChat } from "./wechat/client.js";
|
|
19
|
-
import { setupWeChatHandlers } from "./wechat/event-handler.js";
|
|
20
|
-
import { sendTextReply as sendWeChatTextReply } from "./wechat/message-sender.js";
|
|
21
18
|
import { initWeWork, stopWeWork } from "./wework/client.js";
|
|
22
19
|
import { setupWeWorkHandlers } from "./wework/event-handler.js";
|
|
23
20
|
import { sendProactiveTextReply as sendWeWorkTextReply } from "./wework/message-sender.js";
|
|
@@ -42,7 +39,6 @@ async function sendLifecycleNotification(platform, message) {
|
|
|
42
39
|
const telegramChatId = getActiveChatId("telegram");
|
|
43
40
|
const feishuChatId = getActiveChatId("feishu");
|
|
44
41
|
const qqChatId = getActiveChatId("qq");
|
|
45
|
-
const wechatChatId = getActiveChatId("wechat");
|
|
46
42
|
const weworkChatId = getActiveChatId("wework");
|
|
47
43
|
const sendPromises = [];
|
|
48
44
|
if (platform === "telegram" && telegramChatId) {
|
|
@@ -60,11 +56,6 @@ async function sendLifecycleNotification(platform, message) {
|
|
|
60
56
|
log.debug("Failed to send QQ notification:", err);
|
|
61
57
|
}));
|
|
62
58
|
}
|
|
63
|
-
if (platform === "wechat" && wechatChatId) {
|
|
64
|
-
sendPromises.push(sendWeChatTextReply(wechatChatId, message).catch((err) => {
|
|
65
|
-
log.debug("Failed to send WeChat notification:", err);
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
59
|
if (platform === "wework" && weworkChatId) {
|
|
69
60
|
sendPromises.push(sendWeWorkTextReply(weworkChatId, message).catch((err) => {
|
|
70
61
|
log.debug("Failed to send WeWork notification:", err);
|
|
@@ -173,7 +164,6 @@ export async function main() {
|
|
|
173
164
|
let telegramHandle = null;
|
|
174
165
|
let feishuHandle = null;
|
|
175
166
|
let qqHandle = null;
|
|
176
|
-
let wechatHandle = null;
|
|
177
167
|
let weworkHandle = null;
|
|
178
168
|
let dingtalkHandle = null;
|
|
179
169
|
let workbuddyHandle = null;
|
|
@@ -210,16 +200,6 @@ export async function main() {
|
|
|
210
200
|
log.error("Failed to initialize QQ:", err);
|
|
211
201
|
}
|
|
212
202
|
}
|
|
213
|
-
if (config.enabledPlatforms.includes("wechat")) {
|
|
214
|
-
try {
|
|
215
|
-
wechatHandle = setupWeChatHandlers(config, sessionManager);
|
|
216
|
-
await initWeChat(config, wechatHandle.handleEvent);
|
|
217
|
-
successfulPlatforms.push("wechat");
|
|
218
|
-
}
|
|
219
|
-
catch (err) {
|
|
220
|
-
log.error("Failed to initialize WeChat:", err);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
203
|
if (config.enabledPlatforms.includes("wework")) {
|
|
224
204
|
try {
|
|
225
205
|
weworkHandle = setupWeWorkHandlers(config, sessionManager);
|
|
@@ -290,8 +270,6 @@ export async function main() {
|
|
|
290
270
|
stopFeishu();
|
|
291
271
|
qqHandle?.stop();
|
|
292
272
|
await stopQQ();
|
|
293
|
-
wechatHandle?.stop();
|
|
294
|
-
stopWeChat();
|
|
295
273
|
weworkHandle?.stop();
|
|
296
274
|
stopWeWork();
|
|
297
275
|
dingtalkHandle?.stop();
|
package/dist/setup.js
CHANGED
|
@@ -30,7 +30,7 @@ function getConfiguredPlatforms(existing) {
|
|
|
30
30
|
{ k: "feishu", label: "飞书" },
|
|
31
31
|
{ k: "wework", label: "企业微信" },
|
|
32
32
|
{ k: "dingtalk", label: "钉钉" },
|
|
33
|
-
{ k: "
|
|
33
|
+
{ k: "workbuddy", label: "WorkBuddy (微信)" },
|
|
34
34
|
];
|
|
35
35
|
return names
|
|
36
36
|
.filter(({ k }) => {
|
|
@@ -43,8 +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
|
-
if (k === "
|
|
47
|
-
return !!(p.
|
|
46
|
+
if (k === "workbuddy")
|
|
47
|
+
return !!(p.accessToken && p.refreshToken);
|
|
48
48
|
if (k === "wework")
|
|
49
49
|
return !!(p.corpId && p.secret);
|
|
50
50
|
if (k === "dingtalk")
|
|
@@ -272,8 +272,8 @@ export async function runInteractiveSetup() {
|
|
|
272
272
|
const hasTg = !!existing?.platforms?.telegram?.botToken;
|
|
273
273
|
const hasFs = !!(existing?.platforms?.feishu?.appId && existing?.platforms?.feishu?.appSecret);
|
|
274
274
|
const hasQq = !!(existing?.platforms?.qq?.appId && existing?.platforms?.qq?.secret);
|
|
275
|
-
const wc = existing?.platforms?.
|
|
276
|
-
const hasWc = !!(wc?.
|
|
275
|
+
const wc = existing?.platforms?.workbuddy;
|
|
276
|
+
const hasWc = !!(wc?.accessToken && wc?.refreshToken);
|
|
277
277
|
const hasWw = !!(existing?.platforms?.wework?.corpId && existing?.platforms?.wework?.secret);
|
|
278
278
|
const hasDt = !!(existing?.platforms?.dingtalk?.clientId && existing?.platforms?.dingtalk?.clientSecret);
|
|
279
279
|
// 第一步:选择平台(在选项和提示中显示已配置项)
|
|
@@ -307,9 +307,9 @@ export async function runInteractiveSetup() {
|
|
|
307
307
|
value: "dingtalk",
|
|
308
308
|
},
|
|
309
309
|
{
|
|
310
|
-
title: "
|
|
310
|
+
title: "WorkBuddy 微信客服 (WeChat KF)" +
|
|
311
311
|
(hasWc ? " ✓已配置" : ""),
|
|
312
|
-
value: "
|
|
312
|
+
value: "workbuddy",
|
|
313
313
|
},
|
|
314
314
|
{ title: "配置多个平台", value: "multi" },
|
|
315
315
|
],
|
|
@@ -332,7 +332,7 @@ export async function runInteractiveSetup() {
|
|
|
332
332
|
{ title: "飞书 (Feishu)" + (hasFs ? " ✓已配置" : ""), value: "feishu", selected: hasFs },
|
|
333
333
|
{ title: "企业微信 (WeWork)" + (hasWw ? " ✓已配置" : ""), value: "wework", selected: hasWw },
|
|
334
334
|
{ title: "钉钉 (DingTalk)" + (hasDt ? " ✓已配置" : ""), value: "dingtalk", selected: hasDt },
|
|
335
|
-
{ title: "
|
|
335
|
+
{ title: "WorkBuddy 微信客服 (WeChat KF)" + (hasWc ? " ✓已配置" : ""), value: "workbuddy", selected: hasWc },
|
|
336
336
|
],
|
|
337
337
|
}, { onCancel });
|
|
338
338
|
if (!multiResp.platforms || multiResp.platforms.length === 0) {
|
|
@@ -420,13 +420,13 @@ export async function runInteractiveSetup() {
|
|
|
420
420
|
return false;
|
|
421
421
|
}
|
|
422
422
|
}
|
|
423
|
-
if (selectedPlatforms.includes("
|
|
424
|
-
const
|
|
425
|
-
const hasWbCreds = !!(
|
|
426
|
-
const
|
|
423
|
+
if (selectedPlatforms.includes("workbuddy")) {
|
|
424
|
+
const wb = existing?.platforms?.workbuddy;
|
|
425
|
+
const hasWbCreds = !!(wb?.accessToken && wb?.refreshToken);
|
|
426
|
+
const wbModeResp = await prompts({
|
|
427
427
|
type: "select",
|
|
428
428
|
name: "mode",
|
|
429
|
-
message: "
|
|
429
|
+
message: "WorkBuddy 微信客服(CodeBuddy OAuth)",
|
|
430
430
|
choices: [
|
|
431
431
|
{
|
|
432
432
|
title: "在浏览器中完成 CodeBuddy 登录并绑定微信客服(推荐)",
|
|
@@ -440,7 +440,7 @@ export async function runInteractiveSetup() {
|
|
|
440
440
|
],
|
|
441
441
|
initial: hasWbCreds ? 1 : 0,
|
|
442
442
|
}, { onCancel });
|
|
443
|
-
if (
|
|
443
|
+
if (wbModeResp.mode === "oauth") {
|
|
444
444
|
console.log("\n正在启动 WorkBuddy OAuth 登录...\n");
|
|
445
445
|
try {
|
|
446
446
|
const { WorkBuddyOAuth } = await import("./workbuddy/oauth.js");
|
|
@@ -460,10 +460,12 @@ export async function runInteractiveSetup() {
|
|
|
460
460
|
// account info is optional
|
|
461
461
|
}
|
|
462
462
|
const userId = accountInfo?.uid?.toString() ?? "";
|
|
463
|
-
|
|
463
|
+
// Set oauth.userId so buildSessionId() produces the correct sessionId.
|
|
464
|
+
oauth.userId = userId;
|
|
465
|
+
config.platforms.workbuddy = {
|
|
464
466
|
enabled: true,
|
|
465
|
-
|
|
466
|
-
|
|
467
|
+
accessToken: tokenResult.accessToken,
|
|
468
|
+
refreshToken: tokenResult.refreshToken,
|
|
467
469
|
userId,
|
|
468
470
|
};
|
|
469
471
|
console.log("\n正在获取微信客服绑定链接...");
|
|
@@ -489,17 +491,17 @@ export async function runInteractiveSetup() {
|
|
|
489
491
|
}
|
|
490
492
|
catch (err) {
|
|
491
493
|
console.error("\n❌ WorkBuddy 登录失败:", err instanceof Error ? err.message : String(err));
|
|
492
|
-
if (platform === "
|
|
494
|
+
if (platform === "workbuddy")
|
|
493
495
|
return false;
|
|
494
496
|
}
|
|
495
497
|
}
|
|
496
498
|
else if (hasWbCreds) {
|
|
497
|
-
config.platforms.
|
|
498
|
-
...
|
|
499
|
+
config.platforms.workbuddy = {
|
|
500
|
+
...wb,
|
|
499
501
|
enabled: true,
|
|
500
502
|
};
|
|
501
503
|
}
|
|
502
|
-
else if (platform === "
|
|
504
|
+
else if (platform === "workbuddy") {
|
|
503
505
|
return false;
|
|
504
506
|
}
|
|
505
507
|
}
|
|
@@ -575,7 +577,7 @@ export async function runInteractiveSetup() {
|
|
|
575
577
|
const tgIds = existing?.platforms?.telegram?.allowedUserIds?.join(", ") ?? "";
|
|
576
578
|
const fsIds = existing?.platforms?.feishu?.allowedUserIds?.join(", ") ?? "";
|
|
577
579
|
const qqIds = existing?.platforms?.qq?.allowedUserIds?.join(", ") ?? "";
|
|
578
|
-
const wcIds = existing?.platforms?.
|
|
580
|
+
const wcIds = existing?.platforms?.workbuddy?.allowedUserIds?.join(", ") ?? "";
|
|
579
581
|
const wwIds = existing?.platforms?.wework?.allowedUserIds?.join(", ") ?? "";
|
|
580
582
|
const dtIds = existing?.platforms?.dingtalk?.allowedUserIds?.join(", ") ?? "";
|
|
581
583
|
const aiIdx = ["claude", "codex", "codebuddy"].indexOf(existing?.aiCommand ?? "claude");
|
|
@@ -604,11 +606,11 @@ export async function runInteractiveSetup() {
|
|
|
604
606
|
initial: fsIds,
|
|
605
607
|
});
|
|
606
608
|
}
|
|
607
|
-
if (selectedPlatforms.includes("
|
|
609
|
+
if (selectedPlatforms.includes("workbuddy")) {
|
|
608
610
|
commonPrompts.push({
|
|
609
611
|
type: "text",
|
|
610
|
-
name: "
|
|
611
|
-
message: "
|
|
612
|
+
name: "workbuddyAllowedUserIds",
|
|
613
|
+
message: "WorkBuddy 白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
|
|
612
614
|
initial: wcIds,
|
|
613
615
|
});
|
|
614
616
|
}
|
|
@@ -739,9 +741,9 @@ export async function runInteractiveSetup() {
|
|
|
739
741
|
const qqIdsFinal = selectedPlatforms.includes("qq")
|
|
740
742
|
? parseIds(commonResp.qqAllowedUserIds)
|
|
741
743
|
: parseIds(existing?.platforms?.qq?.allowedUserIds?.join(", "));
|
|
742
|
-
const
|
|
743
|
-
? parseIds(commonResp.
|
|
744
|
-
: parseIds(existing?.platforms?.
|
|
744
|
+
const workbuddyIds = selectedPlatforms.includes("workbuddy")
|
|
745
|
+
? parseIds(commonResp.workbuddyAllowedUserIds)
|
|
746
|
+
: parseIds(existing?.platforms?.workbuddy?.allowedUserIds?.join(", "));
|
|
745
747
|
const weworkIds = selectedPlatforms.includes("wework")
|
|
746
748
|
? parseIds(commonResp.weworkAllowedUserIds)
|
|
747
749
|
: parseIds(existing?.platforms?.wework?.allowedUserIds?.join(", "));
|
|
@@ -881,32 +883,29 @@ export async function runInteractiveSetup() {
|
|
|
881
883
|
else {
|
|
882
884
|
outPlatforms.qq = { enabled: false, allowedUserIds: qqIdsFinal };
|
|
883
885
|
}
|
|
884
|
-
if (selectedPlatforms.includes("
|
|
885
|
-
const
|
|
886
|
-
const
|
|
886
|
+
if (selectedPlatforms.includes("workbuddy")) {
|
|
887
|
+
const wbConfig = config.platforms?.workbuddy;
|
|
888
|
+
const baseWb = base?.platforms?.workbuddy;
|
|
887
889
|
const wbOut = {
|
|
888
890
|
enabled: true,
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
userId:
|
|
892
|
-
allowedUserIds:
|
|
891
|
+
accessToken: wbConfig?.accessToken ?? baseWb?.accessToken,
|
|
892
|
+
refreshToken: wbConfig?.refreshToken ?? baseWb?.refreshToken,
|
|
893
|
+
userId: wbConfig?.userId ?? baseWb?.userId ?? "",
|
|
894
|
+
allowedUserIds: workbuddyIds,
|
|
893
895
|
};
|
|
894
|
-
const wbBaseUrl =
|
|
895
|
-
const wbHostId = wcConfig?.workbuddyHostId ?? baseWc?.workbuddyHostId;
|
|
896
|
+
const wbBaseUrl = wbConfig?.baseUrl ?? baseWb?.baseUrl;
|
|
896
897
|
if (wbBaseUrl)
|
|
897
|
-
wbOut.
|
|
898
|
-
|
|
899
|
-
wbOut.workbuddyHostId = wbHostId;
|
|
900
|
-
out.platforms.wechat = wbOut;
|
|
898
|
+
wbOut.baseUrl = wbBaseUrl;
|
|
899
|
+
out.platforms.workbuddy = wbOut;
|
|
901
900
|
}
|
|
902
|
-
else if (basePlatforms?.
|
|
903
|
-
outPlatforms.
|
|
904
|
-
...basePlatforms.
|
|
905
|
-
allowedUserIds:
|
|
901
|
+
else if (basePlatforms?.workbuddy) {
|
|
902
|
+
outPlatforms.workbuddy = {
|
|
903
|
+
...basePlatforms.workbuddy,
|
|
904
|
+
allowedUserIds: workbuddyIds.length > 0 ? workbuddyIds : basePlatforms.workbuddy.allowedUserIds ?? [],
|
|
906
905
|
};
|
|
907
906
|
}
|
|
908
907
|
else {
|
|
909
|
-
outPlatforms.
|
|
908
|
+
outPlatforms.workbuddy = { enabled: false, allowedUserIds: workbuddyIds };
|
|
910
909
|
}
|
|
911
910
|
if (selectedPlatforms.includes("wework")) {
|
|
912
911
|
outPlatforms.wework = {
|
|
@@ -960,10 +959,9 @@ const PLATFORM_LABELS = {
|
|
|
960
959
|
feishu: "飞书",
|
|
961
960
|
wework: "企业微信",
|
|
962
961
|
dingtalk: "钉钉",
|
|
963
|
-
|
|
964
|
-
workbuddy: "WorkBuddy",
|
|
962
|
+
workbuddy: "WorkBuddy 微信客服",
|
|
965
963
|
};
|
|
966
|
-
const ALL_PLATFORMS = ["telegram", "feishu", "qq", "wework", "dingtalk", "
|
|
964
|
+
const ALL_PLATFORMS = ["telegram", "feishu", "qq", "wework", "dingtalk", "workbuddy"];
|
|
967
965
|
/**
|
|
968
966
|
* 启动时让用户选择要启用的平台(无论单通道还是多通道)
|
|
969
967
|
* 显示全部 4 个平台,已配置的预选;若用户选择未配置的,引导运行 init
|
|
@@ -145,19 +145,24 @@ export class WorkBuddyCentrifugeClient {
|
|
|
145
145
|
// WeChat KF messages: send via HTTP COPILOT_RESPONSE
|
|
146
146
|
if (this.config.httpBaseUrl && this.config.httpAccessToken) {
|
|
147
147
|
const message = payload.content?.map((c) => c.text).join('') || payload.error || '';
|
|
148
|
+
// chatId format: "<wechatUserId>::origin::wechatkfProxy"
|
|
149
|
+
// Extract user ID for toUser field; keep full chatId for routing.
|
|
150
|
+
const chatIdFull = payload.session_id;
|
|
151
|
+
const toUser = chatIdFull.includes('::') ? chatIdFull.split('::')[0] : chatIdFull;
|
|
148
152
|
const httpPayload = {
|
|
149
153
|
type: 'COPILOT_RESPONSE',
|
|
150
154
|
msgId: payload.prompt_id,
|
|
151
|
-
chatId:
|
|
155
|
+
chatId: chatIdFull,
|
|
156
|
+
toUser,
|
|
152
157
|
success: payload.stop_reason === 'end_turn',
|
|
153
158
|
message,
|
|
154
159
|
metadata: {
|
|
155
160
|
sessionId: this.config.workspaceSessionId || payload.session_id,
|
|
156
|
-
|
|
157
|
-
state: payload.stop_reason === 'end_turn' ? 'completed' : payload.stop_reason,
|
|
161
|
+
toUser,
|
|
158
162
|
},
|
|
159
163
|
};
|
|
160
164
|
const url = `${this.config.httpBaseUrl}/v2/backgroundagent/wecom/local-proxy/receive`;
|
|
165
|
+
log.debug(`${this.logPrefix} HTTP COPILOT_RESPONSE → ${url} chatId=${payload.session_id} msgLen=${message.length}`);
|
|
161
166
|
fetch(url, {
|
|
162
167
|
method: 'POST',
|
|
163
168
|
headers: {
|
|
@@ -168,9 +173,12 @@ export class WorkBuddyCentrifugeClient {
|
|
|
168
173
|
signal: AbortSignal.timeout(30_000),
|
|
169
174
|
})
|
|
170
175
|
.then(async (res) => {
|
|
176
|
+
const body = await res.text().catch(() => '');
|
|
171
177
|
if (!res.ok) {
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
log.error(`${this.logPrefix} HTTP COPILOT_RESPONSE failed: ${res.status} ${body.substring(0, 300)}`);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
log.info(`${this.logPrefix} HTTP COPILOT_RESPONSE ok: ${res.status} ${body.substring(0, 200)}`);
|
|
174
182
|
}
|
|
175
183
|
})
|
|
176
184
|
.catch((err) => {
|
|
@@ -1,27 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WorkBuddy Client -
|
|
2
|
+
* WorkBuddy Client - CodeBuddy OAuth + Centrifuge WebSocket for WeChat KF
|
|
3
|
+
*
|
|
4
|
+
* Manages the full lifecycle: connect → register WeChat KF channel → heartbeat →
|
|
5
|
+
* auto-reconnect on drop.
|
|
3
6
|
*/
|
|
4
7
|
import type { Config } from '../config.js';
|
|
5
8
|
import { WorkBuddyOAuth } from './oauth.js';
|
|
6
9
|
import { WorkBuddyCentrifugeClient } from './centrifuge-client.js';
|
|
7
10
|
import type { WorkBuddyState } from './types.js';
|
|
8
|
-
/**
|
|
9
|
-
* Get current channel state
|
|
10
|
-
*/
|
|
11
11
|
export declare function getChannelState(): WorkBuddyState;
|
|
12
|
-
/**
|
|
13
|
-
* Initialize WorkBuddy client with CodeBuddy OAuth and Centrifuge WebSocket
|
|
14
|
-
*/
|
|
15
12
|
export declare function initWorkBuddy(config: Config, eventHandler: (chatId: string, msgId: string, content: string) => Promise<void>, onStateChange?: (state: WorkBuddyState) => void): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Get Centrifuge client for sending messages
|
|
18
|
-
*/
|
|
19
13
|
export declare function getCentrifugeClient(): WorkBuddyCentrifugeClient | null;
|
|
20
|
-
/**
|
|
21
|
-
* Get OAuth client
|
|
22
|
-
*/
|
|
23
14
|
export declare function getOAuth(): WorkBuddyOAuth | null;
|
|
24
|
-
/**
|
|
25
|
-
* Stop WorkBuddy client
|
|
26
|
-
*/
|
|
27
15
|
export declare function stopWorkBuddy(): void;
|