$ErrorActionPreference = "Stop" $LogFile = Join-Path $env:TEMP "xlight-reset.log" trap { ($_ | Out-String) | Out-File $LogFile -Append -Encoding UTF8 Write-Host "" Write-Host "XLight cleanup was not completed." -ForegroundColor Red Write-Host "Reason: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "Claude Code, Codex and Hermes were not uninstalled." Write-Host "Technical log: $LogFile" exit 1 } $Dest = Join-Path $HOME ".xlight" $Startup = [Environment]::GetFolderPath("Startup") $StartupFile = Join-Path $Startup "XLight Bridge.vbs" Write-Host "[1/4] Removing startup entries and stopping XLight processes..." Remove-Item $StartupFile -Force -ErrorAction SilentlyContinue Get-ScheduledTask -TaskName "XLight Bridge" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$false -ErrorAction SilentlyContinue for ($Attempt = 1; $Attempt -le 3; $Attempt++) { $Processes = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -and ( $_.CommandLine -like "*$Dest*" -or $_.CommandLine -like "*XLight Bridge.vbs*" -or $_.CommandLine -like "*xlight-daemon*" ) } foreach ($Process in $Processes) { if ($Process.ProcessId -ne $PID) { & cmd.exe /d /c "taskkill /PID $($Process.ProcessId) /T /F >nul 2>&1" } } foreach ($Image in @("python.exe", "pythonw.exe", "wscript.exe", "cscript.exe")) { & cmd.exe /d /c "taskkill /IM $Image /F >nul 2>&1" } Start-Sleep -Milliseconds 800 } Write-Host "[2/4] Removing XLight hooks from Claude Code and Codex..." $Markers = @("xlight", "chuncui-ble", "hook-client.mjs", "traffic_light", "traffic-monitor", "traffic_monitor") $ConfigFiles = @( (Join-Path $HOME ".claude\settings.json"), (Join-Path $HOME ".codex\hooks.json") ) foreach ($Path in $ConfigFiles) { if (-not (Test-Path $Path)) { continue } try { $Data = Get-Content $Path -Raw -Encoding UTF8 | ConvertFrom-Json } catch { Write-Warning "Skipping invalid JSON config: $Path" continue } if (-not $Data.hooks) { continue } foreach ($Event in @($Data.hooks.PSObject.Properties.Name)) { $Kept = @() foreach ($Entry in @($Data.hooks.$Event)) { $Remove = $false foreach ($Hook in @($Entry.hooks)) { $Command = [string]$Hook.command foreach ($Marker in $Markers) { if ($Command.ToLowerInvariant().Contains($Marker)) { $Remove = $true break } } if ($Remove) { break } } if (-not $Remove) { $Kept += $Entry } } if ($Kept.Count -gt 0) { $Data.hooks.$Event = $Kept } else { $Data.hooks.PSObject.Properties.Remove($Event) } } if (@($Data.hooks.PSObject.Properties).Count -eq 0) { $Data.PSObject.Properties.Remove("hooks") } $Json = $Data | ConvertTo-Json -Depth 20 $Utf8NoBom = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllText($Path, $Json + [Environment]::NewLine, $Utf8NoBom) } Write-Host "[3/4] Removing XLight files, logs and startup entry..." for ($Attempt = 1; $Attempt -le 5 -and (Test-Path $Dest); $Attempt++) { Remove-Item $Dest -Recurse -Force -ErrorAction SilentlyContinue if (Test-Path $Dest) { Start-Sleep -Seconds 1 } } Write-Host "[4/4] Verifying cleanup..." $Remaining = @() if (Test-Path $Dest) { $Remaining += $Dest } if (Test-Path $StartupFile) { $Remaining += $StartupFile } if ($Remaining.Count -gt 0) { Write-Host "Remaining paths:" $Remaining | ForEach-Object { Write-Host " $_" } throw "Cleanup did not finish. Restart Windows, then run this script once more before opening XLight or Claude Code." } Write-Host "" Write-Host "XLight cleanup completed successfully." -ForegroundColor Green Write-Host "Claude Code, Codex, Hermes, their sessions and unrelated settings were preserved." Write-Host "You can now test firmware upgrade and perform a clean XLight installation."