Skip to content

Commit e390298

Browse files
fix(cli): centralize cross-platform npm process execution without shell
1 parent fe19e5d commit e390298

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

cli/src/cli.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ import { serve } from 'srvx'
88
import { createConnectorApp, generateToken, CONNECTOR_VERSION } from './server.ts'
99
import { getNpmUser, NPM_REGISTRY_URL } from './npm-client.ts'
1010
import { initLogger, showToken, logInfo, logWarning, logError } from './logger.ts'
11+
import { resolveNpmProcessCommand } from './npm-process.ts'
1112

1213
const DEFAULT_PORT = 31415
1314
const DEFAULT_FRONTEND_URL = 'https://npmx.dev/'
1415
const DEV_FRONTEND_URL = 'http://127.0.0.1:3000/'
15-
const NPM_COMMAND = process.platform === 'win32' ? 'npm.cmd' : 'npm'
16-
1716
async function runNpmLogin(): Promise<boolean> {
1817
return new Promise(resolve => {
19-
const child = spawn(NPM_COMMAND, ['login', `--registry=${NPM_REGISTRY_URL}`], {
18+
const { command, args } = resolveNpmProcessCommand([
19+
'login',
20+
`--registry=${NPM_REGISTRY_URL}`,
21+
])
22+
23+
const child = spawn(command, args, {
2024
stdio: 'inherit',
2125
})
2226

cli/src/npm-client.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import { join } from 'node:path'
88
import * as v from 'valibot'
99
import { PackageNameSchema, UsernameSchema, OrgNameSchema, ScopeTeamSchema } from './schemas.ts'
1010
import { logCommand, logSuccess, logError, logDebug } from './logger.ts'
11+
import { resolveNpmProcessCommand } from './npm-process.ts'
1112

1213
const execFileAsync = promisify(execFile)
1314
export const NPM_REGISTRY_URL = 'https://registry.npmjs.org/'
14-
const NPM_COMMAND = process.platform === 'win32' ? 'npm.cmd' : 'npm'
1515

1616
function createNpmEnv(overrides: Record<string, string> = {}): Record<string, string> {
1717
return {
@@ -210,7 +210,7 @@ async function execNpmInteractive(
210210
env.npm_config_browser = 'false'
211211
}
212212

213-
const child = pty.spawn(NPM_COMMAND, npmArgs, {
213+
const child = pty.spawn('npm', npmArgs, {
214214
name: 'xterm-256color',
215215
cols: 120,
216216
rows: 30,
@@ -332,10 +332,9 @@ async function execNpm(args: string[], options: ExecNpmOptions = {}): Promise<Np
332332
}
333333

334334
try {
335-
logDebug('Executing npm command:', { command: NPM_COMMAND, args: npmArgs })
336-
// Use execFile instead of exec to avoid shell injection vulnerabilities.
337-
// Use npm.cmd on Windows to avoid shell wrapping and DEP0190 warnings.
338-
const { stdout, stderr } = await execFileAsync(NPM_COMMAND, npmArgs, {
335+
logDebug('Executing npm command:', { command: 'npm', args: npmArgs })
336+
const { command, args: processArgs } = resolveNpmProcessCommand(npmArgs)
337+
const { stdout, stderr } = await execFileAsync(command, processArgs, {
339338
timeout: 60000,
340339
env: createNpmEnv(),
341340
})
@@ -609,7 +608,8 @@ export async function packageInit(
609608
logCommand(`${displayCmd} (in temp dir for ${name})`)
610609

611610
try {
612-
const { stdout, stderr } = await execFileAsync(NPM_COMMAND, npmArgs, {
611+
const { command, args: processArgs } = resolveNpmProcessCommand(npmArgs)
612+
const { stdout, stderr } = await execFileAsync(command, processArgs, {
613613
timeout: 60000,
614614
cwd: tempDir,
615615
env: createNpmEnv(),

cli/src/npm-process.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import process from 'node:process'
2+
3+
export interface NpmProcessCommand {
4+
command: string
5+
args: string[]
6+
}
7+
8+
export function resolveNpmProcessCommand(
9+
npmArgs: string[],
10+
platform = process.platform,
11+
comSpec = process.env.ComSpec,
12+
): NpmProcessCommand {
13+
if (platform === 'win32') {
14+
return {
15+
command: comSpec || 'cmd.exe',
16+
args: ['/d', '/s', '/c', 'npm', ...npmArgs],
17+
}
18+
}
19+
20+
return {
21+
command: 'npm',
22+
args: npmArgs,
23+
}
24+
}

0 commit comments

Comments
 (0)