ararajuba_tools_coding/git/
checkout.rs1use ararajuba_core::tools::tool::{tool, ToolDef};
4use git2::Repository;
5use serde_json::json;
6
7pub fn git_checkout_tool() -> ToolDef {
12 tool("git_checkout")
13 .description("Switch to a branch. Use create=true for checkout -b.")
14 .input_schema(json!({
15 "type": "object",
16 "properties": {
17 "branch": { "type": "string", "description": "Branch to switch to" },
18 "create": { "type": "boolean", "description": "Create branch first (default false)" }
19 },
20 "required": ["branch"]
21 }))
22 .execute(|input| async move {
23 let branch_name = input["branch"]
24 .as_str()
25 .ok_or_else(|| "missing required field: branch".to_string())?;
26 let create = input["create"].as_bool().unwrap_or(false);
27
28 let repo = Repository::discover(".")
29 .map_err(|e| format!("failed to open repository: {e}"))?;
30
31 if create {
32 let head_commit = repo
33 .head()
34 .and_then(|h| h.peel_to_commit())
35 .map_err(|e| format!("failed to get HEAD: {e}"))?;
36
37 repo.branch(branch_name, &head_commit, false)
38 .map_err(|e| format!("failed to create branch: {e}"))?;
39 }
40
41 let refname = format!("refs/heads/{branch_name}");
43 repo.set_head(&refname)
44 .map_err(|e| format!("failed to set HEAD: {e}"))?;
45
46 repo.checkout_head(Some(
48 git2::build::CheckoutBuilder::new().force(),
49 ))
50 .map_err(|e| format!("failed to checkout: {e}"))?;
51
52 Ok(json!({
53 "ok": true,
54 "branch": branch_name
55 }))
56 })
57 .build()
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn tool_metadata() {
66 let t = git_checkout_tool();
67 assert_eq!(t.name, "git_checkout");
68 assert!(t.execute.is_some());
69 }
70}