dsh-napcat-keeper 2.1.2 → 2.5.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,94 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.5.0 — 统一用 DSH 自带的 Node 运行时
4
+ - **为什么改**:以前凡是「要跑一段 JS」的地方,都默认那台机器上装过 node,或者干脆蹭 NapCat / QQ 的私有环境。换台机器、换个装法就哑火 —— 不通用。
5
+ - **新增 `resolveNode()`**,顺序固定、结果缓存 60 秒:
6
+ 1. 手填的 `nodePath`(设置页「Node 运行时」);
7
+ 2. **DSH 自带**:`<DSH NEXT>\resources\runtime\<arch>\primary-runtime\dependencies\node\bin\node.exe`(DSH_NODE_PATH / DSH_NODE 环境变量也认;插件本身就跑在 node 里时直接用 `process.execPath`);
8
+ 3. 系统 `PATH`(`where node`);
9
+ 4. 常见安装目录(`Program Files\nodejs`、`%LOCALAPPDATA%\Programs\nodejs`);
10
+ 5. NapCat 目录里自带的 `node.exe` 兜底。
11
+ - **补上「Shell 型」NapCat**:目录**顶层**有 `napcat.mjs` 的(官方 NapCat.Shell 包那种),现在会用上面这份 node 生成 `~/Dsh/napcat-autogen-node.bat` 去跑 `node napcat.mjs`;以前只认 `NapCatWinBootMain.exe`,遇到 node 型安装直接报「找不到启动脚本」。注入版 `versions\*\resources\app\napcat\napcat.mjs` **不会**被当成入口(那份是等 QQ 注入的,普通 node 跑必崩)。
12
+ - **注入型(OneKey)不变**:NapCat 跑在 `QQ.exe --type=utility --utility-sub-type=node.mojom.NodeService` 里,磁盘上没有 node.exe,外部 node 替不了它 —— 这条链路插件只负责调 bootmain。
13
+ - **可见性**:设置页新增「Node 运行时」一栏 + 「测一下 node」按钮;状态条显示「哪份 node / 什么版本 / 路径」;`napcat_status` 返回值里多了 `node` 字段;启动日志 `boot:` 那行带上 node 来源。
14
+ - **发版前隐私清洗**:`lib/client.js` 的「接口没响应」提示原来硬编码了本机家目录,改成 `~/.dsh/napcat-keeper.log`;`scripts/selftest-scan.mjs` / `scripts/smoke-client.mjs` 里写死的本机绝对路径改成按脚本自身位置定位;`smoke-client` 的 `launchAccount` fixture 换成合成占位 `1000000000`。现在换台机器 clone 下来,自测脚本照样跑得起来。
15
+ - **新增 `scripts/check-privacy.mjs`(0 依赖)**:扫包内文本文件,拦家目录真实用户名、私人邮箱(含 QQ 邮箱)、凭据形状(`ghp_` / `npm_` / `sk-` / `AKIA` / 实体 Bearer)、DSH 会话 id、fixture 里的真号。`npm run check` 现在是「清单体检 + 隐私体检」两道,命中即 exit 1;行内写 `check-privacy:ignore` 可豁免。
16
+ - 版本 2.5.0。
17
+
18
+ ## 2.4.1 — 清单被 PowerShell 往返成乱码 + 断引号,同一个位置第二次炸
19
+ - **事故**:DSH 加载插件时报 `Bad control character in string literal in JSON at position 899 (line 36 column 23)`。这次不是 BOM,而是 `package.json` 被「按 ANSI 读 → 按 UTF-8 写」往返了一遍:
20
+ - `description` / `author` 变成双层乱码(`鐔欑殑澶ц偉楸`);
21
+ - `author` 末尾「鱼」的 `E9 B1 BC` 在 GBK 里凑不成整字,最后一个字节把**收尾的引号**一起吃了 → 字符串没闭合,后面的换行就成了字符串里的裸控制字符 —— 报错里的第 36 行第 23 列就是那个换行。
22
+ - **后果**:DSH 读清单时就失败,插件整段不加载,看门狗跟着消失(NapCat 那头还活着,端口 3000 通,只是一断开就没人再拉它)。
23
+ - **修复**:`package.json` 按 UTF-8(无 BOM)重写、中文如实写回;顺手把版本对齐到 2.4.1 —— 之前清单写着 2.4.0、`lib/index.js` 里还留着 2.3.2。
24
+ - **体检脚本升级**(`scripts/check-manifest.mjs`,仍是 0 依赖):BOM 之外再查 ① 每个文本文件是不是合法 UTF-8;② 有没有出现双重编码乱码;③ JSON 解析失败时给出错行/错列并用 `^` 指到那个字符;④ `package.json` 的 `version` 与 `lib/index.js` 的 `export const version` 同不同步。
25
+ - **规矩补一条**:改本插件任何文本文件只用 `write`/`edit` 工具,或 `[IO.File]::WriteAllText(路径, 文本, (New-Object System.Text.UTF8Encoding($false)))`;别用 `Get-Content` 再 `Set-Content -Encoding utf8` 往返(既写 BOM,又把中文变乱码)。
26
+ - 版本 2.4.1。
27
+
28
+ ## 2.4.0 — 默认改回「跟着 DSH 生灭」:这插件的用途就是开机接上 QQ
29
+ - **默认值翻了**:`taskName: ''`、`autoCreateTask: false`。默认走 `cscript` 直接拉,QQ 链挂在 DSH 下面——DSH 起来才有 QQ,DSH 关掉 QQ 跟着走,下次开 DSH 重拉一条。这正是插件的定位:**DSH 启动后把人接到 QQ 上**,不是替 QQ 续命。
30
+ - **计划任务降级成可选项**:想要「DSH 关了 QQ 还活着」这种反过来的用法,才自己填任务名 + 勾自动创建;那时才用 `schtasks /run`,父进程变任务计划服务。
31
+ - 本机同步处理:配置里的 `taskName` / `autoCreateTask` 清空,删掉遗留的 `NapCat-Keeper-Launch` 计划任务,并把已经在跑的那条链重拉一次,让它真的挂在 DSH 下面。
32
+ - 文档改写:README 那节从「计划任务为什么重要」换成「拉起方式:默认跟着 DSH 生灭」,常见问题里「QQ 会不会跟着 DSH 掉」按新默认如实回答。
33
+ - 版本 2.4.0。
34
+
35
+ ## 2.3.2 — 清单带 BOM 会把整个插件打死,加一条体检命令
36
+ - **事故**:`package.json` 被写成 UTF-8 **带 BOM**(`EF BB BF`)。DSH 加载插件时要对它做一次干净的 `JSON.parse`,BOM 会让它当场抛 `Unexpected token '', "{ "name"... is not valid JSON` —— 插件代码一行都没跑到,看门狗整个不生效,NapCat 也就不再自启。`lib/index.js` 同时被带 BOM 覆盖(这个 Node 自己会吞掉,不致命)。
37
+ - **根因**:本机 `pwsh` 实际是 **PowerShell 5.1**,`Set-Content` / `Out-File -Encoding utf8` 默认**写 BOM**。用它重写 json/js 就等于埋雷。
38
+ - **规矩**:改本插件任何 json/js,只用 DSH 的 `write`/`edit` 工具,或 `[System.IO.File]::WriteAllText(path, text, (New-Object System.Text.UTF8Encoding($false)))`;别用 `Set-Content`。
39
+ - **新增 `scripts/check-manifest.mjs`(0 依赖)**:查 package.json 有无 BOM / 能否 `JSON.parse`、entry 与 `dsh.bundle.patch` 指向的文件在不在、全目录扫 BOM(`.ps1`/`.txt` 豁免——那两个反而需要 BOM 才不乱码)。红→绿都自测过:带 BOM 时 exit 1 并指名文件,`--fix` 只抹 BOM 不动内容,修完 exit 0。
40
+ - 命令:`node scripts/check-manifest.mjs` / `... --fix`;`package.json` 里也挂了 `scripts`(`check` / `check:fix` / `smoke:client` / `selftest:scan` / `selftest:setup`)。
41
+ - 版本 2.3.2。
42
+
43
+ ## 2.3.1 — 扫到的目录要分得出真假:真 Shell 排在前面
44
+ - **扫描结果会标「像不像真 Shell」。** 判据是目录里有没有 `versions/`、`QQ.exe`、`napcat.mjs` 这三样里的任意一样(有就是真 Shell)。只有 `NapCatWinBootMain.exe` + 一个 .bat 的不算——那多半是 OneKey 装完留下的壳模板。
45
+ - **为什么需要这个**:OneKey 安装器会先解一份壳模板到 `NapCat/OneKey/bootmain`(01:02),再把真正的版本装成 `NapCat.52230.Shell`(01:04)。旧判据只看「有 NapCatWinBootMain.exe 或名字带 napcat」+「有 .bat」,两个都命中,于是一次扫描列出两条,看起来像装了两份。其实一份安装,`bootmain` 只是壳、没有 QQ 本体。
46
+ - **真 Shell 排前面**:`/state` 返回的 `scan.found` 现在按 `shell` 降序再按路径升序,磁盘遍历顺序不再影响谁排第一。
47
+ - **按钮分两种**:真 Shell 标绿「✓ 像真 Shell:versions/ · QQ.exe」、按钮「用这个」;存疑的标黄「⚠ 没看到 versions/QQ.exe/napcat.mjs —— 多半是 OneKey 装完留下的壳模板…」、按钮「仍要用这个」(没禁用,精简布局确实可能没有这三样)。
48
+ - 新增 `scripts/selftest-scan.mjs`(15 项):临时树造壳模板 / 真 Shell / 精简版 / 普通目录,真跑 `scanOneDrive` 验证判定与排序;`scripts/smoke-client.mjs` 加到 29 项(两种标记、两种按钮文案)。
49
+ - 版本 2.3.1。
50
+
51
+ ## 2.3.0 — 提权交接:要管理员的事写成脚本,让你自己按那一下
52
+
53
+ - **新增「需要你点一下的脚本」一组。** 插件自己不去抢管理员:勾上要做的事,点「生成脚本并打开文件夹」,它把每一步写进 `~/.dsh/napcat-keeper-setup/`,你双击 `apply-admin.cmd` —— 只有含管理员步骤的那一批才会弹 UAC,那个「是」是你自己按的;不含的批次双击直接跑完。跑完回面板点「读结果」,逐条列出成没成、为什么没成。
54
+ - **4 件可勾的事**:自动启动脚本(`napcat.quick.auto.bat`)、中间层(把密码塞环境变量,仍只在勾了「记住密码」时才有内容)、计划任务(用户级)、防火墙放行(`New-NetFirewallRule`,只有这条真的需要管理员)。
55
+ - **一次生成、可撤回。** 同目录还有 `undo-admin.cmd`:跑一遍把脚本建的东西全撤掉(启动脚本、中间层、计划任务),撤完告诉你撤了几项。`plan.json` 记录这次要做哪几步,`result.json` 记录上次结果,`run.log` 是脚本自己写的流水账。
56
+ - **不需要管理员时绝不弹 UAC。** `apply.ps1` 先数一遍 `admin: true` 的步骤,一条都没有就直接原地跑;有才 `Start-Process -Verb RunAs` 自我提权一次。
57
+ - **密码不进命令行。** 中间层的密码以 base64 落在 `plan.json`(跟 `napcat-keeper-env.bat` 同一份秘密,README 里写了别外传),脚本用 `[IO.File]::WriteAllBytes` 写盘,不拼进任何命令行;`/state` 也绝不把 base64 回给前端。
58
+ - **编码的坑都堵了**:`apply.ps1` 与 `README.txt` 存 UTF-8 **带 BOM**(PS 5.1 没 BOM 会按 ANSI 解、中文全乱),`.cmd` 入口保持纯 ASCII(cmd 对 UTF-8 不友好)。
59
+ - 新增 `scripts/selftest-setup.mjs`:临时目录里造假 NapCat,真跑一遍 apply / 幂等二跑 / undo,45 项断言;`scripts/smoke-client.mjs` 扩到 27 项(含提权区勾选框、禁用态、结果摘要)。
60
+ - `/state` 多回 `setup`(目录、4 条 need 的 ready/why/needAdmin、上次 plan 摘要、上次结果),新增 `action=makeSetup` / `openSetup` / `setupResult`。
61
+ - 版本 2.3.0。
62
+
63
+ ## 2.2.2 — 目录只认人选:删掉「自动探测」
64
+
65
+ - **删:`自动探测` 按钮与整套猜目录逻辑。** 设置页 `shellDir` 旁边不再有「自动探测」;后端 `resolveConfig` 也不再把空值悄悄填成 `detectShellDir()` 的结果。留空就老老实实是空——不再出现「我没选,它自己填了个错目录,然后一直拉不起来」。
66
+ - **盘符枚举换实现,有盘就一定列出来。** 原先按 `A:`–`Z:` 逐个 `statSync('X:\\')`,遇上 BitLocker 锁着的卷、无介质光驱、某些虚拟盘会 stat 失败,于是「明明有盘却不显示」。现在先用 `[System.IO.DriveInfo]::GetDrives()` 拿系统真实盘符(正则收 `X:`),一条都没读到才回退旧的 A–Z 试探;本机实测 186ms 拿到 `C: D: E:`。
67
+ - **新增「重新读盘」按钮**:作废缓存后立刻重问系统(`{do:'drives'}`),插了移动盘 / 映射了网络盘不用重启 DSH。前端只刷新盘符列表,**不动你正在编辑的草稿**。
68
+ - 按钮下方写明「读到 N 块盘:C:、D:、E:」,一眼能看出系统到底给了几块。
69
+ - `detectShellDir()` 函数与 `__internals` 导出保留(给测试/老脚本调用),但主流程已无任何调用点;`uiState` 里的 `detect` 字段删除。
70
+ - 版本 2.2.2。
71
+
72
+ ## 2.2.1 — 设置页不再把插件全家拖垮
73
+
74
+ - **修:点开设置页就白屏、整个设置面板卡死。** `lib/client.js` 里的 `settings.section` 钩子还是老签名 `(ctx, id, options)`,新版 DSH 实际传进来的是**数组**,`hooks[hooks.length] = …` 当场抛 `Cannot add property 7, object is not extensible`。这个异常发生在设置面板的渲染期,会把**整个设置面板**(不只是本插件)一起干掉。改成新签名 `(ctx)`,自己从数组里摘 `{ section }`,旧形状仍留兜底。
75
+ - **修:`/state` 每次都新起一个 PowerShell(约 300ms)。** NapCat 在线时是 4 个 QQ 进程 + 1 个 launcher,配置页轮询一次就要现查一次进程,等于 PowerShell 风暴(DSH 是单进程同时伺候 GUI 和所有插件,实测被拖到 11% CPU、界面 2.5 秒一帧)。现在加了三层缓冲:热路径 300 秒内复用上一次的进程快照、`?light=1` 完全不扫描只读缓存、同一个 `since` 的并发请求合并成一次。实测首次 16ms、light 1.2ms、连发 5 次共 1ms。
76
+ - **修:工具注册消失**(日志里一直写着 `tools: unavailable, watchdog-only mode`)。DSH NEXT 里已经没有 `@deepseek-ai/dsh-tools` 这个包,`defineTool` 永远是 undefined。改成不依赖它:直接给 `tools.register()` 一个 plain object(`{ name, description, parameters, output: { schema }, execute }`),注册前再走一遍 `normalizeToolDefinition` 兜底。
77
+ - **修:热重载会漏定时器和进程缓存。** `state` / `procCache` 改挂到 `globalThis[Symbol.for('dsh.napcat-keeper.state')]`,DSH 改一次插件文件就重新 apply 一次,新模块实例拿到的是同一份 shared 状态;`armTimer()` 里先 `clearInterval` 旧的,45 秒巡检不会再越堆越多。
78
+ - 版本 2.2.1。`napcat_status` / `napcat_restart` / `napcat_dedupe` 恢复正常注册(活体日志:`tools: napcat_status / napcat_restart / napcat_dedupe registered (v2.2.1)`)。
79
+
80
+ ## 2.2.0 — 分盘扫描:换个盘也能找到 NapCat
81
+
82
+ - 自动探测不再只盯家目录和几个固定文件夹:常见位置扩展到每个盘的 `NapCat` / `Tools\NapCat` / `Soft\NapCat` / `Program Files\NapCat` / `ProgramData\NapCat`。
83
+ - 设置页新增「分盘扫描」一组:本机有几块盘就列几个按钮(`扫 C:` / `扫 D:` …),另有一个「全部盘(慢)」。点了就在后台扫,界面上边扫边报「已看多少目录 / 用时多少秒 / 命中几个」,可随时「停止」。
84
+ - 扫描规则:深度 7 层、跳过 `Windows` / `回收站` / `System Volume Information` / `node_modules` / `Temp` 这类目录、单盘 90 秒预算(全部盘时每盘 45 秒);命中一个像 NapCat Shell 的目录(名字带 napcat,或含 `NapCatWinBootMain.exe`,并且有 `.bat`)就不再往它下面钻。
85
+ - 扫到的结果逐条列出路径 + 挑出来的启动脚本 + 是否含 `NapCatWinBootMain.exe`,每条带「用这个」按钮:点一下就把 `shellDir` 存进配置并重新挑启动脚本,不用手打路径。
86
+ - 上限保护:单盘最多看 25 万个目录,到点/到量会明确告诉你「结果可能不全」,不会闷着扫一小时。
87
+ - `/state` 多返回 `scan`(进度:running / drive / visited / found / elapsedMs / limitHit / cancelled)与 `drives`(本机盘符),设置页靠它轮询。
88
+ ## 2.1.2
89
+
90
+ - 与 2.1.1 内容一致;npm 的边发布边排队(202 Accepted)有几分钟延迟,重发一次把 latest 顶上去。
91
+
3
92
  ## 2.1.1
4
93
 
5
94
  - 修:风险清单里的 **明文** 在设置页会原样显示成星号,改成「明文」。
package/README.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  | 情况 | 看门狗怎么做 |
21
21
  | --- | --- |
22
- | OneBot 端口不通、也没有 NapCat 进程 | 拉起来(优先走计划任务,其次 cscript) |
22
+ | OneBot 端口不通、也没有 NapCat 进程 | 拉起来(默认 cscript;只有填了计划任务名才走任务) |
23
23
  | 刚拉起、端口还没通 | 给宽限期(默认 150s),期间不重复拉 |
24
24
  | 拉到一半卡在扫码 | 记一笔 `need-scan`;超过 `scanTimeoutSec` 就杀掉重来,重试 `maxScanRetries` 次后放弃并写日志 |
25
25
  | 有两条 QQ 进程链(客户端互踢的根源) | 按启动时间聚类判重,只杀晚出现的那几条,保留正在服务的那条 |
@@ -52,25 +52,76 @@ dsh plugin --profile <profile> add C:\path\to\dsh-napcat-keeper
52
52
 
53
53
  | 填什么 | 说明 |
54
54
  | --- | --- |
55
- | **NapCat Shell 目录** | 点旁边的「自动探测」多半就填好了;也可手填,例如 `C:/Users/你/NapCat/OneKey/NapCat.<版本>.Shell` |
55
+ | **NapCat Shell 目录** | 用下面的「分盘扫描」找:本机有几块盘就点哪块,扫到后点「用这个」直接填进去;也能手填,例如 `C:/Users/你/NapCat/OneKey/NapCat.<版本>.Shell` |
56
56
  | **要快登的 QQ 号** | 填了它,插件优先挑「写死了这个号」的启动脚本;连脚本都没有时,自动生成一个直接调 `NapCatWinBootMain.exe <号>` 的脚本 |
57
57
  | **OneBot HTTP 端口** | 跟 NapCat 网络配置里的 httpServers 一致(默认 3000) |
58
58
 
59
59
  点 **保存设置** → 存到 `~/.dsh/napcat-keeper-config.json`,立刻热生效。
60
60
  回「状态」看:在线会显示昵称和 QQ 号;离线就点「拉起 NapCat」。
61
61
 
62
+ ## 分盘扫描:装在哪都能找到
63
+
64
+ 从 2.2.2 起插件**不再自己猜** NapCat 装在哪(`自动探测` 已删):`shellDir` 留空就是空,不会悄悄填一个可能填错的目录。
65
+ 设置页第一组是 **分盘扫描**,目录由你来选:
66
+
67
+ - 本机有几块盘就列几个按钮(盘符取自系统 `DriveInfo`,光驱、移动盘、上锁的卷都会列),点哪个扫哪个;
68
+ 有「全部盘(慢)」;扫的时候可以点「停止」;插了新盘点「重新读盘」,不用重启 DSH。
69
+ - 扫描会跳过 `Windows`、回收站、`System Volume Information`、`node_modules`、`Temp` 这类目录,
70
+ 深度上限 7 层,单盘最多看 25 万个目录、最多 90 秒(全部盘时每盘 45 秒)。
71
+ - 命中判据:目录名带 `napcat`,或目录里有 `NapCatWinBootMain.exe`,且带有 `.bat` 启动脚本。
72
+ 命中后不再往它下面钻(QQ 目录里几千个文件,钻进去只会变慢)。
73
+ - **命中之后再分真假**:目录里只要有 `versions/`、`QQ.exe`、`napcat.mjs` 里的任意一样,就是**真 Shell**
74
+ (标绿 `✓ 像真 Shell:versions/ · QQ.exe`,按钮「用这个」);三样都没有的标黄
75
+ `⚠ 没看到 versions/QQ.exe/napcat.mjs`,按钮是「仍要用这个」(没禁用——精简版布局确实可能没有这三样,你更清楚)。
76
+ 真 Shell 一律排在前面,不受磁盘遍历顺序影响。
77
+ - **为什么会有两个**:OneKey 安装器会先把壳模板解到 `NapCat\OneKey\bootmain`(只有 `NapCatWinBootMain.exe`
78
+ + `napcat.quick.bat`,**没有 QQ 本体**),再把真正的版本装成 `NapCat\<版本>.Shell`(有 `versions/` 和 `QQ.exe`)。
79
+ 一次安装留下两个目录,只有后者能拉起来。
80
+ - 每命中一条就列一行:路径、挑出来的启动脚本、是否含 `NapCatWinBootMain.exe`、真假判定,右边按钮一键填入。
81
+ - 到时间/到数量上限会明确写「结果可能不全」,不会闷头扫一小时。
82
+
62
83
  ## 页面上的按钮
63
84
 
64
85
  | 按钮 | 作用 |
65
86
  | --- | --- |
66
- | 自动探测 | 扫常见位置找 NapCat Shell 目录,找到就填进输入框(尚未保存) |
67
- | 重新探测 | 立刻跑一轮 tick(探端口 + 探进程) |
87
+ | 扫 C: / 扫 D: … | 分盘深扫(深度 7 层,跳过系统目录,单盘 90 秒),边扫边报进度,命中就列出来 |
88
+ | 重新读盘 | 立刻重新问系统要盘符(插了移动盘 / 映射了网络盘之后点,不用重启 DSH) |
89
+ | 全部盘(慢) | 把本机每块盘都扫一遍(每盘 45 秒预算),装在冷门位置时用这个 |
90
+ | 用这个 | 在扫描结果里点:直接把这个目录存成 `shellDir`,并重新挑启动脚本 |
91
+ | 重新探活 | 立刻跑一轮 tick(探端口 + 探进程);跟「找 NapCat 目录」无关 |
68
92
  | 拉起 NapCat | 手动下达拉起指令 |
69
93
  | 杀掉重拉 | 干净地杀掉整条链再拉一条(杀不干净就不拉,避免互踢) |
70
94
  | 去重复链 | 只杀掉晚出现的那几条链,保留最早那条 |
71
95
  | 建计划任务 | 现在就把计划任务建好(用户级,不需要管理员) |
72
96
  | 收起黑框 | 把已经在跑的控制台窗口藏起来(不用重启 QQ) |
73
97
  | 全部杀掉 | 只杀,不拉 |
98
+ | 生成脚本并打开文件夹 | 把勾好的「需要你点一下的脚本」写成 `apply.ps1` + 双击入口,同时弹资源管理器选中它 |
99
+ | 打开文件夹 | 只打开那个目录(脚本已经生成过时用,不用重新生成一遍) |
100
+ | 读结果 | 读回 `result.json`:上次跑成没成、哪一步失败、用没用上管理员 |
101
+
102
+ ## 要动系统的部分:交给你点一下的脚本
103
+
104
+ DSH 自己是普通权限。插件要碰「装系统的位置」(往防火墙加规则、往别人的目录里写启动脚本……)时,
105
+ 它不去偷偷提权,也不要你「以管理员身份重启 DSH」,而是把要做的事**写成一份脚本交给你**:
106
+
107
+ 1. 设置页「需要你点一下的脚本」里勾上要做的事 → 点 **生成脚本并打开文件夹**;
108
+ 2. 资源管理器会跳出来并选中 `apply-admin.cmd`,双击它;
109
+ 3. 里面若含管理员步骤,会弹一次 UAC —— **那个「是」就是你自己按的确认键**;一条都不含就直接跑完,不弹任何窗;
110
+ 4. 回面板点 **读结果**,逐条显示成没成、为什么没成;
111
+ 5. 想全撤,双击同目录的 `undo-admin.cmd`。
112
+
113
+ 可勾的四件事:
114
+
115
+ | 事 | 会做什么 | 要不要管理员 |
116
+ | --- | --- | --- |
117
+ | 自动启动脚本 | 在 `shellDir` 里补一个 `napcat.quick.auto.bat`(写死账号和 `NapCatWinBootMain.exe` 路径) | 看那个目录你能不能写,不能写才需要 |
118
+ | 中间层 | 写 `napcat-keeper-env.bat`:把密码塞进环境变量再 call 启动脚本 | 不需要 |
119
+ | 计划任务 | 用 `schtasks` 建用户级任务(要不要隐藏黑框跟着设置走) | 不需要 |
120
+ | 防火墙放行 | `New-NetFirewallRule` 放行 OneBot 端口入站 | 需要 |
121
+
122
+ `plan.json` 里存着这次要做的每一步(要写的文件内容以 base64 存 —— **开了「记住密码」时这里面就是那份密码**,
123
+ 别把这个目录发出去、别丢进同步盘);`result.json` 是上次跑的结果,`run.log` 是脚本自己记的流水账。
124
+ 不用管理员就能做完的批次,`apply.ps1` 一条 `admin: true` 都数不到,于是原地跑完、绝不弹 UAC。
74
125
 
75
126
  ## 桌面上那个黑框
76
127
 
@@ -97,13 +148,34 @@ NapCat 的**快速登录令牌会失效**(实测几小时到几天),失效
97
148
  密码不写成命令行参数(`NapCatWinBootMain.exe <号> <密码>` 那样会进进程列表和 Windows 事件日志),
98
149
  而是走环境变量 `NAPCAT_QUICK_PASSWORD` / `NAPCAT_QUICK_PASSWORD_MD5`,且只有本机 `127.0.0.1:3000` 回连时才注入。
99
150
 
100
- ## 计划任务为什么重要
151
+ ## 拉起方式:默认跟着 DSH 生灭
152
+
153
+ 这个插件的用途就一句话:**DSH 起来以后,把 QQ 接上**。所以默认用 `cscript` 直接拉,
154
+ QQ 那条进程链挂在本 DSH 实例下面——DSH 开着它就在,DSH 关掉它就跟着走,下次开 DSH 再拉一条新的。
155
+
156
+ 「刚重启 DSH,QQ 就掉了」不是毛病,是这个默认行为:新实例会自己重新拉起,扫不上就自动密码登录。
157
+
158
+ 要是反过来想要「DSH 关了 QQ 还活着」,才去填「计划任务名」(默认 `NapCat-Keeper-Launch`)+ 勾「自动创建计划任务」,
159
+ 那时插件改用 `schtasks /run` 拉,父进程是任务计划服务,DSH 重启牵连不到它——代价是 QQ 的寿命从此跟 DSH 脱钩。
160
+
161
+ ## 用哪份 Node:默认借 DSH 自带的
162
+
163
+ 插件要跑一段 JS 时才需要 Node,取的顺序是(找到第一个能用的就停):
164
+
165
+ 1. 设置页里手填的 `nodePath`;
166
+ 2. **DSH 自带**:`<DSH NEXT>\resources\runtime\<arch>\primary-runtime\dependencies\node\bin\node.exe`(`DSH_NODE_PATH` / `DSH_NODE` 环境变量也认);
167
+ 3. 系统 `PATH` 里的 `node`;
168
+ 4. 常见安装目录(`Program Files\nodejs`、`%LOCALAPPDATA%\Programs\nodejs`);
169
+ 5. NapCat 目录里附带的 `node.exe` 兜底。
101
170
 
102
- `napcat.bat` / `NapCatWinBootMain.exe` 拉起的进程链会跟着「拉起它的进程」一起死。
103
- 要是由 DSH 自己 `spawn`,DSH 一重启 QQ 就跟着没——这就是「刚才还好好的,重启完就不通」最常见的原因。
171
+ 所以正常情况下**不用装 Node、也不用管版本**,跟着 DSH 走就行。状态条里会直接写着用的是哪一份、什么版本;设置页有「测一下 node」按钮可以当场验一次。
104
172
 
105
- 所以默认由计划任务(`NapCat-Keeper-Launch`)来拉,父进程是任务计划服务,DSH 重启牵连不到。
106
- 任务不存在时插件自动创建,也可以点「建计划任务」;不想用就把「自动创建计划任务」和「计划任务名」清掉,退回 cscript(能用,但 DSH 退出会带走 QQ)。
173
+ 两种 NapCat 装法的区别:
174
+
175
+ - **Shell 型**(官方 `NapCat.Shell` 包、目录**顶层**有 `napcat.mjs`):插件会用上面这份 Node 生成 `~/Dsh/napcat-autogen-node.bat` 去跑 `node napcat.mjs` —— 这是 Node 运行时真正派上用场的地方;
176
+ - **注入型**(OneKey 那种,本机就是):NapCat 跑在 `QQ.exe` 自己的 Node service 里(`--type=utility --utility-sub-type=node.mojom.NodeService`),磁盘上根本没有 `node.exe`,外面的 Node 也替不了它。这条链路插件只负责调 `NapCatWinBootMain.exe`,跟 Node 无关。
177
+
178
+ > 顺带一提:`versions\*\resources\app\napcat\napcat.mjs` 那份**不会**被当成入口——它是等 QQ 注入用的,拿普通 Node 直接跑必崩。
107
179
 
108
180
  ## 给 agent 用的三个工具
109
181
 
@@ -118,16 +190,17 @@ NapCat 的**快速登录令牌会失效**(实测几小时到几天),失效
118
190
  | 键 | 默认 | 说明 |
119
191
  | --- | --- | --- |
120
192
  | `enabled` | `true` | 总开关;关掉只保留状态观察,不自动拉也不自动杀 |
121
- | `shellDir` | 自动探测 | NapCat Shell 目录(启动脚本所在目录) |
122
- | `launcherScript` | 自动探测 | 启动脚本名或绝对路径 |
193
+ | `shellDir` | 空(只认人选) | NapCat Shell 目录(启动脚本所在目录);留空就表示还没选,插件不会替你猜 |
194
+ | `launcherScript` | 空(由 shellDir 找) | 启动脚本名或绝对路径 |
123
195
  | `launchAccount` | 空 | 想快登的 QQ 号 |
124
196
  | `launchArgs` | 空 | 追加给启动脚本的参数 |
197
+ | `nodePath` | 空(自动) | 指定 `node.exe`;留空按「DSH 自带 → 系统 PATH → 常见安装目录 → NapCat 目录」找,见上一节 |
125
198
  | `rememberPassword` | `false` | 记住 QQ 密码、令牌失效时自动密码登录(**明文落盘,详见上节**) |
126
199
  | `quickPassword` | 空 | QQ 密码;只在保存时写入,接口不回显、日志不打印 |
127
200
  | `onebotPort` | `3000` | OneBot 11 HTTP 端口 |
128
201
  | `accessToken` | 空 | OneBot access token |
129
- | `taskName` | `NapCat-Keeper-Launch` | 负责拉起的计划任务名,留空 = 不用 |
130
- | `autoCreateTask` | `true` | 任务不存在时自动创建 |
202
+ | `taskName` | 空(= 用 cscript,QQ 跟着 DSH 生灭) | 想脱离 DSH 才填计划任务名 |
203
+ | `autoCreateTask` | `false` | 填了 `taskName` 且任务不存在时自动创建 |
131
204
  | `probeIntervalSec` | `45` | 复查间隔 |
132
205
  | `launchGraceSec` | `150` | 拉起后的宽限期 |
133
206
  | `scanTimeoutSec` | `300` | 扫码等待上限 |
@@ -146,15 +219,40 @@ NapCat 的**快速登录令牌会失效**(实测几小时到几天),失效
146
219
  ~/.dsh/napcat-keeper-env.bat 只在「记住密码」开启时生成:把密码塞进环境变量给启动脚本
147
220
  ~/.dsh/napcat-keeper-state.json 每轮 tick 的状态快照
148
221
  ~/.dsh/napcat-qr.png 最近一张二维码副本(扫码时会更新)
222
+ ~/.dsh/napcat-keeper-setup/ 提权交接目录:plan.json / apply.ps1 / apply-admin.cmd
223
+ / undo-admin.cmd / result.json / run.log / README.txt
149
224
  ```
150
225
 
226
+ ## 出事了先跑体检:`npm run check`
227
+
228
+ 插件整个没加载、DSH 日志里连一个字都不提它、QQ 掉线后再没人拉起来 —— 十有八九是 `package.json` 被动过:BOM、双重编码乱码、或者 JSON 语法坏掉。清单读不动,DSH 连插件代码都不会 import,看门狗自然一起消失。
229
+
230
+ `npm run check` 是两道体检,一次跑完:
231
+
232
+ ```bash
233
+ npm run check # 清单体检 + 隐私体检
234
+ npm run check:manifest # 只查清单
235
+ npm run check:manifest -- --fix # 顺手抹掉 BOM(只动 BOM,不动内容)
236
+ npm run check:privacy # 只查隐私(发版前必跑)
237
+ ```
238
+
239
+ **清单体检**查这几样:清单能不能 `JSON.parse`、有没有 BOM、是不是合法 UTF-8、有没有出现「鐔欑殑澶ц偉楸」这种双重编码乱码、入口文件在不在、清单版本和 `lib/index.js` 里的 `export const version` 同不同步。JSON 坏掉时直接告诉你第几行第几列,并用 `^` 指到那个字符上(位置 899 那种报错不用再数换行)。
240
+
241
+ **隐私体检**管包里别夹带本机的东西:家目录绝对路径里的真实用户名、私人邮箱(含 QQ 邮箱)、凭据形状(`ghp_` / `npm_` / `sk-` / `AKIA`、实体 Bearer)、DSH 会话 id、fixture 里像真号的账号。命中就 exit 1,指到 `文件:行`;那一行确实要举例说明什么算泄漏的,写 `check-privacy:ignore` 豁免。
242
+
243
+ 另外三个自测:`npm run smoke:client`(把 `lib/client.js` 塞进假 React 渲染一遍)、`npm run selftest:scan`(造假树验扫盘判定)、`npm run selftest:setup`(临时目录里真跑一遍 apply / 重跑 / undo)。都不依赖本机路径,clone 下来就能跑。
244
+
245
+ > **改这个插件的文件的规矩**:别用 `Get-Content` 读、`Set-Content -Encoding utf8` 写 —— PowerShell 5.1 会按 ANSI 读、再按 UTF-8 写,一趟往返中文全变乱码,BOM 还照写。用编辑器另存为「UTF-8 无 BOM」,或者
246
+ > `[IO.File]::WriteAllText($path, $text, (New-Object System.Text.UTF8Encoding($false)))`。
247
+
151
248
  ## 常见问题
152
249
 
153
250
  **「离线」但进程明明还在?**
154
251
  端口没通。看 `napcat-keeper-launch.log`多半是卡在扫码,或者 QQ 弹了验证窗。
155
252
 
156
- **刚重启 DSH,QQ 就掉了?**
157
- 说明这条链还是 DSH 拉起来的。填上「计划任务名」、点「建计划任务」,以后交给任务计划服务。
253
+ **刚关掉 DSH,QQ 就跟着退了?**
254
+ 正常,默认就是这样:QQ 挂在 DSH 下面,DSH 一走它就走。下次开 DSH 会重新拉一条。
255
+ 想反过来(DSH 关了 QQ 还活着)才去填「计划任务名」+ 勾「自动创建计划任务」。
158
256
 
159
257
  **两个 QQ 客户端互相踢?**
160
258
  去重会兜住,但根因通常是有人手动又点了一次 `napcat.bat`。点「去重复链」立刻收敛。
@@ -172,6 +270,10 @@ NapCat 的**快速登录令牌会失效**(实测几小时到几天),失效
172
270
  **能在 Linux / macOS 上用吗?**
173
271
  看门狗本身是 node 实现,但「进程路径探测 / 计划任务 / cscript」这几处是为 Windows 写的;其它平台目前只保证「探端口 + 判活」。
174
272
 
273
+ **设置页点开一片空白,连别的插件设置也不见了?**
274
+ 2.2.1 之前是 `settings.section` 钩子签名对不上新版 DSH(抛 `Cannot add property N, object is not extensible`),异常冒到设置面板层,整个面板一起白。升级后重开 DSH 即可。
275
+ 另外设置页会轮询 `/state`,2.2.1 起热路径有 300 秒进程快照缓存,不再每次都新起 PowerShell;如果你自己写脚本调这个接口,加 `?light=1` 只读缓存、不扫描进程。
276
+
175
277
  ## License
176
278
 
177
279
  MIT