Skip to content

Commit bfc0bd9

Browse files
authored
fix(installer): consolidate windows install reliability (#85)
1 parent 79adf1b commit bfc0bd9

File tree

2 files changed

+124
-28
lines changed

2 files changed

+124
-28
lines changed

.github/workflows/install-smoke.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,36 @@ jobs:
102102

103103
- name: Run git smoke (install-cli.sh)
104104
run: docker run --rm -t openclaw-install-cli-git-smoke:ci
105+
106+
windows-install-verify:
107+
runs-on: ${{ matrix.os }}
108+
strategy:
109+
fail-fast: false
110+
matrix:
111+
os: [windows-2022, windows-latest]
112+
node: [22, 24]
113+
steps:
114+
- name: Checkout
115+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
116+
117+
- name: Setup Node.js
118+
uses: actions/setup-node@v4
119+
with:
120+
node-version: ${{ matrix.node }}
121+
122+
- name: Install via install.ps1
123+
shell: pwsh
124+
run: .\public\install.ps1 -NoOnboard -InstallMethod npm
125+
126+
- name: Verify command resolution and shim location
127+
shell: pwsh
128+
run: |
129+
$cmd = Get-Command openclaw.cmd -ErrorAction Stop
130+
& $cmd.Source --version
131+
132+
$prefix = (npm config get prefix 2>$null).Trim()
133+
$rootShim = Join-Path $prefix "openclaw.cmd"
134+
$binShim = Join-Path (Join-Path $prefix "bin") "openclaw.cmd"
135+
if (-not ((Test-Path $rootShim) -or (Test-Path $binShim))) {
136+
throw "openclaw.cmd was not found in npm global prefix candidates."
137+
}

public/install.ps1

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,11 @@ function Install-Node {
125125

126126
# Check for existing OpenClaw installation
127127
function Check-ExistingOpenClaw {
128-
try {
129-
$null = Get-Command openclaw -ErrorAction Stop
130-
Write-Host "[*] Existing OpenClaw installation detected" -ForegroundColor Yellow
131-
return $true
132-
} catch {
133-
return $false
128+
if (Get-OpenClawCommandPath) {
129+
Write-Host "[*] Existing OpenClaw installation detected" -ForegroundColor Yellow
130+
return $true
134131
}
132+
return $false
135133
}
136134

137135
function Check-Git {
@@ -153,8 +151,53 @@ function Require-Git {
153151
exit 1
154152
}
155153

154+
function Get-OpenClawCommandPath {
155+
$openclawCmd = Get-Command openclaw.cmd -ErrorAction SilentlyContinue
156+
if ($openclawCmd -and $openclawCmd.Source) {
157+
return $openclawCmd.Source
158+
}
159+
160+
$openclaw = Get-Command openclaw -ErrorAction SilentlyContinue
161+
if ($openclaw -and $openclaw.Source) {
162+
return $openclaw.Source
163+
}
164+
165+
return $null
166+
}
167+
168+
function Invoke-OpenClawCommand {
169+
param(
170+
[Parameter(ValueFromRemainingArguments = $true)]
171+
[string[]]$Arguments
172+
)
173+
174+
$commandPath = Get-OpenClawCommandPath
175+
if (-not $commandPath) {
176+
throw "openclaw command not found on PATH."
177+
}
178+
179+
& $commandPath @Arguments
180+
}
181+
182+
function Get-NpmGlobalBinCandidates {
183+
param(
184+
[string]$NpmPrefix
185+
)
186+
187+
$candidates = @()
188+
if (-not [string]::IsNullOrWhiteSpace($NpmPrefix)) {
189+
$candidates += $NpmPrefix
190+
$candidates += (Join-Path $NpmPrefix "bin")
191+
}
192+
if (-not [string]::IsNullOrWhiteSpace($env:APPDATA)) {
193+
$candidates += (Join-Path $env:APPDATA "npm")
194+
}
195+
196+
return $candidates | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique
197+
}
198+
156199
function Ensure-OpenClawOnPath {
157-
if (Get-Command openclaw -ErrorAction SilentlyContinue) {
200+
if (Get-OpenClawCommandPath) {
158201
return $true
159202
}
160203

@@ -165,23 +208,28 @@ function Ensure-OpenClawOnPath {
165208
$npmPrefix = $null
166209
}
167210

168-
if (-not [string]::IsNullOrWhiteSpace($npmPrefix)) {
169-
$npmBin = Join-Path $npmPrefix "bin"
211+
$npmBins = Get-NpmGlobalBinCandidates -NpmPrefix $npmPrefix
212+
foreach ($npmBin in $npmBins) {
213+
if (-not (Test-Path (Join-Path $npmBin "openclaw.cmd"))) {
214+
continue
215+
}
216+
170217
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
171218
if (-not ($userPath -split ";" | Where-Object { $_ -ieq $npmBin })) {
172219
[Environment]::SetEnvironmentVariable("Path", "$userPath;$npmBin", "User")
173220
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
174221
Write-Host "[!] Added $npmBin to user PATH (restart terminal if command not found)" -ForegroundColor Yellow
175222
}
176-
if (Test-Path (Join-Path $npmBin "openclaw.cmd")) {
177-
return $true
178-
}
223+
return $true
179224
}
180225

181226
Write-Host "[!] openclaw is not on PATH yet." -ForegroundColor Yellow
182-
Write-Host "Restart PowerShell or add the npm global bin folder to PATH." -ForegroundColor Yellow
183-
if ($npmPrefix) {
184-
Write-Host "Expected path: $npmPrefix\\bin" -ForegroundColor Cyan
227+
Write-Host "Restart PowerShell or add the npm global install folder to PATH." -ForegroundColor Yellow
228+
if ($npmBins.Count -gt 0) {
229+
Write-Host "Expected path (one of):" -ForegroundColor Gray
230+
foreach ($npmBin in $npmBins) {
231+
Write-Host " $npmBin" -ForegroundColor Cyan
232+
}
185233
} else {
186234
Write-Host "Hint: run \"npm config get prefix\" to find your npm global path." -ForegroundColor Gray
187235
}
@@ -205,7 +253,13 @@ function Ensure-Pnpm {
205253
}
206254
}
207255
Write-Host "[*] Installing pnpm..." -ForegroundColor Yellow
208-
npm install -g pnpm
256+
$prevScriptShell = $env:NPM_CONFIG_SCRIPT_SHELL
257+
$env:NPM_CONFIG_SCRIPT_SHELL = "cmd.exe"
258+
try {
259+
npm install -g pnpm
260+
} finally {
261+
$env:NPM_CONFIG_SCRIPT_SHELL = $prevScriptShell
262+
}
209263
Write-Host "[OK] pnpm installed" -ForegroundColor Green
210264
}
211265

@@ -224,10 +278,12 @@ function Install-OpenClaw {
224278
$prevUpdateNotifier = $env:NPM_CONFIG_UPDATE_NOTIFIER
225279
$prevFund = $env:NPM_CONFIG_FUND
226280
$prevAudit = $env:NPM_CONFIG_AUDIT
281+
$prevScriptShell = $env:NPM_CONFIG_SCRIPT_SHELL
227282
$env:NPM_CONFIG_LOGLEVEL = "error"
228283
$env:NPM_CONFIG_UPDATE_NOTIFIER = "false"
229284
$env:NPM_CONFIG_FUND = "false"
230285
$env:NPM_CONFIG_AUDIT = "false"
286+
$env:NPM_CONFIG_SCRIPT_SHELL = "cmd.exe"
231287
try {
232288
$npmOutput = npm install -g "$packageName@$Tag" 2>&1
233289
if ($LASTEXITCODE -ne 0) {
@@ -248,6 +304,7 @@ function Install-OpenClaw {
248304
$env:NPM_CONFIG_UPDATE_NOTIFIER = $prevUpdateNotifier
249305
$env:NPM_CONFIG_FUND = $prevFund
250306
$env:NPM_CONFIG_AUDIT = $prevAudit
307+
$env:NPM_CONFIG_SCRIPT_SHELL = $prevScriptShell
251308
}
252309
Write-Host "[OK] OpenClaw installed" -ForegroundColor Green
253310
}
@@ -280,11 +337,17 @@ function Install-OpenClawFromGit {
280337

281338
Remove-LegacySubmodule -RepoDir $RepoDir
282339

283-
pnpm -C $RepoDir install
284-
if (-not (pnpm -C $RepoDir ui:build)) {
285-
Write-Host "[!] UI build failed; continuing (CLI may still work)" -ForegroundColor Yellow
340+
$prevPnpmScriptShell = $env:NPM_CONFIG_SCRIPT_SHELL
341+
$env:NPM_CONFIG_SCRIPT_SHELL = "cmd.exe"
342+
try {
343+
pnpm -C $RepoDir install
344+
if (-not (pnpm -C $RepoDir ui:build)) {
345+
Write-Host "[!] UI build failed; continuing (CLI may still work)" -ForegroundColor Yellow
346+
}
347+
pnpm -C $RepoDir build
348+
} finally {
349+
$env:NPM_CONFIG_SCRIPT_SHELL = $prevPnpmScriptShell
286350
}
287-
pnpm -C $RepoDir build
288351

289352
$binDir = Join-Path $env:USERPROFILE ".local\\bin"
290353
if (-not (Test-Path $binDir)) {
@@ -309,7 +372,7 @@ function Install-OpenClawFromGit {
309372
function Run-Doctor {
310373
Write-Host "[*] Running doctor to migrate settings..." -ForegroundColor Yellow
311374
try {
312-
openclaw doctor --non-interactive
375+
Invoke-OpenClawCommand doctor --non-interactive
313376
} catch {
314377
# Ignore errors from doctor
315378
}
@@ -318,7 +381,7 @@ function Run-Doctor {
318381

319382
function Test-GatewayServiceLoaded {
320383
try {
321-
$statusJson = (openclaw daemon status --json 2>$null)
384+
$statusJson = (Invoke-OpenClawCommand daemon status --json 2>$null)
322385
if ([string]::IsNullOrWhiteSpace($statusJson)) {
323386
return $false
324387
}
@@ -333,7 +396,7 @@ function Test-GatewayServiceLoaded {
333396
}
334397

335398
function Refresh-GatewayServiceIfLoaded {
336-
if (-not (Get-Command openclaw -ErrorAction SilentlyContinue)) {
399+
if (-not (Get-OpenClawCommandPath)) {
337400
return
338401
}
339402
if (-not (Test-GatewayServiceLoaded)) {
@@ -342,15 +405,15 @@ function Refresh-GatewayServiceIfLoaded {
342405

343406
Write-Host "[*] Refreshing loaded gateway service..." -ForegroundColor Yellow
344407
try {
345-
openclaw gateway install --force | Out-Null
408+
Invoke-OpenClawCommand gateway install --force | Out-Null
346409
} catch {
347410
Write-Host "[!] Gateway service refresh failed; continuing." -ForegroundColor Yellow
348411
return
349412
}
350413

351414
try {
352-
openclaw gateway restart | Out-Null
353-
openclaw gateway status --probe --json | Out-Null
415+
Invoke-OpenClawCommand gateway restart | Out-Null
416+
Invoke-OpenClawCommand gateway status --probe --json | Out-Null
354417
Write-Host "[OK] Gateway service refreshed" -ForegroundColor Green
355418
} catch {
356419
Write-Host "[!] Gateway service restart failed; continuing." -ForegroundColor Yellow
@@ -446,7 +509,7 @@ function Main {
446509

447510
$installedVersion = $null
448511
try {
449-
$installedVersion = (openclaw --version 2>$null).Trim()
512+
$installedVersion = (Invoke-OpenClawCommand --version 2>$null).Trim()
450513
} catch {
451514
$installedVersion = $null
452515
}
@@ -528,7 +591,7 @@ function Main {
528591
} else {
529592
Write-Host "Starting setup..." -ForegroundColor Cyan
530593
Write-Host ""
531-
openclaw onboard
594+
Invoke-OpenClawCommand onboard
532595
}
533596
}
534597
}

0 commit comments

Comments
 (0)