From 6c3538f8884a4ee33633ba6c7bd7fb8118a74fa5 Mon Sep 17 00:00:00 2001 From: Julian lechner Date: Thu, 17 Sep 2026 21:48:29 +0200 Subject: [PATCH] feat(install-options): add npm CLI reinstall helpers (PowerShell) Test-GlobalNpmPackage, Get-CliNpmPackage, Read-CliReinstallOption, and Invoke-CliReinstall let install.ps1 offer uninstalling and reinstalling a client CLI through npm. Not wired into install.ps1 yet. Co-Authored-By: Claude Sonnet 5 --- scripts/lib/install-options.ps1 | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/scripts/lib/install-options.ps1 b/scripts/lib/install-options.ps1 index cee229f..2e8ba9d 100644 --- a/scripts/lib/install-options.ps1 +++ b/scripts/lib/install-options.ps1 @@ -46,6 +46,61 @@ function Test-GlobalNpmCodex { } } +function Test-GlobalNpmPackage { + param([Parameter(Mandatory=$true)][string]$Package) + $npm = Get-Command npm -ErrorAction SilentlyContinue + if (-not $npm) { return $false } + $previousPreference = $ErrorActionPreference + try { + $ErrorActionPreference = 'Continue' + & $npm list -g $Package --depth=0 --json 1>$null 2>$null + return $LASTEXITCODE -eq 0 + } finally { + $ErrorActionPreference = $previousPreference + } +} + +function Get-CliNpmPackage { + param([ValidateSet('codex','claude')][Parameter(Mandatory=$true)][string]$Client) + if ($Client -eq 'codex') { return '@openai/codex' } + return '@anthropic-ai/claude-code' +} + +function Read-CliReinstallOption { + <# + .SYNOPSIS + Asked once per install run, never persisted; a dry run never prompts and never previews it. + #> + param([string]$Client, [switch]$DryRun) + if ($DryRun) { return $false } + return Read-InstallBoolean -Prompt "Uninstall $Client and reinstall via npm?" -Default $false +} + +function Invoke-CliReinstall { + param([string]$Client, [switch]$DryRun, [switch]$Summary) + $clients = if ($Client -eq 'Both') { @('codex', 'claude') } else { @($Client.ToLowerInvariant()) } + $previousAutoUpdate = $env:CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE + try { + $env:CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE = '1' + foreach ($selectedClient in $clients) { + if ($selectedClient -eq 'codex' -and -not $DryRun -and (Test-CodexProcessActive)) { + Write-Warning 'Codex CLI reinstall skipped because codex.exe is running. Close all Codex sessions and run install again to reinstall the CLI.' + continue + } + $package = Get-CliNpmPackage -Client $selectedClient + if (Test-GlobalNpmPackage -Package $package) { + Invoke-PluginCommand -Command 'npm' -Arguments @('uninstall', '-g', $package) -DryRun:$DryRun -Summary:$Summary + } else { + Write-Warning "$selectedClient CLI was not found as a global npm package; a non-npm installation cannot be removed automatically. Installing $package via npm alongside it." + } + Invoke-PluginCommand -Command 'npm' -Arguments @('install', '-g', "$package@latest") -DryRun:$DryRun -Summary:$Summary + if ($Summary) { Write-Output "CLI $selectedClient reinstall: $(if ($DryRun) { 'dry-run' } else { 'PASS' })" } + } + } finally { + $env:CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE = $previousAutoUpdate + } +} + function Update-SelectedAgentClis { param([string]$Client, [switch]$DryRun, [switch]$Summary) $clients = if ($Client -eq 'Both') { @('codex', 'claude') } else { @($Client.ToLowerInvariant()) }