From d9c5f60598fa3a807396cf002fe523c5dcc5b795 Mon Sep 17 00:00:00 2001 From: Yeachan-Heo Date: Tue, 31 Mar 2026 21:01:21 +0000 Subject: [PATCH] Polish permission inspection and switching output Rework /permissions output into the same operator-console format used by status, config, and model so the command feels intentional and self-explanatory. Switching modes now reports previous and current state, while inspection shows the available modes and their meaning without adding fake policy logic. Constraint: Permission output must stay aligned with the real three-mode runtime policy already implemented Rejected: Add richer permission-policy previews per tool | would require more UI surface and risks overstating current policy fidelity Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep permission-mode docs in the CLI consistent with normalize_permission_mode and permission_policy behavior Tested: cargo fmt --manifest-path ./rust/Cargo.toml --all; cargo clippy --manifest-path ./rust/Cargo.toml --workspace --all-targets -- -D warnings; cargo test --manifest-path ./rust/Cargo.toml --workspace Not-tested: Manual operator UX review of /permissions flows in a live REPL --- rust/crates/rusty-claude-cli/src/main.rs | 55 +++++++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index faa9639..d26f1c9 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -291,6 +291,26 @@ fn format_model_switch_report(previous: &str, next: &str, message_count: usize) ) } +fn format_permissions_report(mode: &str) -> String { + format!( + "Permissions + Current mode {mode} + +Available modes + read-only Allow read/search tools only + workspace-write Allow editing within the workspace + danger-full-access Allow unrestricted tool access" + ) +} + +fn format_permissions_switch_report(previous: &str, next: &str) -> String { + format!( + "Permissions updated + Previous {previous} + Current {next}" + ) +} + fn run_resume_command( session_path: &Path, session: &Session, @@ -548,7 +568,7 @@ impl LiveCli { fn set_permissions(&mut self, mode: Option) -> Result<(), Box> { let Some(mode) = mode else { - println!("Current permission mode: {}", permission_mode_label()); + println!("{}", format_permissions_report(permission_mode_label())); return Ok(()); }; @@ -559,10 +579,11 @@ impl LiveCli { })?; if normalized == permission_mode_label() { - println!("Permission mode already set to {normalized}."); + println!("{}", format_permissions_report(normalized)); return Ok(()); } + let previous = permission_mode_label().to_string(); let session = self.runtime.session().clone(); self.runtime = build_runtime_with_permission_mode( session, @@ -571,7 +592,10 @@ impl LiveCli { true, normalized, )?; - println!("Switched permission mode to {normalized}."); + println!( + "{}", + format_permissions_switch_report(&previous, normalized) + ); Ok(()) } @@ -1234,10 +1258,10 @@ fn print_help() { #[cfg(test)] mod tests { use super::{ - format_model_report, format_model_switch_report, format_status_report, - normalize_permission_mode, parse_args, render_init_claude_md, render_repl_help, - resume_supported_slash_commands, status_context, CliAction, SlashCommand, StatusUsage, - DEFAULT_MODEL, + format_model_report, format_model_switch_report, format_permissions_report, + format_permissions_switch_report, format_status_report, normalize_permission_mode, + parse_args, render_init_claude_md, render_repl_help, resume_supported_slash_commands, + status_context, CliAction, SlashCommand, StatusUsage, DEFAULT_MODEL, }; use runtime::{ContentBlock, ConversationMessage, MessageRole}; use std::path::{Path, PathBuf}; @@ -1352,6 +1376,23 @@ mod tests { ); } + #[test] + fn permissions_report_uses_sectioned_layout() { + let report = format_permissions_report("workspace-write"); + assert!(report.contains("Permissions")); + assert!(report.contains("Current mode workspace-write")); + assert!(report.contains("Available modes")); + assert!(report.contains("danger-full-access")); + } + + #[test] + fn permissions_switch_report_is_structured() { + let report = format_permissions_switch_report("read-only", "workspace-write"); + assert!(report.contains("Permissions updated")); + assert!(report.contains("Previous read-only")); + assert!(report.contains("Current workspace-write")); + } + #[test] fn model_report_uses_sectioned_layout() { let report = format_model_report("claude-sonnet", 12, 4);