@zaofan/dsh-qqbot 1.5.12 → 1.5.14
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/README.md +31 -117
- package/{README.md.bak-1511-1790525690506 → README.md.bak-final-1790552188493} +25 -61
- package/{README.md.bak-1512-1790529705004 → README.md.bak-ghnote-1790548468037} +19 -99
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +70 -9
- package/dist/index.js.map +1 -1
- package/docs/USER-GUIDE.md +113 -0
- package/entry.js +57 -0
- package/package.json +136 -125
- package/settings-host.js +72 -25
- package/client/qqbot-settings.js.bak-apifix-1790512748500 +0 -4846
- package/client/qqbot-settings.js.bak-bind3-1790517775201 +0 -4882
- package/client/qqbot-settings.js.bak-clamp-195559 +0 -4780
- package/client/qqbot-settings.js.bak-ctxev-1790511964477 +0 -4830
- package/client/qqbot-settings.js.bak-ctxless-202526 +0 -4785
- package/client/qqbot-settings.js.bak-ctxui-1790511940536 +0 -4824
- package/client/qqbot-settings.js.bak-delegate-1790515486404 +0 -4844
- package/client/qqbot-settings.js.bak-fixctx2-1790512183370 +0 -4844
- package/client/qqbot-settings.js.bak-ga-041943 +0 -4775
- package/client/qqbot-settings.js.bak-lmreset-1790522156560 +0 -4873
- package/client/qqbot-settings.js.bak-lmreset2-1790522188051 +0 -4873
- package/client/qqbot-settings.js.bak-movectx-1790512156480 +0 -4838
- package/client/qqbot-settings.js.bak-privacy-1790525734851 +0 -4876
- package/client/qqbot-settings.js.bak-save2-1790517095028 +0 -4859
- package/dist/commands/approve.d.ts +0 -17
- package/dist/commands/approve.d.ts.map +0 -1
- package/dist/commands/approve.js +0 -24
- package/dist/commands/approve.js.map +0 -1
- package/dist/features/approval-switch.d.ts +0 -22
- package/dist/features/approval-switch.d.ts.map +0 -1
- package/dist/features/approval-switch.js +0 -10
- package/dist/features/approval-switch.js.map +0 -1
package/docs/USER-GUIDE.md
CHANGED
|
@@ -72,6 +72,24 @@ npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
|
|
|
72
72
|
|
|
73
73
|
> 思路来源: wang-22-code/dsh-qqbot-bridge 的 QQ 审批设计(宿主 dsh `approval/request` 标准事件,官方 dsh-acp / Web 审批弹窗同款机制)。
|
|
74
74
|
|
|
75
|
+
|
|
76
|
+
### 审批卡片:谁可以点(v1.5.12+)
|
|
77
|
+
|
|
78
|
+
发起审批的卡片**发到发起者所在的会话**(群里就发到群里),但**只有下列人能点按钮**:
|
|
79
|
+
|
|
80
|
+
1. **发起者本人**
|
|
81
|
+
2. **主人白名单** —— `groupAdmin.owners`
|
|
82
|
+
|
|
83
|
+
> ⚠️ **群聊场景一定要填白名单**:设置 → QQ 机器人 →「允许操作的主人 openid(逗号分隔,可留空=不校验)」。
|
|
84
|
+
> 否则别人发起的审批,主人点了没反应(卡片只认发起者)。
|
|
85
|
+
> 私聊场景不受影响(本就只有双方)。
|
|
86
|
+
|
|
87
|
+
**这个白名单同时用于**:群管理工具的权限校验 + 审批卡片的可点名单(同一个"主人"概念)。
|
|
88
|
+
|
|
89
|
+
**排障**:若点了按钮后"本轮运行失败",且日志里有
|
|
90
|
+
`SessionFormatError: format v4 message requires a producer-owned source kind` ——
|
|
91
|
+
说明插件版本 < 1.5.12(旧代码用了 dsh V4 禁止的 `source.kind='plugin'`),升级即可。
|
|
92
|
+
|
|
75
93
|
## QQ 群管理(可选)
|
|
76
94
|
|
|
77
95
|
机器人**为群管理员**时,可开启群管理能力:实时接收「入群申请」并自动提醒主人、按申请审批入群、查询/设置群成员禁言。所有操作走腾讯官方 GroupOpenMsg 接口,错误信息已做"人话"映射(如 11703=机器人不是该群管理员、40103004=不能禁言群主/管理员、11255=群已注销)。
|
|
@@ -183,6 +201,43 @@ Invoke-WebRequest "$base/config.json" -OutFile "$dir\config.json"
|
|
|
183
201
|
- **拦截边界**:被 @ 的永远放行;带图一律放行;**只有被拦在唤醒之前**(没花 token)的那次才会**回滚**本群的回复冷却 —— 冷却本来就是用来省 token 的,token 花了就不算白花。
|
|
184
202
|
- **评分记录**:`{dataRoot}/.qqbot/value-scores.jsonl`,一行一条,字段 `score / worth / gate / min / conf / mention / img / lib / agg / top`。面板能直读,也可以让 AI 读它来维护样例库(`{dataRoot}/.qqbot/value-samples.jsonl`:`{"m":"消息文本","y":1|0}`,y=1 表示"她会想接话")。
|
|
185
203
|
|
|
204
|
+
|
|
205
|
+
## 🚫 无上下文模式(按会话省 token)(v1.5.11+)
|
|
206
|
+
|
|
207
|
+
让某个 QQ 会话**每轮只记得最近几条对话**,更早的历史自动折叠 —— 群聊省 token 利器。
|
|
208
|
+
|
|
209
|
+
### 怎么开
|
|
210
|
+
|
|
211
|
+
1. 打开 dock 面板(右下角 🛡)→「⚙ **单会话设置**」→ 子标签「🚫 **无上下文**」
|
|
212
|
+
2. 确认面板上显示的"作用对象"是你想设的那个群
|
|
213
|
+
3. 勾选「无上下文模式」,填「带 @ 前 N 条」,点「💾 保存(本会话)」
|
|
214
|
+
- 保存成功会显示「✅ 已保存并回读确认: 开启 / 带 N 条」
|
|
215
|
+
|
|
216
|
+
### 行为说明(几个容易误解的地方)
|
|
217
|
+
|
|
218
|
+
| 现象 | 说明 |
|
|
219
|
+
|---|---|
|
|
220
|
+
| **web 上还能翻到旧对话** | ✅ 正常。折叠的只是「模型视野」,**会话记录本身不删**;web 里会多一行「上下文已压缩 · 已压缩 N 条历史记录」的折叠标记 |
|
|
221
|
+
| **N 条 ≠ N 条 QQ 消息** | ⚠️ N 计的是 **dsh 侧的消息条数**。插件入站时会把"群历史 + 当前消息"**聚合成一条**,所以 1 条可能含多条 QQ 消息(群历史缓冲上限由 `historyLimit` 控制,默认 10) |
|
|
222
|
+
| **群守则每轮都重新注入** | ✅ 正常且必要。压缩会把旧的守则一起折叠,所以每轮补一份;**改了群守则会立刻生效**(去重按内容比较) |
|
|
223
|
+
| **什么时候生效** | 压缩发生在**回合开始**,所以**从下一轮起**才看不到更早的对话(当轮她已经装好上下文了) |
|
|
224
|
+
| **会调额外的模型吗** | ❌ 不会。替身文本是写死的,**零 LLM 调用**(比 dsh 自带 compaction"生成摘要"更省) |
|
|
225
|
+
|
|
226
|
+
### 全局开启(可选)
|
|
227
|
+
|
|
228
|
+
不逐会话设置也可以开全局:
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
contextlessMode: true # 所有会话都启用
|
|
232
|
+
contextlessWindow: 5 # 保留最近 5 条
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 存储位置
|
|
236
|
+
|
|
237
|
+
`{dataRoot}/.qqbot/contextless.json` —— 键是会话(`qqbot:<appId>:group:<群openid>`),值 `{ enabled, window }`。
|
|
238
|
+
|
|
239
|
+
> ⚠️ 别手改这个文件(面板保存会回读校验);想全关就把每个 key 的 `enabled` 改成 `false`。
|
|
240
|
+
|
|
186
241
|
## 💗 好感度与熟识度(v1.5.0+)
|
|
187
242
|
|
|
188
243
|
两个维度**分开算、互不干扰**:
|
|
@@ -434,6 +489,64 @@ sessionKey: `qqbot:${appId}:${scope}:${peerId}`,由 SHA-256 确定性派生 Se
|
|
|
434
489
|
|
|
435
490
|
解析策略:进程内复用 → 持久化恢复 → 全新创建。
|
|
436
491
|
|
|
492
|
+
|
|
493
|
+
## 常见问题(详解)
|
|
494
|
+
|
|
495
|
+
### Q: 升级 dsh 0.1.7 后,恢复会话报「预设缺失」/ 机器人不理人?
|
|
496
|
+
|
|
497
|
+
**原因**:0.1.7 把「Agent 预设」从"目录里的文件"改成了"profile 里的声明行",旧的预设目录不再被扫描。
|
|
498
|
+
|
|
499
|
+
**处理**:用插件自带的迁移脚本把预设迁到 profile 声明里(或重新在「Agent 预设」页里建一次),然后重启 dsh。
|
|
500
|
+
|
|
501
|
+
### Q: 升级 dsh 0.1.7 后,某些插件被「禁用 / 跳过」?
|
|
502
|
+
|
|
503
|
+
**原因**:0.1.7 起按 `peerDependencies` 校验插件与宿主兼容性,声明不匹配的会被跳过(打印 `skipping profile bundle ...`)。
|
|
504
|
+
|
|
505
|
+
**处理**:升级该插件,或按提示用 `dsh plugin allow-version` 显式豁免。
|
|
506
|
+
|
|
507
|
+
### Q: 升级后我自定义的配置(群守则 / 注入规则 / 互动事件)被默认值顶掉了,能找回吗?
|
|
508
|
+
|
|
509
|
+
**能。** 0.1.7 会把 `~/.dsh/settings.yaml` 一次性导入 profile,但**导入不一定落到 entry config 里**;
|
|
510
|
+
插件读不到自定义值就用默认值回写,把你的配置顶掉。
|
|
511
|
+
|
|
512
|
+
**找回步骤**:
|
|
513
|
+
1. 打开 `~/.dsh/settings.yaml.imported`(同目录通常还有 `.bak`)
|
|
514
|
+
2. 找到你实例的 section(如 `im-qqbot-2:`),再找对应字段(`groupPrompt:` / `injectRules:` / `botplayEvents:` …)
|
|
515
|
+
3. 复制内容,回 Web 设置页粘回去保存
|
|
516
|
+
(1.5.9 起配置存在插件自有存储,不会再被默认值覆盖)
|
|
517
|
+
|
|
518
|
+
> ⚠️ 群守则里常含私人信息(主人 openid、进群暗号等),**发布/分享/截图时记得剔除**。
|
|
519
|
+
|
|
520
|
+
### Q: 设置页保存后,为什么 patch 里看不到我的改动?
|
|
521
|
+
|
|
522
|
+
**这是有意设计**。设置页保存**不写 profile 的 `cordis.patch.yml`**,而是写插件自己的存储:
|
|
523
|
+
`{DSH_HOME}/qqbot-settings/<实例 id>.json`。
|
|
524
|
+
|
|
525
|
+
**为什么**:写 patch 会被宿主当成热更新提交 → 插件重新加载 → 若凭据无效又会写 → 形成死循环(实测能把 dsh 启动刷死)。
|
|
526
|
+
另外手拼 YAML 也保不住字段类型(已实测出 `expected string` / `expected array` 等问题)。
|
|
527
|
+
|
|
528
|
+
**读取顺序**:patch 值 + 自有存储覆盖(后者优先)。
|
|
529
|
+
|
|
530
|
+
### Q: 面板上「实时入群事件」开关是干什么的?打开后机器人连不上了?
|
|
531
|
+
|
|
532
|
+
**原因**:这个开关会订阅 QQ 的 `GROUP_JOIN_REQUEST` 事件(intent `1<<24`)。
|
|
533
|
+
**若开放平台没有开通该事件,网关会拒绝连接(close 4914/4915)→ 机器人直接离线**。
|
|
534
|
+
|
|
535
|
+
**正确处理顺序**:**① 平台开通事件 → ② 打开开关 → ③ 重启**。
|
|
536
|
+
|
|
537
|
+
**不想折腾平台**:用「轮询入群申请」(不需要任何授权):
|
|
538
|
+
- `轮询入群申请` 是**总开关**,不勾它,下面的选项都不生效
|
|
539
|
+
- 「唤醒 AI」与「注入群管会话」**互斥且唤醒优先** —— 两个都勾只会唤醒 AI,不会注入群管会话
|
|
540
|
+
- 想要静默注入群管会话,就**只勾「注入群管会话」**
|
|
541
|
+
|
|
542
|
+
### Q: 为什么自有存储里不要出现空对象(`{}`)?
|
|
543
|
+
|
|
544
|
+
**原因**:合并是递归深合并,但**空对象会把整块默认配置顶掉**。
|
|
545
|
+
例如 `sticker: {}` 会顶掉 patch 里的整个 `sticker` 块 → `collectEnabled` 变成 `undefined` → **图片自动下载静默停摆**
|
|
546
|
+
(症状:最后一张自动下载的图停在某个时刻,之后入站图片只剩 QQ 长 URL)。
|
|
547
|
+
|
|
548
|
+
**处理**:**想恢复默认就删掉该字段,不要写 `{}`**。
|
|
549
|
+
|
|
437
550
|
## 设计原则
|
|
438
551
|
|
|
439
552
|
- **纯 Cordis 插件** — 遵循 dsh "Plugins, not loop changes" 原则
|
package/entry.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 包入口守卫(永远随包发布,不参与编译)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要它:
|
|
5
|
+
* 仓库不提交编译产物 `dist/`,而 dsh 的插件页支持"填 GitHub 仓库地址安装"。
|
|
6
|
+
* 从 git 直装时若 pnpm 没有执行 `prepare`(新版 pnpm 默认拦截 git 依赖的构建脚本:
|
|
7
|
+
* `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`),装出来的包里就没有 `dist/`,
|
|
8
|
+
* 宿主只会打印一句很难懂的 `failed to import`。
|
|
9
|
+
*
|
|
10
|
+
* 这里在入口处先自检,把"真正的原因 + 怎么办"直接打到控制台。
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
|
|
16
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const missing = [];
|
|
18
|
+
for (const rel of ['dist/index.js', 'client/qqbot-settings.js', 'settings-host.js', 'cordis.patch.yml']) {
|
|
19
|
+
if (!existsSync(join(here, rel))) missing.push(rel);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (missing.length > 0) {
|
|
23
|
+
const isDistMissing = missing.includes('dist/index.js');
|
|
24
|
+
console.error('');
|
|
25
|
+
console.error(' ┌──────────────────────────────────────────────────────────────┐');
|
|
26
|
+
console.error(' │ dsh-qqbot 安装不完整,无法启动 │');
|
|
27
|
+
console.error(' └──────────────────────────────────────────────────────────────┘');
|
|
28
|
+
console.error(' 缺少文件: ' + missing.join(', '));
|
|
29
|
+
console.error(' 安装目录: ' + here);
|
|
30
|
+
console.error('');
|
|
31
|
+
if (isDistMissing) {
|
|
32
|
+
console.error(' 【最可能的原因】你是用 "GitHub 仓库地址" 安装的。');
|
|
33
|
+
console.error(' 仓库不提交编译产物 dist/,而新版 pnpm 默认不允许 git 依赖执行构建脚本');
|
|
34
|
+
console.error(' (报错类似 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED),于是 dist/ 没被编译出来。');
|
|
35
|
+
console.error('');
|
|
36
|
+
console.error(' 【最简单的解决办法】');
|
|
37
|
+
console.error(' 把依赖换成本包在 npm 上的发布版(自带 dist,不需要任何构建):');
|
|
38
|
+
console.error(' pnpm add @zaofan/dsh-qqbot');
|
|
39
|
+
console.error(' 或者在 dsh 插件页里填【包名】 @zaofan/dsh-qqbot (而不是 GitHub 地址)。');
|
|
40
|
+
console.error('');
|
|
41
|
+
console.error(' 【想继续用 git 源的化】');
|
|
42
|
+
console.error(' 在上面那个安装目录里手动编译一次:');
|
|
43
|
+
console.error(' npm install && npm run build');
|
|
44
|
+
console.error(' 如果报 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED,需要在 profile 的');
|
|
45
|
+
console.error(' pnpm-workspace.yaml 里允许它执行脚本(错误信息里会给出确切的 allowBuilds 写法)。');
|
|
46
|
+
}
|
|
47
|
+
console.error('');
|
|
48
|
+
throw new Error('dsh-qqbot: 安装不完整(缺少 ' + missing.join(', ') + '),请按上面的提示处理');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 自检通过 → 正常导出
|
|
52
|
+
// ⚠️ 2026-09-28 修:原来这里多写了一句 `export { default } from './dist/index.js'`,
|
|
53
|
+
// 但 dist/index.js 并没有 default 导出 → 触发
|
|
54
|
+
// SyntaxError: The requested module './dist/index.js' does not provide an export named 'default'
|
|
55
|
+
// → 整个插件 import 失败(宿主只报一句难懂的 "failed to import")。
|
|
56
|
+
// 这是个语法级错误:哪怕自检全过,插件也永远加载不起来。
|
|
57
|
+
export * from './dist/index.js';
|
package/package.json
CHANGED
|
@@ -1,125 +1,136 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@zaofan/dsh-qqbot",
|
|
3
|
-
"version": "1.5.
|
|
4
|
-
"description": "QQ Bot IM channel plugin for deepseek-harness (dsh)",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"import": "./
|
|
12
|
-
},
|
|
13
|
-
"./channel-tools": {
|
|
14
|
-
"types": "./dist/channel-tools.d.ts",
|
|
15
|
-
"import": "./dist/channel-tools.js"
|
|
16
|
-
},
|
|
17
|
-
"./sticker-store": {
|
|
18
|
-
"types": "./dist/features/sticker-store.d.ts",
|
|
19
|
-
"import": "./dist/features/sticker-store.js"
|
|
20
|
-
},
|
|
21
|
-
"./schedule-store": {
|
|
22
|
-
"types": "./dist/features/schedule-store.d.ts",
|
|
23
|
-
"import": "./dist/features/schedule-store.js"
|
|
24
|
-
},
|
|
25
|
-
"./client": "./client/qqbot-settings.js"
|
|
26
|
-
},
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsc",
|
|
29
|
-
"dev": "tsc --watch",
|
|
30
|
-
"prepublishOnly": "npm run build && node scripts/check-package.mjs",
|
|
31
|
-
"check:package": "node scripts/check-package.mjs",
|
|
32
|
-
"lint": "eslint src/",
|
|
33
|
-
"test": "vitest run",
|
|
34
|
-
"clean": "rm -rf dist",
|
|
35
|
-
"ci:prepare-test-pkg": "node scripts/prepare-test-pkg.js"
|
|
36
|
-
},
|
|
37
|
-
"repository": {
|
|
38
|
-
"type": "git",
|
|
39
|
-
"url": "git+https://github.com/gcry13067381632-jpg/dsh-qqbot.git"
|
|
40
|
-
},
|
|
41
|
-
"homepage": "https://github.com/gcry13067381632-jpg/dsh-qqbot#readme",
|
|
42
|
-
"bugs": {
|
|
43
|
-
"url": "https://github.com/gcry13067381632-jpg/dsh-qqbot/issues"
|
|
44
|
-
},
|
|
45
|
-
"keywords": [
|
|
46
|
-
"deepseek-harness",
|
|
47
|
-
"dsh",
|
|
48
|
-
"dsh-plugin",
|
|
49
|
-
"qqbot",
|
|
50
|
-
"qq-bot",
|
|
51
|
-
"chatbot",
|
|
52
|
-
"ai-agent",
|
|
53
|
-
"cordis",
|
|
54
|
-
"plugin",
|
|
55
|
-
"llm"
|
|
56
|
-
],
|
|
57
|
-
"license": "MIT",
|
|
58
|
-
"files": [
|
|
59
|
-
"dist",
|
|
60
|
-
"docs/USER-GUIDE.md",
|
|
61
|
-
"client",
|
|
62
|
-
"cordis.patch.yml",
|
|
63
|
-
"settings-host.js",
|
|
64
|
-
"README.md",
|
|
65
|
-
"README_EN.md",
|
|
66
|
-
"LICENSE",
|
|
67
|
-
"voice-convert.mjs",
|
|
68
|
-
"scripts/download-model.mjs",
|
|
69
|
-
"scripts/fix-dsh-016-presets.ps1"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
"@deepseek-ai/dsh-
|
|
91
|
-
"@deepseek-ai/dsh-
|
|
92
|
-
"@deepseek-ai/
|
|
93
|
-
"@
|
|
94
|
-
"@tencent-connect/qqbot-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"@deepseek-ai/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"@deepseek-ai/dsh-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"@deepseek-ai/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"@deepseek-ai/dsh-session":
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"@
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@zaofan/dsh-qqbot",
|
|
3
|
+
"version": "1.5.14",
|
|
4
|
+
"description": "QQ Bot IM channel plugin for deepseek-harness (dsh)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./entry.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./entry.js"
|
|
12
|
+
},
|
|
13
|
+
"./channel-tools": {
|
|
14
|
+
"types": "./dist/channel-tools.d.ts",
|
|
15
|
+
"import": "./dist/channel-tools.js"
|
|
16
|
+
},
|
|
17
|
+
"./sticker-store": {
|
|
18
|
+
"types": "./dist/features/sticker-store.d.ts",
|
|
19
|
+
"import": "./dist/features/sticker-store.js"
|
|
20
|
+
},
|
|
21
|
+
"./schedule-store": {
|
|
22
|
+
"types": "./dist/features/schedule-store.d.ts",
|
|
23
|
+
"import": "./dist/features/schedule-store.js"
|
|
24
|
+
},
|
|
25
|
+
"./client": "./client/qqbot-settings.js"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"dev": "tsc --watch",
|
|
30
|
+
"prepublishOnly": "npm run build && node scripts/check-package.mjs",
|
|
31
|
+
"check:package": "node scripts/check-package.mjs",
|
|
32
|
+
"lint": "eslint src/",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"clean": "rm -rf dist",
|
|
35
|
+
"ci:prepare-test-pkg": "node scripts/prepare-test-pkg.js"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/gcry13067381632-jpg/dsh-qqbot.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/gcry13067381632-jpg/dsh-qqbot#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/gcry13067381632-jpg/dsh-qqbot/issues"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"deepseek-harness",
|
|
47
|
+
"dsh",
|
|
48
|
+
"dsh-plugin",
|
|
49
|
+
"qqbot",
|
|
50
|
+
"qq-bot",
|
|
51
|
+
"chatbot",
|
|
52
|
+
"ai-agent",
|
|
53
|
+
"cordis",
|
|
54
|
+
"plugin",
|
|
55
|
+
"llm"
|
|
56
|
+
],
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"files": [
|
|
59
|
+
"dist",
|
|
60
|
+
"docs/USER-GUIDE.md",
|
|
61
|
+
"client",
|
|
62
|
+
"cordis.patch.yml",
|
|
63
|
+
"settings-host.js",
|
|
64
|
+
"README.md",
|
|
65
|
+
"README_EN.md",
|
|
66
|
+
"LICENSE",
|
|
67
|
+
"voice-convert.mjs",
|
|
68
|
+
"scripts/download-model.mjs",
|
|
69
|
+
"scripts/fix-dsh-016-presets.ps1",
|
|
70
|
+
"entry.js"
|
|
71
|
+
],
|
|
72
|
+
"dsh": {
|
|
73
|
+
"bundle": {
|
|
74
|
+
"patch": "./cordis.patch.yml"
|
|
75
|
+
},
|
|
76
|
+
"client": {
|
|
77
|
+
"platform": "web",
|
|
78
|
+
"inject": [
|
|
79
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
81
|
+
],
|
|
82
|
+
"immediately": true
|
|
83
|
+
},
|
|
84
|
+
"engines": {
|
|
85
|
+
"dsh": "0.1.5-rc.2 || 0.1.6-alpha.2 || 0.1.7-rc.1"
|
|
86
|
+
},
|
|
87
|
+
"manifestVersion": 1
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.1",
|
|
91
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
|
|
92
|
+
"@deepseek-ai/schemastery": "3.18.4",
|
|
93
|
+
"@tencent-connect/qqbot-connector": "1.2.0",
|
|
94
|
+
"@tencent-connect/qqbot-nodejs": "^1.0.4",
|
|
95
|
+
"js-yaml": "^4.1.0",
|
|
96
|
+
"lamejs-fixed": "^1.2.2",
|
|
97
|
+
"silk-wasm": "^3.7.1"
|
|
98
|
+
},
|
|
99
|
+
"peerDependencies": {
|
|
100
|
+
"@deepseek-ai/cordis": ">=4.0.1",
|
|
101
|
+
"@deepseek-ai/dsh-agent": ">=0.1.0-rc.6",
|
|
102
|
+
"@deepseek-ai/dsh-llm": ">=0.1.0-rc.6",
|
|
103
|
+
"@deepseek-ai/dsh-session": ">=0.1.0-rc.6",
|
|
104
|
+
"@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
|
|
105
|
+
"@tencent-connect/qqbot-connector": "1.2.0"
|
|
106
|
+
},
|
|
107
|
+
"peerDependenciesMeta": {
|
|
108
|
+
"@deepseek-ai/cordis": {
|
|
109
|
+
"optional": false
|
|
110
|
+
},
|
|
111
|
+
"@deepseek-ai/schemastery": {
|
|
112
|
+
"optional": false
|
|
113
|
+
},
|
|
114
|
+
"@deepseek-ai/dsh-agent": {
|
|
115
|
+
"optional": false
|
|
116
|
+
},
|
|
117
|
+
"@deepseek-ai/dsh-session": {
|
|
118
|
+
"optional": false
|
|
119
|
+
},
|
|
120
|
+
"@deepseek-ai/dsh-llm": {
|
|
121
|
+
"optional": false
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"devDependencies": {
|
|
125
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
126
|
+
"@deepseek-ai/dsh-agent": "0.1.0-rc.6",
|
|
127
|
+
"@deepseek-ai/dsh-llm": "0.1.0-rc.6",
|
|
128
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.6",
|
|
129
|
+
"@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
|
|
130
|
+
"@deepseek-ai/schemastery": "3.18.1",
|
|
131
|
+
"@types/js-yaml": "^4.0.9",
|
|
132
|
+
"@types/node": "^26.2.0",
|
|
133
|
+
"typescript": "^5.5.0",
|
|
134
|
+
"vitest": "^4.1.8"
|
|
135
|
+
}
|
|
136
|
+
}
|
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
|
-
|
|
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:
|
|
846
|
-
appSecret:
|
|
847
|
-
hasSecret:
|
|
848
|
-
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
|
-
|
|
1741
|
-
|
|
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
|
|
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
|
-
|
|
1858
|
-
|
|
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;
|