mirror of
https://github.com/openai/codex.git
synced 2026-04-28 18:32:04 +03:00
7.9 KiB
7.9 KiB
PR #1933: approval ui
- URL: https://github.com/openai/codex/pull/1933
- Author: aibrahim-oai
- Created: 2025-08-07 08:30:18 UTC
- Updated: 2025-08-07 09:54:43 UTC
- Changes: +58/-29, Files changed: 3, Commits: 3
Description
Asking for approval:
Allow:
Reject:
Always Approve:
Full Diff
diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs
index 9936c0eef9..d4872d377e 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 be96a9e9ef..c5c02581fa 100644
--- a/codex-rs/tui/src/history_cell.rs
+++ b/codex-rs/tui/src/history_cell.rs
@@ -433,7 +433,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<Line<'static>> = 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 70b355d794..966b8d68f9 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<String>,
+ #[allow(dead_code)]
cwd: PathBuf,
reason: Option<String>,
},
@@ -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: <cmd>"
+ let mut cmd_span: Span = cmd.clone().into();
+ cmd_span.style = cmd_span.style.add_modifier(Modifier::DIM);
let mut contents: Vec<Line> = 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:?}")));
Review Comments
codex-rs/tui/src/history_cell.rs
- Created: 2025-08-07 09:54:42 UTC | Link: https://github.com/openai/codex/pull/1933#discussion_r2259765555
@@ -433,7 +433,8 @@ impl HistoryCell {
view: TextBlock::new(lines),
}
}
-
+ // allow dead code for now. maybe we'll use it again.
+ #[allow(dead_code)]
I would just rip it all out in a follow-up PR.
As a colleague once told me, "It will live on in Git history."