From 0a8cdec697ee5830a1df23c5e1f247fa1f2efefd Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:39:33 -0700 Subject: [PATCH] fix(desktop): silence wsl.exe stderr banner + detached explorer relaunch rung Follow-ups to the salvaged WSL-bridge gating (#66447): - wsl-path-bridge.ts: discard wsl.exe stderr so the 'WSL is not installed' banner can never leak into an attached console on WSL-less machines (#80184). - scripts/desktop-update/windows.ps1: add an explorer.exe-mediated detached relaunch rung between the WMI attempt and the tethered Start-Process fallback. When Win32_Process.Create fails (observed ReturnValue 8), the Desktop no longer re-attaches to the hand-off console, so its stdout stops flooding the window and the console can close. --- apps/desktop/electron/wsl-path-bridge.ts | 5 +++ scripts/desktop-update/windows.ps1 | 53 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/apps/desktop/electron/wsl-path-bridge.ts b/apps/desktop/electron/wsl-path-bridge.ts index 74b991643c..feff32a2f7 100644 --- a/apps/desktop/electron/wsl-path-bridge.ts +++ b/apps/desktop/electron/wsl-path-bridge.ts @@ -86,6 +86,11 @@ export function resolveDefaultWslDistro(): string { const out = execFileSync('wsl.exe', ['-l', '-q'], { encoding: 'utf8', env: { ...process.env, WSL_UTF8: '1' }, + // On WSL-less machines wsl.exe prints "The Windows Subsystem for Linux + // is not installed..." to stderr; stderr is inherited by default, so + // that banner leaks into whatever console the app is attached to + // (visible e.g. during the update hand-off). Discard it. (#80184) + stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, windowsHide: true }) diff --git a/scripts/desktop-update/windows.ps1 b/scripts/desktop-update/windows.ps1 index f0bfd52839..5787519495 100644 --- a/scripts/desktop-update/windows.ps1 +++ b/scripts/desktop-update/windows.ps1 @@ -571,6 +571,59 @@ function Start-DesktopRelaunch { } catch { Write-HandoffLog "WARNING: WMI relaunch failed: $($_.Exception.Message); falling back" } + if (-not $spawned) { + # Middle rung: explorer.exe-mediated launch. On some machines + # Win32_Process.Create fails outright (observed ReturnValue 8, + # "unknown failure"), and the tethered fallback below re-attaches the + # Desktop to this console — its stdout then floods the console and the + # window can't close while the app lives. Explorer re-parents the + # target exactly like a normal shell launch, giving the same + # no-console detachment WMI would have. Explorer returns no pid, so + # verify by watching for a fresh Hermes process. + try { + $exeName = [System.IO.Path]::GetFileNameWithoutExtension($RelaunchExe) + $before = @(Get-Process -Name $exeName -ErrorAction SilentlyContinue | ForEach-Object { $_.Id }) + Start-Process -FilePath 'explorer.exe' -ArgumentList ('"{0}"' -f $RelaunchExe) | Out-Null + $explorerDeadline = (Get-Date).AddSeconds(15) + while ((Get-Date) -lt $explorerDeadline) { + $fresh = @(Get-Process -Name $exeName -ErrorAction SilentlyContinue | Where-Object { $before -notcontains $_.Id }) + if ($fresh.Count -gt 0) { + Write-HandoffLog "desktop relaunched detached via explorer (pid $($fresh[0].Id))" + $spawned = $true + # Same foreground hand-off as the WMI rung: the new process + # starts unfocused and only the current foreground owner + # (us) can delegate that right. + try { + if ($script:Win32) { + [HermesHandoff.Win32]::AllowSetForegroundWindow([int]$fresh[0].Id) | Out-Null + $focusDeadline = (Get-Date).AddSeconds(20) + while ((Get-Date) -lt $focusDeadline) { + $hwnd = [System.IntPtr]::Zero + try { $hwnd = (Get-Process -Id $fresh[0].Id -ErrorAction Stop).MainWindowHandle } catch { break } + if ($hwnd -ne [System.IntPtr]::Zero) { + [HermesHandoff.Win32]::ShowWindow($hwnd, 9) | Out-Null # SW_RESTORE + [HermesHandoff.Win32]::SetForegroundWindow($hwnd) | Out-Null + Write-HandoffLog "focused relaunched desktop window" + break + } + Start-Sleep -Milliseconds 400 + } + } + } catch { + Write-HandoffLog "WARNING: could not focus relaunched desktop: $($_.Exception.Message)" + } + break + } + Start-Sleep -Milliseconds 400 + if ($script:Ui) { [System.Windows.Forms.Application]::DoEvents() } + } + if (-not $spawned) { + Write-HandoffLog "WARNING: explorer relaunch did not produce a $exeName process; falling back" + } + } catch { + Write-HandoffLog "WARNING: explorer relaunch failed: $($_.Exception.Message); falling back" + } + } if (-not $spawned) { try { # Fallback keeps the old behavior (console tie-in and all) --