fix: fall back to Windows PowerShell 5.1 when pwsh is missing

The installer wrote a hardcoded pwsh.exe path into settings.json even when
PowerShell 7 was not installed, so Claude Code ran a nonexistent binary and
the statusline silently failed to render. Now detect the available host
(prefer pwsh 7, fall back to Windows PowerShell 5.1 which ships with every
Windows install) and add an end-to-end self-test so a broken host path is
caught at install time instead of silently at runtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C4QKwZ7bC7oCMVtnuJdDKm
This commit is contained in:
André Bezek
2026-07-19 12:19:27 +02:00
co-authored by Claude Opus 4.8
parent 6252310229
commit 104903e29d
+36 -10
View File
@@ -127,17 +127,23 @@ $wrapperTarget = Join-Path $claude 'cship-statusline.ps1'
Copy-Item (Join-Path $assets 'cship-statusline.ps1') $wrapperTarget -Force Copy-Item (Join-Path $assets 'cship-statusline.ps1') $wrapperTarget -Force
Write-Ok "cship-statusline.ps1 -> $claude" Write-Ok "cship-statusline.ps1 -> $claude"
# --- 4. Locate pwsh --------------------------------------------------------- # --- 4. Locate a PowerShell host --------------------------------------------
# Prefer PowerShell 7 (pwsh). If it isn't installed, fall back to Windows
# PowerShell 5.1 (powershell.exe) which ships with every Windows install and
# runs the wrapper correctly - so the statusline works out of the box instead
# of pointing at a non-existent pwsh.exe and silently rendering nothing.
$pwsh = (Get-Command pwsh -ErrorAction SilentlyContinue).Source $pwsh = (Get-Command pwsh -ErrorAction SilentlyContinue).Source
if (-not $pwsh) { if (-not $pwsh -and (Test-Path 'C:\Program Files\PowerShell\7\pwsh.exe')) {
$fallback = 'C:\Program Files\PowerShell\7\pwsh.exe' $pwsh = 'C:\Program Files\PowerShell\7\pwsh.exe'
if (Test-Path $fallback) {
$pwsh = $fallback
} else {
Write-Warn "PowerShell 7 (pwsh) not found. Install it, then re-run this script."
Write-Warn " winget install --id Microsoft.PowerShell -e"
$pwsh = $fallback # write the conventional path so it works once pwsh is installed
} }
if (-not $pwsh) {
$pwsh = (Get-Command powershell -ErrorAction SilentlyContinue).Source
if (-not $pwsh) {
$pwsh = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'
}
Write-Warn "PowerShell 7 (pwsh) not found - using Windows PowerShell 5.1."
Write-Warn " For sharper rendering, install PS7 and re-run this script:"
Write-Warn " winget install --id Microsoft.PowerShell -e"
} }
$pwshFwd = $pwsh.Replace('\', '/') $pwshFwd = $pwsh.Replace('\', '/')
$wrapperFwd = $wrapperTarget.Replace('\', '/') $wrapperFwd = $wrapperTarget.Replace('\', '/')
@@ -160,7 +166,27 @@ if ($settings.PSObject.Properties.Name -contains 'statusLine') {
} }
$settings | ConvertTo-Json -Depth 20 | Set-Content $settingsPath -Encoding UTF8 $settings | ConvertTo-Json -Depth 20 | Set-Content $settingsPath -Encoding UTF8
Write-Ok "settings.json statusLine wired to detected pwsh" Write-Ok "settings.json statusLine wired to $([IO.Path]::GetFileName($pwsh))"
# --- 5b. End-to-end self-test -----------------------------------------------
# Actually run the configured host + wrapper against a sample Status payload so
# a broken host path (the classic "no statusline appears" failure) is caught
# here rather than silently at runtime, where Claude Code just shows nothing.
$sample = '{"hook_event_name":"Status","model":{"display_name":"Opus"},' +
'"workspace":{"current_dir":"' + ($claude -replace '\\','/') + '",' +
'"project_dir":"' + ($claude -replace '\\','/') + '"},' +
'"context_window":{"used_tokens":1000}}'
try {
$probe = $sample | & $pwsh -NoProfile -ExecutionPolicy Bypass -File $wrapperTarget 2>$null
if ([string]::IsNullOrWhiteSpace(($probe -join ''))) {
Write-Warn "Self-test produced no output - the statusline may not render."
Write-Warn " Check that '$pwsh' runs and that cship.exe is present."
} else {
Write-Ok "Self-test passed - statusline renders."
}
} catch {
Write-Warn "Self-test could not run the host: $($_.Exception.Message)"
}
# --- 6. Nerd Font (safety net, per-user) ------------------------------------ # --- 6. Nerd Font (safety net, per-user) ------------------------------------
if ($SkipFont) { if ($SkipFont) {