claw-code/rust/crates/rusty-claude-cli/src/permission.rs

67 lines
2.3 KiB
Rust

use std::io::{self, Write};
use runtime::{PermissionMode, PermissionPolicy, PermissionPromptDecision, PermissionRequest};
use tools::GlobalToolRegistry;
pub(crate) struct CliPermissionPrompter {
current_mode: PermissionMode,
}
impl CliPermissionPrompter {
pub(crate) fn new(current_mode: PermissionMode) -> Self {
Self { current_mode }
}
}
impl runtime::PermissionPrompter for CliPermissionPrompter {
fn decide(
&mut self,
request: &PermissionRequest,
) -> PermissionPromptDecision {
println!();
println!("Permission approval required");
println!(" Tool {}", request.tool_name);
println!(" Current mode {}", self.current_mode.as_str());
println!(" Required mode {}", request.required_mode.as_str());
if let Some(reason) = &request.reason {
println!(" Reason {reason}");
}
println!(" Input {}", request.input);
print!("Approve this tool call? [y/N]: ");
let _ = io::stdout().flush();
let mut response = String::new();
match io::stdin().read_line(&mut response) {
Ok(_) => {
let normalized = response.trim().to_ascii_lowercase();
if matches!(normalized.as_str(), "y" | "yes") {
PermissionPromptDecision::Allow
} else {
PermissionPromptDecision::Deny {
reason: format!(
"tool '{}' denied by user approval prompt",
request.tool_name
),
}
}
}
Err(error) => PermissionPromptDecision::Deny {
reason: format!("permission approval failed: {error}"),
},
}
}
}
pub(crate) fn permission_policy(
mode: PermissionMode,
feature_config: &runtime::RuntimeFeatureConfig,
tool_registry: &GlobalToolRegistry,
) -> Result<PermissionPolicy, String> {
Ok(tool_registry.permission_specs(None)?.into_iter().fold(
PermissionPolicy::new(mode).with_permission_rules(feature_config.permission_rules()),
|policy, (name, required_permission)| {
policy.with_tool_requirement(name, required_permission)
},
))
}