From df9e65127fbb2883924fd99d431faf4712ca1f75 Mon Sep 17 00:00:00 2001 From: "Rai (Michael Pokorny)" Date: Tue, 24 Jun 2025 14:31:35 -0700 Subject: [PATCH] Auto-commit pending changes on agentydragon-task/07-undo-feedback-decision --- agentydragon/README.md | 4 ++ .../tasks/07-undo-feedback-decision.md | 13 ++++--- codex-rs/tui/src/user_approval_widget.rs | 37 ++++++++++++++++++- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/agentydragon/README.md b/agentydragon/README.md index 9c56c20e8c..9af997f688 100644 --- a/agentydragon/README.md +++ b/agentydragon/README.md @@ -18,6 +18,10 @@ This file documents the changes introduced on the `agentydragon` branch ## Dependency updates - Added `uuid` crate to `codex-rs/cli` and `codex-rs/tui`. +## codex-rs/tui: Undo feedback decision with Esc key +- Pressing `Esc` in feedback-entry mode now cancels feedback entry and returns to the select menu, preserving the partially entered feedback text. +- Added a unit test for the ESC cancellation behavior in `tui/src/user_approval_widget.rs`. + ## Documentation tasks Tasks live under `agentydragon/tasks/` as individual Markdown files. Please update each task’s **Status** and **Implementation** sections in place rather than maintaining a static list here. diff --git a/agentydragon/tasks/07-undo-feedback-decision.md b/agentydragon/tasks/07-undo-feedback-decision.md index 846925b13e..5e9e9cd648 100644 --- a/agentydragon/tasks/07-undo-feedback-decision.md +++ b/agentydragon/tasks/07-undo-feedback-decision.md @@ -4,8 +4,8 @@ ## Status -**General Status**: Not started -**Summary**: Not started; missing Implementation details (How it was implemented and How it works). +**General Status**: Completed +**Summary**: ESC key now cancels feedback entry and returns to the select menu, preserving any entered text; implementation and tests added. ## Goal Enhance the user-approval dialog so that if the user opted to leave feedback (“No, enter feedback”) they can press `Esc` to cancel the feedback flow and return to the previous approval choice menu (e.g. “Yes, proceed” vs. “No, enter feedback”). @@ -17,10 +17,13 @@ Enhance the user-approval dialog so that if the user opted to leave feedback ( ## Implementation **How it was implemented** -*(Not implemented yet)* +- In `tui/src/user_approval_widget.rs`, updated `UserApprovalWidget::handle_input_key` so that pressing `Esc` in input mode switches `mode` back to `Select` (rather than sending a deny decision), and restores `selected_option` to the feedback entry item without clearing the input buffer. +- Added a unit test in the same module to verify that `Esc` cancels input mode, preserves the feedback text, and does not emit any decision event. **How it works** -*(Not implemented yet)* +- When the widget is in `Mode::Input` (feedback-entry), receiving `KeyCode::Esc` resets `mode` to `Select` and sets `selected_option` to the index of the “Edit or give feedback” option. +- The `input` buffer remains intact, so any partially typed feedback is preserved for if/when the user re-enters feedback mode. +- No approval decision is sent on `Esc`, so the modal remains active and the user can still approve, deny, or re-enter feedback. ## Notes -- Changes in `tui/src/bottom_pane/approval_modal_view.rs` and input handling in the approval modal. \ No newline at end of file +- Changes in `tui/src/user_approval_widget.rs` to treat `Esc` in input mode as a cancel-feedback action and added corresponding tests. \ No newline at end of file diff --git a/codex-rs/tui/src/user_approval_widget.rs b/codex-rs/tui/src/user_approval_widget.rs index 6604daace8..b2967f0a30 100644 --- a/codex-rs/tui/src/user_approval_widget.rs +++ b/codex-rs/tui/src/user_approval_widget.rs @@ -276,8 +276,10 @@ impl UserApprovalWidget<'_> { self.send_decision_with_feedback(ReviewDecision::Denied, feedback); } KeyCode::Esc => { - // Cancel input – treat as deny without feedback. - self.send_decision(ReviewDecision::Denied); + self.mode = Mode::Select; + if let Some(idx) = SELECT_OPTIONS.iter().position(|opt| opt.enters_input_mode) { + self.selected_option = idx; + } } _ => { // Feed into input widget for normal editing. @@ -370,3 +372,34 @@ impl WidgetRef for &UserApprovalWidget<'_> { Widget::render(List::new(lines), response_chunk, buf); } } + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::mpsc; + use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; + + #[test] + fn esc_in_input_mode_cancels_input_and_preserves_value() { + let (tx, rx) = mpsc::channel(); + let app_event_tx = AppEventSender::new(tx); + let mut widget = UserApprovalWidget::new( + ApprovalRequest::Exec { + id: "id".into(), + command: Vec::new(), + cwd: std::env::current_dir().unwrap(), + reason: None, + }, + app_event_tx.clone(), + ); + widget.mode = Mode::Input; + widget.input.get_mut().set_value("feedback".to_string()); + widget.handle_key_event(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)); + assert_eq!(widget.mode, Mode::Select); + let expected_idx = SELECT_OPTIONS.iter().position(|opt| opt.enters_input_mode).unwrap(); + assert_eq!(widget.selected_option, expected_idx); + assert_eq!(widget.input.value(), "feedback"); + assert!(rx.try_recv().is_err()); + assert!(!widget.done); + } +}