Print final stage output after run result summary

Reads the checkpoint to find the last stage with a response and
prints it under an "=== Output ===" header so users can see what
the workflow produced without digging into log files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-04 01:45:13 -05:00
parent eb2246c626
commit 0a0f47b218

View file

@ -744,6 +744,8 @@ pub async fn run_command(
eprintln!("{}", styles.red.apply_to(format!("Failure: {failure}")),);
}
print_final_output(&logs_dir, styles);
// 9. Exit code
match outcome.status {
StageStatus::Success | StageStatus::PartialSuccess => Ok(()),
@ -1019,12 +1021,39 @@ async fn run_from_branch(
HumanDuration(Duration::from_millis(run_duration_ms))
);
print_final_output(&logs_dir, styles);
match outcome.status {
StageStatus::Success | StageStatus::PartialSuccess => Ok(()),
_ => std::process::exit(1),
}
}
/// Print the final stage output from the checkpoint, if available.
fn print_final_output(logs_dir: &std::path::Path, styles: &Styles) {
let checkpoint_path = logs_dir.join("checkpoint.json");
let Ok(data) = std::fs::read_to_string(&checkpoint_path) else {
return;
};
let Ok(checkpoint) = serde_json::from_str::<Checkpoint>(&data) else {
return;
};
// Find the last stage that produced a response (walk completed_nodes in reverse,
// looking for a "response.{node_id}" entry in context_values).
for node_id in checkpoint.completed_nodes.iter().rev() {
let key = format!("response.{node_id}");
if let Some(serde_json::Value::String(response)) = checkpoint.context_values.get(&key) {
let text = response.trim();
if !text.is_empty() {
eprintln!("\n{}", styles.bold.apply_to("=== Output ==="));
eprintln!("{text}");
}
return;
}
}
}
/// Validate run configuration without executing the workflow.
///
/// Boots the sandbox (init + cleanup), checks LLM provider availability,