Skip to content

Commit df694e9

Browse files
authored
feat: unify CLI output with shared output module and Vite+ branding (#614)
- Add vite_shared::output module with standardized info/warn/error/note/success functions and CHECK/CROSS/WARN_SIGN/ARROW symbol constants - Migrate all Rust CLI commands (upgrade, vpx, env/which, env/pin, env/doctor, main.rs) to use shared output module - Migrate all vite_install Warning/Note messages (14 command files) to use shared output module - Rebrand rolldown-vite: VITE→VITE+, [vite]→[vite+], inject VITE_PLUS_VERSION env var for Build/Dev/Preview subcommands - Add brand-rolldown-vite.ts post-sync script to maintain branding patches after upstream sync - Add sub-tool banners (vite+ v{version} — test/lint/fmt) for TTY stderr - Add JS-side infoMsg/warnMsg/errorMsg/noteMsg prefix functions in terminal.ts
1 parent 018e4ef commit df694e9

56 files changed

Lines changed: 1184 additions & 263 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/build-upstream/action.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ runs:
3838
target/${{ inputs.target }}/release/vp.exe
3939
key: ${{ steps.cache-key.outputs.key }}
4040

41+
# Apply Vite+ branding patches to rolldown-vite source (CI checks out
42+
# upstream rolldown-vite which doesn't have branding patches)
43+
- name: Brand rolldown-vite
44+
shell: bash
45+
run: pnpm exec tool brand-rolldown-vite
46+
4147
# Build upstream TypeScript packages first (don't depend on native bindings)
4248
- name: Build upstream TypeScript packages
4349
shell: bash

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/vite_global_cli/src/cli.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,62 +530,71 @@ pub enum Commands {
530530
// Category C: Local CLI Delegation (stubs for now)
531531
// =========================================================================
532532
/// Run the development server
533+
#[command(disable_help_flag = true)]
533534
Dev {
534535
/// Additional arguments
535536
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
536537
args: Vec<String>,
537538
},
538539

539540
/// Build application
541+
#[command(disable_help_flag = true)]
540542
Build {
541543
/// Additional arguments
542544
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
543545
args: Vec<String>,
544546
},
545547

546548
/// Run tests
549+
#[command(disable_help_flag = true)]
547550
Test {
548551
/// Additional arguments
549552
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
550553
args: Vec<String>,
551554
},
552555

553556
/// Lint code
557+
#[command(disable_help_flag = true)]
554558
Lint {
555559
/// Additional arguments
556560
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
557561
args: Vec<String>,
558562
},
559563

560564
/// Format code
565+
#[command(disable_help_flag = true)]
561566
Fmt {
562567
/// Additional arguments
563568
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
564569
args: Vec<String>,
565570
},
566571

567572
/// Build library
573+
#[command(disable_help_flag = true)]
568574
Pack {
569575
/// Additional arguments
570576
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
571577
args: Vec<String>,
572578
},
573579

574580
/// Run tasks
581+
#[command(disable_help_flag = true)]
575582
Run {
576583
/// Additional arguments
577584
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
578585
args: Vec<String>,
579586
},
580587

581588
/// Preview production build
589+
#[command(disable_help_flag = true)]
582590
Preview {
583591
/// Additional arguments
584592
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
585593
args: Vec<String>,
586594
},
587595

588596
/// Manage the task cache
597+
#[command(disable_help_flag = true)]
589598
Cache {
590599
/// Additional arguments
591600
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]

crates/vite_global_cli/src/commands/env/doctor.rs

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::process::ExitStatus;
44

55
use owo_colors::OwoColorize;
66
use vite_path::{AbsolutePathBuf, current_dir};
7-
use vite_shared::env_vars;
7+
use vite_shared::{env_vars, output};
88

99
use super::config::{
1010
self, ShimMode, get_bin_dir, get_vite_plus_home, load_config, resolve_version,
@@ -111,7 +111,7 @@ async fn check_vite_plus_home() -> bool {
111111
Ok(h) => h,
112112
Err(e) => {
113113
print_check(
114-
&"\u{2717}".red().to_string(),
114+
&output::CROSS.red().to_string(),
115115
env_vars::VITE_PLUS_HOME,
116116
&format!("{e}").red().to_string(),
117117
);
@@ -122,11 +122,11 @@ async fn check_vite_plus_home() -> bool {
122122
let display = abbreviate_home(&home.as_path().display().to_string());
123123

124124
if tokio::fs::try_exists(&home).await.unwrap_or(false) {
125-
print_check(&"\u{2713}".green().to_string(), env_vars::VITE_PLUS_HOME, &display);
125+
print_check(&output::CHECK.green().to_string(), env_vars::VITE_PLUS_HOME, &display);
126126
true
127127
} else {
128128
print_check(
129-
&"\u{2717}".red().to_string(),
129+
&output::CROSS.red().to_string(),
130130
env_vars::VITE_PLUS_HOME,
131131
&"does not exist".red().to_string(),
132132
);
@@ -144,15 +144,15 @@ async fn check_bin_dir() -> bool {
144144

145145
if !tokio::fs::try_exists(&bin_dir).await.unwrap_or(false) {
146146
print_check(
147-
&"\u{2717}".red().to_string(),
147+
&output::CROSS.red().to_string(),
148148
"Bin directory",
149149
&"does not exist".red().to_string(),
150150
);
151151
print_hint("Run 'vp env setup' to create bin directory and shims.");
152152
return false;
153153
}
154154

155-
print_check(&"\u{2713}".green().to_string(), "Bin directory", "exists");
155+
print_check(&output::CHECK.green().to_string(), "Bin directory", "exists");
156156

157157
let mut missing = Vec::new();
158158

@@ -164,11 +164,11 @@ async fn check_bin_dir() -> bool {
164164
}
165165

166166
if missing.is_empty() {
167-
print_check(&"\u{2713}".green().to_string(), "Shims", &SHIM_TOOLS.join(", "));
167+
print_check(&output::CHECK.green().to_string(), "Shims", &SHIM_TOOLS.join(", "));
168168
true
169169
} else {
170170
print_check(
171-
&"\u{2717}".red().to_string(),
171+
&output::CROSS.red().to_string(),
172172
"Missing shims",
173173
&missing.join(", ").red().to_string(),
174174
);
@@ -197,7 +197,7 @@ async fn check_shim_mode() {
197197
Ok(c) => c,
198198
Err(e) => {
199199
print_check(
200-
&"\u{26A0}".yellow().to_string(),
200+
&output::WARN_SIGN.yellow().to_string(),
201201
"Shim mode",
202202
&format!("config error: {e}").yellow().to_string(),
203203
);
@@ -207,11 +207,11 @@ async fn check_shim_mode() {
207207

208208
match config.shim_mode {
209209
ShimMode::Managed => {
210-
print_check(&"\u{2713}".green().to_string(), "Shim mode", "managed");
210+
print_check(&output::CHECK.green().to_string(), "Shim mode", "managed");
211211
}
212212
ShimMode::SystemFirst => {
213213
print_check(
214-
&"\u{2713}".green().to_string(),
214+
&output::CHECK.green().to_string(),
215215
"Shim mode",
216216
&"system-first".cyan().to_string(),
217217
);
@@ -221,7 +221,7 @@ async fn check_shim_mode() {
221221
print_check(" ", "System Node.js", &system_node.display().to_string());
222222
} else {
223223
print_check(
224-
&"\u{26A0}".yellow().to_string(),
224+
&output::WARN_SIGN.yellow().to_string(),
225225
"System Node.js",
226226
&"not found (will use managed)".yellow().to_string(),
227227
);
@@ -261,7 +261,7 @@ fn check_ide_integration() -> bool {
261261

262262
if let Some(file) = check_profile_files(&home_path) {
263263
print_check(
264-
&"\u{2713}".green().to_string(),
264+
&output::CHECK.green().to_string(),
265265
"IDE integration",
266266
&format!("env sourced in {file}"),
267267
);
@@ -308,7 +308,7 @@ fn check_session_override() {
308308
let version = version.trim();
309309
if !version.is_empty() {
310310
print_check(
311-
&"\u{26A0}".yellow().to_string(),
311+
&output::WARN_SIGN.yellow().to_string(),
312312
"Session override",
313313
&format!("{}={version}", env_vars::VITE_PLUS_NODE_VERSION).yellow().to_string(),
314314
);
@@ -320,7 +320,7 @@ fn check_session_override() {
320320
// Also check session version file
321321
if let Some(version) = config::read_session_version_sync() {
322322
print_check(
323-
&"\u{26A0}".yellow().to_string(),
323+
&output::WARN_SIGN.yellow().to_string(),
324324
"Session override (file)",
325325
&format!("{}={version}", config::SESSION_VERSION_FILE).yellow().to_string(),
326326
);
@@ -346,18 +346,18 @@ async fn check_path() -> bool {
346346

347347
match bin_position {
348348
Some(0) => {
349-
print_check(&"\u{2713}".green().to_string(), "vp", "first in PATH");
349+
print_check(&output::CHECK.green().to_string(), "vp", "first in PATH");
350350
}
351351
Some(pos) => {
352352
print_check(
353-
&"\u{26A0}".yellow().to_string(),
353+
&output::WARN_SIGN.yellow().to_string(),
354354
"vp",
355355
&format!("in PATH at position {pos}").yellow().to_string(),
356356
);
357357
print_hint("For best results, bin should be first in PATH.");
358358
}
359359
None => {
360-
print_check(&"\u{2717}".red().to_string(), "vp", &"not in PATH".red().to_string());
360+
print_check(&output::CROSS.red().to_string(), "vp", &"not in PATH".red().to_string());
361361
print_hint(&format!("Expected: {bin_display}"));
362362
println!();
363363
print_path_fix(&bin_dir);
@@ -372,13 +372,13 @@ async fn check_path() -> bool {
372372
let display = abbreviate_home(&tool_path.display().to_string());
373373
if tool_path == expected.as_path() {
374374
print_check(
375-
&"\u{2713}".green().to_string(),
375+
&output::CHECK.green().to_string(),
376376
tool,
377377
&format!("{display} {}", "(vp shim)".dimmed()),
378378
);
379379
} else {
380380
print_check(
381-
&"\u{26A0}".yellow().to_string(),
381+
&output::WARN_SIGN.yellow().to_string(),
382382
tool,
383383
&format!("{} {}", display.yellow(), "(not vp shim)".dimmed()),
384384
);
@@ -501,7 +501,7 @@ fn print_ide_setup_guidance(bin_dir: &vite_path::AbsolutePath) {
501501

502502
print_section("IDE Setup");
503503
print_check(
504-
&"\u{26A0}".yellow().to_string(),
504+
&output::WARN_SIGN.yellow().to_string(),
505505
"",
506506
&"GUI applications may not see shell PATH changes.".yellow().to_string(),
507507
);
@@ -557,10 +557,10 @@ async fn check_current_resolution(cwd: &AbsolutePathBuf) {
557557
let binary_path = home_dir.join("bin").join("node");
558558

559559
if tokio::fs::try_exists(&binary_path).await.unwrap_or(false) {
560-
print_check(&"\u{2713}".green().to_string(), "Node binary", "installed");
560+
print_check(&output::CHECK.green().to_string(), "Node binary", "installed");
561561
} else {
562562
print_check(
563-
&"\u{26A0}".yellow().to_string(),
563+
&output::WARN_SIGN.yellow().to_string(),
564564
"Node binary",
565565
&"not installed".yellow().to_string(),
566566
);
@@ -569,7 +569,7 @@ async fn check_current_resolution(cwd: &AbsolutePathBuf) {
569569
}
570570
Err(e) => {
571571
print_check(
572-
&"\u{2717}".red().to_string(),
572+
&output::CROSS.red().to_string(),
573573
"Resolution",
574574
&format!("failed: {e}").red().to_string(),
575575
);
@@ -609,7 +609,7 @@ fn check_conflicts() {
609609
print_section("Conflicts");
610610
for manager in &conflicts {
611611
print_check(
612-
&"\u{26A0}".yellow().to_string(),
612+
&output::WARN_SIGN.yellow().to_string(),
613613
manager,
614614
&format!(
615615
"detected ({} is set)",

crates/vite_global_cli/src/commands/env/pin.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::{io::Write, process::ExitStatus};
77

88
use vite_js_runtime::NodeProvider;
99
use vite_path::AbsolutePathBuf;
10+
use vite_shared::output;
1011

1112
use super::config::{get_config_path, load_config};
1213
use crate::error::Error;
@@ -131,15 +132,17 @@ async fn do_pin(
131132

132133
// Print success message
133134
if was_alias {
134-
println!("\u{2713} Pinned Node.js version to {resolved_version} (resolved from {version})");
135+
output::success(&format!(
136+
"Pinned Node.js version to {resolved_version} (resolved from {version})"
137+
));
135138
} else {
136-
println!("\u{2713} Pinned Node.js version to {resolved_version}");
139+
output::success(&format!("Pinned Node.js version to {resolved_version}"));
137140
}
138141
println!(" Created {} in {}", NODE_VERSION_FILE, cwd.as_path().display());
139142

140143
// Pre-download the version unless --no-install is specified
141144
if no_install {
142-
println!(" Note: Version will be downloaded on first use.");
145+
output::note("Version will be downloaded on first use.");
143146
} else {
144147
// Download the runtime
145148
match vite_js_runtime::download_runtime(
@@ -149,11 +152,11 @@ async fn do_pin(
149152
.await
150153
{
151154
Ok(_) => {
152-
println!("\u{2713} Node.js {resolved_version} installed");
155+
output::success(&format!("Node.js {resolved_version} installed"));
153156
}
154157
Err(e) => {
155-
eprintln!("Warning: Failed to download Node.js {resolved_version}: {e}");
156-
eprintln!(" Version will be downloaded on first use.");
158+
output::warn(&format!("Failed to download Node.js {resolved_version}: {e}"));
159+
output::note("Version will be downloaded on first use.");
157160
}
158161
}
159162
}
@@ -204,7 +207,7 @@ pub async fn do_unpin(cwd: &AbsolutePathBuf) -> Result<ExitStatus, Error> {
204207
}
205208

206209
tokio::fs::remove_file(&node_version_path).await?;
207-
println!("\u{2713} Removed {} from {}", NODE_VERSION_FILE, cwd.as_path().display());
210+
output::success(&format!("Removed {} from {}", NODE_VERSION_FILE, cwd.as_path().display()));
208211

209212
Ok(ExitStatus::default())
210213
}

crates/vite_global_cli/src/commands/env/which.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::process::ExitStatus;
1111
use chrono::Local;
1212
use owo_colors::OwoColorize;
1313
use vite_path::AbsolutePathBuf;
14+
use vite_shared::output;
1415

1516
use super::{
1617
config::{VERSION_ENV_VAR, get_node_modules_dir, get_packages_dir, resolve_version},
@@ -37,7 +38,7 @@ pub async fn execute(cwd: AbsolutePathBuf, tool: &str) -> Result<ExitStatus, Err
3738
}
3839

3940
// Unknown tool
40-
eprintln!("{} tool '{}' not found", "error:".red().bold(), tool.bold());
41+
output::error(&format!("tool '{}' not found", tool.bold()));
4142
eprintln!("Not a core tool (node, npm, npx) or installed global package.");
4243
eprintln!("Run 'vp list -g' to see installed packages.");
4344
Ok(exit_status(1))
@@ -66,7 +67,7 @@ async fn execute_core_tool(cwd: AbsolutePathBuf, tool: &str) -> Result<ExitStatu
6667

6768
// Check if the tool exists
6869
if !tokio::fs::try_exists(&tool_path).await.unwrap_or(false) {
69-
eprintln!("{} {} not found", "error:".red().bold(), tool.bold());
70+
output::error(&format!("{} not found", tool.bold()));
7071
eprintln!("Node.js {} is not installed.", resolution.version);
7172
eprintln!("Run 'vp env install {}' to install it.", resolution.version);
7273
return Ok(exit_status(1));
@@ -102,7 +103,7 @@ async fn execute_package_binary(
102103

103104
// Check if binary exists
104105
if !tokio::fs::try_exists(&binary_path).await.unwrap_or(false) {
105-
eprintln!("{} binary '{}' not found", "error:".red().bold(), tool.bold());
106+
output::error(&format!("binary '{}' not found", tool.bold()));
106107
eprintln!("Package {} may need to be reinstalled.", metadata.name);
107108
eprintln!("Run 'vp install -g {}' to reinstall.", metadata.name);
108109
return Ok(exit_status(1));

0 commit comments

Comments
 (0)