Skip to content

fix(node): expand tilde in default_packages_file path#8709

Merged
jdx merged 2 commits intomainfrom
fix/node-default-packages-tilde
Mar 22, 2026
Merged

fix(node): expand tilde in default_packages_file path#8709
jdx merged 2 commits intomainfrom
fix/node-default-packages-tilde

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Mar 22, 2026

Summary

  • Wrap settings.node.default_packages_file() with file::replace_path() to expand ~ to $HOME, matching the behavior of Ruby, Go, and Python plugins.

Closes #8606

Test plan

  • Set default_packages_file = "~/.config/mise/default-npm-packages" in ~/.config/mise/config.toml
  • Run mise install node and verify default packages are installed

🤖 Generated with Claude Code


Note

Low Risk
Low risk: a small path-resolution change limited to reading the Node default-packages list, with behavior now consistent with other plugins.

Overview
Fixes Node default npm package installation when settings.node.default_packages_file uses ~ by expanding the path via file::replace_path() before reading the file.

Written by Cursor Bugbot for commit c797d14. This will update automatically on new commits. Configure here.

Closes #8606

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an inconsistency in path handling within the Node.js plugin. By introducing tilde expansion for the default_packages_file setting, it resolves an issue where user-defined paths starting with ~ were not correctly interpreted, thereby improving the reliability and user experience when configuring default Node.js packages.

Highlights

  • Path Resolution: Implemented tilde (~) expansion for the default_packages_file path in the Node.js plugin, ensuring consistency with other language plugins like Ruby, Go, and Python.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 22, 2026

Greptile Summary

This PR fixes a one-line bug in the Node plugin where a user-configured default_packages_file path containing ~ was not expanded to $HOME, causing the file to not be found and default packages to be silently skipped. The fix wraps the result of settings.node.default_packages_file() with file::replace_path(), which is exactly the same pattern already used in the Ruby (ruby.rs, ruby_windows.rs) and Go (go.rs) plugins.

Key observations:

  • The fix is minimal and targeted — one line changed.
  • The default fallback paths (e.g. ~/.default-nodejs-packages) are already returned as absolute PathBuf values via env::HOME.join(...), so passing them through file::replace_path() is a no-op and introduces no regression.
  • Paths from the NODE_DEFAULT_PACKAGES_FILE env var are constructed with PathBuf::from(), which does not expand ~; this fix correctly handles that case too.
  • The existing e2e test (e2e/core/test_node_slow) uses an absolute $PWD-based path, so it does not exercise the tilde expansion — but the change is simple enough that a manual test (as described in the PR) is sufficient.

Confidence Score: 5/5

  • Safe to merge — minimal, correct, well-precedented one-line fix with no regression risk.
  • The change is a single-line addition that mirrors an identical pattern already used in Ruby and Go plugins. The default fallback paths are unaffected (they are already absolute), and the only behavioral change is the intended one: expanding ~ in user-configured paths. No new dependencies, no logic changes, no risk of data loss.
  • No files require special attention.

Important Files Changed

Filename Overview
src/plugins/core/node.rs Single-line fix wrapping settings.node.default_packages_file() with file::replace_path() to expand ~ in user-specified paths, consistent with Ruby and Go plugins.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["install_default_packages()"] --> B["settings.node.default_packages_file()"]
    B --> C{Source}
    C -->|"config.toml setting"| D["User-defined path\n(may contain ~)"]
    C -->|"NODE_DEFAULT_PACKAGES_FILE env var"| E["Env var path\n(may contain ~)"]
    C -->|"fallback"| F["~/.default-nodejs-packages\n~/.default-node-packages\n~/.default-npm-packages\n(already absolute via HOME.join)"]
    D --> G["file::replace_path()\n~ → $HOME"]
    E --> G
    F --> G
    G --> H["file::read_to_string()\nnpm install --global"]
Loading

Reviews (2): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile

@jdx jdx enabled auto-merge (squash) March 22, 2026 15:16
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly identifies the need to expand tilde in the default_packages_file path for the node plugin, making it consistent with other plugins. However, the file::replace_path function being used has a bug related to tilde expansion where it does not handle ~ by itself. I've left a comment with details on the issue and a suggested fix. I have updated the suggested fix to use dirs::home_dir().unwrap() instead of dirs::HOME.clone() as dirs::HOME is an Option and this avoids a potential panic.

) -> Result<()> {
let settings = Settings::get();
let default_packages_file = settings.node.default_packages_file();
let default_packages_file = file::replace_path(settings.node.default_packages_file());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The file::replace_path function doesn't correctly handle a path that is exactly ~. It only expands paths starting with ~/. If a user configures default_packages_file = "~", this will cause read_to_string to look for a file named ~ in the current directory, which is incorrect.

While file::replace_path is not in this diff, it should be fixed to be more robust. A correct implementation should also handle the ~ case. For example:

pub fn replace_path<P: AsRef<Path>>(path: P) -> PathBuf {
    let s = path.as_ref().to_string_lossy();
    if s == "~" {
        dirs::home_dir().unwrap()
    } else if let Some(p) = s.strip_prefix("~/") {
        dirs::home_dir().unwrap().join(p)
    } else {
        path.as_ref().to_path_buf()
    }
}

@jdx jdx merged commit 6d4329e into main Mar 22, 2026
34 checks passed
@jdx jdx deleted the fix/node-default-packages-tilde branch March 22, 2026 15:35
@github-actions
Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 x -- echo 25.5 ± 0.7 23.8 29.6 1.00 ± 0.04
mise x -- echo 25.4 ± 0.8 23.9 36.2 1.00

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 env 24.9 ± 0.9 23.0 29.6 1.01 ± 0.04
mise env 24.8 ± 0.6 23.4 26.8 1.00

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 hook-env 24.6 ± 0.5 23.7 26.5 1.00
mise hook-env 24.9 ± 0.5 23.9 27.0 1.01 ± 0.03

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 ls 23.6 ± 0.4 22.9 25.5 1.00
mise ls 24.2 ± 0.7 23.1 29.5 1.02 ± 0.04

xtasks/test/perf

Command mise-2026.3.10 mise Variance
install (cached) 153ms 152ms +0%
ls (cached) 84ms 84ms +0%
bin-paths (cached) 87ms 87ms +0%
task-ls (cached) 849ms ⚠️ 4692ms -81%

⚠️ Warning: task-ls cached performance variance is -81%

mise-en-dev added a commit that referenced this pull request Mar 22, 2026
### 🚀 Features

- **(github)** read tokens from gh CLI hosts.yml config by @jdx in
[#8692](#8692)
- **(task)** support optional `args` and `env` fields in `run` entries
by @jdx in [#8687](#8687)
- **(task)** add --skip-tools flag to mise run by @jdx in
[#8699](#8699)
- **(vfox)** add try_get, try_head, try_download_file to Lua HTTP module
by @jdx in [#8697](#8697)

### 🐛 Bug Fixes

- **(config)** recognize SSH and other non-HTTPS URLs in get_repo_url by
@modestman in [#8666](#8666)
- **(docs)** add dark mode support to favicon by @jdx in
[#8678](#8678)
- **(env)** support multiple --env/-E flags by @jdx in
[#8686](#8686)
- **(github)** rename_exe renames correct binary when archive contains
multiple executables by @jdx in
[#8700](#8700)
- **(implode)** include system data dir in implode cleanup by @jdx in
[#8696](#8696)
- **(install)** skip GitHub API calls for aqua tools in --locked mode by
@jdx in [#8679](#8679)
- **(install)** skip redundant provenance verification when lockfile has
integrity data by @jdx in [#8688](#8688)
- **(lock)** respect existing platforms in lockfile when running `mise
lock` by @jdx in [#8708](#8708)
- **(lock)** skip global config lockfile by default by @jdx in
[#8707](#8707)
- **(node)** expand tilde in default_packages_file path by @jdx in
[#8709](#8709)
- **(shell)** error when no version specified instead of silent no-op by
@jdx in [#8693](#8693)
- **(shim)** detect shims by checking shims directory instead of binary
name by @jdx in [#8694](#8694)
- **(task)** inherit task_config.dir for included TOML and file tasks by
@jdx in [#8689](#8689)
- **(task)** strip inline args when validating run.tasks references by
@jdx in [#8701](#8701)
- **(task)** include idiomatic version files in monorepo task toolset by
@jdx in [#8702](#8702)
- **(task)** improve error message when task files are not executable by
@jdx in [#8705](#8705)
- **(test)** update vfox provenance test for checksum-backed skip by
@jdx in [#8703](#8703)
- improve usage spec element support in tasks by @nkakouros in
[#8623](#8623)
- make env plugin (Module) vars available in Tera template context by
@victor-founder in [#8682](#8682)
- respect MISE_COLOR=0 for color_eyre error output by @jdx in
[#8690](#8690)
- add windows support for usage tool registry by @jdx in
[#8713](#8713)

### 📚 Documentation

- **(task)** clarify interactive task blocking behavior by @jdx in
[#8685](#8685)
- improve visibility of install_before setting by @jdx in
[#8712](#8712)

### 📦 Registry

- add rtk ([github:rtk-ai/rtk](https://github.com/rtk-ai/rtk)) by
@bricelalu in [#8683](#8683)

### New Contributors

- @victor-founder made their first contribution in
[#8682](#8682)
- @modestman made their first contribution in
[#8666](#8666)
- @bricelalu made their first contribution in
[#8683](#8683)
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.

1 participant