@andrebuzeli/git-mcp 5.4.4 → 5.4.5
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/providers/provider-operation-handler.d.ts.map +1 -1
- package/dist/providers/provider-operation-handler.js +4 -7
- package/dist/providers/provider-operation-handler.js.map +1 -1
- package/dist/providers/types.d.ts +0 -18
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/tools/git-analytics.d.ts +24 -29
- package/dist/tools/git-analytics.d.ts.map +1 -1
- package/dist/tools/git-analytics.js +26 -31
- package/dist/tools/git-analytics.js.map +1 -1
- package/dist/tools/git-branches.d.ts +1 -113
- package/dist/tools/git-branches.d.ts.map +1 -1
- package/dist/tools/git-branches.js +56 -51
- package/dist/tools/git-branches.js.map +1 -1
- package/dist/tools/git-files.d.ts +5 -10
- package/dist/tools/git-files.d.ts.map +1 -1
- package/dist/tools/git-files.js +7 -12
- package/dist/tools/git-files.js.map +1 -1
- package/dist/tools/git-issues.d.ts +73 -78
- package/dist/tools/git-issues.d.ts.map +1 -1
- package/dist/tools/git-issues.js +76 -81
- package/dist/tools/git-issues.js.map +1 -1
- package/dist/tools/git-packages.d.ts +13 -18
- package/dist/tools/git-packages.d.ts.map +1 -1
- package/dist/tools/git-packages.js +15 -20
- package/dist/tools/git-packages.js.map +1 -1
- package/dist/tools/git-pulls.d.ts +89 -94
- package/dist/tools/git-pulls.d.ts.map +1 -1
- package/dist/tools/git-pulls.js +92 -97
- package/dist/tools/git-pulls.js.map +1 -1
- package/dist/tools/git-release.d.ts +17 -22
- package/dist/tools/git-release.d.ts.map +1 -1
- package/dist/tools/git-release.js +19 -24
- package/dist/tools/git-release.js.map +1 -1
- package/dist/tools/git-sync.d.ts +5 -14
- package/dist/tools/git-sync.d.ts.map +1 -1
- package/dist/tools/git-sync.js +23 -27
- package/dist/tools/git-sync.js.map +1 -1
- package/dist/tools/git-tags.d.ts +9 -14
- package/dist/tools/git-tags.d.ts.map +1 -1
- package/dist/tools/git-tags.js +11 -16
- package/dist/tools/git-tags.js.map +1 -1
- package/dist/tools/git-workflow.d.ts +53 -85
- package/dist/tools/git-workflow.d.ts.map +1 -1
- package/dist/tools/git-workflow.js +231 -357
- package/dist/tools/git-workflow.js.map +1 -1
- package/dist/utils/parameter-validator.js +8 -8
- package/dist/utils/parameter-validator.js.map +1 -1
- package/dist/utils/repository-sync.d.ts +5 -3
- package/dist/utils/repository-sync.d.ts.map +1 -1
- package/dist/utils/repository-sync.js +37 -15
- package/dist/utils/repository-sync.js.map +1 -1
- package/package.json +2 -2
|
@@ -2,23 +2,18 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Git Workflow Tool
|
|
4
4
|
*
|
|
5
|
-
* Core Git workflow tool
|
|
6
|
-
* Supports
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Remote operations: create, list, get, update, delete, fork, search
|
|
5
|
+
* Core Git workflow tool for local and remote Git operations.
|
|
6
|
+
* Supports init, status, commit, sync, backup, create, list, get, update, delete, fork, and search operations.
|
|
7
|
+
* Provides comprehensive Git repository management with both local and remote provider support (GitHub/Gitea).
|
|
8
|
+
* In universal mode (GIT_MCP_MODE=universal), automatically executes on both GitHub and Gitea providers.
|
|
10
9
|
*/
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
11
|
exports.GitWorkflowTool = void 0;
|
|
16
|
-
const git_command_executor_js_1 = require("../utils/git-command-executor.js");
|
|
17
12
|
const parameter_validator_js_1 = require("../utils/parameter-validator.js");
|
|
18
13
|
const operation_error_handler_js_1 = require("../utils/operation-error-handler.js");
|
|
19
14
|
const provider_operation_handler_js_1 = require("../providers/provider-operation-handler.js");
|
|
20
15
|
const config_js_1 = require("../config.js");
|
|
21
|
-
const
|
|
16
|
+
const git_command_executor_js_1 = require("../utils/git-command-executor.js");
|
|
22
17
|
class GitWorkflowTool {
|
|
23
18
|
gitExecutor;
|
|
24
19
|
providerHandler;
|
|
@@ -59,32 +54,18 @@ class GitWorkflowTool {
|
|
|
59
54
|
}
|
|
60
55
|
}
|
|
61
56
|
/**
|
|
62
|
-
*
|
|
57
|
+
* Check if operation is remote
|
|
63
58
|
*/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
case 'status':
|
|
69
|
-
return await this.handleStatus(params, startTime);
|
|
70
|
-
case 'commit':
|
|
71
|
-
return await this.handleCommit(params, startTime);
|
|
72
|
-
case 'sync':
|
|
73
|
-
return await this.handleSync(params, startTime);
|
|
74
|
-
case 'backup':
|
|
75
|
-
return await this.handleBackup(params, startTime);
|
|
76
|
-
case 'push':
|
|
77
|
-
return await this.handlePush(params, startTime);
|
|
78
|
-
case 'pull':
|
|
79
|
-
return await this.handlePull(params, startTime);
|
|
80
|
-
default:
|
|
81
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('UNSUPPORTED_OPERATION', `Local operation '${params.action}' is not supported`, params.action, {}, ['Use one of: init, status, commit, sync, backup, push, pull']);
|
|
82
|
-
}
|
|
59
|
+
isRemoteOperation(action) {
|
|
60
|
+
// Remote operations require provider
|
|
61
|
+
const remoteOperations = ['create', 'list', 'get', 'update', 'delete', 'fork', 'search'];
|
|
62
|
+
return remoteOperations.includes(action);
|
|
83
63
|
}
|
|
84
64
|
/**
|
|
85
|
-
* Execute remote
|
|
65
|
+
* Execute remote repository operations
|
|
86
66
|
*/
|
|
87
67
|
async executeRemoteOperation(params, startTime) {
|
|
68
|
+
// Check provider configuration
|
|
88
69
|
if (!this.providerHandler) {
|
|
89
70
|
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PROVIDER_NOT_CONFIGURED', 'Provider handler is not configured for remote operations', params.action, {}, ['Configure GitHub or Gitea provider to use remote operations']);
|
|
90
71
|
}
|
|
@@ -97,10 +78,45 @@ class GitWorkflowTool {
|
|
|
97
78
|
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PROVIDER_REQUIRED', 'Provider parameter is required for remote operations', params.action, {}, ['Specify provider as: github, gitea, or both']);
|
|
98
79
|
}
|
|
99
80
|
}
|
|
81
|
+
return await this.executeRepositoryOperation(params, startTime);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Execute local Git operations
|
|
85
|
+
*/
|
|
86
|
+
async executeLocalOperation(params, startTime) {
|
|
87
|
+
try {
|
|
88
|
+
switch (params.action) {
|
|
89
|
+
case 'init':
|
|
90
|
+
return await this.executeInit(params, startTime);
|
|
91
|
+
case 'status':
|
|
92
|
+
return await this.executeStatus(params, startTime);
|
|
93
|
+
case 'commit':
|
|
94
|
+
return await this.executeCommit(params, startTime);
|
|
95
|
+
case 'sync':
|
|
96
|
+
return await this.executeSync(params, startTime);
|
|
97
|
+
case 'backup':
|
|
98
|
+
return await this.executeBackup(params, startTime);
|
|
99
|
+
case 'push':
|
|
100
|
+
return await this.executePush(params, startTime);
|
|
101
|
+
case 'pull':
|
|
102
|
+
return await this.executePull(params, startTime);
|
|
103
|
+
default:
|
|
104
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('UNSUPPORTED_OPERATION', `Local operation '${params.action}' is not supported`, params.action, {}, ['Use supported local operations: init, status, commit, sync, backup, push, pull']);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
109
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('LOCAL_OPERATION_ERROR', `Local operation failed: ${errorMessage}`, params.action, { error: errorMessage }, ['Check Git installation and repository state']);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Execute repository operation through provider
|
|
114
|
+
*/
|
|
115
|
+
async executeRepositoryOperation(params, startTime) {
|
|
100
116
|
const operation = {
|
|
101
117
|
provider: params.provider,
|
|
102
118
|
operation: this.mapActionToProviderOperation(params.action),
|
|
103
|
-
parameters: this.
|
|
119
|
+
parameters: this.extractRepositoryParameters(params),
|
|
104
120
|
requiresAuth: true,
|
|
105
121
|
isRemoteOperation: true
|
|
106
122
|
};
|
|
@@ -110,10 +126,10 @@ class GitWorkflowTool {
|
|
|
110
126
|
success: result.success,
|
|
111
127
|
data: result.partialFailure ? result : result.results[0]?.data,
|
|
112
128
|
error: result.success ? undefined : {
|
|
113
|
-
code: result.errors[0]?.error?.code || '
|
|
114
|
-
message: result.errors[0]?.error?.message || '
|
|
129
|
+
code: result.errors[0]?.error?.code || 'REPO_OPERATION_ERROR',
|
|
130
|
+
message: result.errors[0]?.error?.message || 'Repository operation failed',
|
|
115
131
|
details: result.errors,
|
|
116
|
-
suggestions:
|
|
132
|
+
suggestions: this.getOperationSuggestions(params.action)
|
|
117
133
|
},
|
|
118
134
|
metadata: {
|
|
119
135
|
provider: params.provider,
|
|
@@ -125,43 +141,19 @@ class GitWorkflowTool {
|
|
|
125
141
|
}
|
|
126
142
|
catch (error) {
|
|
127
143
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
128
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('
|
|
144
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('REPO_OPERATION_ERROR', `Repository operation failed: ${errorMessage}`, params.action, { error: errorMessage }, ['Check provider configuration and network connectivity']);
|
|
129
145
|
}
|
|
130
146
|
}
|
|
131
147
|
/**
|
|
132
|
-
*
|
|
148
|
+
* Execute Git init
|
|
133
149
|
*/
|
|
134
|
-
async
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (isRepo) {
|
|
139
|
-
return {
|
|
140
|
-
success: true,
|
|
141
|
-
data: {
|
|
142
|
-
message: 'Repository already initialized',
|
|
143
|
-
path: params.projectPath,
|
|
144
|
-
alreadyExists: true
|
|
145
|
-
},
|
|
146
|
-
metadata: {
|
|
147
|
-
operation: 'init',
|
|
148
|
-
timestamp: new Date().toISOString(),
|
|
149
|
-
executionTime: Date.now() - startTime
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
const result = await this.gitExecutor.initRepository(params.projectPath, params.bare || false);
|
|
154
|
-
if (!result.success) {
|
|
155
|
-
return operation_error_handler_js_1.OperationErrorHandler.handleGitError(result.stderr, 'init', params.projectPath);
|
|
156
|
-
}
|
|
150
|
+
async executeInit(params, startTime) {
|
|
151
|
+
const initCommand = params.bare ? ['init', '--bare'] : ['init'];
|
|
152
|
+
const result = await this.gitExecutor.executeGitCommand('init', initCommand, params.projectPath);
|
|
153
|
+
if (result.success) {
|
|
157
154
|
return {
|
|
158
155
|
success: true,
|
|
159
|
-
data: {
|
|
160
|
-
message: 'Git repository initialized successfully',
|
|
161
|
-
path: params.projectPath,
|
|
162
|
-
bare: params.bare || false,
|
|
163
|
-
output: result.stdout
|
|
164
|
-
},
|
|
156
|
+
data: { message: 'Git repository initialized successfully' },
|
|
165
157
|
metadata: {
|
|
166
158
|
operation: 'init',
|
|
167
159
|
timestamp: new Date().toISOString(),
|
|
@@ -169,29 +161,23 @@ class GitWorkflowTool {
|
|
|
169
161
|
}
|
|
170
162
|
};
|
|
171
163
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('INIT_ERROR', `Failed to initialize repository: ${errorMessage}`, 'init', { error: errorMessage, projectPath: params.projectPath });
|
|
164
|
+
else {
|
|
165
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('INIT_FAILED', `Git init failed: ${result.stderr}`, 'init', { stderr: result.stderr }, ['Check if directory exists and is writable', 'Verify Git installation']);
|
|
175
166
|
}
|
|
176
167
|
}
|
|
177
168
|
/**
|
|
178
|
-
*
|
|
169
|
+
* Execute Git status
|
|
179
170
|
*/
|
|
180
|
-
async
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return operation_error_handler_js_1.OperationErrorHandler.handleGitError(result.stderr, 'status', params.projectPath);
|
|
185
|
-
}
|
|
171
|
+
async executeStatus(params, startTime) {
|
|
172
|
+
const result = await this.gitExecutor.executeGitCommand('status', ['--porcelain'], params.projectPath);
|
|
173
|
+
if (result.success) {
|
|
174
|
+
const hasChanges = result.stdout.trim().length > 0;
|
|
186
175
|
return {
|
|
187
176
|
success: true,
|
|
188
177
|
data: {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
path: params.projectPath,
|
|
193
|
-
isGitRepository: result.isGitRepository
|
|
194
|
-
}
|
|
178
|
+
hasChanges,
|
|
179
|
+
changes: hasChanges ? result.stdout.trim().split('\n') : [],
|
|
180
|
+
message: hasChanges ? 'Working directory has uncommitted changes' : 'Working directory is clean'
|
|
195
181
|
},
|
|
196
182
|
metadata: {
|
|
197
183
|
operation: 'status',
|
|
@@ -200,39 +186,37 @@ class GitWorkflowTool {
|
|
|
200
186
|
}
|
|
201
187
|
};
|
|
202
188
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('STATUS_ERROR', `Failed to get repository status: ${errorMessage}`, 'status', { error: errorMessage, projectPath: params.projectPath });
|
|
189
|
+
else {
|
|
190
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('STATUS_FAILED', `Git status failed: ${result.stderr}`, 'status', { stderr: result.stderr }, ['Ensure this is a Git repository', 'Check Git installation']);
|
|
206
191
|
}
|
|
207
192
|
}
|
|
208
193
|
/**
|
|
209
|
-
*
|
|
194
|
+
* Execute Git commit
|
|
210
195
|
*/
|
|
211
|
-
async
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const addResult = await this.gitExecutor.
|
|
196
|
+
async executeCommit(params, startTime) {
|
|
197
|
+
if (!params.message) {
|
|
198
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('COMMIT_MESSAGE_REQUIRED', 'Commit message is required', 'commit', {}, ['Provide a commit message with the message parameter']);
|
|
199
|
+
}
|
|
200
|
+
const commitArgs = ['-m', params.message];
|
|
201
|
+
if (params.files && params.files.length > 0) {
|
|
202
|
+
// Add specific files first
|
|
203
|
+
const addResult = await this.gitExecutor.executeGitCommand('add', params.files, params.projectPath);
|
|
219
204
|
if (!addResult.success) {
|
|
220
|
-
return operation_error_handler_js_1.OperationErrorHandler.
|
|
205
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('ADD_FAILED', `Failed to add files: ${addResult.stderr}`, 'commit', { stderr: addResult.stderr }, ['Check if files exist', 'Verify file paths are correct']);
|
|
221
206
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Add all changes
|
|
210
|
+
const addResult = await this.gitExecutor.executeGitCommand('add', ['.'], params.projectPath);
|
|
211
|
+
if (!addResult.success) {
|
|
212
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('ADD_FAILED', `Failed to add files: ${addResult.stderr}`, 'commit', { stderr: addResult.stderr }, ['Check working directory status']);
|
|
226
213
|
}
|
|
214
|
+
}
|
|
215
|
+
const result = await this.gitExecutor.executeGitCommand('commit', commitArgs, params.projectPath);
|
|
216
|
+
if (result.success) {
|
|
227
217
|
return {
|
|
228
218
|
success: true,
|
|
229
|
-
data: {
|
|
230
|
-
message: 'Changes committed successfully',
|
|
231
|
-
commitMessage: params.message,
|
|
232
|
-
files: filesToAdd,
|
|
233
|
-
output: commitResult.stdout,
|
|
234
|
-
addOutput: addResult.stdout
|
|
235
|
-
},
|
|
219
|
+
data: { message: 'Changes committed successfully' },
|
|
236
220
|
metadata: {
|
|
237
221
|
operation: 'commit',
|
|
238
222
|
timestamp: new Date().toISOString(),
|
|
@@ -240,51 +224,29 @@ class GitWorkflowTool {
|
|
|
240
224
|
}
|
|
241
225
|
};
|
|
242
226
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('COMMIT_ERROR', `Failed to commit changes: ${errorMessage}`, 'commit', { error: errorMessage, projectPath: params.projectPath });
|
|
227
|
+
else {
|
|
228
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('COMMIT_FAILED', `Git commit failed: ${result.stderr}`, 'commit', { stderr: result.stderr }, ['Check if there are changes to commit', 'Ensure commit message is provided']);
|
|
246
229
|
}
|
|
247
230
|
}
|
|
248
231
|
/**
|
|
249
|
-
*
|
|
232
|
+
* Execute Git sync (pull + push)
|
|
250
233
|
*/
|
|
251
|
-
async
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
pushResult = await this.gitExecutor.push(params.projectPath, remote, params.branch, { force: params.force });
|
|
265
|
-
results.push({ operation: 'push', success: pushResult.success, output: pushResult.stdout, error: pushResult.stderr });
|
|
266
|
-
}
|
|
267
|
-
const allSuccessful = results.every(r => r.success);
|
|
268
|
-
const hasErrors = results.some(r => !r.success);
|
|
234
|
+
async executeSync(params, startTime) {
|
|
235
|
+
const remote = params.remote || 'origin';
|
|
236
|
+
const branch = params.branch || await this.getCurrentBranch(params.projectPath) || 'main';
|
|
237
|
+
// Pull first
|
|
238
|
+
const pullResult = await this.gitExecutor.executeGitCommand('pull', [remote, branch], params.projectPath);
|
|
239
|
+
if (!pullResult.success) {
|
|
240
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PULL_FAILED', `Git pull failed: ${pullResult.stderr}`, 'sync', { stderr: pullResult.stderr }, ['Check remote configuration', 'Resolve merge conflicts if any']);
|
|
241
|
+
}
|
|
242
|
+
// Push
|
|
243
|
+
const pushArgs = params.force ? ['--force'] : [];
|
|
244
|
+
pushArgs.push(remote, branch);
|
|
245
|
+
const pushResult = await this.gitExecutor.executeGitCommand('push', pushArgs, params.projectPath);
|
|
246
|
+
if (pushResult.success) {
|
|
269
247
|
return {
|
|
270
|
-
success:
|
|
271
|
-
data: {
|
|
272
|
-
message: allSuccessful ? 'Repository synchronized successfully' : 'Synchronization completed with some errors',
|
|
273
|
-
remote,
|
|
274
|
-
branch: params.branch,
|
|
275
|
-
operations: results,
|
|
276
|
-
summary: {
|
|
277
|
-
fetch: fetchResult.success,
|
|
278
|
-
pull: pullResult.success,
|
|
279
|
-
push: pushResult?.success || false
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
error: hasErrors ? {
|
|
283
|
-
code: 'SYNC_PARTIAL_ERROR',
|
|
284
|
-
message: 'Some synchronization operations failed',
|
|
285
|
-
details: results.filter(r => !r.success),
|
|
286
|
-
suggestions: ['Check the individual operation errors and resolve them']
|
|
287
|
-
} : undefined,
|
|
248
|
+
success: true,
|
|
249
|
+
data: { message: 'Repository synchronized successfully' },
|
|
288
250
|
metadata: {
|
|
289
251
|
operation: 'sync',
|
|
290
252
|
timestamp: new Date().toISOString(),
|
|
@@ -292,140 +254,65 @@ class GitWorkflowTool {
|
|
|
292
254
|
}
|
|
293
255
|
};
|
|
294
256
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('SYNC_ERROR', `Failed to synchronize repository: ${errorMessage}`, 'sync', { error: errorMessage, projectPath: params.projectPath });
|
|
257
|
+
else {
|
|
258
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PUSH_FAILED', `Git push failed: ${pushResult.stderr}`, 'sync', { stderr: pushResult.stderr }, ['Check remote configuration', 'Verify you have push permissions']);
|
|
298
259
|
}
|
|
299
260
|
}
|
|
300
261
|
/**
|
|
301
|
-
*
|
|
262
|
+
* Execute Git push
|
|
302
263
|
*/
|
|
303
|
-
async
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
const pushArgs = [remote, branch];
|
|
311
|
-
if (params.force) {
|
|
312
|
-
pushArgs.push('--force');
|
|
313
|
-
}
|
|
314
|
-
const result = await this.gitExecutor.executeGitCommand('push', pushArgs, params.projectPath);
|
|
315
|
-
if (!result.success) {
|
|
316
|
-
// Check for common push errors
|
|
317
|
-
if (result.stderr.includes('Push cannot contain secrets')) {
|
|
318
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('SECURITY_VIOLATION', 'Push blocked due to detected secrets in commit history', params.action, {
|
|
319
|
-
gitError: result.stderr,
|
|
320
|
-
suggestion: 'Remove sensitive data from commit history using git reset or git filter-branch'
|
|
321
|
-
}, [
|
|
322
|
-
'Use git reset to remove commits with secrets',
|
|
323
|
-
'Use git filter-branch to clean history',
|
|
324
|
-
'Never commit tokens, passwords, or API keys'
|
|
325
|
-
]);
|
|
326
|
-
}
|
|
327
|
-
if (result.stderr.includes('rejected')) {
|
|
328
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PUSH_REJECTED', `Push rejected: ${result.stderr}`, params.action, { gitError: result.stderr }, [
|
|
329
|
-
'Pull latest changes first with git pull',
|
|
330
|
-
'Resolve any conflicts before pushing',
|
|
331
|
-
'Check if you have push permissions'
|
|
332
|
-
]);
|
|
333
|
-
}
|
|
334
|
-
return operation_error_handler_js_1.OperationErrorHandler.handleGitError(result.stderr, 'push', params.projectPath);
|
|
335
|
-
}
|
|
264
|
+
async executePush(params, startTime) {
|
|
265
|
+
const remote = params.pushRemote || 'origin';
|
|
266
|
+
const branch = params.pushBranch || await this.getCurrentBranch(params.projectPath) || 'main';
|
|
267
|
+
const pushArgs = [remote, branch];
|
|
268
|
+
const result = await this.gitExecutor.executeGitCommand('push', pushArgs, params.projectPath);
|
|
269
|
+
if (result.success) {
|
|
336
270
|
return {
|
|
337
271
|
success: true,
|
|
338
|
-
data: {
|
|
339
|
-
message: `Successfully pushed to ${remote}/${branch}`,
|
|
340
|
-
remote,
|
|
341
|
-
branch,
|
|
342
|
-
output: result.stdout
|
|
343
|
-
},
|
|
272
|
+
data: { message: 'Changes pushed successfully' },
|
|
344
273
|
metadata: {
|
|
345
274
|
operation: 'push',
|
|
346
|
-
|
|
347
|
-
|
|
275
|
+
timestamp: new Date().toISOString(),
|
|
276
|
+
executionTime: Date.now() - startTime
|
|
348
277
|
}
|
|
349
278
|
};
|
|
350
279
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PUSH_ERROR', `Push operation failed: ${errorMessage}`, params.action, { error: errorMessage }, ['Check network connectivity and repository permissions']);
|
|
280
|
+
else {
|
|
281
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PUSH_FAILED', `Git push failed: ${result.stderr}`, 'push', { stderr: result.stderr }, ['Check remote configuration', 'Verify you have push permissions']);
|
|
354
282
|
}
|
|
355
283
|
}
|
|
356
284
|
/**
|
|
357
|
-
*
|
|
285
|
+
* Execute Git pull
|
|
358
286
|
*/
|
|
359
|
-
async
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('NO_BRANCH', 'No branch found to pull from', params.action, {}, ['Ensure you are on a valid branch or specify pullBranch parameter']);
|
|
365
|
-
}
|
|
366
|
-
const pullArgs = [remote, branch];
|
|
367
|
-
if (params.strategy && params.strategy !== 'merge') {
|
|
368
|
-
pullArgs.push(`--${params.strategy}`);
|
|
369
|
-
}
|
|
370
|
-
const result = await this.gitExecutor.executeGitCommand('pull', pullArgs, params.projectPath);
|
|
371
|
-
if (!result.success) {
|
|
372
|
-
if (result.stderr.includes('merge conflict')) {
|
|
373
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MERGE_CONFLICT', 'Pull failed due to merge conflicts', params.action, {
|
|
374
|
-
gitError: result.stderr,
|
|
375
|
-
conflicts: this.extractConflictFiles(result.stderr)
|
|
376
|
-
}, [
|
|
377
|
-
'Resolve conflicts in the listed files',
|
|
378
|
-
'Use git add to stage resolved files',
|
|
379
|
-
'Complete merge with git commit'
|
|
380
|
-
]);
|
|
381
|
-
}
|
|
382
|
-
return operation_error_handler_js_1.OperationErrorHandler.handleGitError(result.stderr, 'pull', params.projectPath);
|
|
383
|
-
}
|
|
287
|
+
async executePull(params, startTime) {
|
|
288
|
+
const remote = params.pullRemote || 'origin';
|
|
289
|
+
const branch = params.pullBranch || await this.getCurrentBranch(params.projectPath) || 'main';
|
|
290
|
+
const result = await this.gitExecutor.executeGitCommand('pull', [remote, branch], params.projectPath);
|
|
291
|
+
if (result.success) {
|
|
384
292
|
return {
|
|
385
293
|
success: true,
|
|
386
|
-
data: {
|
|
387
|
-
message: `Successfully pulled from ${remote}/${branch}`,
|
|
388
|
-
remote,
|
|
389
|
-
branch,
|
|
390
|
-
strategy: params.strategy || 'merge',
|
|
391
|
-
output: result.stdout
|
|
392
|
-
},
|
|
294
|
+
data: { message: 'Changes pulled successfully' },
|
|
393
295
|
metadata: {
|
|
394
296
|
operation: 'pull',
|
|
395
|
-
|
|
396
|
-
|
|
297
|
+
timestamp: new Date().toISOString(),
|
|
298
|
+
executionTime: Date.now() - startTime
|
|
397
299
|
}
|
|
398
300
|
};
|
|
399
301
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PULL_ERROR', `Pull operation failed: ${errorMessage}`, params.action, { error: errorMessage }, ['Check network connectivity and repository access']);
|
|
302
|
+
else {
|
|
303
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PULL_FAILED', `Git pull failed: ${result.stderr}`, 'pull', { stderr: result.stderr }, ['Check remote configuration', 'Resolve merge conflicts if any']);
|
|
403
304
|
}
|
|
404
305
|
}
|
|
405
306
|
/**
|
|
406
|
-
*
|
|
307
|
+
* Execute backup
|
|
407
308
|
*/
|
|
408
|
-
async
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const projectName = path_1.default.basename(params.projectPath);
|
|
413
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
414
|
-
params.backupPath = path_1.default.join(params.projectPath, '..', `${projectName}-backup-${timestamp}`);
|
|
415
|
-
}
|
|
416
|
-
const result = await this.gitExecutor.createBackup(params.projectPath, params.backupPath, 'tar');
|
|
417
|
-
if (!result.success) {
|
|
418
|
-
return operation_error_handler_js_1.OperationErrorHandler.handleGitError(result.stderr, 'backup', params.projectPath);
|
|
419
|
-
}
|
|
309
|
+
async executeBackup(params, startTime) {
|
|
310
|
+
const backupPath = params.backupPath || `backup-${Date.now()}.tar.gz`;
|
|
311
|
+
const result = await this.gitExecutor.executeGitCommand('archive', ['--format=tar', '--output', backupPath, 'HEAD'], params.projectPath);
|
|
312
|
+
if (result.success) {
|
|
420
313
|
return {
|
|
421
314
|
success: true,
|
|
422
|
-
data: {
|
|
423
|
-
message: 'Repository backup created successfully',
|
|
424
|
-
backupPath: `${params.backupPath}.tar.gz`,
|
|
425
|
-
originalPath: params.projectPath,
|
|
426
|
-
format: 'tar.gz',
|
|
427
|
-
output: result.stdout
|
|
428
|
-
},
|
|
315
|
+
data: { backupPath, message: 'Repository backed up successfully' },
|
|
429
316
|
metadata: {
|
|
430
317
|
operation: 'backup',
|
|
431
318
|
timestamp: new Date().toISOString(),
|
|
@@ -433,66 +320,47 @@ class GitWorkflowTool {
|
|
|
433
320
|
}
|
|
434
321
|
};
|
|
435
322
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
return operation_error_handler_js_1.OperationErrorHandler.createToolError('BACKUP_ERROR', `Failed to create repository backup: ${errorMessage}`, 'backup', { error: errorMessage, projectPath: params.projectPath });
|
|
323
|
+
else {
|
|
324
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('BACKUP_FAILED', `Backup failed: ${result.stderr}`, 'backup', { stderr: result.stderr }, ['Check write permissions', 'Verify Git repository integrity']);
|
|
439
325
|
}
|
|
440
326
|
}
|
|
441
327
|
/**
|
|
442
|
-
*
|
|
443
|
-
*/
|
|
444
|
-
isRemoteOperation(action) {
|
|
445
|
-
const remoteOperations = ['create', 'list', 'get', 'update', 'delete', 'fork', 'search'];
|
|
446
|
-
return remoteOperations.includes(action);
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Extract parameters for remote operations
|
|
328
|
+
* Extract parameters for repository operations
|
|
450
329
|
*/
|
|
451
|
-
|
|
452
|
-
const
|
|
330
|
+
extractRepositoryParameters(params) {
|
|
331
|
+
const repoParams = {
|
|
453
332
|
projectPath: params.projectPath
|
|
454
333
|
};
|
|
455
|
-
//
|
|
456
|
-
if (params.owner)
|
|
457
|
-
remoteParams.owner = params.owner;
|
|
334
|
+
// Auto-detect repo if not provided
|
|
458
335
|
if (params.repo)
|
|
459
|
-
|
|
336
|
+
repoParams.repo = params.repo;
|
|
460
337
|
// Operation-specific parameters
|
|
461
338
|
switch (params.action) {
|
|
462
339
|
case 'create':
|
|
463
340
|
if (params.name)
|
|
464
|
-
|
|
341
|
+
repoParams.name = params.name;
|
|
465
342
|
if (params.description)
|
|
466
|
-
|
|
343
|
+
repoParams.description = params.description;
|
|
467
344
|
if (params.private !== undefined)
|
|
468
|
-
|
|
345
|
+
repoParams.private = params.private;
|
|
469
346
|
break;
|
|
470
347
|
case 'list':
|
|
471
|
-
//
|
|
348
|
+
// No additional parameters needed
|
|
472
349
|
break;
|
|
473
350
|
case 'get':
|
|
474
|
-
// Get operations need owner and repo (already handled above)
|
|
475
|
-
break;
|
|
476
351
|
case 'update':
|
|
477
|
-
if (params.name)
|
|
478
|
-
remoteParams.name = params.name;
|
|
479
|
-
if (params.description)
|
|
480
|
-
remoteParams.description = params.description;
|
|
481
|
-
if (params.private !== undefined)
|
|
482
|
-
remoteParams.private = params.private;
|
|
483
|
-
break;
|
|
484
352
|
case 'delete':
|
|
485
|
-
// Delete operations need owner and repo (already handled above)
|
|
486
|
-
break;
|
|
487
353
|
case 'fork':
|
|
488
|
-
//
|
|
354
|
+
// repo parameter already handled above
|
|
355
|
+
if (params.description)
|
|
356
|
+
repoParams.description = params.description;
|
|
489
357
|
break;
|
|
490
358
|
case 'search':
|
|
491
359
|
if (params.query)
|
|
492
|
-
|
|
360
|
+
repoParams.query = params.query;
|
|
493
361
|
break;
|
|
494
362
|
}
|
|
495
|
-
return
|
|
363
|
+
return repoParams;
|
|
496
364
|
}
|
|
497
365
|
/**
|
|
498
366
|
* Map git-workflow actions to provider operations
|
|
@@ -509,6 +377,63 @@ class GitWorkflowTool {
|
|
|
509
377
|
};
|
|
510
378
|
return actionMap[action] || action;
|
|
511
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Get current branch name
|
|
382
|
+
*/
|
|
383
|
+
async getCurrentBranch(projectPath) {
|
|
384
|
+
try {
|
|
385
|
+
const result = await this.gitExecutor.executeGitCommand('branch', ['--show-current'], projectPath);
|
|
386
|
+
if (result.success && result.stdout.trim()) {
|
|
387
|
+
return result.stdout.trim();
|
|
388
|
+
}
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get operation-specific suggestions
|
|
397
|
+
*/
|
|
398
|
+
getOperationSuggestions(action) {
|
|
399
|
+
const suggestions = {
|
|
400
|
+
'create': [
|
|
401
|
+
'Provide a unique repository name',
|
|
402
|
+
'Check provider permissions for repository creation',
|
|
403
|
+
'Verify repository name format'
|
|
404
|
+
],
|
|
405
|
+
'list': [
|
|
406
|
+
'Check provider access permissions',
|
|
407
|
+
'Verify provider configuration'
|
|
408
|
+
],
|
|
409
|
+
'get': [
|
|
410
|
+
'Verify repository exists',
|
|
411
|
+
'Check repository access permissions',
|
|
412
|
+
'Ensure correct repository name'
|
|
413
|
+
],
|
|
414
|
+
'update': [
|
|
415
|
+
'Verify repository exists and you have admin access',
|
|
416
|
+
'Check what fields you can update',
|
|
417
|
+
'Ensure repository name uniqueness if changing name'
|
|
418
|
+
],
|
|
419
|
+
'delete': [
|
|
420
|
+
'Verify repository exists and you have delete permissions',
|
|
421
|
+
'Ensure you really want to delete the repository',
|
|
422
|
+
'Consider creating a backup first'
|
|
423
|
+
],
|
|
424
|
+
'fork': [
|
|
425
|
+
'Verify source repository exists and is accessible',
|
|
426
|
+
'Check fork permissions on the source repository',
|
|
427
|
+
'Ensure you don\'t already have a fork'
|
|
428
|
+
],
|
|
429
|
+
'search': [
|
|
430
|
+
'Provide a search query',
|
|
431
|
+
'Check search syntax for the provider',
|
|
432
|
+
'Try different search terms'
|
|
433
|
+
]
|
|
434
|
+
};
|
|
435
|
+
return suggestions[action] || ['Check provider configuration and try again'];
|
|
436
|
+
}
|
|
512
437
|
/**
|
|
513
438
|
* Get tool schema for MCP registration
|
|
514
439
|
*/
|
|
@@ -521,7 +446,7 @@ class GitWorkflowTool {
|
|
|
521
446
|
properties: {
|
|
522
447
|
action: {
|
|
523
448
|
type: 'string',
|
|
524
|
-
enum: ['init', 'status', 'commit', 'sync', 'backup', 'create', 'list', 'get', 'update', 'delete', 'fork', 'search'],
|
|
449
|
+
enum: ['init', 'status', 'commit', 'sync', 'backup', 'push', 'pull', 'create', 'list', 'get', 'update', 'delete', 'fork', 'search'],
|
|
525
450
|
description: 'The Git operation to perform. Local operations: init, status, commit, sync, backup. Remote operations: create, list, get, update, delete, fork, search (require provider parameter).'
|
|
526
451
|
},
|
|
527
452
|
projectPath: {
|
|
@@ -566,10 +491,6 @@ class GitWorkflowTool {
|
|
|
566
491
|
type: 'string',
|
|
567
492
|
description: 'Search query (for search action)'
|
|
568
493
|
},
|
|
569
|
-
owner: {
|
|
570
|
-
type: 'string',
|
|
571
|
-
description: 'Repository owner (for get/update/delete/fork actions)'
|
|
572
|
-
},
|
|
573
494
|
repo: {
|
|
574
495
|
type: 'string',
|
|
575
496
|
description: 'Repository name (for get/update/delete/fork actions)'
|
|
@@ -585,74 +506,27 @@ class GitWorkflowTool {
|
|
|
585
506
|
force: {
|
|
586
507
|
type: 'boolean',
|
|
587
508
|
description: 'Force operation (for sync action)'
|
|
509
|
+
},
|
|
510
|
+
pushRemote: {
|
|
511
|
+
type: 'string',
|
|
512
|
+
description: 'Remote name for push (default: origin)'
|
|
513
|
+
},
|
|
514
|
+
pushBranch: {
|
|
515
|
+
type: 'string',
|
|
516
|
+
description: 'Branch name for push (default: current branch)'
|
|
517
|
+
},
|
|
518
|
+
pullRemote: {
|
|
519
|
+
type: 'string',
|
|
520
|
+
description: 'Remote name for pull (default: origin)'
|
|
521
|
+
},
|
|
522
|
+
pullBranch: {
|
|
523
|
+
type: 'string',
|
|
524
|
+
description: 'Branch name for pull (default: current branch)'
|
|
588
525
|
}
|
|
589
526
|
},
|
|
590
|
-
required: ['action', 'projectPath']
|
|
591
|
-
additionalProperties: false
|
|
592
|
-
},
|
|
593
|
-
errorCodes: {
|
|
594
|
-
'VALIDATION_ERROR': 'Parameter validation failed - check required parameters and format',
|
|
595
|
-
'NOT_A_GIT_REPOSITORY': 'Directory is not a Git repository - use init action first',
|
|
596
|
-
'NOTHING_TO_COMMIT': 'No changes to commit - make changes first',
|
|
597
|
-
'MERGE_CONFLICT': 'Merge conflicts detected - resolve conflicts before proceeding',
|
|
598
|
-
'PERMISSION_DENIED': 'Permission denied - check credentials and access rights',
|
|
599
|
-
'PROVIDER_NOT_CONFIGURED': 'Provider not configured - set up GitHub or Gitea credentials',
|
|
600
|
-
'NETWORK_ERROR': 'Network connectivity issue - check internet connection',
|
|
601
|
-
'BACKUP_ERROR': 'Backup creation failed - check disk space and permissions'
|
|
602
|
-
},
|
|
603
|
-
examples: [
|
|
604
|
-
{
|
|
605
|
-
description: 'Initialize a new Git repository',
|
|
606
|
-
input: {
|
|
607
|
-
action: 'init',
|
|
608
|
-
projectPath: '/path/to/project'
|
|
609
|
-
}
|
|
610
|
-
},
|
|
611
|
-
{
|
|
612
|
-
description: 'Commit all changes with message',
|
|
613
|
-
input: {
|
|
614
|
-
action: 'commit',
|
|
615
|
-
projectPath: '/path/to/project',
|
|
616
|
-
message: 'Add new feature implementation'
|
|
617
|
-
}
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
description: 'Create repository on GitHub',
|
|
621
|
-
input: {
|
|
622
|
-
action: 'create',
|
|
623
|
-
projectPath: '/path/to/project',
|
|
624
|
-
provider: 'github',
|
|
625
|
-
name: 'my-new-repo',
|
|
626
|
-
description: 'My new repository',
|
|
627
|
-
private: true
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
]
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Extract conflict files from git error output
|
|
635
|
-
*/
|
|
636
|
-
extractConflictFiles(stderr) {
|
|
637
|
-
const conflictMatches = stderr.match(/both modified:\s+(.+)/g);
|
|
638
|
-
if (!conflictMatches)
|
|
639
|
-
return [];
|
|
640
|
-
return conflictMatches.map(match => match.replace('both modified:', '').trim());
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* Get current branch name
|
|
644
|
-
*/
|
|
645
|
-
async getCurrentBranch(projectPath) {
|
|
646
|
-
try {
|
|
647
|
-
const result = await this.gitExecutor.executeGitCommand('branch', ['--show-current'], projectPath);
|
|
648
|
-
if (result.success && result.stdout.trim()) {
|
|
649
|
-
return result.stdout.trim();
|
|
527
|
+
required: ['action', 'projectPath']
|
|
650
528
|
}
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
catch (error) {
|
|
654
|
-
return null;
|
|
655
|
-
}
|
|
529
|
+
};
|
|
656
530
|
}
|
|
657
531
|
}
|
|
658
532
|
exports.GitWorkflowTool = GitWorkflowTool;
|