Skip to content

fix(npm): resolve cached package name from install dir for non-registry specs#24821

Open
sjawhar wants to merge 1 commit intoanomalyco:devfrom
sjawhar:fix/npm-cache-name-resolution-upstream
Open

fix(npm): resolve cached package name from install dir for non-registry specs#24821
sjawhar wants to merge 1 commit intoanomalyco:devfrom
sjawhar:fix/npm-cache-name-resolution-upstream

Conversation

@sjawhar
Copy link
Copy Markdown

@sjawhar sjawhar commented Apr 28, 2026

Issue for this PR

Closes #24828

Type of change

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

What does this PR do?

Fixes the Npm.add cache fast-path so it resolves non-registry specs to their actual installed directory instead of a path derived from the spec string.

The cache fast-path was reading the package name from npa(pkg).name. That works for registry specs like @scope/pkg@1.0.0, but for https://, git+https://, github:owner/repo, and file: specs npa(pkg).name returns undefined, so name falls back to the full spec string and the resulting <dir>/node_modules/<spec>/ path doesn't exist.

The fix: read the install-root package.json (which Arborist writes during the fresh-install path) and recover the actual name from its first dependencies entry. This is the same source Npm.install already reads on lines 247-275 to detect dirty installs.

Fallback chain: install-root package.json first dep → npa(pkg).name → spec string. The third level preserves backward compat for the unlikely case where package.json is missing or has no deps.

The fresh-install path is unchanged — it's correct and continues to use tree.edgesOut.

How did you verify your code works?

Added 5 tests in packages/core/test/npm.test.ts covering each spec type. Each test seeds a synthetic populated cache (mimicking a previous successful install) and asserts Npm.add(spec).directory resolves through the install dir to the actual package, not the broken spec-string path.

  • https remote tarball
  • git+https URL
  • github shorthand
  • file: local tarball
  • registry package (regression check)

Without the fix, the four non-registry tests fail. With the fix, all five pass.

End-to-end tested against a production opencode setup that uses a private GitHub release tarball as a plugin: previously the cache fast-path returned a non-existent path on every run after the first, now it resolves correctly.

Screenshots / recordings

N/A — no UI changes.

Checklist

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

…ry specs

Npm.add cache fast-path used npa(pkg).name as the package name. For
non-registry specs (remote tarball URLs, git+https://, github: shorthand,
file: paths), npa returns name=undefined and the code fell back to the
spec string itself, then looked at <dir>/node_modules/<spec>/ which does
not exist. Plugins/packages installed from these sources fail to load on
the second and subsequent runs, even though the fresh-install path works
correctly.

The fresh-install path uses tree.edgesOut.values().next().value.to.{name,
path} from Arborist. For the cache fast-path, derive the actual installed
package name from <dir>/package.json's first dependency entry (the same
source Npm.install reads to detect dirty installs).

Fallback chain: package.json first dep -> npa(pkg).name -> spec string.
@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. needs:issue labels Apr 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Apr 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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.

Npm.add cache fast-path resolves to broken paths for non-registry specs

1 participant