OpenCode update targets a Vite+ shim that delegates to another install (shimMode system_first), then reports "still outdated"#22741

opened4d agobyCcoygeek

What happened

Clicking the OpenCode "Update" button (bottom bar) on a remote environment ("Mac Studio") ended with:

Update failed — Mac Studio · OpenCode: Update command completed, but T3 Code still detects an outdated provider version.

and a persistent "Mac Studio failed" pill. Retrying gave the same result.

Diagnosis

The provider maintenance resolver picked the wrong install to update. It ran vp i -g @opencode/cli, which installed 2.1.2 into a Vite+ copy that never runs, and left the copy that does run at 2.1.1.

Machine layout:

  • The OpenCode that actually runs is ~/.opencode/bin/opencode, a small sh wrapper that execs OpenCode 2 from a dedicated npm prefix (~/.opencode-v2/lib/node_modules/@opencode/cli). Version 2.1.1.
  • Vite+ 0.3.0 is installed and its bin dir ~/.local/share/vite-plus/bin comes before ~/.opencode/bin on the server's PATH. Vite+ also had an opencode shim registered (~/.local/share/vite-plus/bins/opencode.json, created weeks earlier).
  • ~/.config/vite-plus/config.json is {"shimMode": "system_first"}. In this mode a Vite+ shim runs the next matching executable on PATH, and only falls back to the Vite+-managed copy when there is none.

Sequence:

  1. resolveCommandPath("opencode") returns ~/.local/share/vite-plus/bin/opencode. In packages/provider-core/src/server/maintenanceResolver.ts, isVitePlusGlobalCommandPath matches that path, and resolvePackageManagedProviderMaintenance returns updateExecutable: "vp", updateArgs: ["i", "-g", "@opencode/cli"]. The cached advisory showed "updateCommand": "vp i -g @opencode/cli".
  2. vp i -g @opencode/cli succeeds: vp list -g shows @opencode/cli@2.1.2, and running the Vite+-managed binary directly prints opencode v2.1.2.
  3. Verification runs opencode --version through the same shim. Because of system_first, the shim delegates to ~/.opencode/bin/opencode, which prints opencode v2.1.1, so runCommandAndVerify reports the version as still outdated.

Shim behavior, observed directly:

1PATH=<vp>/bin:/usr/bin:/bin <vp>/bin/opencode --version -> opencode v2.1.2
2PATH=<vp>/bin:~/.opencode/bin:/usr/bin:/bin <vp>/bin/opencode --version -> opencode v2.1.1

A path inside <VP_HOME>/bin does not prove Vite+ owns the executable that runs. With shimMode: system_first, or when no Vite+ global package provides the binary, the shim runs some other install. The resolver then updates the Vite+ copy, and vp i -g also creates a new, unused Vite+ install of the provider.

Possible fixes:

  • Treat a Vite+ shim as Vite+-owned only when vp env which <cmd> (or an equivalent check) resolves into <VP_HOME>/packages. Otherwise resolve the next PATH entry and classify that instead.
  • Skip the Vite+ branch when shimMode is system_first and another candidate exists later on PATH.
  • When post-update verification fails, name the binary that was actually executed, so a shadowing install is visible to the user.

Not covered by the existing fix for #13010 (verification reads the installed CLI version, fe4ebc704): the installed CLI version is read correctly here, but from a different install than the one updated. main has no changes to maintenanceResolver.ts since this nightly.

Steps to reproduce

  1. On macOS, install Vite+ (0.3.0) with its bin dir first on PATH and set vp env off (writes "shimMode": "system_first").
  2. Install OpenCode 2 at an older version outside Vite+, e.g. in a dedicated npm prefix exposed through a directory later on PATH (here ~/.opencode/bin).
  3. Make Vite+ create an opencode shim in <VP_HOME>/bin, e.g. vp i -g @opencode/cli@<older version>. With system_first, the shim keeps running the step 2 install.
  4. Start T3 Code. OpenCode shows as outdated with update command vp i -g @opencode/cli.
  5. Click Update. The command succeeds, and T3 Code reports "Update command completed, but T3 Code still detects an outdated provider version."

Version

T3 Code 0.1.2-nightly.20261021.3457 (server t3 serve and the T3 Code (Nightly) desktop app on the affected machine; the UI was viewed from another Mac connected to it as a remote environment)

Environment

macOS 27.0.1 arm64, Node v26.12.0, Vite+ (vp) 0.3.0 with shimMode system_first, OpenCode 2.1.1 (@opencode/cli in a separate npm prefix) before the fix

Evidence

shell
1# T3 provider cache (~/.t3/caches/opencode.json) after the failed update
2"version": "2.1.1",
3"versionAdvisory": { "status": "behind_latest", "currentVersion": "2.1.1", "latestVersion": "2.1.2",
4 "updateCommand": "vp i -g @opencode/cli", ... }
5
6# Server trace: two update attempts, all spans exit Success
700:43:33 ProviderMaintenanceRunner.updateProvider -> runCommandAndVerify -> runCommand (7088 ms)
800:45:05 ProviderMaintenanceRunner.runCommandAndVerify -> runCommand
9
10# Vite+ state after the update
11$ vp list -g
12@opencode/cli@2.1.2 24.22.0 opencode, opencode2
13$ cat ~/.config/vite-plus/config.json
14{ "shimMode": "system_first" }
15
16# Server PATH order (excerpt)
17...:~/.local/share/vite-plus/bin:...:~/.opencode/bin:...
18
19# Which binary runs
20$ which -a opencode
21~/.local/share/vite-plus/bin/opencode
22~/.opencode/bin/opencode
23$ ~/.local/share/vite-plus/bin/opencode --version # under the server PATH
24opencode v2.1.1
25$ <vp packages>/@opencode/cli/<id>/bin/opencode --version
26opencode v2.1.2

Related issues

#2714 (OpenCode update used npm regardless of install method), #5629 (Codex npm install -g loop against unverified installs), #10050 (mise shims made updates target the version manager), #18768 (Homebrew Grok update installed a second off-PATH copy). Same family, different cause: this one is Vite+ shims in system_first mode delegating to another install. #13010 is fixed, and its fix does not cover this case.

Fix applied or workaround

On the affected machine: ran the real install's updater (~/.opencode/bin/opencode upgrade, 2.1.1 → 2.1.2), then vp remove -g @opencode/cli to drop the Vite+ copy and shim so opencode resolves to the real install again.

Filed by

Claude Code (claude-opus-5-5) via npx t3@nightly triage

Synced from GitHub

This still needs to stay open. At main 96bae546, the resolver still selects vp i -g @opencode/cli from the Vite+ shim path without checking system_first delegation; stable v0.1.1 has the same branch. #22745 is unmerged and explicitly reports that its runtime proof still fails because OpenCode's own updater can choose Vite+ again. #13010 and #22839 address stale server versions, not updating the wrong install. This was a source/history check, not a fresh live-update reproduction.