Skip to content

fix(core): canonicalize npm package cache key - #49612

Open
log0u7 wants to merge 1 commit into
anomalyco:devfrom
log0u7:npm-cache-key
Open

log0u7 wants to merge 1 commit into
anomalyco:devfrom
log0u7:npm-cache-key

Conversation

@log0u7

@log0u7 log0u7 commented Sep 17, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #48514

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Npm.add and Npm.which keyed the package cache directory by the raw specifier string, and callers pass different forms of the same package: the plugin loader normalizes bare names to @latest before calling Npm.add (plugin/shared.ts), while the provider loader (provider.ts), the V1 config plugin refs (config/plugin/external.ts) and the core dynamic providers pass their specifier verbatim. One package ends up installed under two cache roots, e.g. packages/opencode-worktree-guard@latest and packages/opencode-worktree-guard created seconds apart in one boot.

Two consequences: the package module is evaluated twice in one process (a plugin counting module evaluations on a globalThis symbol warns "Module loaded 2 times" on every boot - reproducible with opencode-worktree-guard 0.3.7), and per #48514 the bare copy is returned forever without ever being refreshed.

Cache roots are now keyed by a canonical specifier: a bare name resolves to name@latest, while versioned, git and file specs keep their own root. All five call sites converge on one install; existing bare-name dirs become harmless leftovers. The separate "existing installs never refresh" aspect (#25293) is untouched by this change.

How did you verify your code works?

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Npm.add and Npm.which keyed the package cache directory by the raw
specifier string. Callers passed different forms of the same package:
the plugin loader normalizes bare names to @latest before calling
Npm.add, while the provider loader, the V1 config plugin refs and the
core dynamic providers pass their specifier verbatim. One package could
end up installed under two cache roots (packages/name@latest and
packages/name), double-evaluating the module in one process and never
refreshing the stale bare copy.

Cache roots are now keyed by a canonical specifier: a bare name resolves
to name@latest, while versioned, git and file specs keep their own root.
Existing bare-name cache dirs become harmless leftovers as every caller
converges on the @latest root.

Refs anomalyco#48514
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.

[Bug]: Plugin and provider loaders cache the same package under two keys and never refresh an existing install

1 participant