diff --git a/codex-rs/config/src/requirements_exec_policy.rs b/codex-rs/config/src/requirements_exec_policy.rs index 30a1a0e69..95f02b249 100644 --- a/codex-rs/config/src/requirements_exec_policy.rs +++ b/codex-rs/config/src/requirements_exec_policy.rs @@ -1,9 +1,9 @@ use codex_execpolicy::Decision; -use codex_execpolicy::PatternToken; use codex_execpolicy::Policy; -use codex_execpolicy::PrefixPattern; -use codex_execpolicy::PrefixRule; use codex_execpolicy::RuleRef; +use codex_execpolicy::rule::PatternToken; +use codex_execpolicy::rule::PrefixPattern; +use codex_execpolicy::rule::PrefixRule; use multimap::MultiMap; use serde::Deserialize; use std::sync::Arc; diff --git a/codex-rs/execpolicy/src/lib.rs b/codex-rs/execpolicy/src/lib.rs index 128c9dd41..45d364241 100644 --- a/codex-rs/execpolicy/src/lib.rs +++ b/codex-rs/execpolicy/src/lib.rs @@ -5,7 +5,7 @@ pub(crate) mod execpolicycheck; mod executable_name; pub(crate) mod parser; pub(crate) mod policy; -pub(crate) mod rule; +pub mod rule; pub use amend::AmendError; pub use amend::blocking_append_allow_prefix_rule; diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index 6cf6c18d3..acd022a8a 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -455,7 +455,10 @@ impl ChatComposer { realtime_conversation_enabled: false, audio_device_selection_enabled: false, windows_degraded_sandbox_active: false, - is_zellij: codex_terminal_detection::terminal_info().is_zellij(), + is_zellij: matches!( + codex_terminal_detection::terminal_info().multiplexer, + Some(codex_terminal_detection::Multiplexer::Zellij {}) + ), status_line_value: None, status_line_enabled: false, active_agent_label: None, diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index c198e0d5c..267232c60 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -14,6 +14,7 @@ use codex_app_server_client::InProcessAppServerClient; use codex_app_server_client::InProcessClientStartArgs; use codex_app_server_client::RemoteAppServerClient; use codex_app_server_client::RemoteAppServerConnectArgs; +use codex_app_server_protocol::Account as AppServerAccount; use codex_app_server_protocol::AuthMode as AppServerAuthMode; use codex_app_server_protocol::ConfigWarningNotification; use codex_app_server_protocol::Thread as AppServerThread; @@ -1016,32 +1017,33 @@ async fn run_ratatui_app( // Initialize high-fidelity session event logging if enabled. session_log::maybe_init(&initial_config); + let mut app_server = Some( + match start_app_server( + &app_server_target, + arg0_paths.clone(), + initial_config.clone(), + cli_kv_overrides.clone(), + loader_overrides.clone(), + cloud_requirements.clone(), + feedback.clone(), + ) + .await + { + Ok(app_server) => AppServerSession::new(app_server) + .with_remote_cwd_override(remote_cwd_override.clone()), + Err(err) => { + terminal_restore_guard.restore_silently(); + session_log::log_session_end(); + return Err(err); + } + }, + ); + let should_show_trust_screen_flag = !remote_mode && should_show_trust_screen(&initial_config); let mut trust_decision_was_made = false; - let needs_onboarding_app_server = - should_show_trust_screen_flag || initial_config.model_provider.requires_openai_auth; - let mut onboarding_app_server = if needs_onboarding_app_server { - Some( - AppServerSession::new( - start_app_server( - &app_server_target, - arg0_paths.clone(), - initial_config.clone(), - cli_kv_overrides.clone(), - loader_overrides.clone(), - cloud_requirements.clone(), - feedback.clone(), - ) - .await?, - ) - .with_remote_cwd_override(remote_cwd_override.clone()), - ) - } else { - None - }; let login_status = if initial_config.model_provider.requires_openai_auth { - let Some(app_server) = onboarding_app_server.as_mut() else { - unreachable!("onboarding app server should exist when auth is required"); + let Some(app_server) = app_server.as_mut() else { + unreachable!("app server should exist when auth is required"); }; get_login_status(app_server, &initial_config).await? } else { @@ -1057,13 +1059,13 @@ async fn run_ratatui_app( show_login_screen, show_trust_screen: should_show_trust_screen_flag, login_status, - app_server_request_handle: onboarding_app_server + app_server_request_handle: app_server .as_ref() .map(AppServerSession::request_handle), config: initial_config.clone(), }, if show_login_screen { - onboarding_app_server.take() + app_server.as_mut() } else { None }, @@ -1071,6 +1073,7 @@ async fn run_ratatui_app( ) .await?; if onboarding_result.should_exit { + shutdown_app_server_if_present(app_server.take()).await; terminal_restore_guard.restore_silently(); session_log::log_session_end(); let _ = tui.terminal.clear(); @@ -1110,10 +1113,8 @@ async fn run_ratatui_app( initial_config } } else { - shutdown_app_server_if_present(onboarding_app_server.take()).await; initial_config }; - shutdown_app_server_if_present(onboarding_app_server.take()).await; let mut missing_session_exit = |id_str: &str, action: &str| { error!("Error finding conversation path: {id_str}"); @@ -1131,42 +1132,16 @@ async fn run_ratatui_app( }) }; - let needs_app_server_session_lookup = cli.resume_last - || cli.fork_last - || cli.resume_session_id.is_some() - || cli.fork_session_id.is_some() - || cli.resume_picker - || cli.fork_picker; - let mut session_lookup_app_server = if needs_app_server_session_lookup { - Some( - AppServerSession::new( - start_app_server( - &app_server_target, - arg0_paths.clone(), - config.clone(), - cli_kv_overrides.clone(), - loader_overrides.clone(), - cloud_requirements.clone(), - feedback.clone(), - ) - .await?, - ) - .with_remote_cwd_override(remote_cwd_override.clone()), - ) - } else { - None - }; - let use_fork = cli.fork_picker || cli.fork_last || cli.fork_session_id.is_some(); let session_selection = if use_fork { if let Some(id_str) = cli.fork_session_id.as_deref() { - let Some(app_server) = session_lookup_app_server.as_mut() else { - unreachable!("session lookup app server should be initialized for --fork "); + let Some(startup_app_server) = app_server.as_mut() else { + unreachable!("app server should be initialized for --fork "); }; - match lookup_session_target_with_app_server(app_server, id_str).await? { + match lookup_session_target_with_app_server(startup_app_server, id_str).await? { Some(target_session) => resume_picker::SessionSelection::Fork(target_session), None => { - shutdown_app_server_if_present(session_lookup_app_server.take()).await; + shutdown_app_server_if_present(app_server.take()).await; return missing_session_exit(id_str, "fork"); } } @@ -1181,8 +1156,8 @@ async fn run_ratatui_app( } else { None }; - let Some(app_server) = session_lookup_app_server.as_mut() else { - unreachable!("session lookup app server should be initialized for --fork --last"); + let Some(app_server) = app_server.as_mut() else { + unreachable!("app server should be initialized for --fork --last"); }; match lookup_latest_session_target_with_app_server( app_server, &config, filter_cwd, /*include_non_interactive*/ false, @@ -1193,8 +1168,8 @@ async fn run_ratatui_app( None => resume_picker::SessionSelection::StartFresh, } } else if cli.fork_picker { - let Some(app_server) = session_lookup_app_server.take() else { - unreachable!("session lookup app server should be initialized for --fork picker"); + let Some(app_server) = app_server.take() else { + unreachable!("app server should be initialized for --fork picker"); }; match resume_picker::run_fork_picker_with_app_server( &mut tui, @@ -1221,13 +1196,13 @@ async fn run_ratatui_app( resume_picker::SessionSelection::StartFresh } } else if let Some(id_str) = cli.resume_session_id.as_deref() { - let Some(app_server) = session_lookup_app_server.as_mut() else { - unreachable!("session lookup app server should be initialized for --resume "); + let Some(startup_app_server) = app_server.as_mut() else { + unreachable!("app server should be initialized for --resume "); }; - match lookup_session_target_with_app_server(app_server, id_str).await? { + match lookup_session_target_with_app_server(startup_app_server, id_str).await? { Some(target_session) => resume_picker::SessionSelection::Resume(target_session), None => { - shutdown_app_server_if_present(session_lookup_app_server.take()).await; + shutdown_app_server_if_present(app_server.take()).await; return missing_session_exit(id_str, "resume"); } } @@ -1238,8 +1213,8 @@ async fn run_ratatui_app( &config, cli.resume_show_all, ); - let Some(app_server) = session_lookup_app_server.as_mut() else { - unreachable!("session lookup app server should be initialized for --resume --last"); + let Some(app_server) = app_server.as_mut() else { + unreachable!("app server should be initialized for --resume --last"); }; match lookup_latest_session_target_with_app_server( app_server, @@ -1253,8 +1228,8 @@ async fn run_ratatui_app( None => resume_picker::SessionSelection::StartFresh, } } else if cli.resume_picker { - let Some(app_server) = session_lookup_app_server.take() else { - unreachable!("session lookup app server should be initialized for --resume picker"); + let Some(app_server) = app_server.take() else { + unreachable!("app server should be initialized for --resume picker"); }; match resume_picker::run_resume_picker_with_app_server( &mut tui, @@ -1281,7 +1256,6 @@ async fn run_ratatui_app( } else { resume_picker::SessionSelection::StartFresh }; - shutdown_app_server_if_present(session_lookup_app_server.take()).await; let current_cwd = config.cwd.clone(); let allow_prompt = !remote_mode && cli.cwd.is_none(); @@ -1367,28 +1341,32 @@ async fn run_ratatui_app( let use_alt_screen = determine_alt_screen_mode(no_alt_screen, config.tui_alternate_screen); tui.set_alt_screen_enabled(use_alt_screen); - let app_server = match start_app_server( - &app_server_target, - arg0_paths, - config.clone(), - cli_kv_overrides.clone(), - loader_overrides, - cloud_requirements.clone(), - feedback.clone(), - ) - .await - { - Ok(app_server) => app_server, - Err(err) => { - terminal_restore_guard.restore_silently(); - session_log::log_session_end(); - return Err(err); - } + let app_server = match app_server { + Some(app_server) => app_server, + None => match start_app_server( + &app_server_target, + arg0_paths, + config.clone(), + cli_kv_overrides.clone(), + loader_overrides, + cloud_requirements.clone(), + feedback.clone(), + ) + .await + { + Ok(app_server) => AppServerSession::new(app_server) + .with_remote_cwd_override(remote_cwd_override.clone()), + Err(err) => { + terminal_restore_guard.restore_silently(); + session_log::log_session_end(); + return Err(err); + } + }, }; let app_result = App::run( &mut tui, - AppServerSession::new(app_server).with_remote_cwd_override(remote_cwd_override), + app_server, config, cli_kv_overrides.clone(), overrides.clone(), @@ -1603,7 +1581,10 @@ fn determine_alt_screen_mode(no_alt_screen: bool, tui_alternate_screen: AltScree AltScreenMode::Never => false, AltScreenMode::Auto => { let terminal_info = terminal_info(); - !terminal_info.is_zellij() + !matches!( + terminal_info.multiplexer, + Some(codex_terminal_detection::Multiplexer::Zellij {}) + ) } } } @@ -1628,12 +1609,8 @@ async fn get_login_status( let account = app_server.read_account().await?; Ok(match account.account { - Some(codex_app_server_protocol::Account::ApiKey {}) => { - LoginStatus::AuthMode(AppServerAuthMode::ApiKey) - } - Some(codex_app_server_protocol::Account::Chatgpt { .. }) => { - LoginStatus::AuthMode(AppServerAuthMode::Chatgpt) - } + Some(AppServerAccount::ApiKey {}) => LoginStatus::AuthMode(AppServerAuthMode::ApiKey), + Some(AppServerAccount::Chatgpt { .. }) => LoginStatus::AuthMode(AppServerAuthMode::Chatgpt), None => LoginStatus::NotAuthenticated, }) } diff --git a/codex-rs/tui/src/onboarding/onboarding_screen.rs b/codex-rs/tui/src/onboarding/onboarding_screen.rs index be2e41bc8..ae74691f0 100644 --- a/codex-rs/tui/src/onboarding/onboarding_screen.rs +++ b/codex-rs/tui/src/onboarding/onboarding_screen.rs @@ -447,7 +447,7 @@ impl WidgetRef for Step { pub(crate) async fn run_onboarding_app( args: OnboardingScreenArgs, - mut app_server: Option, + mut app_server: Option<&mut AppServerSession>, tui: &mut Tui, ) -> Result { use tokio_stream::StreamExt; @@ -533,9 +533,6 @@ pub(crate) async fn run_onboarding_app( } } } - if let Some(app_server) = app_server { - app_server.shutdown().await.ok(); - } Ok(OnboardingResult { directory_trust_decision: onboarding_screen.directory_trust_decision(), should_exit: onboarding_screen.should_exit(), diff --git a/codex-rs/tui/src/tui.rs b/codex-rs/tui/src/tui.rs index fc5d35052..9fc67d0a5 100644 --- a/codex-rs/tui/src/tui.rs +++ b/codex-rs/tui/src/tui.rs @@ -270,7 +270,10 @@ impl Tui { // Cache this to avoid contention with the event reader. supports_color::on_cached(supports_color::Stream::Stdout); let _ = crate::terminal_palette::default_colors(); - let is_zellij = codex_terminal_detection::terminal_info().is_zellij(); + let is_zellij = matches!( + codex_terminal_detection::terminal_info().multiplexer, + Some(codex_terminal_detection::Multiplexer::Zellij {}) + ); Self { frame_requester, diff --git a/codex-rs/utils/image/src/lib.rs b/codex-rs/utils/image/src/lib.rs index 9d491bc10..0c0a026e4 100644 --- a/codex-rs/utils/image/src/lib.rs +++ b/codex-rs/utils/image/src/lib.rs @@ -20,7 +20,7 @@ pub const MAX_WIDTH: u32 = 2048; /// Maximum height used when resizing images before uploading. pub const MAX_HEIGHT: u32 = 768; -pub(crate) mod error; +pub mod error; pub use crate::error::ImageProcessingError;