fix: lower Node.js requirement to v18, update repo before running updater
- Changed MIN_NODE_VERSION from (24, 13, 0) to (18, 0, 0) to match Claude Code requirements - Updated uclaude_install.sh to fetch latest repo before running updater - Rewrote uclaude_update.ps1 to require v18+ and update repo first - Added multiple fallback methods for Node.js installation on Windows Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
#!/bin/bash
|
||||
# UClaude — one-line installer with full auto-install chain
|
||||
# Usage: curl -fsSL -H "Authorization: token TOKEN" https://git.sensey24.ru/aibot777/unlimitedcoding/raw/branch/master/claude/uclaude_install.sh -o /tmp/uclaude.sh && sudo bash /tmp/uclaude.sh
|
||||
set -e
|
||||
set -uo pipefail
|
||||
|
||||
# Error handler
|
||||
error_handler() {
|
||||
local line_no=$1
|
||||
echo "ERROR: Command failed at line $line_no" >&2
|
||||
echo "Last command: $BASH_COMMAND" >&2
|
||||
echo "Exiting..." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap 'error_handler $LINENO' ERR
|
||||
|
||||
# Read-only access token for private repo (scoped: read:repository only)
|
||||
GITEA_TOKEN="${GITEA_TOKEN:-cadffcb0a6a3be728ac1ff619bb40c86588f6837}"
|
||||
@@ -92,6 +103,12 @@ else
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " Updating repo to latest version before running updater..."
|
||||
# Update repo to latest version BEFORE running updater (so we get latest MIN_NODE_VERSION fix)
|
||||
cd "$INSTALL_DIR"
|
||||
git fetch --depth 1 origin master 2>/dev/null
|
||||
git reset --hard origin/master 2>/dev/null || git pull --quiet 2>/dev/null
|
||||
|
||||
echo " Running updater..."
|
||||
|
||||
# Run updater (needs root for cli.js replacement + node install)
|
||||
|
||||
@@ -6,28 +6,45 @@ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RepoRoot = Split-Path -Parent $ScriptDir
|
||||
Set-Location $RepoRoot
|
||||
|
||||
# ---- Check prerequisites ----
|
||||
# ---- Pull latest FIRST so we always run newest scripts ----
|
||||
|
||||
Write-Host " Updating from remote..." -ForegroundColor Cyan
|
||||
git fetch --depth 1 origin master 2>$null
|
||||
git reset --hard origin/master 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
git pull --quiet 2>$null
|
||||
}
|
||||
|
||||
# ---- Helpers ----
|
||||
|
||||
function Test-Command($cmd) {
|
||||
return [bool](Get-Command $cmd -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
function Install-WithWinget($id, $name) {
|
||||
if (Test-Command "winget") {
|
||||
Write-Host " Installing $name via winget..." -ForegroundColor Yellow
|
||||
winget install --id $id --accept-package-agreements --accept-source-agreements -e
|
||||
# Refresh PATH
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||
return $true
|
||||
}
|
||||
return $false
|
||||
function Refresh-Path {
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
|
||||
[System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||
}
|
||||
|
||||
function Get-NodeMajor {
|
||||
if (Test-Command "node") {
|
||||
try { return [int](((node --version 2>$null) -replace '^v', '') -split '\.')[0] }
|
||||
catch { return 0 }
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
# ---- Check prerequisites ----
|
||||
|
||||
# Git
|
||||
if (-not (Test-Command "git")) {
|
||||
Write-Host " git not found." -ForegroundColor Red
|
||||
if (-not (Install-WithWinget "Git.Git" "Git")) {
|
||||
Write-Host " Install manually: https://git-scm.com/download/win" -ForegroundColor Yellow
|
||||
if (Test-Command "winget") {
|
||||
winget install --id Git.Git --accept-package-agreements --accept-source-agreements -e
|
||||
Refresh-Path
|
||||
}
|
||||
if (-not (Test-Command "git")) {
|
||||
Write-Host " Install git manually: https://git-scm.com/download/win" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -36,40 +53,82 @@ if (-not (Test-Command "git")) {
|
||||
$hasPython = (Test-Command "python3") -or (Test-Command "python")
|
||||
if (-not $hasPython) {
|
||||
Write-Host " Python not found." -ForegroundColor Red
|
||||
if (-not (Install-WithWinget "Python.Python.3.12" "Python 3.12")) {
|
||||
Write-Host " Install manually: https://www.python.org/downloads/" -ForegroundColor Yellow
|
||||
if (Test-Command "winget") {
|
||||
winget install --id Python.Python.3.12 --accept-package-agreements --accept-source-agreements -e
|
||||
Refresh-Path
|
||||
}
|
||||
$hasPython = (Test-Command "python3") -or (Test-Command "python")
|
||||
if (-not $hasPython) {
|
||||
Write-Host " Install Python manually: https://www.python.org/downloads/" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Node.js v24+
|
||||
$nodeOk = $false
|
||||
if (Test-Command "node") {
|
||||
$nodeVer = (node --version) -replace '^v', ''
|
||||
$nodeMajor = [int]($nodeVer -split '\.')[0]
|
||||
if ($nodeMajor -ge 24) {
|
||||
$nodeOk = $true
|
||||
} else {
|
||||
Write-Host " Node.js v$nodeVer found, need v24+. Upgrading..." -ForegroundColor Yellow
|
||||
}
|
||||
# Node.js v18+ (Claude Code requires v18+, v20/v22/v24 all work)
|
||||
$MIN_NODE_MAJOR = 18
|
||||
$nodeMajor = Get-NodeMajor
|
||||
|
||||
if ($nodeMajor -ge $MIN_NODE_MAJOR) {
|
||||
Write-Host " Node.js v$nodeMajor.x OK" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " Node.js not found." -ForegroundColor Yellow
|
||||
}
|
||||
if (-not $nodeOk) {
|
||||
if (-not (Install-WithWinget "OpenJS.NodeJS.V24" "Node.js v24")) {
|
||||
Write-Host " Install Node.js v24+ manually: https://nodejs.org/" -ForegroundColor Yellow
|
||||
if ($nodeMajor -gt 0) {
|
||||
Write-Host " Node.js v$nodeMajor found, need v$MIN_NODE_MAJOR+. Upgrading..." -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " Node.js not found. Installing..." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
$installed = $false
|
||||
|
||||
# 1. Try winget LTS
|
||||
if (-not $installed -and (Test-Command "winget")) {
|
||||
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 }
|
||||
}
|
||||
|
||||
# 2. Try Chocolatey
|
||||
if (-not $installed -and (Test-Command "choco")) {
|
||||
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 }
|
||||
}
|
||||
|
||||
# 3. Direct MSI download — Node.js 20 LTS (most compatible)
|
||||
if (-not $installed) {
|
||||
Write-Host " Downloading Node.js 20 LTS MSI..." -ForegroundColor Yellow
|
||||
try {
|
||||
$msiUrl = "https://nodejs.org/dist/v20.18.0/node-v20.18.0-x64.msi"
|
||||
$msiFile = Join-Path $env:TEMP "node-v20-lts.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 }
|
||||
} catch {
|
||||
Write-Host " Download failed: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
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 " Then re-run this script." -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " Node.js v$(Get-NodeMajor).x installed OK" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# ---- Pull latest artifacts ----
|
||||
# ---- Check admin, re-launch elevated if needed ----
|
||||
|
||||
git pull --quiet 2>$null
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
# ---- Check admin ----
|
||||
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Host "Re-running as Administrator..." -ForegroundColor Yellow
|
||||
Write-Host " Re-running as Administrator..." -ForegroundColor Yellow
|
||||
Start-Process powershell -ArgumentList "-ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`" $args" -Verb RunAs
|
||||
exit
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ def run_cmd(cmd, **kwargs):
|
||||
# Node.js check and auto-install
|
||||
# ============================================================
|
||||
|
||||
MIN_NODE_VERSION = (24, 13, 0)
|
||||
MIN_NODE_VERSION = (18, 0, 0)
|
||||
|
||||
|
||||
def get_node_version():
|
||||
@@ -133,7 +133,7 @@ def install_node():
|
||||
os.remove(old_list)
|
||||
|
||||
result = run_cmd(
|
||||
["bash", "-c", "curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && apt-get install -y nodejs"],
|
||||
["bash", "-c", "curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && apt-get remove -y nodejs || true && apt-get install -y nodejs"],
|
||||
timeout=180, capture_output=True, text=True,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
@@ -176,7 +176,15 @@ def ensure_node():
|
||||
if ver is None:
|
||||
print(f" {Y}Node.js not found.{D}")
|
||||
if is_admin():
|
||||
return install_node()
|
||||
ok = install_node()
|
||||
if ok:
|
||||
# Re-verify after install — PATH may now point to new binary
|
||||
ver = get_node_version()
|
||||
if ver and ver >= MIN_NODE_VERSION:
|
||||
return True
|
||||
eprint(f" {R}Node.js still not available after install. Reopen shell or check PATH.{D}")
|
||||
return False
|
||||
return False
|
||||
else:
|
||||
eprint(f" {R}Install Node.js v{'.'.join(map(str, MIN_NODE_VERSION))}+: https://nodejs.org/{D}")
|
||||
return False
|
||||
@@ -184,7 +192,15 @@ def ensure_node():
|
||||
if ver < MIN_NODE_VERSION:
|
||||
print(f" {Y}Node.js v{'.'.join(map(str, ver))} found, need v{'.'.join(map(str, MIN_NODE_VERSION))}+{D}")
|
||||
if is_admin():
|
||||
return install_node()
|
||||
ok = install_node()
|
||||
if ok:
|
||||
# Re-verify after upgrade — PATH may now point to new binary
|
||||
ver = get_node_version()
|
||||
if ver and ver >= MIN_NODE_VERSION:
|
||||
return True
|
||||
eprint(f" {R}Node.js version still insufficient after upgrade. Reopen shell or check PATH.{D}")
|
||||
return False
|
||||
return False
|
||||
else:
|
||||
eprint(f" {R}Update Node.js: https://nodejs.org/{D}")
|
||||
return False
|
||||
@@ -265,6 +281,15 @@ def find_cli_js():
|
||||
"/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js",
|
||||
]
|
||||
|
||||
# Prepend npm root -g result (most reliable, works across all Node install methods)
|
||||
try:
|
||||
result = subprocess.run(["npm", "root", "-g"], capture_output=True, text=True, timeout=10)
|
||||
if result.returncode == 0:
|
||||
npm_global = result.stdout.strip()
|
||||
candidates.insert(0, os.path.join(npm_global, "@anthropic-ai", "claude-code", "cli.js"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for path in candidates:
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
|
||||
Reference in New Issue
Block a user