qq-bot-roost 1.0.1 → 1.0.3
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 +3 -1
- package/package.json +1 -1
- package/src/updater.js +51 -16
- package/web/index.html +1 -1
- package/web/style.css +17 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="零依赖">
|
|
11
11
|
<img src="https://img.shields.io/badge/tests-771%20passed-brightgreen" alt="测试 771 项">
|
|
12
12
|
<img src="https://img.shields.io/badge/plugins-JS%20%7C%20Python%20%7C%20Go%20%7C%20any-blue" alt="多语言插件">
|
|
13
|
-
<img src="https://img.shields.io/badge/version-1.0.
|
|
13
|
+
<img src="https://img.shields.io/badge/version-1.0.3-blueviolet" alt="版本 1.0.3">
|
|
14
14
|
<img src="https://img.shields.io/badge/license-Non--Commercial-red" alt="禁止商用">
|
|
15
15
|
<a href="https://github.com/tdcq9594/qq-bot-roost/actions"><img src="https://img.shields.io/github/actions/workflow/status/tdcq9594/qq-bot-roost/ci.yml?branch=master" alt="CI"></a>
|
|
16
16
|
|
|
@@ -80,6 +80,8 @@
|
|
|
80
80
|
- **消息带四个字段**:`uin` / `groupUin` / `userAliases` / `groupAliases`。插件用 `ctx.identity` 只读视图查,绑定表由框架维护
|
|
81
81
|
- 配套升级:`dsh-roost` 1.0.0(别名合并读取 + 账号迁移页)、`ai-chat` 4.4.1(透传字段)。**三个一起升**,少一个号码就传不到 DSH
|
|
82
82
|
|
|
83
|
+
> **绑定完全自愿、非必需**:QQ 官方接口不提供 QQ号 / 群号,本项目不会以任何方式获取、推算或抓取;绑定表里的号码只来自用户本人主动提供,或由管理员依据本人提供的号码代为登记(应事先取得本人同意)。不绑定不影响机器人的任何功能,未绑定时行为与绑定能力上线前完全一致;绑定信息仅保存在本机 `identity.json`,可在面板「身份」页随时解绑或停用,不上传、不共享,也不用于「认人认群、找回旧记忆」以外的用途。请勿把提供号码设为加群、发言或使用机器人的条件,也不要替他人报号。
|
|
84
|
+
|
|
83
85
|
**连接与容错**
|
|
84
86
|
|
|
85
87
|
- **两种收事件方式**:WebSocket 长连接(本地默认)或 **Webhook 回调**(公网 / Serverless / 容器)
|
package/package.json
CHANGED
package/src/updater.js
CHANGED
|
@@ -337,6 +337,54 @@ function buildResult(cur, tag, extra = {}) {
|
|
|
337
337
|
|
|
338
338
|
/* ---------------- 下载与解包 ---------------- */
|
|
339
339
|
|
|
340
|
+
/**
|
|
341
|
+
* 从 Gitee 拉一份**指定版本**的代码。
|
|
342
|
+
*
|
|
343
|
+
* 为什么必须锁 tag:GitHub 那条路下的是 `archive/refs/tags/v<版本>.tar.gz`,
|
|
344
|
+
* 内容被版本号钉死;Gitee 这条路以前固定拉默认分支,两条路一个锁版本、
|
|
345
|
+
* 一个跟着分支漂移。结果就是「发版后又往 master 推了个提交」时,
|
|
346
|
+
* 先更新的用户算出的指纹对得上、后更新的用户全部失败。
|
|
347
|
+
*
|
|
348
|
+
* v1.0.1 就是这么挂的(2026-11-04):tag d76e646 的指纹是 ed2ebca6,
|
|
349
|
+
* 而 22:24 又推了一个只改 docs 的 7c35106 到 master,指纹变成 822f67f6,
|
|
350
|
+
* 版本号却没动 —— 从那一刻起所有 Gitee 源的用户都无法更新。
|
|
351
|
+
*
|
|
352
|
+
* 回退只在「这个 ref 根本不存在」时发生(列清单 404 / 树是空的):
|
|
353
|
+
* 作者漏推 tag 时仍然得能装上,能不能过指纹那一关由 `applyUpdate` 判。
|
|
354
|
+
* 文件级失败(451 内容审查之类)换 ref 也一样,直接抛。
|
|
355
|
+
*
|
|
356
|
+
* @param {object} rel checkUpdate 的返回值(要 `tag`)
|
|
357
|
+
* @param {string} destDir 目标目录,失败重试前会被清空
|
|
358
|
+
*/
|
|
359
|
+
async function fetchTagFromGitee(rel, destDir) {
|
|
360
|
+
const token = currentMirror().giteeToken;
|
|
361
|
+
const tag = String(rel?.tag ?? '').trim();
|
|
362
|
+
|
|
363
|
+
const candidates = [];
|
|
364
|
+
if (tag) candidates.push(tag);
|
|
365
|
+
const branch = rel?.giteeRef || (await detectGiteeRef(REPO));
|
|
366
|
+
if (!candidates.includes(branch)) candidates.push(branch);
|
|
367
|
+
|
|
368
|
+
let lastErr = null;
|
|
369
|
+
for (const ref of candidates) {
|
|
370
|
+
try {
|
|
371
|
+
await fetchGiteeTree({ repo: REPO, ref, destDir, only: GITEE_ONLY, token });
|
|
372
|
+
if (tag && ref !== tag) {
|
|
373
|
+
log.warn(`Gitee 上找不到 ${tag},已退回分支 ${ref}(内容可能与指纹不一致)`);
|
|
374
|
+
}
|
|
375
|
+
return;
|
|
376
|
+
} catch (e) {
|
|
377
|
+
lastErr = e;
|
|
378
|
+
if (!/文件清单失败|没有文件/.test(e.message)) throw e;
|
|
379
|
+
log.warn(`Gitee ${ref} 拉不到:${e.message}`);
|
|
380
|
+
// 半截文件不能留着,下一个 ref 要在一片空地上拉
|
|
381
|
+
await fs.rm(destDir, { recursive: true, force: true }).catch(() => {});
|
|
382
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
throw lastErr;
|
|
386
|
+
}
|
|
387
|
+
|
|
340
388
|
/**
|
|
341
389
|
* 下载并解包到临时目录。
|
|
342
390
|
*
|
|
@@ -349,20 +397,13 @@ function buildResult(cur, tag, extra = {}) {
|
|
|
349
397
|
* auto 模式下 GitHub 失败会自动切 Gitee——用户选 auto 时这就是承诺。
|
|
350
398
|
*
|
|
351
399
|
* @param {string} tmpDir
|
|
352
|
-
* @param {object} rel checkUpdate 的返回值(带 tarball / giteeRef)
|
|
400
|
+
* @param {object} rel checkUpdate 的返回值(带 tarball / tag / giteeRef)
|
|
353
401
|
*/
|
|
354
402
|
async function downloadTo(tmpDir, rel) {
|
|
355
403
|
const id = currentMirror().id;
|
|
356
|
-
const token = currentMirror().giteeToken;
|
|
357
404
|
|
|
358
405
|
if (id === 'gitee') {
|
|
359
|
-
await
|
|
360
|
-
repo: REPO,
|
|
361
|
-
ref: rel.giteeRef ?? (await detectGiteeRef(REPO)),
|
|
362
|
-
destDir: tmpDir,
|
|
363
|
-
only: GITEE_ONLY,
|
|
364
|
-
token,
|
|
365
|
-
});
|
|
406
|
+
await fetchTagFromGitee(rel, tmpDir);
|
|
366
407
|
return tmpDir;
|
|
367
408
|
}
|
|
368
409
|
|
|
@@ -381,13 +422,7 @@ async function downloadTo(tmpDir, rel) {
|
|
|
381
422
|
log.warn(`GitHub 下载失败(${e.message}),改用 Gitee 镜像`);
|
|
382
423
|
// 清掉可能写了一半的残留,再整树重拉
|
|
383
424
|
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});
|
|
384
|
-
await
|
|
385
|
-
repo: REPO,
|
|
386
|
-
ref: await detectGiteeRef(REPO),
|
|
387
|
-
destDir: tmpDir,
|
|
388
|
-
only: GITEE_ONLY,
|
|
389
|
-
token,
|
|
390
|
-
});
|
|
425
|
+
await fetchTagFromGitee(rel, tmpDir);
|
|
391
426
|
}
|
|
392
427
|
return tmpDir;
|
|
393
428
|
}
|
package/web/index.html
CHANGED
|
@@ -1103,8 +1103,8 @@
|
|
|
1103
1103
|
<div id="ppDash" class="pp-body" hidden></div>
|
|
1104
1104
|
<div id="ppGroups" class="pp-body" hidden></div>
|
|
1105
1105
|
<div class="modal-actions">
|
|
1106
|
+
<button class="btn danger act-left" id="ppReset" title="把所有配置项恢复成插件声明的默认值">恢复默认</button>
|
|
1106
1107
|
<button class="btn" id="ppClose">关闭</button>
|
|
1107
|
-
<button class="btn danger" id="ppReset" title="把所有配置项恢复成插件声明的默认值">恢复默认</button>
|
|
1108
1108
|
<button class="btn primary" id="ppSave">保存配置</button>
|
|
1109
1109
|
</div>
|
|
1110
1110
|
</div>
|
package/web/style.css
CHANGED
|
@@ -259,6 +259,15 @@ body {
|
|
|
259
259
|
animation: modal-fade .12s ease-out;
|
|
260
260
|
}
|
|
261
261
|
.modal-mask[hidden] { display: none; }
|
|
262
|
+
/*
|
|
263
|
+
* 通用确认弹窗(#modalMask)永远压在最上面。
|
|
264
|
+
*
|
|
265
|
+
* 四个 .modal-mask 都是 z-index:100,同层级时「DOM 里靠后的盖住靠前的」,
|
|
266
|
+
* 而 #modalMask 写在 index.html 最前面、插件设置面板在后面 ——
|
|
267
|
+
* 于是「保存配置」弹的「已保存」整个被插件设置面板挡住,看起来像点了没反应。
|
|
268
|
+
* 确认弹窗本身是「盖在别的弹窗上回答一个问题」的层,层级必须高人一等。
|
|
269
|
+
*/
|
|
270
|
+
#modalMask { z-index: 200; }
|
|
262
271
|
.modal {
|
|
263
272
|
width: min(420px, calc(100vw - 32px));
|
|
264
273
|
background: var(--panel);
|
|
@@ -279,6 +288,14 @@ body {
|
|
|
279
288
|
.modal-actions {
|
|
280
289
|
display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px;
|
|
281
290
|
}
|
|
291
|
+
/*
|
|
292
|
+
* 破坏性操作推到最左,右边只留「关闭 / 保存配置」。
|
|
293
|
+
*
|
|
294
|
+
* 原先三个按钮挤成一排右对齐,灰色的「关闭」在最左边、离蓝色的「保存配置」
|
|
295
|
+
* 隔着一个红色的「恢复默认」,用户看完配置直接就去点主按钮,找不到退出的地方。
|
|
296
|
+
* 把「恢复默认」单独甩到左边后,两个正常出口挨在一起,也顺手拉开了误点的距离。
|
|
297
|
+
*/
|
|
298
|
+
.modal-actions > .act-left { margin-right: auto; }
|
|
282
299
|
@keyframes modal-fade { from { opacity: 0 } to { opacity: 1 } }
|
|
283
300
|
@keyframes modal-pop { from { opacity: 0; transform: translateY(6px) scale(.98) } to { opacity: 1; transform: none } }
|
|
284
301
|
|