chatccc 0.2.108 → 0.2.110

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,63 +1,63 @@
1
- {
2
- "name": "chatccc",
3
- "version": "0.2.108",
4
- "description": "Feishu bot bridge for Claude Code",
5
- "license": "Apache-2.0",
6
- "type": "module",
7
- "main": "./src/index.ts",
8
- "bin": {
9
- "chatccc": "bin/chatccc.mjs"
10
- },
11
- "files": [
12
- "src/",
13
- "bin/",
14
- "scripts/postinstall-sharp-check.mjs",
15
- "demo/ilink_echo_probe.ts",
16
- "im-skills/",
17
- "images/img_readme_*.jpg",
18
- "images/img_readme_*.png",
19
- "images/avatars/status_*.png",
20
- "images/avatars/badges/",
21
- "package.json",
22
- "README.md",
23
- "config.sample.json"
24
- ],
25
- "scripts": {
26
- "dev": "tsx src/index.ts",
27
- "chatccc": "tsx src/index.ts",
28
- "start": "tsx src/index.ts",
29
- "demo:bot-test": "tsx demo/bot_test.ts",
30
- "demo:bot-test:local": "tsx demo/bot_test.ts --local",
31
- "demo:create-group": "tsx src/index.ts",
32
- "demo:create-group:local": "tsx src/index.ts --local",
33
- "demo:permission-check": "tsx demo/permission_check.ts",
34
- "demo:claude-hi": "tsx demo/claude_say_hi.ts",
35
- "demo:codex-hi": "tsx demo/codex_say_hi.ts",
36
- "demo:ilink-echo": "tsx demo/ilink_echo_probe.ts",
37
- "test": "vitest run",
38
- "test:watch": "vitest",
39
- "postinstall": "node scripts/postinstall-sharp-check.mjs"
40
- },
41
- "dependencies": {
42
- "@ai-sdk/openai-compatible": "^2.0.47",
43
- "@anthropic-ai/claude-agent-sdk": "0.2.133",
44
- "@larksuiteoapi/node-sdk": "^1.59.0",
45
- "@openilink/openilink-sdk-node": "^0.6.0",
46
- "ai": "^6.0.184",
47
- "nodemailer": "^8.0.7",
48
- "qrcode-terminal": "^0.12.0",
49
- "sharp": "^0.34.5",
50
- "tsx": "^4.0.0",
51
- "ws": "^8.18.0"
52
- },
53
- "devDependencies": {
54
- "@types/node": "^20.0.0",
55
- "@types/qrcode-terminal": "^0.12.2",
56
- "@types/ws": "^8.18.1",
57
- "typescript": "^5.0.0",
58
- "vitest": "^3.2.4"
59
- },
60
- "engines": {
61
- "node": ">=20"
62
- }
63
- }
1
+ {
2
+ "name": "chatccc",
3
+ "version": "0.2.110",
4
+ "description": "Feishu bot bridge for Claude Code",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./src/index.ts",
8
+ "bin": {
9
+ "chatccc": "bin/chatccc.mjs"
10
+ },
11
+ "files": [
12
+ "src/",
13
+ "bin/",
14
+ "scripts/postinstall-sharp-check.mjs",
15
+ "demo/ilink_echo_probe.ts",
16
+ "im-skills/",
17
+ "images/img_readme_*.jpg",
18
+ "images/img_readme_*.png",
19
+ "images/avatars/status_*.png",
20
+ "images/avatars/badges/",
21
+ "package.json",
22
+ "README.md",
23
+ "config.sample.json"
24
+ ],
25
+ "scripts": {
26
+ "dev": "tsx src/index.ts",
27
+ "chatccc": "tsx src/index.ts",
28
+ "start": "tsx src/index.ts",
29
+ "demo:bot-test": "tsx demo/bot_test.ts",
30
+ "demo:bot-test:local": "tsx demo/bot_test.ts --local",
31
+ "demo:create-group": "tsx src/index.ts",
32
+ "demo:create-group:local": "tsx src/index.ts --local",
33
+ "demo:permission-check": "tsx demo/permission_check.ts",
34
+ "demo:claude-hi": "tsx demo/claude_say_hi.ts",
35
+ "demo:codex-hi": "tsx demo/codex_say_hi.ts",
36
+ "demo:ilink-echo": "tsx demo/ilink_echo_probe.ts",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "postinstall": "node scripts/postinstall-sharp-check.mjs"
40
+ },
41
+ "dependencies": {
42
+ "@ai-sdk/openai-compatible": "^2.0.47",
43
+ "@anthropic-ai/claude-agent-sdk": "0.2.133",
44
+ "@larksuiteoapi/node-sdk": "^1.59.0",
45
+ "@openilink/openilink-sdk-node": "^0.6.0",
46
+ "ai": "^6.0.184",
47
+ "nodemailer": "^8.0.7",
48
+ "qrcode-terminal": "^0.12.0",
49
+ "sharp": "^0.34.5",
50
+ "tsx": "^4.0.0",
51
+ "ws": "^8.18.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.0.0",
55
+ "@types/qrcode-terminal": "^0.12.2",
56
+ "@types/ws": "^8.18.1",
57
+ "typescript": "^5.0.0",
58
+ "vitest": "^3.2.4"
59
+ },
60
+ "engines": {
61
+ "node": ">=20"
62
+ }
63
+ }
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
  }
@@ -286,6 +286,12 @@ export async function handleCommand(
286
286
  const content = buildCdContent(targetDir, withStats, isUpdate, sessionCwd);
287
287
  await platform.sendCard(chatId, "新会话工作路径", content, "blue");
288
288
  logTrace(tid, "DONE", { outcome: "cd_path", targetDir, isUpdate });
289
+
290
+ // 微信模式下,若用户没有活跃会话,自动创建新会话
291
+ if (platform.kind === "wechat" && !sessionInfoMap.has(chatId)) {
292
+ logTrace(tid, "BRANCH", { cmd: "/new", trigger: "auto_after_cd" });
293
+ await handleCommand(platform, "/new", chatId, openId, msgTimestamp, chatType, traceId);
294
+ }
289
295
  }
290
296
  return;
291
297
  }
@@ -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}`);