@zaofan/dsh-qqbot 1.10.33 → 1.10.35
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 +13 -8
- package/package.json +1 -1
- package/settings-host.js +36 -75
package/README.md
CHANGED
|
@@ -107,9 +107,9 @@ DSH 前端会把**回复正文里的 markdown 图片**渲染成图;本插件
|
|
|
107
107
|
配合表情包库最顺手:`list_stickers` 搜到图 → 把本地路径写进正文 → 图组直接出来,比连发 `send_media` 更像翻漫画。
|
|
108
108
|
|
|
109
109
|
失败策略:图传不上去时会**原样留在文字里**(不阻断本条,不会吞掉正文)。
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
113
|
## 📦 扩展包与插件市场:把你的扩展分享给别人
|
|
114
114
|
|
|
115
115
|
单个 `.mjs` 是「扩展文件」,**一个目录就是一个「扩展包」** —— 可以带工具、斜杠命令、封面、版本号,装进别人的面板里就是一张卡片。
|
|
@@ -173,9 +173,14 @@ export default {
|
|
|
173
173
|
run: async (args) => ({ ok: true, msg: '选中:' + args.options[0] }),
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
//
|
|
176
|
+
// ✅ 也认 parameters 这个别名
|
|
177
|
+
// (源码 src/features/extension-store.ts:225 是 inputSchema ?? parameters ?? {})
|
|
178
|
+
// ⚠️ 但值同样必须是扁平字段表,不能包 type/properties
|
|
179
|
+
|
|
180
|
+
// ❌ 错:包成标准 JSON Schema
|
|
177
181
|
// inputSchema: { type: 'object', properties: { options: {...} } }
|
|
178
|
-
// →
|
|
182
|
+
// → dsh 会拿这个对象的顶层键当参数名,于是模型看到的参数是 type / properties,
|
|
183
|
+
// 真正的 options 藏在 properties 里 → 看不见、调不动
|
|
179
184
|
```
|
|
180
185
|
|
|
181
186
|
命令的契约也不一样:工具用 **`run`**,命令用 **`handler`**(返回字符串)。
|
|
@@ -273,15 +278,15 @@ env.user / env.owners / env.peer · env.log() · env.kernel(全权限遥控器
|
|
|
273
278
|
|
|
274
279
|
---
|
|
275
280
|
|
|
276
|
-
## 🛒 插件市场与扩展包面板
|
|
277
|
-
|
|
281
|
+
## 🛒 插件市场与扩展包面板
|
|
282
|
+
|
|
278
283
|
**插件市场**——两列卡片、封面图、版本号、安装/更新/卸载一键搞定(数据来自扩展索引仓库,支持填代理解决墙内访问);
|
|
279
284
|
**扩展包面板**——每个包下面直接列出它带的工具和 `/斜杠命令`,点「设置」还能配自定义参数。
|
|
280
285
|
|
|
281
286
|

|
|
282
287
|
|
|
283
288
|

|
|
284
|
-
|
|
289
|
+
|
|
285
290
|
## 🆚 官方 Bot 方案 vs onbot / NapCat 等第三方协议端
|
|
286
291
|
|
|
287
292
|
本插件走的是**腾讯官方 QQ 机器人开放平台**(AppID + AppSecret + 官方 SDK),
|
package/package.json
CHANGED
package/settings-host.js
CHANGED
|
@@ -258,51 +258,36 @@ const OWN_SETTINGS_DIR = join(DSH_HOME_DIR, 'qqbot-settings');
|
|
|
258
258
|
* 现在与 `src/shared/utils.ts` 的 `resolveProfileName()` **同规则**:环境变量 → `PROFILE_ROOT` 目录名
|
|
259
259
|
* (要求其父目录名为 `profiles`,挡住源码 checkout 目录)→ 落 `_default`。改一处务必同步另一处。
|
|
260
260
|
*/
|
|
261
|
-
function resolveProfileName() {
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// 直接 return null → 评分/群管理/图库面板全空白,而 bot 收发消息完全正常,
|
|
292
|
-
// 极易被误判成"评分没跑起来"。issue #20 就是这个。
|
|
293
|
-
// ⚠️ 只在「恰好只有一个真实 profile 目录」时才认 —— **不猜**。
|
|
294
|
-
// 一台机器上可能同时有 desktop/ 和 web/(实测本机就有这两个),
|
|
295
|
-
// 按 prefer 猜会让 web 用户读到 desktop 的凭据,比原来更糟。
|
|
296
|
-
// 而那个场景下第 1 层环境变量本来就有值,根本轮不到这里。
|
|
297
|
-
try {
|
|
298
|
-
const subs = readdirSync(OWN_SETTINGS_DIR, { withFileTypes: true })
|
|
299
|
-
.filter((d) => d.isDirectory() && d.name !== '_default')
|
|
300
|
-
.map((d) => d.name);
|
|
301
|
-
if (subs.length === 1) return subs[0];
|
|
302
|
-
} catch { /* 目录还不存在(首次启动) */ }
|
|
303
|
-
|
|
304
|
-
return '';
|
|
305
|
-
}
|
|
261
|
+
function resolveProfileName() {
|
|
262
|
+
// ── 按维护手册 §「profile 定位的正解:回写环境变量,别改推断逻辑」 ──
|
|
263
|
+
// 宿主的 profileContext 是权威答案,src/index.ts 的 apply() 已经把它回写到:
|
|
264
|
+
// process.env.DSH_PROFILE / DSH_PROFILE_DIR
|
|
265
|
+
// globalThis.__dshProfileName / __dshProfileContext
|
|
266
|
+
// 这里只要**读**它,别自己猜路径。
|
|
267
|
+
|
|
268
|
+
// ① 环境变量(apply 阶段回写,最直接)
|
|
269
|
+
const env = String(process.env.DSH_PROFILE || '').trim();
|
|
270
|
+
if (env) return env;
|
|
271
|
+
|
|
272
|
+
// ② apply() 落下的全局变量 —— **这是关键补的一层**:
|
|
273
|
+
// settings-host.js 有可能在 apply() 之前就被加载(模块顶层求值),
|
|
274
|
+
// 那时环境变量还没回写;但真正用到 profile 名是在请求处理阶段(惰性化后),
|
|
275
|
+
// 那时 __dshProfileName 早就有了。
|
|
276
|
+
try {
|
|
277
|
+
const g = globalThis.__dshProfileName;
|
|
278
|
+
if (typeof g === 'string' && g.trim()) return g.trim();
|
|
279
|
+
} catch { /* 下一层 */ }
|
|
280
|
+
|
|
281
|
+
// ③ 老宿主没有 profileContext 服务 → 只能从 PROFILE_ROOT 目录名反推
|
|
282
|
+
try {
|
|
283
|
+
if (basename(dirname(PROFILE_ROOT)) === 'profiles') {
|
|
284
|
+
const n = basename(PROFILE_ROOT);
|
|
285
|
+
if (n && n !== 'profiles') return n;
|
|
286
|
+
}
|
|
287
|
+
} catch { /* 放弃 */ }
|
|
288
|
+
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
306
291
|
/**
|
|
307
292
|
* 当前 profile 对应的存档子目录名。
|
|
308
293
|
*
|
|
@@ -312,36 +297,12 @@ function resolveProfileName() {
|
|
|
312
297
|
* (真实存档在 qqbot-settings/desktop/xxx.json)⇒ 凭据读不到 ⇒ nsBot() null。
|
|
313
298
|
* 改成每次调用时现算(开销是几次字符串/目录读,API 请求级,可忽略)。
|
|
314
299
|
*/
|
|
315
|
-
function nsProfileDir(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
// 一台机器上 qqbot-settings/ 可能同时有 web/ 和 desktop/,
|
|
322
|
-
// 这时**不能猜**(猜错 = 读到别人的凭据),要用事实来判断。
|
|
323
|
-
try {
|
|
324
|
-
const subs = readdirSync(OWN_SETTINGS_DIR, { withFileTypes: true })
|
|
325
|
-
.filter((d) => d.isDirectory() && d.name !== '_default')
|
|
326
|
-
.map((d) => d.name);
|
|
327
|
-
|
|
328
|
-
// ① 只有一个 profile 目录 → 就是它
|
|
329
|
-
if (subs.length === 1) return subs[0];
|
|
330
|
-
|
|
331
|
-
// ② 多个目录 → 看哪个目录里**真的存着这个 ns 的配置**
|
|
332
|
-
// (凭据就在 <profile>/<ns>.json,谁有谁就是当前 profile)
|
|
333
|
-
if (ns) {
|
|
334
|
-
const f = safeNsOf(ns) + '.json';
|
|
335
|
-
const hits = subs.filter((name) => {
|
|
336
|
-
try { return existsSync(join(OWN_SETTINGS_DIR, name, f)); } catch { return false; }
|
|
337
|
-
});
|
|
338
|
-
if (hits.length === 1) return hits[0];
|
|
339
|
-
// 两个 profile 都配过同一个 ns → 不猜,走 _default。
|
|
340
|
-
// 这种「共用一个 settingsNs」的情况本来就会被 writer.json 的 NS_CONFLICT 拦住。
|
|
341
|
-
}
|
|
342
|
-
} catch { /* 目录还不存在(首次启动) */ }
|
|
343
|
-
|
|
344
|
-
return '_default';
|
|
300
|
+
function nsProfileDir() {
|
|
301
|
+
// 惰性求值(issue #20 的核心修复):原来这是个模块顶层 const,
|
|
302
|
+
// 算的时候 apply() 还没回写 DSH_PROFILE → 永远落 _default。
|
|
303
|
+
const n = String(resolveProfileName()).trim().replace(/[^A-Za-z0-9_-]/g, '_');
|
|
304
|
+
if (n) return n;
|
|
305
|
+
return '_default';
|
|
345
306
|
}
|
|
346
307
|
function safeNsOf(ns) {
|
|
347
308
|
return String(ns || NS).replace(/[^A-Za-z0-9_-]/g, '_') || 'im-qqbot';
|