@wu529778790/open-im 1.8.3-beta.8 → 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.
@@ -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.wechat.inbound.image).toBe("fallback");
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: 'dingtalk' | 'feishu' | 'qq' | 'telegram' | 'wechat' | 'wework' | 'workbuddy', handleClaudeRequest: ClaudeRequestHandler): Promise<boolean>;
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;
@@ -407,7 +407,6 @@ function createProbeConfig(values) {
407
407
  telegramAllowedUserIds: [],
408
408
  feishuAllowedUserIds: [],
409
409
  qqAllowedUserIds: [],
410
- wechatAllowedUserIds: [],
411
410
  weworkAllowedUserIds: [],
412
411
  dingtalkAllowedUserIds: [],
413
412
  workbuddyAllowedUserIds: [],
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' | 'wechat' | 'wework' | 'workbuddy';
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
- /** 获取已配置凭证的平台列表(用于多通道启动时让用户选择),顺序:Telegram、飞书、企业微信、微信 */
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
- return !hasTelegram && !hasFeishu && !hasQQ && !hasWechat && !hasWework && !hasDingtalk;
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
- const fileWorkBuddy = file.platforms?.workbuddy;
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
- /** 获取已配置凭证的平台列表(用于多通道启动时让用户选择),顺序:Telegram、飞书、企业微信、微信 */
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 wc = config.platforms.wechat;
667
- if (wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken)
668
- r.push('wechat');
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: "wechat", label: "微信" },
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 === "wechat")
47
- return !!(p.workbuddyAccessToken && p.workbuddyRefreshToken);
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?.wechat;
276
- const hasWc = !!(wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken);
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: "微信 (WeChat)" +
310
+ title: "WorkBuddy 微信客服 (WeChat KF)" +
311
311
  (hasWc ? " ✓已配置" : ""),
312
- value: "wechat",
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: "微信 (WeChat,测试中)" + (hasWc ? " ✓已配置" : ""), value: "wechat", selected: hasWc },
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("wechat")) {
424
- const wc = existing?.platforms?.wechat;
425
- const hasWbCreds = !!(wc?.workbuddyAccessToken && wc?.workbuddyRefreshToken);
426
- const wechatModeResp = await prompts({
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: "微信(WorkBuddy / CodeBuddy OAuth)",
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 (wechatModeResp.mode === "oauth") {
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");
@@ -461,13 +461,11 @@ export async function runInteractiveSetup() {
461
461
  }
462
462
  const userId = accountInfo?.uid?.toString() ?? "";
463
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
464
  oauth.userId = userId;
467
- config.platforms.wechat = {
465
+ config.platforms.workbuddy = {
468
466
  enabled: true,
469
- workbuddyAccessToken: tokenResult.accessToken,
470
- workbuddyRefreshToken: tokenResult.refreshToken,
467
+ accessToken: tokenResult.accessToken,
468
+ refreshToken: tokenResult.refreshToken,
471
469
  userId,
472
470
  };
473
471
  console.log("\n正在获取微信客服绑定链接...");
@@ -493,17 +491,17 @@ export async function runInteractiveSetup() {
493
491
  }
494
492
  catch (err) {
495
493
  console.error("\n❌ WorkBuddy 登录失败:", err instanceof Error ? err.message : String(err));
496
- if (platform === "wechat")
494
+ if (platform === "workbuddy")
497
495
  return false;
498
496
  }
499
497
  }
500
498
  else if (hasWbCreds) {
501
- config.platforms.wechat = {
502
- ...wc,
499
+ config.platforms.workbuddy = {
500
+ ...wb,
503
501
  enabled: true,
504
502
  };
505
503
  }
506
- else if (platform === "wechat") {
504
+ else if (platform === "workbuddy") {
507
505
  return false;
508
506
  }
509
507
  }
@@ -579,7 +577,7 @@ export async function runInteractiveSetup() {
579
577
  const tgIds = existing?.platforms?.telegram?.allowedUserIds?.join(", ") ?? "";
580
578
  const fsIds = existing?.platforms?.feishu?.allowedUserIds?.join(", ") ?? "";
581
579
  const qqIds = existing?.platforms?.qq?.allowedUserIds?.join(", ") ?? "";
582
- const wcIds = existing?.platforms?.wechat?.allowedUserIds?.join(", ") ?? "";
580
+ const wcIds = existing?.platforms?.workbuddy?.allowedUserIds?.join(", ") ?? "";
583
581
  const wwIds = existing?.platforms?.wework?.allowedUserIds?.join(", ") ?? "";
584
582
  const dtIds = existing?.platforms?.dingtalk?.allowedUserIds?.join(", ") ?? "";
585
583
  const aiIdx = ["claude", "codex", "codebuddy"].indexOf(existing?.aiCommand ?? "claude");
@@ -608,11 +606,11 @@ export async function runInteractiveSetup() {
608
606
  initial: fsIds,
609
607
  });
610
608
  }
611
- if (selectedPlatforms.includes("wechat")) {
609
+ if (selectedPlatforms.includes("workbuddy")) {
612
610
  commonPrompts.push({
613
611
  type: "text",
614
- name: "wechatAllowedUserIds",
615
- message: "微信白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
612
+ name: "workbuddyAllowedUserIds",
613
+ message: "WorkBuddy 白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
616
614
  initial: wcIds,
617
615
  });
618
616
  }
@@ -743,9 +741,9 @@ export async function runInteractiveSetup() {
743
741
  const qqIdsFinal = selectedPlatforms.includes("qq")
744
742
  ? parseIds(commonResp.qqAllowedUserIds)
745
743
  : parseIds(existing?.platforms?.qq?.allowedUserIds?.join(", "));
746
- const wechatIds = selectedPlatforms.includes("wechat")
747
- ? parseIds(commonResp.wechatAllowedUserIds)
748
- : parseIds(existing?.platforms?.wechat?.allowedUserIds?.join(", "));
744
+ const workbuddyIds = selectedPlatforms.includes("workbuddy")
745
+ ? parseIds(commonResp.workbuddyAllowedUserIds)
746
+ : parseIds(existing?.platforms?.workbuddy?.allowedUserIds?.join(", "));
749
747
  const weworkIds = selectedPlatforms.includes("wework")
750
748
  ? parseIds(commonResp.weworkAllowedUserIds)
751
749
  : parseIds(existing?.platforms?.wework?.allowedUserIds?.join(", "));
@@ -885,32 +883,29 @@ export async function runInteractiveSetup() {
885
883
  else {
886
884
  outPlatforms.qq = { enabled: false, allowedUserIds: qqIdsFinal };
887
885
  }
888
- if (selectedPlatforms.includes("wechat")) {
889
- const wcConfig = config.platforms?.wechat;
890
- const baseWc = base?.platforms?.wechat;
886
+ if (selectedPlatforms.includes("workbuddy")) {
887
+ const wbConfig = config.platforms?.workbuddy;
888
+ const baseWb = base?.platforms?.workbuddy;
891
889
  const wbOut = {
892
890
  enabled: true,
893
- workbuddyAccessToken: wcConfig?.workbuddyAccessToken ?? baseWc?.workbuddyAccessToken,
894
- workbuddyRefreshToken: wcConfig?.workbuddyRefreshToken ?? baseWc?.workbuddyRefreshToken,
895
- userId: wcConfig?.userId ?? baseWc?.userId ?? "",
896
- allowedUserIds: wechatIds,
891
+ accessToken: wbConfig?.accessToken ?? baseWb?.accessToken,
892
+ refreshToken: wbConfig?.refreshToken ?? baseWb?.refreshToken,
893
+ userId: wbConfig?.userId ?? baseWb?.userId ?? "",
894
+ allowedUserIds: workbuddyIds,
897
895
  };
898
- const wbBaseUrl = wcConfig?.workbuddyBaseUrl ?? baseWc?.workbuddyBaseUrl;
899
- const wbHostId = wcConfig?.workbuddyHostId ?? baseWc?.workbuddyHostId;
896
+ const wbBaseUrl = wbConfig?.baseUrl ?? baseWb?.baseUrl;
900
897
  if (wbBaseUrl)
901
- wbOut.workbuddyBaseUrl = wbBaseUrl;
902
- if (wbHostId)
903
- wbOut.workbuddyHostId = wbHostId;
904
- out.platforms.wechat = wbOut;
898
+ wbOut.baseUrl = wbBaseUrl;
899
+ out.platforms.workbuddy = wbOut;
905
900
  }
906
- else if (basePlatforms?.wechat) {
907
- outPlatforms.wechat = {
908
- ...basePlatforms.wechat,
909
- allowedUserIds: wechatIds.length > 0 ? wechatIds : basePlatforms.wechat.allowedUserIds ?? [],
901
+ else if (basePlatforms?.workbuddy) {
902
+ outPlatforms.workbuddy = {
903
+ ...basePlatforms.workbuddy,
904
+ allowedUserIds: workbuddyIds.length > 0 ? workbuddyIds : basePlatforms.workbuddy.allowedUserIds ?? [],
910
905
  };
911
906
  }
912
907
  else {
913
- outPlatforms.wechat = { enabled: false, allowedUserIds: wechatIds };
908
+ outPlatforms.workbuddy = { enabled: false, allowedUserIds: workbuddyIds };
914
909
  }
915
910
  if (selectedPlatforms.includes("wework")) {
916
911
  outPlatforms.wework = {
@@ -964,10 +959,9 @@ const PLATFORM_LABELS = {
964
959
  feishu: "飞书",
965
960
  wework: "企业微信",
966
961
  dingtalk: "钉钉",
967
- wechat: "微信(测试中)",
968
- workbuddy: "WorkBuddy",
962
+ workbuddy: "WorkBuddy 微信客服",
969
963
  };
970
- const ALL_PLATFORMS = ["telegram", "feishu", "qq", "wework", "dingtalk", "wechat", "workbuddy"];
964
+ const ALL_PLATFORMS = ["telegram", "feishu", "qq", "wework", "dingtalk", "workbuddy"];
971
965
  /**
972
966
  * 启动时让用户选择要启用的平台(无论单通道还是多通道)
973
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: payload.session_id,
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
- requestId: payload.prompt_id,
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
- const body = await res.text().catch(() => '');
173
- log.error(`${this.logPrefix} HTTP COPILOT_RESPONSE failed: ${res.status} ${body.substring(0, 200)}`);
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 - Main client for WorkBuddy WeChat integration
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;