diff --git a/adds-on/src/main.rs b/adds-on/src/main.rs index 7c7c4dd..bcf7e94 100644 --- a/adds-on/src/main.rs +++ b/adds-on/src/main.rs @@ -21,7 +21,8 @@ SPECIAL COMMANDS: → real uv completions + plugins injected shells: bash zsh fish nushell uv __complete → list discovered plugins (used by shell completions) - uv --version, -V → show wrapper version + uv --wrapper-version → show this wrapper's version + (--version / -V pass through to the real uv) uv --help, -h → show this message ENVIRONMENT: @@ -43,7 +44,12 @@ fn main() { Some("-h") | Some("--help") => { print_help(); } - Some("--version") | Some("-V") => { + // Report the wrapper's own version under a dedicated flag. We must NOT + // intercept `--version`/`-V`: tools like pipx and uv's own bootstrap run + // `uv --version` and parse the second whitespace token as a semver — a + // banner like "uv (plugin wrapper) 2.6.0" breaks them ("Unrecognized uv + // version '(plugin'"). Those flags fall through to the real uv below. + Some("--wrapper-version") => { println!("uv (plugin wrapper) {}", env!("CARGO_PKG_VERSION")); } // Dynamic plugin discovery — called by shell completion at tab-press time diff --git a/adds-on/tests/integration.rs b/adds-on/tests/integration.rs index 02cb23f..c82fa1d 100644 --- a/adds-on/tests/integration.rs +++ b/adds-on/tests/integration.rs @@ -45,23 +45,47 @@ fn help_short_flag() { // ── version ───────────────────────────────────────────────────── +/// The wrapper exposes its own version under a dedicated flag. #[test] -fn version_long_flag() { - let out = wrapper(&["--version"]); +fn wrapper_version_flag() { + let out = wrapper(&["--wrapper-version"]); assert!(out.status.success()); let stdout = String::from_utf8_lossy(&out.stdout); assert!( stdout.contains("uv (plugin wrapper)"), - "expected version line, got: {stdout}" + "expected wrapper version line, got: {stdout}" ); } +/// `--version` must pass through to the real uv unchanged so version-parsing +/// tools (pipx, uv's own bootstrap) see uv's exact output, not our banner. #[test] -fn version_short_flag() { +fn version_long_flag_passes_through() { + let out = wrapper(&["--version"]); + assert!(out.status.success()); + let stdout = String::from_utf8_lossy(&out.stdout); + assert!( + !stdout.contains("plugin wrapper"), + "wrapper banner leaked into --version output: {stdout}" + ); + // Real uv prints `uv ...`; the second token must parse as a version. + let second = stdout.split_whitespace().nth(1).unwrap_or(""); + assert!( + second.split('.').next().map(|s| s.chars().all(|c| c.is_ascii_digit())).unwrap_or(false), + "expected `uv `, got: {stdout}" + ); +} + +/// `-V` must also pass through to the real uv. +#[test] +fn version_short_flag_passes_through() { let out = wrapper(&["-V"]); assert!(out.status.success()); let stdout = String::from_utf8_lossy(&out.stdout); - assert!(stdout.contains("uv (plugin wrapper)")); + assert!( + !stdout.contains("plugin wrapper"), + "wrapper banner leaked into -V output: {stdout}" + ); } // ── __complete ──────────────────────────────────────────────────