Add explicit prefix-approval decision and wire it through execpolicy/UI snapshots

This commit is contained in:
kevin zhao
2025-11-20 19:16:12 -05:00
parent 80e3635b25
commit ea9fc79dec
9 changed files with 37 additions and 10 deletions

View File

@@ -70,7 +70,9 @@ pub(crate) async fn apply_patch(
)
.await;
match rx_approve.await.unwrap_or_default() {
ReviewDecision::Approved | ReviewDecision::ApprovedForSession => {
ReviewDecision::Approved
| ReviewDecision::ApprovedAllowPrefix
| ReviewDecision::ApprovedForSession => {
InternalApplyPatchInvocation::DelegateToExec(ApplyPatchExec {
action,
user_explicitly_approved_this_action: true,

View File

@@ -1671,7 +1671,9 @@ mod handlers {
if let Some(prefix) = allow_prefix
&& matches!(
decision,
ReviewDecision::Approved | ReviewDecision::ApprovedForSession
ReviewDecision::Approved
| ReviewDecision::ApprovedAllowPrefix
| ReviewDecision::ApprovedForSession
)
&& let Err(err) = sess.persist_command_allow_prefix(&prefix).await
{

View File

@@ -94,7 +94,9 @@ impl ToolOrchestrator {
ReviewDecision::Denied | ReviewDecision::Abort => {
return Err(ToolError::Rejected("rejected by user".to_string()));
}
ReviewDecision::Approved | ReviewDecision::ApprovedForSession => {}
ReviewDecision::Approved
| ReviewDecision::ApprovedAllowPrefix
| ReviewDecision::ApprovedForSession => {}
}
already_approved = true;
}
@@ -175,7 +177,9 @@ impl ToolOrchestrator {
ReviewDecision::Denied | ReviewDecision::Abort => {
return Err(ToolError::Rejected("rejected by user".to_string()));
}
ReviewDecision::Approved | ReviewDecision::ApprovedForSession => {}
ReviewDecision::Approved
| ReviewDecision::ApprovedAllowPrefix
| ReviewDecision::ApprovedForSession => {}
}
}

View File

@@ -1657,6 +1657,10 @@ pub enum ReviewDecision {
/// User has approved this command and the agent should execute it.
Approved,
/// User has approved this command and wants to add the command prefix to
/// the execpolicy allow list so future matching commands are permitted.
ApprovedAllowPrefix,
/// User has approved this command and wants to automatically approve any
/// future identical instances (`command` and `cwd` match exactly) for the
/// remainder of the session.

View File

@@ -498,7 +498,7 @@ fn exec_options(allow_prefix: Option<Vec<String>>) -> Vec<ApprovalOption> {
.into_iter()
.chain(allow_prefix.map(|prefix| ApprovalOption {
label: "Yes, and don't ask again for commands with this prefix".to_string(),
decision: ApprovalDecision::Review(ReviewDecision::ApprovedForSession),
decision: ApprovalDecision::Review(ReviewDecision::ApprovedAllowPrefix),
display_shortcut: None,
additional_shortcuts: vec![key_hint::plain(KeyCode::Char('p'))],
allow_prefix: Some(prefix),
@@ -627,7 +627,7 @@ mod tests {
..
}) = ev
{
assert_eq!(decision, ReviewDecision::ApprovedForSession);
assert_eq!(decision, ReviewDecision::ApprovedAllowPrefix);
assert_eq!(allow_prefix, Some(vec!["echo".to_string()]));
saw_op = true;
break;

View File

@@ -11,6 +11,7 @@ expression: terminal.backend().vt100().screen().contents()
1. Yes, proceed (y)
2. Yes, and don't ask again for this command (a)
3. No, and tell Codex what to do differently (esc)
3. Yes, and don't ask again for commands with this prefix (p)
4. No, and tell Codex what to do differently (esc)
Press enter to confirm or esc to cancel

View File

@@ -8,6 +8,7 @@ expression: terminal.backend().vt100().screen().contents()
1. Yes, proceed (y)
2. Yes, and don't ask again for this command (a)
3. No, and tell Codex what to do differently (esc)
3. Yes, and don't ask again for commands with this prefix (p)
4. No, and tell Codex what to do differently (esc)
Press enter to confirm or esc to cancel

View File

@@ -1,6 +1,5 @@
---
source: tui/src/chatwidget/tests.rs
assertion_line: 1548
expression: terminal.backend()
---
" "
@@ -14,6 +13,7 @@ expression: terminal.backend()
" "
" 1. Yes, proceed (y) "
" 2. Yes, and don't ask again for this command (a) "
" 3. No, and tell Codex what to do differently (esc) "
" 3. Yes, and don't ask again for commands with this prefix (p) "
" 4. No, and tell Codex what to do differently (esc) "
" "
" Press enter to confirm or esc to cancel "

View File

@@ -408,6 +408,19 @@ pub fn new_approval_decision_cell(
],
)
}
ApprovedAllowPrefix => {
let snippet = Span::from(exec_snippet(&command)).dim();
(
"".green(),
vec![
"You ".into(),
"approved".bold(),
" codex to run ".into(),
snippet,
" and added its prefix to your allow list".bold(),
],
)
}
ApprovedForSession => {
let snippet = Span::from(exec_snippet(&command)).dim();
(