Polish run output: tilde paths, retro timing, dim cost, goal spacing

- Shorten paths with ~ instead of full home directory
- Show retro duration right-aligned like stage lines
- Add "Running retro..." indicator before retro agent runs
- Dim the Cost/Tokens summary line
- Add blank line after Goal before progress section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-04 01:16:32 -05:00
parent a71b9d0561
commit 23a943efca
3 changed files with 38 additions and 12 deletions

View file

@ -584,6 +584,16 @@ pub fn format_tokens_human(tokens: i64) -> String {
}
}
/// Shorten an absolute path by replacing the home directory prefix with `~`.
pub fn tilde_path(path: &Path) -> String {
if let Some(home) = dirs::home_dir() {
if let Ok(suffix) = path.strip_prefix(&home) {
return format!("~/{}", suffix.display());
}
}
path.display().to_string()
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -59,7 +59,7 @@ fn red_cross() -> &'static str {
// ── Duration formatting ─────────────────────────────────────────────────
fn format_duration_short(d: Duration) -> String {
pub(crate) fn format_duration_short(d: Duration) -> String {
let secs = d.as_secs();
if secs >= 60 {
format!("{}m{:02}s", secs / 60, secs % 60)
@ -311,7 +311,7 @@ impl ProgressUI {
// ── Logs dir (called externally) ────────────────────────────────────
pub fn show_logs_dir(&mut self, logs_dir: &Path) {
let path_str = logs_dir.display().to_string();
let path_str = super::tilde_path(logs_dir);
match &self.renderer {
ProgressRenderer::Tty(tty) => {
let bar = tty.multi.add(ProgressBar::new_spinner());

View file

@ -219,7 +219,7 @@ pub async fn run_command(
let goal = graph.goal();
if !goal.is_empty() {
eprintln!("{} {goal}", styles.bold.apply_to("Goal:"));
eprintln!("{} {goal}\n", styles.bold.apply_to("Goal:"));
}
print_diagnostics(&diagnostics, styles);
@ -277,7 +277,7 @@ pub async fn run_command(
eprintln!(
"{} {}",
styles.dim.apply_to("Logs:"),
styles.underline.apply_to(logs_dir.display()),
styles.underline.apply_to(super::tilde_path(&logs_dir)),
);
} else {
progress_ui
@ -708,12 +708,15 @@ pub async fn run_command(
if total_tokens > 0 {
if acc.has_pricing {
eprintln!(
"Cost: {} ({} tokens)",
format_cost(acc.total_cost),
format_tokens_human(total_tokens)
"{}",
styles.dim.apply_to(format!(
"Cost: {} ({} tokens)",
format_cost(acc.total_cost),
format_tokens_human(total_tokens)
))
);
} else {
eprintln!("Tokens: {}", format_tokens_human(total_tokens));
eprintln!("{}", styles.dim.apply_to(format!("Tokens: {}", format_tokens_human(total_tokens))));
}
if acc.total_cache_read_tokens > 0 {
eprintln!(
@ -1217,6 +1220,8 @@ async fn generate_retro(
}
// Run retro agent session
eprintln!("{}", styles.dim.apply_to("Running retro..."));
let retro_start = std::time::Instant::now();
let narrative_result = if dry_run_mode {
Ok(crate::retro_agent::dry_run_narrative())
} else if let Some(client) = llm_client {
@ -1224,18 +1229,29 @@ async fn generate_retro(
} else {
Err(anyhow::anyhow!("No LLM client available"))
};
let retro_dur = progress::format_duration_short(retro_start.elapsed());
match narrative_result {
Ok(narrative) => {
retro.apply_narrative(narrative);
match retro.save(logs_dir) {
Ok(()) => {
let retro_path = format!(
"{}/retro.json",
super::tilde_path(logs_dir)
);
let msg = format!("Retro saved to {retro_path}");
let term_width = console::Term::stderr()
.size()
.1 as usize;
let dur_len = retro_dur.len();
let pad = term_width.saturating_sub(msg.len() + dur_len);
eprintln!(
"{} {}",
"{} {}{:pad$}{}",
styles.dim.apply_to("Retro saved to"),
styles
.underline
.apply_to(format!("{}/retro.json", logs_dir.display())),
styles.underline.apply_to(&retro_path),
"",
styles.dim.apply_to(&retro_dur),
);
}
Err(e) => {