diff --git a/CHANGELOG.md b/CHANGELOG.md index a45309776..86882860b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug Fixes +* **npx:** fix `rtk npx --flags` calling `npm run ` instead of `npx ` for unknown packages like `vue-tsc` ([#1269](https://github.com/rtk-ai/rtk/issues/1269)) * **git:** remove `-u` short alias from `--ultra-compact` to fix `git push -u` upstream tracking ([#1086](https://github.com/rtk-ai/rtk/issues/1086)) ## [0.35.0](https://github.com/rtk-ai/rtk/compare/v0.34.3...v0.35.0) (2026-04-06) diff --git a/src/cmds/js/npm_cmd.rs b/src/cmds/js/npm_cmd.rs index cd8723ede..85eefeed0 100644 --- a/src/cmds/js/npm_cmd.rs +++ b/src/cmds/js/npm_cmd.rs @@ -4,6 +4,32 @@ use crate::core::runner; use crate::core::utils::resolved_command; use anyhow::Result; +/// Generic npx passthrough: runs `npx ` directly without injecting "run". +/// Used for unknown npx packages like `vue-tsc`, `taze`, etc. +pub fn run_npx(args: &[String], verbose: u8, skip_env: bool) -> Result { + let mut cmd = resolved_command("npx"); + + for arg in args { + cmd.arg(arg); + } + + if skip_env { + cmd.env("SKIP_ENV_VALIDATION", "1"); + } + + if verbose > 0 { + eprintln!("Running: npx {}", args.join(" ")); + } + + runner::run_filtered( + cmd, + "npx", + &args.join(" "), + filter_npm_output, + runner::RunOptions::default(), + ) +} + /// Known npm subcommands that should NOT get "run" injected. /// Shared between production code and tests to avoid drift. const NPM_SUBCOMMANDS: &[&str] = &[ @@ -220,4 +246,26 @@ npm notice let result = filter_npm_output(output); assert_eq!(result, "ok"); } + + // Regression: https://github.com/rtk-ai/rtk/issues/1269 + #[test] + fn test_npx_vue_tsc_output_passes_through() { + let output = r#"src/components/Foo.vue:10:5 - error TS2322: Type 'string' is not assignable to type 'number'. + +10 const count: number = "hello" + ~~~~~ + +src/components/Bar.vue:5:3 - error TS2339: Property 'foo' does not exist on type '{}'. + +5 this.foo + ~~~~ + +Found 2 errors in 2 files. +"#; + let result = filter_npm_output(output); + assert!(result.contains("error TS2322"), "type error must be preserved"); + assert!(result.contains("error TS2339"), "type error must be preserved"); + assert!(result.contains("Found 2 errors"), "error summary must be preserved"); + } + } diff --git a/src/main.rs b/src/main.rs index a8f724d85..fd851f8a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1978,7 +1978,7 @@ fn run_cli() -> Result { "playwright" => playwright_cmd::run(&args[1..], cli.verbose)?, _ => { // Generic passthrough with npm boilerplate filter - npm_cmd::run(&args, cli.verbose, cli.skip_env)? + npm_cmd::run_npx(&args, cli.verbose, cli.skip_env)? } } }