fix(installer): retry transient Windows npm failures

This commit is contained in:
Peter Steinberger
2026-07-16 11:19:17 +01:00
parent a88ff7a6ba
commit 8dd204e4fc
2 changed files with 28 additions and 13 deletions
+19 -6
View File
@@ -1250,7 +1250,8 @@ function Get-NpmDebugLogRootCandidates {
}
function Get-LatestNpmDebugLogPath {
foreach ($cacheDir in (Get-NpmDebugLogRootCandidates)) {
param([object[]]$CacheRoots)
foreach ($cacheDir in @($CacheRoots)) {
$logDir = Join-Path $cacheDir "_logs"
if (-not (Test-Path -LiteralPath $logDir -PathType Container)) {
continue
@@ -1266,7 +1267,10 @@ function Get-LatestNpmDebugLogPath {
}
function Write-NpmInstallFailureDetails {
param([object[]]$Output)
param(
[object[]]$Output,
[object[]]$CacheRoots
)
$printedOutput = $false
foreach ($line in @($Output)) {
if ($null -eq $line) {
@@ -1280,7 +1284,7 @@ function Write-NpmInstallFailureDetails {
$printedOutput = $true
}
$latestLog = Get-LatestNpmDebugLogPath
$latestLog = Get-LatestNpmDebugLogPath -CacheRoots $CacheRoots
if ($latestLog) {
Write-Host "Latest npm debug log ($latestLog):" -ForegroundColor Yellow
Get-Content -LiteralPath $latestLog -Tail 120 -ErrorAction SilentlyContinue | ForEach-Object { Write-Host $_ }
@@ -1338,8 +1342,17 @@ function Install-OpenClaw {
Remove-Item Env:NPM_CONFIG_BEFORE -ErrorAction SilentlyContinue
Remove-Item Env:NPM_CONFIG_MIN_RELEASE_AGE -ErrorAction SilentlyContinue
try {
$npmOutput = Invoke-NpmCommand -Arguments (@("install", "-g") + $freshnessArgs + @("$installSpec")) 2>&1
if ($LASTEXITCODE -ne 0) {
# Resolve cache roots before the install so failure reporting cannot create a newer npm log.
$npmDebugLogRoots = @(Get-NpmDebugLogRootCandidates)
$npmInstallArguments = @("install", "-g") + $freshnessArgs + @("$installSpec")
$npmOutput = Invoke-NpmCommand -Arguments $npmInstallArguments 2>&1
$npmInstallStatus = $LASTEXITCODE
if ($npmInstallStatus -ne 0) {
Write-Host "[!] npm install failed; retrying once" -ForegroundColor Yellow
$npmOutput = Invoke-NpmCommand -Arguments $npmInstallArguments 2>&1
$npmInstallStatus = $LASTEXITCODE
}
if ($npmInstallStatus -ne 0) {
Write-Host "[!] npm install failed" -ForegroundColor Red
if ($npmOutput -match "spawn git" -or $npmOutput -match "ENOENT.*git") {
Write-Host "Error: git is missing from PATH." -ForegroundColor Red
@@ -1349,7 +1362,7 @@ function Install-OpenClaw {
Write-Host "Re-run with verbose output to see the full error:" -ForegroundColor Yellow
Write-Host ' powershell -c "irm https://openclaw.ai/install.ps1 | iex"' -ForegroundColor Cyan
}
Write-NpmInstallFailureDetails -Output $npmOutput
Write-NpmInstallFailureDetails -Output $npmOutput -CacheRoots $npmDebugLogRoots
return $false
}
} finally {
+9 -7
View File
@@ -531,6 +531,12 @@ describe("install.ps1 failure handling", () => {
it("runs npm install through the resolved command with quiet CI defaults", () => {
const npmInstallBody = extractFunctionBody(source, "Install-OpenClaw");
expect(npmInstallBody).toContain("$npmOutput = Invoke-NpmCommand -Arguments");
expect(npmInstallBody).toContain("$npmDebugLogRoots = @(Get-NpmDebugLogRootCandidates)");
expect(npmInstallBody).toContain('$npmInstallArguments = @("install", "-g")');
expect(npmInstallBody).toContain('Write-Host "[!] npm install failed; retrying once"');
expect(
npmInstallBody.match(/Invoke-NpmCommand -Arguments \$npmInstallArguments/g),
).toHaveLength(2);
expect(npmInstallBody).toContain('$env:NPM_CONFIG_LOGLEVEL = "error"');
expect(npmInstallBody).toContain('$env:NPM_CONFIG_UPDATE_NOTIFIER = "false"');
expect(npmInstallBody).toContain('$env:NPM_CONFIG_FUND = "false"');
@@ -540,18 +546,14 @@ describe("install.ps1 failure handling", () => {
expect(npmInstallBody).toContain("Remove-Item Env:NPM_CONFIG_BEFORE");
expect(npmInstallBody).toContain("Remove-Item Env:NPM_CONFIG_MIN_RELEASE_AGE");
expect(npmInstallBody).toContain('$env:NODE_LLAMA_CPP_SKIP_DOWNLOAD = "1"');
expect(npmInstallBody).toContain(
[
"$npmOutput = Invoke-NpmCommand -Arguments",
'(@("install", "-g") + $freshnessArgs + @("$installSpec"))',
].join(" "),
);
expect(npmInstallBody).toContain("$env:NPM_CONFIG_LOGLEVEL = $prevLogLevel");
expect(npmInstallBody).toContain("$env:NPM_CONFIG_BEFORE = $prevBefore");
expect(npmInstallBody).toContain(
"$env:NODE_LLAMA_CPP_SKIP_DOWNLOAD = $prevNodeLlamaSkipDownload",
);
expect(npmInstallBody).toContain("Write-NpmInstallFailureDetails -Output $npmOutput");
expect(npmInstallBody).toContain(
"Write-NpmInstallFailureDetails -Output $npmOutput -CacheRoots $npmDebugLogRoots",
);
expect(source).toContain("function Get-LatestNpmDebugLogPath {");
expect(source).toContain("Get-Content -LiteralPath $latestLog -Tail 120");
});