Skip to main content
Glama
node-check.ts8.74 kB
/** * Node.js Version Check Module * * Checks Node.js version on CLI startup and provides platform-specific * upgrade instructions when requirements aren't met. * * @package WP_Navigator_Pro * @since 2.4.0 */ import { execFileSync } from 'child_process'; import { error, info, newline, list, colorize, symbols } from '../tui/components.js'; // ============================================================================= // Constants // ============================================================================= /** Minimum required Node.js version (from package.json engines) */ export const REQUIRED_NODE_VERSION = { major: 18, minor: 0, patch: 0 }; /** Exit code for Node.js version errors */ export const EXIT_CODE_NODE_VERSION = 10; // ============================================================================= // Types // ============================================================================= export interface NodeVersion { major: number; minor: number; patch: number; raw: string; } export type InstallMethod = 'brew' | 'nvm' | 'fnm' | 'volta' | 'asdf' | 'system' | 'unknown'; export interface NodeCheckResult { ok: boolean; current: NodeVersion; required: NodeVersion; installMethod: InstallMethod; platform: NodeJS.Platform; instructions?: string[]; } // ============================================================================= // Version Parsing // ============================================================================= /** * Parse Node.js version string into components */ export function parseNodeVersion(versionString: string): NodeVersion { // Handle 'v' prefix (e.g., 'v18.17.0') const clean = versionString.replace(/^v/, ''); const parts = clean.split('.'); return { major: parseInt(parts[0] || '0', 10), minor: parseInt(parts[1] || '0', 10), patch: parseInt(parts[2] || '0', 10), raw: versionString, }; } /** * Get current Node.js version */ export function getNodeVersion(): NodeVersion { return parseNodeVersion(process.version); } /** * Compare two versions, returns: * - negative if a < b * - zero if a == b * - positive if a > b */ export function compareVersions(a: NodeVersion, b: NodeVersion): number { if (a.major !== b.major) return a.major - b.major; if (a.minor !== b.minor) return a.minor - b.minor; return a.patch - b.patch; } /** * Check if current version meets requirements */ export function meetsRequirements(current: NodeVersion, required: NodeVersion): boolean { return compareVersions(current, required) >= 0; } // ============================================================================= // Platform Detection // ============================================================================= /** * Detect how Node.js was installed on the system * * Uses environment variables and safe execFileSync calls (not exec with shell). */ export function detectInstallMethod(): InstallMethod { // Check for version managers via environment variables if (process.env.NVM_DIR) { return 'nvm'; } if (process.env.FNM_DIR || process.env.FNM_MULTISHELL_PATH) { return 'fnm'; } if (process.env.VOLTA_HOME) { return 'volta'; } if (process.env.ASDF_DIR) { return 'asdf'; } // Check for Homebrew on macOS using safe execFileSync (no shell injection) if (process.platform === 'darwin') { try { // Use execFileSync with array args - safe from shell injection const brewList = execFileSync('brew', ['list', 'node'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], }); if (brewList.includes('node')) { return 'brew'; } } catch { // Homebrew not installed or node not managed by brew } } // Check if we can determine it's a system install const nodePath = process.execPath; if (nodePath.includes('/usr/local/') || nodePath.includes('/usr/bin/')) { return 'system'; } return 'unknown'; } /** * Get platform-specific upgrade instructions */ export function getPlatformInstructions( method: InstallMethod, platform: NodeJS.Platform ): string[] { const instructions: string[] = []; switch (method) { case 'brew': instructions.push('brew upgrade node'); break; case 'nvm': instructions.push('nvm install 20'); instructions.push('nvm use 20'); break; case 'fnm': instructions.push('fnm install 20'); instructions.push('fnm use 20'); break; case 'volta': instructions.push('volta install node@20'); break; case 'asdf': instructions.push('asdf install nodejs 20.18.0'); instructions.push('asdf global nodejs 20.18.0'); break; case 'system': case 'unknown': default: // Provide platform-specific fallback instructions switch (platform) { case 'darwin': instructions.push('# Option 1: Using Homebrew'); instructions.push('brew install node'); instructions.push(''); instructions.push('# Option 2: Using nvm (recommended)'); instructions.push( 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash' ); instructions.push('nvm install 20'); break; case 'win32': instructions.push('Download Node.js 20 LTS from: https://nodejs.org/'); instructions.push('Run the installer and follow the prompts'); break; case 'linux': instructions.push('# Option 1: Using apt (Debian/Ubuntu)'); instructions.push('curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -'); instructions.push('sudo apt-get install -y nodejs'); instructions.push(''); instructions.push('# Option 2: Using nvm (recommended)'); instructions.push( 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash' ); instructions.push('nvm install 20'); break; default: instructions.push('Download Node.js 20 LTS from: https://nodejs.org/'); } } return instructions; } // ============================================================================= // Main Check Function // ============================================================================= /** * Check Node.js version and return result */ export function checkNodeVersion(): NodeCheckResult { const current = getNodeVersion(); const required = REQUIRED_NODE_VERSION as NodeVersion & { raw?: string }; required.raw = `v${required.major}.${required.minor}.${required.patch}`; const installMethod = detectInstallMethod(); const platform = process.platform; const ok = meetsRequirements(current, required); const result: NodeCheckResult = { ok, current, required, installMethod, platform, }; if (!ok) { result.instructions = getPlatformInstructions(installMethod, platform); } return result; } // ============================================================================= // Display Functions // ============================================================================= /** * Format version for display */ function formatVersion(v: NodeVersion): string { return `v${v.major}.${v.minor}.${v.patch}`; } /** * Display Node.js version error with upgrade instructions */ export function displayNodeVersionError(result: NodeCheckResult): void { newline(); error( `Node.js ${formatVersion(result.required)}+ required (found: ${formatVersion(result.current)})` ); newline(); // Show detected install method const methodLabels: Record<InstallMethod, string> = { brew: 'Homebrew', nvm: 'nvm', fnm: 'fnm', volta: 'Volta', asdf: 'asdf', system: 'System', unknown: 'Unknown', }; info(`Detected install method: ${methodLabels[result.installMethod]}`); newline(); // Show upgrade instructions console.error(colorize('To upgrade Node.js:', 'bold')); newline(); if (result.instructions && result.instructions.length > 0) { for (const instruction of result.instructions) { if (instruction === '') { console.error(''); } else if (instruction.startsWith('#')) { // Comment line console.error(colorize(` ${instruction}`, 'dim')); } else { console.error(` ${colorize(symbols.arrow, 'cyan')} ${colorize(instruction, 'cyan')}`); } } } newline(); info(`After upgrading, run your command again.`); newline(); // Show helpful links console.error(colorize('More info:', 'dim')); list([ 'Node.js downloads: https://nodejs.org/', 'nvm (recommended): https://github.com/nvm-sh/nvm', ]); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/littlebearapps/wp-navigator-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server