vtcode_core/cli/
tool_policy_commands.rs1use crate::tool_policy::{ToolPolicy, ToolPolicyManager};
4use crate::tools::ToolRegistry;
5use crate::utils::colors::style;
6use anyhow::Result;
7use clap::Subcommand;
8
9#[derive(Debug, Clone, Subcommand)]
11pub enum ToolPolicyCommands {
12 Status,
14 Allow {
16 tool: String,
18 },
19 Deny {
21 tool: String,
23 },
24 Prompt {
26 tool: String,
28 },
29 AllowAll,
31 DenyAll,
33 ResetAll,
35}
36
37pub async fn handle_tool_policy_command(command: ToolPolicyCommands) -> Result<()> {
39 let mut policy_manager = ToolPolicyManager::new().await?;
40
41 match command {
42 ToolPolicyCommands::Status => {
43 policy_manager.print_status();
44 }
45 ToolPolicyCommands::Allow { tool } => {
46 let normalized_tool = normalize_cli_tool_name(&tool).await;
47 policy_manager
48 .set_policy(&normalized_tool, ToolPolicy::Allow)
49 .await?;
50 println!(
51 "{}",
52 style(format!(
53 "✓ Tool '{}' is now allowed",
54 display_tool_name(&tool, &normalized_tool)
55 ))
56 .green()
57 );
58 }
59 ToolPolicyCommands::Deny { tool } => {
60 let normalized_tool = normalize_cli_tool_name(&tool).await;
61 policy_manager
62 .set_policy(&normalized_tool, ToolPolicy::Deny)
63 .await?;
64 println!(
65 "{}",
66 style(format!(
67 "✗ Tool '{}' is now denied",
68 display_tool_name(&tool, &normalized_tool)
69 ))
70 .red()
71 );
72 }
73 ToolPolicyCommands::Prompt { tool } => {
74 let normalized_tool = normalize_cli_tool_name(&tool).await;
75 policy_manager
76 .set_policy(&normalized_tool, ToolPolicy::Prompt)
77 .await?;
78 println!(
79 "{}",
80 style(format!(
81 "? Tool '{}' will now prompt for confirmation",
82 display_tool_name(&tool, &normalized_tool)
83 ))
84 .cyan()
85 );
86 }
87 ToolPolicyCommands::AllowAll => {
88 policy_manager.allow_all_tools().await?;
89 println!("{}", style("✓ All tools are now allowed").green());
90 }
91 ToolPolicyCommands::DenyAll => {
92 policy_manager.deny_all_tools().await?;
93 println!("{}", style("✗ All tools are now denied").red());
94 }
95 ToolPolicyCommands::ResetAll => {
96 policy_manager.reset_all_to_prompt().await?;
97 println!(
98 "{}",
99 style("? All tools reset to prompt for confirmation").cyan()
100 );
101 }
102 }
103
104 Ok(())
105}
106
107async fn normalize_cli_tool_name(tool: &str) -> String {
108 let Ok(workspace_root) = std::env::current_dir() else {
109 return tool.to_string();
110 };
111
112 let registry = ToolRegistry::new(workspace_root).await;
113 registry
114 .resolve_public_tool_name_sync(tool)
115 .unwrap_or_else(|_| tool.to_string())
116}
117
118fn display_tool_name(requested_tool: &str, normalized_tool: &str) -> String {
119 if requested_tool == normalized_tool {
120 requested_tool.to_string()
121 } else {
122 format!("{requested_tool} -> {normalized_tool}")
123 }
124}
125
126pub fn print_tool_policy_help() {
128 println!("{}", style("Tool Policy Management").cyan().bold());
129 println!();
130 println!("Tool policies control which tools the agent can use:");
131 println!();
132 println!(
133 " {} - Tool executes automatically without prompting",
134 style("allow").green()
135 );
136 println!(
137 " {} - Tool prompts for user confirmation each time",
138 style("prompt").cyan()
139 );
140 println!(
141 " {} - Tool is never allowed to execute",
142 style("deny").red()
143 );
144 println!();
145 println!("Policies are stored in ~/.vtcode/tool-policy.json");
146 println!("Once you approve or deny a tool, your choice is remembered for future runs.");
147 println!();
148 println!("Examples:");
149 println!(" vtcode tool-policy status # Show current policies");
150 println!(" vtcode tool-policy allow read_file # Allow read_file tool");
151 println!(" vtcode tool-policy deny rm # Deny rm tool");
152 println!(" vtcode tool-policy reset-all # Reset all to prompt");
153}