fix(compat): Windows 兼容性修复 + 跨平台兼容分析

终端在 Windows 上起不来 (打包规则漏解包)
- 根因: build.asarUnpack 写的是 "**/node_modules/@lydell/node-pty-*/*", 只匹配一层,
  于是 prebuilds/<plat>/ 下的文件没被解包, 留在 app.asar 里
- Windows 上这些必须是磁盘上的真实文件: conpty.dll (OS loader 加载)、
  OpenConsole.exe (CreateProcess)、以及 node-pty 用 worker_threads.Worker 起的
  conoutSocketWorker.js —— node-pty 本身就写了
  __dirname.replace('node_modules.asar', 'node_modules.asar.unpacked') 来适配
- Linux 上看不出来: 只需要一个 pty.node, Electron 的 asar 层能 dlopen 归档里的 .node
- 修复: 规则递归化为 "**/node_modules/@lydell/node-pty-*/**/*"
- 验证: 重新打包后 pty.node 已落到 app.asar.unpacked, 安装版真实 spawn 成功

Windows 保留设备名 / 尾部点空格导致落盘写错
- 新增 src/main/safe-name.ts 的 safeFileName()
- Win32 把 CON/PRN/AUX/NUL/COM1-9/LPT1-9 (带扩展名也算) 当设备, open() 打开的不是文件;
  还会悄悄吃掉文件名结尾的点和空格, 导致 existsSync 判断和实际落盘对不上
- 两处落盘都接上: file-server.ts 的 targetPath()、drive.ts 的 downloadDriveFile()
  (后者名字来自对端共享目录, 属不可信输入)
- 策略是"最小必要": 非法字符全平台都清, 保留名和尾点空格只在 win32 上改写,
  避免动到 Linux 上合法的文件名

其他
- 终端 cwd: Windows 优先用 USERPROFILE (装了 Git Bash 时 HOME 可能是 POSIX 路径, Win32 下不存在)
- USB 面板空列表提示按平台给, 不再一律说"Linux 用户需要在 dialout 组"

分析文档与自测
- 新增 docs/windows-compat.md: 各原生模块的 N-API 情况、已有 win32 分支的位置、
  已知限制 (ConPTY 需 Win10 1809+、防火墙首次弹窗、USB 需 WinUSB 驱动等)、
  以及一份 Windows 真机验证清单
- 自测新增 S1-S8 组: 保留名改写、尾部点空格、非法字符、跨平台不过度清洗、
  超长截断、默认 shell/cwd、asarUnpack 规则回归护栏、上传落盘 + 路径穿越
- 全部 38 条用例通过
This commit is contained in:
2026-10-20 16:59:26 +08:00
parent a79086e4e8
commit f158377742
10 changed files with 390 additions and 8 deletions
+8
View File
@@ -94,3 +94,11 @@ Ubuntu 装完"没图标"是个坑,有两个独立原因:
2. **`StartupWMClass` 要跟窗口真实的 WM_CLASS 一致。** electron-builder 默认填 `productName`(`LocalNetMsg`),但 Electron 实际设的是**可执行文件名**(`local-net-msg`)—— 对不上,任务栏就找不到对应启动器,显示成通用图标。用 `xprop -id <wid> WM_CLASS` 确认真实值,然后在 `build.linux.desktop.StartupWMClass` 里写它。
Windows / macOS 仍用单张 `resources/icon.png`(那里不按尺寸分目录)。
## Windows 兼容性
完整的分析、已修问题和待验证清单见 `docs/windows-compat.md`。最容易踩的两个:
1. **`build.asarUnpack` 里的原生模块规则必须递归(`**/*`)。** node-pty 1.2 是"主包 + 平台包"拆包架构,平台包 `@lydell/node-pty-<platform>-<arch>` 里除了 `.node` 还有 `conpty.dll` / `OpenConsole.exe`,而 node-pty 的 ConPTY worker 用 `worker_threads.Worker` 起脚本——都必须是磁盘上的真实文件。规则写成 `.../node-pty-*/*`(单层)会把 `prebuilds/<plat>/` 下的东西留在 asar 里,Windows 终端直接起不来(Linux 上看不出来,因为只需要一个 `.node`)。自测 S7 守着这条规则。
2. **Windows 保留设备名**:`CON` `PRN` `AUX` `NUL` `COM1-9` `LPT1-9`(带扩展名也算)不能直接当文件名——对它们 `open()` 打开的是设备不是文件。落盘前统一走 `src/main/safe-name.ts` 的 `safeFileName()`(按**本机**平台决定要不要改写,Linux 上 `CON` 是合法文件名,不该动)。