diff --git a/cli/package.json b/cli/package.json index ca1bea454..0dc83ead5 100644 --- a/cli/package.json +++ b/cli/package.json @@ -28,6 +28,7 @@ "scripts": { "build": "tsdown", "dev": "NPMX_CLI_DEV=true node src/cli.ts", + "dev:debug": "DEBUG=npmx-connector NPMX_CLI_DEV=true node src/cli.ts", "test:types": "tsc --noEmit" }, "dependencies": { diff --git a/cli/src/npm-client.ts b/cli/src/npm-client.ts index 1c1cb270f..b709e77fa 100644 --- a/cli/src/npm-client.ts +++ b/cli/src/npm-client.ts @@ -7,7 +7,7 @@ import { tmpdir } from 'node:os' import { join } from 'node:path' import * as v from 'valibot' import { PackageNameSchema, UsernameSchema, OrgNameSchema, ScopeTeamSchema } from './schemas.ts' -import { logCommand, logSuccess, logError } from './logger.ts' +import { logCommand, logSuccess, logError, logDebug } from './logger.ts' const execFileAsync = promisify(execFile) @@ -75,10 +75,15 @@ function detectOtpRequired(stderr: string): boolean { 'EOTP', 'one-time password', 'This operation requires a one-time password', + 'OTP required for authentication', '--otp=', ] const lowerStderr = stderr.toLowerCase() - return otpPatterns.some(pattern => lowerStderr.includes(pattern.toLowerCase())) + logDebug('Checking for OTP requirement in stderr:', stderr) + logDebug('OTP patterns:', otpPatterns) + const result = otpPatterns.some(pattern => lowerStderr.includes(pattern.toLowerCase())) + logDebug('OTP required:', result) + return result } function detectAuthFailure(stderr: string): boolean { @@ -96,7 +101,11 @@ function detectAuthFailure(stderr: string): boolean { 'npm adduser', ] const lowerStderr = stderr.toLowerCase() - return authPatterns.some(pattern => lowerStderr.includes(pattern.toLowerCase())) + logDebug('Checking for auth failure in stderr:', stderr) + logDebug('Auth patterns:', authPatterns) + const result = authPatterns.some(pattern => lowerStderr.includes(pattern.toLowerCase())) + logDebug('Auth failure:', result) + return result } function filterNpmWarnings(stderr: string): string { @@ -123,6 +132,7 @@ async function execNpm( } try { + logDebug('Executing npm command:', { command: 'npm', args: npmArgs }) // Use execFile instead of exec to avoid shell injection vulnerabilities // On Windows, shell: true is required to execute .cmd files (like npm.cmd) // On Unix, we keep it false for better security and performance @@ -132,6 +142,8 @@ async function execNpm( shell: process.platform === 'win32', }) + logDebug('Command succeeded:', { stdout, stderr }) + if (!options.silent) { logSuccess('Done') } @@ -144,6 +156,7 @@ async function execNpm( } catch (error) { const err = error as { stdout?: string; stderr?: string; code?: number } const stderr = err.stderr?.trim() ?? String(error) + logDebug('Command failed:', { error, stdout: err.stdout, stderr: err.stderr, code: err.code }) const requiresOtp = detectOtpRequired(stderr) const authFailure = detectAuthFailure(stderr)