Files
2026-03-12 12:47:56 +08:00

169 lines
7.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
export const gitOpsTool = {
name: "git_ops",
description: "Git 全套操作。支持 status、diff、add、commit、push、pull、log、branch、checkout、stash、reset 等所有常用 Git 命令。自动解析输出为结构化报告。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
action: {
type: "string",
description: "Git 操作",
enum: [
"status", "diff", "diff_staged", "add", "add_all", "commit",
"push", "pull", "log", "branch", "branch_create", "checkout",
"stash", "stash_pop", "reset_soft", "reset_hard", "remote", "init",
],
},
message: {
type: "string",
description: "commit 消息commit 时必填)",
},
target: {
type: "string",
description: "目标参数(文件路径/分支名/commit hash 等)",
},
count: {
type: "number",
description: "log 显示条数(默认 10",
},
},
required: ["project_path", "action"],
},
};
async function git(args, cwd) {
try {
const { stdout, stderr } = await execAsync(`git ${args}`, {
cwd,
timeout: 30000,
maxBuffer: 1024 * 1024 * 5,
});
return { stdout, stderr, code: 0 };
}
catch (error) {
return { stdout: error.stdout || "", stderr: error.stderr || "", code: error.code ?? 1 };
}
}
export async function executeGitOps(args) {
const { project_path, action, message, target, count = 10 } = args;
let result;
let title = "";
switch (action) {
case "status":
title = "Git Status";
result = await git("status --short --branch", project_path);
if (result.code === 0) {
const lines = result.stdout.trim().split("\n");
const branch = lines[0] || "";
const changes = lines.slice(1);
const staged = changes.filter((l) => /^[MADRC]/.test(l));
const unstaged = changes.filter((l) => /^.[MADRC]/.test(l));
const untracked = changes.filter((l) => l.startsWith("??"));
return [
`# ${title}`, `📂 ${project_path}`, `🌿 ${branch}`, ``,
`| 状态 | 数量 |`, `|------|------|`,
`| ✅ 已暂存 | ${staged.length} |`,
`| 📝 已修改 | ${unstaged.length} |`,
`| ❓ 未跟踪 | ${untracked.length} |`, ``,
changes.length > 0 ? "```\n" + result.stdout.trim() + "\n```" : "✨ 工作区干净",
].join("\n");
}
break;
case "diff":
title = "Git Diff (工作区)";
result = await git(`diff ${target ? `-- "${target}"` : ""} --stat`, project_path);
if (result.stdout.trim()) {
const detail = await git(`diff ${target ? `-- "${target}"` : ""} --no-color`, project_path);
return `# ${title}\n\n## 摘要\n\`\`\`\n${result.stdout.trim()}\n\`\`\`\n\n## 详细\n\`\`\`diff\n${detail.stdout.slice(0, 8000)}\n\`\`\``;
}
return `# ${title}\n\n✨ 无差异`;
case "diff_staged":
title = "Git Diff (暂存区)";
result = await git("diff --cached --stat", project_path);
if (result.stdout.trim()) {
const detail = await git("diff --cached --no-color", project_path);
return `# ${title}\n\n## 摘要\n\`\`\`\n${result.stdout.trim()}\n\`\`\`\n\n## 详细\n\`\`\`diff\n${detail.stdout.slice(0, 8000)}\n\`\`\``;
}
return `# ${title}\n\n✨ 暂存区无内容`;
case "add":
title = "Git Add";
result = await git(`add "${target || "."}"`, project_path);
break;
case "add_all":
title = "Git Add All";
result = await git("add -A", project_path);
break;
case "commit":
if (!message)
return "❌ commit 需要提供 message 参数";
title = "Git Commit";
result = await git(`commit -m "${message.replace(/"/g, '\\"')}"`, project_path);
break;
case "push":
title = "Git Push";
result = await git(`push ${target || ""}`, project_path);
break;
case "pull":
title = "Git Pull";
result = await git(`pull ${target || ""}`, project_path);
break;
case "log":
title = "Git Log";
result = await git(`log --oneline --graph --decorate -n ${count}`, project_path);
if (result.code === 0) {
return `# ${title} (最近 ${count} 条)\n\n\`\`\`\n${result.stdout.trim()}\n\`\`\``;
}
break;
case "branch":
title = "Git Branch";
result = await git("branch -a -v", project_path);
break;
case "branch_create":
if (!target)
return "❌ 创建分支需要提供 target分支名";
title = `Git Branch Create: ${target}`;
result = await git(`checkout -b "${target}"`, project_path);
break;
case "checkout":
if (!target)
return "❌ checkout 需要提供 target分支名或文件";
title = `Git Checkout: ${target}`;
result = await git(`checkout "${target}"`, project_path);
break;
case "stash":
title = "Git Stash";
result = await git(`stash${message ? ` push -m "${message}"` : ""}`, project_path);
break;
case "stash_pop":
title = "Git Stash Pop";
result = await git("stash pop", project_path);
break;
case "reset_soft":
title = "Git Reset (soft)";
result = await git(`reset --soft ${target || "HEAD~1"}`, project_path);
break;
case "reset_hard":
title = "Git Reset (hard) ⚠️";
result = await git(`reset --hard ${target || "HEAD"}`, project_path);
break;
case "remote":
title = "Git Remote";
result = await git("remote -v", project_path);
break;
case "init":
title = "Git Init";
result = await git("init", project_path);
break;
default:
return `❌ 未知 Git 操作: ${action}`;
}
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
const icon = result.code === 0 ? "✅" : "❌";
return `# ${icon} ${title}\n\n📂 ${project_path}\n\n\`\`\`\n${output || "(无输出)"}\n\`\`\``;
}
//# sourceMappingURL=gitOps.js.map