Skip to content

[bug] custom version suffix (1.2.27-vim.2) breaks plugin loading — @opencode-ai/plugin resolution fails #20

@MomePP

Description

@MomePP

Description

Hi, Thanks for the ocv fork — the vim keybindings are great.
After the upstream anthropic legal request (PR #18186) removed built-in Anthropic OAuth, Pro/Max subscribers need the community opencode-claude-auth plugin to authenticate. It works on upstream opencode@1.2.27 but fails to load on ocv due to a version suffix mismatch.

Note: This issue was investigated with the help of Claude — analysis of the compiled binary strings, upstream source, and npm registry to trace the root cause.

Summary

The ocv fork uses a custom version string 1.2.27-vim.2 (with the -vim.2 suffix) as Installation.VERSION. The opencode plugin system uses this version verbatim to resolve the @opencode-ai/plugin SDK from npm. Since @opencode-ai/plugin is only published under upstream version numbers (e.g. 1.2.27), the resolution fails with a 404, breaking all plugin loading.
Plugins appear in /status (read from config) but never actually function.

Environment

Component Version Install method
ocv 1.2.27-vim.2 brew install leohenon/tap/ocv
opencode (upstream) 1.2.27 brew install opencode
Plugin tested opencode-claude-auth@0.5.5 npm i -g opencode-claude-auth
Platform macOS arm64

Expected vs Actual

  • Expected: Plugins load and function the same way as upstream opencode, since ocv is based on the same 1.2.27 codebase.
  • Actual: Plugin loading silently fails. The -vim.2 suffix causes the plugin system to request a non-existent package version from npm.

Root Cause

The version suffix "-vim.2" propagates into two functions in the plugin dependency resolution pipeline (packages/opencode/src/config/config.ts), both of which use Installation.VERSION directly.

1. Version hardcoded in the binary

# Extracted from the compiled ocv binary:
Installation.VERSION = "1.2.27-vim.2";
# Versus upstream opencode:
Installation.VERSION = "1.2.27";

2. needsInstall() uses strict equality

const targetVersion = Installation.isLocal() ? "latest" : Installation.VERSION
// ocv: targetVersion = "1.2.27-vim.2"
// ...
if (depVersion === targetVersion) return false  // strict equality — no semver coercion
return true  // triggers reinstall

The cached @opencode-ai/plugin is at version "1.2.27" (installed by upstream opencode or a previous successful install). The check "1.2.27" === "1.2.27-vim.2" fails, so it always triggers a reinstall.

3. installDependencies() writes the unresolvable version

const targetVersion = Installation.isLocal() ? "*" : Installation.VERSION
json.dependencies = {
    ...json.dependencies,
    "@opencode-ai/plugin": targetVersion,  // writes "1.2.27-vim.2"
}
// then runs bun install → tries to fetch @opencode-ai/plugin@1.2.27-vim.2 → 404

4. The version does not exist on npm

$ npm view @opencode-ai/plugin@1.2.27-vim.2 version
npm error code E404
npm error 404 No match found for version 1.2.27-vim.2
npm error 404  The requested resource '@opencode-ai/plugin@1.2.27-vim.2' could not be found

Published versions (all upstream):

1.2.18, 1.2.19, 1.2.20, 1.2.21, 1.2.22, 1.2.23, 1.2.24, 1.2.25, 1.2.26, 1.2.27

Failure chain

ocv starts
  → Installation.VERSION = "1.2.27-vim.2"
  → Config.needsInstall()
    → depVersion ("1.2.27") !== targetVersion ("1.2.27-vim.2")
    → returns true → triggers install
  → Config.installDependencies()
    → writes "@opencode-ai/plugin": "1.2.27-vim.2" to ~/.cache/opencode/package.json
    → bun install → npm 404 → install fails
  → Config.waitForDependencies() completes (error caught silently)
  → Plugin loader attempts import → node_modules in broken/stale state → fails
  → Plugin visible in /status but non-functional

Secondary issue: shared cache conflict

Both opencode and ocv share ~/.cache/opencode/. They overwrite each other's @opencode-ai/plugin target version on every startup:

  1. opencode runs → writes "@opencode-ai/plugin": "1.2.27" → bun install succeeds
  2. ocv runs → writes "@opencode-ai/plugin": "1.2.27-vim.2" → bun install fails
  3. opencode runs → writes "1.2.27" again → succeeds
  4. (repeat)

Suggested Fix

The -vim.2 suffix is a semver prerelease identifier. The plugin SDK version should be derived from the base upstream version that ocv is forked from, not the full fork version string.

Option A — Strip prerelease suffix for plugin resolution

semver is already imported in the codebase.

// In both needsInstall() and installDependencies():
import semver from "semver"
const baseVersion = `${semver.major(Installation.VERSION)}.${semver.minor(Installation.VERSION)}.${semver.patch(Installation.VERSION)}`
const targetVersion = Installation.isLocal() ? "*" : baseVersion
// "1.2.27-vim.2" → "1.2.27"

Option B — Separate constant for upstream base version

Installation.VERSION = "1.2.27-vim.2"       // display / user-agent
Installation.UPSTREAM_VERSION = "1.2.27"    // plugin SDK resolution

Use UPSTREAM_VERSION in needsInstall() and installDependencies().

Option C — Separate cache directory (complementary)

// ~/.cache/ocv/ instead of ~/.cache/opencode/

Prevents the shared-cache conflict when both binaries are installed, but still needs Option A or B to resolve the core 404 issue.

References

ocv version

1.2.27-vim.2

Steps to reproduce

  1. Install ocv:
    brew install leohenon/tap/ocv
  2. Install a plugin globally:
    npm i -g opencode-claude-auth
  3. Add the plugin to ~/.config/opencode/opencode.json:
    {
      "plugin": ["opencode-claude-auth"]
    }
  4. Run ocv and open a session
  5. Type /status — plugin is listed under plugins
  6. Verify it's non-functional — Claude credentials are not synced to ~/.local/share/opencode/auth.json

To confirm the version mismatch is the cause:

# The version ocv uses for plugin SDK resolution:
strings $(which ocv) | grep 'Installation.VERSION'
# → Installation.VERSION = "1.2.27-vim.2";
# That version does not exist on npm:
npm view @opencode-ai/plugin@1.2.27-vim.2 version
# → npm error 404 No match found for version 1.2.27-vim.2
# The lockfile shows what's actually resolved (upstream version):
cat ~/.cache/opencode/bun.lock | grep '@opencode-ai/plugin'
# → "@opencode-ai/plugin": ["@opencode-ai/plugin@1.2.27", ...]
# Compare: upstream opencode works with the same plugin and config
opencode  # → plugin loads and functions correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions