diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 50dbd0bf6..03a99e3aa 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -1599,6 +1599,7 @@ impl App { self.config.cwd.to_path_buf(), version, ) + .with_yolo_mode(history_cell::is_yolo_mode(&self.config)) .display_lines(width) } diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 599655b36..2f5258bf2 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -9722,14 +9722,17 @@ impl ChatWidget { /// Build a placeholder header cell while the session is configuring. fn placeholder_session_header_cell(config: &Config) -> Box { let placeholder_style = Style::default().add_modifier(Modifier::DIM | Modifier::ITALIC); - Box::new(history_cell::SessionHeaderHistoryCell::new_with_style( - DEFAULT_MODEL_DISPLAY_NAME.to_string(), - placeholder_style, - /*reasoning_effort*/ None, - /*show_fast_status*/ false, - config.cwd.to_path_buf(), - CODEX_CLI_VERSION, - )) + Box::new( + history_cell::SessionHeaderHistoryCell::new_with_style( + DEFAULT_MODEL_DISPLAY_NAME.to_string(), + placeholder_style, + /*reasoning_effort*/ None, + /*show_fast_status*/ false, + config.cwd.to_path_buf(), + CODEX_CLI_VERSION, + ) + .with_yolo_mode(history_cell::is_yolo_mode(config)), + ) } /// Merge the real session info cell with any placeholder header to avoid double boxes. diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index 79deede95..f0611e968 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -61,9 +61,11 @@ use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::plan_tool::PlanItemArg; use codex_protocol::plan_tool::StepStatus; use codex_protocol::plan_tool::UpdatePlanArgs; +use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::FileChange; use codex_protocol::protocol::McpAuthStatus; use codex_protocol::protocol::McpInvocation; +use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::SessionConfiguredEvent; use codex_protocol::request_user_input::RequestUserInputAnswer; use codex_protocol::request_user_input::RequestUserInputQuestion; @@ -1186,6 +1188,8 @@ pub(crate) fn new_session_info( let SessionConfiguredEvent { model, reasoning_effort, + approval_policy, + sandbox_policy, .. } = event; // Header box rendered as history (so it appears at the very top) @@ -1195,7 +1199,8 @@ pub(crate) fn new_session_info( show_fast_status, config.cwd.to_path_buf(), CODEX_CLI_VERSION, - ); + ) + .with_yolo_mode(has_yolo_permissions(approval_policy, &sandbox_policy)); let mut parts: Vec> = vec![Box::new(header)]; if is_first_event { @@ -1259,6 +1264,17 @@ pub(crate) fn new_session_info( SessionInfoCell(CompositeHistoryCell { parts }) } +pub(crate) fn is_yolo_mode(config: &Config) -> bool { + has_yolo_permissions( + config.permissions.approval_policy.value(), + config.permissions.sandbox_policy.get(), + ) +} + +fn has_yolo_permissions(approval_policy: AskForApproval, sandbox_policy: &SandboxPolicy) -> bool { + approval_policy == AskForApproval::Never && *sandbox_policy == SandboxPolicy::DangerFullAccess +} + pub(crate) fn new_user_prompt( message: String, text_elements: Vec, @@ -1281,6 +1297,7 @@ pub(crate) struct SessionHeaderHistoryCell { reasoning_effort: Option, show_fast_status: bool, directory: PathBuf, + yolo_mode: bool, } impl SessionHeaderHistoryCell { @@ -1316,9 +1333,15 @@ impl SessionHeaderHistoryCell { reasoning_effort, show_fast_status, directory, + yolo_mode: false, } } + pub(crate) fn with_yolo_mode(mut self, yolo_mode: bool) -> Self { + self.yolo_mode = yolo_mode; + self + } + fn format_directory(&self, max_width: Option) -> String { Self::format_directory_inner(&self.directory, max_width) } @@ -1377,7 +1400,12 @@ impl HistoryCell for SessionHeaderHistoryCell { const CHANGE_MODEL_HINT_COMMAND: &str = "/model"; const CHANGE_MODEL_HINT_EXPLANATION: &str = " to change"; const DIR_LABEL: &str = "directory:"; - let label_width = DIR_LABEL.len(); + const PERMISSIONS_LABEL: &str = "permissions:"; + let label_width = if self.yolo_mode { + DIR_LABEL.len().max(PERMISSIONS_LABEL.len()) + } else { + DIR_LABEL.len() + }; let model_label = format!( "{model_label:_ OpenAI Codex (vtest) │ +│ │ +│ model: gpt-5 /model to change │ +│ directory: /tmp/project │ +│ permissions: YOLO mode │ +╰───────────────────────────────────────╯