feat(tui) /permissions

This commit is contained in:
Dylan Hurd
2026-01-20 13:48:15 -08:00
parent 714151eb4e
commit df6a95ce9c
7 changed files with 57 additions and 10 deletions

View File

@@ -302,6 +302,7 @@ mod tests {
cmds,
vec![
"model",
"permissions",
"experimental",
"resume",
"compact",

View File

@@ -5,5 +5,5 @@ expression: terminal.backend()
" "
" /mo "
" "
" /model choose what model and reasoning effort to use "
" /mention mention a file "
" /model choose what model and reasoning effort to "
" use "

View File

@@ -2254,6 +2254,9 @@ impl ChatWidget {
SlashCommand::Approvals => {
self.open_approvals_popup();
}
SlashCommand::Permissions => {
self.open_permissions_popup();
}
SlashCommand::ElevateSandbox => {
#[cfg(target_os = "windows")]
{
@@ -3519,6 +3522,42 @@ impl ChatWidget {
/// Open a popup to choose the approvals mode (ask for approval policy + sandbox policy).
pub(crate) fn open_approvals_popup(&mut self) {
self.open_approval_mode_popup(
"Update Model Permissions",
true,
|preset, is_windows_degraded| {
if preset.id == "auto" && is_windows_degraded {
"Agent (non-elevated sandbox)".to_string()
} else {
preset.label.to_string()
}
},
);
}
/// Open a popup to choose the permissions mode (approval policy + sandbox policy).
pub(crate) fn open_permissions_popup(&mut self) {
let include_read_only = cfg!(target_os = "windows");
self.open_approval_mode_popup(
"Update Model Permissions",
include_read_only,
|preset, _| match preset.id {
"read-only" => "Read Only".to_string(),
"auto" => "Default".to_string(),
"full-access" => "Full Access".to_string(),
_ => preset.label.to_string(),
},
);
}
fn open_approval_mode_popup<F>(
&mut self,
title: &str,
include_read_only: bool,
label_for_preset: F,
) where
F: Fn(&ApprovalPreset, bool) -> String,
{
let current_approval = self.config.approval_policy.value();
let current_sandbox = self.config.sandbox_policy.get();
let mut items: Vec<SelectionItem> = Vec::new();
@@ -3535,13 +3574,12 @@ impl ChatWidget {
&& presets.iter().any(|preset| preset.id == "auto");
for preset in presets.into_iter() {
if !include_read_only && preset.id == "read-only" {
continue;
}
let is_current =
Self::preset_matches_current(current_approval, current_sandbox, &preset);
let name = if preset.id == "auto" && windows_degraded_sandbox_enabled {
"Agent (non-elevated sandbox)".to_string()
} else {
preset.label.to_string()
};
let name = label_for_preset(&preset, windows_degraded_sandbox_enabled);
let description = Some(preset.description.to_string());
let disabled_reason = match self.config.approval_policy.can_set(&preset.approval) {
Ok(()) => None,
@@ -3627,7 +3665,7 @@ impl ChatWidget {
});
self.bottom_pane.show_selection_view(SelectionViewParams {
title: Some("Select Approval Mode".to_string()),
title: Some(title.to_string()),
footer_note,
footer_hint: Some(standard_popup_hint_line()),
items,

View File

@@ -2,7 +2,7 @@
source: tui/src/chatwidget/tests.rs
expression: popup
---
Select Approval Mode
Update Model Permissions
1. Read Only (current) Requires approval to edit files and run commands.
2. Agent Read and edit files, and run commands.

View File

@@ -3010,7 +3010,7 @@ async fn approvals_popup_navigation_skips_disabled() {
.expect("render approvals popup after disabled selection");
let screen = terminal.backend().vt100().screen().contents();
assert!(
screen.contains("Select Approval Mode"),
screen.contains("Update Model Permissions"),
"popup should remain open after selecting a disabled entry"
);
assert!(

View File

@@ -947,6 +947,11 @@ pub(crate) fn new_session_info(
"/approvals".into(),
" - choose what Codex can do without approval".dim(),
]),
Line::from(vec![
" ".into(),
"/permissions".into(),
" - choose what Codex is allowed to do".dim(),
]),
Line::from(vec![
" ".into(),
"/model".into(),

View File

@@ -14,6 +14,7 @@ pub enum SlashCommand {
// more frequently used commands should be listed first.
Model,
Approvals,
Permissions,
#[strum(serialize = "setup-elevated-sandbox")]
ElevateSandbox,
Experimental,
@@ -60,6 +61,7 @@ impl SlashCommand {
SlashCommand::Model => "choose what model and reasoning effort to use",
SlashCommand::Collab => "change collaboration mode (experimental)",
SlashCommand::Approvals => "choose what Codex can do without approval",
SlashCommand::Permissions => "choose what Codex is allowed to do",
SlashCommand::ElevateSandbox => "set up elevated agent sandbox",
SlashCommand::Experimental => "toggle beta features",
SlashCommand::Mcp => "list configured MCP tools",
@@ -86,6 +88,7 @@ impl SlashCommand {
// | SlashCommand::Undo
| SlashCommand::Model
| SlashCommand::Approvals
| SlashCommand::Permissions
| SlashCommand::ElevateSandbox
| SlashCommand::Experimental
| SlashCommand::Review