Skip to content

feat(desktop): ship the CLI as opencode and put it on the Windows PATH - #56897

Open
Hona wants to merge 2 commits into
devfrom
cli-on-path
Open

Hona wants to merge 2 commits into
devfrom
cli-on-path

Conversation

@Hona

@Hona Hona commented Oct 18, 2026

Copy link
Copy Markdown
Member
  • The bundled CLI is now opencode / opencode.exe (was opencode-cli) on every platform. That covers resources, staging, the version file, mac signing entitlements, dev builds and the Windows signature check in publish.yml.
  • On Windows, typing opencode in any new terminal now runs the desktop's CLI.

Why a link directory

Each version stages its CLI in its own folder (<userData>\cli\<version>-<arch>\), because Windows cannot replace an exe that is still running. Putting that folder on PATH would mean editing PATH on every update. Instead, PATH gets one fixed folder that holds a hard link to the current stage:

flowchart LR
  PATH["User PATH<br/>%APPDATA%\ai.opencode.desktop\bin"] --> link["bin\opencode.exe<br/>(hard link)"]
  link --> stage["cli\2.1.0-x64\opencode.exe"]
  old["cli\2.0.20-x64\opencode.exe"] -. "cleanStages" .-> gone((removed))
Loading
  • PATH is edited once. It is edited only on the launch that creates bin\. If the user removes the entry, it stays removed.
  • No extra disk use. The hard link uses no space, and an update only moves the link. If a hard link is not possible, the app copies the exe instead.
  • Safe while the CLI runs. If a terminal is still running the old link, the app renames it to *.old (Windows allows renaming a running exe) and deletes it on a later launch.
  • Outside $INSTDIR. The installer stops every process that runs from the install directory. A link there would kill open TUI sessions on every update.
  • Existing installs win. The entry goes at the end of the user PATH, so a curl, npm or winget opencode that is already on PATH keeps priority.

PATH editing

cli-path.ts makes a one-time call to Windows PowerShell off the startup path. It reads the raw registry value so %USERPROFILE% entries stay unexpanded and REG_EXPAND_SZ is kept. Then it broadcasts WM_SETTINGCHANGE so Explorer picks up the change:

$key = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Environment')
$entries = @(([string]$key.GetValue('Path', '', 'DoNotExpandEnvironmentNames')) -split ';' | Where-Object { $_ })
if ($entries -contains $directory) { exit 0 }
$key.SetValue('Path', (($entries + $directory) -join ';'), 'ExpandString')
[Environment]::SetEnvironmentVariable('OPENCODE_PATH_REFRESH', $null, 'User')  # broadcasts WM_SETTINGCHANGE
  • This avoids setx, which cuts PATH at 1024 characters, and [Environment]::SetEnvironmentVariable('Path', …), which rewrites PATH as REG_SZ.
  • A real uninstall (not an update) removes the PATH entry and bin\ in customUnInstall. A reinstall then adds them again.

@Hona
Hona requested a review from Brendonovich as a code owner October 18, 2026 23:12
Copilot AI balanced review requested due to automatic review settings October 18, 2026 23:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

Base automatically changed from beta to dev October 26, 2026 03:56

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants