clash 0.5.1

Command Line Agent Safety Harness — permission policies for coding agents
Documentation
use anyhow::Result;
use tracing::{Level, instrument};

use crate::debug::replay;
use crate::display;
use crate::settings::ClashSettings;
use crate::style;
use crate::ui;

/// Explain which policy rule would match a given tool invocation.
///
/// Accepts CLI args (`clash explain bash "git push"`) or JSON from stdin.
#[instrument(level = Level::TRACE)]
pub fn run(json_output: bool, tool: String, input_args: String) -> Result<()> {
    let input_arg = if input_args.is_empty() {
        None
    } else {
        Some(input_args.as_str())
    };
    let (tool_name, tool_input) = replay::resolve_tool_input(&tool, input_arg)?;

    let settings = ClashSettings::load_or_create()?;
    let tree = match settings.policy_tree() {
        Some(t) => t,
        None => {
            if json_output {
                println!(
                    "{}",
                    serde_json::json!({"error": "no compiled policy available"})
                );
            } else {
                eprintln!("No compiled policy available.");
                eprintln!("run `clash init`.");
            }
            return Ok(());
        }
    };

    let decision = tree.evaluate(&tool_name, &tool_input);

    if json_output {
        let output = display::decision_to_json(&decision);
        println!("{}", serde_json::to_string_pretty(&output)?);
    } else {
        ui::print_tool_header("Input:", &tool_name, &tool_input);
        println!();
        ui::print_decision(&decision);

        if let Some(ref sandbox) = decision.sandbox {
            println!();
            println!("{}", style::header("Sandbox policy:"));
            ui::print_sandbox_summary(sandbox);
        }
    }

    Ok(())
}