diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 9936c0ee..d4872d37 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -45,7 +45,6 @@ use crate::bottom_pane::BottomPane; use crate::bottom_pane::BottomPaneParams; use crate::bottom_pane::CancellationEvent; use crate::bottom_pane::InputResult; -use crate::exec_command::strip_bash_lc_and_escape; use crate::history_cell::CommandOutput; use crate::history_cell::HistoryCell; use crate::history_cell::PatchEventType; @@ -393,17 +392,6 @@ impl ChatWidget<'_> { reason, }) => { self.finalize_active_stream(); - // Log a background summary immediately so the history is chronological. - let cmdline = strip_bash_lc_and_escape(&command); - let text = format!( - "command requires approval:\n$ {cmdline}{reason}", - reason = reason - .as_ref() - .map(|r| format!("\n{r}")) - .unwrap_or_default() - ); - self.add_to_history(HistoryCell::new_background_event(text)); - let request = ApprovalRequest::Exec { id, command, diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index b87525a0..903e3087 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -435,7 +435,8 @@ impl HistoryCell { view: TextBlock::new(lines), } } - + // allow dead code for now. maybe we'll use it again. + #[allow(dead_code)] pub(crate) fn new_background_event(message: String) -> Self { let mut lines: Vec> = Vec::new(); lines.push(Line::from("event".dim())); diff --git a/codex-rs/tui/src/user_approval_widget.rs b/codex-rs/tui/src/user_approval_widget.rs index 70b355d7..966b8d68 100644 --- a/codex-rs/tui/src/user_approval_widget.rs +++ b/codex-rs/tui/src/user_approval_widget.rs @@ -28,7 +28,6 @@ use ratatui::widgets::Wrap; use crate::app_event::AppEvent; use crate::app_event_sender::AppEventSender; -use crate::exec_command::relativize_to_home; use crate::exec_command::strip_bash_lc_and_escape; /// Request coming from the agent that needs user approval. @@ -36,6 +35,7 @@ pub(crate) enum ApprovalRequest { Exec { id: String, command: Vec, + #[allow(dead_code)] cwd: PathBuf, reason: Option, }, @@ -115,21 +115,18 @@ impl UserApprovalWidget<'_> { pub(crate) fn new(approval_request: ApprovalRequest, app_event_tx: AppEventSender) -> Self { let confirmation_prompt = match &approval_request { ApprovalRequest::Exec { - command, - cwd, - reason, - .. + command, reason, .. } => { let cmd = strip_bash_lc_and_escape(command); - // Maybe try to relativize to the cwd of this process first? - // Will make cwd_str shorter in the common case. - let cwd_str = match relativize_to_home(cwd) { - Some(rel) => format!("~/{}", rel.display()), - None => cwd.display().to_string(), - }; + // Present a single-line summary without cwd: "codex wants to run: " + let mut cmd_span: Span = cmd.clone().into(); + cmd_span.style = cmd_span.style.add_modifier(Modifier::DIM); let mut contents: Vec = vec![ - Line::from(vec!["codex".bold().magenta(), " wants to run:".into()]), - Line::from(vec![cwd_str.dim(), "$".into(), format!(" {cmd}").into()]), + Line::from(vec![ + "? ".fg(Color::Blue), + "Codex wants to run ".bold(), + cmd_span, + ]), Line::from(""), ]; if let Some(reason) = reason { @@ -243,9 +240,52 @@ impl UserApprovalWidget<'_> { match &self.approval_request { ApprovalRequest::Exec { command, .. } => { let cmd = strip_bash_lc_and_escape(command); - lines.push(Line::from("approval decision")); - lines.push(Line::from(format!("$ {cmd}"))); - lines.push(Line::from(format!("decision: {decision:?}"))); + let mut cmd_span: Span = cmd.clone().into(); + cmd_span.style = cmd_span.style.add_modifier(Modifier::DIM); + + // Result line based on decision. + match decision { + ReviewDecision::Approved => { + lines.push(Line::from(vec![ + "✓ ".fg(Color::Green), + "You ".into(), + "approved".bold(), + " codex to run ".into(), + cmd_span, + " ".into(), + "this time".bold(), + ])); + } + ReviewDecision::ApprovedForSession => { + lines.push(Line::from(vec![ + "✓ ".fg(Color::Green), + "You ".into(), + "approved".bold(), + " codex to run ".into(), + cmd_span, + " ".into(), + "every time this session".bold(), + ])); + } + ReviewDecision::Denied => { + lines.push(Line::from(vec![ + "✗ ".fg(Color::Red), + "You ".into(), + "did not approve".bold(), + " codex to run ".into(), + cmd_span, + ])); + } + ReviewDecision::Abort => { + lines.push(Line::from(vec![ + "✗ ".fg(Color::Red), + "You ".into(), + "canceled".bold(), + " the request to run ".into(), + cmd_span, + ])); + } + } } ApprovalRequest::ApplyPatch { .. } => { lines.push(Line::from(format!("patch approval decision: {decision:?}")));