Repository navigation
v0.5.1
A patch release for two Windows bugs that 0.5.0 shipped with. One of them affects most contained tools rather than an edge case, which is why this follows 0.5.0 within a day.
The sandbox had no working temp directory
Windows ignores the TEMP nvx sets for a contained process and redirects it to <LOCALAPPDATA>\Packages\<package>\AC\Temp. That path resolved inside the sandbox, but nothing ever created it — so os.tmpdir() pointed at a directory that did not exist and every scratch file written by contained code failed with ENOENT. That is most tools, not a corner case. It was found while diagnosing the next item.
Installs that capture a subprocess no longer hang
npm install esbuild hung forever inside the sandbox, with no error. 0.5.0 documented this as an OS limitation nvx could not fix. That was half right.
The restriction is real and is now measured rather than asserted: CreateNamedPipeW inside a real AppContainer returns ERROR_ACCESS_DENIED for every name shape tried, so it is the named-pipe device refusing and no choice of name avoids it. Granting it would mean loosening \Device\NamedPipe for every AppContainer on the machine.
But file descriptors were never restricted, and synchronous capture does not need a stream — its whole contract is "run it, give me the output at the end", which a file satisfies exactly. A preload in every contained node process now routes spawnSync, execSync and execFileSync through temp files in the guest home. esbuild installs in seconds and the resulting binary works. The preload falls back to the original function on any error, because it loads into every contained node process and must never be the reason one fails.
Still broken, deliberately not folded into the above: asynchronous spawn(..., { stdio: "pipe" }) is a real stream that a file cannot stand in for, and it still hangs. Install such a package with --no-sandbox. nvx warns after two minutes naming this as the likely cause.
Also
The lifecycle smoke test could not fail on the bug it was written for — its fixture's postinstall only wrote a file and never captured a subprocess, so it passed while esbuild hung. It now captures a child and asserts the captured text, verified by disabling the preload and watching it hang rather than pass.
Nothing here changes containment. It changes how a contained process talks to its own children, not what it is able to reach.
Upgrading from 0.5.0 is a binary replacement; no state migration.