@andrebuzeli/git-mcp 10.0.7 → 10.0.9
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/LICENSE +0 -0
- package/README.md +1 -1
- package/dist/providers/providerManager.js +2 -4
- package/dist/scripts/test_e2e.d.ts +1 -0
- package/dist/scripts/test_e2e.js +199 -0
- package/dist/scripts/test_exhaustive.d.ts +1 -0
- package/dist/scripts/test_exhaustive.js +275 -0
- package/dist/scripts/test_gitea_creation.d.ts +1 -0
- package/dist/scripts/test_gitea_creation.js +116 -0
- package/dist/scripts/verify_setup.d.ts +1 -0
- package/dist/scripts/verify_setup.js +61 -0
- package/dist/tools/gitAnalytics.js +3 -3
- package/dist/tools/gitBackup.d.ts +2 -2
- package/dist/tools/gitBackup.js +5 -5
- package/dist/tools/gitBranches.js +40 -29
- package/dist/tools/gitConfig.d.ts +2 -2
- package/dist/tools/gitConfig.js +12 -13
- package/dist/tools/gitFix.d.ts +2 -1
- package/dist/tools/gitFix.js +20 -24
- package/dist/tools/gitFix.tool.d.ts +2 -2
- package/dist/tools/gitFix.tool.js +2 -2
- package/dist/tools/gitHistory.js +4 -5
- package/dist/tools/gitIssues.js +8 -8
- package/dist/tools/gitMonitor.js +28 -33
- package/dist/tools/gitPulls.js +8 -8
- package/dist/tools/gitRelease.js +5 -6
- package/dist/tools/gitRemote.d.ts +1 -11
- package/dist/tools/gitRemote.js +14 -20
- package/dist/tools/gitReset.js +6 -7
- package/dist/tools/gitStash.d.ts +1 -12
- package/dist/tools/gitStash.js +11 -22
- package/dist/tools/gitSync.js +44 -36
- package/dist/tools/gitTags.d.ts +8 -0
- package/dist/tools/gitTags.js +44 -34
- package/dist/tools/gitUpdate.d.ts +27 -0
- package/dist/tools/gitUpdate.js +61 -34
- package/dist/tools/gitUpload.js +29 -44
- package/dist/tools/gitWorkflow.js +27 -46
- package/dist/utils/gitAdapter.js +10 -0
- package/dist/utils/repoHelpers.js +7 -12
- package/package.json +2 -3
- package/dist/server-new.d.ts +0 -2
- package/dist/server-new.js +0 -224
- package/dist/tools/gitFiles-new.d.ts +0 -89
- package/dist/tools/gitFiles-new.js +0 -335
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ProviderManager } from '../providers/providerManager.js';
|
|
2
|
+
import { IsomorphicGitAdapter } from '../utils/gitAdapter.js';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
async function verify() {
|
|
6
|
+
console.log('🔍 Verifying setup and credentials...');
|
|
7
|
+
// 1. Check Environment Variables
|
|
8
|
+
console.log('\n1. Environment Variables:');
|
|
9
|
+
const vars = ['GITHUB_TOKEN', 'GITHUB_USERNAME', 'GITEA_TOKEN', 'GITEA_URL', 'GITEA_USERNAME'];
|
|
10
|
+
const missing = [];
|
|
11
|
+
for (const v of vars) {
|
|
12
|
+
if (process.env[v]) {
|
|
13
|
+
console.log(` ✅ ${v} is set`);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
console.log(` ❌ ${v} is MISSING`);
|
|
17
|
+
missing.push(v);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// 2. Validate Providers
|
|
21
|
+
console.log('\n2. Provider Connection:');
|
|
22
|
+
const providerManager = new ProviderManager();
|
|
23
|
+
const results = await providerManager.validateConfiguredProviders();
|
|
24
|
+
if (results.github) {
|
|
25
|
+
console.log(` GitHub: ${results.github.ok ? '✅ Connected' : '❌ Failed: ' + results.github.error}`);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.log(' GitHub: ⚠️ Not configured');
|
|
29
|
+
}
|
|
30
|
+
if (results.gitea) {
|
|
31
|
+
console.log(` Gitea: ${results.gitea.ok ? '✅ Connected' : '❌ Failed: ' + results.gitea.error}`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(' Gitea: ⚠️ Not configured');
|
|
35
|
+
}
|
|
36
|
+
// 3. Validate GitAdapter
|
|
37
|
+
console.log('\n3. GitAdapter Initialization:');
|
|
38
|
+
try {
|
|
39
|
+
const gitAdapter = new IsomorphicGitAdapter(providerManager);
|
|
40
|
+
console.log(' ✅ GitAdapter initialized successfully');
|
|
41
|
+
// Try a simple local operation if we are in a git repo
|
|
42
|
+
const currentDir = process.cwd();
|
|
43
|
+
if (fs.existsSync(path.join(currentDir, '.git'))) {
|
|
44
|
+
try {
|
|
45
|
+
const branch = await gitAdapter.getCurrentBranch(currentDir);
|
|
46
|
+
console.log(` ✅ Local Git check passed (Current branch: ${branch})`);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
console.log(` ❌ Local Git check failed: ${e.message}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.log(' ℹ️ Current directory is not a git repo, skipping local check');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
console.log(` ❌ GitAdapter initialization failed: ${err.message}`);
|
|
58
|
+
}
|
|
59
|
+
console.log('\n🏁 Verification Complete');
|
|
60
|
+
}
|
|
61
|
+
verify().catch(console.error);
|
|
@@ -45,10 +45,10 @@ export class GitAnalyticsTool {
|
|
|
45
45
|
throw new MCPError('VALIDATION_ERROR', 'projectPath is required');
|
|
46
46
|
// Auto-extract repo info from projectPath
|
|
47
47
|
const repoInfo = getRepoInfo(projectPath);
|
|
48
|
-
const repo = repoInfo.repoName;
|
|
48
|
+
const repo = params.repo || repoInfo.repoName;
|
|
49
49
|
// Each provider uses its own username from env
|
|
50
|
-
const githubOwner = process.env.GITHUB_USERNAME;
|
|
51
|
-
const giteaOwner = process.env.GITEA_USERNAME;
|
|
50
|
+
const githubOwner = params.owner || process.env.GITHUB_USERNAME;
|
|
51
|
+
const giteaOwner = params.owner || process.env.GITEA_USERNAME;
|
|
52
52
|
switch (action) {
|
|
53
53
|
case 'stats': {
|
|
54
54
|
const results = { success: true, providers: {} };
|
|
@@ -40,8 +40,8 @@ export declare class GitBackupTool implements Tool {
|
|
|
40
40
|
backupData: {
|
|
41
41
|
projectPath: any;
|
|
42
42
|
timestamp: string;
|
|
43
|
-
branch: string
|
|
44
|
-
lastCommit: string |
|
|
43
|
+
branch: string;
|
|
44
|
+
lastCommit: string | null;
|
|
45
45
|
files: number;
|
|
46
46
|
};
|
|
47
47
|
message: string;
|
package/dist/tools/gitBackup.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import simpleGit from 'simple-git';
|
|
4
3
|
import { MCPError } from '../utils/errors.js';
|
|
5
4
|
export class GitBackupTool {
|
|
6
5
|
constructor() {
|
|
@@ -46,6 +45,7 @@ export class GitBackupTool {
|
|
|
46
45
|
throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
|
|
47
46
|
}
|
|
48
47
|
switch (action) {
|
|
48
|
+
case 'create':
|
|
49
49
|
case 'backup': {
|
|
50
50
|
const backupDir = params.backupDir || path.join(projectPath, '.git-backups');
|
|
51
51
|
const backupName = params.backupName || `backup-${Date.now()}.json`;
|
|
@@ -53,14 +53,14 @@ export class GitBackupTool {
|
|
|
53
53
|
// Criar diretório de backups
|
|
54
54
|
await fs.mkdir(backupDir, { recursive: true });
|
|
55
55
|
const backupPath = path.join(backupDir, backupName);
|
|
56
|
-
const git =
|
|
57
|
-
const status = await git.status();
|
|
58
|
-
const log = await git.log({ maxCount: 1 });
|
|
56
|
+
const git = ctx.gitAdapter;
|
|
57
|
+
const status = await git.status(projectPath);
|
|
58
|
+
const log = await git.log(projectPath, { maxCount: 1 });
|
|
59
59
|
const backupData = {
|
|
60
60
|
projectPath,
|
|
61
61
|
timestamp: new Date().toISOString(),
|
|
62
62
|
branch: status.current,
|
|
63
|
-
lastCommit: log.
|
|
63
|
+
lastCommit: log.length > 0 ? log[0].hash : null,
|
|
64
64
|
files: status.files.length,
|
|
65
65
|
};
|
|
66
66
|
await fs.writeFile(backupPath, JSON.stringify(backupData, null, 2));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import simpleGit from 'simple-git';
|
|
2
1
|
import { MCPError } from '../utils/errors.js';
|
|
3
2
|
import { requireConfirmationIfDestructive } from '../utils/safetyController.js';
|
|
4
3
|
import { getRepoInfo } from '../utils/repoHelpers.js';
|
|
@@ -62,7 +61,9 @@ export class GitBranchesTool {
|
|
|
62
61
|
if (!action || !projectPath) {
|
|
63
62
|
throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
|
|
64
63
|
}
|
|
65
|
-
|
|
64
|
+
if (!ctx.gitAdapter) {
|
|
65
|
+
throw new MCPError('INTERNAL_ERROR', 'Git adapter not available');
|
|
66
|
+
}
|
|
66
67
|
switch (action) {
|
|
67
68
|
case 'create': {
|
|
68
69
|
const branchName = params.branchName;
|
|
@@ -70,34 +71,36 @@ export class GitBranchesTool {
|
|
|
70
71
|
throw new MCPError('VALIDATION_ERROR', 'branchName is required');
|
|
71
72
|
const sourceBranch = params.sourceBranch;
|
|
72
73
|
if (sourceBranch) {
|
|
73
|
-
await
|
|
74
|
+
await ctx.gitAdapter.checkout(projectPath, sourceBranch);
|
|
74
75
|
}
|
|
75
|
-
await
|
|
76
|
+
await ctx.gitAdapter.createBranch(projectPath, branchName);
|
|
76
77
|
if (params.checkout !== false) {
|
|
77
|
-
await
|
|
78
|
+
await ctx.gitAdapter.checkout(projectPath, branchName);
|
|
78
79
|
}
|
|
79
80
|
return { success: true, branch: branchName, local: true };
|
|
80
81
|
}
|
|
81
82
|
case 'list': {
|
|
82
|
-
const
|
|
83
|
+
const branches = await ctx.gitAdapter.listBranches(projectPath);
|
|
84
|
+
const current = await ctx.gitAdapter.getCurrentBranch(projectPath);
|
|
83
85
|
const results = {
|
|
84
86
|
success: true,
|
|
85
87
|
local: {
|
|
86
|
-
branches
|
|
87
|
-
current
|
|
88
|
+
branches,
|
|
89
|
+
current,
|
|
88
90
|
},
|
|
89
91
|
providers: {}
|
|
90
92
|
};
|
|
91
93
|
// Also query remote APIs
|
|
92
94
|
const repoInfo = getRepoInfo(projectPath);
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
+
const repo = params.repo || repoInfo.repoName;
|
|
96
|
+
const githubOwner = params.owner || process.env.GITHUB_USERNAME;
|
|
97
|
+
const giteaOwner = params.owner || process.env.GITEA_USERNAME;
|
|
95
98
|
// GitHub
|
|
96
99
|
if (ctx.providerManager.github && githubOwner) {
|
|
97
100
|
try {
|
|
98
101
|
const branches = await ctx.providerManager.github.rest.repos.listBranches({
|
|
99
102
|
owner: githubOwner,
|
|
100
|
-
repo:
|
|
103
|
+
repo: repo,
|
|
101
104
|
});
|
|
102
105
|
results.providers.github = {
|
|
103
106
|
success: true,
|
|
@@ -115,7 +118,7 @@ export class GitBranchesTool {
|
|
|
115
118
|
// Gitea
|
|
116
119
|
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
117
120
|
try {
|
|
118
|
-
const branches = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${
|
|
121
|
+
const branches = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/branches`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
119
122
|
results.providers.gitea = {
|
|
120
123
|
success: true,
|
|
121
124
|
branches: branches.data.map((b) => ({
|
|
@@ -135,23 +138,25 @@ export class GitBranchesTool {
|
|
|
135
138
|
const branchName = params.branchName;
|
|
136
139
|
if (!branchName)
|
|
137
140
|
throw new MCPError('VALIDATION_ERROR', 'branchName is required');
|
|
138
|
-
const branches = await
|
|
139
|
-
const
|
|
141
|
+
const branches = await ctx.gitAdapter.listBranches(projectPath);
|
|
142
|
+
const current = await ctx.gitAdapter.getCurrentBranch(projectPath);
|
|
143
|
+
const found = branches.includes(branchName);
|
|
140
144
|
const results = {
|
|
141
145
|
success: true,
|
|
142
|
-
local:
|
|
146
|
+
local: found ? { branch: branchName, current: current === branchName } : { found: false },
|
|
143
147
|
providers: {}
|
|
144
148
|
};
|
|
145
149
|
// Also query remote APIs
|
|
146
150
|
const repoInfo = getRepoInfo(projectPath);
|
|
147
|
-
const
|
|
148
|
-
const
|
|
151
|
+
const repo = params.repo || repoInfo.repoName;
|
|
152
|
+
const githubOwner = params.owner || process.env.GITHUB_USERNAME;
|
|
153
|
+
const giteaOwner = params.owner || process.env.GITEA_USERNAME;
|
|
149
154
|
// GitHub
|
|
150
155
|
if (ctx.providerManager.github && githubOwner) {
|
|
151
156
|
try {
|
|
152
157
|
const branchData = await ctx.providerManager.github.rest.repos.getBranch({
|
|
153
158
|
owner: githubOwner,
|
|
154
|
-
repo:
|
|
159
|
+
repo: repo,
|
|
155
160
|
branch: branchName,
|
|
156
161
|
});
|
|
157
162
|
results.providers.github = {
|
|
@@ -171,7 +176,7 @@ export class GitBranchesTool {
|
|
|
171
176
|
// Gitea
|
|
172
177
|
if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
|
|
173
178
|
try {
|
|
174
|
-
const branchData = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${
|
|
179
|
+
const branchData = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/branches/${branchName}`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
|
|
175
180
|
results.providers.gitea = {
|
|
176
181
|
success: true,
|
|
177
182
|
branch: {
|
|
@@ -193,7 +198,7 @@ export class GitBranchesTool {
|
|
|
193
198
|
const branchName = params.branchName;
|
|
194
199
|
if (!branchName)
|
|
195
200
|
throw new MCPError('VALIDATION_ERROR', 'branchName is required');
|
|
196
|
-
await
|
|
201
|
+
await ctx.gitAdapter.deleteBranch(projectPath, branchName, params.force);
|
|
197
202
|
return { success: true, deleted: branchName, local: true };
|
|
198
203
|
}
|
|
199
204
|
case 'merge': {
|
|
@@ -202,9 +207,9 @@ export class GitBranchesTool {
|
|
|
202
207
|
if (!branchName)
|
|
203
208
|
throw new MCPError('VALIDATION_ERROR', 'branchName is required');
|
|
204
209
|
if (targetBranch) {
|
|
205
|
-
await
|
|
210
|
+
await ctx.gitAdapter.checkout(projectPath, targetBranch);
|
|
206
211
|
}
|
|
207
|
-
const result = await
|
|
212
|
+
const result = await ctx.gitAdapter.merge(projectPath, branchName);
|
|
208
213
|
return { success: true, result, local: true };
|
|
209
214
|
}
|
|
210
215
|
case 'compare': {
|
|
@@ -213,28 +218,34 @@ export class GitBranchesTool {
|
|
|
213
218
|
if (!baseBranch || !compareBranch) {
|
|
214
219
|
throw new MCPError('VALIDATION_ERROR', 'baseBranch and compareBranch are required');
|
|
215
220
|
}
|
|
216
|
-
|
|
217
|
-
|
|
221
|
+
// Basic comparison using log
|
|
222
|
+
// Note: This is a simplified comparison compared to git log base..compare
|
|
223
|
+
const baseLog = await ctx.gitAdapter.log(projectPath, { ref: baseBranch, maxCount: 20 });
|
|
224
|
+
const compareLog = await ctx.gitAdapter.log(projectPath, { ref: compareBranch, maxCount: 20 });
|
|
225
|
+
// Find commits in compare that are not in base
|
|
226
|
+
const baseHashes = new Set(baseLog.map(c => c.hash));
|
|
227
|
+
const uniqueCommits = compareLog.filter(c => !baseHashes.has(c.hash));
|
|
218
228
|
const results = {
|
|
219
229
|
success: true,
|
|
220
230
|
local: {
|
|
221
231
|
baseBranch,
|
|
222
232
|
compareBranch,
|
|
223
|
-
commits:
|
|
224
|
-
diff,
|
|
233
|
+
commits: uniqueCommits,
|
|
234
|
+
diff: "Diff not supported in adapter yet", // Placeholder
|
|
225
235
|
},
|
|
226
236
|
providers: {}
|
|
227
237
|
};
|
|
228
238
|
// Also compare on remote APIs
|
|
229
239
|
const repoInfo = getRepoInfo(projectPath);
|
|
230
|
-
const
|
|
231
|
-
const
|
|
240
|
+
const repo = params.repo || repoInfo.repoName;
|
|
241
|
+
const githubOwner = params.owner || process.env.GITHUB_USERNAME;
|
|
242
|
+
const giteaOwner = params.owner || process.env.GITEA_USERNAME;
|
|
232
243
|
// GitHub
|
|
233
244
|
if (ctx.providerManager.github && githubOwner) {
|
|
234
245
|
try {
|
|
235
246
|
const comparison = await ctx.providerManager.github.rest.repos.compareCommits({
|
|
236
247
|
owner: githubOwner,
|
|
237
|
-
repo:
|
|
248
|
+
repo: repo,
|
|
238
249
|
base: baseBranch,
|
|
239
250
|
head: compareBranch,
|
|
240
251
|
});
|
|
@@ -63,7 +63,7 @@ export declare class GitConfigTool implements Tool {
|
|
|
63
63
|
} | {
|
|
64
64
|
success: boolean;
|
|
65
65
|
scope: string;
|
|
66
|
-
configs:
|
|
66
|
+
configs: Record<string, string>;
|
|
67
67
|
key?: undefined;
|
|
68
68
|
value?: undefined;
|
|
69
69
|
message?: undefined;
|
|
@@ -74,7 +74,7 @@ export declare class GitConfigTool implements Tool {
|
|
|
74
74
|
} | {
|
|
75
75
|
success: boolean;
|
|
76
76
|
key: any;
|
|
77
|
-
value: string |
|
|
77
|
+
value: string | undefined;
|
|
78
78
|
scope: string | undefined;
|
|
79
79
|
message?: undefined;
|
|
80
80
|
configs?: undefined;
|
package/dist/tools/gitConfig.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import simpleGit from 'simple-git';
|
|
2
1
|
import { MCPError } from '../utils/errors.js';
|
|
3
2
|
import * as fs from 'fs/promises';
|
|
4
3
|
import * as path from 'path';
|
|
@@ -49,49 +48,49 @@ export class GitConfigTool {
|
|
|
49
48
|
if (!action || !projectPath) {
|
|
50
49
|
throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
if (!ctx.gitAdapter) {
|
|
52
|
+
throw new MCPError('INTERNAL_ERROR', 'Git adapter not available');
|
|
53
|
+
}
|
|
53
54
|
const scope = params.global ? 'global' : params.system ? 'system' : 'local';
|
|
54
55
|
switch (action) {
|
|
55
56
|
case 'get': {
|
|
56
57
|
const key = params.key;
|
|
57
58
|
if (!key)
|
|
58
59
|
throw new MCPError('VALIDATION_ERROR', 'key is required');
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return { success: true, key, value: value.value };
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
60
|
+
const value = await ctx.gitAdapter.getConfig(projectPath, key, scope);
|
|
61
|
+
if (value === undefined) {
|
|
64
62
|
throw new MCPError('CONFIG_NOT_FOUND', `Configuration key '${key}' not found`);
|
|
65
63
|
}
|
|
64
|
+
return { success: true, key, value };
|
|
66
65
|
}
|
|
67
66
|
case 'set': {
|
|
68
67
|
const key = params.key;
|
|
69
68
|
const value = params.value;
|
|
70
69
|
if (!key || value === undefined)
|
|
71
70
|
throw new MCPError('VALIDATION_ERROR', 'key and value are required');
|
|
72
|
-
await
|
|
71
|
+
await ctx.gitAdapter.setConfig(projectPath, key, value, scope);
|
|
73
72
|
return { success: true, key, value };
|
|
74
73
|
}
|
|
75
74
|
case 'unset': {
|
|
76
75
|
const key = params.key;
|
|
77
76
|
if (!key)
|
|
78
77
|
throw new MCPError('VALIDATION_ERROR', 'key is required');
|
|
79
|
-
await
|
|
78
|
+
await ctx.gitAdapter.unsetConfig(projectPath, key, scope);
|
|
80
79
|
return { success: true, key, message: 'Configuration removed' };
|
|
81
80
|
}
|
|
82
81
|
case 'list': {
|
|
83
|
-
const configs = await
|
|
84
|
-
return { success: true, scope, configs
|
|
82
|
+
const configs = await ctx.gitAdapter.listConfig(projectPath, scope);
|
|
83
|
+
return { success: true, scope, configs };
|
|
85
84
|
}
|
|
86
85
|
case 'show': {
|
|
87
86
|
const key = params.key;
|
|
88
87
|
if (!key)
|
|
89
88
|
throw new MCPError('VALIDATION_ERROR', 'key is required');
|
|
90
|
-
const value = await
|
|
89
|
+
const value = await ctx.gitAdapter.getConfig(projectPath, key, scope);
|
|
91
90
|
return {
|
|
92
91
|
success: true,
|
|
93
92
|
key,
|
|
94
|
-
value
|
|
93
|
+
value,
|
|
95
94
|
scope: params.showScope ? scope : undefined,
|
|
96
95
|
};
|
|
97
96
|
}
|
package/dist/tools/gitFix.d.ts
CHANGED
package/dist/tools/gitFix.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import simpleGit from 'simple-git';
|
|
2
1
|
import path from 'path';
|
|
3
2
|
import fs from 'fs/promises';
|
|
4
3
|
import { existsSync } from 'fs';
|
|
5
4
|
import { buildGitHubUrl, buildGiteaUrl } from '../utils/repoHelpers.js';
|
|
6
|
-
export async function handleGitFix(args) {
|
|
5
|
+
export async function handleGitFix(args, ctx) {
|
|
7
6
|
try {
|
|
8
7
|
const { projectPath, githubRepo, giteaRepo, autoDetect = true } = args;
|
|
9
8
|
if (!projectPath) {
|
|
@@ -13,7 +12,7 @@ export async function handleGitFix(args) {
|
|
|
13
12
|
if (!existsSync(absolutePath)) {
|
|
14
13
|
throw new Error(`Caminho não existe: ${absolutePath}`);
|
|
15
14
|
}
|
|
16
|
-
const git =
|
|
15
|
+
const git = ctx.gitAdapter;
|
|
17
16
|
const result = {
|
|
18
17
|
success: false,
|
|
19
18
|
projectPath: absolutePath,
|
|
@@ -28,24 +27,21 @@ export async function handleGitFix(args) {
|
|
|
28
27
|
// Verificar se é um repositório Git
|
|
29
28
|
let isGitRepo = false;
|
|
30
29
|
try {
|
|
31
|
-
await git.status();
|
|
30
|
+
await git.status(absolutePath);
|
|
32
31
|
isGitRepo = true;
|
|
33
32
|
result.fixed.push('✅ Repositório Git válido encontrado');
|
|
34
33
|
}
|
|
35
34
|
catch (err) {
|
|
36
|
-
if
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
else {
|
|
43
|
-
throw err;
|
|
44
|
-
}
|
|
35
|
+
// isomorphic-git throws if not a repo, but we should check the error message or type if possible
|
|
36
|
+
// For now, assume any error means it's not a repo or has issues
|
|
37
|
+
result.warnings.push('⚠️ Não é um repositório Git - inicializando...');
|
|
38
|
+
await git.init(absolutePath);
|
|
39
|
+
result.fixed.push('✅ Git inicializado');
|
|
40
|
+
isGitRepo = true;
|
|
45
41
|
}
|
|
46
42
|
// Capturar remotes antes
|
|
47
|
-
const remotesBefore = await git.
|
|
48
|
-
result.remotes.before = remotesBefore.map(r => ({ name: r.name, url: r.
|
|
43
|
+
const remotesBefore = await git.listRemotes(absolutePath);
|
|
44
|
+
result.remotes.before = remotesBefore.map(r => ({ name: r.name, url: r.url || '' }));
|
|
49
45
|
// Obter usernames das env vars (OBRIGATÓRIO usar as credenciais fornecidas)
|
|
50
46
|
const githubUsername = process.env.GITHUB_USERNAME;
|
|
51
47
|
const giteaUsername = process.env.GITEA_USERNAME;
|
|
@@ -58,7 +54,7 @@ export async function handleGitFix(args) {
|
|
|
58
54
|
let detectedRepoName = null;
|
|
59
55
|
if (autoDetect && remotesBefore.length > 0) {
|
|
60
56
|
for (const remote of remotesBefore) {
|
|
61
|
-
const url = remote.
|
|
57
|
+
const url = remote.url || '';
|
|
62
58
|
// Detectar APENAS o nome do repo (sem username)
|
|
63
59
|
if (url.includes('github.com') && !detectedRepoName) {
|
|
64
60
|
const match = url.match(/github\.com[:/][^/]+\/([^/.]+)/);
|
|
@@ -102,27 +98,27 @@ export async function handleGitFix(args) {
|
|
|
102
98
|
for (const remoteName of remotesToRemove) {
|
|
103
99
|
const exists = remotesBefore.find(r => r.name === remoteName);
|
|
104
100
|
if (exists) {
|
|
105
|
-
await git.removeRemote(remoteName);
|
|
101
|
+
await git.removeRemote(absolutePath, remoteName);
|
|
106
102
|
result.fixed.push(`🗑️ Removido remote antigo: ${remoteName}`);
|
|
107
103
|
}
|
|
108
104
|
}
|
|
109
105
|
// Adicionar novos remotes no padrão dual
|
|
110
106
|
const githubUrl = buildGitHubUrl(finalGithubRepo.split('/')[0], finalGithubRepo.split('/')[1]);
|
|
111
107
|
const giteaUrlFull = buildGiteaUrl(finalGiteaRepo.split('/')[0], finalGiteaRepo.split('/')[1]);
|
|
112
|
-
await git.addRemote('github', githubUrl);
|
|
108
|
+
await git.addRemote(absolutePath, 'github', githubUrl);
|
|
113
109
|
result.fixed.push(`✅ Adicionado remote GitHub: ${githubUrl.replace(/oauth2:[^@]+@/, 'oauth2:***@')}`);
|
|
114
|
-
await git.addRemote('gitea', giteaUrlFull);
|
|
110
|
+
await git.addRemote(absolutePath, 'gitea', giteaUrlFull);
|
|
115
111
|
result.fixed.push(`✅ Adicionado remote Gitea: ${giteaUrlFull.replace(/:[^:]+@/, ':***@')}`);
|
|
116
112
|
// Configurar origin como push múltiplo
|
|
117
|
-
await git.addRemote('origin', githubUrl);
|
|
118
|
-
await git.
|
|
113
|
+
await git.addRemote(absolutePath, 'origin', githubUrl);
|
|
114
|
+
await git.setConfig(absolutePath, 'remote.origin.pushurl', giteaUrlFull, 'local');
|
|
119
115
|
result.fixed.push(`✅ Configurado origin para push dual (GitHub + Gitea)`);
|
|
120
116
|
// Capturar remotes depois
|
|
121
|
-
const remotesAfter = await git.
|
|
122
|
-
result.remotes.after = remotesAfter.map(r => ({ name: r.name, url: r.
|
|
117
|
+
const remotesAfter = await git.listRemotes(absolutePath);
|
|
118
|
+
result.remotes.after = remotesAfter.map(r => ({ name: r.name, url: r.url || '' }));
|
|
123
119
|
// Verificar se há commits
|
|
124
120
|
try {
|
|
125
|
-
await git.log();
|
|
121
|
+
await git.log(absolutePath);
|
|
126
122
|
result.fixed.push('✅ Histórico de commits preservado');
|
|
127
123
|
}
|
|
128
124
|
catch (err) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Tool } from '../types.js';
|
|
1
|
+
import { Tool, MCPContext } from '../types.js';
|
|
2
2
|
export declare class GitFixTool implements Tool {
|
|
3
3
|
name: string;
|
|
4
4
|
description: string;
|
|
@@ -25,7 +25,7 @@ export declare class GitFixTool implements Tool {
|
|
|
25
25
|
required: string[];
|
|
26
26
|
additionalProperties: boolean;
|
|
27
27
|
};
|
|
28
|
-
handle(args: any): Promise<{
|
|
28
|
+
handle(args: any, ctx: MCPContext): Promise<{
|
|
29
29
|
content: any[];
|
|
30
30
|
}>;
|
|
31
31
|
}
|
package/dist/tools/gitHistory.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import simpleGit from 'simple-git';
|
|
2
1
|
import { MCPError } from '../utils/errors.js';
|
|
3
2
|
import axios from 'axios';
|
|
4
3
|
import * as fs from 'fs/promises';
|
|
@@ -44,7 +43,7 @@ export class GitHistoryTool {
|
|
|
44
43
|
throw new MCPError('VALIDATION_ERROR', 'projectPath is required');
|
|
45
44
|
}
|
|
46
45
|
const action = params.action || 'track';
|
|
47
|
-
const git =
|
|
46
|
+
const git = ctx.gitAdapter;
|
|
48
47
|
switch (action) {
|
|
49
48
|
case 'track': {
|
|
50
49
|
// Rastrear mudança específica e criar histórico remoto
|
|
@@ -82,9 +81,9 @@ export class GitHistoryTool {
|
|
|
82
81
|
};
|
|
83
82
|
try {
|
|
84
83
|
// 1. Coletar detalhes da mudança
|
|
85
|
-
const status = await git.status();
|
|
86
|
-
const log = await git.log({ maxCount: 1 });
|
|
87
|
-
const lastCommit = log.
|
|
84
|
+
const status = await git.status(projectPath);
|
|
85
|
+
const log = await git.log(projectPath, { maxCount: 1 });
|
|
86
|
+
const lastCommit = log.length > 0 ? log[0] : null;
|
|
88
87
|
results.traceability.changeDetails = {
|
|
89
88
|
branch: status.current,
|
|
90
89
|
lastCommit: lastCommit ? {
|
package/dist/tools/gitIssues.js
CHANGED
|
@@ -84,9 +84,9 @@ export class GitIssuesTool {
|
|
|
84
84
|
if (!projectPath)
|
|
85
85
|
throw new MCPError('VALIDATION_ERROR', 'projectPath is required');
|
|
86
86
|
const repoInfo = getRepoInfo(projectPath);
|
|
87
|
-
const repo = repoInfo.repoName;
|
|
88
|
-
const githubOwner = repoInfo.githubOwner || process.env.GITHUB_USERNAME;
|
|
89
|
-
const giteaOwner = repoInfo.giteaOwner || process.env.GITEA_USERNAME;
|
|
87
|
+
const repo = params.repo || repoInfo.repoName;
|
|
88
|
+
const githubOwner = params.owner || repoInfo.githubOwner || process.env.GITHUB_USERNAME;
|
|
89
|
+
const giteaOwner = params.owner || repoInfo.giteaOwner || process.env.GITEA_USERNAME;
|
|
90
90
|
switch (action) {
|
|
91
91
|
case 'create': {
|
|
92
92
|
if (!params.title)
|
|
@@ -174,7 +174,7 @@ export class GitIssuesTool {
|
|
|
174
174
|
return results;
|
|
175
175
|
}
|
|
176
176
|
case 'get': {
|
|
177
|
-
const issue_number = params.issue_number;
|
|
177
|
+
const issue_number = params.issue_number || params.issueNumber;
|
|
178
178
|
if (!issue_number)
|
|
179
179
|
throw new MCPError('VALIDATION_ERROR', 'issue_number is required');
|
|
180
180
|
if (!repo)
|
|
@@ -210,7 +210,7 @@ export class GitIssuesTool {
|
|
|
210
210
|
return results;
|
|
211
211
|
}
|
|
212
212
|
case 'update': {
|
|
213
|
-
const issue_number = params.issue_number;
|
|
213
|
+
const issue_number = params.issue_number || params.issueNumber;
|
|
214
214
|
if (!issue_number)
|
|
215
215
|
throw new MCPError('VALIDATION_ERROR', 'issue_number is required');
|
|
216
216
|
if (!repo)
|
|
@@ -253,7 +253,7 @@ export class GitIssuesTool {
|
|
|
253
253
|
return results;
|
|
254
254
|
}
|
|
255
255
|
case 'close': {
|
|
256
|
-
const issue_number = params.issue_number;
|
|
256
|
+
const issue_number = params.issue_number || params.issueNumber;
|
|
257
257
|
if (!issue_number)
|
|
258
258
|
throw new MCPError('VALIDATION_ERROR', 'issue_number is required');
|
|
259
259
|
if (!repo)
|
|
@@ -290,8 +290,8 @@ export class GitIssuesTool {
|
|
|
290
290
|
return results;
|
|
291
291
|
}
|
|
292
292
|
case 'comment': {
|
|
293
|
-
const issue_number = params.issue_number;
|
|
294
|
-
const comment_body = params.comment_body;
|
|
293
|
+
const issue_number = params.issue_number || params.issueNumber;
|
|
294
|
+
const comment_body = params.comment_body || params.body;
|
|
295
295
|
if (!issue_number)
|
|
296
296
|
throw new MCPError('VALIDATION_ERROR', 'issue_number is required');
|
|
297
297
|
if (!comment_body)
|