@tencent-connect/openclaw-qqbot 1.6.4-alpha.13 → 1.6.4-alpha.14

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.
@@ -337,26 +337,55 @@ function switchPluginSourceToNpm() {
337
337
  const cfgPath = path.join(homeDir, `.${cli}`, `${cli}.json`);
338
338
  if (!fs.existsSync(cfgPath))
339
339
  continue;
340
- // 读取当前配置
340
+ // 读取当前配置(保留原始文本用于回退)
341
341
  const raw = fs.readFileSync(cfgPath, "utf8");
342
- const cfg = JSON.parse(raw);
342
+ let cfg;
343
+ try {
344
+ cfg = JSON.parse(raw);
345
+ }
346
+ catch {
347
+ // 配置文件已经是损坏的 JSON,不要继续操作以免加剧问题
348
+ break;
349
+ }
343
350
  const inst = cfg?.plugins?.installs?.["openclaw-qqbot"];
344
351
  if (!inst || inst.source === "npm") {
345
352
  break; // 无需修改
346
353
  }
347
- // 记录修改前的 channels.qqbot 快照,用于写后校验
348
- const channelsBefore = JSON.stringify(cfg.channels?.qqbot ?? null);
354
+ // 记录修改前的完整快照,用于写后校验
355
+ const channelsBefore = JSON.stringify(cfg.channels ?? null);
349
356
  inst.source = "npm";
350
357
  delete inst.sourcePath;
351
358
  const newRaw = JSON.stringify(cfg, null, 4) + "\n";
352
- // 写后校验:重新解析确认 channels.qqbot 未被破坏
353
- const verify = JSON.parse(newRaw);
354
- const channelsAfter = JSON.stringify(verify.channels?.qqbot ?? null);
359
+ // 写后校验:重新解析确认整个 JSON 合法且 channels 未被破坏
360
+ let verify;
361
+ try {
362
+ verify = JSON.parse(newRaw);
363
+ }
364
+ catch {
365
+ // stringify 后竟然无法 parse(理论上不会),放弃写入
366
+ break;
367
+ }
368
+ const channelsAfter = JSON.stringify(verify.channels ?? null);
355
369
  if (channelsBefore !== channelsAfter) {
356
370
  // channels 数据异常,放弃写入
357
371
  break;
358
372
  }
359
- fs.writeFileSync(cfgPath, newRaw);
373
+ // 原子写入:先写临时文件,再 rename 替换,避免写入中途崩溃导致配置文件损坏
374
+ const tmpPath = cfgPath + ".qqbot-upgrade.tmp";
375
+ fs.writeFileSync(tmpPath, newRaw, { mode: 0o644 });
376
+ // 再次校验临时文件的完整性
377
+ try {
378
+ JSON.parse(fs.readFileSync(tmpPath, "utf8"));
379
+ }
380
+ catch {
381
+ // 写入的临时文件不完整,清理后放弃
382
+ try {
383
+ fs.unlinkSync(tmpPath);
384
+ }
385
+ catch { }
386
+ break;
387
+ }
388
+ fs.renameSync(tmpPath, cfgPath);
360
389
  break;
361
390
  }
362
391
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tencent-connect/openclaw-qqbot",
3
- "version": "1.6.4-alpha.13",
3
+ "version": "1.6.4-alpha.14",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -433,30 +433,57 @@ function switchPluginSourceToNpm(): void {
433
433
  const cfgPath = path.join(homeDir, `.${cli}`, `${cli}.json`);
434
434
  if (!fs.existsSync(cfgPath)) continue;
435
435
 
436
- // 读取当前配置
436
+ // 读取当前配置(保留原始文本用于回退)
437
437
  const raw = fs.readFileSync(cfgPath, "utf8");
438
- const cfg = JSON.parse(raw);
438
+
439
+ let cfg: any;
440
+ try {
441
+ cfg = JSON.parse(raw);
442
+ } catch {
443
+ // 配置文件已经是损坏的 JSON,不要继续操作以免加剧问题
444
+ break;
445
+ }
446
+
439
447
  const inst = cfg?.plugins?.installs?.["openclaw-qqbot"];
440
448
  if (!inst || inst.source === "npm") {
441
449
  break; // 无需修改
442
450
  }
443
451
 
444
- // 记录修改前的 channels.qqbot 快照,用于写后校验
445
- const channelsBefore = JSON.stringify(cfg.channels?.qqbot ?? null);
452
+ // 记录修改前的完整快照,用于写后校验
453
+ const channelsBefore = JSON.stringify(cfg.channels ?? null);
446
454
 
447
455
  inst.source = "npm";
448
456
  delete inst.sourcePath;
449
457
  const newRaw = JSON.stringify(cfg, null, 4) + "\n";
450
458
 
451
- // 写后校验:重新解析确认 channels.qqbot 未被破坏
452
- const verify = JSON.parse(newRaw);
453
- const channelsAfter = JSON.stringify(verify.channels?.qqbot ?? null);
459
+ // 写后校验:重新解析确认整个 JSON 合法且 channels 未被破坏
460
+ let verify: any;
461
+ try {
462
+ verify = JSON.parse(newRaw);
463
+ } catch {
464
+ // stringify 后竟然无法 parse(理论上不会),放弃写入
465
+ break;
466
+ }
467
+ const channelsAfter = JSON.stringify(verify.channels ?? null);
454
468
  if (channelsBefore !== channelsAfter) {
455
469
  // channels 数据异常,放弃写入
456
470
  break;
457
471
  }
458
472
 
459
- fs.writeFileSync(cfgPath, newRaw);
473
+ // 原子写入:先写临时文件,再 rename 替换,避免写入中途崩溃导致配置文件损坏
474
+ const tmpPath = cfgPath + ".qqbot-upgrade.tmp";
475
+ fs.writeFileSync(tmpPath, newRaw, { mode: 0o644 });
476
+
477
+ // 再次校验临时文件的完整性
478
+ try {
479
+ JSON.parse(fs.readFileSync(tmpPath, "utf8"));
480
+ } catch {
481
+ // 写入的临时文件不完整,清理后放弃
482
+ try { fs.unlinkSync(tmpPath); } catch {}
483
+ break;
484
+ }
485
+
486
+ fs.renameSync(tmpPath, cfgPath);
460
487
  break;
461
488
  }
462
489
  } catch {