fix terminal corruption that could happen when onboarding and update banner (#5269)
Instead of printing characters before booting the app, make the upgrade banner a history cell so it's well-behaved. <img width="771" height="586" alt="Screenshot 2025-10-16 at 4 20 51 PM" src="https://github.com/user-attachments/assets/90629d47-2c3d-4970-a826-283795ab34e5" /> --------- Co-authored-by: Josh McKinney <joshka@openai.com>
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
#![cfg(any(not(debug_assertions), test))]
|
||||
|
||||
use chrono::DateTime;
|
||||
use chrono::Duration;
|
||||
use chrono::Utc;
|
||||
@@ -142,6 +140,53 @@ fn parse_version(v: &str) -> Option<(u64, u64, u64)> {
|
||||
Some((maj, min, pat))
|
||||
}
|
||||
|
||||
/// Update action the CLI should perform after the TUI exits.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UpdateAction {
|
||||
/// Update via `npm install -g @openai/codex@latest`.
|
||||
NpmGlobalLatest,
|
||||
/// Update via `bun install -g @openai/codex@latest`.
|
||||
BunGlobalLatest,
|
||||
/// Update via `brew upgrade codex`.
|
||||
BrewUpgrade,
|
||||
}
|
||||
|
||||
#[cfg(any(not(debug_assertions), test))]
|
||||
pub(crate) fn get_update_action() -> Option<UpdateAction> {
|
||||
let exe = std::env::current_exe().unwrap_or_default();
|
||||
let managed_by_npm = std::env::var_os("CODEX_MANAGED_BY_NPM").is_some();
|
||||
let managed_by_bun = std::env::var_os("CODEX_MANAGED_BY_BUN").is_some();
|
||||
if managed_by_npm {
|
||||
Some(UpdateAction::NpmGlobalLatest)
|
||||
} else if managed_by_bun {
|
||||
Some(UpdateAction::BunGlobalLatest)
|
||||
} else if cfg!(target_os = "macos")
|
||||
&& (exe.starts_with("/opt/homebrew") || exe.starts_with("/usr/local"))
|
||||
{
|
||||
Some(UpdateAction::BrewUpgrade)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl UpdateAction {
|
||||
/// Returns the list of command-line arguments for invoking the update.
|
||||
pub fn command_args(self) -> (&'static str, &'static [&'static str]) {
|
||||
match self {
|
||||
UpdateAction::NpmGlobalLatest => ("npm", &["install", "-g", "@openai/codex@latest"]),
|
||||
UpdateAction::BunGlobalLatest => ("bun", &["install", "-g", "@openai/codex@latest"]),
|
||||
UpdateAction::BrewUpgrade => ("brew", &["upgrade", "codex"]),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns string representation of the command-line arguments for invoking the update.
|
||||
pub fn command_str(self) -> String {
|
||||
let (command, args) = self.command_args();
|
||||
let args_str = args.join(" ");
|
||||
format!("{command} {args_str}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -165,4 +210,24 @@ mod tests {
|
||||
assert_eq!(parse_version(" 1.2.3 \n"), Some((1, 2, 3)));
|
||||
assert_eq!(is_newer(" 1.2.3 ", "1.2.2"), Some(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_update_action() {
|
||||
let prev = std::env::var_os("CODEX_MANAGED_BY_NPM");
|
||||
|
||||
// First: no npm var -> expect None (we do not run from brew in CI)
|
||||
unsafe { std::env::remove_var("CODEX_MANAGED_BY_NPM") };
|
||||
assert_eq!(get_update_action(), None);
|
||||
|
||||
// Then: with npm var -> expect NpmGlobalLatest
|
||||
unsafe { std::env::set_var("CODEX_MANAGED_BY_NPM", "1") };
|
||||
assert_eq!(get_update_action(), Some(UpdateAction::NpmGlobalLatest));
|
||||
|
||||
// Restore prior value to avoid leaking state
|
||||
if let Some(v) = prev {
|
||||
unsafe { std::env::set_var("CODEX_MANAGED_BY_NPM", v) };
|
||||
} else {
|
||||
unsafe { std::env::remove_var("CODEX_MANAGED_BY_NPM") };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user