ararajuba_tools_coding/git/
commit.rs1use ararajuba_core::tools::tool::{tool, ToolDef};
4use git2::Repository;
5use serde_json::json;
6
7pub fn git_commit_tool() -> ToolDef {
12 tool("git_commit")
13 .description("Commit staged changes with a message.")
14 .input_schema(json!({
15 "type": "object",
16 "properties": {
17 "message": { "type": "string", "description": "Commit message" }
18 },
19 "required": ["message"]
20 }))
21 .execute(|input| async move {
22 let message = input["message"]
23 .as_str()
24 .ok_or_else(|| "missing required field: message".to_string())?;
25
26 let repo = Repository::discover(".")
27 .map_err(|e| format!("failed to open repository: {e}"))?;
28
29 let sig = repo
30 .signature()
31 .map_err(|e| format!("failed to get signature (set user.name/email): {e}"))?;
32
33 let mut index = repo
34 .index()
35 .map_err(|e| format!("failed to get index: {e}"))?;
36
37 let tree_id = index
38 .write_tree()
39 .map_err(|e| format!("failed to write tree: {e}"))?;
40
41 let tree = repo
42 .find_tree(tree_id)
43 .map_err(|e| format!("failed to find tree: {e}"))?;
44
45 let parents: Vec<git2::Commit> = if let Ok(head) = repo.head() {
47 vec![head
48 .peel_to_commit()
49 .map_err(|e| format!("failed to peel HEAD to commit: {e}"))?]
50 } else {
51 vec![]
52 };
53 let parent_refs: Vec<&git2::Commit> = parents.iter().collect();
54
55 let oid = repo
56 .commit(Some("HEAD"), &sig, &sig, message, &tree, &parent_refs)
57 .map_err(|e| format!("failed to commit: {e}"))?;
58
59 let hash = oid.to_string();
60 let short = &hash[..7.min(hash.len())];
61
62 Ok(json!({
63 "hash": hash,
64 "short_hash": short
65 }))
66 })
67 .build()
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn tool_metadata() {
76 let t = git_commit_tool();
77 assert_eq!(t.name, "git_commit");
78 assert!(t.execute.is_some());
79 }
80}