@andrebuzeli/git-mcp 5.0.5 → 5.0.6
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 +21 -0
- package/README.md +143 -89
- package/dist/config.d.ts +72 -71
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +226 -139
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +15 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +133 -128
- package/dist/index.js.map +1 -1
- package/dist/providers/base-provider.d.ts +42 -153
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/base-provider.js +42 -302
- package/dist/providers/base-provider.js.map +1 -1
- package/dist/providers/gitea-provider.d.ts +67 -118
- package/dist/providers/gitea-provider.d.ts.map +1 -1
- package/dist/providers/gitea-provider.js +487 -1161
- package/dist/providers/gitea-provider.js.map +1 -1
- package/dist/providers/github-provider.d.ts +70 -81
- package/dist/providers/github-provider.d.ts.map +1 -1
- package/dist/providers/github-provider.js +641 -278
- package/dist/providers/github-provider.js.map +1 -1
- package/dist/providers/index.d.ts +9 -9
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +13 -19
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/provider-factory.d.ts +29 -59
- package/dist/providers/provider-factory.d.ts.map +1 -1
- package/dist/providers/provider-factory.js +134 -265
- package/dist/providers/provider-factory.js.map +1 -1
- package/dist/providers/provider-operation-handler.d.ts +93 -0
- package/dist/providers/provider-operation-handler.d.ts.map +1 -0
- package/dist/providers/provider-operation-handler.js +280 -0
- package/dist/providers/provider-operation-handler.js.map +1 -0
- package/dist/providers/types.d.ts +201 -355
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +3 -2
- package/dist/providers/types.js.map +1 -1
- package/dist/server.d.ts +34 -8
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +436 -494
- package/dist/server.js.map +1 -1
- package/dist/tools/git-analytics.d.ts +239 -16
- package/dist/tools/git-analytics.d.ts.map +1 -1
- package/dist/tools/git-analytics.js +737 -25
- package/dist/tools/git-analytics.js.map +1 -1
- package/dist/tools/git-archive.d.ts +109 -15
- package/dist/tools/git-archive.d.ts.map +1 -1
- package/dist/tools/git-archive.js +462 -10
- package/dist/tools/git-archive.js.map +1 -1
- package/dist/tools/git-backup.d.ts +101 -15
- package/dist/tools/git-backup.d.ts.map +1 -1
- package/dist/tools/git-backup.js +410 -10
- package/dist/tools/git-backup.js.map +1 -1
- package/dist/tools/git-branches.d.ts +141 -15
- package/dist/tools/git-branches.d.ts.map +1 -1
- package/dist/tools/git-branches.js +466 -11
- package/dist/tools/git-branches.js.map +1 -1
- package/dist/tools/git-config.d.ts +115 -15
- package/dist/tools/git-config.d.ts.map +1 -1
- package/dist/tools/git-config.js +446 -11
- package/dist/tools/git-config.js.map +1 -1
- package/dist/tools/git-files.d.ts +179 -59
- package/dist/tools/git-files.d.ts.map +1 -1
- package/dist/tools/git-files.js +682 -222
- package/dist/tools/git-files.js.map +1 -1
- package/dist/tools/git-issues.d.ts +158 -15
- package/dist/tools/git-issues.d.ts.map +1 -1
- package/dist/tools/git-issues.js +323 -11
- package/dist/tools/git-issues.js.map +1 -1
- package/dist/tools/git-monitor.d.ts +149 -14
- package/dist/tools/git-monitor.d.ts.map +1 -1
- package/dist/tools/git-monitor.js +528 -11
- package/dist/tools/git-monitor.js.map +1 -1
- package/dist/tools/git-packages.d.ts +163 -15
- package/dist/tools/git-packages.d.ts.map +1 -1
- package/dist/tools/git-packages.js +526 -11
- package/dist/tools/git-packages.js.map +1 -1
- package/dist/tools/git-pulls.d.ts +174 -15
- package/dist/tools/git-pulls.d.ts.map +1 -1
- package/dist/tools/git-pulls.js +352 -11
- package/dist/tools/git-pulls.js.map +1 -1
- package/dist/tools/git-release.d.ts +167 -15
- package/dist/tools/git-release.d.ts.map +1 -1
- package/dist/tools/git-release.js +465 -11
- package/dist/tools/git-release.js.map +1 -1
- package/dist/tools/git-remote.d.ts +124 -15
- package/dist/tools/git-remote.d.ts.map +1 -1
- package/dist/tools/git-remote.js +539 -11
- package/dist/tools/git-remote.js.map +1 -1
- package/dist/tools/git-reset.d.ts +100 -15
- package/dist/tools/git-reset.d.ts.map +1 -1
- package/dist/tools/git-reset.js +409 -11
- package/dist/tools/git-reset.js.map +1 -1
- package/dist/tools/git-stash.d.ts +120 -15
- package/dist/tools/git-stash.d.ts.map +1 -1
- package/dist/tools/git-stash.js +503 -11
- package/dist/tools/git-stash.js.map +1 -1
- package/dist/tools/git-sync.d.ts +160 -16
- package/dist/tools/git-sync.d.ts.map +1 -1
- package/dist/tools/git-sync.js +462 -113
- package/dist/tools/git-sync.js.map +1 -1
- package/dist/tools/git-tags.d.ts +142 -15
- package/dist/tools/git-tags.d.ts.map +1 -1
- package/dist/tools/git-tags.js +471 -11
- package/dist/tools/git-tags.js.map +1 -1
- package/dist/tools/git-workflow.d.ts +151 -80
- package/dist/tools/git-workflow.d.ts.map +1 -1
- package/dist/tools/git-workflow.js +407 -912
- package/dist/tools/git-workflow.js.map +1 -1
- package/dist/utils/credential-manager.d.ts +119 -0
- package/dist/utils/credential-manager.d.ts.map +1 -0
- package/dist/utils/credential-manager.js +450 -0
- package/dist/utils/credential-manager.js.map +1 -0
- package/dist/utils/git-command-executor.d.ts +326 -0
- package/dist/utils/git-command-executor.d.ts.map +1 -0
- package/dist/utils/git-command-executor.js +877 -0
- package/dist/utils/git-command-executor.js.map +1 -0
- package/dist/utils/logger.d.ts +143 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +473 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/operation-error-handler.d.ts +54 -41
- package/dist/utils/operation-error-handler.d.ts.map +1 -1
- package/dist/utils/operation-error-handler.js +211 -227
- package/dist/utils/operation-error-handler.js.map +1 -1
- package/dist/utils/parameter-validator.d.ts +41 -0
- package/dist/utils/parameter-validator.d.ts.map +1 -0
- package/dist/utils/parameter-validator.js +464 -0
- package/dist/utils/parameter-validator.js.map +1 -0
- package/dist/utils/repository-detector.d.ts +128 -0
- package/dist/utils/repository-detector.d.ts.map +1 -0
- package/dist/utils/repository-detector.js +422 -0
- package/dist/utils/repository-detector.js.map +1 -0
- package/dist/utils/response-formatter.d.ts +146 -0
- package/dist/utils/response-formatter.d.ts.map +1 -0
- package/dist/utils/response-formatter.js +378 -0
- package/dist/utils/response-formatter.js.map +1 -0
- package/dist/utils/retry.d.ts +12 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +28 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/terminal-controller.d.ts +73 -139
- package/dist/utils/terminal-controller.d.ts.map +1 -1
- package/dist/utils/terminal-controller.js +234 -459
- package/dist/utils/terminal-controller.js.map +1 -1
- package/package.json +79 -60
- package/dist/providers/error-handler.d.ts +0 -51
- package/dist/providers/error-handler.d.ts.map +0 -1
- package/dist/providers/error-handler.js +0 -176
- package/dist/providers/error-handler.js.map +0 -1
- package/dist/providers/github-provider-backup.d.ts +0 -81
- package/dist/providers/github-provider-backup.d.ts.map +0 -1
- package/dist/providers/github-provider-backup.js +0 -1179
- package/dist/providers/github-provider-backup.js.map +0 -1
- package/dist/providers/github-provider-complete.d.ts +0 -1
- package/dist/providers/github-provider-complete.d.ts.map +0 -1
- package/dist/providers/github-provider-complete.js +0 -2
- package/dist/providers/github-provider-complete.js.map +0 -1
- package/dist/tools/git-init.d.ts +0 -50
- package/dist/tools/git-init.d.ts.map +0 -1
- package/dist/tools/git-init.js +0 -258
- package/dist/tools/git-init.js.map +0 -1
- package/dist/tools/git-log.d.ts +0 -67
- package/dist/tools/git-log.d.ts.map +0 -1
- package/dist/tools/git-log.js +0 -320
- package/dist/tools/git-log.js.map +0 -1
- package/dist/tools/git-status.d.ts +0 -29
- package/dist/tools/git-status.d.ts.map +0 -1
- package/dist/tools/git-status.js +0 -182
- package/dist/tools/git-status.js.map +0 -1
- package/dist/tools/git-update.d.ts +0 -34
- package/dist/tools/git-update.d.ts.map +0 -1
- package/dist/tools/git-update.js +0 -191
- package/dist/tools/git-update.js.map +0 -1
- package/dist/utils/auto-detection.d.ts +0 -120
- package/dist/utils/auto-detection.d.ts.map +0 -1
- package/dist/utils/auto-detection.js +0 -259
- package/dist/utils/auto-detection.js.map +0 -1
- package/dist/utils/configuration-error-generator.d.ts +0 -41
- package/dist/utils/configuration-error-generator.d.ts.map +0 -1
- package/dist/utils/configuration-error-generator.js +0 -168
- package/dist/utils/configuration-error-generator.js.map +0 -1
- package/dist/utils/configuration-validator.d.ts +0 -67
- package/dist/utils/configuration-validator.d.ts.map +0 -1
- package/dist/utils/configuration-validator.js +0 -257
- package/dist/utils/configuration-validator.js.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -107
- package/dist/utils/error-handler.d.ts.map +0 -1
- package/dist/utils/error-handler.js +0 -331
- package/dist/utils/error-handler.js.map +0 -1
- package/dist/utils/git-operations.d.ts +0 -200
- package/dist/utils/git-operations.d.ts.map +0 -1
- package/dist/utils/git-operations.js +0 -836
- package/dist/utils/git-operations.js.map +0 -1
- package/dist/utils/multi-provider-error-handler.d.ts +0 -75
- package/dist/utils/multi-provider-error-handler.d.ts.map +0 -1
- package/dist/utils/multi-provider-error-handler.js +0 -276
- package/dist/utils/multi-provider-error-handler.js.map +0 -1
- package/dist/utils/multi-provider-operation-handler.d.ts +0 -113
- package/dist/utils/multi-provider-operation-handler.d.ts.map +0 -1
- package/dist/utils/multi-provider-operation-handler.js +0 -303
- package/dist/utils/multi-provider-operation-handler.js.map +0 -1
- package/dist/utils/provider-operation-handler.d.ts +0 -80
- package/dist/utils/provider-operation-handler.d.ts.map +0 -1
- package/dist/utils/provider-operation-handler.js +0 -201
- package/dist/utils/provider-operation-handler.js.map +0 -1
- package/dist/utils/response-helper.d.ts +0 -57
- package/dist/utils/response-helper.d.ts.map +0 -1
- package/dist/utils/response-helper.js +0 -54
- package/dist/utils/response-helper.js.map +0 -1
- package/dist/utils/user-detection.d.ts +0 -25
- package/dist/utils/user-detection.d.ts.map +0 -1
- package/dist/utils/user-detection.js +0 -54
- package/dist/utils/user-detection.js.map +0 -1
package/dist/tools/git-files.js
CHANGED
|
@@ -1,237 +1,697 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.gitFilesTool = void 0;
|
|
4
|
-
const auto_detection_js_1 = require("../utils/auto-detection.js");
|
|
5
|
-
const configuration_validator_js_1 = require("../utils/configuration-validator.js");
|
|
6
|
-
const index_js_1 = require("../providers/index.js");
|
|
7
2
|
/**
|
|
8
|
-
* Git Files Tool
|
|
3
|
+
* Git Files Tool
|
|
4
|
+
*
|
|
5
|
+
* File management tool providing CRUD operations for repository files.
|
|
6
|
+
* Supports both local Git operations and remote provider operations.
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
* - read: Ler conteúdo de arquivo do repositório remoto
|
|
12
|
-
* - create: Criar novo arquivo no repositório remoto
|
|
13
|
-
* - update: Atualizar arquivo existente no repositório remoto
|
|
14
|
-
* - delete: Remover arquivo do repositório remoto
|
|
15
|
-
* - search: Buscar conteúdo em arquivos do repositório remoto
|
|
16
|
-
* - list: Listar arquivos do repositório remoto
|
|
8
|
+
* Operations: read, create, update, delete, search, backup
|
|
17
9
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
properties: {
|
|
21
|
-
action: {
|
|
22
|
-
type: 'string',
|
|
23
|
-
enum: ['read', 'create', 'list'],
|
|
24
|
-
description: 'Ação de arquivo a executar'
|
|
25
|
-
},
|
|
26
|
-
projectPath: {
|
|
27
|
-
type: 'string',
|
|
28
|
-
description: 'Caminho do projeto (obrigatório)'
|
|
29
|
-
},
|
|
30
|
-
provider: {
|
|
31
|
-
type: 'string',
|
|
32
|
-
enum: ['github', 'gitea', 'both'],
|
|
33
|
-
description: 'Provider para operações remotas (obrigatório)'
|
|
34
|
-
},
|
|
35
|
-
owner: {
|
|
36
|
-
type: 'string',
|
|
37
|
-
description: 'Proprietário do repositório (auto-detectado se não fornecido)'
|
|
38
|
-
},
|
|
39
|
-
repo: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
description: 'Nome do repositório (auto-detectado se não fornecido)'
|
|
42
|
-
},
|
|
43
|
-
filePath: {
|
|
44
|
-
type: 'string',
|
|
45
|
-
description: 'Caminho do arquivo no repositório'
|
|
46
|
-
},
|
|
47
|
-
content: {
|
|
48
|
-
type: 'string',
|
|
49
|
-
description: 'Conteúdo do arquivo (para create/update)'
|
|
50
|
-
},
|
|
51
|
-
message: {
|
|
52
|
-
type: 'string',
|
|
53
|
-
description: 'Mensagem de commit (para create/update/delete)'
|
|
54
|
-
},
|
|
55
|
-
branch: {
|
|
56
|
-
type: 'string',
|
|
57
|
-
description: 'Branch para operação (padrão: main)'
|
|
58
|
-
},
|
|
59
|
-
sha: {
|
|
60
|
-
type: 'string',
|
|
61
|
-
description: 'SHA do arquivo (obrigatório para update/delete)'
|
|
62
|
-
},
|
|
63
|
-
searchTerm: {
|
|
64
|
-
type: 'string',
|
|
65
|
-
description: 'Termo de busca (para search)'
|
|
66
|
-
},
|
|
67
|
-
path: {
|
|
68
|
-
type: 'string',
|
|
69
|
-
description: 'Caminho do diretório para listar (para list)'
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
required: ['action', 'projectPath', 'provider']
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
73
12
|
};
|
|
74
|
-
exports
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.GitFilesTool = void 0;
|
|
15
|
+
const git_command_executor_js_1 = require("../utils/git-command-executor.js");
|
|
16
|
+
const parameter_validator_js_1 = require("../utils/parameter-validator.js");
|
|
17
|
+
const operation_error_handler_js_1 = require("../utils/operation-error-handler.js");
|
|
18
|
+
const provider_operation_handler_js_1 = require("../providers/provider-operation-handler.js");
|
|
19
|
+
const terminal_controller_js_1 = require("../utils/terminal-controller.js");
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
22
|
+
class GitFilesTool {
|
|
23
|
+
gitExecutor;
|
|
24
|
+
terminalController;
|
|
25
|
+
providerHandler;
|
|
26
|
+
constructor(providerConfig) {
|
|
27
|
+
this.gitExecutor = new git_command_executor_js_1.GitCommandExecutor();
|
|
28
|
+
this.terminalController = new terminal_controller_js_1.TerminalController();
|
|
29
|
+
if (providerConfig) {
|
|
30
|
+
this.providerHandler = new provider_operation_handler_js_1.ProviderOperationHandler(providerConfig);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Execute git-files operation
|
|
35
|
+
*/
|
|
36
|
+
async execute(params) {
|
|
37
|
+
const startTime = Date.now();
|
|
79
38
|
try {
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
throw new Error('Provider é obrigatório. Use: github, gitea, ou both');
|
|
85
|
-
}
|
|
86
|
-
// Validar provider
|
|
87
|
-
const providerValidation = configuration_validator_js_1.ConfigurationValidator.validateProvider(provider);
|
|
88
|
-
if (!providerValidation.valid) {
|
|
89
|
-
return (0, auto_detection_js_1.createUniversalResponse)(false, action, providerValidation.error.message, detection, 'git-files', undefined, {
|
|
90
|
-
code: providerValidation.error.code,
|
|
91
|
-
message: providerValidation.error.message,
|
|
92
|
-
cause: 'Invalid provider parameter',
|
|
93
|
-
suggestion: providerValidation.error.suggestion
|
|
94
|
-
});
|
|
39
|
+
// Validate basic parameters
|
|
40
|
+
const validation = parameter_validator_js_1.ParameterValidator.validateToolParams('git-files', params);
|
|
41
|
+
if (!validation.isValid) {
|
|
42
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('VALIDATION_ERROR', `Parameter validation failed: ${validation.errors.join(', ')}`, params.action, { validationErrors: validation.errors }, validation.suggestions);
|
|
95
43
|
}
|
|
96
|
-
//
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
44
|
+
// Validate operation-specific parameters
|
|
45
|
+
const operationValidation = parameter_validator_js_1.ParameterValidator.validateOperationParams('git-files', params.action, params);
|
|
46
|
+
if (!operationValidation.isValid) {
|
|
47
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('VALIDATION_ERROR', `Operation validation failed: ${operationValidation.errors.join(', ')}`, params.action, { validationErrors: operationValidation.errors }, operationValidation.suggestions);
|
|
48
|
+
}
|
|
49
|
+
// Route to appropriate handler
|
|
50
|
+
// File operations are local by default, remote only when provider is explicitly specified
|
|
51
|
+
const isRemoteOperation = params.provider && this.isRemoteOperation(params.action);
|
|
52
|
+
if (isRemoteOperation) {
|
|
53
|
+
return await this.executeRemoteOperation(params, startTime);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return await this.executeLocalOperation(params, startTime);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
61
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('EXECUTION_ERROR', `Failed to execute ${params.action}: ${errorMessage}`, params.action, { error: errorMessage }, ['Check the error details and try again']);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Execute local file operations
|
|
66
|
+
*/
|
|
67
|
+
async executeLocalOperation(params, startTime) {
|
|
68
|
+
switch (params.action) {
|
|
69
|
+
case 'list':
|
|
70
|
+
return await this.handleLocalList(params, startTime);
|
|
71
|
+
case 'read':
|
|
72
|
+
return await this.handleLocalRead(params, startTime);
|
|
73
|
+
case 'create':
|
|
74
|
+
return await this.handleLocalCreate(params, startTime);
|
|
75
|
+
case 'update':
|
|
76
|
+
return await this.handleLocalUpdate(params, startTime);
|
|
77
|
+
case 'delete':
|
|
78
|
+
return await this.handleLocalDelete(params, startTime);
|
|
79
|
+
case 'search':
|
|
80
|
+
return await this.handleLocalSearch(params, startTime);
|
|
81
|
+
case 'backup':
|
|
82
|
+
return await this.handleLocalBackup(params, startTime);
|
|
83
|
+
default:
|
|
84
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('UNSUPPORTED_OPERATION', `Local operation '${params.action}' is not supported`, params.action, {}, ['Use one of: read, create, update, delete, search, backup']);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Execute remote provider operations
|
|
89
|
+
*/
|
|
90
|
+
async executeRemoteOperation(params, startTime) {
|
|
91
|
+
if (!this.providerHandler) {
|
|
92
|
+
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']);
|
|
93
|
+
}
|
|
94
|
+
if (!params.provider) {
|
|
95
|
+
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']);
|
|
96
|
+
}
|
|
97
|
+
const operation = {
|
|
98
|
+
provider: params.provider,
|
|
99
|
+
operation: this.mapActionToProviderOperation(params.action),
|
|
100
|
+
parameters: this.extractRemoteParameters(params),
|
|
101
|
+
requiresAuth: true,
|
|
102
|
+
isRemoteOperation: true
|
|
103
|
+
};
|
|
104
|
+
try {
|
|
105
|
+
const result = await this.providerHandler.executeOperation(operation);
|
|
106
|
+
return {
|
|
107
|
+
success: result.success,
|
|
108
|
+
data: result.partialFailure ? result : result.results[0]?.data,
|
|
109
|
+
error: result.success ? undefined : {
|
|
110
|
+
code: result.errors[0]?.error?.code || 'REMOTE_OPERATION_ERROR',
|
|
111
|
+
message: result.errors[0]?.error?.message || 'Remote operation failed',
|
|
112
|
+
details: result.errors,
|
|
113
|
+
suggestions: ['Check provider configuration and credentials']
|
|
114
|
+
},
|
|
115
|
+
metadata: {
|
|
116
|
+
provider: params.provider,
|
|
117
|
+
operation: params.action,
|
|
118
|
+
timestamp: new Date().toISOString(),
|
|
119
|
+
executionTime: Date.now() - startTime
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
125
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('REMOTE_OPERATION_ERROR', `Remote operation failed: ${errorMessage}`, params.action, { error: errorMessage }, ['Check provider configuration and network connectivity']);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Handle local file read operation
|
|
130
|
+
*/
|
|
131
|
+
async handleLocalRead(params, startTime) {
|
|
132
|
+
try {
|
|
133
|
+
if (!params.filePath) {
|
|
134
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'File path is required for read operation', 'read', {}, ['Provide a filePath parameter with the relative path to the file']);
|
|
135
|
+
}
|
|
136
|
+
const fullPath = path_1.default.join(params.projectPath, params.filePath);
|
|
137
|
+
// Check if file exists
|
|
138
|
+
try {
|
|
139
|
+
await promises_1.default.access(fullPath);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('FILE_NOT_FOUND', `File not found: ${params.filePath}`, 'read', { filePath: params.filePath, fullPath }, ['Check that the file path is correct and the file exists']);
|
|
143
|
+
}
|
|
144
|
+
// Read file content
|
|
145
|
+
const encoding = params.encoding || 'utf8';
|
|
146
|
+
let content;
|
|
147
|
+
if (encoding === 'binary') {
|
|
148
|
+
content = await promises_1.default.readFile(fullPath);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
content = await promises_1.default.readFile(fullPath, encoding);
|
|
152
|
+
}
|
|
153
|
+
// Get file stats
|
|
154
|
+
const stats = await promises_1.default.stat(fullPath);
|
|
155
|
+
return {
|
|
156
|
+
success: true,
|
|
157
|
+
data: {
|
|
158
|
+
filePath: params.filePath,
|
|
159
|
+
content: encoding === 'binary' ? content.toString('base64') : content,
|
|
160
|
+
encoding,
|
|
161
|
+
size: stats.size,
|
|
162
|
+
modified: stats.mtime.toISOString(),
|
|
163
|
+
created: stats.birthtime.toISOString(),
|
|
164
|
+
isDirectory: stats.isDirectory(),
|
|
165
|
+
permissions: stats.mode.toString(8)
|
|
166
|
+
},
|
|
167
|
+
metadata: {
|
|
168
|
+
operation: 'read',
|
|
169
|
+
timestamp: new Date().toISOString(),
|
|
170
|
+
executionTime: Date.now() - startTime
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
176
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('READ_ERROR', `Failed to read file: ${errorMessage}`, 'read', { error: errorMessage, filePath: params.filePath });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Handle local file create operation
|
|
181
|
+
*/
|
|
182
|
+
async handleLocalCreate(params, startTime) {
|
|
183
|
+
try {
|
|
184
|
+
if (!params.filePath) {
|
|
185
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'File path is required for create operation', 'create', {}, ['Provide a filePath parameter with the relative path for the new file']);
|
|
186
|
+
}
|
|
187
|
+
if (params.content === undefined) {
|
|
188
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'Content is required for create operation', 'create', {}, ['Provide content parameter with the file content']);
|
|
189
|
+
}
|
|
190
|
+
const fullPath = path_1.default.join(params.projectPath, params.filePath);
|
|
191
|
+
// Check if file already exists
|
|
192
|
+
try {
|
|
193
|
+
await promises_1.default.access(fullPath);
|
|
194
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('FILE_EXISTS', `File already exists: ${params.filePath}`, 'create', { filePath: params.filePath }, ['Use update operation to modify existing files, or choose a different file path']);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// File doesn't exist, which is what we want for create
|
|
198
|
+
}
|
|
199
|
+
// Ensure directory exists
|
|
200
|
+
const dirPath = path_1.default.dirname(fullPath);
|
|
201
|
+
await promises_1.default.mkdir(dirPath, { recursive: true });
|
|
202
|
+
// Write file content
|
|
203
|
+
const encoding = params.encoding || 'utf8';
|
|
204
|
+
let contentToWrite = params.content;
|
|
205
|
+
if (encoding === 'base64') {
|
|
206
|
+
contentToWrite = Buffer.from(params.content, 'base64');
|
|
207
|
+
}
|
|
208
|
+
else if (encoding === 'binary') {
|
|
209
|
+
contentToWrite = Buffer.from(params.content, 'binary');
|
|
210
|
+
}
|
|
211
|
+
await promises_1.default.writeFile(fullPath, contentToWrite, encoding === 'utf8' ? 'utf8' : undefined);
|
|
212
|
+
// Get file stats
|
|
213
|
+
const stats = await promises_1.default.stat(fullPath);
|
|
214
|
+
return {
|
|
215
|
+
success: true,
|
|
216
|
+
data: {
|
|
217
|
+
message: 'File created successfully',
|
|
218
|
+
filePath: params.filePath,
|
|
219
|
+
size: stats.size,
|
|
220
|
+
created: stats.birthtime.toISOString(),
|
|
221
|
+
encoding
|
|
222
|
+
},
|
|
223
|
+
metadata: {
|
|
224
|
+
operation: 'create',
|
|
225
|
+
timestamp: new Date().toISOString(),
|
|
226
|
+
executionTime: Date.now() - startTime
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
232
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('CREATE_ERROR', `Failed to create file: ${errorMessage}`, 'create', { error: errorMessage, filePath: params.filePath });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Handle local file update operation
|
|
237
|
+
*/
|
|
238
|
+
async handleLocalUpdate(params, startTime) {
|
|
239
|
+
try {
|
|
240
|
+
if (!params.filePath) {
|
|
241
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'File path is required for update operation', 'update', {}, ['Provide a filePath parameter with the relative path to the file']);
|
|
242
|
+
}
|
|
243
|
+
if (params.content === undefined) {
|
|
244
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'Content is required for update operation', 'update', {}, ['Provide content parameter with the new file content']);
|
|
245
|
+
}
|
|
246
|
+
const fullPath = path_1.default.join(params.projectPath, params.filePath);
|
|
247
|
+
// Check if file exists
|
|
248
|
+
try {
|
|
249
|
+
await promises_1.default.access(fullPath);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('FILE_NOT_FOUND', `File not found: ${params.filePath}`, 'update', { filePath: params.filePath }, ['Use create operation for new files, or check that the file path is correct']);
|
|
253
|
+
}
|
|
254
|
+
// Get original file stats for comparison
|
|
255
|
+
const originalStats = await promises_1.default.stat(fullPath);
|
|
256
|
+
// Write updated content
|
|
257
|
+
const encoding = params.encoding || 'utf8';
|
|
258
|
+
let contentToWrite = params.content;
|
|
259
|
+
if (encoding === 'base64') {
|
|
260
|
+
contentToWrite = Buffer.from(params.content, 'base64');
|
|
261
|
+
}
|
|
262
|
+
else if (encoding === 'binary') {
|
|
263
|
+
contentToWrite = Buffer.from(params.content, 'binary');
|
|
264
|
+
}
|
|
265
|
+
await promises_1.default.writeFile(fullPath, contentToWrite, encoding === 'utf8' ? 'utf8' : undefined);
|
|
266
|
+
// Get updated file stats
|
|
267
|
+
const updatedStats = await promises_1.default.stat(fullPath);
|
|
268
|
+
return {
|
|
269
|
+
success: true,
|
|
270
|
+
data: {
|
|
271
|
+
message: 'File updated successfully',
|
|
272
|
+
filePath: params.filePath,
|
|
273
|
+
originalSize: originalStats.size,
|
|
274
|
+
newSize: updatedStats.size,
|
|
275
|
+
modified: updatedStats.mtime.toISOString(),
|
|
276
|
+
encoding
|
|
277
|
+
},
|
|
278
|
+
metadata: {
|
|
279
|
+
operation: 'update',
|
|
280
|
+
timestamp: new Date().toISOString(),
|
|
281
|
+
executionTime: Date.now() - startTime
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
287
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('UPDATE_ERROR', `Failed to update file: ${errorMessage}`, 'update', { error: errorMessage, filePath: params.filePath });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Handle local file delete operation
|
|
292
|
+
*/
|
|
293
|
+
async handleLocalDelete(params, startTime) {
|
|
294
|
+
try {
|
|
295
|
+
if (!params.filePath) {
|
|
296
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'File path is required for delete operation', 'delete', {}, ['Provide a filePath parameter with the relative path to the file']);
|
|
297
|
+
}
|
|
298
|
+
const fullPath = path_1.default.join(params.projectPath, params.filePath);
|
|
299
|
+
// Check if file exists and get stats
|
|
300
|
+
let stats;
|
|
301
|
+
try {
|
|
302
|
+
stats = await promises_1.default.stat(fullPath);
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('FILE_NOT_FOUND', `File not found: ${params.filePath}`, 'delete', { filePath: params.filePath }, ['Check that the file path is correct and the file exists']);
|
|
306
|
+
}
|
|
307
|
+
// Delete the file
|
|
308
|
+
await promises_1.default.unlink(fullPath);
|
|
309
|
+
return {
|
|
310
|
+
success: true,
|
|
311
|
+
data: {
|
|
312
|
+
message: 'File deleted successfully',
|
|
313
|
+
filePath: params.filePath,
|
|
314
|
+
deletedSize: stats.size,
|
|
315
|
+
wasDirectory: stats.isDirectory()
|
|
316
|
+
},
|
|
317
|
+
metadata: {
|
|
318
|
+
operation: 'delete',
|
|
319
|
+
timestamp: new Date().toISOString(),
|
|
320
|
+
executionTime: Date.now() - startTime
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
326
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('DELETE_ERROR', `Failed to delete file: ${errorMessage}`, 'delete', { error: errorMessage, filePath: params.filePath });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Handle local file search operation
|
|
331
|
+
*/
|
|
332
|
+
async handleLocalSearch(params, startTime) {
|
|
333
|
+
try {
|
|
334
|
+
if (!params.query) {
|
|
335
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('MISSING_PARAMETER', 'Query is required for search operation', 'search', {}, ['Provide a query parameter with the text to search for']);
|
|
336
|
+
}
|
|
337
|
+
const searchOptions = {
|
|
338
|
+
caseSensitive: params.caseSensitive || false,
|
|
339
|
+
filePattern: params.filePattern || '*',
|
|
340
|
+
maxResults: 100
|
|
341
|
+
};
|
|
342
|
+
// Use terminal controller to search for content
|
|
343
|
+
const searchResult = await this.terminalController.searchInFiles(params.projectPath, params.query, searchOptions);
|
|
344
|
+
if (!searchResult.success) {
|
|
345
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('SEARCH_ERROR', `Search failed: ${searchResult.stderr}`, 'search', { error: searchResult.stderr }, ['Check the search query and try again']);
|
|
346
|
+
}
|
|
347
|
+
// Parse search results
|
|
348
|
+
const matches = this.parseSearchResults(searchResult.stdout);
|
|
349
|
+
return {
|
|
350
|
+
success: true,
|
|
351
|
+
data: {
|
|
352
|
+
query: params.query,
|
|
353
|
+
matches,
|
|
354
|
+
totalMatches: matches.length,
|
|
355
|
+
searchOptions
|
|
356
|
+
},
|
|
357
|
+
metadata: {
|
|
358
|
+
operation: 'search',
|
|
359
|
+
timestamp: new Date().toISOString(),
|
|
360
|
+
executionTime: Date.now() - startTime
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
366
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('SEARCH_ERROR', `Failed to search files: ${errorMessage}`, 'search', { error: errorMessage, query: params.query });
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Handle local directory listing
|
|
371
|
+
*/
|
|
372
|
+
async handleLocalList(params, startTime) {
|
|
373
|
+
try {
|
|
374
|
+
const listPath = params.filePath ? path_1.default.join(params.projectPath, params.filePath) : params.projectPath;
|
|
375
|
+
// Verify path exists
|
|
376
|
+
try {
|
|
377
|
+
await promises_1.default.access(listPath);
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('PATH_NOT_FOUND', `Path not found: ${listPath}`, 'list', { path: listPath }, ['Provide a valid projectPath/filePath']);
|
|
381
|
+
}
|
|
382
|
+
const entries = await promises_1.default.readdir(listPath, { withFileTypes: true });
|
|
383
|
+
const items = await Promise.all(entries.map(async (entry) => {
|
|
384
|
+
const entryPath = path_1.default.join(listPath, entry.name);
|
|
385
|
+
const stats = await promises_1.default.stat(entryPath);
|
|
386
|
+
return {
|
|
387
|
+
name: entry.name,
|
|
388
|
+
path: path_1.default.relative(params.projectPath, entryPath).replace(/\\/g, '/'),
|
|
389
|
+
isDirectory: entry.isDirectory(),
|
|
390
|
+
size: stats.size,
|
|
391
|
+
modified: stats.mtime.toISOString()
|
|
392
|
+
};
|
|
393
|
+
}));
|
|
394
|
+
return {
|
|
395
|
+
success: true,
|
|
396
|
+
data: {
|
|
397
|
+
items,
|
|
398
|
+
total: items.length
|
|
399
|
+
},
|
|
400
|
+
metadata: {
|
|
401
|
+
operation: 'list',
|
|
402
|
+
timestamp: new Date().toISOString(),
|
|
403
|
+
executionTime: Date.now() - startTime
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
409
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('LIST_ERROR', `Failed to list path: ${errorMessage}`, 'list', { error: errorMessage });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Handle local file backup operation
|
|
414
|
+
*/
|
|
415
|
+
async handleLocalBackup(params, startTime) {
|
|
416
|
+
try {
|
|
417
|
+
if (!params.backupPath) {
|
|
418
|
+
// Generate default backup path
|
|
419
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
420
|
+
params.backupPath = path_1.default.join(params.projectPath, '..', `files-backup-${timestamp}`);
|
|
421
|
+
}
|
|
422
|
+
// Create backup using git archive if in a git repository
|
|
423
|
+
const isGitRepo = await this.gitExecutor.isGitRepository(params.projectPath);
|
|
424
|
+
if (isGitRepo) {
|
|
425
|
+
const result = await this.gitExecutor.createBackup(params.projectPath, params.backupPath, 'tar');
|
|
426
|
+
if (!result.success) {
|
|
427
|
+
return operation_error_handler_js_1.OperationErrorHandler.handleGitError(result.stderr, 'backup', params.projectPath);
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
success: true,
|
|
431
|
+
data: {
|
|
432
|
+
message: 'Files backup created successfully using Git archive',
|
|
433
|
+
backupPath: `${params.backupPath}.tar.gz`,
|
|
434
|
+
method: 'git-archive',
|
|
435
|
+
output: result.stdout
|
|
436
|
+
},
|
|
437
|
+
metadata: {
|
|
438
|
+
operation: 'backup',
|
|
439
|
+
timestamp: new Date().toISOString(),
|
|
440
|
+
executionTime: Date.now() - startTime
|
|
193
441
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
// Fallback to manual file copy
|
|
446
|
+
const backupResult = await this.createManualBackup(params.projectPath, params.backupPath, {
|
|
447
|
+
includePattern: params.includePattern,
|
|
448
|
+
excludePattern: params.excludePattern
|
|
449
|
+
});
|
|
450
|
+
return {
|
|
451
|
+
success: true,
|
|
452
|
+
data: {
|
|
453
|
+
message: 'Files backup created successfully using file copy',
|
|
454
|
+
backupPath: params.backupPath,
|
|
455
|
+
method: 'file-copy',
|
|
456
|
+
filesBackedUp: backupResult.fileCount,
|
|
457
|
+
totalSize: backupResult.totalSize
|
|
458
|
+
},
|
|
459
|
+
metadata: {
|
|
460
|
+
operation: 'backup',
|
|
461
|
+
timestamp: new Date().toISOString(),
|
|
462
|
+
executionTime: Date.now() - startTime
|
|
208
463
|
}
|
|
209
|
-
|
|
210
|
-
return (0, auto_detection_js_1.createUniversalResponse)(true, action, `${files.length} arquivos encontrados em ${listPath || 'raiz'}`, detection, 'git-files', {
|
|
211
|
-
path: listPath,
|
|
212
|
-
files: files.map((file) => ({
|
|
213
|
-
name: file.name,
|
|
214
|
-
path: file.path,
|
|
215
|
-
type: file.type,
|
|
216
|
-
size: file.size,
|
|
217
|
-
sha: file.sha
|
|
218
|
-
})),
|
|
219
|
-
totalFiles: files.length,
|
|
220
|
-
provider
|
|
221
|
-
});
|
|
222
|
-
default:
|
|
223
|
-
throw new Error(`Ação '${action}' não suportada. Ações disponíveis: read, create, list`);
|
|
464
|
+
};
|
|
224
465
|
}
|
|
225
466
|
}
|
|
226
467
|
catch (error) {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
return (0, auto_detection_js_1.createUniversalResponse)(false, input.action || 'unknown', `Erro na operação de arquivo: ${errorInstance.message}`, detection, 'git-files', undefined, {
|
|
230
|
-
code: 'FILE_OPERATION_ERROR',
|
|
231
|
-
message: errorInstance.message,
|
|
232
|
-
cause: 'File operation failed'
|
|
233
|
-
});
|
|
468
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
469
|
+
return operation_error_handler_js_1.OperationErrorHandler.createToolError('BACKUP_ERROR', `Failed to create backup: ${errorMessage}`, 'backup', { error: errorMessage, backupPath: params.backupPath });
|
|
234
470
|
}
|
|
235
471
|
}
|
|
236
|
-
|
|
472
|
+
/**
|
|
473
|
+
* Create manual backup by copying files
|
|
474
|
+
*/
|
|
475
|
+
async createManualBackup(sourcePath, backupPath, options) {
|
|
476
|
+
await promises_1.default.mkdir(backupPath, { recursive: true });
|
|
477
|
+
let fileCount = 0;
|
|
478
|
+
let totalSize = 0;
|
|
479
|
+
const copyRecursive = async (src, dest) => {
|
|
480
|
+
const stats = await promises_1.default.stat(src);
|
|
481
|
+
if (stats.isDirectory()) {
|
|
482
|
+
await promises_1.default.mkdir(dest, { recursive: true });
|
|
483
|
+
const entries = await promises_1.default.readdir(src);
|
|
484
|
+
for (const entry of entries) {
|
|
485
|
+
const srcPath = path_1.default.join(src, entry);
|
|
486
|
+
const destPath = path_1.default.join(dest, entry);
|
|
487
|
+
await copyRecursive(srcPath, destPath);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
// Apply include/exclude patterns
|
|
492
|
+
const relativePath = path_1.default.relative(sourcePath, src);
|
|
493
|
+
if (options.excludePattern && this.matchesPattern(relativePath, options.excludePattern)) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (options.includePattern && !this.matchesPattern(relativePath, options.includePattern)) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
await promises_1.default.copyFile(src, dest);
|
|
500
|
+
fileCount++;
|
|
501
|
+
totalSize += stats.size;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
await copyRecursive(sourcePath, backupPath);
|
|
505
|
+
return { fileCount, totalSize };
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Check if operation is a remote operation
|
|
509
|
+
*/
|
|
510
|
+
isRemoteOperation(action) {
|
|
511
|
+
// All file operations can be remote operations when provider is specified
|
|
512
|
+
return ['read', 'create', 'update', 'delete', 'search'].includes(action);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Extract parameters for remote operations
|
|
516
|
+
*/
|
|
517
|
+
extractRemoteParameters(params) {
|
|
518
|
+
const remoteParams = {
|
|
519
|
+
projectPath: params.projectPath
|
|
520
|
+
};
|
|
521
|
+
// Common parameters
|
|
522
|
+
if (params.owner)
|
|
523
|
+
remoteParams.owner = params.owner;
|
|
524
|
+
if (params.repo)
|
|
525
|
+
remoteParams.repo = params.repo;
|
|
526
|
+
if (params.filePath)
|
|
527
|
+
remoteParams.path = params.filePath;
|
|
528
|
+
// Operation-specific parameters
|
|
529
|
+
switch (params.action) {
|
|
530
|
+
case 'read':
|
|
531
|
+
if (params.branch)
|
|
532
|
+
remoteParams.ref = params.branch;
|
|
533
|
+
break;
|
|
534
|
+
case 'create':
|
|
535
|
+
case 'update':
|
|
536
|
+
if (params.content) {
|
|
537
|
+
// Encode content as base64 for API
|
|
538
|
+
remoteParams.content = Buffer.from(params.content).toString('base64');
|
|
539
|
+
}
|
|
540
|
+
if (params.message)
|
|
541
|
+
remoteParams.message = params.message;
|
|
542
|
+
if (params.branch)
|
|
543
|
+
remoteParams.branch = params.branch;
|
|
544
|
+
if (params.sha)
|
|
545
|
+
remoteParams.sha = params.sha;
|
|
546
|
+
break;
|
|
547
|
+
case 'delete':
|
|
548
|
+
if (params.message)
|
|
549
|
+
remoteParams.message = params.message;
|
|
550
|
+
if (params.sha)
|
|
551
|
+
remoteParams.sha = params.sha;
|
|
552
|
+
if (params.branch)
|
|
553
|
+
remoteParams.branch = params.branch;
|
|
554
|
+
break;
|
|
555
|
+
case 'search':
|
|
556
|
+
if (params.query)
|
|
557
|
+
remoteParams.query = params.query;
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
return remoteParams;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Map git-files actions to provider operations
|
|
564
|
+
*/
|
|
565
|
+
mapActionToProviderOperation(action) {
|
|
566
|
+
const actionMap = {
|
|
567
|
+
'read': 'file-read',
|
|
568
|
+
'list': 'listFiles',
|
|
569
|
+
'create': 'file-create',
|
|
570
|
+
'update': 'file-update',
|
|
571
|
+
'delete': 'file-delete',
|
|
572
|
+
'search': 'file-search'
|
|
573
|
+
};
|
|
574
|
+
return actionMap[action] || action;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Parse search results from grep-like output
|
|
578
|
+
*/
|
|
579
|
+
parseSearchResults(output) {
|
|
580
|
+
const matches = [];
|
|
581
|
+
const lines = output.split('\n').filter(line => line.trim());
|
|
582
|
+
for (const line of lines) {
|
|
583
|
+
// Parse grep output format: file:line:content
|
|
584
|
+
const match = line.match(/^([^:]+):(\d+):(.*)$/);
|
|
585
|
+
if (match) {
|
|
586
|
+
const [, file, lineNum, content] = match;
|
|
587
|
+
matches.push({
|
|
588
|
+
file,
|
|
589
|
+
line: parseInt(lineNum),
|
|
590
|
+
content: content.trim(),
|
|
591
|
+
match: content.trim()
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return matches;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Check if path matches pattern (simple glob matching)
|
|
599
|
+
*/
|
|
600
|
+
matchesPattern(filePath, pattern) {
|
|
601
|
+
// Convert glob pattern to regex
|
|
602
|
+
const regexPattern = pattern
|
|
603
|
+
.replace(/\./g, '\\.')
|
|
604
|
+
.replace(/\*/g, '.*')
|
|
605
|
+
.replace(/\?/g, '.');
|
|
606
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
607
|
+
return regex.test(filePath);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Get tool schema for MCP registration
|
|
611
|
+
*/
|
|
612
|
+
static getToolSchema() {
|
|
613
|
+
return {
|
|
614
|
+
name: 'git-files',
|
|
615
|
+
description: 'File management tool for repository files. Supports CRUD operations, search, and backup for both local and remote repositories.',
|
|
616
|
+
inputSchema: {
|
|
617
|
+
type: 'object',
|
|
618
|
+
properties: {
|
|
619
|
+
action: {
|
|
620
|
+
type: 'string',
|
|
621
|
+
enum: ['read', 'create', 'update', 'delete', 'search', 'backup', 'list'],
|
|
622
|
+
description: 'The file operation to perform'
|
|
623
|
+
},
|
|
624
|
+
projectPath: {
|
|
625
|
+
type: 'string',
|
|
626
|
+
description: 'Absolute path to the project directory'
|
|
627
|
+
},
|
|
628
|
+
provider: {
|
|
629
|
+
type: 'string',
|
|
630
|
+
enum: ['github', 'gitea', 'both'],
|
|
631
|
+
description: 'Provider for remote operations (optional for local operations)'
|
|
632
|
+
},
|
|
633
|
+
filePath: {
|
|
634
|
+
type: 'string',
|
|
635
|
+
description: 'Relative path to the file within the repository (required for read, create, update, delete)'
|
|
636
|
+
},
|
|
637
|
+
content: {
|
|
638
|
+
type: 'string',
|
|
639
|
+
description: 'File content (required for create and update operations)'
|
|
640
|
+
},
|
|
641
|
+
encoding: {
|
|
642
|
+
type: 'string',
|
|
643
|
+
enum: ['utf8', 'base64', 'binary'],
|
|
644
|
+
description: 'Content encoding (default: utf8)'
|
|
645
|
+
},
|
|
646
|
+
message: {
|
|
647
|
+
type: 'string',
|
|
648
|
+
description: 'Commit message for remote operations'
|
|
649
|
+
},
|
|
650
|
+
branch: {
|
|
651
|
+
type: 'string',
|
|
652
|
+
description: 'Target branch for remote operations'
|
|
653
|
+
},
|
|
654
|
+
sha: {
|
|
655
|
+
type: 'string',
|
|
656
|
+
description: 'File SHA for remote update/delete operations'
|
|
657
|
+
},
|
|
658
|
+
query: {
|
|
659
|
+
type: 'string',
|
|
660
|
+
description: 'Search query (required for search operation)'
|
|
661
|
+
},
|
|
662
|
+
filePattern: {
|
|
663
|
+
type: 'string',
|
|
664
|
+
description: 'File pattern for search (e.g., "*.js")'
|
|
665
|
+
},
|
|
666
|
+
caseSensitive: {
|
|
667
|
+
type: 'boolean',
|
|
668
|
+
description: 'Case sensitive search (default: false)'
|
|
669
|
+
},
|
|
670
|
+
backupPath: {
|
|
671
|
+
type: 'string',
|
|
672
|
+
description: 'Path for backup (for backup operation)'
|
|
673
|
+
},
|
|
674
|
+
includePattern: {
|
|
675
|
+
type: 'string',
|
|
676
|
+
description: 'Pattern for files to include in backup'
|
|
677
|
+
},
|
|
678
|
+
excludePattern: {
|
|
679
|
+
type: 'string',
|
|
680
|
+
description: 'Pattern for files to exclude from backup'
|
|
681
|
+
},
|
|
682
|
+
owner: {
|
|
683
|
+
type: 'string',
|
|
684
|
+
description: 'Repository owner (for remote operations)'
|
|
685
|
+
},
|
|
686
|
+
repo: {
|
|
687
|
+
type: 'string',
|
|
688
|
+
description: 'Repository name (for remote operations)'
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
required: ['action', 'projectPath']
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
exports.GitFilesTool = GitFilesTool;
|
|
237
697
|
//# sourceMappingURL=git-files.js.map
|