install(windows): store bin-link metadata in :bunx NTFS stream instead of .bunx sidecar
What
On Windows, node_modules/.bin currently holds two files per bin: <name>.exe (the embedded bun_shim_impl stub) and <name>.bunx (the per-bin metadata: relative target path + parsed shebang). This PR moves the metadata into a :bunx NTFS alternate data stream on the exe itself, so .bin holds one file per bin and the metadata can't orphan or desync from its stub.
The two-file layout remains the fallback when the stream can't be created (exFAT/FAT32 and some network shares reject named streams); readers probe the stream first and fall back to the sidecar.
Changes
Write (bin.rs create_windows_shim): write the exe first, then try <name>.exe:bunx (FILE_OVERWRITE_IF, so reinstalls truncate the stream without touching other streams). On success, delete any pre-existing <name>.bunx sidecar so upgrading from the old layout leaves nothing stale. On any stream-open error, write <name>.bunx instead.
Read, standalone shim (bun_shim_impl.rs): copy the full image path (including .exe) into buf1, append :bunx, NtCreateFile. On failure, overwrite exe with bunx in place and retry with the sidecar length. The read_ptr walk that derives node_modules/ is driven by image_path_b_len alone and is unchanged by either suffix.
Read, bun.exe fast path (run_command.rs BunXFastPath::try_launch): callers still build <...>.bunx in DIRECT_LAUNCH_BUFFER; try_launch rewrites the tail to .exe:bunx for the probe, falls back to .bunx, then restores .bunx before handing base_path to the launcher (so the launcher's buffer math is unchanged).
Unlink (bin.rs unlink_bin_or_shim): no change. It already deletes both <name>.exe and <name>.bunx; deleting the exe removes its streams, and deleting the sidecar covers old-layout cleanup.
Tests
toBeValidBin/toHaveBins now accept either layout. New Windows tests in the existing windows bin linking shim should work suite cover:
.bincontains only.exeentries after install; every exe has a non-empty:bunxstream- the standalone shim reads a
.bunxsidecar when no stream is present bun install --forceover a project with stale.bunxsidecars removes them
All 47 tests in that suite pass on a Windows x64 debug build; the 3 new tests fail against main's src/.
no test proof · iteration 1 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/cli/install/bun-install-lifecycle-scripts.test.ts test/cli/install/bun-install-registry.test.ts test/cli/install/bun-publish.test.ts test/cli/install/bun-run.test.ts test/cli/install/bunx.test.ts test/cli/install/isolated-install.test.ts test/regression/issue/13316.test.ts