@ryantest/openclaw-qqbot 1.6.7-beta.15 → 1.6.7-beta.16

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.
@@ -694,131 +694,91 @@ function fireHotUpgrade(targetVersion, pkg, useLocal) {
694
694
  // openclaw plugins install/update 启动时会校验整个配置文件,
695
695
  // 如果 channels.qqbot 已存在但 qqbot 插件尚未加载,校验会报 "unknown channel id: qqbot"。
696
696
  //
697
- // 策略(双保险):
698
- // 1. 直接从真实 openclaw.json 中临时移除 channels.qqbot / plugins.entries.openclaw-qqbot,
699
- // 暂存到备份文件,脚本完成后恢复。这是最可靠的方式,因为 openclaw CLI 一定读取真实配置。
700
- // 移除后的配置是合法的,gateway 的 config file watcher 重新加载不会失败。
701
- // 2. 同时创建临时配置副本并通过 OPENCLAW_CONFIG_PATH 环境变量传递给子进程,
702
- // 作为额外保险(防止某些 openclaw 版本在 install 过程中多次加载配置)。
697
+ // ⚠️ 关键:绝不能直接修改真实的 openclaw.json!
698
+ // gateway config file watcher 会检测到变更并触发 SIGUSR1 重启,
699
+ // 导致当前进程被杀、execFile 回调(restoreConfigAndCleanup)永远不会执行,
700
+ // channels.qqbot 配置就此丢失。
701
+ //
702
+ // 策略:创建临时配置副本(不含 channels.qqbot),通过 OPENCLAW_CONFIG_PATH
703
+ // 环境变量传递给子进程,真实配置文件不受影响。
704
+ // shell 脚本(upgrade-via-npm.sh)内部也有同样的临时配置机制作为双保险。
703
705
  const homeDir = getHomeDir();
704
706
  const realConfigPath = path.join(homeDir, ".openclaw", "openclaw.json");
705
- const channelBackupPath = path.join(homeDir, ".openclaw", ".qqbot-upgrade-channel-stash.json");
706
- let stashedChannelConfig = null;
707
- let stashedPluginEntry = null;
708
- let configModified = false;
709
707
  let tempConfigPath = null;
710
708
  const childEnv = { ...process.env };
711
709
  try {
712
710
  if (fs.existsSync(realConfigPath)) {
713
711
  const cfg = JSON.parse(fs.readFileSync(realConfigPath, "utf8"));
714
- let needsModify = false;
715
- if (cfg.channels?.qqbot)
716
- needsModify = true;
717
- if (cfg.plugins?.entries?.["openclaw-qqbot"])
718
- needsModify = true;
719
- if (needsModify) {
720
- // 暂存需要移除的配置项
721
- const stash = {};
722
- if (cfg.channels?.qqbot) {
723
- stash.channelsQqbot = cfg.channels.qqbot;
724
- stashedChannelConfig = cfg.channels.qqbot;
725
- }
726
- if (cfg.plugins?.entries?.["openclaw-qqbot"]) {
727
- stash.pluginsEntry = cfg.plugins.entries["openclaw-qqbot"];
728
- stashedPluginEntry = cfg.plugins.entries["openclaw-qqbot"];
712
+ const needsTempConfig = !!(cfg.channels?.qqbot) ||
713
+ !!(cfg.plugins?.entries?.["openclaw-qqbot"]);
714
+ if (needsTempConfig) {
715
+ // 创建临时配置副本(移除 channels.qqbot 和 plugins.entries.openclaw-qqbot
716
+ const cleanCfg = JSON.parse(JSON.stringify(cfg)); // deep clone
717
+ if (cleanCfg.channels?.qqbot) {
718
+ delete cleanCfg.channels.qqbot;
719
+ if (Object.keys(cleanCfg.channels).length === 0)
720
+ delete cleanCfg.channels;
729
721
  }
730
- // 写入备份文件(防止进程异常退出时丢失暂存数据)
731
- fs.writeFileSync(channelBackupPath, JSON.stringify(stash, null, 2), "utf8");
732
- // 从真实配置中移除会导致校验失败的项
733
- if (cfg.channels?.qqbot) {
734
- delete cfg.channels.qqbot;
735
- if (Object.keys(cfg.channels).length === 0)
736
- delete cfg.channels;
722
+ if (cleanCfg.plugins?.entries?.["openclaw-qqbot"]) {
723
+ delete cleanCfg.plugins.entries["openclaw-qqbot"];
724
+ if (cleanCfg.plugins.entries && Object.keys(cleanCfg.plugins.entries).length === 0)
725
+ delete cleanCfg.plugins.entries;
737
726
  }
738
- if (cfg.plugins?.entries?.["openclaw-qqbot"]) {
739
- delete cfg.plugins.entries["openclaw-qqbot"];
740
- if (Object.keys(cfg.plugins.entries).length === 0)
741
- delete cfg.plugins.entries;
742
- }
743
- fs.writeFileSync(realConfigPath, JSON.stringify(cfg, null, 4) + "\n");
744
- configModified = true;
745
- console.log(`[qqbot] fireHotUpgrade: temporarily removed channels.qqbot & plugins.entries from real config (stash=${channelBackupPath})`);
746
- // 双保险:同时创建临时配置副本并通过 OPENCLAW_CONFIG_PATH 传递
747
- try {
748
- const tmpDir = path.join(homeDir, ".openclaw", ".qqbot-upgrade-tmp");
749
- fs.mkdirSync(tmpDir, { recursive: true });
750
- tempConfigPath = path.join(tmpDir, "openclaw-tmp.json");
751
- fs.writeFileSync(tempConfigPath, JSON.stringify(cfg, null, 4) + "\n");
752
- childEnv.OPENCLAW_CONFIG_PATH = tempConfigPath;
753
- }
754
- catch { /* 非关键,忽略 */ }
727
+ const tmpDir = path.join(homeDir, ".openclaw", ".qqbot-upgrade-tmp");
728
+ fs.mkdirSync(tmpDir, { recursive: true });
729
+ tempConfigPath = path.join(tmpDir, "openclaw-tmp.json");
730
+ fs.writeFileSync(tempConfigPath, JSON.stringify(cleanCfg, null, 4) + "\n");
731
+ childEnv.OPENCLAW_CONFIG_PATH = tempConfigPath;
732
+ console.log(`[qqbot] fireHotUpgrade: created temp config without channels.qqbot (OPENCLAW_CONFIG_PATH=${tempConfigPath}), real config untouched`);
755
733
  }
756
734
  }
757
735
  }
758
736
  catch (e) {
759
- console.warn(`[qqbot] fireHotUpgrade: failed to modify config for upgrade: ${e.message}, proceeding with original`);
760
- configModified = false;
761
- stashedChannelConfig = null;
762
- stashedPluginEntry = null;
737
+ console.warn(`[qqbot] fireHotUpgrade: failed to create temp config: ${e.message}, proceeding with original`);
738
+ tempConfigPath = null;
763
739
  }
764
740
  /**
765
- * 恢复暂存的 channels.qqbot plugins.entries 到真实配置,
766
- * 同时合并 openclaw plugins install 写入的 installs/entries 记录。
741
+ * openclaw plugins install 写入临时配置的 installs/entries 记录同步回真实配置,
742
+ * 然后清理临时文件。
743
+ *
744
+ * 注意:真实配置中的 channels.qqbot 从未被移除,无需恢复。
767
745
  */
768
- function restoreConfigAndCleanup() {
746
+ function syncTempConfigAndCleanup() {
769
747
  try {
770
- // 从备份文件恢复暂存数据(优先使用文件,防止内存中的数据因异常丢失)
771
- let stash = {};
772
- if (fs.existsSync(channelBackupPath)) {
773
- try {
774
- stash = JSON.parse(fs.readFileSync(channelBackupPath, "utf8"));
775
- }
776
- catch { /* 解析失败,使用内存中的数据 */ }
777
- }
778
- const channelCfg = stash.channelsQqbot ?? stashedChannelConfig;
779
- const entryCfg = stash.pluginsEntry ?? stashedPluginEntry;
780
- if (configModified && fs.existsSync(realConfigPath)) {
781
- const cfg = JSON.parse(fs.readFileSync(realConfigPath, "utf8"));
782
- // 恢复 channels.qqbot
783
- if (channelCfg) {
784
- if (!cfg.channels)
785
- cfg.channels = {};
786
- cfg.channels.qqbot = channelCfg;
787
- }
788
- // 恢复 plugins.entries.openclaw-qqbot(仅当 openclaw plugins install 没有写入新 entry 时)
789
- if (entryCfg) {
790
- if (!cfg.plugins)
791
- cfg.plugins = {};
792
- if (!cfg.plugins.entries)
793
- cfg.plugins.entries = {};
794
- if (!cfg.plugins.entries["openclaw-qqbot"]) {
795
- cfg.plugins.entries["openclaw-qqbot"] = entryCfg;
796
- }
748
+ if (tempConfigPath && fs.existsSync(tempConfigPath) && fs.existsSync(realConfigPath)) {
749
+ const tmp = JSON.parse(fs.readFileSync(tempConfigPath, "utf8"));
750
+ const real = JSON.parse(fs.readFileSync(realConfigPath, "utf8"));
751
+ let changed = false;
752
+ // 同步 plugins.installs(openclaw plugins install 会写入安装记录)
753
+ if (tmp.plugins?.installs) {
754
+ if (!real.plugins)
755
+ real.plugins = {};
756
+ real.plugins.installs = { ...(real.plugins.installs || {}), ...tmp.plugins.installs };
757
+ changed = true;
797
758
  }
798
- // 如果临时配置中有 plugins install 写入的新记录,也合并过来
799
- if (tempConfigPath && fs.existsSync(tempConfigPath)) {
800
- try {
801
- const tmp = JSON.parse(fs.readFileSync(tempConfigPath, "utf8"));
802
- if (tmp.plugins?.installs) {
803
- if (!cfg.plugins)
804
- cfg.plugins = {};
805
- cfg.plugins.installs = { ...(cfg.plugins.installs || {}), ...tmp.plugins.installs };
759
+ // 同步 plugins.entries(openclaw plugins install 会写入 entries)
760
+ if (tmp.plugins?.entries) {
761
+ if (!real.plugins)
762
+ real.plugins = {};
763
+ if (!real.plugins.entries)
764
+ real.plugins.entries = {};
765
+ for (const [k, v] of Object.entries(tmp.plugins.entries)) {
766
+ if (!real.plugins.entries[k]) {
767
+ real.plugins.entries[k] = v;
768
+ changed = true;
806
769
  }
807
770
  }
808
- catch { /* 忽略 */ }
809
771
  }
810
- fs.writeFileSync(realConfigPath, JSON.stringify(cfg, null, 4) + "\n");
811
- console.log("[qqbot] fireHotUpgrade: restored channels.qqbot & plugins.entries to real config");
772
+ if (changed) {
773
+ fs.writeFileSync(realConfigPath, JSON.stringify(real, null, 4) + "\n");
774
+ console.log("[qqbot] fireHotUpgrade: synced install/entries records from temp config to real config");
775
+ }
812
776
  }
813
777
  }
814
778
  catch (e) {
815
- console.warn(`[qqbot] fireHotUpgrade: failed to restore config: ${e.message}`);
779
+ console.warn(`[qqbot] fireHotUpgrade: failed to sync temp config: ${e.message}`);
816
780
  }
817
- // 清理备份和临时文件
818
- try {
819
- fs.unlinkSync(channelBackupPath);
820
- }
821
- catch { /* ignore */ }
781
+ // 清理临时文件
822
782
  try {
823
783
  if (tempConfigPath)
824
784
  fs.unlinkSync(tempConfigPath);
@@ -841,7 +801,7 @@ function fireHotUpgrade(targetVersion, pkg, useLocal) {
841
801
  console.error(`[qqbot] fireHotUpgrade: stdout: ${stdout.slice(0, 2000)}`);
842
802
  if (_stderr)
843
803
  console.error(`[qqbot] fireHotUpgrade: stderr: ${_stderr.slice(0, 2000)}`);
844
- restoreConfigAndCleanup();
804
+ syncTempConfigAndCleanup();
845
805
  cleanupTempScript();
846
806
  _upgrading = false;
847
807
  return;
@@ -852,14 +812,14 @@ function fireHotUpgrade(targetVersion, pkg, useLocal) {
852
812
  const newVersion = versionMatch?.[1];
853
813
  if (newVersion === "unknown") {
854
814
  console.error(`[qqbot] fireHotUpgrade: script output QQBOT_NEW_VERSION=unknown, aborting restart`);
855
- restoreConfigAndCleanup();
815
+ syncTempConfigAndCleanup();
856
816
  cleanupTempScript();
857
817
  _upgrading = false;
858
818
  return;
859
819
  }
860
820
  console.log(`[qqbot] fireHotUpgrade: new version=${newVersion || "(not detected)"}, triggering restart...`);
861
- // 脚本执行成功,恢复暂存的配置并清理
862
- restoreConfigAndCleanup();
821
+ // 脚本执行成功,同步临时配置中的 install 记录并清理
822
+ syncTempConfigAndCleanup();
863
823
  cleanupTempScript();
864
824
  // 文件替换成功,在 restart 之前把 source 从 path 切换为 npm,
865
825
  // 确保新进程启动时读到的是 npm source,不会被本地源码覆盖。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryantest/openclaw-qqbot",
3
- "version": "1.6.7-beta.15",
3
+ "version": "1.6.7-beta.16",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -796,125 +796,91 @@ function fireHotUpgrade(targetVersion?: string, pkg?: string, useLocal?: boolean
796
796
  // openclaw plugins install/update 启动时会校验整个配置文件,
797
797
  // 如果 channels.qqbot 已存在但 qqbot 插件尚未加载,校验会报 "unknown channel id: qqbot"。
798
798
  //
799
- // 策略(双保险):
800
- // 1. 直接从真实 openclaw.json 中临时移除 channels.qqbot / plugins.entries.openclaw-qqbot,
801
- // 暂存到备份文件,脚本完成后恢复。这是最可靠的方式,因为 openclaw CLI 一定读取真实配置。
802
- // 移除后的配置是合法的,gateway 的 config file watcher 重新加载不会失败。
803
- // 2. 同时创建临时配置副本并通过 OPENCLAW_CONFIG_PATH 环境变量传递给子进程,
804
- // 作为额外保险(防止某些 openclaw 版本在 install 过程中多次加载配置)。
799
+ // ⚠️ 关键:绝不能直接修改真实的 openclaw.json!
800
+ // gateway config file watcher 会检测到变更并触发 SIGUSR1 重启,
801
+ // 导致当前进程被杀、execFile 回调(restoreConfigAndCleanup)永远不会执行,
802
+ // channels.qqbot 配置就此丢失。
803
+ //
804
+ // 策略:创建临时配置副本(不含 channels.qqbot),通过 OPENCLAW_CONFIG_PATH
805
+ // 环境变量传递给子进程,真实配置文件不受影响。
806
+ // shell 脚本(upgrade-via-npm.sh)内部也有同样的临时配置机制作为双保险。
805
807
  const homeDir = getHomeDir();
806
808
  const realConfigPath = path.join(homeDir, ".openclaw", "openclaw.json");
807
- const channelBackupPath = path.join(homeDir, ".openclaw", ".qqbot-upgrade-channel-stash.json");
808
- let stashedChannelConfig: unknown = null;
809
- let stashedPluginEntry: unknown = null;
810
- let configModified = false;
811
809
  let tempConfigPath: string | null = null;
812
810
  const childEnv: NodeJS.ProcessEnv = { ...process.env };
813
811
 
814
812
  try {
815
813
  if (fs.existsSync(realConfigPath)) {
816
814
  const cfg = JSON.parse(fs.readFileSync(realConfigPath, "utf8"));
817
- let needsModify = false;
818
-
819
- if (cfg.channels?.qqbot) needsModify = true;
820
- if (cfg.plugins?.entries?.["openclaw-qqbot"]) needsModify = true;
821
-
822
- if (needsModify) {
823
- // 暂存需要移除的配置项
824
- const stash: Record<string, unknown> = {};
825
- if (cfg.channels?.qqbot) {
826
- stash.channelsQqbot = cfg.channels.qqbot;
827
- stashedChannelConfig = cfg.channels.qqbot;
815
+ const needsTempConfig =
816
+ !!(cfg.channels?.qqbot) ||
817
+ !!(cfg.plugins?.entries?.["openclaw-qqbot"]);
818
+
819
+ if (needsTempConfig) {
820
+ // 创建临时配置副本(移除 channels.qqbot 和 plugins.entries.openclaw-qqbot)
821
+ const cleanCfg = JSON.parse(JSON.stringify(cfg)); // deep clone
822
+ if (cleanCfg.channels?.qqbot) {
823
+ delete cleanCfg.channels.qqbot;
824
+ if (Object.keys(cleanCfg.channels).length === 0) delete cleanCfg.channels;
828
825
  }
829
- if (cfg.plugins?.entries?.["openclaw-qqbot"]) {
830
- stash.pluginsEntry = cfg.plugins.entries["openclaw-qqbot"];
831
- stashedPluginEntry = cfg.plugins.entries["openclaw-qqbot"];
826
+ if (cleanCfg.plugins?.entries?.["openclaw-qqbot"]) {
827
+ delete cleanCfg.plugins.entries["openclaw-qqbot"];
828
+ if (cleanCfg.plugins.entries && Object.keys(cleanCfg.plugins.entries).length === 0) delete cleanCfg.plugins.entries;
832
829
  }
833
- // 写入备份文件(防止进程异常退出时丢失暂存数据)
834
- fs.writeFileSync(channelBackupPath, JSON.stringify(stash, null, 2), "utf8");
835
830
 
836
- // 从真实配置中移除会导致校验失败的项
837
- if (cfg.channels?.qqbot) {
838
- delete cfg.channels.qqbot;
839
- if (Object.keys(cfg.channels).length === 0) delete cfg.channels;
840
- }
841
- if (cfg.plugins?.entries?.["openclaw-qqbot"]) {
842
- delete cfg.plugins.entries["openclaw-qqbot"];
843
- if (Object.keys(cfg.plugins.entries).length === 0) delete cfg.plugins.entries;
844
- }
845
- fs.writeFileSync(realConfigPath, JSON.stringify(cfg, null, 4) + "\n");
846
- configModified = true;
847
- console.log(`[qqbot] fireHotUpgrade: temporarily removed channels.qqbot & plugins.entries from real config (stash=${channelBackupPath})`);
848
-
849
- // 双保险:同时创建临时配置副本并通过 OPENCLAW_CONFIG_PATH 传递
850
- try {
851
- const tmpDir = path.join(homeDir, ".openclaw", ".qqbot-upgrade-tmp");
852
- fs.mkdirSync(tmpDir, { recursive: true });
853
- tempConfigPath = path.join(tmpDir, "openclaw-tmp.json");
854
- fs.writeFileSync(tempConfigPath, JSON.stringify(cfg, null, 4) + "\n");
855
- childEnv.OPENCLAW_CONFIG_PATH = tempConfigPath;
856
- } catch { /* 非关键,忽略 */ }
831
+ const tmpDir = path.join(homeDir, ".openclaw", ".qqbot-upgrade-tmp");
832
+ fs.mkdirSync(tmpDir, { recursive: true });
833
+ tempConfigPath = path.join(tmpDir, "openclaw-tmp.json");
834
+ fs.writeFileSync(tempConfigPath, JSON.stringify(cleanCfg, null, 4) + "\n");
835
+ childEnv.OPENCLAW_CONFIG_PATH = tempConfigPath;
836
+ console.log(`[qqbot] fireHotUpgrade: created temp config without channels.qqbot (OPENCLAW_CONFIG_PATH=${tempConfigPath}), real config untouched`);
857
837
  }
858
838
  }
859
839
  } catch (e: any) {
860
- console.warn(`[qqbot] fireHotUpgrade: failed to modify config for upgrade: ${e.message}, proceeding with original`);
861
- configModified = false;
862
- stashedChannelConfig = null;
863
- stashedPluginEntry = null;
840
+ console.warn(`[qqbot] fireHotUpgrade: failed to create temp config: ${e.message}, proceeding with original`);
841
+ tempConfigPath = null;
864
842
  }
865
843
 
866
844
  /**
867
- * 恢复暂存的 channels.qqbot plugins.entries 到真实配置,
868
- * 同时合并 openclaw plugins install 写入的 installs/entries 记录。
845
+ * openclaw plugins install 写入临时配置的 installs/entries 记录同步回真实配置,
846
+ * 然后清理临时文件。
847
+ *
848
+ * 注意:真实配置中的 channels.qqbot 从未被移除,无需恢复。
869
849
  */
870
- function restoreConfigAndCleanup(): void {
850
+ function syncTempConfigAndCleanup(): void {
871
851
  try {
872
- // 从备份文件恢复暂存数据(优先使用文件,防止内存中的数据因异常丢失)
873
- let stash: Record<string, unknown> = {};
874
- if (fs.existsSync(channelBackupPath)) {
875
- try {
876
- stash = JSON.parse(fs.readFileSync(channelBackupPath, "utf8"));
877
- } catch { /* 解析失败,使用内存中的数据 */ }
878
- }
879
- const channelCfg = stash.channelsQqbot ?? stashedChannelConfig;
880
- const entryCfg = stash.pluginsEntry ?? stashedPluginEntry;
881
-
882
- if (configModified && fs.existsSync(realConfigPath)) {
883
- const cfg = JSON.parse(fs.readFileSync(realConfigPath, "utf8"));
884
-
885
- // 恢复 channels.qqbot
886
- if (channelCfg) {
887
- if (!cfg.channels) cfg.channels = {};
888
- cfg.channels.qqbot = channelCfg;
852
+ if (tempConfigPath && fs.existsSync(tempConfigPath) && fs.existsSync(realConfigPath)) {
853
+ const tmp = JSON.parse(fs.readFileSync(tempConfigPath, "utf8"));
854
+ const real = JSON.parse(fs.readFileSync(realConfigPath, "utf8"));
855
+ let changed = false;
856
+
857
+ // 同步 plugins.installs(openclaw plugins install 会写入安装记录)
858
+ if (tmp.plugins?.installs) {
859
+ if (!real.plugins) real.plugins = {};
860
+ real.plugins.installs = { ...(real.plugins.installs || {}), ...tmp.plugins.installs };
861
+ changed = true;
889
862
  }
890
- // 恢复 plugins.entries.openclaw-qqbot(仅当 openclaw plugins install 没有写入新 entry 时)
891
- if (entryCfg) {
892
- if (!cfg.plugins) cfg.plugins = {};
893
- if (!cfg.plugins.entries) cfg.plugins.entries = {};
894
- if (!cfg.plugins.entries["openclaw-qqbot"]) {
895
- cfg.plugins.entries["openclaw-qqbot"] = entryCfg;
863
+ // 同步 plugins.entriesopenclaw plugins install 会写入 entries)
864
+ if (tmp.plugins?.entries) {
865
+ if (!real.plugins) real.plugins = {};
866
+ if (!real.plugins.entries) real.plugins.entries = {};
867
+ for (const [k, v] of Object.entries(tmp.plugins.entries)) {
868
+ if (!real.plugins.entries[k]) {
869
+ real.plugins.entries[k] = v;
870
+ changed = true;
871
+ }
896
872
  }
897
873
  }
898
874
 
899
- // 如果临时配置中有 plugins install 写入的新记录,也合并过来
900
- if (tempConfigPath && fs.existsSync(tempConfigPath)) {
901
- try {
902
- const tmp = JSON.parse(fs.readFileSync(tempConfigPath, "utf8"));
903
- if (tmp.plugins?.installs) {
904
- if (!cfg.plugins) cfg.plugins = {};
905
- cfg.plugins.installs = { ...(cfg.plugins.installs || {}), ...tmp.plugins.installs };
906
- }
907
- } catch { /* 忽略 */ }
875
+ if (changed) {
876
+ fs.writeFileSync(realConfigPath, JSON.stringify(real, null, 4) + "\n");
877
+ console.log("[qqbot] fireHotUpgrade: synced install/entries records from temp config to real config");
908
878
  }
909
-
910
- fs.writeFileSync(realConfigPath, JSON.stringify(cfg, null, 4) + "\n");
911
- console.log("[qqbot] fireHotUpgrade: restored channels.qqbot & plugins.entries to real config");
912
879
  }
913
880
  } catch (e: any) {
914
- console.warn(`[qqbot] fireHotUpgrade: failed to restore config: ${e.message}`);
881
+ console.warn(`[qqbot] fireHotUpgrade: failed to sync temp config: ${e.message}`);
915
882
  }
916
- // 清理备份和临时文件
917
- try { fs.unlinkSync(channelBackupPath); } catch { /* ignore */ }
883
+ // 清理临时文件
918
884
  try { if (tempConfigPath) fs.unlinkSync(tempConfigPath); } catch { /* ignore */ }
919
885
  }
920
886
 
@@ -932,7 +898,7 @@ function fireHotUpgrade(targetVersion?: string, pkg?: string, useLocal?: boolean
932
898
  console.error(`[qqbot] fireHotUpgrade: script failed: ${error.message}`);
933
899
  if (stdout) console.error(`[qqbot] fireHotUpgrade: stdout: ${stdout.slice(0, 2000)}`);
934
900
  if (_stderr) console.error(`[qqbot] fireHotUpgrade: stderr: ${_stderr.slice(0, 2000)}`);
935
- restoreConfigAndCleanup();
901
+ syncTempConfigAndCleanup();
936
902
  cleanupTempScript();
937
903
  _upgrading = false;
938
904
  return;
@@ -945,7 +911,7 @@ function fireHotUpgrade(targetVersion?: string, pkg?: string, useLocal?: boolean
945
911
  const newVersion = versionMatch?.[1];
946
912
  if (newVersion === "unknown") {
947
913
  console.error(`[qqbot] fireHotUpgrade: script output QQBOT_NEW_VERSION=unknown, aborting restart`);
948
- restoreConfigAndCleanup();
914
+ syncTempConfigAndCleanup();
949
915
  cleanupTempScript();
950
916
  _upgrading = false;
951
917
  return;
@@ -953,8 +919,8 @@ function fireHotUpgrade(targetVersion?: string, pkg?: string, useLocal?: boolean
953
919
 
954
920
  console.log(`[qqbot] fireHotUpgrade: new version=${newVersion || "(not detected)"}, triggering restart...`);
955
921
 
956
- // 脚本执行成功,恢复暂存的配置并清理
957
- restoreConfigAndCleanup();
922
+ // 脚本执行成功,同步临时配置中的 install 记录并清理
923
+ syncTempConfigAndCleanup();
958
924
  cleanupTempScript();
959
925
 
960
926
  // 文件替换成功,在 restart 之前把 source 从 path 切换为 npm,