diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index d82fa19a..e959973b 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -273,6 +273,8 @@ async fn run_ratatui_app( // within the TUI scrollback. Building spans keeps styling consistent. #[cfg(not(debug_assertions))] if let Some(latest_version) = updates::get_upgrade_version(&config) { + use crate::history_cell::padded_emoji; + use crate::history_cell::with_border_with_inner_width; use ratatui::style::Stylize as _; use ratatui::text::Line; @@ -280,16 +282,27 @@ async fn run_ratatui_app( let exe = std::env::current_exe()?; let managed_by_npm = std::env::var_os("CODEX_MANAGED_BY_NPM").is_some(); - let mut lines: Vec> = Vec::new(); - lines.push(Line::from(vec![ - "✨⬆️ Update available!".bold().cyan(), - " ".into(), - format!("{current_version} -> {latest_version}.").into(), - ])); + let mut content_lines: Vec> = vec![ + Line::from(vec![ + padded_emoji("✨").bold().cyan(), + "Update available!".bold().cyan(), + " ".into(), + format!("{current_version} -> {latest_version}.").bold(), + ]), + Line::from(""), + Line::from("See full release notes:"), + Line::from(""), + Line::from( + "https://github.com/openai/codex/releases/latest" + .cyan() + .underlined(), + ), + Line::from(""), + ]; if managed_by_npm { let npm_cmd = "npm install -g @openai/codex@latest"; - lines.push(Line::from(vec![ + content_lines.push(Line::from(vec![ "Run ".into(), npm_cmd.cyan(), " to update.".into(), @@ -298,19 +311,22 @@ async fn run_ratatui_app( && (exe.starts_with("/opt/homebrew") || exe.starts_with("/usr/local")) { let brew_cmd = "brew upgrade codex"; - lines.push(Line::from(vec![ + content_lines.push(Line::from(vec![ "Run ".into(), brew_cmd.cyan(), " to update.".into(), ])); } else { - lines.push(Line::from(vec![ + content_lines.push(Line::from(vec![ "See ".into(), - "https://github.com/openai/codex/releases/latest".cyan(), - " for the latest releases and installation options.".into(), + "https://github.com/openai/codex".cyan().underlined(), + " for installation options.".into(), ])); } + let viewport_width = tui.terminal.viewport_area.width as usize; + let inner_width = viewport_width.saturating_sub(4).max(1); + let mut lines = with_border_with_inner_width(content_lines, inner_width); lines.push("".into()); tui.insert_history_lines(lines); }