From d9623737dc97b17454a06d58484ce1136de4d300 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Thu, 2 Apr 2026 20:14:49 -0700 Subject: [PATCH 1/2] chore(cli): use mkdtempDisposable for package init cleanup --- cli/src/npm-client.ts | 145 ++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 76 deletions(-) diff --git a/cli/src/npm-client.ts b/cli/src/npm-client.ts index 8448413b52..5e288cd412 100644 --- a/cli/src/npm-client.ts +++ b/cli/src/npm-client.ts @@ -2,7 +2,7 @@ import crypto from 'node:crypto' import process from 'node:process' import { execFile } from 'node:child_process' import { promisify } from 'node:util' -import { mkdtemp, writeFile, rm } from 'node:fs/promises' +import { mkdtempDisposable, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import * as v from 'valibot' @@ -569,91 +569,84 @@ export async function packageInit( ): Promise { validatePackageName(name) - // Create a temporary directory - const tempDir = await mkdtemp(join(tmpdir(), 'npmx-init-')) - - try { - // Determine access type based on whether it's a scoped package - const isScoped = name.startsWith('@') - const access = isScoped ? 'public' : undefined - - // Create minimal package.json - const packageJson = { - name, - version: '0.0.0', - description: `Placeholder for ${name}`, - main: 'index.js', - scripts: {}, - keywords: [], - author: author ? `${author} (https://www.npmjs.com/~${author})` : '', - license: 'UNLICENSED', - private: false, - ...(access && { publishConfig: { access } }), - } + // Let Node clean up the temp directory automatically when this scope exits. + await using tempDir = await mkdtempDisposable(join(tmpdir(), 'npmx-init-')) + + // Determine access type based on whether it's a scoped package + const isScoped = name.startsWith('@') + const access = isScoped ? 'public' : undefined + + // Create minimal package.json + const packageJson = { + name, + version: '0.0.0', + description: `Placeholder for ${name}`, + main: 'index.js', + scripts: {}, + keywords: [], + author: author ? `${author} (https://www.npmjs.com/~${author})` : '', + license: 'UNLICENSED', + private: false, + ...(access && { publishConfig: { access } }), + } - await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson, null, 2)) + await writeFile(join(tempDir.path, 'package.json'), JSON.stringify(packageJson, null, 2)) - // Create empty index.js - await writeFile(join(tempDir, 'index.js'), '// Placeholder\n') + // Create empty index.js + await writeFile(join(tempDir.path, 'index.js'), '// Placeholder\n') - // Build npm publish args - const args = ['publish'] - if (access) { - args.push('--access', access) - } + // Build npm publish args + const args = ['publish'] + if (access) { + args.push('--access', access) + } - // Run npm publish from the temp directory - const npmArgs = otp ? [...args, '--otp', otp] : args + // Run npm publish from the temp directory + const npmArgs = otp ? [...args, '--otp', otp] : args - // Log the command being run (hide OTP value for security) - const displayCmd = otp ? `npm ${args.join(' ')} --otp ******` : `npm ${args.join(' ')}` - logCommand(`${displayCmd} (in temp dir for ${name})`) + // Log the command being run (hide OTP value for security) + const displayCmd = otp ? `npm ${args.join(' ')} --otp ******` : `npm ${args.join(' ')}` + logCommand(`${displayCmd} (in temp dir for ${name})`) - try { - const { stdout, stderr } = await execFileAsync('npm', npmArgs, { - timeout: 60000, - cwd: tempDir, - env: createNpmEnv(), - shell: process.platform === 'win32', - }) + try { + const { stdout, stderr } = await execFileAsync('npm', npmArgs, { + timeout: 60000, + cwd: tempDir.path, + env: createNpmEnv(), + shell: process.platform === 'win32', + }) - logSuccess(`Published ${name}@0.0.0`) + logSuccess(`Published ${name}@0.0.0`) - return { - stdout: stdout.trim(), - stderr: filterNpmWarnings(stderr), - exitCode: 0, - } - } catch (error) { - const err = error as { stdout?: string; stderr?: string; code?: number } - const stderr = err.stderr?.trim() ?? String(error) - const requiresOtp = detectOtpRequired(stderr) - const authFailure = detectAuthFailure(stderr) + return { + stdout: stdout.trim(), + stderr: filterNpmWarnings(stderr), + exitCode: 0, + } + } catch (error) { + const err = error as { stdout?: string; stderr?: string; code?: number } + const stderr = err.stderr?.trim() ?? String(error) + const requiresOtp = detectOtpRequired(stderr) + const authFailure = detectAuthFailure(stderr) - if (requiresOtp) { - logError('OTP required') - } else if (authFailure) { - logError('Authentication required - please run "npm login" and restart the connector') - } else { - logError(filterNpmWarnings(stderr).split('\n')[0] || 'Command failed') - } + if (requiresOtp) { + logError('OTP required') + } else if (authFailure) { + logError('Authentication required - please run "npm login" and restart the connector') + } else { + logError(filterNpmWarnings(stderr).split('\n')[0] || 'Command failed') + } - return { - stdout: err.stdout?.trim() ?? '', - stderr: requiresOtp - ? 'This operation requires a one-time password (OTP).' - : authFailure - ? 'Authentication failed. Please run "npm login" and restart the connector.' - : filterNpmWarnings(stderr), - exitCode: err.code ?? 1, - requiresOtp, - authFailure, - } + return { + stdout: err.stdout?.trim() ?? '', + stderr: requiresOtp + ? 'This operation requires a one-time password (OTP).' + : authFailure + ? 'Authentication failed. Please run "npm login" and restart the connector.' + : filterNpmWarnings(stderr), + exitCode: err.code ?? 1, + requiresOtp, + authFailure, } - } finally { - // Clean up temp directory - await rm(tempDir, { recursive: true, force: true }).catch(() => { - // Ignore cleanup errors - }) } } From e6822889ed25c5abc336937408ebbd7939ee8940 Mon Sep 17 00:00:00 2001 From: "Willow (GHOST)" Date: Sat, 4 Apr 2026 05:31:47 -0400 Subject: [PATCH 2/2] chore: update node version --- cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/package.json b/cli/package.json index 455fd222d8..c205f7d4c9 100644 --- a/cli/package.json +++ b/cli/package.json @@ -46,6 +46,6 @@ "typescript": "6.0.2" }, "engines": { - "node": ">=24" + "node": ">=24.4.0" } }