Skip to content

feat(env): honor system-only in shims and installers - #3233

Open
myuron wants to merge 4 commits into
voidzero-dev:mainfrom
myuron:feat/system-only-shim
Open

myuron wants to merge 4 commits into
voidzero-dev:mainfrom
myuron:feat/system-only-shim

Conversation

@myuron

@myuron myuron commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Part of #1899 (system-only management mode for NixOS). Follows #3143.

VP_*_MANAGER=system-only restricts Node.js or a package-manager family to the system installation. Shims then use only tools found on PATH: they never fall back to a managed version, download, or reuse a cached managed install. Every other managed entry point fails with a clear error instead of downloading.

system-only is intentionally undocumented until the remaining paths are covered (vp commands, reinstall/upgrade dependency installation, and installation-time setup). Without a system-only variable, nothing changes: yes/no, config.json modes, and the existing installer probe response behave as before.

What's Changed

Parsing and safety net

  • ManagerPreference::SystemOnly matches only the exact lowercase value. A family variable (VP_PNPM_MANAGER, ...) takes precedence over VP_PM_MANAGER. At run time, system-only overrides config.json. The other values still apply only at installation.
  • Managed Node.js and package-manager entry points fail with DisabledBySystemOnly before their cache lookups: runtime download, the Node.js version index, package-manager download and binary lookup, and registry version resolution. The error is not an integrity failure.
  • Installation ignores system-only for now: self_setup treats it like an unknown value.

Shims

  • vp_command::find_external_tool gets an exclude_managed option. With it, installs under <DATA>/js_runtime and <DATA>/package_manager, and the fallback-bin directory, never count as the system tool. Paths are compared after canonicalization, so /nix/store/... tools are accepted.
  • New EffectiveMode { Managed, SystemFirst, SystemOnly } combines the config.json shim mode with the environment.
  • The core-shim selection moves from dispatch() into select_core_tool, which does not exec and can be tested directly. With system-only Node.js, it ignores session overrides, .node-version-style pins, and a managed runtime inherited from a parent shim. A system-only family ignores packageManager pins and makes no registry requests.
  • The VP_BYPASS path, the reuse of a tool selected by a parent shim, global package binaries, and vpx global binaries follow the same rules. The npm bundled with a managed runtime is treated as part of that runtime.
  • System-only directories are never added to the child PATH. A canonical path such as /nix/store/...-nodejs/bin matches no PATH entry, so adding it would reorder the user's PATH. Children reach the same tools through PATH or the shims.
  • When no system tool is found, the shim fails with VP_NODE_MANAGER=system-only requires a system 'node' on PATH, but none was found.

Installers and vp upgrade

A vp that predates this change would ignore system-only and download managed tools. Installers and vp upgrade therefore refuse to hand over to such a binary while any system-only variable is set.

  • vp answers VP_SELF_SETUP_SUPPORT_CHECK=system-only with a second line, vite-plus-self-setup-system-only. The response to the existing check (vite-plus-self-setup-v1) is unchanged, because released installers compare it exactly.
  • install.sh, install.ps1, and vp_installer probe with the new value only when a system-only variable is set. They fail before the legacy installer path, which would download Node.js itself.
  • vp upgrade checks the extracted binary before installing dependencies, and vp upgrade --rollback checks the previous version before switching.
  • vp_installer tracks the Node.js choice as NodeManager { Enabled, Disabled, SystemOnly }. system-only takes precedence over --no-node-manager and cannot be toggled in the menu. When package managers inherit the Node.js choice, system-only becomes no, so only an explicit variable makes them system-only.

Current limitations (follow-up PRs)

With system-only set, after this PR:

  • Shims (node, npm, pnpm, ...) use system tools.
  • vp install, vp run, vp env *, and vpx package downloads fail with DisabledBySystemOnly instead of using or downloading managed tools.
  • Reinstalling or running vp upgrade with system-only exported fails while installing dependencies, for the same reason.
  • Setting system-only at installation is not saved yet.

Testing

On the current main:

  • Each of the three commits on its own: cargo fmt --all -- --check, cargo check --workspace --locked, cargo clippy -- -D warnings and cargo test for the affected crates
  • New snapshot cases: shim_system_first_fallback/system_only_overrides_managed_shims (an unreachable Node.js mirror and registry, checks that no managed install is created and that the child PATH is unchanged), and command_self_setup/command_self_setup_system_only_probe

Before rebasing onto the current main (the only conflict was an import in shim/dispatch.rs):

  • just check, just lint, just test
  • .github/scripts/test-install-bootstrap.sh: all scenarios, including five new system-only scenarios

Not run locally:

  • .github/scripts/test-install-bootstrap.ps1 and test-install-legacy-remote.ps1 (CI; no PowerShell locally)
  • Windows (CI)

Some existing command_self_setup and shim snapshot cases fail locally on NixOS both before and after this change (same cases); relying on CI for those.

@liangmiQwQ
liangmiQwQ self-requested a review October 25, 2026 14:55

This branch has not been deployed

No deployments
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