Skip to content

feat: Windows 完整移植(server.js 后端兼容 + 终端/截图直通车 + 深度验证)#33

Closed
cookiesheep wants to merge 8 commits into
alchaincyf:masterfrom
cookiesheep:windows-port
Closed

feat: Windows 完整移植(server.js 后端兼容 + 终端/截图直通车 + 深度验证)#33
cookiesheep wants to merge 8 commits into
alchaincyf:masterfrom
cookiesheep:windows-port

Conversation

@cookiesheep

Copy link
Copy Markdown

完整把 FanBox 移植到 Windows 了,从 master 出发独立做的,mac 那边的逻辑都用平台判断保留着,没动。

看到已经有 #10#24 两个 Windows 的 PR,这俩主要覆盖了桌面壳(标题栏、剪贴板、截图目录)和打包。不过它们都没动 server.js,所以装上虽然能开,但后端那几样还是坏的——图片/视频缩略图走的 sips/qlmanage、磁盘占用的 du、AI 整理找 claude/codex 用的 /bin/zsh command -v,这些 Windows 上都没有,会静默失败。这个 PR 把后端也一起补了,整个工具在 Windows 上是真的能用,不只是「能打开」。

补的几块:

  • 缩略图:sips 换 PowerShell 的 System.Drawing,视频/PDF 换 ffmpeg 抽帧(PDF 没原生工具就走图标兜底)
  • HEIC:ffmpeg → System.Drawing → 415 三级兜底,能不能解看系统装没装 HEVC 解码器
  • 磁盘占用:du 换纯 Node 递归(du 口径,算全,含 node_modules)
  • 找 agentcommand -vwhere.exe
  • 终端当前目录:lsof 那套 Windows 没有,拿 spawn 起始目录兜着(conpty 拿不到 shell 实时 cwd)
  • 复制文件到剪贴板:PowerShell 的 SetFileDropList(被别的程序占着剪贴板会重试一次)
  • 前端:一堆 split('/') 改成同时认反斜杠,⌘→Ctrl、废纸篓→回收站(写了个跟 i18n 一样的 observer),相对路径判断补了盘符
  • 截图直通车:监听 Pictures\Screenshots 和 OneDrive 下,Win+PrintScreen 的截图照样能浮出直通卡

过程中还踩到一个 master 里的 bug:/fs/ 路由的 slice(3) 在 mac 上凑巧能用,在 Windows 上把 /fs/D:/code/x 切成 /D:/code/x 当相对路径,导致 md 和 html 预览里的本地图片全 404。改成 slice(4) 加按平台补回开头斜杠。

测试我没只测接口——用 Playwright 驱动真 app 跑了一遍,15 项全过:平台识别、9 个 IPC 桥接、文件列表、缩略图实际解码(4/4 不裂图)、终端 spawn 到回显的全链路、Monaco、Milkdown、零渲染报错,截图直通车也单独测了。打包也试了,npm run dist:win 出 NSIS 安装包,装上能跑。

还有几个没搞定的,老实说一下:

  • HEIC 靠系统 HEVC 解码器,没装就显示图标(本机 ffmpeg 也没 heif demuxer,救不了)
  • 合盖不休眠、微信 ClawBot 太 mac 了,跳过没动
  • Windows 版没签名,SmartScreen 第一次会弹(这个得有证书才干净)
  • 终端里打印的 Windows 路径现在能点了(之前只能点 / 形式的)

node-pty 我发现 1.x 是 N-API 预编译的,Electron 直接加载、不用 rebuild,README 里那条 npm run rebuild 在 Windows 上反而会失败(但不影响),顺手在文档里说明了。

改动大概 +600 行,跨 server.js / electron/main.js / 前端 / 打包配置。要是 #10#24 你更想合并,我这边后端那部分(server.js)也可以单独拆出来给它们补,都行。

后端 7 处平台缺口补齐,网页模式在 Windows 完整可用:
- du 磁盘占用:win32 退化纯 Node 递归求和(du 仅 Git Bash 可用,打包后系统 PATH 无)
- 图片缩略图:win32 走 PowerShell System.Drawing(落盘式 _thumb.ps1 + -File argv,规避 quoting)
- 视频缩略图:win32 走 ffmpeg 抽帧
- HEIC 转码:win32 ffmpeg(heif)→System.Drawing→415 三级兜底
- findAgentBin/detectBin:win32 用 where.exe(claude/codex/gh 探测)
- pruneThumbs 跳过 _thumb.ps1

实测通过:roots/du/jpg·png·中文空格·视频缩略图/回收站删除/organize-launch。
保留所有 mac 原行为,零依赖原则不变。审计见 docs/Windows移植-平台审计.md。
前端逻辑型 bug 全修,mac 行为零回归:
- 加跨平台路径工具 pathSplit/pathBase/isAbsPath/joinPath
- 所有硬编码 split('/') 改 pathSplit(fsUrl、md 图片兜底、终端进程名、
  变更过滤、du 下钻、follow、外部编辑器重载路径)
- 相对路径判断改 isAbsPath(C:\ 不再被误判为相对路径)
- state 默认 platform/sep 按 navigator UA 嗅探(首屏 win32 即对)
- shell 白名单两处都补 pwsh/powershell.exe/cmd.exe
- CHANGE_IGNORE 补 AppData/$Recycle.Bin 等 Windows 噪声
- 截图「收进素材」子目录拼接改 joinPath

新增 platform-l10n.js:照搬 i18n MutationObserver 模式,win32 下集中
改写 ⌘→Ctrl(+)/废纸篓→回收站/访达→资源管理器/Finder→Explorer,
单点覆盖所有静态+动态文案,与 i18n 互补不冲突。

修 server.js /fs/ 路由真实 Windows bug:p.slice(3) 在 mac 保留开头 /
是巧合,Windows 上 /fs/D:/code/ → /D:/code/ 被当相对路径拼到 HOME → 404。
主端口+预览端口两处改为 slice(4) + POSIX 补回开头 /。

实测通过:fsUrl 分段编码 /fs/ 取 D: 盘文件·中文空格·html 预览全 200。
桌面壳 4 处缺口补齐,核心功能(内嵌终端)在 Windows 验证可用:
- 窗口:titleBarStyle hiddenInset + vibrancy 收敛为 mac 专属,Windows/Linux 用原生标题栏
- pty:cwd:Windows 无 lsof,存 spawn 起始目录作兜底(点标签定位到初始项目目录)
- clip:file:Windows 走 PowerShell STA + Clipboard.SetFileDropList(路径经环境变量传,资源管理器可粘贴)
- findFfmpeg:Windows 走 where.exe(本机 Scoop ffmpeg 可被找到,录像导出 mp4/gif 可用)

新增 experiments/test-pty-win.js:在 Electron 运行时里实测 node-pty spawn。

关键验证:node-pty 1.1.0 是 N-API 预编译,Electron 33 无需 npm run rebuild
(VS Build Tools 缺失也不影响)。实测 cmd.exe spawn + 命令回显正常。
渲染层 --enable-logging 零 JS 报错。clip:file PowerShell 单测通过。
code review 抓到的 3 个 HIGH + 2 个 MEDIUM:
- dirSize 不再套 IGNORE_DIRS:du 口径要算全(含 node_modules/.git),否则 Win 上
  node_modules 报成 0 与 mac 不一致(实测:现在正确报 769.9MB)
- dirSize 返回 {size,truncated},diskUsage 60s deadline + 截断标记,前端可提示「估算中」
- clip:file 加 PS try/catch(剪贴板被占用退出码 2)+ main 重试一次(250ms)
- joinPath 空值守卫(a/b 任一为空直接返回另一段,避免拼出 UNC 根)
- terminal scrollback 的 C:\ 路径检测:regex 调优复杂且无法可视化验证,记为已知限制
  (openTermPath 路径解析已修,/ 形式的 agent 路径仍可点)

打包准备:
- electron 钉死 33.4.11(electron-builder 要求精确版本下载平台二进制)
- build 配置加 electronVersion 兜底
- node-pty 是 N-API 预编译,npmRebuild:false 下打包无需编译
- package.json: build.win(nsis x64)+ nsis 配置 + electronVersion 兜底
- 脚本 dist:win / dist:win:portable(保留 mac 的 dist 不动)
- 图标用 build/icon-1024.png,electron-builder 自动转 ico

打包验证(本机 Win11):
- 产出 dist/FanBox-Setup-1.13.0-x64.exe(107MB NSIS 安装包)+ win-unpacked/FanBox.exe
- node-pty N-API 预编译(pty.node/conpty.node)正确打进 app.asar.unpacked/.../prebuilds/win32-x64/
- 启动打包后的 exe:后端 4567 返回 win32、PowerShell 缩略图 200 正常

文档:docs/Windows移植-实现与运行说明.md(改动全记录 + 运行/打包命令 + 已知限制 + 验证矩阵)。
README 加 Windows 徽章。
逐项验证 Windows 版:平台识别/9 IPC 桥接/文件列表/盘符面包屑/
platform-l10n(⌘→Ctrl)/缩略图解码/终端spawn+回显全链路/Monaco/Milkdown/
零渲染报错。实测 15/15 通过。截图存证 experiments/verify-win-files.png。
push 前最后一轮,补两个之前列的限制:

1. 终端 scrollback 里 C:\code\app.js 现在能点了
   - app.js 加盘符路径专用检测 reWin(lookbehind 挡 http:// 的 p: 误伤)
   - 修 server.js termVerify 给绝对路径乱拼 cwd 的 bug(C:\ 被拼成 cwd/C:\)
   - regex 单测 + term-verify 接口单测都过

2. 截图直通车支持 Windows(原 mac 专属整块跳过)
   - startShotWatch 重构为多目录跨平台:盯 ~/Pictures/Screenshots
     (Win+PrintScreen) + ~/OneDrive/Pictures/Screenshots (OneDrive 接管)
   - 实测:丢 png 进去渲染层收到 shot:new(含空格+括号文件名)

15/15 深度验证无回归。已知限制只剩:HEIC 靠系统 HEVC 解码器
(ffmpeg 无 heif demuxer 救不了)、合盖/微信 ClawBot mac 专属、Win 版未签名。
文档同步更新。新增 experiments/verify-shot-win.js。
冲突解决(全在 electron/main.js):
- termStartCwd(我的) + termTails(master微信用) 两个 Map 都保留
- pty:cwd 取 master 新抽出的 termCwdByPid helper,把我 Windows 的起始目录
  兜底注入它的 async handler(onExit/kill 两个 Map 都删)
package.json:master 的 version 2.3.0 + 我的 electron 钉死/build.win/nsis/dist:win 全保留。
合并后 15/15 深度验证仍通过。
@alchaincyf

Copy link
Copy Markdown
Owner

谢谢这份完整的移植和验证,质量看得出很用心🙏 不过官方仓库我决定维持 mac-only:我没有 Windows 机器,没法对 Windows 版的体验和安全负责,合进主仓库就成了官方背书。所以这个 PR 我先关掉,但这不是否定你的工作,恰恰相反,我已经把你的移植版列进 README 的安装区,让 Windows 用户能找到你这版。也欢迎你继续维护社区版,辛苦了!

@alchaincyf alchaincyf closed this Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants