feat: dynamic Node.js version detection from npm registry
- Add get_required_node_version() — fetches engines.node from npm registry
for @anthropic-ai/claude-code@latest and extracts required major version
- install_node() now installs setup_{major}.x matching Claude Code requirement
- ensure_node() uses dynamic version for checks and error messages
- Windows: Get-RequiredNodeMajor fetches version from npm registry
- Windows: MSI download uses required major version, not hardcoded v22
- Fallback to MIN_NODE_VERSION (18) if npm registry is unreachable
- Future-proof: when Claude Code raises requirement to 26+, scripts auto-adapt
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,17 +64,35 @@ if (-not $hasPython) {
|
||||
}
|
||||
}
|
||||
|
||||
# Node.js v18+ (Claude Code requires v18+, v20/v22/v24 all work)
|
||||
$MIN_NODE_MAJOR = 18
|
||||
$nodeMajor = Get-NodeMajor
|
||||
# Dynamic Node.js version detection from npm registry
|
||||
$MIN_NODE_MAJOR = 18 # fallback
|
||||
|
||||
if ($nodeMajor -ge $MIN_NODE_MAJOR) {
|
||||
function Get-RequiredNodeMajor {
|
||||
# Try to detect required Node.js major version from npm registry
|
||||
try {
|
||||
$response = Invoke-RestMethod -Uri "https://registry.npmjs.org/@anthropic-ai/claude-code/latest" -UseBasicParsing -TimeoutSec 10
|
||||
$engines = $response.engines
|
||||
$nodeReq = $engines.node
|
||||
|
||||
# Parse ">=18.0.0" or "^24.0.0" etc → extract first number
|
||||
if ($nodeReq -match '(\d+)') {
|
||||
return [int]$matches[1]
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Warning: Could not fetch Node.js requirement from npm, using fallback v$MIN_NODE_MAJOR" -ForegroundColor Yellow
|
||||
}
|
||||
return $MIN_NODE_MAJOR
|
||||
}
|
||||
$nodeMajor = Get-NodeMajor
|
||||
$requiredMajor = Get-RequiredNodeMajor
|
||||
|
||||
if ($nodeMajor -ge $requiredMajor) {
|
||||
Write-Host " Node.js v$nodeMajor.x OK" -ForegroundColor Green
|
||||
} else {
|
||||
if ($nodeMajor -gt 0) {
|
||||
Write-Host " Node.js v$nodeMajor found, need v$MIN_NODE_MAJOR+. Upgrading..." -ForegroundColor Yellow
|
||||
Write-Host " Node.js v$nodeMajor found, need v$requiredMajor+. Upgrading..." -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " Node.js not found. Installing..." -ForegroundColor Yellow
|
||||
Write-Host " Node.js not found. Installing v$requiredMajor+..." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
$installed = $false
|
||||
@@ -84,7 +102,7 @@ if ($nodeMajor -ge $MIN_NODE_MAJOR) {
|
||||
Write-Host " Trying winget (Node.js LTS)..." -ForegroundColor Yellow
|
||||
winget install --id OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements -e 2>$null
|
||||
Refresh-Path
|
||||
if ((Get-NodeMajor) -ge $MIN_NODE_MAJOR) { $installed = $true }
|
||||
if ((Get-NodeMajor) -ge $requiredMajor) { $installed = $true }
|
||||
}
|
||||
|
||||
# 2. Try Chocolatey
|
||||
@@ -92,27 +110,27 @@ if ($nodeMajor -ge $MIN_NODE_MAJOR) {
|
||||
Write-Host " Trying Chocolatey (nodejs-lts)..." -ForegroundColor Yellow
|
||||
choco install nodejs-lts -y 2>$null
|
||||
Refresh-Path
|
||||
if ((Get-NodeMajor) -ge $MIN_NODE_MAJOR) { $installed = $true }
|
||||
if ((Get-NodeMajor) -ge $requiredMajor) { $installed = $true }
|
||||
}
|
||||
|
||||
# 3. Direct MSI download — Node.js 22 LTS (most compatible)
|
||||
# 3. Direct MSI download — dynamically pick the right major version
|
||||
if (-not $installed) {
|
||||
Write-Host " Downloading Node.js 22 LTS MSI..." -ForegroundColor Yellow
|
||||
Write-Host " Downloading Node.js v$requiredMajor MSI..." -ForegroundColor Yellow
|
||||
try {
|
||||
# Try to get latest LTS version dynamically, fallback to known good version
|
||||
$latestLts = "v22.14.0"
|
||||
# Fetch latest release of the required major version from nodejs.org
|
||||
$latestForMajor = "v$requiredMajor.0.0"
|
||||
try {
|
||||
$releases = Invoke-RestMethod -Uri "https://nodejs.org/dist/index.json" -UseBasicParsing -TimeoutSec 10
|
||||
$lts = $releases | Where-Object { $_.lts -and $_.version -match "^v22\." } | Select-Object -First 1
|
||||
if ($lts) { $latestLts = $lts.version }
|
||||
$match = $releases | Where-Object { $_.version -match "^v$requiredMajor\." } | Select-Object -First 1
|
||||
if ($match) { $latestForMajor = $match.version }
|
||||
} catch {}
|
||||
$msiUrl = "https://nodejs.org/dist/$latestLts/node-$latestLts-x64.msi"
|
||||
$msiFile = Join-Path $env:TEMP "node-lts.msi"
|
||||
$msiUrl = "https://nodejs.org/dist/$latestForMajor/node-$latestForMajor-x64.msi"
|
||||
$msiFile = Join-Path $env:TEMP "node-v$requiredMajor.msi"
|
||||
Invoke-WebRequest -Uri $msiUrl -OutFile $msiFile -UseBasicParsing
|
||||
Start-Process msiexec.exe -ArgumentList "/i `"$msiFile`" /quiet /norestart" -Wait
|
||||
Refresh-Path
|
||||
Remove-Item $msiFile -Force -ErrorAction SilentlyContinue
|
||||
if ((Get-NodeMajor) -ge $MIN_NODE_MAJOR) { $installed = $true }
|
||||
if ((Get-NodeMajor) -ge $requiredMajor) { $installed = $true }
|
||||
} catch {
|
||||
Write-Host " Download failed: $_" -ForegroundColor Red
|
||||
}
|
||||
@@ -121,7 +139,7 @@ if ($nodeMajor -ge $MIN_NODE_MAJOR) {
|
||||
if (-not $installed) {
|
||||
Write-Host "" -ForegroundColor Red
|
||||
Write-Host " Could not install Node.js automatically." -ForegroundColor Red
|
||||
Write-Host " Install manually: https://nodejs.org/en/download/ (v20 LTS)" -ForegroundColor Yellow
|
||||
Write-Host " Install manually: https://nodejs.org/en/download/ (v$requiredMajor+)" -ForegroundColor Yellow
|
||||
Write-Host " Then re-run this script." -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user