Skip to main content

ararajuba_tools_coding/git/
add.rs

1//! `git_add` tool — stage files.
2
3use ararajuba_core::tools::tool::{tool, ToolDef};
4use git2::Repository;
5use serde_json::json;
6use std::path::Path;
7
8/// Create the `git_add` tool.
9///
10/// Stages the listed files. Use `"."` to stage all changes.
11pub fn git_add_tool() -> ToolDef {
12    tool("git_add")
13        .description("Stage files for commit. Use [\".\"] to stage all changes.")
14        .input_schema(json!({
15            "type": "object",
16            "properties": {
17                "files": {
18                    "type": "array",
19                    "items": { "type": "string" },
20                    "description": "Files to stage (relative to repo root)"
21                }
22            },
23            "required": ["files"]
24        }))
25        .execute(|input| async move {
26            let files = input["files"]
27                .as_array()
28                .ok_or_else(|| "missing required field: files".to_string())?;
29
30            let repo = Repository::discover(".")
31                .map_err(|e| format!("failed to open repository: {e}"))?;
32
33            let mut index = repo
34                .index()
35                .map_err(|e| format!("failed to get index: {e}"))?;
36
37            let mut staged = Vec::new();
38
39            for f in files {
40                let file_str = f
41                    .as_str()
42                    .ok_or_else(|| "file entry must be a string".to_string())?;
43
44                if file_str == "." {
45                    index
46                        .add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)
47                        .map_err(|e| format!("failed to add all: {e}"))?;
48                    staged.push(".".to_string());
49                } else {
50                    index
51                        .add_path(Path::new(file_str))
52                        .map_err(|e| format!("failed to add {file_str}: {e}"))?;
53                    staged.push(file_str.to_string());
54                }
55            }
56
57            index
58                .write()
59                .map_err(|e| format!("failed to write index: {e}"))?;
60
61            Ok(json!({ "staged": staged }))
62        })
63        .build()
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn tool_metadata() {
72        let t = git_add_tool();
73        assert_eq!(t.name, "git_add");
74        assert!(t.execute.is_some());
75    }
76}