ai-agent-sdk 0.5.0

Idiomatic agent sdk inspired by the claude code source leak
Documentation
//! Git worktree tools.
//!
//! Provides tools for managing git worktrees.

use crate::types::*;

/// EnterWorktree tool - create and enter a git worktree
pub struct EnterWorktreeTool;

impl EnterWorktreeTool {
    pub fn new() -> Self {
        Self
    }

    pub fn input_schema(&self) -> ToolInputSchema {
        ToolInputSchema {
            schema_type: "object".to_string(),
            properties: serde_json::json!({
                "name": {
                    "type": "string",
                    "description": "Optional name for the worktree. If not provided, a random name is generated."
                }
            }),
            required: None,
        }
    }

    pub async fn execute(&self, input: serde_json::Value, _context: &ToolContext) -> Result<ToolResult, crate::error::AgentError> {
        let name = input["name"].as_str();

        let response = if let Some(n) = name {
            format!(
                "Creating worktree '{}'...\nNote: Full implementation would create a new git worktree at .ai/worktrees/{} and switch to it.",
                n, n
            )
        } else {
            "Creating worktree with random name...\nNote: Full implementation would create a new git worktree.".to_string()
        };

        Ok(ToolResult {
            result_type: "text".to_string(),
            tool_use_id: "enter_worktree".to_string(),
            content: response,
            is_error: Some(false),
        })
    }
}

impl Default for EnterWorktreeTool {
    fn default() -> Self {
        Self::new()
    }
}

/// ExitWorktree tool - exit a worktree and return to original directory
pub struct ExitWorktreeTool;

impl ExitWorktreeTool {
    pub fn new() -> Self {
        Self
    }

    pub fn input_schema(&self) -> ToolInputSchema {
        ToolInputSchema {
            schema_type: "object".to_string(),
            properties: serde_json::json!({
                "action": {
                    "type": "string",
                    "enum": ["keep", "remove"],
                    "description": "What to do with the worktree: 'keep' leaves it on disk, 'remove' deletes it"
                },
                "discardChanges": {
                    "type": "boolean",
                    "description": "If true, discard uncommitted changes before removing"
                }
            }),
            required: None,
        }
    }

    pub async fn execute(&self, input: serde_json::Value, _context: &ToolContext) -> Result<ToolResult, crate::error::AgentError> {
        let action = input["action"].as_str().unwrap_or("keep");
        let discard = input["discardChanges"].as_bool().unwrap_or(false);

        let response = format!(
            "Exiting worktree...\nAction: {}\nDiscard changes: {}\nNote: Full implementation would restore the session to the original working directory.",
            action, discard
        );

        Ok(ToolResult {
            result_type: "text".to_string(),
            tool_use_id: "exit_worktree".to_string(),
            content: response,
            is_error: Some(false),
        })
    }
}

impl Default for ExitWorktreeTool {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_enter_worktree_schema() {
        let tool = EnterWorktreeTool::new();
        let schema = tool.input_schema();
        assert!(schema.properties.get("name").is_some());
    }

    #[test]
    fn test_exit_worktree_schema() {
        let tool = ExitWorktreeTool::new();
        let schema = tool.input_schema();
        assert!(schema.properties.get("action").is_some());
    }
}