fix(build): make root workspace build run on Windows
Two Windows-only breakages in the build path:
- scripts/build-workspace.mjs: the "run as main" guard compared import.meta.url
to `file://${process.argv[1]}`, which never matches on Windows (import.meta.url
is file:///C:/… with forward slashes and a triple slash; argv[1] is C:\… with
backslashes and no scheme). So `pnpm build` at the repo root silently no-opped
(exit 0, no output, no dist) and packaging shipped empty/stale dist. Compare
against pathToFileURL(process.argv[1]).href instead.
- scripts/build-workspace.mjs runPlannedBuilds and packages/cli/tsup.config.ts
runWorkspaceCommand spawned `pnpm` without shell:true; on Windows pnpm is a
.cmd shim Node refuses to spawn without a shell (ENOENT/EINVAL, CVE-2024-27980),
failing with `spawn pnpm ENOENT`. Pass shell on win32 (args are fixed repo build
invocations with no shell metacharacters).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -200,6 +200,15 @@ function runWorkspaceCommand(command: string, args: string[], cwd: string, timeo
|
||||
cwd,
|
||||
stdio: "inherit",
|
||||
env: process.env,
|
||||
/*
|
||||
* FNXC:DesktopPackaging 2026-07-02-15:10:
|
||||
* On Windows `pnpm` (and other npm bins) resolve to a `.cmd` shim that Node refuses to
|
||||
* spawn without a shell (ENOENT / EINVAL since CVE-2024-27980). Without shell:true the CLI
|
||||
* package build failed with `spawn pnpm ENOENT` on Windows at the "building @fusion/desktop"
|
||||
* step. The command/args here are fixed repo build invocations (no untrusted input), so shell
|
||||
* quoting is safe.
|
||||
*/
|
||||
shell: process.platform === "win32",
|
||||
});
|
||||
const timer = setTimeout(() => {
|
||||
child.kill("SIGTERM");
|
||||
|
||||
@@ -7,7 +7,7 @@ Root builds may skip unchanged plugin workspaces to keep local and CI feedback f
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import fg from "fast-glob";
|
||||
import YAML from "yaml";
|
||||
import {
|
||||
@@ -370,7 +370,14 @@ export function runPlannedBuilds(plannedPackages, rootDir, spawnFn = spawnSync)
|
||||
if (plannedPackages.length === 0) return { status: 0, packageNames: [] };
|
||||
const packageNames = plannedPackages.map((pkg) => pkg.name);
|
||||
const args = [...packageNames.flatMap((name) => ["--filter", name]), "build"];
|
||||
const result = spawnFn("pnpm", args, { cwd: rootDir, stdio: "inherit" });
|
||||
/*
|
||||
* FNXC:WorkspaceBuild 2026-07-02-15:10:
|
||||
* On Windows `pnpm` resolves to a `.cmd` shim; Node refuses to spawn .cmd/.bat without a
|
||||
* shell (ENOENT / EINVAL since CVE-2024-27980). Without shell:true the root build failed
|
||||
* with `spawn pnpm ENOENT` on Windows. The args are workspace filters + package names
|
||||
* (no spaces or shell metacharacters), so shell quoting is safe.
|
||||
*/
|
||||
const result = spawnFn("pnpm", args, { cwd: rootDir, stdio: "inherit", shell: process.platform === "win32" });
|
||||
return { status: result.status ?? 1, packageNames };
|
||||
}
|
||||
|
||||
@@ -422,6 +429,15 @@ export function main({ rootDir = repoRoot, spawnFn = spawnSync, gitFn = defaultG
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
/*
|
||||
* FNXC:WorkspaceBuild 2026-07-02-15:10:
|
||||
* Cross-platform "run as main" guard. The old `import.meta.url === \`file://${process.argv[1]}\``
|
||||
* check NEVER matched on Windows: import.meta.url is `file:///C:/…/build-workspace.mjs`
|
||||
* (triple slash, forward slashes) while process.argv[1] is `C:\…\build-workspace.mjs`
|
||||
* (backslashes, no scheme). So `pnpm build` at the repo root silently no-opped on Windows
|
||||
* (exit 0, no output, no dist) — packaging then shipped empty/stale dist. Compare against the
|
||||
* file URL of argv[1] so the guard is correct on Windows, macOS, and Linux.
|
||||
*/
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
process.exit(main());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user