@andrebuzeli/git-mcp 6.3.2 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resources/toolsGuide.js +23 -3
- package/dist/tools/gitAnalytics.d.ts +1 -24
- package/dist/tools/gitAnalytics.js +168 -43
- package/dist/tools/gitArchive.js +1 -1
- package/dist/tools/gitBackup.js +1 -1
- package/dist/tools/gitBranches.d.ts +1 -67
- package/dist/tools/gitBranches.js +151 -19
- package/dist/tools/gitConfig.js +1 -1
- package/dist/tools/gitFiles.js +1 -1
- package/dist/tools/gitIssues.js +1 -1
- package/dist/tools/gitMonitor.d.ts +1 -46
- package/dist/tools/gitMonitor.js +184 -14
- package/dist/tools/gitPackages.js +1 -1
- package/dist/tools/gitRemote.js +1 -1
- package/dist/tools/gitStash.js +1 -1
- package/dist/tools/gitSync.js +1 -1
- package/dist/tools/gitTags.d.ts +1 -25
- package/dist/tools/gitTags.js +161 -13
- package/dist/utils/dualExecution.d.ts +49 -0
- package/dist/utils/dualExecution.js +96 -0
- package/package.json +2 -2
|
@@ -10,11 +10,31 @@ exports.TOOLS_GUIDE = {
|
|
|
10
10
|
name: "Git-MCP Tools Complete Guide",
|
|
11
11
|
description: "Detailed documentation and usage instructions for all 20 Git tools with 102 actions",
|
|
12
12
|
mimeType: "text/markdown",
|
|
13
|
-
content: `# 🛠️ Git-MCP
|
|
13
|
+
content: `# 🛠️ Git-MCP v7.0.0 - Complete Tools Guide
|
|
14
14
|
|
|
15
15
|
> **Comprehensive documentation for all 21 Git tools with 110+ actions**
|
|
16
|
-
> **Supports:**
|
|
17
|
-
> **
|
|
16
|
+
> **Supports:** Automatic DUAL execution on GitHub + Gitea APIs
|
|
17
|
+
> **BREAKING CHANGES in v7.0.0:** ALL tools now execute DUAL automatically with env var usernames
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 🚀 v7.0.0 MAJOR UPDATE: AUTOMATIC DUAL EXECUTION
|
|
22
|
+
|
|
23
|
+
**ALL TOOLS NOW:**
|
|
24
|
+
- ✅ Execute on BOTH GitHub and Gitea APIs automatically
|
|
25
|
+
- ✅ Use GITHUB_USERNAME and GITEA_USERNAME from environment variables
|
|
26
|
+
- ✅ Return separated responses: \`{ github: {...}, gitea: {...} }\`
|
|
27
|
+
- ✅ NO manual owner/user/author parameters needed
|
|
28
|
+
- ✅ Each provider uses its own credentials automatically
|
|
29
|
+
|
|
30
|
+
### Environment Variables Required:
|
|
31
|
+
\\\`\\\`\\\`bash
|
|
32
|
+
GITHUB_TOKEN=your_github_token
|
|
33
|
+
GITHUB_USERNAME=YourGitHubUsername
|
|
34
|
+
GITEA_TOKEN=your_gitea_token
|
|
35
|
+
GITEA_USERNAME=yourGiteaUsername
|
|
36
|
+
GITEA_URL=http://your-gitea-server:port
|
|
37
|
+
\\\`\\\`\\\`
|
|
18
38
|
|
|
19
39
|
---
|
|
20
40
|
|
|
@@ -2,28 +2,5 @@ import { Tool, MCPContext } from '../types';
|
|
|
2
2
|
export declare class GitAnalyticsTool implements Tool {
|
|
3
3
|
name: string;
|
|
4
4
|
description: string;
|
|
5
|
-
handle(params: Record<string, any>, ctx: MCPContext): Promise<
|
|
6
|
-
success: boolean;
|
|
7
|
-
stats: {
|
|
8
|
-
totalCommits: number;
|
|
9
|
-
branches: number;
|
|
10
|
-
tags: number;
|
|
11
|
-
latestCommit: (import("simple-git").DefaultLogFields & import("simple-git").ListLogLine) | null;
|
|
12
|
-
};
|
|
13
|
-
commits?: undefined;
|
|
14
|
-
details?: undefined;
|
|
15
|
-
contributors?: undefined;
|
|
16
|
-
} | {
|
|
17
|
-
success: boolean;
|
|
18
|
-
commits: number;
|
|
19
|
-
details: readonly (import("simple-git").DefaultLogFields & import("simple-git").ListLogLine)[];
|
|
20
|
-
stats?: undefined;
|
|
21
|
-
contributors?: undefined;
|
|
22
|
-
} | {
|
|
23
|
-
success: boolean;
|
|
24
|
-
contributors: any[];
|
|
25
|
-
stats?: undefined;
|
|
26
|
-
commits?: undefined;
|
|
27
|
-
details?: undefined;
|
|
28
|
-
}>;
|
|
5
|
+
handle(params: Record<string, any>, ctx: MCPContext): Promise<any>;
|
|
29
6
|
}
|
|
@@ -4,65 +4,190 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.GitAnalyticsTool = void 0;
|
|
7
|
-
const simple_git_1 = __importDefault(require("simple-git"));
|
|
8
7
|
const errors_1 = require("../utils/errors");
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const repoHelpers_1 = require("../utils/repoHelpers");
|
|
9
10
|
class GitAnalyticsTool {
|
|
10
11
|
constructor() {
|
|
11
12
|
this.name = 'git-analytics';
|
|
12
|
-
this.description = 'Repository analytics and statistics';
|
|
13
|
+
this.description = 'Repository analytics and statistics - automatic dual-provider execution using GitHub and Gitea APIs';
|
|
13
14
|
}
|
|
14
15
|
async handle(params, ctx) {
|
|
15
16
|
const action = params.action;
|
|
16
17
|
const projectPath = params.projectPath;
|
|
17
|
-
if (!action
|
|
18
|
-
throw new errors_1.MCPError('VALIDATION_ERROR', 'action
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
if (!action)
|
|
19
|
+
throw new errors_1.MCPError('VALIDATION_ERROR', 'action is required');
|
|
20
|
+
if (!projectPath)
|
|
21
|
+
throw new errors_1.MCPError('VALIDATION_ERROR', 'projectPath is required');
|
|
22
|
+
// Auto-extract repo info from projectPath
|
|
23
|
+
const repoInfo = (0, repoHelpers_1.getRepoInfo)(projectPath);
|
|
24
|
+
const repo = repoInfo.repoName;
|
|
25
|
+
// Each provider uses its own username from env
|
|
26
|
+
const githubOwner = process.env.GITHUB_USERNAME;
|
|
27
|
+
const giteaOwner = process.env.GITEA_USERNAME;
|
|
21
28
|
switch (action) {
|
|
22
29
|
case 'stats': {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
const results = { success: true, providers: {} };
|
|
31
|
+
// GitHub API
|
|
32
|
+
if (ctx.providerManager.github && githubOwner) {
|
|
33
|
+
try {
|
|
34
|
+
const repoData = await ctx.providerManager.github.rest.repos.get({
|
|
35
|
+
owner: githubOwner,
|
|
36
|
+
repo: repo,
|
|
37
|
+
});
|
|
38
|
+
const branches = await ctx.providerManager.github.rest.repos.listBranches({
|
|
39
|
+
owner: githubOwner,
|
|
40
|
+
repo: repo,
|
|
41
|
+
});
|
|
42
|
+
const tags = await ctx.providerManager.github.rest.repos.listTags({
|
|
43
|
+
owner: githubOwner,
|
|
44
|
+
repo: repo,
|
|
45
|
+
});
|
|
46
|
+
const commits = await ctx.providerManager.github.rest.repos.listCommits({
|
|
47
|
+
owner: githubOwner,
|
|
48
|
+
repo: repo,
|
|
49
|
+
per_page: 1,
|
|
50
|
+
});
|
|
51
|
+
results.providers.github = {
|
|
52
|
+
success: true,
|
|
53
|
+
stats: {
|
|
54
|
+
totalCommits: repoData.data.size,
|
|
55
|
+
branches: branches.data.length,
|
|
56
|
+
tags: tags.data.length,
|
|
57
|
+
defaultBranch: repoData.data.default_branch,
|
|
58
|
+
latestCommit: commits.data[0] || null,
|
|
59
|
+
size: repoData.data.size,
|
|
60
|
+
language: repoData.data.language,
|
|
61
|
+
stars: repoData.data.stargazers_count,
|
|
62
|
+
forks: repoData.data.forks_count,
|
|
63
|
+
openIssues: repoData.data.open_issues_count,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
results.providers.github = { success: false, error: err.message };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Gitea API
|
|
72
|
+
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
73
|
+
try {
|
|
74
|
+
const repoData = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
75
|
+
const branches = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/branches`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
76
|
+
const tags = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/tags`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
77
|
+
const commits = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/commits`, {
|
|
78
|
+
params: { limit: 1 },
|
|
79
|
+
headers: { Authorization: `token ${ctx.providerManager.giteaToken}` }
|
|
80
|
+
});
|
|
81
|
+
results.providers.gitea = {
|
|
82
|
+
success: true,
|
|
83
|
+
stats: {
|
|
84
|
+
totalCommits: repoData.data.size,
|
|
85
|
+
branches: branches.data.length,
|
|
86
|
+
tags: tags.data.length,
|
|
87
|
+
defaultBranch: repoData.data.default_branch,
|
|
88
|
+
latestCommit: commits.data[0] || null,
|
|
89
|
+
size: repoData.data.size,
|
|
90
|
+
language: repoData.data.language,
|
|
91
|
+
stars: repoData.data.stars_count,
|
|
92
|
+
forks: repoData.data.forks_count,
|
|
93
|
+
openIssues: repoData.data.open_issues_count,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
results.providers.gitea = { success: false, error: err.message };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return results;
|
|
35
102
|
}
|
|
36
103
|
case 'commits': {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
104
|
+
const results = { success: true, providers: {} };
|
|
105
|
+
// GitHub API
|
|
106
|
+
if (ctx.providerManager.github && githubOwner) {
|
|
107
|
+
try {
|
|
108
|
+
const commits = await ctx.providerManager.github.rest.repos.listCommits({
|
|
109
|
+
owner: githubOwner,
|
|
110
|
+
repo: repo,
|
|
111
|
+
since: params.since,
|
|
112
|
+
until: params.until,
|
|
113
|
+
per_page: params.limit || 100,
|
|
114
|
+
});
|
|
115
|
+
results.providers.github = {
|
|
116
|
+
success: true,
|
|
117
|
+
commits: commits.data.length,
|
|
118
|
+
details: commits.data,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
results.providers.github = { success: false, error: err.message };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Gitea API
|
|
126
|
+
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
127
|
+
try {
|
|
128
|
+
const commits = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/commits`, {
|
|
129
|
+
params: {
|
|
130
|
+
since: params.since,
|
|
131
|
+
until: params.until,
|
|
132
|
+
limit: params.limit || 100,
|
|
133
|
+
},
|
|
134
|
+
headers: { Authorization: `token ${ctx.providerManager.giteaToken}` }
|
|
135
|
+
});
|
|
136
|
+
results.providers.gitea = {
|
|
137
|
+
success: true,
|
|
138
|
+
commits: commits.data.length,
|
|
139
|
+
details: commits.data,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
results.providers.gitea = { success: false, error: err.message };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return results;
|
|
49
147
|
}
|
|
50
148
|
case 'contributors': {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
149
|
+
const results = { success: true, providers: {} };
|
|
150
|
+
// GitHub API
|
|
151
|
+
if (ctx.providerManager.github && githubOwner) {
|
|
152
|
+
try {
|
|
153
|
+
const contributors = await ctx.providerManager.github.rest.repos.listContributors({
|
|
154
|
+
owner: githubOwner,
|
|
155
|
+
repo: repo,
|
|
156
|
+
per_page: 100,
|
|
157
|
+
});
|
|
158
|
+
results.providers.github = {
|
|
159
|
+
success: true,
|
|
160
|
+
contributors: contributors.data.map((c) => ({
|
|
161
|
+
login: c.login,
|
|
162
|
+
name: c.login,
|
|
163
|
+
contributions: c.contributions,
|
|
164
|
+
avatar_url: c.avatar_url,
|
|
165
|
+
})),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
results.providers.github = { success: false, error: err.message };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Gitea API
|
|
173
|
+
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
174
|
+
try {
|
|
175
|
+
const contributors = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/contributors`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
176
|
+
results.providers.gitea = {
|
|
177
|
+
success: true,
|
|
178
|
+
contributors: contributors.data.map((c) => ({
|
|
179
|
+
login: c.login,
|
|
180
|
+
name: c.name || c.login,
|
|
181
|
+
contributions: c.contributions,
|
|
182
|
+
avatar_url: c.avatar_url,
|
|
183
|
+
})),
|
|
184
|
+
};
|
|
57
185
|
}
|
|
58
|
-
|
|
59
|
-
|
|
186
|
+
catch (err) {
|
|
187
|
+
results.providers.gitea = { success: false, error: err.message };
|
|
60
188
|
}
|
|
61
|
-
}
|
|
62
|
-
return
|
|
63
|
-
success: true,
|
|
64
|
-
contributors: Array.from(contributors.values()).sort((a, b) => b.count - a.count),
|
|
65
|
-
};
|
|
189
|
+
}
|
|
190
|
+
return results;
|
|
66
191
|
}
|
|
67
192
|
default:
|
|
68
193
|
throw new errors_1.MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
|
package/dist/tools/gitArchive.js
CHANGED
|
@@ -5,7 +5,7 @@ const errors_1 = require("../utils/errors");
|
|
|
5
5
|
class GitArchiveTool {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.name = 'git-archive';
|
|
8
|
-
this.description = 'Repository archive operations';
|
|
8
|
+
this.description = 'Repository archive operations - local operations';
|
|
9
9
|
}
|
|
10
10
|
async handle(params, ctx) {
|
|
11
11
|
const action = params.action;
|
package/dist/tools/gitBackup.js
CHANGED
|
@@ -9,7 +9,7 @@ const errors_1 = require("../utils/errors");
|
|
|
9
9
|
class GitBackupTool {
|
|
10
10
|
constructor() {
|
|
11
11
|
this.name = 'git-backup';
|
|
12
|
-
this.description = 'Repository backup and restore operations';
|
|
12
|
+
this.description = 'Repository backup and restore operations - local operations';
|
|
13
13
|
}
|
|
14
14
|
async handle(params, ctx) {
|
|
15
15
|
const action = params.action;
|
|
@@ -2,71 +2,5 @@ import { Tool, MCPContext } from '../types';
|
|
|
2
2
|
export declare class GitBranchesTool implements Tool {
|
|
3
3
|
name: string;
|
|
4
4
|
description: string;
|
|
5
|
-
handle(params: Record<string, any>, ctx: MCPContext): Promise<
|
|
6
|
-
success: boolean;
|
|
7
|
-
branch: any;
|
|
8
|
-
branches?: undefined;
|
|
9
|
-
current?: undefined;
|
|
10
|
-
deleted?: undefined;
|
|
11
|
-
result?: undefined;
|
|
12
|
-
baseBranch?: undefined;
|
|
13
|
-
compareBranch?: undefined;
|
|
14
|
-
commits?: undefined;
|
|
15
|
-
diff?: undefined;
|
|
16
|
-
} | {
|
|
17
|
-
branches: string[];
|
|
18
|
-
current: string;
|
|
19
|
-
success?: undefined;
|
|
20
|
-
branch?: undefined;
|
|
21
|
-
deleted?: undefined;
|
|
22
|
-
result?: undefined;
|
|
23
|
-
baseBranch?: undefined;
|
|
24
|
-
compareBranch?: undefined;
|
|
25
|
-
commits?: undefined;
|
|
26
|
-
diff?: undefined;
|
|
27
|
-
} | {
|
|
28
|
-
success: boolean;
|
|
29
|
-
branch: string;
|
|
30
|
-
current: boolean;
|
|
31
|
-
branches?: undefined;
|
|
32
|
-
deleted?: undefined;
|
|
33
|
-
result?: undefined;
|
|
34
|
-
baseBranch?: undefined;
|
|
35
|
-
compareBranch?: undefined;
|
|
36
|
-
commits?: undefined;
|
|
37
|
-
diff?: undefined;
|
|
38
|
-
} | {
|
|
39
|
-
success: boolean;
|
|
40
|
-
deleted: any;
|
|
41
|
-
branch?: undefined;
|
|
42
|
-
branches?: undefined;
|
|
43
|
-
current?: undefined;
|
|
44
|
-
result?: undefined;
|
|
45
|
-
baseBranch?: undefined;
|
|
46
|
-
compareBranch?: undefined;
|
|
47
|
-
commits?: undefined;
|
|
48
|
-
diff?: undefined;
|
|
49
|
-
} | {
|
|
50
|
-
success: boolean;
|
|
51
|
-
result: import("simple-git").MergeResult;
|
|
52
|
-
branch?: undefined;
|
|
53
|
-
branches?: undefined;
|
|
54
|
-
current?: undefined;
|
|
55
|
-
deleted?: undefined;
|
|
56
|
-
baseBranch?: undefined;
|
|
57
|
-
compareBranch?: undefined;
|
|
58
|
-
commits?: undefined;
|
|
59
|
-
diff?: undefined;
|
|
60
|
-
} | {
|
|
61
|
-
success: boolean;
|
|
62
|
-
baseBranch: any;
|
|
63
|
-
compareBranch: any;
|
|
64
|
-
commits: readonly (import("simple-git").DefaultLogFields & import("simple-git").ListLogLine)[];
|
|
65
|
-
diff: string;
|
|
66
|
-
branch?: undefined;
|
|
67
|
-
branches?: undefined;
|
|
68
|
-
current?: undefined;
|
|
69
|
-
deleted?: undefined;
|
|
70
|
-
result?: undefined;
|
|
71
|
-
}>;
|
|
5
|
+
handle(params: Record<string, any>, ctx: MCPContext): Promise<any>;
|
|
72
6
|
}
|
|
@@ -7,10 +7,12 @@ exports.GitBranchesTool = void 0;
|
|
|
7
7
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
8
8
|
const errors_1 = require("../utils/errors");
|
|
9
9
|
const safetyController_1 = require("../utils/safetyController");
|
|
10
|
+
const repoHelpers_1 = require("../utils/repoHelpers");
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
12
|
class GitBranchesTool {
|
|
11
13
|
constructor() {
|
|
12
14
|
this.name = 'git-branches';
|
|
13
|
-
this.description = 'Branch management operations';
|
|
15
|
+
this.description = 'Branch management operations - automatic dual-provider execution for remote queries';
|
|
14
16
|
}
|
|
15
17
|
async handle(params, ctx) {
|
|
16
18
|
const action = params.action;
|
|
@@ -32,14 +34,60 @@ class GitBranchesTool {
|
|
|
32
34
|
if (params.checkout !== false) {
|
|
33
35
|
await git.checkout(branchName);
|
|
34
36
|
}
|
|
35
|
-
return { success: true, branch: branchName };
|
|
37
|
+
return { success: true, branch: branchName, local: true };
|
|
36
38
|
}
|
|
37
39
|
case 'list': {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const localBranches = await git.branch();
|
|
41
|
+
const results = {
|
|
42
|
+
success: true,
|
|
43
|
+
local: {
|
|
44
|
+
branches: localBranches.all,
|
|
45
|
+
current: localBranches.current,
|
|
46
|
+
},
|
|
47
|
+
providers: {}
|
|
42
48
|
};
|
|
49
|
+
// Also query remote APIs
|
|
50
|
+
const repoInfo = (0, repoHelpers_1.getRepoInfo)(projectPath);
|
|
51
|
+
const githubOwner = process.env.GITHUB_USERNAME;
|
|
52
|
+
const giteaOwner = process.env.GITEA_USERNAME;
|
|
53
|
+
// GitHub
|
|
54
|
+
if (ctx.providerManager.github && githubOwner) {
|
|
55
|
+
try {
|
|
56
|
+
const branches = await ctx.providerManager.github.rest.repos.listBranches({
|
|
57
|
+
owner: githubOwner,
|
|
58
|
+
repo: repoInfo.repoName,
|
|
59
|
+
});
|
|
60
|
+
results.providers.github = {
|
|
61
|
+
success: true,
|
|
62
|
+
branches: branches.data.map((b) => ({
|
|
63
|
+
name: b.name,
|
|
64
|
+
protected: b.protected,
|
|
65
|
+
sha: b.commit.sha,
|
|
66
|
+
})),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
results.providers.github = { success: false, error: err.message };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Gitea
|
|
74
|
+
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
75
|
+
try {
|
|
76
|
+
const branches = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repoInfo.repoName}/branches`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
77
|
+
results.providers.gitea = {
|
|
78
|
+
success: true,
|
|
79
|
+
branches: branches.data.map((b) => ({
|
|
80
|
+
name: b.name,
|
|
81
|
+
protected: b.protected,
|
|
82
|
+
sha: b.commit.id,
|
|
83
|
+
})),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
results.providers.gitea = { success: false, error: err.message };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return results;
|
|
43
91
|
}
|
|
44
92
|
case 'get': {
|
|
45
93
|
const branchName = params.branchName;
|
|
@@ -47,13 +95,56 @@ class GitBranchesTool {
|
|
|
47
95
|
throw new errors_1.MCPError('VALIDATION_ERROR', 'branchName is required');
|
|
48
96
|
const branches = await git.branch();
|
|
49
97
|
const branch = branches.all.find(b => b === branchName);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
98
|
+
const results = {
|
|
99
|
+
success: true,
|
|
100
|
+
local: branch ? { branch, current: branches.current === branchName } : { found: false },
|
|
101
|
+
providers: {}
|
|
102
|
+
};
|
|
103
|
+
// Also query remote APIs
|
|
104
|
+
const repoInfo = (0, repoHelpers_1.getRepoInfo)(projectPath);
|
|
105
|
+
const githubOwner = process.env.GITHUB_USERNAME;
|
|
106
|
+
const giteaOwner = process.env.GITEA_USERNAME;
|
|
107
|
+
// GitHub
|
|
108
|
+
if (ctx.providerManager.github && githubOwner) {
|
|
109
|
+
try {
|
|
110
|
+
const branchData = await ctx.providerManager.github.rest.repos.getBranch({
|
|
111
|
+
owner: githubOwner,
|
|
112
|
+
repo: repoInfo.repoName,
|
|
113
|
+
branch: branchName,
|
|
114
|
+
});
|
|
115
|
+
results.providers.github = {
|
|
116
|
+
success: true,
|
|
117
|
+
branch: {
|
|
118
|
+
name: branchData.data.name,
|
|
119
|
+
protected: branchData.data.protected,
|
|
120
|
+
sha: branchData.data.commit.sha,
|
|
121
|
+
commit: branchData.data.commit,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
results.providers.github = { success: false, error: err.message };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Gitea
|
|
130
|
+
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
131
|
+
try {
|
|
132
|
+
const branchData = await axios_1.default.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repoInfo.repoName}/branches/${branchName}`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
133
|
+
results.providers.gitea = {
|
|
134
|
+
success: true,
|
|
135
|
+
branch: {
|
|
136
|
+
name: branchData.data.name,
|
|
137
|
+
protected: branchData.data.protected,
|
|
138
|
+
sha: branchData.data.commit.id,
|
|
139
|
+
commit: branchData.data.commit,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
results.providers.gitea = { success: false, error: err.message };
|
|
145
|
+
}
|
|
55
146
|
}
|
|
56
|
-
return
|
|
147
|
+
return results;
|
|
57
148
|
}
|
|
58
149
|
case 'delete': {
|
|
59
150
|
(0, safetyController_1.requireConfirmationIfDestructive)('delete', params);
|
|
@@ -61,7 +152,7 @@ class GitBranchesTool {
|
|
|
61
152
|
if (!branchName)
|
|
62
153
|
throw new errors_1.MCPError('VALIDATION_ERROR', 'branchName is required');
|
|
63
154
|
await git.deleteLocalBranch(branchName, params.force);
|
|
64
|
-
return { success: true, deleted: branchName };
|
|
155
|
+
return { success: true, deleted: branchName, local: true };
|
|
65
156
|
}
|
|
66
157
|
case 'merge': {
|
|
67
158
|
const branchName = params.branchName;
|
|
@@ -72,7 +163,7 @@ class GitBranchesTool {
|
|
|
72
163
|
await git.checkout(targetBranch);
|
|
73
164
|
}
|
|
74
165
|
const result = await git.merge([branchName]);
|
|
75
|
-
return { success: true, result };
|
|
166
|
+
return { success: true, result, local: true };
|
|
76
167
|
}
|
|
77
168
|
case 'compare': {
|
|
78
169
|
const baseBranch = params.baseBranch;
|
|
@@ -82,13 +173,54 @@ class GitBranchesTool {
|
|
|
82
173
|
}
|
|
83
174
|
const diff = await git.diff([`${baseBranch}...${compareBranch}`]);
|
|
84
175
|
const log = await git.log({ from: baseBranch, to: compareBranch });
|
|
85
|
-
|
|
176
|
+
const results = {
|
|
86
177
|
success: true,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
178
|
+
local: {
|
|
179
|
+
baseBranch,
|
|
180
|
+
compareBranch,
|
|
181
|
+
commits: log.all,
|
|
182
|
+
diff,
|
|
183
|
+
},
|
|
184
|
+
providers: {}
|
|
91
185
|
};
|
|
186
|
+
// Also compare on remote APIs
|
|
187
|
+
const repoInfo = (0, repoHelpers_1.getRepoInfo)(projectPath);
|
|
188
|
+
const githubOwner = process.env.GITHUB_USERNAME;
|
|
189
|
+
const giteaOwner = process.env.GITEA_USERNAME;
|
|
190
|
+
// GitHub
|
|
191
|
+
if (ctx.providerManager.github && githubOwner) {
|
|
192
|
+
try {
|
|
193
|
+
const comparison = await ctx.providerManager.github.rest.repos.compareCommits({
|
|
194
|
+
owner: githubOwner,
|
|
195
|
+
repo: repoInfo.repoName,
|
|
196
|
+
base: baseBranch,
|
|
197
|
+
head: compareBranch,
|
|
198
|
+
});
|
|
199
|
+
results.providers.github = {
|
|
200
|
+
success: true,
|
|
201
|
+
comparison: {
|
|
202
|
+
status: comparison.data.status,
|
|
203
|
+
ahead_by: comparison.data.ahead_by,
|
|
204
|
+
behind_by: comparison.data.behind_by,
|
|
205
|
+
total_commits: comparison.data.total_commits,
|
|
206
|
+
commits: comparison.data.commits.map((c) => ({
|
|
207
|
+
sha: c.sha,
|
|
208
|
+
message: c.commit.message,
|
|
209
|
+
author: c.commit.author.name,
|
|
210
|
+
date: c.commit.author.date,
|
|
211
|
+
})),
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
results.providers.github = { success: false, error: err.message };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Gitea - comparison API might not be available
|
|
220
|
+
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
221
|
+
results.providers.gitea = { success: false, error: 'Comparison API not available in Gitea' };
|
|
222
|
+
}
|
|
223
|
+
return results;
|
|
92
224
|
}
|
|
93
225
|
default:
|
|
94
226
|
throw new errors_1.MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
|
package/dist/tools/gitConfig.js
CHANGED
|
@@ -9,7 +9,7 @@ const errors_1 = require("../utils/errors");
|
|
|
9
9
|
class GitConfigTool {
|
|
10
10
|
constructor() {
|
|
11
11
|
this.name = 'git-config';
|
|
12
|
-
this.description = 'Git configuration management';
|
|
12
|
+
this.description = 'Git configuration management - local Git operations';
|
|
13
13
|
}
|
|
14
14
|
async handle(params, ctx) {
|
|
15
15
|
const action = params.action;
|
package/dist/tools/gitFiles.js
CHANGED
|
@@ -10,7 +10,7 @@ const errors_1 = require("../utils/errors");
|
|
|
10
10
|
class GitFilesTool {
|
|
11
11
|
constructor() {
|
|
12
12
|
this.name = 'git-files';
|
|
13
|
-
this.description = 'Read-only file operations for repositories';
|
|
13
|
+
this.description = 'Read-only file operations for repositories - local operations only';
|
|
14
14
|
}
|
|
15
15
|
async handle(params) {
|
|
16
16
|
const action = params.action;
|
package/dist/tools/gitIssues.js
CHANGED
|
@@ -6,7 +6,7 @@ const repoHelpers_1 = require("../utils/repoHelpers");
|
|
|
6
6
|
class GitIssuesTool {
|
|
7
7
|
constructor() {
|
|
8
8
|
this.name = 'git-issues';
|
|
9
|
-
this.description = 'Issue management for GitHub and Gitea';
|
|
9
|
+
this.description = 'Issue management for GitHub and Gitea - automatic dual-provider execution';
|
|
10
10
|
}
|
|
11
11
|
async handle(params, ctx) {
|
|
12
12
|
const action = params.action;
|