Skip to content

Commit ec1ecd3

Browse files
committed
feat: guided setup: start
1 parent 1e45001 commit ec1ecd3

16 files changed

Lines changed: 1743 additions & 3 deletions

File tree

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/maabarium-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ path = "src/main.rs"
1313
maabarium-core = { path = "../maabarium-core" }
1414
tokio = { workspace = true }
1515
tokio-util = { workspace = true }
16+
serde_json = { workspace = true }
1617
clap = { workspace = true }
1718
tracing = { workspace = true }
1819
tracing-subscriber = { workspace = true }

crates/maabarium-cli/src/main.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use maabarium_core::{
44
ExportFormat, GitDependencyEnsureOutcome, Persistence, PromotionOutcome, SecretStore,
55
UpdaterConfiguration, check_for_cli_update, default_db_path, default_log_path,
66
ensure_git_dependency, install_cli_update,
7+
ReadinessLevel, ReadinessScanner,
8+
analyze_workspace, apply_all_fixes, detect_recommended_profile,
79
};
810
use maabarium_core::error::UpdaterError;
911
use secrecy::{ExposeSecret, SecretString};
@@ -49,6 +51,21 @@ enum Commands {
4951
#[command(subcommand)]
5052
action: KeysAction,
5153
},
54+
/// Check and fix setup readiness
55+
Setup {
56+
/// Non-interactive readiness check (exit 0 = ready, 1 = needs attention)
57+
#[arg(long)]
58+
check: bool,
59+
/// Output readiness report as JSON
60+
#[arg(long)]
61+
json: bool,
62+
/// Workspace path to analyze
63+
#[arg(long)]
64+
workspace: Option<String>,
65+
/// Runtime strategy hint: local, mixed, remote
66+
#[arg(long)]
67+
strategy: Option<String>,
68+
},
5269
/// Inspect and update the CLI binary itself
5370
#[command(name = "self")]
5471
SelfManage {
@@ -182,6 +199,60 @@ async fn main() -> anyhow::Result<()> {
182199
println!("{}", render_delete_key_message(&secret_store, &provider)?);
183200
}
184201
},
202+
Commands::Setup {
203+
check,
204+
json,
205+
workspace,
206+
strategy,
207+
} => {
208+
let workspace_ref = workspace.as_deref();
209+
let strategy_ref = strategy.as_deref();
210+
let report = ReadinessScanner::scan(workspace_ref, strategy_ref);
211+
212+
if json {
213+
println!("{}", serde_json::to_string_pretty(&report)?);
214+
} else {
215+
render_readiness_report(&report, workspace_ref);
216+
}
217+
218+
if check {
219+
if !report.is_ready() {
220+
std::process::exit(1);
221+
}
222+
} else {
223+
// Interactive: attempt fixes for items needing attention
224+
let needs_fix = report.needs_attention();
225+
if needs_fix.is_empty() {
226+
println!("\nAll checks passed. Maabarium is ready to run.");
227+
} else {
228+
println!("\nAttempting one-click fixes...");
229+
let outcomes = apply_all_fixes(workspace_ref);
230+
for outcome in &outcomes {
231+
let icon = if outcome.success { "[OK]" } else { "[!!]" };
232+
println!(" {icon} {}", outcome.message);
233+
}
234+
if outcomes.iter().any(|o| !o.success) {
235+
println!("\nSome fixes require manual intervention. See messages above.");
236+
} else {
237+
println!("\nAll automatic fixes applied successfully.");
238+
}
239+
}
240+
241+
// Show workspace analysis if workspace provided
242+
if let Some(ws) = workspace_ref {
243+
let analysis = analyze_workspace(ws);
244+
render_workspace_analysis(&analysis);
245+
}
246+
247+
// Show recommended profile
248+
let recommended = detect_recommended_profile();
249+
println!(
250+
"\nRecommended environment profile: {} - {}",
251+
recommended.label(),
252+
recommended.description()
253+
);
254+
}
255+
}
185256
Commands::SelfManage { action } => match action {
186257
SelfAction::Version => {
187258
println!("maabarium {}", env!("CARGO_PKG_VERSION"));
@@ -435,6 +506,59 @@ fn render_delete_key_message(
435506
}
436507
}
437508

509+
fn render_readiness_report(report: &maabarium_core::ReadinessReport, workspace: Option<&str>) {
510+
println!("Maabarium Setup Readiness Report");
511+
println!("===============================");
512+
if let Some(ws) = workspace {
513+
println!("Workspace: {ws}");
514+
}
515+
println!();
516+
517+
for item in &report.items {
518+
let icon = match item.status {
519+
ReadinessLevel::Ready => "[OK]",
520+
ReadinessLevel::Optional => "[--]",
521+
ReadinessLevel::NeedsAction => "[!!]",
522+
};
523+
println!("{} {}", icon, item.title);
524+
println!(" {}", item.summary);
525+
if let Some(fix) = &item.fix_label {
526+
println!(" Action: {fix}");
527+
}
528+
if let Some(hint) = &item.fix_hint {
529+
println!(" Hint: {hint}");
530+
}
531+
println!();
532+
}
533+
534+
if report.is_ready() {
535+
println!("Status: READY - All checks passed.");
536+
} else {
537+
let count = report.needs_attention().len();
538+
println!("Status: NEEDS ATTENTION - {count} item(s) require fixes.");
539+
}
540+
}
541+
542+
fn render_workspace_analysis(analysis: &maabarium_core::WorkspaceAnalysis) {
543+
println!("\nWorkspace Analysis: {}", analysis.path);
544+
println!(" {}", analysis.project_summary);
545+
if let Some(lang) = &analysis.language {
546+
println!(" Language: {lang}");
547+
}
548+
if let Some(cmd) = &analysis.test_command {
549+
println!(" Test command: {cmd}");
550+
}
551+
if !analysis.suggested_target_files.is_empty() {
552+
println!(
553+
" Suggested targets: {}",
554+
analysis.suggested_target_files.join(", ")
555+
);
556+
}
557+
if analysis.has_ci_config {
558+
println!(" CI configuration detected");
559+
}
560+
}
561+
438562
#[cfg(test)]
439563
mod tests {
440564
use super::*;

crates/maabarium-core/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod metrics;
1515
pub mod persistence;
1616
pub mod runtime_dependencies;
1717
pub mod secrets;
18+
pub mod setup_wizard;
1819
pub mod updater;
1920

2021
pub use blueprint::{
@@ -40,6 +41,15 @@ pub use runtime_dependencies::{
4041
git_dependency_status,
4142
};
4243
pub use secrets::{ApiKeyStore, SecretStore};
44+
pub use setup_wizard::{
45+
EnvironmentProfile, FixOutcome, FixTarget, OllamaStatus as SetupOllamaStatus,
46+
ProfileConfig, ProviderValidationResult, ReadinessItem as SetupReadinessItem,
47+
ReadinessLevel, ReadinessReport, ReadinessScanner, WorkspaceAnalysis,
48+
analyze_workspace, apply_all_fixes, apply_git_fix, apply_profile,
49+
detect_recommended_profile, ollama_status as setup_ollama_status,
50+
start_ollama as setup_start_ollama, validate_ollama_connection,
51+
validate_provider_connection,
52+
};
4353
pub use updater::{
4454
CliArtifactManifest, CliReleaseArtifact, ReleaseManifest, UpdaterConfiguration,
4555
check_for_cli_update, install_cli_update,

0 commit comments

Comments
 (0)