Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
36158f0
docs: add low-Node passthrough design for #1909 #1916
Jun 23, 2026
728546b
docs: add low-Node passthrough implementation plan
Jun 23, 2026
036f6c8
docs: fix self-review contradictions in passthrough plan (clone, walk…
Jun 23, 2026
9e7ddfd
feat(vite_shared): add MIN_SUPPORTED_NODE passthrough threshold
Jun 23, 2026
3007ed7
docs: require reading AGENTS.md + ban bare cargo test in plan constra…
Jun 23, 2026
5f0ef67
fix(vite_shared): add node-semver dep + fix Version::parse Result mat…
Jun 23, 2026
fb18611
docs: add local env prerequisites (RUSTC_BOOTSTRAP, vite-task patch) …
Jun 23, 2026
1533d4e
feat(vite_install): add PackageManagerBuilder::detect_only for passth…
Jun 23, 2026
325a643
feat(vite_global_cli): add passthrough eligibility + notice helpers
Jun 23, 2026
582ff13
docs: fix vite_global_cli test cmd (--bin vp not --lib) + note pre-ex…
Jun 23, 2026
070ffb4
refactor(vite_pm_cli): extract dispatch_with_pm and *_with_pm handlers
Jun 23, 2026
8aeaac3
feat(vite_global_cli): implement passthrough execute via detect_only …
Jun 23, 2026
2a5979e
fix: address Task 4a/4b review findings
Jun 23, 2026
7aed1ca
feat(vite_global_cli): add passthrough precheck in run_command_with_o…
Jun 23, 2026
5d290e8
test(vite_global_cli): add passthrough e2e + snap fixture
Jun 23, 2026
aa9d941
fix: add passthrough precheck to vpr shim path
Jun 24, 2026
6081e10
chore: remove design docs from PR (not intended for merge)
Jun 24, 2026
ac565de
chore: clean up dead_code comments in passthrough module
Jun 24, 2026
5cfcafa
Merge branch 'main' into feat/low-node-passthrough
l246804 Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 2 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions crates/vite_global_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,20 @@ pub async fn run_command_with_options(
return Ok(std::process::ExitStatus::default());
};

// Low-Node passthrough precheck: when the project's resolved Node is below
// the supported minimum AND the command is eligible (run / package manager),
// bypass the Vite+ JS CLI and run the project's own package manager directly.
// See docs/superpowers/specs/2026-06-23-low-node-passthrough-design.md
if commands::passthrough::is_eligible(&command) {
if let Some(node_version) = resolve_project_node_version(&cwd).await? {
if commands::passthrough::should_passthrough(&command, &node_version) {
let mut executor = crate::js_executor::JsExecutor::new(None);
let runtime = executor.ensure_project_runtime(&cwd).await?;
return commands::passthrough::execute(&cwd, &command, runtime).await;
}
}
}

match command {
// Category A: Package Manager Commands
// Print the runtime header for `vp install` (when not silent).
Expand Down Expand Up @@ -1111,6 +1125,24 @@ pub fn try_parse_args_from_with_options(
Args::from_arg_matches(&matches).map_err(|e| e.into())
}

/// Resolve the project's Node version string (if any), without forcing a
/// download. Used by the passthrough precheck to decide activation.
///
/// Returns `None` when the project has no Node version source (no .node-version,
/// no devEngines.runtime, no engines.node) — in that case the original path
/// runs (which falls back to CLI/LTS runtime, above the minimum).
async fn resolve_project_node_version(
cwd: &vite_path::AbsolutePath,
) -> Result<Option<String>, Error> {
use vite_js_runtime::resolve_node_version;
// walk_up=true to match ensure_project_runtime's resolution
// (has_valid_version_source uses resolve_node_version(path, true) at
// js_executor.rs:189); using false here could disagree with the runtime
// version actually downloaded, causing passthrough to mis-fire.
let resolution = resolve_node_version(cwd, true).await?;
Ok(resolution.map(|r| r.version.to_string()))
Comment on lines +1142 to +1143

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve version ranges before testing the low-Node cutoff

This returns the raw version source, so supported inputs like .node-version containing 18/18.20 or engines.node: "<20" are passed directly to is_node_below_min, fail semver parsing, and skip passthrough. Those projects then continue to the old JS delegation path even though the runtime resolver would choose a Node version below 20.19.0. Compare against the resolved exact Node version instead of the raw source string.

Useful? React with 👍 / 👎.

}

#[cfg(test)]
mod tests {
use super::{
Expand Down
3 changes: 3 additions & 0 deletions crates/vite_global_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ pub mod upgrade;
// Category C: Local CLI Delegation
pub mod delegate;

// Low-Node passthrough (degrades eligible commands to the project's package manager)
pub mod passthrough;

#[cfg(test)]
mod tests {
use vite_path::AbsolutePathBuf;
Expand Down
Loading
Loading