Skip to content

[Windows] Desktop 'Install and Restart' kills external opencode CLI TUI sessions, corrupts terminal state #24248

@mekwall

Description

@mekwall

Description

When the OpenCode Desktop app prompts the user to "Install and Restart" after detecting an update, it forcefully kills all running opencode.exe processes on the system — including external CLI TUI sessions that were launched independently from the terminal. These CLI sessions are killed without any graceful shutdown, leaving the terminal in a corrupted state with mouse tracking enabled, which floods the prompt with raw escape sequences like ^[[<35;77;46M.

Steps to reproduce

  1. Open two terminal tabs in Windows Terminal
  2. Launch opencode (CLI TUI) in both tabs — confirm they are running
  3. Launch OpenCode Desktop app
  4. If an update is available, the Desktop app shows an "Install and Restart" prompt
  5. Click "Install and Restart"
  6. Observe: Both CLI TUI sessions are immediately killed
  7. Observe: The terminal tabs where the CLI was running now show mouse escape sequences spamming the prompt (^[[<35;77;46M, ^[[<35;62;19M, etc.) and the shell becomes unresponsive

Expected behavior

  • The Desktop app should only terminate its own embedded sidecar (opencode-cli), not external opencode.exe CLI TUI processes
  • If external processes must be terminated, they should receive a graceful shutdown signal (SIGTERM) allowing the TUI to restore terminal state (disable mouse tracking, restore cooked mode, etc.)
  • Active user sessions should be preserved or the user should be warned before killing them

Actual behavior

  • All opencode.exe processes are forcefully killed (no graceful shutdown)
  • Terminal state is left corrupted: mouse tracking remains enabled, raw escape sequences flood the prompt
  • The shell in the affected terminal tab may become completely unresponsive, requiring the tab to be closed
  • Any active work in the CLI TUI sessions is lost

Technical Analysis

Root cause: The Desktop app's update flow calls killSidecar() (which correctly targets only the embedded sidecar child process) before update.install(). However, update.install() triggers the NSIS installer, which uses nsProcess::KillProcess to terminate the main application binary. Since the Desktop binary is named OpenCode.exe and the CLI binary is named opencode.exe, and nsProcess::KillProcess is case-insensitive on Windows, the NSIS installer matches and kills both OpenCode.exe (Desktop) AND opencode.exe (CLI TUI).

Evidence from source:

  • packages/desktop/src/updater.ts lines 41-50: The updater only calls commands.killSidecar() for its embedded sidecar
  • packages/desktop/src-tauri/tauri.conf.json: NSIS config has no custom hooks — relies on Tauri's default NSIS template behavior
  • packages/desktop/src-tauri/src/cli.rs lines 131-134: install_cli is explicitly disabled on Windows ("CLI installation is only supported on macOS & Linux")
  • The TUI has a win32InstallCtrlCGuard() for clean SIGINT handling, but this is bypassed by NSIS's forceful process termination

Suggested fixes:

  1. In the NSIS configuration, constrain the process kill to the exact binary name (case-sensitive match) or PID of the Desktop process specifically, rather than matching all opencode* processes
  2. Before triggering the NSIS installer, enumerate and gracefully terminate external opencode.exe processes with a SIGTERM + timeout, allowing them to clean up terminal state
  3. At minimum, show a confirmation dialog warning the user that other opencode sessions will be closed

Plugins

N/A

OpenCode version

  • Desktop: SST.OpenCodeDesktop 1.14.24 (via winget)
  • CLI: SST.opencode 1.14.22 (via winget)

Operating System

Windows 11

Terminal

Windows Terminal

Related Issues

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions