feat: git功能开发
This commit is contained in:
@@ -127,6 +127,14 @@ Example configuration for Claude Desktop (`claude_desktop_config.json`):
|
|||||||
- `docs_bun` - Get Bun documentation
|
- `docs_bun` - Get Bun documentation
|
||||||
- `code_review` - Review code
|
- `code_review` - Review code
|
||||||
- `code_optimize` - Get optimization suggestions
|
- `code_optimize` - Get optimization suggestions
|
||||||
|
- `git_status` - Get git repository status
|
||||||
|
- `git_add` - Stage files for commit
|
||||||
|
- `git_commit` - Commit staged changes
|
||||||
|
- `git_push` - Push commits to remote
|
||||||
|
- `git_pull` - Pull latest changes from remote
|
||||||
|
- `git_log` - Show commit history
|
||||||
|
- `git_branch` - List, create, or delete branches
|
||||||
|
- `git_diff` - Show changes between commits or working directory
|
||||||
|
|
||||||
### DevOps
|
### DevOps
|
||||||
- `nas_list_files` - List NAS files
|
- `nas_list_files` - List NAS files
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { registerCodeSnippetTools } from "./tools/programming/codeSnippet.js";
|
|||||||
import { registerProjectTemplateTools } from "./tools/programming/projectTemplate.js";
|
import { registerProjectTemplateTools } from "./tools/programming/projectTemplate.js";
|
||||||
import { registerDocsTools } from "./tools/programming/docs.js";
|
import { registerDocsTools } from "./tools/programming/docs.js";
|
||||||
import { registerCodeReviewTools } from "./tools/programming/codeReview.js";
|
import { registerCodeReviewTools } from "./tools/programming/codeReview.js";
|
||||||
|
import { registerGitTools } from "./tools/programming/git.js";
|
||||||
|
|
||||||
import { registerNASTools } from "./tools/devops/nas.js";
|
import { registerNASTools } from "./tools/devops/nas.js";
|
||||||
import { registerServerTools } from "./tools/devops/server.js";
|
import { registerServerTools } from "./tools/devops/server.js";
|
||||||
@@ -35,6 +36,7 @@ registerCodeSnippetTools();
|
|||||||
registerProjectTemplateTools();
|
registerProjectTemplateTools();
|
||||||
registerDocsTools();
|
registerDocsTools();
|
||||||
registerCodeReviewTools();
|
registerCodeReviewTools();
|
||||||
|
registerGitTools();
|
||||||
|
|
||||||
// DevOps tools
|
// DevOps tools
|
||||||
registerNASTools();
|
registerNASTools();
|
||||||
|
|||||||
672
src/tools/programming/git.ts
Normal file
672
src/tools/programming/git.ts
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
/**
|
||||||
|
* Git version control tools
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mcpServer } from "../../server.js";
|
||||||
|
import { logger } from "../../utils/logger.js";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
export function registerGitTools(): void {
|
||||||
|
// Git status
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_status",
|
||||||
|
description: "Get git repository status (working directory, staged files, branch)",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = execSync("git status --short", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
const lastCommit = execSync("git log -1 --oneline", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
let output = `Git Status (${repoPath})\n\n`;
|
||||||
|
output += `Branch: ${branch}\n`;
|
||||||
|
output += `Last commit: ${lastCommit}\n\n`;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
output += `Working directory changes:\n${status}`;
|
||||||
|
} else {
|
||||||
|
output += "Working directory clean";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: output,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git add
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_add",
|
||||||
|
description: "Stage files for commit",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
files: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "Files to stage (use '.' for all files)",
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["files"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const files = args.files as string[];
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const filesToAdd = files.length === 0 ? ["."] : files;
|
||||||
|
execSync(`git add ${filesToAdd.join(" ")}`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
const staged = execSync("git diff --cached --name-only", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Files staged successfully!\n\nStaged files:\n${staged || "No files staged"}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git commit
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_commit",
|
||||||
|
description: "Commit staged changes",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
description: "Commit message",
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["message"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const message = args.message as string;
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
execSync(`git commit -m "${message}"`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
const commitHash = execSync("git rev-parse HEAD", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
const commitInfo = execSync("git log -1 --oneline", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Commit created successfully!\n\n${commitInfo}\nHash: ${commitHash}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}\n\nNote: Make sure you have staged files before committing.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git push
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_push",
|
||||||
|
description: "Push commits to remote repository",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
remote: {
|
||||||
|
type: "string",
|
||||||
|
description: "Remote name (default: origin)",
|
||||||
|
default: "origin",
|
||||||
|
},
|
||||||
|
branch: {
|
||||||
|
type: "string",
|
||||||
|
description: "Branch to push (default: current branch)",
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const remote = (args.remote as string) || "origin";
|
||||||
|
const branch = args.branch as string | undefined;
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentBranch =
|
||||||
|
branch ||
|
||||||
|
execSync("git rev-parse --abbrev-ref HEAD", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
execSync(`git push ${remote} ${currentBranch}`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Pushed to ${remote}/${currentBranch} successfully!`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}\n\nNote: Make sure you have commits to push and remote is configured.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git pull
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_pull",
|
||||||
|
description: "Pull latest changes from remote repository",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
remote: {
|
||||||
|
type: "string",
|
||||||
|
description: "Remote name (default: origin)",
|
||||||
|
default: "origin",
|
||||||
|
},
|
||||||
|
branch: {
|
||||||
|
type: "string",
|
||||||
|
description: "Branch to pull (default: current branch)",
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const remote = (args.remote as string) || "origin";
|
||||||
|
const branch = args.branch as string | undefined;
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentBranch =
|
||||||
|
branch ||
|
||||||
|
execSync("git rev-parse --abbrev-ref HEAD", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
const output = execSync(`git pull ${remote} ${currentBranch}`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Pulled from ${remote}/${currentBranch} successfully!\n\n${output}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git log
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_log",
|
||||||
|
description: "Show commit history",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
limit: {
|
||||||
|
type: "number",
|
||||||
|
description: "Number of commits to show (default: 10)",
|
||||||
|
default: 10,
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const limit = (args.limit as number) || 10;
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const log = execSync(`git log -${limit} --oneline --decorate`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Recent commits (${limit}):\n\n${log || "No commits found"}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git branch
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_branch",
|
||||||
|
description: "List, create, or delete branches",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
action: {
|
||||||
|
type: "string",
|
||||||
|
description: "Action: 'list', 'create', or 'delete'",
|
||||||
|
enum: ["list", "create", "delete"],
|
||||||
|
default: "list",
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
description: "Branch name (required for create/delete)",
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const action = (args.action as string) || "list";
|
||||||
|
const name = args.name as string | undefined;
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === "list") {
|
||||||
|
const branches = execSync("git branch -a", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
const currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Branches:\n\n${branches}\n\nCurrent branch: ${currentBranch}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} else if (action === "create") {
|
||||||
|
if (!name) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: "Error: Branch name is required for create action",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
execSync(`git branch ${name}`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Branch "${name}" created successfully!`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} else if (action === "delete") {
|
||||||
|
if (!name) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: "Error: Branch name is required for delete action",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
execSync(`git branch -d ${name}`, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Branch "${name}" deleted successfully!`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: "Invalid action",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Git diff
|
||||||
|
mcpServer.registerTool(
|
||||||
|
{
|
||||||
|
name: "git_diff",
|
||||||
|
description: "Show changes between commits, branches, or working directory",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Path to git repository (default: current directory)",
|
||||||
|
default: ".",
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
type: "string",
|
||||||
|
description: "Specific file to show diff (optional)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
try {
|
||||||
|
const repoPath = (args.path as string) || process.cwd();
|
||||||
|
const file = args.file as string | undefined;
|
||||||
|
|
||||||
|
const gitDir = join(repoPath, ".git");
|
||||||
|
if (!existsSync(gitDir)) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Not a git repository: ${repoPath}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const diffCommand = file ? `git diff ${file}` : "git diff";
|
||||||
|
const diff = execSync(diffCommand, {
|
||||||
|
cwd: repoPath,
|
||||||
|
encoding: "utf-8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: diff || "No changes found",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user