@zaofan/dsh-qqbot 1.5.12 → 1.5.15

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.
Files changed (32) hide show
  1. package/README.md +31 -117
  2. package/{README.md.bak-1511-1790525690506 → README.md.bak-final-1790552188493} +25 -61
  3. package/{README.md.bak-1512-1790529705004 → README.md.bak-ghnote-1790548468037} +19 -99
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +100 -10
  6. package/dist/index.js.map +1 -1
  7. package/docs/USER-GUIDE.md +113 -0
  8. package/entry.js +57 -0
  9. package/package.json +136 -125
  10. package/settings-host.js +72 -25
  11. package/client/qqbot-settings.js.bak-apifix-1790512748500 +0 -4846
  12. package/client/qqbot-settings.js.bak-bind3-1790517775201 +0 -4882
  13. package/client/qqbot-settings.js.bak-clamp-195559 +0 -4780
  14. package/client/qqbot-settings.js.bak-ctxev-1790511964477 +0 -4830
  15. package/client/qqbot-settings.js.bak-ctxless-202526 +0 -4785
  16. package/client/qqbot-settings.js.bak-ctxui-1790511940536 +0 -4824
  17. package/client/qqbot-settings.js.bak-delegate-1790515486404 +0 -4844
  18. package/client/qqbot-settings.js.bak-fixctx2-1790512183370 +0 -4844
  19. package/client/qqbot-settings.js.bak-ga-041943 +0 -4775
  20. package/client/qqbot-settings.js.bak-lmreset-1790522156560 +0 -4873
  21. package/client/qqbot-settings.js.bak-lmreset2-1790522188051 +0 -4873
  22. package/client/qqbot-settings.js.bak-movectx-1790512156480 +0 -4838
  23. package/client/qqbot-settings.js.bak-privacy-1790525734851 +0 -4876
  24. package/client/qqbot-settings.js.bak-save2-1790517095028 +0 -4859
  25. package/dist/commands/approve.d.ts +0 -17
  26. package/dist/commands/approve.d.ts.map +0 -1
  27. package/dist/commands/approve.js +0 -24
  28. package/dist/commands/approve.js.map +0 -1
  29. package/dist/features/approval-switch.d.ts +0 -22
  30. package/dist/features/approval-switch.d.ts.map +0 -1
  31. package/dist/features/approval-switch.js +0 -10
  32. package/dist/features/approval-switch.js.map +0 -1
package/settings-host.js CHANGED
@@ -836,18 +836,26 @@ export function apply(ctx) {
836
836
  writeJson(res, 200, {
837
837
  hasFile,
838
838
  instances: bots.map((b) => {
839
- const cwd = b.cfg?.cwd || '';
839
+ // ⚠️ 2026-09-28 修:保存时 cwd/preset/appId 只写【自有存储】(见 saveInstances 的 2026-09-24 注释),
840
+ // 但回显原先只读 patch → 界面上填过的 cwd/preset 保存后就"变空"了(前端拿到空串)。
841
+ // 这里把自有存储的值一并合并,与写路径对称(patch 优先,其次自有存储)。
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);
840
848
  // 数据根与 dist 侧 dataRootOf 对齐: 未配 dataRoot → `{cwd}/dshqqbot`(2026-09-12 新默认)
841
849
  const droot = b.cfg?.dataRoot || (cwd ? join(cwd, 'dshqqbot') : '');
842
850
  return {
843
851
  id: b.id,
844
852
  ns: b.id, // settings 命名空间 = 实例 id(主 im-qqbot; 非主实例 render 已写 settingsNs=id)
845
- appId: b.cfg?.appId || '',
846
- appSecret: b.cfg?.appSecret ? SECRET_MASK : '', // 掩码回显(借鉴 panel: masked)
847
- hasSecret: !!b.cfg?.appSecret,
848
- preset: b.cfg?.preset || '',
853
+ appId: appIdMerged,
854
+ appSecret: hasSecretMerged ? SECRET_MASK : '', // 掩码回显(借鉴 panel: masked)
855
+ hasSecret: hasSecretMerged,
856
+ preset: presetMerged,
849
857
  cwd,
850
- disabled: !!b.disabled,
858
+ disabled: !!b.disabled || ownCfg.disabled === true,
851
859
  online: typeof reg.isBotOnline === 'function' ? reg.isBotOnline(b.id) : false, // 在线状态(bot ws ready 事件驱动)
852
860
  // 账号数据目录(各号各库各定时): 图库={cwd}/表情包, 定时={cwd}/.qqbot
853
861
  dataDir: droot ? join(droot, '表情包') : '',
@@ -1732,16 +1740,50 @@ export function apply(ctx) {
1732
1740
  // ── ⑥QQ 群管理面板(P3, 2026-09-05): 多群管理 host 路由(读/写走 GroupAdminClient; 面板=主人直发免 QQ 审批) ──
1733
1741
  // 数据: {cwd}/.qqbot/{groups.json 群注册表, join-pending.json 待审, group-audit.jsonl 审计日志}
1734
1742
  // 鉴权: 与全路由一致走 route() 同源 loopback fence; 面板主人级鉴权(P4 加强)。
1743
+ /**
1744
+ * 把【插件自有存储】的值合并进 patch 解析出的实例列表。
1745
+ *
1746
+ * ⚠️ 2026-09-28 根治同类问题:
1747
+ * 自 2026-09-24 起,已有账号的 appId / appSecret / preset / cwd 只写自有存储、不写 patch
1748
+ * (避免多条目 insert 时块边界写歪 YAML)。但桥里有若干地方**只读 patch** 取账号配置,
1749
+ * 于是用户存进自有存储的值读不到 —— 表现为:
1750
+ * · 账号页填了「工作目录」保存后回显为空
1751
+ * · nsBot() 返回 null → 群管理/图库/无上下文/Excel 导出全部走错路径
1752
+ * 这里统一合并(patch 优先,其次自有存储),所有取账号配置的入口都应走它。
1753
+ */
1754
+ function mergeOwnIntoCfg(cfg, nsLike) {
1755
+ let own = {};
1756
+ 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)));
1758
+ return {
1759
+ ...cfg,
1760
+ appId: pick('appId'),
1761
+ appSecret: pick('appSecret'),
1762
+ preset: pick('preset'),
1763
+ cwd: pick('cwd'),
1764
+ dataRoot: pick('dataRoot'),
1765
+ };
1766
+ }
1767
+
1735
1768
  function nsBot(ns) {
1736
1769
  const { bots } = parsePatch();
1737
1770
  const id = ns && ns !== 'im-qqbot' ? String(ns) : 'im-qqbot';
1738
1771
  const b = bots.find((x) => x.id === id);
1739
1772
  if (!b) return null;
1740
- const appId = b.cfg?.appId || '';
1741
- const appSecret = b.cfg?.appSecret || '';
1773
+ // ⚠️ 2026-09-28 修(同类问题根治):自 2026-09-24 起,已有账号的 appId/appSecret/preset/cwd
1774
+ // 只写【插件自有存储】,不再写 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 || '';
1742
1783
  // 数据根: dataRoot(新) > `{cwd}/dshqqbot`(**2026-09-12 新默认**, 与 dist 侧 dataRootOf 对齐);
1743
1784
  // nsBot 的 cwd 字段按数据根返回(全为数据目录用途) —— 未配 dataRoot 的实例不再落到工作目录。
1744
- const cwd = (b.cfg?.dataRoot || (b.cfg?.cwd ? join(b.cfg.cwd, 'dshqqbot') : ''));
1785
+ const cwdCfg = b.cfg?.cwd || own.cwd || '';
1786
+ const cwd = (b.cfg?.dataRoot || own.dataRoot || (cwdCfg ? join(cwdCfg, 'dshqqbot') : ''));
1745
1787
  if (!appId || !appSecret) return null;
1746
1788
  return { id, appId, appSecret, cwd, ns: id };
1747
1789
  }
@@ -1854,8 +1896,11 @@ export function apply(ctx) {
1854
1896
  const { bots } = parsePatch();
1855
1897
  const botByNs = new Map();
1856
1898
  for (const bot of bots) {
1857
- if (bot.disabled || !bot.cfg?.appId || !bot.cfg?.cwd) continue;
1858
- botByNs.set(bot.id, bot);
1899
+ // ⚠️ 2026-09-28:appId/cwd 可能只在【自有存储】里(2026-09-24 起的保存策略),
1900
+ // 合并后再判断,否则这类账号会被误跳过。
1901
+ const mcfg = mergeOwnIntoCfg(bot.cfg || {}, bot.cfg?.settingsNs || bot.id);
1902
+ if (bot.disabled || !mcfg.appId || !mcfg.cwd) continue;
1903
+ botByNs.set(bot.id, { ...bot, cfg: mcfg });
1859
1904
  }
1860
1905
  const hits = [];
1861
1906
  const seen = new Set();
@@ -2038,20 +2083,20 @@ export function apply(ctx) {
2038
2083
  req.setTimeout(180000, () => req.destroy(new Error('下载超时(180s)')));
2039
2084
  });
2040
2085
  }
2041
- // ── 本地小模型:强制重置加载状态(面板「🔄 重新检测」调用)──
2042
- // 背景:local-embed 曾有"一次失败永久关闭"的缺陷,用户点重新检测时希望能立刻再试一次。
2043
- // ⚠️ 桥与插件在同进程:动态 import 同一份 dist 模块,拿到的就是插件正在用的那个实例表。
2044
- route(ctx, 'POST', '/api/qqbot-settings/local-model/reset', async (req, res) => {
2045
- try {
2046
- const mod = await import('./dist/features/local-embed.js');
2047
- let n = 0;
2048
- try { n = typeof mod.resetAllEmbedders === 'function' ? mod.resetAllEmbedders() : 0; } catch (e) { n = -1; }
2049
- return writeJson(res, 200, { ok: true, reset: n });
2050
- } catch (e) {
2051
- return writeJson(res, 500, { error: String((e && e.message) || e) });
2052
- }
2053
- });
2054
-
2086
+ // ── 本地小模型:强制重置加载状态(面板「🔄 重新检测」调用)──
2087
+ // 背景:local-embed 曾有"一次失败永久关闭"的缺陷,用户点重新检测时希望能立刻再试一次。
2088
+ // ⚠️ 桥与插件在同进程:动态 import 同一份 dist 模块,拿到的就是插件正在用的那个实例表。
2089
+ route(ctx, 'POST', '/api/qqbot-settings/local-model/reset', async (req, res) => {
2090
+ try {
2091
+ const mod = await import('./dist/features/local-embed.js');
2092
+ let n = 0;
2093
+ try { n = typeof mod.resetAllEmbedders === 'function' ? mod.resetAllEmbedders() : 0; } catch (e) { n = -1; }
2094
+ return writeJson(res, 200, { ok: true, reset: n });
2095
+ } catch (e) {
2096
+ return writeJson(res, 500, { error: String((e && e.message) || e) });
2097
+ }
2098
+ });
2099
+
2055
2100
  route(ctx, 'GET', '/api/qqbot-settings/local-model/status', async (req, res) => {
2056
2101
  try {
2057
2102
  const u = new URL(req.url ?? '/', 'http://x');
@@ -3746,6 +3791,8 @@ const WHY_MAP = { busy: '目标会话回合活跃,已等待至回合结束仍超
3746
3791
  const { bots } = parsePatch();
3747
3792
  const out = [];
3748
3793
  for (const bot of bots) {
3794
+ // ⚠️ 2026-09-28:凭据可能只在【自有存储】里(2026-09-24 起的保存策略),合并后再判断。
3795
+ bot.cfg = mergeOwnIntoCfg(bot.cfg || {}, bot.cfg?.settingsNs || bot.id);
3749
3796
  if (bot.disabled || !bot.cfg?.appId || !bot.cfg?.appSecret) continue;
3750
3797
  try {
3751
3798
  const ns = bot.id;