Skip to content

fix(desktop): recursive copyFileSync fallback for native-binary dirs on Windows - #76211

Closed
ruguanvip-beep wants to merge 1 commit into
NousResearch:mainfrom
ruguanvip-beep:fix/windows-conpty-eio-copy
Closed

ruguanvip-beep wants to merge 1 commit into
NousResearch:mainfrom
ruguanvip-beep:fix/windows-conpty-eio-copy

Conversation

@ruguanvip-beep

Copy link
Copy Markdown

问题

Windows 桌面构建的 stage-native-deps.mjs 用 fs.cpSync 复制含原生二进制的目录。当源目录含被占用的 DLL/EXE(典型是 node-pty 的 conpty/,含 OpenConsole.exe + conpty.dll)时,cpSync 报 EIO / "Access is denied",导致桌面重建中断,hermes update 自更新无法完成(在 bootstrap-installer.log 中反复出现 2025-07-09 -> 07-24)。

根因

Node 的 cpSync 在 Windows 上复制含被占用原生二进制的目录时触发该缺陷。更新器执行 git reset --hard origin/main 后重建,又跑到同一段会失败的拷贝 -> 自更新死循环。

修复

新增 copyDirRecursive(srcDir, destDir):用 copyFileSync 逐文件递归拷贝(单文件拷贝不走 cpSync 的缺陷代码路径),并在原生依赖 staging 处用它替代 cpSync。

影响范围

  • 仅改 apps/desktop/scripts/stage-native-deps.mjs(构建期 staging 脚本,不影响运行时)。
  • macOS/Linux 走既有逻辑不变;Windows 仅在 conpty 等含原生二进制目录下走新递归拷贝。

测试计划

  • Windows:hermes update / 完整桌面重建在 conpty 路径不再报 EIO,能完成。
  • macOS/Linux:桌面重建仍成功。

背景

这原本是本地补丁——hermes update 会 git reset --hard origin/main,每次自更新后都得手动重打,且正是它让工作树 dirty、与桌面「启动强制自更新」形成死结,导致桌面端启动死循环。上游合入后:本地补丁不再需要;hermes update 重建不再 EIO -> 自更新收敛 -> 桌面端恢复正常。

🤖 Generated with WorkBuddy

…on Windows

Node fs.cpSync fails with EIO / "Access is denied" on Windows when copying
directories that contain in-use native binaries (notably node-pty's conpty/
with OpenConsole.exe + conpty.dll). This breaks the desktop rebuild on
Windows (reproduced repeatedly 2025-07-09 -> 07-24).

Add copyDirRecursive() which walks the tree with copyFileSync, bypassing the
cpSync code path that triggers the defect, and use it for native dependency
staging so the Windows desktop rebuild completes.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for targeting the active native-dependency staging path. Current main still recursively calls cpSync for build/Release directories (apps/desktop/scripts/stage-native-deps.mjs:97-100) and for the conpty prebuild directory (apps/desktop/scripts/stage-native-deps.mjs:262-265).

Problems

  • The new helper is used unconditionally in the PR at apps/desktop/scripts/stage-native-deps.mjs:124, so macOS/Linux build/Release copies also change despite the stated Windows-only scope.
  • No regression test accompanies the change. The current staging fixture at apps/desktop/scripts/stage-native-deps.test.mjs:34-47 does not create a conpty directory or nested payload.

Suggested changes

  • Keep cpSync for non-Windows hosts and scope the workaround to process.platform === 'win32'.
  • Add a fixture with nested conpty files and assert stageNodePtyInto stages them.

Automated hermes-sweeper review.

@@ -96,7 +124,7 @@ function copyBuildRelease(srcDir, destDir) {
mkdirSync(destDir, { recursive: true })

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This replacement runs for every host platform whenever copyBuildRelease is used, not only Windows. Please retain cpSync on macOS/Linux and scope the workaround to Windows so the stated platform-limited behavior is preserved.

@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) platform/windows Native Windows-specific behavior or breakage area/install-update Installer, updater, packaging, wheels, doctor P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 1, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Duplicate of #61832: both repair the same Windows recursive-cpSync conpty paths in stage-native-deps.mjs with a manual directory walk. #61832 is the earlier open patch and includes focused regression coverage.

@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Aug 1, 2026
teknium1 added a commit that referenced this pull request Sep 17, 2026
…k .bak wipe

The salvaged commits drop the cpSync/rmSync imports, but stageGetWindowsInto
landed on main after the PR was opened and still called both, so the module
threw ReferenceError on every platform (7 vitest failures on the cherry-picked
head). Route its six sites through copyFileSync/removeDirSync so get-windows
staging survives the same non-ASCII profile paths as node-pty.

preserveRollbackBackup had the same rmSync no-op as cleanStaleAppOutDir: a
surviving .bak makes renameSync fail, so the previous working build gets wiped
instead of kept as rollback material. Same existsSync -> removeDirSync fallback.

Earlier fixes for the same crash: #60480 (@liuhao1024), #61832 (@danilofalcao),
#76211, #103458, #109273, #111590.
Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
Co-authored-by: danilofalcao <danilofalcao@users.noreply.github.com>
@teknium1

Copy link
Copy Markdown
Collaborator

Fixed on main by #113919 (4146fcbd7a7), which lands @kosazoltan's #66687 — the same approach as here (libuv-backed copyFileSync walks instead of fs.cpSync/fs.rmSync in apps/desktop/scripts/stage-native-deps.mjs), widened to rmSync, before-pack.mjs and the get-windows staging. Thanks for the report and fix; closing as superseded.

@teknium1 teknium1 closed this Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/desktop Electron desktop app (apps/desktop/*) duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists platform/windows Native Windows-specific behavior or breakage sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants