@zaofan/dsh-qqbot 1.5.31 → 1.6.1
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 +58 -12
- package/client/qqbot-settings.js.bak-ctxkey-1790880133352 +5069 -0
- package/client/qqbot-settings.js.bak-mmui-1790922963087 +5085 -0
- package/client/qqbot-settings.js.bak-radio-1790899148239 +5076 -0
- package/client/qqbot-settings.js.bak-ui4b-1790879732726 +5046 -0
- package/dist/channel-tools.d.ts +18 -0
- package/dist/channel-tools.d.ts.map +1 -1
- package/dist/channel-tools.js +272 -2
- package/dist/channel-tools.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/features/context-memo.d.ts +29 -0
- package/dist/features/context-memo.d.ts.map +1 -0
- package/dist/features/context-memo.js +173 -0
- package/dist/features/context-memo.js.map +1 -0
- package/dist/features/contextless-store.d.ts +20 -0
- package/dist/features/contextless-store.d.ts.map +1 -1
- package/dist/features/contextless-store.js +35 -1
- package/dist/features/contextless-store.js.map +1 -1
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +198 -21
- package/dist/session/session-manager.js.map +1 -1
- package/dist/shared/path-utils.d.ts.map +1 -0
- package/dist/shared/path-utils.js.map +1 -0
- package/package.json +1 -1
- package/settings-host.js +18 -17
package/client/qqbot-settings.js
CHANGED
|
@@ -2047,6 +2047,13 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
|
|
|
2047
2047
|
if (m) appId = m[1]
|
|
2048
2048
|
} catch (e) {}
|
|
2049
2049
|
}
|
|
2050
|
+
// ★ 优先用「顶栏命中的当前会话」—— 群/私聊通用(2026-10-01 修:原来只支持群,私聊保存会报未命中)
|
|
2051
|
+
var hit = state.detectedHit
|
|
2052
|
+
if (hit && hit.peerId && appId) {
|
|
2053
|
+
var kind = (hit.scope === 'c2c') ? 'c2c' : 'group'
|
|
2054
|
+
return 'qqbot:' + appId + ':' + kind + ':' + String(hit.peerId)
|
|
2055
|
+
}
|
|
2056
|
+
// 回落:面板里选中的群
|
|
2050
2057
|
var gid = ''
|
|
2051
2058
|
try { gid = curHitGid() || '' } catch (e) { gid = '' }
|
|
2052
2059
|
if (!gid) gid = state.gid || ''
|
|
@@ -2060,12 +2067,22 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
|
|
|
2060
2067
|
var win = panel ? panel.querySelector('#dk-ctxless-win') : null
|
|
2061
2068
|
var hint = panel ? panel.querySelector('#dk-ctxless-hint') : null
|
|
2062
2069
|
var key = ctxlessKey()
|
|
2063
|
-
if (!key) { if (hint) hint.textContent = '
|
|
2070
|
+
if (!key) { if (hint) hint.textContent = '先选一个群/私聊'; return }
|
|
2064
2071
|
api('contextless?sessionKey=' + encodeURIComponent(key))
|
|
2065
2072
|
.then(function (d) {
|
|
2066
2073
|
state.ctxless = d || null
|
|
2067
2074
|
if (on) on.checked = !!(d && d.enabled)
|
|
2068
2075
|
if (win && d && typeof d.window === 'number') win.value = String(d.window)
|
|
2076
|
+
try { var _mmEl = document.getElementById('dk-ctxless-memomax'); if (_mmEl) _mmEl.value = String((d && typeof d.memoMax === 'number') ? d.memoMax : 20) } catch (e) { /* ignore */ }
|
|
2077
|
+
// 2026-10-01: 同步 radio(原来只更新了条数框 —— 面板先渲染后拉数据,radio 会停在默认的"按条数")
|
|
2078
|
+
try {
|
|
2079
|
+
var _isSmart = !!(d && d.smart === true)
|
|
2080
|
+
var _rs = document.querySelectorAll('input[name="dk-ctxless-mode"]')
|
|
2081
|
+
Array.prototype.forEach.call(_rs, function (r) {
|
|
2082
|
+
r.checked = (r.value === 'smart') ? _isSmart : !_isSmart
|
|
2083
|
+
})
|
|
2084
|
+
if (win) win.disabled = _isSmart
|
|
2085
|
+
} catch (e) { /* ignore */ }
|
|
2069
2086
|
if (hint) hint.textContent = (d && d.enabled) ? '已开启(本会话)' : ''
|
|
2070
2087
|
})
|
|
2071
2088
|
.catch(function () { if (hint) hint.textContent = '读取失败(面板需刷新/重启后重试)' })
|
|
@@ -2079,14 +2096,27 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
|
|
|
2079
2096
|
if (hint) hint.textContent = '读取当前会话…'
|
|
2080
2097
|
lookupCurrentSession(function () {
|
|
2081
2098
|
var key = ctxlessKey()
|
|
2082
|
-
if (!key) { if (hint) hint.textContent = '未命中 QQ 会话 ——
|
|
2083
|
-
|
|
2099
|
+
if (!key) { if (hint) hint.textContent = '未命中 QQ 会话 —— 先和 bot 在群里或私聊里聊一句(让它成为活跃会话),再回来保存'; return }
|
|
2100
|
+
// 2026-10-01: 模式单选 → smart;smart=true 时 window 不生效(互斥)
|
|
2101
|
+
var _modeEl = document.querySelector('input[name="dk-ctxless-mode"]:checked')
|
|
2102
|
+
var _mode = _modeEl ? String(_modeEl.value) : 'window'
|
|
2103
|
+
var _mmEl2 = document.getElementById('dk-ctxless-memomax')
|
|
2104
|
+
var body = { sessionKey: key, enabled: !!(on && on.checked), window: win ? (parseInt(win.value, 10) || 0) : 5, smart: _mode === 'smart', memoMax: _mmEl2 ? (parseInt(_mmEl2.value, 10) || 20) : 20 }
|
|
2105
|
+
// radio 切换:智能判断时条数框禁用(互斥的视觉提示)
|
|
2106
|
+
Array.prototype.forEach.call(document.querySelectorAll('input[name="dk-ctxless-mode"]'), function (r) {
|
|
2107
|
+
r.onchange = function () {
|
|
2108
|
+
var w = document.getElementById('dk-ctxless-win')
|
|
2109
|
+
if (w) w.disabled = (r.value === 'smart')
|
|
2110
|
+
}
|
|
2111
|
+
})
|
|
2084
2112
|
if (hint) hint.textContent = '保存中…'
|
|
2085
2113
|
apiPost('contextless', body).then(function (d) {
|
|
2086
2114
|
if (!d || !d.ok) { if (hint) hint.textContent = '保存失败: ' + JSON.stringify(d); return }
|
|
2087
2115
|
// ★ 保存后【回读】验证(这样"到底存进去没有"一眼可见,不用猜)
|
|
2088
2116
|
api('contextless?sessionKey=' + encodeURIComponent(key)).then(function (back) {
|
|
2089
2117
|
var same = back && back.enabled === body.enabled && Number(back.window) === Number(body.window)
|
|
2118
|
+
&& (back.smart === true) === (body.smart === true)
|
|
2119
|
+
&& Number(back.memoMax || 20) === Number(body.memoMax || 20)
|
|
2090
2120
|
if (hint) {
|
|
2091
2121
|
hint.textContent = same
|
|
2092
2122
|
? ('✅ 已保存并回读确认: ' + (back.enabled ? '开启' : '关闭') + ' / 带 ' + back.window + ' 条')
|
|
@@ -3641,12 +3671,28 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
|
|
|
3641
3671
|
var ctxHit = curHitLabel()
|
|
3642
3672
|
body += '<div class="dk-msg" style="line-height:1.6">开启后, 本会话每轮<b>不继承历史对话</b>(系统规则照旧), 只带上「@ 之前 N 条群消息」—— 群聊省 token 的利器。</div>'
|
|
3643
3673
|
body += '<div class="dk-msg" style="color:#888;font-size:12px;margin:2px 0 6px">作用对象: <b>' + (ctxHit || '(当前会话不是 QQ 会话)') + '</b></div>'
|
|
3674
|
+
var _smartOn = !!(state.ctxless && state.ctxless.smart === true)
|
|
3675
|
+
var _winVal = (state.ctxless && typeof state.ctxless.window === 'number') ? state.ctxless.window : 5
|
|
3644
3676
|
body += '<div class="dk-row" style="gap:8px;flex-wrap:wrap;align-items:center">'
|
|
3645
3677
|
+ '<label style="display:inline-flex;align-items:center;gap:4px;cursor:pointer;font-size:13px"><input type="checkbox" id="dk-ctxless-on"' + (state.ctxless && state.ctxless.enabled ? ' checked' : '') + '>无上下文模式</label>'
|
|
3646
|
-
+ '<span style="font-size:12px;color:#666">带 @ 前 <input type="number" id="dk-ctxless-win" min="0" value="' + ((state.ctxless && typeof state.ctxless.window === 'number') ? state.ctxless.window : 5) + '" style="width:56px"> 条</span>'
|
|
3647
3678
|
+ '<button class="dk-btn ok" id="dk-ctxless-save" style="margin-left:auto">💾 保存(本会话)</button>'
|
|
3648
3679
|
+ '<span class="dk-msg" id="dk-ctxless-hint" style="color:#2f9e44"></span></div>'
|
|
3649
|
-
|
|
3680
|
+
// 2026-10-01: 两种模式**互斥**(单参数是死参数、智能判断交给 AI),所以做成单选
|
|
3681
|
+
body += '<div style="margin:4px 0 0 22px;display:flex;flex-direction:column;gap:8px">'
|
|
3682
|
+
+ '<label style="display:flex;align-items:flex-start;gap:6px;cursor:pointer;font-size:13px">'
|
|
3683
|
+
+ '<input type="radio" name="dk-ctxless-mode" value="window"' + (_smartOn ? '' : ' checked') + ' style="margin-top:3px">'
|
|
3684
|
+
+ '<span>按条数保留 <span style="font-size:12px;color:#666">带 @ 前 <input type="number" id="dk-ctxless-win" min="0" value="' + _winVal + '"' + (_smartOn ? ' disabled' : '') + ' style="width:56px"> 条</span>'
|
|
3685
|
+
+ '<div style="font-size:12px;color:#888;line-height:1.4">不管在聊什么,每轮都只带「@ 前 N 条」。简单、可预期;但<b>同一话题接着聊可能断片</b>,<b>换了话题又会多带</b>。</div></span></label>'
|
|
3686
|
+
+ '<label style="display:flex;align-items:flex-start;gap:6px;cursor:pointer;font-size:13px">'
|
|
3687
|
+
+ '<input type="radio" name="dk-ctxless-mode" value="smart"' + (_smartOn ? ' checked' : '') + ' style="margin-top:3px">'
|
|
3688
|
+
+ '<span>智能判断(推荐)'
|
|
3689
|
+
+ '<div style="font-size:12px;color:#888;line-height:1.4">由 AI <b>每轮自己判断话题是否结束</b>:结束了它就压缩旧历史(可留最近几条)或整段丢弃,<b>只留下自己总结的要点</b> —— 省 token 最狠,也不容易断片。要点存在独立文件里,<b>压缩永远碰不到</b>。</div></span></label>'
|
|
3690
|
+
+ '</div>'
|
|
3691
|
+
// 备忘条数上限(面板可设;超出自动丢最旧)
|
|
3692
|
+
body += '<div class="dk-row" style="gap:6px;align-items:center;margin:4px 0 2px 22px;font-size:13px">'
|
|
3693
|
+
+ '<span>备忘条数上限 <input type="number" id="dk-ctxless-memomax" min="1" max="500" value="' + ((state.ctxless && typeof state.ctxless.memoMax === 'number') ? state.ctxless.memoMax : 20) + '" style="width:60px"> 条</span>'
|
|
3694
|
+
+ '<span style="font-size:12px;color:#888">(超出自动丢最旧的;AI 每轮的提示已要求它写精简)</span></div>'
|
|
3695
|
+
body += '<div class="dk-msg" style="line-height:1.5;color:#888">0 条 = 完全不带群消息(只剩系统规则 + 当前这句)。智能判断模式下条数不生效。开关存在插件数据目录, 重启不丢;<b>面板保存即时生效</b>,直接改文件则需重启。</div>'
|
|
3650
3696
|
} else if (st === 'blank') {
|
|
3651
3697
|
body += '<div style="border:1px dashed #cfc7ee;border-radius:8px;padding:20px 14px;margin:8px 0;text-align:center;line-height:2">'
|
|
3652
3698
|
+ '<div style="font-size:15px;font-weight:700">📄 空白样板</div>'
|
|
@@ -4513,18 +4559,18 @@ var QQS_CSS = ".qqs-btn{font:inherit;color:#333;background:linear-gradient(180de
|
|
|
4513
4559
|
var keyOf = function (x) { return String(x.seq) + '|' + String(x.dir) + '|' + String(x.text || '').slice(0, 24) }
|
|
4514
4560
|
var have = {}
|
|
4515
4561
|
state.chatItems.forEach(function (x) { have[keyOf(x)] = 1 })
|
|
4516
|
-
// ⚠️ 2026-10-01 主人实测「向下滚后最新消息后面冒出历史消息」:
|
|
4517
|
-
// 群打包块([历史]…[/历史])会被拆成多条挂在**同一个新 seq** 上, 内容却是**更早**的消息;
|
|
4518
|
-
// 不过滤就会被当新事件整块接到列表尾部。只收"时间不早于列表尾部那条"的条目。
|
|
4519
|
-
var _tailT = state.chatItems.length ? (Number(state.chatItems[state.chatItems.length - 1].time) || 0) : 0
|
|
4520
|
-
var fresh = list.filter(function (x) {
|
|
4521
|
-
return !have[keyOf(x)] && (Number(x.time) || 0) >= _tailT
|
|
4562
|
+
// ⚠️ 2026-10-01 主人实测「向下滚后最新消息后面冒出历史消息」:
|
|
4563
|
+
// 群打包块([历史]…[/历史])会被拆成多条挂在**同一个新 seq** 上, 内容却是**更早**的消息;
|
|
4564
|
+
// 不过滤就会被当新事件整块接到列表尾部。只收"时间不早于列表尾部那条"的条目。
|
|
4565
|
+
var _tailT = state.chatItems.length ? (Number(state.chatItems[state.chatItems.length - 1].time) || 0) : 0
|
|
4566
|
+
var fresh = list.filter(function (x) {
|
|
4567
|
+
return !have[keyOf(x)] && (Number(x.time) || 0) >= _tailT
|
|
4522
4568
|
})
|
|
4523
4569
|
if (fresh.length) {
|
|
4524
4570
|
state.chatItems = state.chatItems.concat(fresh)
|
|
4525
4571
|
appendChatRows(fresh) // ★ 增量追加: 不重绘、不闪、不跳位置
|
|
4526
4572
|
}
|
|
4527
|
-
// 已加载位置 = 列表里最大的事件 seq(同 ①:不能用 tailSeq)
|
|
4573
|
+
// 已加载位置 = 列表里最大的事件 seq(同 ①:不能用 tailSeq)
|
|
4528
4574
|
state.chatItems.forEach(function (x) { var n = Number(x.seq); if (n > state.chatNewest) state.chatNewest = n })
|
|
4529
4575
|
updateChatStatus()
|
|
4530
4576
|
}).catch(function () { state.chatBusy = ''; updateChatStatus() })
|