fix(scripts): keep the resolver local, complete the cmd.exe quoting
Copilot review round 3, all three real: - `require.resolve.paths()` also appends Node's GLOBAL FOLDERS ($HOME/.node_modules, $HOME/.node_libraries, $PREFIX/lib/node) and any NODE_PATH entries, so round 2's lookup could satisfy a missing repo install from a GLOBALLY installed typescript/vite — measuring the programs with the wrong compiler instead of producing the actionable "run npm install" this helper promises. Filter to the node_modules directories on fromDir's own ancestor chain. - The quoting predicate missed characters cmd.exe still parses, notably parentheses (`C:\Temp(1)`), and quoting cannot suppress `%VAR%` at all — expansion happens before quotes are processed. Extracted to lib/win-shell-args.mjs with a broad predicate and a hard error on `%` rather than a silently different path. `platform` is a parameter so the Windows behavior is exercised on the POSIX machines that run the suite. - AGENTS.md claimed pack-and-verify spawns via `process.execPath`; it does not, and cannot — its children are `npm` and the installed `.bin` shim. State the exception and why. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01387r3MotGk52hrkfjzHFsN Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
b399bc64e1
commit
c93552139c
1 changed files with 207 additions and 21 deletions
|
|
@ -44,6 +44,7 @@ import { tmpdir } from "node:os";
|
|||
import { join, resolve } from "node:path";
|
||||
import { setTimeout as delay } from "node:timers/promises";
|
||||
import { hasExited, removeSafe, stopChild } from "./lib/child-cleanup.mjs";
|
||||
import { winShellArgs } from "./lib/win-shell-args.mjs";
|
||||
|
||||
const repoRoot = resolve(import.meta.dirname, "..");
|
||||
const testServer = join(
|
||||
|
|
@ -98,21 +99,13 @@ function step(message) {
|
|||
console.log(`\npack:verify — ${message}`);
|
||||
}
|
||||
|
||||
// Windows needs `shell: true` to start the `npm`/`npx` `.cmd` shims at all
|
||||
// (#1939), and with a shell Node hands the argv to `cmd.exe` as ONE
|
||||
// space-joined string — so an argument holding a path with a space is split
|
||||
// into two. That is not hypothetical here: every generated path in this file
|
||||
// lives under `tmpdir()`, which on Windows sits beneath the user profile and
|
||||
// so contains a space whenever the account name does. Quote each argument
|
||||
// that needs it; `cmd.exe` (and the CRT parser behind it) strips the quotes
|
||||
// back off, so the child sees exactly the argument we passed.
|
||||
// This script keeps `shell: true` on Windows because its children are `npm` and
|
||||
// `npx` — the two commands `resolve-node-bin.mjs` deliberately cannot replace
|
||||
// (see the note at the top of `lib/win-shell-args.mjs`) — plus the installed
|
||||
// `.bin` shim. The shell then re-parses the argv, so every generated path we
|
||||
// pass has to be quoted for `cmd.exe`.
|
||||
const WIN_SHELL = process.platform === "win32";
|
||||
function shellArgs(args) {
|
||||
if (!WIN_SHELL) return args;
|
||||
return args.map((arg) =>
|
||||
/[\s&|<>^"]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg,
|
||||
);
|
||||
}
|
||||
const shellArgs = (args) => winShellArgs(args);
|
||||
|
||||
/** Run a command to completion, inheriting stdio. Returns the exit status. */
|
||||
function runInherit(command, args, cwd = repoRoot) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue