Problem
When a plugin is configured with an npm dist-tag other than @latest (e.g., @dev, @next, @canary, @beta), OpenCode locks it to the first resolved version and never checks for updates on subsequent startups.
Config:
{
"plugin": [
"oh-my-opencode@latest",
"oc-solomemory@dev"
]
}
Expected: Both plugins check the registry on startup and update if a newer version is published under their respective tag.
Actual: @latest correctly checks for updates every startup. @dev (and any non-latest tag) is cached permanently and never re-resolved — even if a newer version is published under the dev tag on npm.
Root Cause
In packages/opencode/src/bun/index.ts, the install logic only checks the registry for the literal string "latest":
if (!modExists || !cachedVersion) {
// continue to install
} else if (version !== "latest" && cachedVersion === version) {
return mod // ← Any non-"latest" tag: string match against cache, return immediately
} else if (version === "latest") {
const isOutdated = await PackageRegistry.isOutdated(pkg, cachedVersion, Global.Path.cache)
if (!isOutdated) return mod // ← Only "latest" checks the registry
}
After the first install, package.json in the cache stores the tag name (e.g., "dev") as the dependency value. On subsequent startups: cachedVersion === version → "dev" === "dev" → true → returns cached module immediately without ever checking the registry.
Meanwhile, @latest goes through PackageRegistry.isOutdated() which queries bun info {pkg} version and does a semver comparison — so @latest always gets updates.
Suggested Fix
npm dist-tags are mutable pointers, not fixed versions. All dist-tags should be re-resolved on startup, not just "latest". A simple heuristic:
function isDistTag(version: string): boolean {
// Dist-tags are simple lowercase strings: "latest", "dev", "next", "canary", "beta"
// Actual versions contain dots/digits: "1.0.0", "^1.0.0", "1.0.0-dev.abc123"
return /^[a-z][a-z0-9-]*$/i.test(version) && !semver.valid(version)
}
Then in the install logic:
if (!modExists || !cachedVersion) {
// continue to install
} else if (isDistTag(version)) {
// Always check registry for dist-tags (@latest, @dev, @next, etc.)
const isOutdated = await PackageRegistry.isOutdated(pkg, cachedVersion, Global.Path.cache)
if (!isOutdated) return mod
log.info("Cached version is outdated, proceeding with install", { pkg, cachedVersion })
} else if (cachedVersion === version) {
return mod // Exact pinned version, use cache
}
Note: PackageRegistry.isOutdated() currently resolves only the latest tag via bun info {pkg} version. For non-latest tags, it would need to resolve the specific tag (e.g., bun info {pkg}@dev version or query npm view {pkg} dist-tags).
Workaround
Force-update manually:
npm install oc-solomemory@dev --prefix ~/.cache/opencode
Environment
- OpenCode: latest
- OS: Linux (ARM64)
- Plugin:
oc-solomemory@dev
Problem
When a plugin is configured with an npm dist-tag other than
@latest(e.g.,@dev,@next,@canary,@beta), OpenCode locks it to the first resolved version and never checks for updates on subsequent startups.Config:
{ "plugin": [ "oh-my-opencode@latest", "oc-solomemory@dev" ] }Expected: Both plugins check the registry on startup and update if a newer version is published under their respective tag.
Actual:
@latestcorrectly checks for updates every startup.@dev(and any non-latesttag) is cached permanently and never re-resolved — even if a newer version is published under thedevtag on npm.Root Cause
In
packages/opencode/src/bun/index.ts, the install logic only checks the registry for the literal string"latest":After the first install,
package.jsonin the cache stores the tag name (e.g.,"dev") as the dependency value. On subsequent startups:cachedVersion === version→"dev" === "dev"→true→ returns cached module immediately without ever checking the registry.Meanwhile,
@latestgoes throughPackageRegistry.isOutdated()which queriesbun info {pkg} versionand does a semver comparison — so@latestalways gets updates.Suggested Fix
npm dist-tags are mutable pointers, not fixed versions. All dist-tags should be re-resolved on startup, not just
"latest". A simple heuristic:Then in the install logic:
Note:
PackageRegistry.isOutdated()currently resolves only thelatesttag viabun info {pkg} version. For non-latest tags, it would need to resolve the specific tag (e.g.,bun info {pkg}@dev versionor querynpm view {pkg} dist-tags).Workaround
Force-update manually:
npm install oc-solomemory@dev --prefix ~/.cache/opencodeEnvironment
oc-solomemory@dev