Skip to content

feat: add --reinstall-packages-from flag to fnm install#1505

Open
amanthanvi wants to merge 13 commits into
Schniz:masterfrom
amanthanvi:feat/reinstall-packages-from
Open

feat: add --reinstall-packages-from flag to fnm install#1505
amanthanvi wants to merge 13 commits into
Schniz:masterfrom
amanthanvi:feat/reinstall-packages-from

Conversation

@amanthanvi

Copy link
Copy Markdown

Summary

Adds --reinstall-packages-from=<version> flag to fnm install. When specified,
global npm packages from the source Node version are copied to the newly installed
version. This is the nvm-equivalent feature that has been the most requested
migration aid since 2022.

Motivation

Implementation

Package listing (source version)

  • Runs npm ls --global --parseable --long --loglevel=error in the source version's
    context using std::process::Command with PATH set to the source version's bin dir
  • Parses output to extract name@version pairs
  • Filters out npm and corepack (ship with Node, should not be reinstalled)

Package installation (target version)

  • Runs npm install --global <packages> via Exec::new_for_version() on the newly
    installed target version
  • User sees real-time install progress (stdio inherited)

Error handling

  • Source version not installed → clear error message with suggestion
  • Source has no global packages → info message, not an error
  • npm command failures → wrapped in ReinstallPackagesError with context

Cross-platform

  • Unix: bin/npm paths
  • Windows: npm.cmd paths, ; PATH separator
  • Uses cfg!(windows) guards matching the existing enable_corepack() pattern

Usage

# Install v22 and copy all global packages from v24
fnm install 22 --reinstall-packages-from=24

# Works with aliases too
fnm install lts-jod --reinstall-packages-from=default

# If source has no packages, just prints info and continues
fnm install 18 --reinstall-packages-from=20
# "No global packages found in Node v20.x.x."

Testing

  • Unit tests for npm output parser (scoped packages, builtins filter, malformed lines)
  • E2E test: install package on version A, install version B with
    --reinstall-packages-from=A, verify package present on B
  • E2E test: source not installed → error message
  • E2E test: source has no packages → graceful info message
  • Cross-platform: tested across Bash, Zsh, Fish, PowerShell, WinCmd

Checklist

Copies global npm packages from a specified installed Node version to
a newly installed version. Resolves the source version's global
packages via `npm ls`, filters out builtins (npm, corepack), and
installs them on the target version.

Closes Schniz#620
Refs Schniz#703, Schniz#481
Copilot AI review requested due to automatic review settings February 12, 2026 18:47
@changeset-bot

changeset-bot Bot commented Feb 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f3c174f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
fnm Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Feb 12, 2026

Copy link
Copy Markdown

@amanthanvi is attempting to deploy a commit to the Gal Schlezinger's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds the highly requested --reinstall-packages-from flag to the fnm install command, bringing feature parity with nvm. This addresses a major pain point where users lose their global CLI tools (eslint, prettier, typescript, etc.) when installing new Node versions.

Changes:

  • Added --reinstall-packages-from flag to fnm install that copies global npm packages from a source Node version to the newly installed target version
  • Implemented package listing using npm ls --global --parseable --long with proper filtering of built-in packages (npm, corepack)
  • Added comprehensive e2e tests covering success, error, and edge cases
  • Updated documentation and added changeset

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/commands/install.rs Core implementation including package listing, reinstallation logic, parser for npm output, cross-platform path handling, error types, and unit tests
e2e/reinstall-packages-from.test.ts E2e tests for Bash and PowerShell covering package reinstallation, error handling when source not installed, and graceful handling of empty package lists
e2e/snapshots/reinstall-packages-from.test.ts.snap Jest snapshots for the e2e tests
docs/commands.md Documentation for the new --reinstall-packages-from flag
.changeset/shiny-ducks-reinstall.md Changeset documenting this minor version feature addition

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread e2e/reinstall-packages-from.test.ts Outdated
@amanthanvi

Copy link
Copy Markdown
Author

CI note (fork PR):\n- Rust workflow is currently "action_required" (needs maintainer approval to run).\n- Vercel status fails with "Authorization required to deploy" for forks.\n- Copilot code review run failed during artifact cleanup due to fork permissions.\nLocal checks passed: cargo build/test/clippy/fmt + pnpm test -- e2e/reinstall-packages-from.test.ts.

Schniz added 8 commits April 17, 2026 18:32
… the same

Avoids a wasteful no-op reinstall cycle when a user passes the same
version to --reinstall-packages-from as the version being installed.
Adds an e2e test proving the guard works.
The npm path and PATH env setup was duplicated between
list_global_packages and reinstall_packages.
Also adds a clarifying comment on the scoped package '@' filter logic.
Extracts the multi-assertion output verification into a helper function
with shell-specific implementations for Bash/Zsh, Fish, and PowerShell.
Follow up on --reinstall-packages-from by listing global packages from the installed Node directory instead of calling npm ls. This avoids npm output and exit-code quirks while preserving behavior for scoped packages and npm/corepack filtering.
Ignore symlinked entries when scanning global packages for --reinstall-packages-from and log a warning for skipped items. This avoids trying to reinstall locally linked packages that may not exist in registries.
Windows global npm packages may live under %APPDATA%\npm\node_modules. Scan that location in addition to the Node installation path so --reinstall-packages-from consistently finds and reinstalls globals in Windows CI.
Add a Windows-specific discovery path for --reinstall-packages-from using npm ls --global --depth=0 --json, with an inline rationale that npm prefix location is not reliably derivable from fnm install paths. Keep filesystem scanning for non-Windows platforms.
Keep a single changeset for this PR by folding follow-up filesystem discovery, symlink handling, and Windows package discovery notes into the original reinstall-packages-from entry.
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.

Support for reinstall packages from other versions

3 participants