Suppress stray Windows Terminal window behind the standalone app#110
Merged
Conversation
Move the bundled Node.js version pin out of standalone/.node-version and into the root package.json's devEngines.runtime block. pnpm 11 honors this field natively (onFail: "download") so scripts run with the pinned Node locally, eliminating the "wrong node on PATH" failure mode for contributors. build.rs reads the same field to verify the bundled binary, generate-deps.js reads it for the supply-chain disclosure, and release.yml extracts it via jq to drive actions/setup-node — all from one file. Also drops the brittle cargo:rerun-if-changed on the resolved node source path in build.rs: when a node version manager's symlink went dangling (e.g. vfox's cache/current pointing at a deleted version), cargo would keep replaying the stale error instead of re-running. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First `pnpm install` after adding devEngines.runtime materialized the runtime in pnpm-lock.yaml as `node@runtime:22.22.3` with sha256-pinned tarballs for every platform variant (aix/darwin/linux/win × cpu archs + musl). This makes the bundled Node provably reproducible from the lockfile alone, on top of build.rs's runtime check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DETACHED_PROCESS on the sidecar spawn was not actually preventing the visible window — checking the live process tree shows Windows Terminal (class CASCADIA_HOSTING_WINDOW_CLASS) hosting the sidecar with the title set to the node.exe path. On Win11 with WT as the default terminal, the DefTerm COM handoff fires for any console-subsystem (IMAGE_SUBSYSTEM_ WINDOWS_CUI = 3) child regardless of CREATE_NO_WINDOW / DETACHED_PROCESS: those flags suppress the conhost window but not the WT activation. Flip the bundled node.exe's PE Optional Header Subsystem field to 2 (IMAGE_SUBSYSTEM_WINDOWS_GUI) during the build script's post-copy step. A GUI-subsystem binary is never auto-given a console, so the DefTerm path has nothing to hand off and WT is never activated. Node.js itself reads its stdio handles from STARTUPINFO and works identically under either subsystem; smoke-tested with `node -e 'console.log(...)'` after patching. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fs::copy on Windows preserves FILE_ATTRIBUTE_READONLY from the source. When the runtime comes from pnpm's content-addressable store (devEngines onFail: "download"), the source node.exe is read-only, so the destination inherits that and fs::write fails with "access denied" — breaking `pnpm tauri build` on a local Windows workstation. Clear the attribute defensively before writing the patched buffer back. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…json `jq -r` on a missing field exits 0 with the literal output "null", which silently propagated to actions/setup-node as `node-version: null` and produced a confusing "Unable to find Node version" error a step later. Validate the MAJOR.MINOR.PATCH shape at the extraction step so a missing or malformed pin fails CI at the right place with a clear message. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The build patches one byte of the bundled node.exe on Windows (IMAGE_SUBSYSTEM_WINDOWS_CUI → IMAGE_SUBSYSTEM_WINDOWS_GUI) to suppress Windows Terminal's default-terminal handoff. The version-equality claim still holds — `node --version` runs before the patch — but the bundled binary is no longer byte-identical to the upstream archive, so spell that out for a supply-chain reader. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dormouse-bot
approved these changes
May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
node.exeto PE subsystem 2 (Windows GUI) so the sidecar no longer triggers Windows Terminal's default-terminal handoff — that handoff was spawning a stray WT window titled with the node.exe path behind the Dormouse window on Win11.package.json'sdevEngines.runtime.versionas the single source of truth: pnpm honors it locally (onFail: "download"), CI extracts it foractions/setup-node,build.rsverifies the bundled binary against it, and the supply-chain page reads the same field.node.exebefore patching — pnpm's content-addressable store leaves source binaries read-only on Windows, whichfs::copypropagates to the destination and would otherwise breakpnpm tauri buildlocally.devEngines.runtime.versionfails the right step with a clear message instead of becomingnode-version: nulldownstream.node.exediffers from the upstream archive at exactly the documented 2-byte field, version-equality is unchanged.Test plan
pnpm tauri buildon Windows — confirm no stray Windows Terminal window appears behind the standalone app at launchbuild-standalonejob goes green across Linux / macOS / Windowsnode website/scripts/generate-deps.jsfrom a clean checkout produces no diffsecurity-audit-failureissue opened against the new SECURITY.md wording)🤖 Generated with Claude Code