Skip to content

Commit 2734a47

Browse files
authored
Merge pull request #21 from dwalleck/feat/catalyst-cli-phase4-validation-status
feat: Phase 4 - Validation & Status Command
2 parents 0e92eb8 + e220203 commit 2734a47

5 files changed

Lines changed: 1031 additions & 66 deletions

File tree

catalyst-cli/src/bin/catalyst.rs

Lines changed: 279 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,49 @@ fn main() -> Result<()> {
340340
let target_dir =
341341
path.unwrap_or_else(|| env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
342342

343-
if use_color {
344-
println!("{}", "⚠️ Not implemented yet".yellow().bold());
345-
} else {
346-
println!("⚠️ Not implemented yet");
343+
// Detect platform
344+
let platform = catalyst_cli::types::Platform::detect();
345+
346+
// Validate installation
347+
match catalyst_cli::status::validate_installation(&target_dir, platform) {
348+
Ok(report) => {
349+
// If --fix flag provided and there are auto-fixable issues, attempt fixes
350+
let mut fixed_issues = Vec::new();
351+
if fix && report.issues.iter().any(|i| i.auto_fixable) {
352+
match catalyst_cli::status::auto_fix(&target_dir, platform, &report) {
353+
Ok(fixes) => {
354+
fixed_issues = fixes;
355+
}
356+
Err(e) => {
357+
if use_color {
358+
eprintln!(
359+
"{}",
360+
format!("❌ Auto-fix failed: {}", e).red().bold()
361+
);
362+
} else {
363+
eprintln!("❌ Auto-fix failed: {}", e);
364+
}
365+
}
366+
}
367+
}
368+
369+
// Display status report
370+
display_status_report(&report, use_color, &fixed_issues);
371+
372+
// Exit with error code if status is not ok
373+
if report.level != catalyst_cli::types::StatusLevel::Ok {
374+
std::process::exit(1);
375+
}
376+
}
377+
Err(e) => {
378+
if use_color {
379+
eprintln!("{}", format!("❌ Status check failed: {}", e).red().bold());
380+
} else {
381+
eprintln!("❌ Status check failed: {}", e);
382+
}
383+
std::process::exit(1);
384+
}
347385
}
348-
println!("Would check status: {:?}", target_dir);
349-
println!(" Auto-fix: {}", fix);
350386
}
351387

352388
Commands::Update { path, force } => {
@@ -546,3 +582,240 @@ fn main() -> Result<()> {
546582

547583
Ok(())
548584
}
585+
586+
/// Display a formatted status report
587+
fn display_status_report(
588+
report: &catalyst_cli::types::StatusReport,
589+
use_color: bool,
590+
fixed_issues: &[String],
591+
) {
592+
use catalyst_cli::types::{IssueSeverity, StatusLevel};
593+
594+
// Show fixed issues first if any
595+
if !fixed_issues.is_empty() {
596+
if use_color {
597+
println!("\n{}", "🔧 Auto-Fix Results:".cyan().bold());
598+
} else {
599+
println!("\n🔧 Auto-Fix Results:");
600+
}
601+
for fix in fixed_issues {
602+
if use_color {
603+
println!(" {}", format!("✓ {}", fix).green());
604+
} else {
605+
println!(" ✓ {}", fix);
606+
}
607+
}
608+
println!();
609+
}
610+
611+
// Overall status header
612+
let (status_icon, status_text) = match report.level {
613+
StatusLevel::Ok => ("✅", "HEALTHY"),
614+
StatusLevel::Warning => ("⚠️", "WARNING"),
615+
StatusLevel::Error => ("❌", "ERROR"),
616+
};
617+
618+
if use_color {
619+
match report.level {
620+
StatusLevel::Ok => {
621+
println!(
622+
"{} {}",
623+
status_icon,
624+
format!("Catalyst Status: {}", status_text).green().bold()
625+
);
626+
}
627+
StatusLevel::Warning => {
628+
println!(
629+
"{} {}",
630+
status_icon,
631+
format!("Catalyst Status: {}", status_text).yellow().bold()
632+
);
633+
}
634+
StatusLevel::Error => {
635+
println!(
636+
"{} {}",
637+
status_icon,
638+
format!("Catalyst Status: {}", status_text).red().bold()
639+
);
640+
}
641+
}
642+
} else {
643+
println!("{} Catalyst Status: {}", status_icon, status_text);
644+
}
645+
println!();
646+
647+
// Binaries section
648+
if !report.binaries.is_empty() {
649+
if use_color {
650+
println!("{}", "Binaries:".cyan().bold());
651+
} else {
652+
println!("Binaries:");
653+
}
654+
for binary in &report.binaries {
655+
let status_icon = if binary.exists && binary.executable {
656+
"✓"
657+
} else {
658+
"✗"
659+
};
660+
let status_text = if binary.exists {
661+
if binary.executable {
662+
"found"
663+
} else {
664+
"not executable"
665+
}
666+
} else {
667+
"not found"
668+
};
669+
670+
let variant_text = if let Some(ref v) = binary.variant {
671+
format!(" ({})", v)
672+
} else {
673+
String::new()
674+
};
675+
676+
if use_color {
677+
if binary.exists && binary.executable {
678+
println!(
679+
" {} {}{}",
680+
status_icon,
681+
format!("{} ({})", binary.name, status_text).green(),
682+
variant_text
683+
);
684+
} else {
685+
println!(
686+
" {} {}{}",
687+
status_icon,
688+
format!("{} ({})", binary.name, status_text).red(),
689+
variant_text
690+
);
691+
}
692+
} else {
693+
println!(
694+
" {} {} ({}){}",
695+
status_icon, binary.name, status_text, variant_text
696+
);
697+
}
698+
}
699+
println!();
700+
}
701+
702+
// Hooks section
703+
if !report.hooks.is_empty() {
704+
if use_color {
705+
println!("{}", "Hooks:".cyan().bold());
706+
} else {
707+
println!("Hooks:");
708+
}
709+
for hook in &report.hooks {
710+
let status_icon = if hook.exists && hook.executable && hook.calls_correct_binary {
711+
"✓"
712+
} else {
713+
"✗"
714+
};
715+
let event = hook.event.as_deref().unwrap_or("unknown");
716+
717+
if use_color {
718+
if hook.exists && hook.executable && hook.calls_correct_binary {
719+
println!(" {} {} → {}", status_icon, event.green(), hook.name);
720+
} else {
721+
println!(" {} {} → {}", status_icon, event.red(), hook.name);
722+
}
723+
} else {
724+
println!(" {} {} → {}", status_icon, event, hook.name);
725+
}
726+
}
727+
println!();
728+
}
729+
730+
// Skills section
731+
if !report.skills.is_empty() {
732+
if use_color {
733+
println!("{}", "Skills:".cyan().bold());
734+
} else {
735+
println!("Skills:");
736+
}
737+
for skill in &report.skills {
738+
let status_icon = if skill.has_main_file { "✓" } else { "✗" };
739+
let status_text = if skill.has_main_file {
740+
"installed"
741+
} else {
742+
"incomplete"
743+
};
744+
745+
if use_color {
746+
if skill.has_main_file {
747+
println!(" {} {} ({})", status_icon, skill.name.green(), status_text);
748+
} else {
749+
println!(" {} {} ({})", status_icon, skill.name.red(), status_text);
750+
}
751+
} else {
752+
println!(" {} {} ({})", status_icon, skill.name, status_text);
753+
}
754+
}
755+
println!();
756+
}
757+
758+
// Issues section
759+
if !report.issues.is_empty() {
760+
if use_color {
761+
println!("{}", "Issues:".cyan().bold());
762+
} else {
763+
println!("Issues:");
764+
}
765+
for issue in &report.issues {
766+
let severity_icon = match issue.severity {
767+
IssueSeverity::Error => "❌",
768+
IssueSeverity::Warning => "⚠️",
769+
IssueSeverity::Info => "ℹ️",
770+
};
771+
772+
if use_color {
773+
let colored_desc = match issue.severity {
774+
IssueSeverity::Error => issue.description.red(),
775+
IssueSeverity::Warning => issue.description.yellow(),
776+
IssueSeverity::Info => issue.description.blue(),
777+
};
778+
println!(" {} [{}] {}", severity_icon, issue.component, colored_desc);
779+
} else {
780+
println!(
781+
" {} [{}] {}",
782+
severity_icon, issue.component, issue.description
783+
);
784+
}
785+
786+
if let Some(ref fix) = issue.suggested_fix {
787+
if use_color {
788+
println!(" {}", format!("→ {}", fix).cyan());
789+
} else {
790+
println!(" → {}", fix);
791+
}
792+
}
793+
}
794+
println!();
795+
} else {
796+
if use_color {
797+
println!("{}", "Issues: None".green());
798+
} else {
799+
println!("Issues: None");
800+
}
801+
println!();
802+
}
803+
804+
// Final message
805+
if report.level == StatusLevel::Ok {
806+
if use_color {
807+
println!("{}", "All systems operational! 🚀".green().bold());
808+
} else {
809+
println!("All systems operational! 🚀");
810+
}
811+
} else if report.issues.iter().any(|i| i.auto_fixable) && fixed_issues.is_empty() {
812+
if use_color {
813+
println!(
814+
"{}",
815+
"Run 'catalyst status --fix' to auto-repair fixable issues.".yellow()
816+
);
817+
} else {
818+
println!("Run 'catalyst status --fix' to auto-repair fixable issues.");
819+
}
820+
}
821+
}

catalyst-cli/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! for the Catalyst CLI tool.
55
66
pub mod init;
7+
pub mod status;
78
pub mod types;
89
pub mod validation;
910

0 commit comments

Comments
 (0)