/** * Running a project's own CLI without a shell and without a `.cmd` shim. * * THE BUG THIS EXISTS FOR. These tools spawned `npx.cmd` on Windows with * `shell: false`, which used to be exactly right: naming the shim explicitly * meant caller-controlled arguments could never be reinterpreted by a shell. * * Node 20.12 changed that. As the fix for CVE-2024-27980 -- argument injection * through batch files -- Node now REFUSES to spawn any `.cmd` or `.bat` unless * `shell: true`, and throws EINVAL instead. Measured on this machine: every one * of smart_build, smart_install, smart_lint, smart_test and smart_typecheck * threw `spawn EINVAL` on every call. The entire build-systems category was * broken on Windows, and the obvious "fix" -- adding `shell: true` -- would * reintroduce precisely the injection the original comment was guarding * against. * * The way out is to stop involving a shim at all. Every one of these CLIs is a * JavaScript file; `node ` is argv mode, no shell, no batch * file, and identical on every platform. */ import { type SpawnOptionsWithoutStdio, type ChildProcessWithoutNullStreams } from 'child_process'; /** * Finds the JS entry point of a package's CLI, searching upward from the * project so a locally installed copy wins over a global one. * * Returns null when the package is not installed -- the caller can then say so * plainly instead of failing with an errno. */ export declare function resolveBinScript(packageName: string, binName: string, fromDir: string): string | null; export declare class MissingProjectTool extends Error { constructor(packageName: string, toolName: string); } /** * Spawns a package's CLI through the current Node binary. * * `shell: false` throughout: arguments reach the CLI as argv and are never * parsed by cmd.exe or sh, which is the property the original code wanted and * that `shell: true` would have thrown away. */ export declare function spawnNodeBin(packageName: string, binName: string, args: string[], options: SpawnOptionsWithoutStdio & { cwd: string; }, toolName: string): ChildProcessWithoutNullStreams; /** * The npm CLI, which ships with Node itself. * * `npm.cmd` hits the same EINVAL, but npm's own JS entry sits next to the node * binary in every distribution, so it can be run the same way. */ export declare function resolveNpmScript(): string | null; export declare function spawnNpm(args: string[], options: SpawnOptionsWithoutStdio & { cwd: string; }, toolName: string): ChildProcessWithoutNullStreams; /** * The same resolution, for callers that run a package manager SYNCHRONOUSLY. * * Returns the executable and the arguments that must precede the caller's own, * so an `execFileSync`-style call site becomes * * const { command, prefix } = packageManagerInvocation('npm', cwd, 'tool'); * execFileSync(command, [...prefix, 'list', '--json'], { cwd }); * * -- still argv mode, still no shell, and never a `.cmd` for Node to refuse. */ export declare function packageManagerInvocation(packageManager: string, cwd: string, toolName: string): { command: string; prefix: string[]; }; //# sourceMappingURL=run-node-bin.d.ts.map