From 7a6266323c6d0f17afa2549f5cff02c7c98a3c68 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 11 Apr 2026 15:46:54 -0700 Subject: [PATCH] Restore codex-tui resume hint on exit (#17415) Addresses #17303 Problem: The standalone codex-tui entrypoint only printed token usage on exit, so resumable sessions could omit the codex resume footer even when thread metadata was available. Solution: Format codex-tui exit output from AppExitInfo so it includes the same resume hint as the main CLI and reports fatal exits consistently. --- codex-rs/tui/src/main.rs | 45 ++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs index 5fca7c60f..48ef3e4cd 100644 --- a/codex-rs/tui/src/main.rs +++ b/codex-rs/tui/src/main.rs @@ -2,9 +2,37 @@ use clap::Parser; use codex_app_server_client::legacy_core; use codex_arg0::Arg0DispatchPaths; use codex_arg0::arg0_dispatch_or_else; +use codex_tui::AppExitInfo; use codex_tui::Cli; +use codex_tui::ExitReason; use codex_tui::run_main; use codex_utils_cli::CliConfigOverrides; +use supports_color::Stream; + +fn format_exit_messages(exit_info: AppExitInfo, color_enabled: bool) -> Vec { + let AppExitInfo { + token_usage, + thread_id, + thread_name, + .. + } = exit_info; + + let mut lines = Vec::new(); + if !token_usage.is_zero() { + lines.push(codex_protocol::protocol::FinalOutput::from(token_usage).to_string()); + } + + if let Some(resume_cmd) = legacy_core::util::resume_command(thread_name.as_deref(), thread_id) { + let command = if color_enabled { + format!("\u{1b}[36m{resume_cmd}\u{1b}[39m") + } else { + resume_cmd + }; + lines.push(format!("To continue this session, run {command}")); + } + + lines +} #[derive(Parser, Debug)] struct TopCli { @@ -31,12 +59,17 @@ fn main() -> anyhow::Result<()> { /*remote_auth_token*/ None, ) .await?; - let token_usage = exit_info.token_usage; - if !token_usage.is_zero() { - println!( - "{}", - codex_protocol::protocol::FinalOutput::from(token_usage), - ); + match exit_info.exit_reason { + ExitReason::Fatal(message) => { + eprintln!("ERROR: {message}"); + std::process::exit(1); + } + ExitReason::UserRequested => {} + } + + let color_enabled = supports_color::on(Stream::Stdout).is_some(); + for line in format_exit_messages(exit_info, color_enabled) { + println!("{line}"); } Ok(()) })