@andrebuzeli/git-mcp 10.0.4 → 10.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.
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Sistema de validação e tratamento de erros aprimorado para Git-MCP
3
+ * Fornece validação robusta de parâmetros e mensagens de erro detalhadas
4
+ */
5
+ import { MCPError } from './errors.js';
6
+ import path from 'path';
7
+ /**
8
+ * Tipos de validação disponíveis
9
+ */
10
+ export var ValidationType;
11
+ (function (ValidationType) {
12
+ ValidationType["REQUIRED"] = "required";
13
+ ValidationType["STRING"] = "string";
14
+ ValidationType["NUMBER"] = "number";
15
+ ValidationType["BOOLEAN"] = "boolean";
16
+ ValidationType["ARRAY"] = "array";
17
+ ValidationType["OBJECT"] = "object";
18
+ ValidationType["PATH"] = "path";
19
+ ValidationType["URL"] = "url";
20
+ ValidationType["EMAIL"] = "email";
21
+ ValidationType["ENUM"] = "enum";
22
+ ValidationType["PATTERN"] = "pattern";
23
+ ValidationType["RANGE"] = "range";
24
+ ValidationType["LENGTH"] = "length";
25
+ })(ValidationType || (ValidationType = {}));
26
+ /**
27
+ * Validador robusto de parâmetros
28
+ */
29
+ export class ParameterValidator {
30
+ constructor() {
31
+ this.rules = [];
32
+ }
33
+ /**
34
+ * Adiciona regra de validação
35
+ */
36
+ addRule(rule) {
37
+ this.rules.push(rule);
38
+ return this;
39
+ }
40
+ /**
41
+ * Valida parâmetros contra as regras
42
+ */
43
+ validate(params) {
44
+ const errors = [];
45
+ const warnings = [];
46
+ for (const rule of this.rules) {
47
+ const value = params[rule.field];
48
+ // Validação de campo obrigatório
49
+ if (rule.required && (value === undefined || value === null || value === '')) {
50
+ errors.push({
51
+ field: rule.field,
52
+ type: ValidationType.REQUIRED,
53
+ message: rule.message || `Field '${rule.field}' is required`,
54
+ value,
55
+ });
56
+ continue;
57
+ }
58
+ // Se não é obrigatório e não tem valor, pular validações adicionais
59
+ if (!rule.required && (value === undefined || value === null || value === '')) {
60
+ continue;
61
+ }
62
+ // Validação por tipo
63
+ const typeError = this.validateType(rule, value, params);
64
+ if (typeError) {
65
+ errors.push(typeError);
66
+ continue;
67
+ }
68
+ // Validação customizada
69
+ if (rule.custom) {
70
+ const customResult = rule.custom(value, params);
71
+ if (customResult !== true) {
72
+ errors.push({
73
+ field: rule.field,
74
+ type: ValidationType.PATTERN,
75
+ message: typeof customResult === 'string' ? customResult : `Field '${rule.field}' failed custom validation`,
76
+ value,
77
+ });
78
+ }
79
+ }
80
+ // Avisos e sugestões
81
+ this.addWarnings(rule, value, warnings);
82
+ }
83
+ return {
84
+ isValid: errors.length === 0,
85
+ errors,
86
+ warnings,
87
+ };
88
+ }
89
+ /**
90
+ * Valida tipo do valor
91
+ */
92
+ validateType(rule, value, allParams) {
93
+ switch (rule.type) {
94
+ case ValidationType.STRING:
95
+ if (typeof value !== 'string') {
96
+ return {
97
+ field: rule.field,
98
+ type: ValidationType.STRING,
99
+ message: rule.message || `Field '${rule.field}' must be a string`,
100
+ value,
101
+ expected: 'string',
102
+ };
103
+ }
104
+ // Validação de comprimento
105
+ if (rule.minLength && value.length < rule.minLength) {
106
+ return {
107
+ field: rule.field,
108
+ type: ValidationType.LENGTH,
109
+ message: rule.message || `Field '${rule.field}' must be at least ${rule.minLength} characters`,
110
+ value,
111
+ expected: `>= ${rule.minLength}`,
112
+ };
113
+ }
114
+ if (rule.maxLength && value.length > rule.maxLength) {
115
+ return {
116
+ field: rule.field,
117
+ type: ValidationType.LENGTH,
118
+ message: rule.message || `Field '${rule.field}' must be at most ${rule.maxLength} characters`,
119
+ value,
120
+ expected: `<= ${rule.maxLength}`,
121
+ };
122
+ }
123
+ // Validação de padrão
124
+ if (rule.pattern && !rule.pattern.test(value)) {
125
+ return {
126
+ field: rule.field,
127
+ type: ValidationType.PATTERN,
128
+ message: rule.message || `Field '${rule.field}' does not match required pattern`,
129
+ value,
130
+ expected: rule.pattern.toString(),
131
+ };
132
+ }
133
+ // Validação de enum
134
+ if (rule.enum && !rule.enum.includes(value)) {
135
+ return {
136
+ field: rule.field,
137
+ type: ValidationType.ENUM,
138
+ message: rule.message || `Field '${rule.field}' must be one of: ${rule.enum.join(', ')}`,
139
+ value,
140
+ expected: rule.enum,
141
+ };
142
+ }
143
+ break;
144
+ case ValidationType.PATH:
145
+ if (typeof value !== 'string') {
146
+ return {
147
+ field: rule.field,
148
+ type: ValidationType.PATH,
149
+ message: rule.message || `Field '${rule.field}' must be a path string`,
150
+ value,
151
+ expected: 'string',
152
+ };
153
+ }
154
+ // Verificar path traversal
155
+ if (value.includes('..') || value.includes('~')) {
156
+ return {
157
+ field: rule.field,
158
+ type: ValidationType.PATH,
159
+ message: rule.message || `Field '${rule.field}' contains invalid path characters`,
160
+ value,
161
+ };
162
+ }
163
+ break;
164
+ default:
165
+ // Para outros tipos, implementação básica
166
+ if (rule.type === ValidationType.NUMBER && typeof value !== 'number') {
167
+ return {
168
+ field: rule.field,
169
+ type: ValidationType.NUMBER,
170
+ message: rule.message || `Field '${rule.field}' must be a number`,
171
+ value,
172
+ expected: 'number',
173
+ };
174
+ }
175
+ break;
176
+ }
177
+ return null;
178
+ }
179
+ /**
180
+ * Adiciona avisos baseados na validação
181
+ */
182
+ addWarnings(rule, value, warnings) {
183
+ if (rule.type === ValidationType.STRING && typeof value === 'string') {
184
+ // Aviso para strings vazias em campos não obrigatórios
185
+ if (value.trim() === '' && !rule.required) {
186
+ warnings.push({
187
+ field: rule.field,
188
+ message: `Field '${rule.field}' is empty`,
189
+ suggestion: 'Consider removing this field if not needed',
190
+ });
191
+ }
192
+ }
193
+ if (rule.type === ValidationType.PATH && typeof value === 'string') {
194
+ // Aviso para paths absolutos
195
+ if (path.isAbsolute(value)) {
196
+ warnings.push({
197
+ field: rule.field,
198
+ message: `Field '${rule.field}' contains an absolute path`,
199
+ suggestion: 'Consider using relative paths for better portability',
200
+ });
201
+ }
202
+ }
203
+ }
204
+ /**
205
+ * Limpa todas as regras
206
+ */
207
+ clear() {
208
+ this.rules = [];
209
+ }
210
+ }
211
+ /**
212
+ * Validadores pré-configurados para casos comuns
213
+ */
214
+ export const commonValidators = {
215
+ /**
216
+ * Validador para parâmetros Git básicos
217
+ */
218
+ gitParams: () => new ParameterValidator()
219
+ .addRule({ field: 'projectPath', type: ValidationType.STRING, required: true })
220
+ .addRule({
221
+ field: 'projectPath',
222
+ type: ValidationType.PATH,
223
+ custom: (value) => {
224
+ if (value.includes('..'))
225
+ return 'Path cannot contain .. (parent directory)';
226
+ if (value.includes('~'))
227
+ return 'Path cannot contain ~ (home directory)';
228
+ return true;
229
+ }
230
+ }),
231
+ /**
232
+ * Validador para ações Git
233
+ */
234
+ gitAction: (allowedActions) => new ParameterValidator()
235
+ .addRule({
236
+ field: 'action',
237
+ type: ValidationType.STRING,
238
+ required: true,
239
+ enum: allowedActions,
240
+ }),
241
+ /**
242
+ * Validador para branches
243
+ */
244
+ branchName: () => new ParameterValidator()
245
+ .addRule({
246
+ field: 'branchName',
247
+ type: ValidationType.STRING,
248
+ required: true,
249
+ pattern: /^[a-zA-Z0-9._/-]+$/,
250
+ message: 'Branch name can only contain letters, numbers, dots, underscores, hyphens and forward slashes',
251
+ }),
252
+ };
253
+ /**
254
+ * Função helper para validação rápida
255
+ */
256
+ export function validateParams(params, rules) {
257
+ const validator = new ParameterValidator();
258
+ rules.forEach(rule => validator.addRule(rule));
259
+ return validator.validate(params);
260
+ }
261
+ /**
262
+ * Função helper para validação com throw de erro
263
+ */
264
+ export function validateOrThrow(params, rules) {
265
+ const result = validateParams(params, rules);
266
+ if (!result.isValid) {
267
+ const errorMessages = result.errors.map((e) => e.message).join('; ');
268
+ throw new MCPError('VALIDATION_ERROR', errorMessages, result.errors.map((e) => e.message));
269
+ }
270
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrebuzeli/git-mcp",
3
- "version": "10.0.4",
3
+ "version": "10.0.6",
4
4
  "type": "module",
5
5
  "description": "Professional MCP server for Git operations - STDIO UNIVERSAL: works in ANY IDE (Cursor, VSCode, Claude Desktop, Trae AI, Kiro.dev). Fully autonomous DUAL execution (GitHub + Gitea APIs) with automatic username detection. Smart parameter normalization handles both 'action' and 'command' formats. All tools execute on BOTH providers simultaneously. No manual parameters needed.",
6
6
  "main": "dist/index.js",
package/dist/config.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export type MCPConfig = {
2
- env?: Record<string, string>;
3
- [k: string]: any;
4
- };
5
- export declare function loadMCPConfig(configPath?: string): MCPConfig | null;
package/dist/config.js DELETED
@@ -1,35 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- function maskSecret(value) {
4
- if (!value)
5
- return 'undefined';
6
- if (value.length <= 8)
7
- return '****';
8
- return `${value.slice(0, 4)}...${value.slice(-4)}`;
9
- }
10
- export function loadMCPConfig(configPath) {
11
- const cfgPath = path.resolve(process.cwd(), configPath ?? 'mcp.json');
12
- if (!fs.existsSync(cfgPath))
13
- return null;
14
- try {
15
- const raw = fs.readFileSync(cfgPath, 'utf8');
16
- const cfg = JSON.parse(raw);
17
- if (cfg.env) {
18
- for (const [k, v] of Object.entries(cfg.env)) {
19
- // Only set if not already present in process.env
20
- if (process.env[k] == null) {
21
- process.env[k] = v;
22
- }
23
- // Log to stderr only (stdout is used for MCP protocol)
24
- if (process.env.DEBUG) {
25
- console.error(`MCP config: env.${k}=${maskSecret(process.env[k])}`);
26
- }
27
- }
28
- }
29
- return cfg;
30
- }
31
- catch (err) {
32
- console.error('Failed to parse mcp.json:', err.message ?? String(err));
33
- return null;
34
- }
35
- }