You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Plugins using npm dist-tags (e.g. @dev) never auto-update due to bun lockfile caching #12712
When a plugin is configured with an npm dist-tag specifier (e.g. "oc-solomemory@dev"), BunProc.install() resolves the tag to a concrete version on first install and writes it into bun.lock. On subsequent startups, bun sees the specifier "dev" hasn't changed, trusts the lockfile, and skips re-resolving — even though the dist-tag now points to a newer version on npm.
This means plugins using dist-tags like @dev, @beta, @canary, @next etc. are effectively pinned to whatever version was first installed, and never auto-update.
Steps to Reproduce
Configure a plugin with a dist-tag: "plugin": ["my-plugin@dev"]
Publish a new version to the same dist-tag (e.g. 1.0.7-dev.20260208144503.def5678)
Restart opencode — plugin stays on the old version
Root Cause
In packages/opencode/src/bun/index.ts (around line 78), BunProc.install() compares the specifier from config against what's in package.json. Since both are "dev", it either skips install entirely or runs bun install which is a no-op due to the lockfile.
Deleting just bun.lock is insufficient — bun also short-circuits when node_modules/<package> already exists. Both bun.lock AND the cached node_modules/<package> directory must be deleted to force re-resolution.
Current Workaround
rm -rf ~/.cache/opencode/node_modules/<plugin-name>~/.cache/opencode/bun.lock
# Then restart opencode
Suggested Fix
For plugin specifiers that are dist-tags (not semver ranges or exact versions), BunProc.install() should either:
Pass --force to bun for dist-tag specifiers, forcing re-resolution on every startup
Delete the lockfile entry for dist-tag plugins before running bun install
Run bun update <package> instead of bun install when the specifier is a dist-tag
Detection heuristic: if the specifier after @ is not a valid semver range (i.e. doesn't start with a digit, ^, ~, >=, etc.), it's a dist-tag.
The problem is how bun add --exact writes different dist-tags to package.json:
Config specifier
bun add --exact writes to package.json
=== "latest"
=== "dev"
Behavior
my-plugin@latest
"3.3.2" (resolved semver)
"3.3.2" === "latest" → false
—
Always re-installs ✅
my-plugin@dev
"dev" (literal tag)
—
"dev" === "dev" → true
Skips forever ❌
my-plugin@beta
"beta" (literal tag)
—
—
Skips forever ❌
my-plugin@canary
"canary" (literal tag)
—
—
Skips forever ❌
bun add --exact only resolves @latest to a concrete version. All other dist-tags (@dev, @beta, @next, @canary, etc.) are written literally, which means the === check always passes and the plugin never updates.
@latest accidentally self-heals because the cached value (e.g. "3.3.2") never string-matches "latest", forcing a re-install on every startup.
Suggested Fix
For non-latest dist-tags, the equality check needs to resolve the tag before comparing, or alternatively always re-run bun add when the specifier is a dist-tag (not a semver):
functionisDistTag(version: string): boolean{// dist-tags are non-semver strings like "dev", "beta", "next", "canary"return!/^[\d^~>=<]/.test(version)&&version!=="latest"}// In install():if(dependencies[pkg]===version&&modExists&&!isDistTag(version))returnmod
This would make all dist-tags behave like @latest — always re-resolve on startup.
Activity
github-actions commentedon Feb 8, 2026
This issue might be a duplicate of existing issues. Please check:
@latestnever update on restart #12312: Plugins with npm dist-tags other than@latestnever update on restartFeel free to ignore if none of these address your specific case.
ErcinDedeoglu commentedon Feb 8, 2026
Root Cause Found
The issue is in
BunProc.install()atpackages/opencode/src/bun/index.tsline 78:This compares the cached specifier in
~/.cache/opencode/package.jsonagainst the config specifier. The install command usesbun add --force --exact:The problem is how
bun add --exactwrites different dist-tags topackage.json:bun add --exactwrites to package.json=== "latest"=== "dev"my-plugin@latest"3.3.2"(resolved semver)"3.3.2" === "latest"→ falsemy-plugin@dev"dev"(literal tag)"dev" === "dev"→ truemy-plugin@beta"beta"(literal tag)my-plugin@canary"canary"(literal tag)bun add --exactonly resolves@latestto a concrete version. All other dist-tags (@dev,@beta,@next,@canary, etc.) are written literally, which means the===check always passes and the plugin never updates.@latestaccidentally self-heals because the cached value (e.g."3.3.2") never string-matches"latest", forcing a re-install on every startup.Suggested Fix
For non-
latestdist-tags, the equality check needs to resolve the tag before comparing, or alternatively always re-runbun addwhen the specifier is a dist-tag (not a semver):This would make all dist-tags behave like
@latest— always re-resolve on startup.github-actions commentedon Apr 10, 2026
To stay organized issues are automatically closed after 90 days of no activity. If the issue is still relevant please open a new one.