chatccc 0.2.107 → 0.2.109

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.107",
3
+ "version": "0.2.109",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -131,7 +131,8 @@ describe("applyLoadedConfig — 刷新 export let 常量", () => {
131
131
  cursor: { enabled: true, defaultAgent: false, path: "/x/cursor", model: "claude-3.7-sonnet" },
132
132
  });
133
133
 
134
- // CURSOR_AGENT_ARGS 是 ['-p', '--force', ..., '--model', 'claude-3.7-sonnet']
134
+ // CURSOR_AGENT_ARGS 是 ['-p', '--force', '--approve-mcps', ..., '--model', 'claude-3.7-sonnet']
135
+ expect(CURSOR_AGENT_ARGS).toContain("--approve-mcps");
135
136
  expect(CURSOR_AGENT_ARGS).toContain("--model");
136
137
  expect(CURSOR_AGENT_ARGS).toContain("claude-3.7-sonnet");
137
138
  });
package/src/config.ts CHANGED
@@ -555,7 +555,7 @@ function detectCursorAgent(): string {
555
555
  export let CURSOR_AGENT_COMMAND = detectCursorAgent();
556
556
 
557
557
  function resolveCursorAgentArgs(): string[] {
558
- let args = "-p --force --output-format stream-json --stream-partial-output";
558
+ let args = "-p --force --approve-mcps --output-format stream-json --stream-partial-output";
559
559
  const model = config.cursor.model;
560
560
  if (model.trim() !== "") {
561
561
  args += ` --model ${model}`;
@@ -563,7 +563,7 @@ function resolveCursorAgentArgs(): string[] {
563
563
  return args.split(/\s+/).filter(Boolean);
564
564
  }
565
565
 
566
- /** Cursor agent 参数:-p 非交互模式,--force 强制允许命令(yolo),stream-json 流式 JSONL 输出 */
566
+ /** Cursor agent 参数:-p 非交互模式,--force 强制允许命令,--approve-mcps 自动批准 MCP,stream-json 流式 JSONL 输出 */
567
567
  export let CURSOR_AGENT_ARGS = resolveCursorAgentArgs();
568
568
 
569
569
  // ---------------------------------------------------------------------------
package/src/index.ts CHANGED
@@ -660,8 +660,11 @@ async function startWechatSupervisor(): Promise<void> {
660
660
  console.log("\n[WX] 启动微信 iLink 平台...");
661
661
 
662
662
  const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
663
+ const MAX_QR_RETRIES = 3;
664
+ let qrTimeoutCount = 0;
663
665
 
664
666
  while (!wechatSignal.stopped) {
667
+ let isQrTimeout = false;
665
668
  try {
666
669
  await startWechatPlatform(
667
670
  (text, chatId, openId, msgTimestamp, chatType, traceId) =>
@@ -669,14 +672,31 @@ async function startWechatSupervisor(): Promise<void> {
669
672
  wechatSignal,
670
673
  ILINK_REUSE_TOKEN_ON_START,
671
674
  );
675
+ // 登录成功后重置计数
676
+ qrTimeoutCount = 0;
672
677
  } catch (err) {
673
- console.error(
674
- `[WX] 微信 iLink 崩溃: ${(err as Error).message}`,
675
- );
678
+ const msg = (err as Error).message ?? "";
679
+ isQrTimeout = msg.includes("QR 登录超时");
680
+ if (isQrTimeout) {
681
+ qrTimeoutCount++;
682
+ console.error(
683
+ `[WX] QR 登录超时 (${qrTimeoutCount}/${MAX_QR_RETRIES}): ${msg}`,
684
+ );
685
+ if (qrTimeoutCount >= MAX_QR_RETRIES) {
686
+ console.error(
687
+ `[WX] 已连续 ${MAX_QR_RETRIES} 次 QR 登录超时,放弃重试。如需重新尝试请重启 ChatCCC。`,
688
+ );
689
+ break;
690
+ }
691
+ } else {
692
+ console.error(`[WX] 微信 iLink 崩溃: ${msg}`);
693
+ }
676
694
  }
677
695
  if (wechatSignal.stopped) break;
678
- console.log("[WX] 5 秒后重试...");
679
- await sleep(5000);
696
+ const delaySeconds = isQrTimeout ? 300 : 30;
697
+ const delayDesc = isQrTimeout ? "5 分钟" : "30 秒";
698
+ console.log(`[WX] ${delayDesc}后重试...`);
699
+ await sleep(delaySeconds * 1000);
680
700
  }
681
701
  console.log("[WX] 微信 iLink 平台已停止。");
682
702
  }
@@ -429,23 +429,34 @@ export async function startWechatPlatform(
429
429
  }
430
430
  }
431
431
 
432
- // 请求新 QR
433
- platformLog("启动微信 iLink QR 登录...");
432
+ // 请求新 QR(5 分钟内未扫码则放弃本轮,由 supervisor 稍后重试)
433
+ const QR_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
434
+ platformLog("启动微信 iLink QR 登录(5 分钟内未扫码将自动重试)...");
434
435
  ilinkWire = new OpenIlinkWire("", {
435
436
  base_url: saved.baseUrl,
436
437
  });
437
438
 
438
- const loginResult = await ilinkWire.loginWithQr({
439
- on_qrcode: (content) => {
440
- printScanMaterial(content);
441
- },
442
- on_scanned: () => {
443
- platformLog("QR 已扫描,请在微信中确认登录。");
444
- },
445
- on_expired: (attempt, maxAttempts) => {
446
- platformLog(`QR 已过期,正在刷新 (${attempt}/${maxAttempts})。`);
447
- },
448
- });
439
+ let qrExpiredCount = 0;
440
+ const loginResult = await Promise.race([
441
+ ilinkWire.loginWithQr({
442
+ on_qrcode: (content) => {
443
+ printScanMaterial(content);
444
+ },
445
+ on_scanned: () => {
446
+ platformLog("QR 已扫描,请在微信中确认登录。");
447
+ },
448
+ on_expired: (attempt, maxAttempts) => {
449
+ qrExpiredCount++;
450
+ platformLog(`QR 已过期,正在刷新 (${attempt}/${maxAttempts})。`);
451
+ },
452
+ }),
453
+ new Promise<never>((_, reject) =>
454
+ setTimeout(
455
+ () => reject(new Error(`QR 登录超时(${QR_LOGIN_TIMEOUT_MS / 60000} 分钟内未扫码,已刷新 ${qrExpiredCount} 次)`)),
456
+ QR_LOGIN_TIMEOUT_MS,
457
+ ),
458
+ ),
459
+ ]);
449
460
 
450
461
  if (!loginResult.connected) {
451
462
  throw new Error(`微信 iLink QR 登录失败: ${loginResult.message}`);