@zaofan/dsh-qqbot 1.5.10 → 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 +33 -62
- package/README.md.bak-final-1790552188493 +274 -0
- package/README.md.bak-ghnote-1790548468037 +269 -0
- package/client/qqbot-settings.js +4876 -4785
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/features/contextless-store.d.ts +33 -0
- package/dist/features/contextless-store.d.ts.map +1 -0
- package/dist/features/contextless-store.js +253 -0
- package/dist/features/contextless-store.js.map +1 -0
- package/dist/features/contextless-trim.d.ts +47 -0
- package/dist/features/contextless-trim.d.ts.map +1 -0
- package/dist/features/contextless-trim.js +304 -0
- package/dist/features/contextless-trim.js.map +1 -0
- package/dist/features/local-embed.d.ts +8 -0
- package/dist/features/local-embed.d.ts.map +1 -1
- package/dist/features/local-embed.js +58 -7
- package/dist/features/local-embed.js.map +1 -1
- package/dist/features/qq-approval.d.ts.map +1 -1
- package/dist/features/qq-approval.js +14 -2
- package/dist/features/qq-approval.js.map +1 -1
- package/dist/gateway/bootstrap.d.ts.map +1 -1
- package/dist/gateway/bootstrap.js +11 -0
- package/dist/gateway/bootstrap.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +70 -9
- package/dist/index.js.map +1 -1
- package/dist/session/session-manager.d.ts +6 -0
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +95 -0
- package/dist/session/session-manager.js.map +1 -1
- package/dist/transport/inbound.d.ts.map +1 -1
- package/dist/transport/inbound.js +20 -0
- package/dist/transport/inbound.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 +132 -11
- package/client/qqbot-settings.js.bak-clamp-195559 +0 -4780
- package/client/qqbot-settings.js.bak-ga-041943 +0 -4775
- 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/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
|
@@ -380,6 +380,66 @@ export function apply(ctx) {
|
|
|
380
380
|
// 台账文件 {store.dataDir}/known-chats.jsonl 由 dsh-qqbot 中间件 append(见 dsh-qqbot src/features/chat-ledger.ts)。
|
|
381
381
|
// 用途: Web 设置④区下拉点选目标(免抄 openid)——群无群名, 用最近发言者昵称帮主人辨认。
|
|
382
382
|
// 多账号: ?dataDir= 指定账号图库目录(台账与之同目录); 缺省 primary。
|
|
383
|
+
// ── 推断本插件的 dataRoot(与插件 src/gateway/data-root.ts 的算法保持一致)──
|
|
384
|
+
// 为什么要这么做:桥和插件在运行时可能是**两份模块实例**(各自的模块级变量不共享)。
|
|
385
|
+
// 插件在 bootstrap 里 initContextlessStore(dataRoot) 用的是正确路径;桥若没 init,
|
|
386
|
+
// contextless-store 的 ensurePath() 只能兜底到 {DSH_HOME},于是"面板保存"写一个文件、
|
|
387
|
+
// "插件实际读取"读另一个文件 → 表现为保存无效 / 开关显示不一致(2026-09-27 实测)。
|
|
388
|
+
function resolveContextlessDataRoot() {
|
|
389
|
+
try {
|
|
390
|
+
const parsed = parsePatch();
|
|
391
|
+
const bots = (parsed && Array.isArray(parsed.bots)) ? parsed.bots : [];
|
|
392
|
+
// 优先取"未禁用"的实例,其次任意一个有 cwd 的
|
|
393
|
+
const pick = bots.filter((b) => b && !b.disabled && b.cfg && (b.cfg.cwd || b.cfg.dataRoot));
|
|
394
|
+
const list = pick.length ? pick : bots.filter((b) => b && b.cfg && (b.cfg.cwd || b.cfg.dataRoot));
|
|
395
|
+
for (const b of list) {
|
|
396
|
+
const cfg = b.cfg || {};
|
|
397
|
+
if (cfg.dataRoot) return String(cfg.dataRoot);
|
|
398
|
+
if (cfg.cwd) return join(String(cfg.cwd), 'dshqqbot'); // 与 DEFAULT_DATA_SUBDIR 一致
|
|
399
|
+
}
|
|
400
|
+
} catch { /* 推不出来就交给 ensurePath 兜底 */ }
|
|
401
|
+
return '';
|
|
402
|
+
}
|
|
403
|
+
/** 确保 contextless-store 绑定到正确的数据根(幂等;路径变了会重新绑定) */
|
|
404
|
+
async function loadContextlessStore() {
|
|
405
|
+
const mod = await import('./dist/features/contextless-store.js'); // ← 函数体内用真正的动态 import(不能调自己)
|
|
406
|
+
try {
|
|
407
|
+
const dr = resolveContextlessDataRoot();
|
|
408
|
+
if (dr) mod.initContextlessStore(dr);
|
|
409
|
+
} catch { /* ignore */ }
|
|
410
|
+
return mod;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ── 无上下文模式(2026-09-27 主人定)──
|
|
414
|
+
// 会话级开关:dock 面板里对**某个会话**开启;开启后该会话每轮只带
|
|
415
|
+
// 「@ 之前 N 条群消息 + 系统规则」,历史对话全部丢弃(大幅省 token)。
|
|
416
|
+
// 开关存 {dataRoot}/.qqbot/contextless.json(由插件在 bootstrap 时初始化)。
|
|
417
|
+
route(ctx, 'GET', '/api/qqbot-settings/contextless', async (req, res) => {
|
|
418
|
+
try {
|
|
419
|
+
const u = new URL(req.url ?? '/', 'http://x');
|
|
420
|
+
const key = (u.searchParams.get('sessionKey') || '').trim();
|
|
421
|
+
const mod = await loadContextlessStore(); // 先 init 到同一个 dataRoot,避免两份模块实例各写一个文件
|
|
422
|
+
if (key) return writeJson(res, 200, mod.getContextless(key));
|
|
423
|
+
return writeJson(res, 200, { list: mod.listContextless() });
|
|
424
|
+
} catch (e) {
|
|
425
|
+
return writeJson(res, 500, { error: String((e && e.message) || e) });
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
route(ctx, 'POST', '/api/qqbot-settings/contextless', async (req, res) => {
|
|
429
|
+
try {
|
|
430
|
+
const body = await readJsonBody(req);
|
|
431
|
+
if (!body || typeof body !== 'object') return writeJson(res, 400, { error: 'body must be JSON object' });
|
|
432
|
+
const key = String(body.sessionKey || '').trim();
|
|
433
|
+
if (!key) return writeJson(res, 400, { error: 'sessionKey required' });
|
|
434
|
+
const mod = await loadContextlessStore(); // 先 init 到同一个 dataRoot,避免两份模块实例各写一个文件
|
|
435
|
+
if (body.remove === true) { mod.clearContextless(key); return writeJson(res, 200, { ok: true, removed: true }); }
|
|
436
|
+
const next = mod.setContextless(key, { enabled: body.enabled, window: body.window });
|
|
437
|
+
return writeJson(res, 200, { ok: true, value: next });
|
|
438
|
+
} catch (e) {
|
|
439
|
+
return writeJson(res, 500, { error: String((e && e.message) || e) });
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
|
|
383
443
|
route(ctx, 'GET', '/api/qqbot-settings/known-chats', async (req, res) => {
|
|
384
444
|
try {
|
|
385
445
|
const u = new URL(req.url ?? '/', 'http://x');
|
|
@@ -776,18 +836,26 @@ export function apply(ctx) {
|
|
|
776
836
|
writeJson(res, 200, {
|
|
777
837
|
hasFile,
|
|
778
838
|
instances: bots.map((b) => {
|
|
779
|
-
|
|
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);
|
|
780
848
|
// 数据根与 dist 侧 dataRootOf 对齐: 未配 dataRoot → `{cwd}/dshqqbot`(2026-09-12 新默认)
|
|
781
849
|
const droot = b.cfg?.dataRoot || (cwd ? join(cwd, 'dshqqbot') : '');
|
|
782
850
|
return {
|
|
783
851
|
id: b.id,
|
|
784
852
|
ns: b.id, // settings 命名空间 = 实例 id(主 im-qqbot; 非主实例 render 已写 settingsNs=id)
|
|
785
|
-
appId:
|
|
786
|
-
appSecret:
|
|
787
|
-
hasSecret:
|
|
788
|
-
preset:
|
|
853
|
+
appId: appIdMerged,
|
|
854
|
+
appSecret: hasSecretMerged ? SECRET_MASK : '', // 掩码回显(借鉴 panel: masked)
|
|
855
|
+
hasSecret: hasSecretMerged,
|
|
856
|
+
preset: presetMerged,
|
|
789
857
|
cwd,
|
|
790
|
-
disabled: !!b.disabled,
|
|
858
|
+
disabled: !!b.disabled || ownCfg.disabled === true,
|
|
791
859
|
online: typeof reg.isBotOnline === 'function' ? reg.isBotOnline(b.id) : false, // 在线状态(bot ws ready 事件驱动)
|
|
792
860
|
// 账号数据目录(各号各库各定时): 图库={cwd}/表情包, 定时={cwd}/.qqbot
|
|
793
861
|
dataDir: droot ? join(droot, '表情包') : '',
|
|
@@ -1672,16 +1740,50 @@ export function apply(ctx) {
|
|
|
1672
1740
|
// ── ⑥QQ 群管理面板(P3, 2026-09-05): 多群管理 host 路由(读/写走 GroupAdminClient; 面板=主人直发免 QQ 审批) ──
|
|
1673
1741
|
// 数据: {cwd}/.qqbot/{groups.json 群注册表, join-pending.json 待审, group-audit.jsonl 审计日志}
|
|
1674
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
|
+
|
|
1675
1768
|
function nsBot(ns) {
|
|
1676
1769
|
const { bots } = parsePatch();
|
|
1677
1770
|
const id = ns && ns !== 'im-qqbot' ? String(ns) : 'im-qqbot';
|
|
1678
1771
|
const b = bots.find((x) => x.id === id);
|
|
1679
1772
|
if (!b) return null;
|
|
1680
|
-
|
|
1681
|
-
|
|
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 || '';
|
|
1682
1783
|
// 数据根: dataRoot(新) > `{cwd}/dshqqbot`(**2026-09-12 新默认**, 与 dist 侧 dataRootOf 对齐);
|
|
1683
1784
|
// nsBot 的 cwd 字段按数据根返回(全为数据目录用途) —— 未配 dataRoot 的实例不再落到工作目录。
|
|
1684
|
-
const
|
|
1785
|
+
const cwdCfg = b.cfg?.cwd || own.cwd || '';
|
|
1786
|
+
const cwd = (b.cfg?.dataRoot || own.dataRoot || (cwdCfg ? join(cwdCfg, 'dshqqbot') : ''));
|
|
1685
1787
|
if (!appId || !appSecret) return null;
|
|
1686
1788
|
return { id, appId, appSecret, cwd, ns: id };
|
|
1687
1789
|
}
|
|
@@ -1794,8 +1896,11 @@ export function apply(ctx) {
|
|
|
1794
1896
|
const { bots } = parsePatch();
|
|
1795
1897
|
const botByNs = new Map();
|
|
1796
1898
|
for (const bot of bots) {
|
|
1797
|
-
|
|
1798
|
-
|
|
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 });
|
|
1799
1904
|
}
|
|
1800
1905
|
const hits = [];
|
|
1801
1906
|
const seen = new Set();
|
|
@@ -1978,6 +2083,20 @@ export function apply(ctx) {
|
|
|
1978
2083
|
req.setTimeout(180000, () => req.destroy(new Error('下载超时(180s)')));
|
|
1979
2084
|
});
|
|
1980
2085
|
}
|
|
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
|
+
|
|
1981
2100
|
route(ctx, 'GET', '/api/qqbot-settings/local-model/status', async (req, res) => {
|
|
1982
2101
|
try {
|
|
1983
2102
|
const u = new URL(req.url ?? '/', 'http://x');
|
|
@@ -3672,6 +3791,8 @@ const WHY_MAP = { busy: '目标会话回合活跃,已等待至回合结束仍超
|
|
|
3672
3791
|
const { bots } = parsePatch();
|
|
3673
3792
|
const out = [];
|
|
3674
3793
|
for (const bot of bots) {
|
|
3794
|
+
// ⚠️ 2026-09-28:凭据可能只在【自有存储】里(2026-09-24 起的保存策略),合并后再判断。
|
|
3795
|
+
bot.cfg = mergeOwnIntoCfg(bot.cfg || {}, bot.cfg?.settingsNs || bot.id);
|
|
3675
3796
|
if (bot.disabled || !bot.cfg?.appId || !bot.cfg?.appSecret) continue;
|
|
3676
3797
|
try {
|
|
3677
3798
|
const ns = bot.id;
|