@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.
@@ -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({ code, message, data }) }],
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
+ }