@zaofan/dsh-qqbot 1.5.15 → 1.5.17

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.
@@ -4832,8 +4832,17 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
4832
4832
  state.wantPeer = null
4833
4833
  paintDetect()
4834
4834
  lookupCurrentSession(function (hit) {
4835
- if (!state.accts.length) { api('accounts').then(function (dd) { var list = (dd && Array.isArray(dd.instances) ? dd.instances : []).filter(function (a) { return !a.disabled }); state.accts = list; applyHit(hit, list) }) }
4836
- else applyHit(hit, state.accts)
4835
+ // ⚠️ 2026-09-28 修:只滤 disabled 不够 —— 插件 bundle 自动注入的「幽灵实例」
4836
+ // (id: im-qqbot,凭据是占位符 __FROM_ENV__) 的 disabled 是 false,
4837
+ // 它只是【没有 appId】。它一旦被当成"当前账号",面板就会读它的空配置,
4838
+ // 于是评分模式等全部回落成 schema 默认值(看着像"设置全被重置")。
4839
+ function realOnly(list) {
4840
+ return (Array.isArray(list) ? list : []).filter(function (a) {
4841
+ return a && !a.disabled && a.appId
4842
+ })
4843
+ }
4844
+ if (!state.accts.length) { api('accounts').then(function (dd) { var list = realOnly(dd && dd.instances); state.accts = list; applyHit(hit, list) }) }
4845
+ else applyHit(hit, realOnly(state.accts))
4837
4846
  })
4838
4847
  }
4839
4848
  function applyHit(hit, list) {
@@ -4843,6 +4852,8 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
4843
4852
  if (hit.scope === 'c2c') { state.sendScope = 'c2c'; state.sendTo = hit.peerId; state.sendName = hit.name || '' }
4844
4853
  else { state.sendScope = 'group'; state.gid = hit.peerId }
4845
4854
  } else if (list.length && !state.ns) {
4855
+ // 反查不到(例如切到了非 QQ 会话)→ 回落到第一个【真实例】,
4856
+ // ⚠️ 绝不能落到幽灵实例,否则整个面板会显示成默认值。
4846
4857
  state.ns = list[0].ns || ''
4847
4858
  }
4848
4859
  refreshAll(); paintHead(); paintDetect()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaofan/dsh-qqbot",
3
- "version": "1.5.15",
3
+ "version": "1.5.17",
4
4
  "description": "QQ Bot IM channel plugin for deepseek-harness (dsh)",
5
5
  "type": "module",
6
6
  "main": "./entry.js",
package/settings-host.js CHANGED
@@ -837,14 +837,20 @@ export function apply(ctx) {
837
837
  hasFile,
838
838
  instances: bots.map((b) => {
839
839
  // ⚠️ 2026-09-28 修:保存时 cwd/preset/appId 只写【自有存储】(见 saveInstances 的 2026-09-24 注释),
840
- // 但回显原先只读 patch → 界面上填过的 cwd/preset 保存后就"变空"了(前端拿到空串)。
841
- // 这里把自有存储的值一并合并,与写路径对称(patch 优先,其次自有存储)。
840
+ // 但回显原先只读 patch → 界面上填过的 cwd/preset 保存后就"变空"/"显示旧值"。
841
+ // **自有存储优先**(那是用户在设置页保存的最新值;patch 是历史旧值),与 /read 一致。
842
842
  let ownCfg = {};
843
- try { ownCfg = readOwnSettings(String(b.id)) || {}; } catch { ownCfg = {}; }
844
- const cwd = b.cfg?.cwd || ownCfg.cwd || '';
845
- const presetMerged = b.cfg?.preset || ownCfg.preset || '';
846
- const appIdMerged = b.cfg?.appId || ownCfg.appId || '';
847
- const hasSecretMerged = !!(b.cfg?.appSecret || ownCfg.appSecret);
843
+ try { ownCfg = readOwnSettings(String(b.cfg?.settingsNs || b.id)) || {}; } catch { ownCfg = {}; }
844
+ const pickOwn = (k) => {
845
+ const o = ownCfg[k];
846
+ if (o !== undefined && o !== '') return o;
847
+ const c = b.cfg ? b.cfg[k] : undefined;
848
+ return c !== undefined && c !== '' ? c : '';
849
+ };
850
+ const cwd = pickOwn('cwd');
851
+ const presetMerged = pickOwn('preset');
852
+ const appIdMerged = pickOwn('appId');
853
+ const hasSecretMerged = !!pickOwn('appSecret');
848
854
  // 数据根与 dist 侧 dataRootOf 对齐: 未配 dataRoot → `{cwd}/dshqqbot`(2026-09-12 新默认)
849
855
  const droot = b.cfg?.dataRoot || (cwd ? join(cwd, 'dshqqbot') : '');
850
856
  return {
@@ -1748,13 +1754,23 @@ export function apply(ctx) {
1748
1754
  * (避免多条目 insert 时块边界写歪 YAML)。但桥里有若干地方**只读 patch** 取账号配置,
1749
1755
  * 于是用户存进自有存储的值读不到 —— 表现为:
1750
1756
  * · 账号页填了「工作目录」保存后回显为空
1751
- * · nsBot() 返回 null → 群管理/图库/无上下文/Excel 导出全部走错路径
1752
- * 这里统一合并(patch 优先,其次自有存储),所有取账号配置的入口都应走它。
1757
+ * · 改「Agent 预设(人格)」后界面仍显示旧人格(看起来"没改成")
1758
+ * · nsBot() 拿到旧的 appSecret/cwd → 用错凭据连不上(掉线)/ 群管理图库走错路径
1759
+ *
1760
+ * ⚠️⚠️ 优先级必须【自有存储优先】:自有存储 = 用户在设置页保存的最新值;
1761
+ * patch = 历史遗留的旧值。这与 /read 接口的做法一致:
1762
+ * const value = Object.assign({}, base.value || {}, own) // own 覆盖 base
1763
+ * (人家第一版写成"patch 优先",方向搞反,导致界面始终显示旧人格 —— 已修正。)
1753
1764
  */
1754
1765
  function mergeOwnIntoCfg(cfg, nsLike) {
1755
1766
  let own = {};
1756
1767
  try { own = readOwnSettings(String(nsLike)) || {}; } catch { own = {}; }
1757
- const pick = (k) => (cfg && cfg[k] !== undefined && cfg[k] !== '' ? cfg[k] : (own[k] !== undefined && own[k] !== '' ? own[k] : (cfg ? cfg[k] : undefined)));
1768
+ const pick = (k) => {
1769
+ const o = own[k];
1770
+ if (o !== undefined && o !== '') return o; // ← 自有存储优先(用户最新保存的)
1771
+ const c = cfg ? cfg[k] : undefined;
1772
+ return c !== undefined && c !== '' ? c : (cfg ? cfg[k] : undefined);
1773
+ };
1758
1774
  return {
1759
1775
  ...cfg,
1760
1776
  appId: pick('appId'),
@@ -1772,18 +1788,16 @@ export function apply(ctx) {
1772
1788
  if (!b) return null;
1773
1789
  // ⚠️ 2026-09-28 修(同类问题根治):自 2026-09-24 起,已有账号的 appId/appSecret/preset/cwd
1774
1790
  // 只写【插件自有存储】,不再写 profile patch(避免多条目 insert 时块边界写歪 YAML)。
1775
- // 但这里原先只读 patch → 用户存进自有存储的 cwd 读不到 → 数据目录算成空 →
1776
- // 群管理 / 图库 / 无上下文 / Excel 导出 等**所有**依赖 nsBot 的接口全部走错路径
1777
- // (症状:报"找不到该账号实例(请先在账号页配置 appId/appSecret)"、图库与定时目录消失)。
1778
- // 现在先合并自有存储(patch 优先,其次自有存储),与写路径对称。
1779
- let own = {};
1780
- try { own = readOwnSettings(String(b.cfg?.settingsNs || id)) || {}; } catch { own = {}; }
1781
- const appId = b.cfg?.appId || own.appId || '';
1782
- const appSecret = b.cfg?.appSecret || own.appSecret || '';
1791
+ // 但这里原先只读 patch → 用户存进自有存储的 cwd/appSecret 读不到 →
1792
+ // 数据目录算成空 / 用错凭据连不上(掉线)→ 群管理、图库、无上下文、Excel 导出全部走错路径。
1793
+ // 现在统一走 mergeOwnIntoCfg(**自有存储优先**,与 /read 接口一致;patch 是历史旧值)。
1794
+ const m = mergeOwnIntoCfg(b.cfg || {}, b.cfg?.settingsNs || id);
1795
+ const appId = m.appId || '';
1796
+ const appSecret = m.appSecret || '';
1783
1797
  // 数据根: dataRoot(新) > `{cwd}/dshqqbot`(**2026-09-12 新默认**, 与 dist 侧 dataRootOf 对齐);
1784
1798
  // nsBot 的 cwd 字段按数据根返回(全为数据目录用途) —— 未配 dataRoot 的实例不再落到工作目录。
1785
- const cwdCfg = b.cfg?.cwd || own.cwd || '';
1786
- const cwd = (b.cfg?.dataRoot || own.dataRoot || (cwdCfg ? join(cwdCfg, 'dshqqbot') : ''));
1799
+ const cwdCfg = m.cwd || '';
1800
+ const cwd = (m.dataRoot || (cwdCfg ? join(cwdCfg, 'dshqqbot') : ''));
1787
1801
  if (!appId || !appSecret) return null;
1788
1802
  return { id, appId, appSecret, cwd, ns: id };
1789
1803
  }