claude-rust-tools 0.4.0

Tool implementations for bash and file operations
Documentation
use claude_rust_errors::{AppError, AppResult};
use claude_rust_types::{PermissionLevel, Tool};
use serde_json::{Value, json};

pub struct AskUserTool;

#[async_trait::async_trait]
impl Tool for AskUserTool {
    fn name(&self) -> &str {
        "ask_user_question"
    }

    fn description(&self) -> &str {
        "Ask the user a question and wait for their response. Use this when you need clarification or input from the user."
    }

    fn input_schema(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "question": {
                    "type": "string",
                    "description": "The question to ask the user"
                }
            },
            "required": ["question"]
        })
    }

    fn permission_level(&self) -> PermissionLevel {
        PermissionLevel::ReadOnly
    }

    async fn execute(&self, input: Value) -> AppResult<String> {
        let question = input
            .get("question")
            .and_then(|q| q.as_str())
            .ok_or_else(|| AppError::Tool("missing 'question' field".into()))?;

        let question = question.to_string();

        let answer = tokio::task::spawn_blocking(move || -> AppResult<String> {
            use std::io::{self, Write};

            let mut stderr = io::stderr().lock();
            write!(stderr, "\n  \x1b[1m\x1b[36m❓ {question}\x1b[0m\n  \x1b[2m➤\x1b[0m ")
                .map_err(|e| AppError::Tool(format!("failed to write question: {e}")))?;
            stderr
                .flush()
                .map_err(|e| AppError::Tool(format!("failed to flush: {e}")))?;

            let mut line = String::new();
            io::stdin()
                .read_line(&mut line)
                .map_err(|e| AppError::Tool(format!("failed to read answer: {e}")))?;

            Ok(line.trim().to_string())
        })
        .await
        .map_err(|e| AppError::Tool(format!("ask user task failed: {e}")))??;

        Ok(answer)
    }
}