@zaofan/dsh-qqbot 1.11.8 → 1.11.10
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/client/qqbot-settings.js +120 -10
- package/dist/channel-tools.d.ts +18 -0
- package/dist/channel-tools.d.ts.map +1 -1
- package/dist/channel-tools.js +77 -0
- package/dist/channel-tools.js.map +1 -1
- package/dist/session/session-manager.d.ts +16 -0
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +88 -37
- package/dist/session/session-manager.js.map +1 -1
- package/package.json +145 -145
- package/settings-host.js +110 -32
package/client/qqbot-settings.js
CHANGED
|
@@ -2735,7 +2735,7 @@ var QQS_THEME_CSS = [
|
|
|
2735
2735
|
// · 审批/提问 → 打断式弹出(#qqs-ap-float 保持)
|
|
2736
2736
|
// · 入群申请 → 悬浮球上安静红点(不弹窗)
|
|
2737
2737
|
// · 群管理(发消息/审批入群/禁言) → 悬浮球点开成操作台
|
|
2738
|
-
var DOCK_CSS = "#qqs-dock-wrap{position:fixed;right:18px;bottom:190px;z-index:9997;font-family:-apple-system,'PingFang SC','Microsoft YaHei',sans-serif}#qqs-dock-ball{width:52px;height:52px;border-radius:50%;background:linear-gradient(160deg,#7c6cf0,#5b4fd8);color:#fff;font-size:24px;line-height:52px;text-align:center;cursor:pointer;box-shadow:0 6px 20px rgba(90,70,220,.4);user-select:none;transition:transform .12s,box-shadow .12s;position:relative}#qqs-dock-ball:hover{transform:scale(1.06)}#qqs-dock-badge{position:absolute;top:-4px;right:-4px;min-width:18px;height:18px;border-radius:9px;background:#ff4d4f;color:#fff;font-size:11px;font-weight:700;line-height:18px;padding:0 4px;box-sizing:border-box;text-align:center;display:none}#qqs-dock-panel{position:fixed;right:18px;bottom:190px;z-index:9998;width:min(720px,94vw);max-height:68vh;display:none;flex-direction:column;background:#fff;border:1px solid #d9c6ff;border-radius:16px;box-shadow:0 12px 40px rgba(60,40,140,.25);overflow:hidden;font-family:-apple-system,'PingFang SC','Microsoft YaHei',sans-serif}#qqs-dock-panel .dk-h{display:flex;align-items:center;gap:8px;padding:10px 14px;background:linear-gradient(90deg,#7c6cf01f,#7c6cf008);font-size:14px;font-weight:700;color:#4a3a9f;border-bottom:1px solid #efe8ff}#qqs-dock-panel .dk-b{padding:10px 14px;overflow:auto;font-size:13px;color:#1f2329}#qqs-dock-panel .dk-tab{display:flex;gap:4px;border-bottom:1px solid #eee;margin-bottom:10px}#qqs-dock-panel .dk-tab button{font:inherit;font-size:13px;padding:6px 14px;border:none;background:none;cursor:pointer;color:#666;border-bottom:2px solid transparent}#qqs-dock-panel .dk-tab button.on{color:#4a3a9f;font-weight:700;border-bottom-color:#7c6cf0}#qqs-dock-panel select.qqs-sel,#qqs-dock-panel input.qqs-txt,#qqs-dock-panel textarea.qqs-txt{font:inherit;color:#1f2329;background:#fff;border:1px solid #d0d5dd;border-radius:8px;padding:5px 8px;outline:none}#qqs-dock-panel .dk-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:6px 0}#qqs-dock-panel .dk-btn{font:inherit;font-size:13px;padding:5px 12px;border-radius:8px;cursor:pointer;border:1px solid #d9c6ff;background:#f1ecff;color:#4a3a9f}#qqs-dock-panel .dk-btn.ok{background:#e6f7ec;color:#187a3d;border-color:#b8e6c8}#qqs-dock-panel .dk-btn.no{background:#fdeeee;color:#c23131;border-color:#f3c4c4}#qqs-dock-panel .dk-btn:disabled{opacity:.5;cursor:default}#qqs-dock-panel .dk-msg{color:#888;font-size:12px;padding:2px 0}#qqs-dock-panel .dk-list{max-height:34vh;overflow:auto;border:1px solid #f0ecff;border-radius:10px;padding:4px}#qqs-dock-panel .dk-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-bottom:1px solid #f5f2ff;flex-wrap:wrap;font-size:13px}#qqs-dock-panel .dk-item:last-child{border-bottom:none}#qqs-dock-panel .dk-empty{color:#aaa;text-align:center;padding:18px 0;font-size:12px}"
|
|
2738
|
+
var DOCK_CSS = "#qqs-dock-wrap{position:fixed;right:18px;bottom:190px;z-index:9997;font-family:-apple-system,'PingFang SC','Microsoft YaHei',sans-serif}#qqs-dock-ball{width:52px;height:52px;border-radius:50%;background:linear-gradient(160deg,#7c6cf0,#5b4fd8);color:#fff;font-size:24px;line-height:52px;text-align:center;cursor:pointer;box-shadow:0 6px 20px rgba(90,70,220,.4);user-select:none;transition:transform .12s,box-shadow .12s;position:relative}#qqs-dock-ball:hover{transform:scale(1.06)}#qqs-dock-badge{position:absolute;top:-4px;right:-4px;min-width:18px;height:18px;border-radius:9px;background:#ff4d4f;color:#fff;font-size:11px;font-weight:700;line-height:18px;padding:0 4px;box-sizing:border-box;text-align:center;display:none}#qqs-dock-ball.qqs-alert{background:linear-gradient(160deg,#ff8a3d,#ff4d4f)!important;box-shadow:0 6px 20px rgba(255,77,79,.5)!important;animation:qqsDockPulse 1.6s ease-in-out infinite}@keyframes qqsDockPulse{0%,100%{box-shadow:0 6px 20px rgba(255,77,79,.45)}50%{box-shadow:0 6px 28px rgba(255,77,79,.9)}}#qqs-dock-panel{position:fixed;right:18px;bottom:190px;z-index:9998;width:min(720px,94vw);max-height:68vh;display:none;flex-direction:column;background:#fff;border:1px solid #d9c6ff;border-radius:16px;box-shadow:0 12px 40px rgba(60,40,140,.25);overflow:hidden;font-family:-apple-system,'PingFang SC','Microsoft YaHei',sans-serif}#qqs-dock-panel .dk-h{display:flex;align-items:center;gap:8px;padding:10px 14px;background:linear-gradient(90deg,#7c6cf01f,#7c6cf008);font-size:14px;font-weight:700;color:#4a3a9f;border-bottom:1px solid #efe8ff}#qqs-dock-panel .dk-b{padding:10px 14px;overflow:auto;font-size:13px;color:#1f2329}#qqs-dock-panel .dk-tab{display:flex;gap:4px;border-bottom:1px solid #eee;margin-bottom:10px}#qqs-dock-panel .dk-tab button{font:inherit;font-size:13px;padding:6px 14px;border:none;background:none;cursor:pointer;color:#666;border-bottom:2px solid transparent}#qqs-dock-panel .dk-tab button.on{color:#4a3a9f;font-weight:700;border-bottom-color:#7c6cf0}#qqs-dock-panel select.qqs-sel,#qqs-dock-panel input.qqs-txt,#qqs-dock-panel textarea.qqs-txt{font:inherit;color:#1f2329;background:#fff;border:1px solid #d0d5dd;border-radius:8px;padding:5px 8px;outline:none}#qqs-dock-panel .dk-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:6px 0}#qqs-dock-panel .dk-btn{font:inherit;font-size:13px;padding:5px 12px;border-radius:8px;cursor:pointer;border:1px solid #d9c6ff;background:#f1ecff;color:#4a3a9f}#qqs-dock-panel .dk-btn.ok{background:#e6f7ec;color:#187a3d;border-color:#b8e6c8}#qqs-dock-panel .dk-btn.no{background:#fdeeee;color:#c23131;border-color:#f3c4c4}#qqs-dock-panel .dk-btn:disabled{opacity:.5;cursor:default}#qqs-dock-panel .dk-msg{color:#888;font-size:12px;padding:2px 0}#qqs-dock-panel .dk-list{max-height:34vh;overflow:auto;border:1px solid #f0ecff;border-radius:10px;padding:4px}#qqs-dock-panel .dk-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-bottom:1px solid #f5f2ff;flex-wrap:wrap;font-size:13px}#qqs-dock-panel .dk-item:last-child{border-bottom:none}#qqs-dock-panel .dk-empty{color:#aaa;text-align:center;padding:18px 0;font-size:12px}"
|
|
2739
2739
|
// ── 💬 聊天视图样式(dock 追加段, 2026-09-07): QQ 风格气泡, 群友左(bot)右 ──
|
|
2740
2740
|
var DOCK_CSS2 = "#qqs-dock-panel .dk-chat-head{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin:0 0 6px}#qqs-dock-panel .dk-chat-box{overflow-y:auto;overscroll-behavior:contain;background:#f5f6f8;border:1px solid #e6e8ec;border-radius:10px;padding:10px 12px;box-sizing:border-box;height:min(36vh,300px);min-height:140px;scroll-behavior:auto}#qqs-dock-panel .dk-chat-box::-webkit-scrollbar{width:6px}#qqs-dock-panel .dk-chat-box::-webkit-scrollbar-thumb{background:#d3d7dd;border-radius:3px}#qqs-dock-panel .dk-crow{display:flex;gap:8px;align-items:flex-start;margin:0 0 12px}#qqs-dock-panel .dk-crow.out{flex-direction:row-reverse}#qqs-dock-panel .dk-ava{width:32px;height:32px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;color:#fff;overflow:hidden;user-select:none;background:linear-gradient(150deg,#8fb3e8,#5f8fd9)}#qqs-dock-panel .dk-crow.out .dk-ava{background:linear-gradient(150deg,#5ec7f2,#3b8fe0)}#qqs-dock-panel .dk-cmain{display:flex;flex-direction:column;max-width:calc(100% - 40px);min-width:0}#qqs-dock-panel .dk-crow.in .dk-cmain{align-items:flex-start}#qqs-dock-panel .dk-crow.out .dk-cmain{align-items:flex-end}#qqs-dock-panel .dk-cmeta{font-size:11px;color:#9aa0a8;margin:0 6px 2px;max-width:100%;display:flex;align-items:center;gap:5px;flex-wrap:wrap}#qqs-dock-panel .dk-crow.out .dk-cmeta{flex-direction:row-reverse}#qqs-dock-panel .dk-cbubble{padding:7px 11px;font-size:13px;line-height:1.55;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;box-shadow:0 1px 2px rgba(20,30,60,.06);max-width:100%}#qqs-dock-panel .dk-cbubble a.dk-link{color:#1a66d6;text-decoration:underline;word-break:break-all;cursor:pointer}#qqs-dock-panel .dk-crow.out .dk-cbubble a.dk-link{color:#eaf3ff}#qqs-dock-panel .dk-crow.in .dk-cbubble{background:#fff;border:1px solid #e3e6ea;color:#1f2329;border-radius:3px 10px 10px 10px}#qqs-dock-panel .dk-crow.out .dk-cbubble{background:linear-gradient(180deg,#69a6ff,#3d7df5);color:#fff;border-radius:10px 3px 10px 10px}#qqs-dock-panel .dk-img{display:block;max-width:min(230px,52vw);max-height:200px;border-radius:6px;margin:0 0 3px;object-fit:cover;cursor:zoom-in}#qqs-dock-panel .dk-audio{display:block;max-width:min(260px,60vw);width:100%;height:34px;margin:0 0 2px}#qqs-dock-panel .dk-file{display:inline-flex;align-items:center;gap:5px;max-width:100%;padding:6px 12px;border-radius:8px;background:#f0f6ff;border:1px solid #cfe0fa;color:#2b6bd8;font-size:13px;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#qqs-dock-panel .dk-file:hover{background:#e2edff}#qqs-dock-panel .dk-video{display:block;max-width:min(260px,60vw);max-height:180px;border-radius:6px;margin:0 0 2px}#qqs-dock-panel .dk-ctag{display:inline-block;font-size:10px;color:#5b8ff0;background:#eaf2ff;border:1px solid #d4e3fd;border-radius:8px;padding:0 6px}#qqs-dock-panel .dk-chat-top{text-align:center;color:#b0b4bb;font-size:11px;padding:2px 0 6px;user-select:none}#qqs-dock-panel .dk-chat-bottom{text-align:center;color:#c3c7cd;font-size:11px;padding:6px 0 0}#qqs-dock-panel .dk-composer{margin-top:8px;border:1px solid #e3e6ea;border-radius:10px;background:#fff;overflow:visible}#qqs-dock-panel .dk-composer textarea{width:100%;box-sizing:border-box;border:none;outline:none;resize:none;font:inherit;font-size:13px;color:#1f2329;background:transparent;padding:8px 10px 4px;line-height:1.5;max-height:120px}#qqs-dock-panel .dk-cbar{display:flex;align-items:center;gap:4px;padding:4px 8px 6px;flex-wrap:wrap}#qqs-dock-panel .dk-cbar .dk-btn{padding:3px 10px;font-size:12px;border-radius:7px}#qqs-dock-panel .dk-cbar .dk-send{background:linear-gradient(180deg,#69a6ff,#3d7df5);color:#fff;border:none;border-radius:8px;padding:5px 18px;font-size:13px;font-weight:600;cursor:pointer}#qqs-dock-panel .dk-cbar .dk-send:disabled{opacity:.5;cursor:default}#qqs-lightbox{position:fixed;inset:0;z-index:2147483000;background:rgba(8,10,18,.82);display:flex;align-items:center;justify-content:center;cursor:zoom-out}#qqs-lightbox img{max-width:92vw;max-height:92vh;border-radius:8px;box-shadow:0 10px 60px rgba(0,0,0,.6)}#qqs-dock-panel .dk-composer{position:relative}#qqs-dock-panel .dk-at-pop{position:absolute;left:6px;bottom:calc(100% - 4px);z-index:30;min-width:200px;max-width:90%;max-height:190px;overflow-y:auto;background:#fff;border:1px solid #e0e4ea;border-radius:10px;box-shadow:0 8px 24px rgba(30,40,80,.16);padding:4px;display:none}#qqs-dock-panel .dk-at-item{display:flex;align-items:center;gap:6px;padding:5px 9px;border-radius:7px;cursor:pointer;font-size:12px;color:#1f2329;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#qqs-dock-panel .dk-at-item.on,#qqs-dock-panel .dk-at-item:hover{background:#eef3ff;color:#2b5fd0}#qqs-dock-panel .dk-at-empty{color:#aaa;font-size:12px;padding:6px 9px}#qqs-lightbox .lb-x{position:fixed;right:16px;top:10px;color:#fff;font-size:30px;cursor:pointer;line-height:1;padding:6px}#qqs-dock-panel.dk-full{left:0!important;top:0!important;right:0!important;bottom:0!important;width:100vw!important;max-width:100vw!important;height:100vh!important;max-height:100vh!important;border-radius:0;z-index:2147482000;display:flex;flex-direction:column}#qqs-dock-panel.dk-full .dk-h,#qqs-dock-panel.dk-full .dk-detect{flex:none}#qqs-dock-panel.dk-full .dk-b{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column;padding:8px 14px 6px}#qqs-dock-panel.dk-full .dk-chat-wrap{display:flex;flex-direction:column;flex:1;min-height:0}#qqs-dock-panel.dk-full .dk-chat-head{flex:none}#qqs-dock-panel.dk-full .dk-chat-box{flex:1;height:auto!important;min-height:0!important;max-height:none!important;overflow-y:auto;overscroll-behavior:contain}#qqs-dock-panel.dk-full .dk-composer{flex:none;margin-top:6px}#qqs-dock-panel .dk-tab{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;scrollbar-width:none}#qqs-dock-panel .dk-tab::-webkit-scrollbar{display:none}#qqs-dock-panel .dk-tab button{white-space:nowrap;flex:0 0 auto}@media (max-width:560px){#qqs-dock-panel:not(.dk-full){left:8px!important;right:8px!important;width:auto!important;max-width:calc(100vw - 16px)!important;bottom:96px!important}#qqs-dock-panel .dk-h{font-size:13px;padding:8px 10px;gap:6px}#qqs-dock-panel .dk-b{padding:8px 10px;font-size:13px}#qqs-dock-panel .dk-tab button{font-size:12px;padding:7px 10px}#qqs-dock-panel .dk-btn{font-size:12px;padding:6px 10px}#qqs-dock-panel .dk-row{gap:6px;margin:5px 0}#qqs-dock-panel select.qqs-sel,#qqs-dock-panel input.qqs-txt,#qqs-dock-panel textarea.qqs-txt{padding:7px 9px;font-size:16px}#qqs-dock-panel .dk-list{max-height:46vh}#qqs-dock-panel .dk-item{padding:8px 6px;gap:6px}}@media (max-width:560px){#qqs-dock-panel.dk-full{border-radius:0}#qqs-dock-panel.dk-full .dk-b{padding-bottom:calc(8px + env(safe-area-inset-bottom,0px))}#qqs-dock-panel.dk-full .dk-tab{position:relative;background:#fff;z-index:2}}@media (max-width:560px){#qqs-dock-ball{width:46px;height:46px;line-height:46px;font-size:21px}}#qqs-dock-panel .dk-chat-wrap{position:relative}#qqs-dock-panel .dk-jump-latest{display:none;position:absolute;right:12px;bottom:76px;z-index:6;align-items:center;gap:4px;padding:5px 13px;font-size:12px;font-weight:600;color:#fff;cursor:pointer;border:none;border-radius:15px;background:linear-gradient(180deg,#69a6ff,#3d7df5);box-shadow:0 3px 12px rgba(30,60,140,.32);transition:transform .12s,box-shadow .12s}#qqs-dock-panel .dk-jump-latest.on{display:inline-flex}#qqs-dock-panel .dk-jump-latest:hover{background:linear-gradient(180deg,#5c9bfa,#2f6fe6);box-shadow:0 4px 16px rgba(30,60,140,.4)}#qqs-dock-panel .dk-jump-latest:active{transform:scale(.95)}"
|
|
2741
2741
|
function ensureDockCss2() { try { if (!document.getElementById('qqs-dock-css2')) { var st = document.createElement('style'); st.id = 'qqs-dock-css2'; st.textContent = DOCK_CSS2; document.head.appendChild(st) } } catch (e) {} };
|
|
@@ -2760,6 +2760,36 @@ var QQS_THEME_CSS = [
|
|
|
2760
2760
|
document.body.appendChild(wrap)
|
|
2761
2761
|
var ball = wrap.querySelector('#qqs-dock-ball')
|
|
2762
2762
|
var badge = wrap.querySelector('#qqs-dock-badge')
|
|
2763
|
+
// ── 2026-10-28(主人定):悬浮球**只在 QQ 会话里显示** ──
|
|
2764
|
+
// 判定沿用 session-lookup(state.detectedHit 的同一个接口),未命中就不显示。
|
|
2765
|
+
// 为什么还要轮询:会话切换(web 侧点开另一个会话)不会通知这里;
|
|
2766
|
+
// 只比 sessionId 字符串,变了才发请求,开销可忽略。
|
|
2767
|
+
var _dockSid = ''
|
|
2768
|
+
var _dockHit = null
|
|
2769
|
+
var _dockPending = 0
|
|
2770
|
+
function refreshDockVisibility() {
|
|
2771
|
+
if (_dockPending > 0) { wrap.style.display = ''; return }
|
|
2772
|
+
var sid = ''
|
|
2773
|
+
try { sid = curSessionId() } catch (eS) { sid = '' }
|
|
2774
|
+
// 同一会话、已知结论 → 直接套用(不发请求,也不闪)
|
|
2775
|
+
if (sid === _dockSid && _dockHit !== null) { wrap.style.display = _dockHit ? '' : 'none'; return }
|
|
2776
|
+
_dockSid = sid
|
|
2777
|
+
if (!sid) { _dockHit = false; wrap.style.display = 'none'; return }
|
|
2778
|
+
// 会话变了:先按"未命中"藏起来,拿到结论再显示(宁可晚一点,也别让它乱闪)
|
|
2779
|
+
_dockHit = null
|
|
2780
|
+
wrap.style.display = 'none'
|
|
2781
|
+
qqHitOf(sid, function (hit) {
|
|
2782
|
+
if (sid !== _dockSid) return // 查询期间又切了会话:这次结论作废
|
|
2783
|
+
_dockHit = hit
|
|
2784
|
+
wrap.style.display = hit ? '' : 'none'
|
|
2785
|
+
})
|
|
2786
|
+
}
|
|
2787
|
+
try {
|
|
2788
|
+
refreshDockVisibility()
|
|
2789
|
+
// 事件驱动(2026-10-28,主人嫌 2s 轮询费性能):不再 setInterval ——
|
|
2790
|
+
// apply() 里的 refreshQqUi 在「sessions.list 变化 / 窗口聚焦 / 页面重新可见」时调这里。
|
|
2791
|
+
window.__qqsRefreshDock = refreshDockVisibility
|
|
2792
|
+
} catch (eVis) { /* 显隐失败不影响球本身 */ }
|
|
2763
2793
|
var panel = null
|
|
2764
2794
|
var open = false
|
|
2765
2795
|
// ⚠️ 2026-09-27 修复「拖到屏幕外后球永久消失」:拖拽时本来有 clamp(行1749),
|
|
@@ -2956,11 +2986,14 @@ var QQS_THEME_CSS = [
|
|
|
2956
2986
|
d.items.forEach(function (it) { n += (it.pending || 0) })
|
|
2957
2987
|
if (n > 0) { badge.style.display = 'block'; badge.textContent = n > 99 ? '99+' : String(n) }
|
|
2958
2988
|
else badge.style.display = 'none'
|
|
2989
|
+
_dockPending = n
|
|
2990
|
+
try { if (n > 0) ball.classList.add('qqs-alert'); else ball.classList.remove('qqs-alert') } catch (eA) {}
|
|
2991
|
+
try { if (window.__qqsRefreshDock) window.__qqsRefreshDock() } catch (eB) {}
|
|
2959
2992
|
if (panel && open) { var b = panel.querySelector('.dk-join-badge'); if (b) b.style.display = n > 0 ? 'inline-block' : 'none'; if (b) b.textContent = n > 99 ? '99+' : String(n) }
|
|
2960
2993
|
})
|
|
2961
2994
|
}
|
|
2962
2995
|
refreshBadge()
|
|
2963
|
-
setInterval(refreshBadge,
|
|
2996
|
+
setInterval(refreshBadge, 10000)
|
|
2964
2997
|
|
|
2965
2998
|
// ── 面板状态(每个实例独立保存, 切回不丢) ──
|
|
2966
2999
|
var state = { ns: '', accts: [], gid: '', groups: [], tab: 'chat', sendScope: 'group', sendTo: '', sendName: '', sendText: '', insertCtx: true, targetQ: '', c2cs: [], joins: null, mutes: null, members: null, muteSecs: '60', bindGid: '', bindName: '', msg: '', busy: '', wantPeer: null, lookedUp: false, detected: null, detectedHit: null, chatItems: [], chatMore: false, chatBusy: '', chatErr: '', chatOldest: 0, chatText: '', chatIns: true, outMode: '', outRev: undefined, bpEvents: [], bpSel: null, bpDraft: null, bpExt: null, bpExtBusy: '', bpReq: '', bpReqHint: '', bpSrcText: null, bpSrcPath: '', rosterSel: {}, rosterScope: 'all', rosterQ: '', hubSid: '', hubRev: undefined, hubBusy: '', hubMsg: '', gaEnabled: false, gaPoll: false, gaPollWake: true, gaHubNotify: true, gaNotifyGroup: true, gaInterval: 5, gaMinCount: 1, gaMsg: '', gaBusy: '', bcDraft: null, bcTasks: null, cardMd: '', cardBtns: '', cardGid: '', cardBusy: '', cardQ: '', tgGroups: [], tgCur: '', hammerSub: 'mute', arOn: false, arMode: 'keep', arKws: '', arKinds: [], arMute: 0, arDry: false, arMsg: '', qunLogged: null, qunUin: '', qunGroups: [], qunGc: '', qunKw: '', qunMembers: [], qunCount: 0, qunQr: false, qunMsg: '', qunBusy: false, qunLoading: false }
|
|
@@ -6718,6 +6751,31 @@ var QQS_THEME_CSS = [
|
|
|
6718
6751
|
return ''
|
|
6719
6752
|
}
|
|
6720
6753
|
|
|
6754
|
+
/**
|
|
6755
|
+
* 当前会话是不是 QQ 会话(2026-10-28)。
|
|
6756
|
+
* 同一次查询在窗口内共享 —— 悬浮球显隐、扩展页签显隐都走这里,不重复打后端。
|
|
6757
|
+
* ⚠️ 否定结论只缓存 2 秒:宿主刚启动时后端可能还没就绪,长缓存会让悬浮球一直不出现。
|
|
6758
|
+
*/
|
|
6759
|
+
function qqHitOf(sid, cb) {
|
|
6760
|
+
if (!sid) { try { cb(false) } catch (e0) {} ; return }
|
|
6761
|
+
var c = (window.__qqsHitCache = window.__qqsHitCache || {})
|
|
6762
|
+
var e = c[sid]
|
|
6763
|
+
if (e && Date.now() - e.at < (e.hit ? 10000 : 2000)) { try { cb(e.hit) } catch (e1) {} ; return }
|
|
6764
|
+
try {
|
|
6765
|
+
fetch('/api/qqbot-settings/session-lookup?sessionId=' + encodeURIComponent(sid))
|
|
6766
|
+
.then(function (r) { return r.json() })
|
|
6767
|
+
.then(function (d) {
|
|
6768
|
+
var hit = !!(d && d.hits && d.hits.length)
|
|
6769
|
+
c[sid] = { at: Date.now(), hit: hit }
|
|
6770
|
+
try { cb(hit) } catch (e2) {}
|
|
6771
|
+
})
|
|
6772
|
+
.catch(function () { try { cb(false) } catch (e3) {} })
|
|
6773
|
+
} catch (e4) { try { cb(false) } catch (e5) {} }
|
|
6774
|
+
}
|
|
6775
|
+
|
|
6776
|
+
// (2026-10-28)页签显隐不用 DOM 方案了 —— 见 apply() 里的 setExtTabVisible:
|
|
6777
|
+
// `slots.inject` 的返回值是 disposer,注销后宿主自己会刷新页签列表。
|
|
6778
|
+
|
|
6721
6779
|
function curWorkspaceCwd() {
|
|
6722
6780
|
try {
|
|
6723
6781
|
var svc = _extSessionsSvc
|
|
@@ -7762,14 +7820,28 @@ var QQS_THEME_CSS = [
|
|
|
7762
7820
|
function (props) { return h(QqbotHome, { close: props && props.close }) })
|
|
7763
7821
|
})
|
|
7764
7822
|
})
|
|
7765
|
-
// 「QQ
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7823
|
+
// 「QQ机器人扩展」会话页签:**只在 QQ 会话里注入**(2026-10-28 主人定)
|
|
7824
|
+
// 为什么不用 DOM 隐藏:`slots.inject(key, cb)` 的返回值是 disposer(已核 ui-renderer 源码:
|
|
7825
|
+
// `return () => { disposeController(); }`),注销后宿主 `slots.subscribe("conversation.view")`
|
|
7826
|
+
// 会自动刷新页签列表 —— 比按文案找按钮稳得多。
|
|
7827
|
+
var _extTabDisposed = null
|
|
7828
|
+
function setExtTabVisible(show) {
|
|
7829
|
+
if (show) {
|
|
7830
|
+
if (_extTabDisposed) return
|
|
7831
|
+
try {
|
|
7832
|
+
_extTabDisposed = slots.inject('conversation.view', function () {
|
|
7833
|
+
return slots.register(
|
|
7834
|
+
{ name: 'conversation.view', id: 'qqbot-ext', order: 81, label: 'QQ机器人扩展' },
|
|
7835
|
+
ExtPanel)
|
|
7836
|
+
}) || null
|
|
7837
|
+
if (!_extTabDisposed) _extTabDisposed = function () {}
|
|
7838
|
+
} catch (eTab) { _extTabDisposed = null }
|
|
7839
|
+
} else {
|
|
7840
|
+
if (!_extTabDisposed) return
|
|
7841
|
+
try { _extTabDisposed() } catch (eTab2) {}
|
|
7842
|
+
_extTabDisposed = null
|
|
7843
|
+
}
|
|
7844
|
+
}
|
|
7773
7845
|
safe('approval float', startApprovalFloat)
|
|
7774
7846
|
// sessions 服务(宿主根服务): 权威读 web 当前会话(current)与 cwd(agent id === session id)
|
|
7775
7847
|
var sessionsSvc = null
|
|
@@ -7777,6 +7849,44 @@ var QQS_THEME_CSS = [
|
|
|
7777
7849
|
if (!sessionsSvc) { try { sessionsSvc = ctx.get && ctx.get('sessions') } catch (e) {} }
|
|
7778
7850
|
_extSessionsSvc = sessionsSvc // 供 ExtPanel 读当前工作区 cwd
|
|
7779
7851
|
safe('dock', function () { startQqDock(sessionsSvc) })
|
|
7852
|
+
// ── 统一刷新:页签 + 悬浮球,**事件驱动,不轮询**(2026-10-28)──
|
|
7853
|
+
// 信号源:`sessions.list`(ObservableSnapshot,宿主在左侧会话列表切换时就会推)
|
|
7854
|
+
// + window focus / 页面可见性(兜底,切回标签页时补一次)。
|
|
7855
|
+
var _qqUiRetry = 0
|
|
7856
|
+
var refreshQqUi = function () {
|
|
7857
|
+
// dock 球的显隐也走这同一个信号(否则切会话时页签跟走了、球还赖着不动)
|
|
7858
|
+
try { if (typeof window !== 'undefined' && typeof window.__qqsRefreshDock === 'function') window.__qqsRefreshDock() } catch (eDock) {}
|
|
7859
|
+
var sid = ''
|
|
7860
|
+
try { sid = curSessionId() } catch (eSid) { sid = '' }
|
|
7861
|
+
// 有限次重试(≈7 秒内 6 次):宿主刚启动时"当前会话"或后端 lookup 可能还没就绪,
|
|
7862
|
+
// 一次性判空就再也不显示球了(2026-10-28 主人实测)。不是长期轮询。
|
|
7863
|
+
function retryLater() {
|
|
7864
|
+
if (_qqUiRetry >= 6) return
|
|
7865
|
+
_qqUiRetry++
|
|
7866
|
+
setTimeout(function () { refreshQqUi() }, 1200)
|
|
7867
|
+
}
|
|
7868
|
+
if (!sid) { setExtTabVisible(false); retryLater(); return }
|
|
7869
|
+
qqHitOf(sid, function (hit) {
|
|
7870
|
+
var now = ''
|
|
7871
|
+
try { now = curSessionId() } catch (eNow) {}
|
|
7872
|
+
if (now !== sid) return // 查询期间切走了:别把旧结论套到新会话上
|
|
7873
|
+
setExtTabVisible(!!hit)
|
|
7874
|
+
if (hit) { _qqUiRetry = 0; return }
|
|
7875
|
+
retryLater()
|
|
7876
|
+
})
|
|
7877
|
+
}
|
|
7878
|
+
safe('qq ui refresh', function () {
|
|
7879
|
+
refreshQqUi()
|
|
7880
|
+
try {
|
|
7881
|
+
if (sessionsSvc && sessionsSvc.list && typeof sessionsSvc.list.subscribe === 'function') {
|
|
7882
|
+
sessionsSvc.list.subscribe(function () { refreshQqUi() })
|
|
7883
|
+
}
|
|
7884
|
+
} catch (eSub) {}
|
|
7885
|
+
try {
|
|
7886
|
+
window.addEventListener('focus', refreshQqUi)
|
|
7887
|
+
document.addEventListener('visibilitychange', function () { if (!document.hidden) refreshQqUi() })
|
|
7888
|
+
} catch (eWin) {}
|
|
7889
|
+
})
|
|
7780
7890
|
}
|
|
7781
7891
|
|
|
7782
7892
|
exports.inject = ['slots', 'sessions']
|
package/dist/channel-tools.d.ts
CHANGED
|
@@ -110,6 +110,24 @@ export declare function syncContextTools(agentCtx: unknown, shouldHave: boolean,
|
|
|
110
110
|
*/
|
|
111
111
|
export declare function ensureExtToolsGlobal(globalCtx: unknown): void;
|
|
112
112
|
export declare function ensureContextToolsGlobal(globalCtx: unknown): void;
|
|
113
|
+
/**
|
|
114
|
+
* 按会话同步「上下文压缩三件套 + QQ 群管理」的**注册状态**(幂等)。
|
|
115
|
+
*
|
|
116
|
+
* @param agentCtx 该 QQ 会话的 agent 作用域(`record.agentCtx` 或 `agent.ctx`)
|
|
117
|
+
* @param opts.ctxTools 要不要 context_memo / context_compact / context_drop(跟「无上下文·智能判断」开关)
|
|
118
|
+
* @param opts.groupAdmin 要不要 qq_group_admin(跟 groupAdmin.enabled)
|
|
119
|
+
* @param opts.dataRoot 会话坐标(工具执行时反查数据根用)
|
|
120
|
+
* @param opts.sessionKey 会话坐标(备忘类工具要求非空)
|
|
121
|
+
*
|
|
122
|
+
* 失败策略:拿不到 `tools.register` 或注册抛错时**不记状态**(写 `__retry`),下一次 pre-step 重试;
|
|
123
|
+
* 绝不影响会话主流程。
|
|
124
|
+
*/
|
|
125
|
+
export declare function syncChannelScopedTools(agentCtx: unknown, opts: {
|
|
126
|
+
ctxTools: boolean;
|
|
127
|
+
groupAdmin: boolean;
|
|
128
|
+
dataRoot?: string;
|
|
129
|
+
sessionKey?: string;
|
|
130
|
+
}): void;
|
|
113
131
|
export declare function applyExtDisabledRestrict(agentCtx: unknown, dataRoot: string, extToolNames: string[]): void;
|
|
114
132
|
export declare function restrictContextTools(agentCtx: unknown, shouldHave: boolean, env?: {
|
|
115
133
|
dataRoot?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-tools.d.ts","sourceRoot":"","sources":["../src/channel-tools.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"channel-tools.d.ts","sourceRoot":"","sources":["../src/channel-tools.ts"],"names":[],"mappings":"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"}
|
package/dist/channel-tools.js
CHANGED
|
@@ -4047,6 +4047,83 @@ function toolsOfScope(agentCtx) {
|
|
|
4047
4047
|
*
|
|
4048
4048
|
* 幂等:restrict 返回 dispose;每次 apply 先撤销上一次的,再按当前 disabled 重挂。
|
|
4049
4049
|
*/
|
|
4050
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
4051
|
+
// 2026-10-28(主人定,对应 issue #26):上下文/群管理工具改为**按 QQ 会话注册**
|
|
4052
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
4053
|
+
// 旧做法(2026-10-09 起):「插件根作用域全局注册一次 + pre-step 逐会话 restrict deny」。
|
|
4054
|
+
// · 当初改成全局,是为了避开"每步先注销再重注册 → 工具表反复变动 → 宿主每步发
|
|
4055
|
+
// 「工具已更新·移除/新增」"的抖动(那批通知还进上下文,纯烧 token)。
|
|
4056
|
+
// · 代价是:① 第一次 pre-step 之前,无关工作区的会话也能看到这四个名字;
|
|
4057
|
+
// ② `restrict` 只过滤**继承来的**工具,全局层本身就是泄漏源,剪枝只是事后补救。
|
|
4058
|
+
//
|
|
4059
|
+
// 现在照 `mountChannelTools` 的路子(**per-agent register**),配一个幂等状态机:
|
|
4060
|
+
// · 状态没变 → 一根手指都不动(不产生任何变更通知,同样不抖);
|
|
4061
|
+
// · 状态变了 → 先撤旧的、再按新状态注册(面板一改开关,下一 step 生效)。
|
|
4062
|
+
// 非 QQ 会话根本不经过这里 ⇒ 天生看不到,零窗口期、零 token。
|
|
4063
|
+
const ctxScopeState = new WeakMap();
|
|
4064
|
+
/**
|
|
4065
|
+
* 按会话同步「上下文压缩三件套 + QQ 群管理」的**注册状态**(幂等)。
|
|
4066
|
+
*
|
|
4067
|
+
* @param agentCtx 该 QQ 会话的 agent 作用域(`record.agentCtx` 或 `agent.ctx`)
|
|
4068
|
+
* @param opts.ctxTools 要不要 context_memo / context_compact / context_drop(跟「无上下文·智能判断」开关)
|
|
4069
|
+
* @param opts.groupAdmin 要不要 qq_group_admin(跟 groupAdmin.enabled)
|
|
4070
|
+
* @param opts.dataRoot 会话坐标(工具执行时反查数据根用)
|
|
4071
|
+
* @param opts.sessionKey 会话坐标(备忘类工具要求非空)
|
|
4072
|
+
*
|
|
4073
|
+
* 失败策略:拿不到 `tools.register` 或注册抛错时**不记状态**(写 `__retry`),下一次 pre-step 重试;
|
|
4074
|
+
* 绝不影响会话主流程。
|
|
4075
|
+
*/
|
|
4076
|
+
export function syncChannelScopedTools(agentCtx, opts) {
|
|
4077
|
+
try {
|
|
4078
|
+
if (!agentCtx || typeof agentCtx !== 'object')
|
|
4079
|
+
return;
|
|
4080
|
+
const key = agentCtx;
|
|
4081
|
+
// 会话坐标每次都刷新(工具执行时靠它定位数据根/会话)
|
|
4082
|
+
if (opts.dataRoot) {
|
|
4083
|
+
ctxEnvMap.set(key, { dataRoot: String(opts.dataRoot), sessionKey: String(opts.sessionKey ?? '') });
|
|
4084
|
+
}
|
|
4085
|
+
const sig = `${opts.ctxTools ? '1' : '0'}${opts.groupAdmin ? '1' : '0'}`;
|
|
4086
|
+
const st = ctxScopeState.get(key);
|
|
4087
|
+
if (st && st.sig === sig)
|
|
4088
|
+
return; // 状态一致 → 不动(这是"不抖"的关键)
|
|
4089
|
+
const toolsObj = toolsOfScope(agentCtx);
|
|
4090
|
+
const reg = toolsObj?.register;
|
|
4091
|
+
if (!toolsObj || typeof reg !== 'function') {
|
|
4092
|
+
traceToolReg('[scoped-tool] 拿不到 tools.register,跳过(下次再试)');
|
|
4093
|
+
return;
|
|
4094
|
+
}
|
|
4095
|
+
// 先撤旧的(换开关后不能叠加)
|
|
4096
|
+
if (st)
|
|
4097
|
+
for (const d of st.disposers) {
|
|
4098
|
+
try {
|
|
4099
|
+
d();
|
|
4100
|
+
}
|
|
4101
|
+
catch { /* ignore */ }
|
|
4102
|
+
}
|
|
4103
|
+
const want = [
|
|
4104
|
+
...(opts.ctxTools ? ctxToolsRef() : []),
|
|
4105
|
+
...(opts.groupAdmin ? qunAdminRef() : []),
|
|
4106
|
+
];
|
|
4107
|
+
const disposers = [];
|
|
4108
|
+
for (const t of want) {
|
|
4109
|
+
try {
|
|
4110
|
+
const d = reg.call(toolsObj, t);
|
|
4111
|
+
if (typeof d === 'function')
|
|
4112
|
+
disposers.push(d);
|
|
4113
|
+
}
|
|
4114
|
+
catch { /* 单个工具失败不影响其它 */ }
|
|
4115
|
+
}
|
|
4116
|
+
// 全成功才认这个 sig;否则标 __retry,下一 step 重来
|
|
4117
|
+
const okAll = disposers.length === want.length;
|
|
4118
|
+
ctxScopeState.set(key, { sig: okAll ? sig : `__retry-${sig}`, disposers });
|
|
4119
|
+
traceToolReg(`[scoped-tool] 按会话注册 ctx=${opts.ctxTools ? 1 : 0} groupAdmin=${opts.groupAdmin ? 1 : 0}`
|
|
4120
|
+
+ ` want=${want.length} ok=${disposers.length}`
|
|
4121
|
+
+ ` dataRoot=${String(opts.dataRoot ?? '')} sk=${String(opts.sessionKey ?? '')}`);
|
|
4122
|
+
}
|
|
4123
|
+
catch (e) {
|
|
4124
|
+
traceToolReg('[scoped-tool] 异常: ' + String(e?.message ?? e).slice(0, 160));
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4050
4127
|
let __extRestrictDispose;
|
|
4051
4128
|
export function applyExtDisabledRestrict(agentCtx, dataRoot, extToolNames) {
|
|
4052
4129
|
try {
|