feat: phase 2 — automatisation: doctor --watch, schedule, service, orchestration, conteneurs (closes #55 #56 #57 #58 #59)

This commit is contained in:
2026-08-18 10:57:00 -04:00
parent 6a6676fc5d
commit 63dc36660b
27 changed files with 1408 additions and 35 deletions
+42 -1
View File
@@ -7,7 +7,10 @@ use crate::output::{boxed_table, print_json, status_style};
use crate::runner::SystemRunner;
use anyhow::Result;
pub fn run(app: &App, fix: bool) -> Result<i32> {
pub fn run(app: &App, fix: bool, watch: Option<u64>) -> Result<i32> {
if let Some(interval) = watch {
return watch_loop(app, interval.max(1));
}
if fix {
let repaired = doctor::fix(app)?;
for r in &repaired {
@@ -61,3 +64,41 @@ pub fn run(app: &App, fix: bool) -> Result<i32> {
}
Ok(if report.ok() { 0 } else { 1 })
}
/// Issue #59: re-run the doctor checks every N seconds; alert (desktop
/// notification + event) on the first failure, recover silently. Clean
/// Ctrl-C via ctrlc.
fn watch_loop(app: &App, interval: u64) -> Result<i32> {
app.log
.info(&format!("watching every {interval}s (Ctrl-C to stop)"));
let mut was_ok = true;
loop {
let runner = SystemRunner::new(false, false, &app.log);
let report = doctor::run(app, &runner);
let ok = report.ok();
if !ok && was_ok {
// First failure: alert.
app.emit(
&Event::now(EventKind::Doctor)
.with_exit_code(1)
.with_reason(format!("{} problem(s) found", report.problems())),
);
app.log.error(&format!(
"{} problem(s) found — 'am doctor --fix' repairs what it can",
report.problems()
));
let _ = crate::process::desktop_notify(
"agent-manager",
&format!("doctor: {} problem(s)", report.problems()),
);
was_ok = false;
} else if ok && !was_ok {
app.log.success("environment recovered");
was_ok = true;
} else if !ok {
app.log
.warn(&format!("still {} problem(s)", report.problems()));
}
std::thread::sleep(std::time::Duration::from_secs(interval));
}
}