fix: resolve node bins via package.json instead of spawning npx .cmd shims so the verify/smoke scripts run on Windows

On Windows npx/npm are .cmd shims a shell-free execFileSync/spawnSync
cannot start (ENOENT since the CVE-2024-27980 hardening), so
verify:typecheck-coverage died at validate's second step — doubly
silently, echoing "(no diagnostic captured)" per project and then
reporting all 918 tracked files as getting no tsc pass — and
verify:build-gate, the smoke test-server bootstraps, and pack:verify's
npm pack failed the same way.

Add scripts/lib/resolve-node-bin.mjs: resolves the JS entry behind a
package's bin from <pkg>/package.json (deep resolution is blocked by
Vite 8's exports map) and spawns it via process.execPath — the same
walk npx --no-install did, cross-platform and shell-free. Switch the
six npx call sites to it; the npm pack call gets the existing
shell-on-win32 idiom instead (npm has no in-tree package to resolve).
An unresolvable tsc is now a hard "cannot measure" error with
actionable stderr, pinned by a new main() regression test.

Closes #1939

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
olaservo 2026-08-12 09:04:31 -07:00
commit e3a026802b

View file

@ -53,6 +53,7 @@ import { setTimeout as delay } from "node:timers/promises";
import { join, resolve } from "node:path";
import { startProdWebServer } from "./lib/prod-web-server.mjs";
import { stopChild } from "./lib/child-cleanup.mjs";
import { resolveNodeBin } from "./lib/resolve-node-bin.mjs";
const repoRoot = resolve(import.meta.dirname, "..");
const requireFromWeb = createRequire(
@ -140,10 +141,18 @@ function ensureTestServer() {
console.log(
"smoke:web:app — building test-servers (missing build output)...",
);
const r = spawnSync("npx", ["tsc", "-p", "test-servers", "--noCheck"], {
cwd: repoRoot,
stdio: "inherit",
});
// The root-installed tsc, run via this Node — `npx` is a `.cmd` shim on
// Windows that a shell-free spawnSync can't start (ENOENT — #1939).
const r = spawnSync(
process.execPath,
[
resolveNodeBin("typescript", "tsc", repoRoot),
"-p",
"test-servers",
"--noCheck",
],
{ cwd: repoRoot, stdio: "inherit" },
);
if (r.status !== 0 || !existsSync(composableServer)) {
throw new Error(
"could not build the test servers (test-servers/build/server-composable.js). " +