diff --git a/attractor-web/src/EventLog.tsx b/attractor-web/src/EventLog.tsx index 2b77424e3..9faf8ecb6 100644 --- a/attractor-web/src/EventLog.tsx +++ b/attractor-web/src/EventLog.tsx @@ -30,8 +30,11 @@ function eventDetail(event: PipelineEvent): string { return `${data.error} (${data.duration_ms}ms)`; case "StageStarted": return `${data.name} [${data.index}]`; - case "StageCompleted": - return `${data.name} [${data.index}] ${data.duration_ms}ms`; + case "StageCompleted": { + let detail = `${data.name} [${data.index}] ${data.duration_ms}ms ${data.status}`; + if (data.preferred_label) detail += ` → "${data.preferred_label}"`; + return detail; + } case "StageFailed": return `${data.name} [${data.index}]: ${data.error}${data.will_retry ? " (will retry)" : ""}`; case "StageRetrying": diff --git a/attractor-web/src/api.ts b/attractor-web/src/api.ts index 4e303fa7b..718c53bdd 100644 --- a/attractor-web/src/api.ts +++ b/attractor-web/src/api.ts @@ -54,7 +54,7 @@ export type PipelineEvent = | { PipelineCompleted: { duration_ms: number; artifact_count: number } } | { PipelineFailed: { error: string; duration_ms: number } } | { StageStarted: { name: string; index: number } } - | { StageCompleted: { name: string; index: number; duration_ms: number } } + | { StageCompleted: { name: string; index: number; duration_ms: number; status: string; preferred_label?: string; suggested_next_ids: string[] } } | { StageFailed: { name: string; index: number; error: string; will_retry: boolean } } | { StageRetrying: { name: string; index: number; attempt: number; delay_ms: number } } | { ParallelStarted: { branch_count: number } } diff --git a/crates/attractor/src/cli/mod.rs b/crates/attractor/src/cli/mod.rs index 844943230..9acecfca5 100644 --- a/crates/attractor/src/cli/mod.rs +++ b/crates/attractor/src/cli/mod.rs @@ -164,8 +164,18 @@ pub fn format_event_summary(event: &PipelineEvent, styles: &Styles) -> String { name, index, duration_ms, + status, + preferred_label, + suggested_next_ids, } => { - format!("[STAGE_COMPLETED] name={name} index={index} duration={duration_ms}ms") + let mut s = format!("[STAGE_COMPLETED] name={name} index={index} duration={duration_ms}ms status={status}"); + if let Some(label) = preferred_label { + s.push_str(&format!(" preferred_label=\"{label}\"")); + } + if !suggested_next_ids.is_empty() { + s.push_str(&format!(" suggested_next_ids={}", suggested_next_ids.join(","))); + } + s } PipelineEvent::StageFailed { name, @@ -263,8 +273,18 @@ pub fn format_event_detail(event: &PipelineEvent, styles: &Styles) -> String { name, index, duration_ms, + status, + preferred_label, + suggested_next_ids, } => { - format!("{d}── STAGE_COMPLETED ──────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}duration_ms:{r} {duration_ms}\n") + let mut s = format!("{d}── STAGE_COMPLETED ──────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}duration_ms:{r} {duration_ms}\n {d}status:{r} {status}\n"); + if let Some(label) = preferred_label { + s.push_str(&format!(" {d}preferred_label:{r} {label}\n")); + } + if !suggested_next_ids.is_empty() { + s.push_str(&format!(" {d}suggested_next_ids:{r} {}\n", suggested_next_ids.join(", "))); + } + s } PipelineEvent::StageFailed { name, diff --git a/crates/attractor/src/event.rs b/crates/attractor/src/event.rs index c0451d979..8d0b8ddd2 100644 --- a/crates/attractor/src/event.rs +++ b/crates/attractor/src/event.rs @@ -23,6 +23,9 @@ pub enum PipelineEvent { name: String, index: usize, duration_ms: u64, + status: String, + preferred_label: Option, + suggested_next_ids: Vec, }, StageFailed { name: String,