Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[[case]]
name = "command_env_doctor_warnings"
vp = "global"
skip-platforms = ["windows"]
seed-runtime = false
comment = "Warnings describe setups that still work, so doctor names them in the summary and exits with 0."
steps = [
{ argv = ["vpt", "write-file", "$HOME/.profile", ". \"$HOME/.vite-plus/env\""], snapshot = false, comment = "source the env file so the output has no platform-specific IDE guidance" },
{ argv = ["vp", "env", "doctor", "node"], envs = [["VP_NODE_VERSION", "20.18.0"]] },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# command_env_doctor_warnings

Warnings describe setups that still work, so doctor names them in the summary and exits with 0.

## `vpt write-file $HOME/.profile '. "$HOME/.vite-plus/env"'`

source the env file so the output has no platform-specific IDE guidance


## `VP_NODE_VERSION=20.18.0 vp env doctor node`

```
VITE+ - The Unified Toolchain for the Web

Installation
✓ Bin dir ~/.vite-plus/bin
✓ Data dir ~/.vite-plus
✓ Cache dir ~/.vite-plus/cache (not created yet)
✓ Config dir ~/.vite-plus
✓ State dir ~/.vite-plus
✓ Shims node

Configuration
✓ Node.js managed mode
✓ IDE integration env sourced in ~/.profile
⚠ Session override VP_NODE_VERSION=20.18.0
note: Overrides all file-based resolution.
note: Run 'vp env use --unset' to remove.

PATH
✓ vp ~/.vite-plus/bin/vp
✓ Shim dir ~/.vite-plus/bin
✓ node ~/.vite-plus/bin/node (vp shim)

Node.js Resolution
Directory <workspace>
Source VP_NODE_VERSION
Version 20.18.0
⚠ Node binary not installed
note: Version will be downloaded on first use.

⚠ Some warnings found.
```
70 changes: 34 additions & 36 deletions crates/vp_global_cli/src/commands/env/doctor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Doctor command implementation for environment diagnostics.

use std::process::ExitStatus;
use std::{
process::ExitStatus,
sync::atomic::{AtomicBool, Ordering},
};

use console::style;
use vp_pm_cli::{package_manager_bin_path, package_manager_install_dir};
Expand Down Expand Up @@ -42,6 +45,9 @@ const KNOWN_VERSION_MANAGERS: &[(&str, &str)] = &[
/// Column width for left-side keys in aligned output
const KEY_WIDTH: usize = 18;

// Warnings come from many checks that otherwise return nothing, so they are recorded as they print.
static HAS_WARNINGS: AtomicBool = AtomicBool::new(false);

/// Print a section header (bold, with blank line before).
fn print_section(name: &str) {
vp_shared::output::print_stdout_line(format_args!(""));
Expand All @@ -62,6 +68,12 @@ fn print_check(status: &str, key: &str, value: &str) {
}
}

/// Print an aligned key-value line with a warning indicator, and record it for the summary.
fn print_warning(key: &str, value: &str) {
HAS_WARNINGS.store(true, Ordering::Relaxed);
print_check(&style(output::WARN_SIGN).yellow().to_string(), key, value);
}

fn print_package_manager_mode(key: &str, mode: ShimMode) {
let mode = match mode {
ShimMode::Managed => "managed mode",
Expand Down Expand Up @@ -168,6 +180,13 @@ pub async fn execute(cwd: AbsolutePathBuf, scope: Option<String>) -> Result<Exit
style("\u{2717} Some issues found.").red().bold()
));
Ok(super::exit_status(1))
} else if HAS_WARNINGS.load(Ordering::Relaxed) {
// Warnings describe setups that still work, so they keep the zero exit code.
vp_shared::output::print_stdout_line(format_args!(
"{}",
style("\u{26A0} Some warnings found.").yellow().bold()
));
Ok(ExitStatus::default())
} else {
vp_shared::output::print_stdout_line(format_args!(
"{}",
Expand Down Expand Up @@ -304,8 +323,7 @@ async fn check_shim_mode(scope: EnvScope) -> Option<(config::Config, Option<Abso
);
system_node_path = Some(system_node);
} else {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
"System Node.js",
&style("not found (will fall back to managed)").yellow().to_string(),
);
Expand Down Expand Up @@ -429,13 +447,11 @@ async fn check_package_manager_resolution(
package_manager_bin_path(&directory, name).as_path().exists()
})
});
let status = if installed { "installed" } else { "not installed" };
let indicator = if installed {
style(output::CHECK).green().to_string()
if installed {
print_check(&style(output::CHECK).green().to_string(), "PM binaries", "installed");
} else {
style(output::WARN_SIGN).yellow().to_string()
};
print_check(&indicator, "PM binaries", status);
print_warning("PM binaries", "not installed");
}
true
}
Ok(_) => {
Expand Down Expand Up @@ -482,8 +498,7 @@ fn check_env_sourcing() -> EnvSourcingStatus {

// Second: check all shell profiles (interactive terminal sessions)
if let Some(file) = check_profile_files(&env_path, ALL_SHELL_PROFILES) {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
"IDE integration",
&format!(
"{} {}",
Expand All @@ -502,8 +517,7 @@ fn check_session_override() {
if let Ok(version) = std::env::var(config::VERSION_ENV_VAR) {
let version = version.trim();
if !version.is_empty() {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
"Session override",
&style(format!("{}={version}", env_vars::VP_NODE_VERSION)).yellow().to_string(),
);
Expand All @@ -514,8 +528,7 @@ fn check_session_override() {

// Also check session version file
if let Some(version) = config::read_session_version_sync() {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
"Session override (file)",
&style(format!("{}={version}", config::SESSION_VERSION_FILE)).yellow().to_string(),
);
Expand Down Expand Up @@ -601,8 +614,7 @@ async fn check_path(scope: EnvScope) -> bool {
&format!("{display} (system)"),
);
} else {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
tool,
&format!("{} {}", style(&display).yellow(), style("(not vp shim)").dim()),
);
Expand Down Expand Up @@ -732,8 +744,7 @@ fn print_ide_setup_guidance(env_dir: &vt_path::AbsolutePath) {
};

print_section("IDE Setup");
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
"",
&style("GUI applications may not see shell PATH changes.").yellow().to_string(),
);
Expand Down Expand Up @@ -828,11 +839,7 @@ async fn check_current_resolution(
&system_node.as_path().display().to_string(),
);
} else {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
"System Node.js",
&style("not found in PATH").yellow().to_string(),
);
print_warning("System Node.js", &style("not found in PATH").yellow().to_string());
print_hint("Install Node.js or run 'vp env on' to use managed Node.js.");
}
return (true, None);
Expand Down Expand Up @@ -861,11 +868,7 @@ async fn check_current_resolution(
if tokio::fs::try_exists(&binary_path).await.unwrap_or(false) {
print_check(&style(output::CHECK).green().to_string(), "Node binary", "installed");
} else {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
"Node binary",
&style("not installed").yellow().to_string(),
);
print_warning("Node binary", &style("not installed").yellow().to_string());
print_hint("Version will be downloaded on first use.");
}
(true, Some(resolution))
Expand Down Expand Up @@ -963,11 +966,7 @@ async fn check_dev_engines(
print_section("devEngines");
for finding in findings {
if finding.warn {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
finding.key,
&style(&finding.message).yellow().to_string(),
);
print_warning(finding.key, &style(&finding.message).yellow().to_string());
} else {
print_check(" ", finding.key, &finding.message);
}
Expand Down Expand Up @@ -1295,8 +1294,7 @@ fn check_conflicts() {
if !conflicts.is_empty() {
print_section("Conflicts");
for manager in &conflicts {
print_check(
&style(output::WARN_SIGN).yellow().to_string(),
print_warning(
manager,
&style(format!(
"detected ({} is set)",
Expand Down
4 changes: 4 additions & 0 deletions rfcs/env-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -949,8 +949,12 @@ Configuration
Written by 'vp env use'. Run 'vp env use --unset' to remove.

...

⚠ Some warnings found.
```

Warnings describe setups that still work, so they keep the exit code at 0. Errors take precedence: when both appear, the summary is `✗ Some issues found.` and the exit code is 1.

**Doctor Output with System-First Mode:**

```bash
Expand Down
Loading