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