From d348ff405ca9f37711f918db9570598ca85e3a55 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 23 Feb 2026 00:55:02 +0900 Subject: fix(audit): write human-readable output to stderr to match Composer Composer writes advisory and abandoned-package output to stderr, reserving stdout for JSON format only. Mozart was writing everything to stdout, which breaks piping and scripting workflows. Co-Authored-By: Claude Opus 4.6 --- crates/mozart/src/commands/audit.rs | 68 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'crates') diff --git a/crates/mozart/src/commands/audit.rs b/crates/mozart/src/commands/audit.rs index 497726c..70c4400 100644 --- a/crates/mozart/src/commands/audit.rs +++ b/crates/mozart/src/commands/audit.rs @@ -103,7 +103,7 @@ pub async fn execute( let packages = load_packages(&working_dir, args.locked, args.no_dev)?; if packages.is_empty() { - println!("No packages - skipping audit."); + eprintln!("No packages - skipping audit."); return Ok(()); } @@ -386,7 +386,7 @@ fn detect_abandoned(packages: &[PackageEntry]) -> Vec { fn render_table(result: &AuditResult) { if result.total_advisory_count == 0 && result.abandoned.is_empty() { - println!( + eprintln!( "{}", mozart_core::console::info("No security vulnerability advisories found.") ); @@ -403,8 +403,8 @@ fn render_table(result: &AuditResult) { "Found {} security vulnerability {} affecting {} package(s):", result.total_advisory_count, advisory_word, result.affected_package_count ); - println!("{}", mozart_core::console::highlight(&header)); - println!(); + eprintln!("{}", mozart_core::console::highlight(&header)); + eprintln!(); for advisories in result.advisories.values() { for matched in advisories { @@ -436,9 +436,9 @@ fn render_table(result: &AuditResult) { vw = value_width ); - println!("{}", separator); + eprintln!("{}", separator); for (label, value) in &rows { - println!( + eprintln!( "| {: println!( + Some(repl) => eprintln!( "{} ({}) is abandoned. Use {} instead.", pkg.name, pkg.version, repl ), - None => println!( + None => eprintln!( "{} ({}) is abandoned. No replacement was suggested.", pkg.name, pkg.version ), @@ -600,27 +600,27 @@ fn render_json(result: &AuditResult) -> anyhow::Result<()> { fn render_summary(result: &AuditResult) { if result.total_advisory_count == 0 { - println!("No security vulnerability advisories found."); + eprintln!("No security vulnerability advisories found."); } else { let advisory_word = if result.total_advisory_count == 1 { "advisory" } else { "advisories" }; - println!( + eprintln!( "Found {} security vulnerability {} affecting {} package(s).", result.total_advisory_count, advisory_word, result.affected_package_count ); - println!("Run \"mozart audit\" for a full list of advisories."); + eprintln!("Run \"mozart audit\" for a full list of advisories."); } for pkg in &result.abandoned { match &pkg.replacement { - Some(repl) => println!( + Some(repl) => eprintln!( "{} ({}) is abandoned. Use {} instead.", pkg.name, pkg.version, repl ), - None => println!( + None => eprintln!( "{} ({}) is abandoned. No replacement was suggested.", pkg.name, pkg.version ), -- cgit v1.3.1