@andrebuzeli/git-mcp 12.0.0 → 13.6.0
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/package.json +1 -1
- package/src/index.js +4 -4
- package/src/tools/git-branches.js +21 -7
- package/src/tools/git-config.js +8 -9
- package/src/tools/git-files.js +18 -8
- package/src/tools/git-history.js +22 -5
- package/src/tools/git-ignore.js +19 -8
- package/src/tools/git-issues.js +3 -3
- package/src/tools/git-pulls.js +3 -3
- package/src/tools/git-remote.js +5 -3
- package/src/tools/git-reset.js +20 -5
- package/src/tools/git-stash.js +31 -10
- package/src/tools/git-sync.js +21 -5
- package/src/tools/git-tags.js +34 -13
- package/src/tools/git-workflow.js +10 -6
- package/src/utils/errors.js +276 -1
- package/src/utils/gitAdapter.js +392 -9
- package/src/utils/retry.js +58 -9
package/src/utils/errors.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Sistema de Erros Melhorado para AI Agents
|
|
2
|
+
|
|
1
3
|
export class MCPError extends Error {
|
|
2
4
|
constructor(code, message, data) {
|
|
3
5
|
super(message);
|
|
@@ -6,6 +8,262 @@ export class MCPError extends Error {
|
|
|
6
8
|
}
|
|
7
9
|
}
|
|
8
10
|
|
|
11
|
+
// Códigos de erro padronizados com sugestões para AI
|
|
12
|
+
export const ERROR_CODES = {
|
|
13
|
+
// Auth
|
|
14
|
+
AUTH_GITHUB_INVALID: {
|
|
15
|
+
code: "AUTH_GITHUB_INVALID",
|
|
16
|
+
suggestion: "Verifique se GITHUB_TOKEN está configurado e é válido. Gere um novo token em github.com/settings/tokens"
|
|
17
|
+
},
|
|
18
|
+
AUTH_GITEA_INVALID: {
|
|
19
|
+
code: "AUTH_GITEA_INVALID",
|
|
20
|
+
suggestion: "Verifique se GITEA_TOKEN e GITEA_URL estão configurados corretamente"
|
|
21
|
+
},
|
|
22
|
+
AUTH_NO_PERMISSION: {
|
|
23
|
+
code: "AUTH_NO_PERMISSION",
|
|
24
|
+
suggestion: "Token não tem permissão para esta operação. Verifique os scopes do token"
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Repo
|
|
28
|
+
REPO_NOT_FOUND: {
|
|
29
|
+
code: "REPO_NOT_FOUND",
|
|
30
|
+
suggestion: "Repositório não existe. Use action='init' com createIfMissing=true para criar"
|
|
31
|
+
},
|
|
32
|
+
REPO_NO_WRITE: {
|
|
33
|
+
code: "REPO_NO_WRITE",
|
|
34
|
+
suggestion: "Sem permissão de escrita. Verifique se você é owner ou colaborador do repositório"
|
|
35
|
+
},
|
|
36
|
+
REPO_ALREADY_EXISTS: {
|
|
37
|
+
code: "REPO_ALREADY_EXISTS",
|
|
38
|
+
suggestion: "Repositório já existe. Use action='ensure' para verificar ou escolha outro nome"
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// Git Local
|
|
42
|
+
NOT_A_GIT_REPO: {
|
|
43
|
+
code: "NOT_A_GIT_REPO",
|
|
44
|
+
suggestion: "Diretório não é um repositório git. Use action='init' primeiro para inicializar"
|
|
45
|
+
},
|
|
46
|
+
NO_COMMITS: {
|
|
47
|
+
code: "NO_COMMITS",
|
|
48
|
+
suggestion: "Repositório não tem commits. Use action='add' e depois action='commit' primeiro"
|
|
49
|
+
},
|
|
50
|
+
NOTHING_TO_COMMIT: {
|
|
51
|
+
code: "NOTHING_TO_COMMIT",
|
|
52
|
+
suggestion: "Working tree limpa, nada para commitar. Modifique arquivos primeiro"
|
|
53
|
+
},
|
|
54
|
+
NOTHING_TO_PUSH: {
|
|
55
|
+
code: "NOTHING_TO_PUSH",
|
|
56
|
+
suggestion: "Nenhuma mudança para push. Faça commits primeiro"
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// Branches
|
|
60
|
+
BRANCH_NOT_FOUND: {
|
|
61
|
+
code: "BRANCH_NOT_FOUND",
|
|
62
|
+
suggestion: "Branch não existe. Use action='list' para ver branches disponíveis"
|
|
63
|
+
},
|
|
64
|
+
BRANCH_ALREADY_EXISTS: {
|
|
65
|
+
code: "BRANCH_ALREADY_EXISTS",
|
|
66
|
+
suggestion: "Branch já existe. Use outro nome ou delete a existente primeiro"
|
|
67
|
+
},
|
|
68
|
+
CANNOT_DELETE_CURRENT: {
|
|
69
|
+
code: "CANNOT_DELETE_CURRENT",
|
|
70
|
+
suggestion: "Não pode deletar branch atual. Faça checkout para outra branch primeiro"
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Tags
|
|
74
|
+
TAG_NOT_FOUND: {
|
|
75
|
+
code: "TAG_NOT_FOUND",
|
|
76
|
+
suggestion: "Tag não existe. Use action='list' para ver tags disponíveis"
|
|
77
|
+
},
|
|
78
|
+
TAG_ALREADY_EXISTS: {
|
|
79
|
+
code: "TAG_ALREADY_EXISTS",
|
|
80
|
+
suggestion: "Tag já existe. Use outro nome ou delete a existente primeiro"
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Refs
|
|
84
|
+
REF_NOT_FOUND: {
|
|
85
|
+
code: "REF_NOT_FOUND",
|
|
86
|
+
suggestion: "Referência não encontrada. Verifique se o commit/branch/tag existe. Use action='log' para ver histórico"
|
|
87
|
+
},
|
|
88
|
+
INSUFFICIENT_HISTORY: {
|
|
89
|
+
code: "INSUFFICIENT_HISTORY",
|
|
90
|
+
suggestion: "Histórico insuficiente para HEAD~N. Use action='log' para verificar quantos commits existem"
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
// Stash
|
|
94
|
+
NOTHING_TO_STASH: {
|
|
95
|
+
code: "NOTHING_TO_STASH",
|
|
96
|
+
suggestion: "Working tree limpa, nada para stash. Modifique arquivos primeiro"
|
|
97
|
+
},
|
|
98
|
+
STASH_NOT_FOUND: {
|
|
99
|
+
code: "STASH_NOT_FOUND",
|
|
100
|
+
suggestion: "Stash não encontrado. Use action='list' para ver stashes disponíveis"
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// Remote
|
|
104
|
+
REMOTE_NOT_FOUND: {
|
|
105
|
+
code: "REMOTE_NOT_FOUND",
|
|
106
|
+
suggestion: "Remote não configurado. Use action='ensure-remotes' para configurar"
|
|
107
|
+
},
|
|
108
|
+
PUSH_REJECTED: {
|
|
109
|
+
code: "PUSH_REJECTED",
|
|
110
|
+
suggestion: "Push rejeitado (histórico divergente). Use force=true para forçar, ou faça pull primeiro"
|
|
111
|
+
},
|
|
112
|
+
MERGE_CONFLICT: {
|
|
113
|
+
code: "MERGE_CONFLICT",
|
|
114
|
+
suggestion: "Conflito de merge. Resolva conflitos manualmente e faça novo commit"
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Network
|
|
118
|
+
NETWORK_TIMEOUT: {
|
|
119
|
+
code: "NETWORK_TIMEOUT",
|
|
120
|
+
suggestion: "Timeout de conexão. Verifique sua internet e tente novamente"
|
|
121
|
+
},
|
|
122
|
+
RATE_LIMIT: {
|
|
123
|
+
code: "RATE_LIMIT",
|
|
124
|
+
suggestion: "Rate limit excedido. Aguarde alguns minutos antes de tentar novamente"
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// Validation
|
|
128
|
+
VALIDATION_ERROR: {
|
|
129
|
+
code: "VALIDATION_ERROR",
|
|
130
|
+
suggestion: "Parâmetros inválidos. Verifique os parâmetros obrigatórios da action"
|
|
131
|
+
},
|
|
132
|
+
MISSING_PARAMETER: {
|
|
133
|
+
code: "MISSING_PARAMETER",
|
|
134
|
+
suggestion: "Parâmetro obrigatório faltando"
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
// Files
|
|
138
|
+
FILE_NOT_FOUND: {
|
|
139
|
+
code: "FILE_NOT_FOUND",
|
|
140
|
+
suggestion: "Arquivo não encontrado no repositório. Use action='list' para ver arquivos disponíveis"
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Issues/PRs
|
|
144
|
+
ISSUE_NOT_FOUND: {
|
|
145
|
+
code: "ISSUE_NOT_FOUND",
|
|
146
|
+
suggestion: "Issue não encontrada. Use action='list' para ver issues disponíveis"
|
|
147
|
+
},
|
|
148
|
+
PR_NOT_FOUND: {
|
|
149
|
+
code: "PR_NOT_FOUND",
|
|
150
|
+
suggestion: "Pull Request não encontrado. Use action='list' para ver PRs disponíveis"
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// Generic
|
|
154
|
+
UNKNOWN_ERROR: {
|
|
155
|
+
code: "UNKNOWN_ERROR",
|
|
156
|
+
suggestion: "Erro desconhecido. Verifique os logs para mais detalhes"
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// Função para criar erro com sugestão
|
|
161
|
+
export function createError(errorCode, details = {}) {
|
|
162
|
+
const errorInfo = ERROR_CODES[errorCode] || ERROR_CODES.UNKNOWN_ERROR;
|
|
163
|
+
return new MCPError(errorInfo.code, details.message || errorInfo.code, {
|
|
164
|
+
suggestion: errorInfo.suggestion,
|
|
165
|
+
...details
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Função para mapear erros externos para códigos internos
|
|
170
|
+
export function mapExternalError(error, context = {}) {
|
|
171
|
+
const msg = error?.message?.toLowerCase() || String(error).toLowerCase();
|
|
172
|
+
|
|
173
|
+
// GitHub/Gitea API errors
|
|
174
|
+
if (msg.includes("bad credentials") || msg.includes("401")) {
|
|
175
|
+
return context.provider === "gitea"
|
|
176
|
+
? createError("AUTH_GITEA_INVALID", { originalError: msg })
|
|
177
|
+
: createError("AUTH_GITHUB_INVALID", { originalError: msg });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (msg.includes("not found") || msg.includes("404")) {
|
|
181
|
+
if (context.type === "repo") return createError("REPO_NOT_FOUND", { repo: context.repo, originalError: msg });
|
|
182
|
+
if (context.type === "branch") return createError("BRANCH_NOT_FOUND", { branch: context.branch, originalError: msg });
|
|
183
|
+
if (context.type === "tag") return createError("TAG_NOT_FOUND", { tag: context.tag, originalError: msg });
|
|
184
|
+
if (context.type === "file") return createError("FILE_NOT_FOUND", { file: context.file, originalError: msg });
|
|
185
|
+
if (context.type === "issue") return createError("ISSUE_NOT_FOUND", { number: context.number, originalError: msg });
|
|
186
|
+
if (context.type === "pr") return createError("PR_NOT_FOUND", { number: context.number, originalError: msg });
|
|
187
|
+
return createError("REF_NOT_FOUND", { ref: context.ref, originalError: msg });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (msg.includes("permission") || msg.includes("403") || msg.includes("forbidden")) {
|
|
191
|
+
return createError("AUTH_NO_PERMISSION", { originalError: msg });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (msg.includes("rate limit") || msg.includes("429")) {
|
|
195
|
+
return createError("RATE_LIMIT", { originalError: msg });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (msg.includes("timeout") || msg.includes("etimedout") || msg.includes("econnrefused")) {
|
|
199
|
+
return createError("NETWORK_TIMEOUT", { originalError: msg });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (msg.includes("push rejected") || msg.includes("non-fast-forward")) {
|
|
203
|
+
return createError("PUSH_REJECTED", { originalError: msg });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (msg.includes("conflict")) {
|
|
207
|
+
return createError("MERGE_CONFLICT", { originalError: msg });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (msg.includes("already exists")) {
|
|
211
|
+
if (context.type === "repo") return createError("REPO_ALREADY_EXISTS", { repo: context.repo, originalError: msg });
|
|
212
|
+
if (context.type === "branch") return createError("BRANCH_ALREADY_EXISTS", { branch: context.branch, originalError: msg });
|
|
213
|
+
if (context.type === "tag") return createError("TAG_ALREADY_EXISTS", { tag: context.tag, originalError: msg });
|
|
214
|
+
return createError("BRANCH_ALREADY_EXISTS", { originalError: msg });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// isomorphic-git specific errors
|
|
218
|
+
if (msg.includes("could not find") && msg.includes("head~")) {
|
|
219
|
+
return createError("INSUFFICIENT_HISTORY", { originalError: msg });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (msg.includes("is not a git repository") || msg.includes("could not find .git")) {
|
|
223
|
+
return createError("NOT_A_GIT_REPO", { path: context.path, originalError: msg });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (msg.includes("nothing to commit") || msg.includes("working tree clean")) {
|
|
227
|
+
return createError("NOTHING_TO_COMMIT", { originalError: msg });
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (msg.includes("could not resolve ref") || msg.includes("invalid reference")) {
|
|
231
|
+
return createError("REF_NOT_FOUND", { originalError: msg });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (msg.includes("branch") && (msg.includes("does not exist") || msg.includes("not found"))) {
|
|
235
|
+
return createError("BRANCH_NOT_FOUND", { originalError: msg });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (msg.includes("tag") && (msg.includes("does not exist") || msg.includes("not found"))) {
|
|
239
|
+
return createError("TAG_NOT_FOUND", { originalError: msg });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (msg.includes("no commits") || msg.includes("unknown revision")) {
|
|
243
|
+
return createError("NO_COMMITS", { originalError: msg });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (msg.includes("nada para stash") || msg.includes("nothing to stash") || msg.includes("no local changes")) {
|
|
247
|
+
return createError("NOTHING_TO_STASH", { originalError: msg });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (msg.includes("stash") && (msg.includes("not found") || msg.includes("não encontrado"))) {
|
|
251
|
+
return createError("STASH_NOT_FOUND", { originalError: msg });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (msg.includes("author") || msg.includes("committer")) {
|
|
255
|
+
return createError("VALIDATION_ERROR", {
|
|
256
|
+
message: "Configure user.name e user.email",
|
|
257
|
+
suggestion: "Use git-config para configurar ou forneça tokens de provider",
|
|
258
|
+
originalError: msg
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Generic fallback
|
|
263
|
+
return createError("UNKNOWN_ERROR", { originalError: msg, context });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Resultado de sucesso
|
|
9
267
|
export function asToolResult(result) {
|
|
10
268
|
return {
|
|
11
269
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -13,10 +271,27 @@ export function asToolResult(result) {
|
|
|
13
271
|
};
|
|
14
272
|
}
|
|
15
273
|
|
|
274
|
+
// Resultado de erro (formato melhorado para AI agents)
|
|
16
275
|
export function asToolError(code, message, data) {
|
|
276
|
+
const errorInfo = ERROR_CODES[code] || {};
|
|
277
|
+
const response = {
|
|
278
|
+
error: true,
|
|
279
|
+
code: code,
|
|
280
|
+
message: message,
|
|
281
|
+
suggestion: errorInfo.suggestion || "Verifique os parâmetros e tente novamente",
|
|
282
|
+
...data
|
|
283
|
+
};
|
|
17
284
|
return {
|
|
18
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
285
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
19
286
|
isError: true,
|
|
20
287
|
};
|
|
21
288
|
}
|
|
22
289
|
|
|
290
|
+
// Helper para converter MCPError em resposta
|
|
291
|
+
export function errorToResponse(error) {
|
|
292
|
+
if (error instanceof MCPError) {
|
|
293
|
+
return asToolError(error.code, error.message, error.data);
|
|
294
|
+
}
|
|
295
|
+
const mapped = mapExternalError(error);
|
|
296
|
+
return asToolError(mapped.code, mapped.message, mapped.data);
|
|
297
|
+
}
|