@andrebuzeli/git-mcp 15.5.0 → 15.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 +21 -2
- package/src/prompts/index.js +828 -0
- package/src/utils/gitAdapter.js +9 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -24,6 +24,7 @@ import { createGitDiffTool } from "./tools/git-diff.js";
|
|
|
24
24
|
import { createGitCloneTool } from "./tools/git-clone.js";
|
|
25
25
|
import { createGitHelpTool } from "./tools/git-help.js";
|
|
26
26
|
import { getResources, readResource } from "./resources/index.js";
|
|
27
|
+
import { createPromptsHandler, PROMPTS } from "./prompts/index.js";
|
|
27
28
|
|
|
28
29
|
// Carrega variáveis de ambiente do arquivo .env (se existir)
|
|
29
30
|
loadEnv();
|
|
@@ -46,11 +47,14 @@ if (!hasGitHub && !hasGitea) {
|
|
|
46
47
|
|
|
47
48
|
const transport = new StdioServerTransport();
|
|
48
49
|
const server = new Server(
|
|
49
|
-
{ name: "git-mcpv2", version: "15.
|
|
50
|
-
{ capabilities: { tools: {}, resources: {} } }
|
|
50
|
+
{ name: "git-mcpv2", version: "15.6.0" },
|
|
51
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
|
|
51
52
|
);
|
|
52
53
|
server.connect(transport);
|
|
53
54
|
|
|
55
|
+
// Prompts handler
|
|
56
|
+
const promptsHandler = createPromptsHandler(git, pm);
|
|
57
|
+
|
|
54
58
|
// Ajv singleton para validação
|
|
55
59
|
const ajv = new Ajv({ allErrors: true });
|
|
56
60
|
|
|
@@ -123,5 +127,20 @@ server.setRequestHandler(
|
|
|
123
127
|
}
|
|
124
128
|
);
|
|
125
129
|
|
|
130
|
+
// ============ PROMPTS ============
|
|
131
|
+
server.setRequestHandler(
|
|
132
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListPromptsRequestSchema,
|
|
133
|
+
async () => ({ prompts: PROMPTS })
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
server.setRequestHandler(
|
|
137
|
+
(await import("@modelcontextprotocol/sdk/types.js")).GetPromptRequestSchema,
|
|
138
|
+
async (req) => {
|
|
139
|
+
const name = req.params?.name || "";
|
|
140
|
+
const args = req.params?.arguments || {};
|
|
141
|
+
return await promptsHandler.get(name, args);
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
|
|
126
145
|
// Keep process alive
|
|
127
146
|
process.stdin.resume();
|
|
@@ -0,0 +1,828 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Prompts para git-mcp
|
|
3
|
+
*
|
|
4
|
+
* Prompts são templates reutilizáveis que guiam interações com o LLM.
|
|
5
|
+
* Diferente de Tools (executam lógica), Prompts retornam mensagens formatadas.
|
|
6
|
+
* UTILIZANDO APENAS O GIT-MCP
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ============ PROMPT DEFINITIONS ============
|
|
10
|
+
|
|
11
|
+
export const PROMPTS = [
|
|
12
|
+
{
|
|
13
|
+
name: "git-status",
|
|
14
|
+
description: "Mostra status completo do repositório Git. UTILIZANDO APENAS O GIT-MCP"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "git-history",
|
|
18
|
+
description: "Exibe histórico de commits do repositório. UTILIZANDO APENAS O GIT-MCP"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "git-remote",
|
|
22
|
+
description: "Lista e mostra informações dos remotes configurados. UTILIZANDO APENAS O GIT-MCP"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "git-commit",
|
|
26
|
+
description: "Prepara e cria commit das mudanças (sem configurar email). UTILIZANDO APENAS O GIT-MCP"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "git-push",
|
|
30
|
+
description: "Envia commits locais para os remotes (GitHub/Gitea). UTILIZANDO APENAS O GIT-MCP"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "git-cleanup",
|
|
34
|
+
description: "Limpa arquivos não rastreados do repositório. UTILIZANDO APENAS O GIT-MCP"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "git-review",
|
|
38
|
+
description: "Faz code review das mudanças atuais do repositório. UTILIZANDO APENAS O GIT-MCP"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "git-change",
|
|
42
|
+
description: "Gera changelog das mudanças desde última tag ou versão específica. UTILIZANDO APENAS O GIT-MCP"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "git-lint",
|
|
46
|
+
description: "Analisa código modificado procurando problemas comuns e más práticas. UTILIZANDO APENAS O GIT-MCP"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "git-debug",
|
|
50
|
+
description: "Ajuda a encontrar bugs analisando histórico de commits. UTILIZANDO APENAS O GIT-MCP"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "git-release",
|
|
54
|
+
description: "Cria release completa do projeto com tag e release notes. UTILIZANDO APENAS O GIT-MCP"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "git-update",
|
|
58
|
+
description: "Atualiza projeto completo nos providers: commit, push e sincroniza GitHub/Gitea. UTILIZANDO APENAS O GIT-MCP"
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// ============ PROMPT TEMPLATES ============
|
|
63
|
+
|
|
64
|
+
const PROMPT_TEMPLATES = {
|
|
65
|
+
"git-status": {
|
|
66
|
+
getMessages: (context) => [{
|
|
67
|
+
role: "user",
|
|
68
|
+
content: {
|
|
69
|
+
type: "text",
|
|
70
|
+
text: `# Status do Repositório Git
|
|
71
|
+
|
|
72
|
+
Analise o status atual do repositório e forneça um resumo claro e acionável.
|
|
73
|
+
|
|
74
|
+
## Status Atual
|
|
75
|
+
|
|
76
|
+
- **Branch**: ${context.branch || "N/A"}
|
|
77
|
+
- **Arquivos modificados**: ${context.modified?.length || 0}
|
|
78
|
+
- **Arquivos staged**: ${context.staged?.length || 0}
|
|
79
|
+
- **Arquivos não rastreados**: ${context.notAdded?.length || 0}
|
|
80
|
+
- **Arquivos deletados**: ${context.deleted?.length || 0}
|
|
81
|
+
- **Working tree limpa**: ${context.isClean ? "Sim" : "Não"}
|
|
82
|
+
|
|
83
|
+
## Arquivos Modificados
|
|
84
|
+
${context.modified?.map(f => `- ${f}`).join("\n") || "Nenhum"}
|
|
85
|
+
|
|
86
|
+
## Arquivos Staged (prontos para commit)
|
|
87
|
+
${context.staged?.map(f => `- ${f}`).join("\n") || "Nenhum"}
|
|
88
|
+
|
|
89
|
+
## Arquivos Não Rastreados
|
|
90
|
+
${context.notAdded?.map(f => `- ${f}`).join("\n") || "Nenhum"}
|
|
91
|
+
|
|
92
|
+
## Instruções
|
|
93
|
+
|
|
94
|
+
Forneça um resumo do status atual e sugira próximos passos. UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
95
|
+
- Use \`git-workflow\` para add, commit, push
|
|
96
|
+
- Use \`git-branches\` para gerenciar branches
|
|
97
|
+
- Use \`git-status\` apenas para consulta`
|
|
98
|
+
}
|
|
99
|
+
}]
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
"git-history": {
|
|
103
|
+
getMessages: (context) => {
|
|
104
|
+
const maxCount = context.maxCount || 20;
|
|
105
|
+
const userMessage = context.userMessage ? `\n\n## Observação do Usuário\n\n${context.userMessage}\n` : "";
|
|
106
|
+
|
|
107
|
+
return [{
|
|
108
|
+
role: "user",
|
|
109
|
+
content: {
|
|
110
|
+
type: "text",
|
|
111
|
+
text: `# Histórico de Commits${userMessage}
|
|
112
|
+
|
|
113
|
+
## Branch Atual
|
|
114
|
+
${context.branch || "N/A"}
|
|
115
|
+
|
|
116
|
+
## Últimos ${context.commits?.length || 0} Commits
|
|
117
|
+
|
|
118
|
+
${context.commits?.map(c => {
|
|
119
|
+
const author = typeof c.author === 'object' ? c.author?.name : c.author || "Unknown";
|
|
120
|
+
const date = c.date ? new Date(c.date).toLocaleString('pt-BR') : "N/A";
|
|
121
|
+
return `### ${c.shortSha || c.sha?.substring(0, 7) || "N/A"}
|
|
122
|
+
- **Autor**: ${author}
|
|
123
|
+
- **Data**: ${date}
|
|
124
|
+
- **Mensagem**: ${c.message || "Sem mensagem"}
|
|
125
|
+
- **SHA completo**: ${c.sha || "N/A"}`;
|
|
126
|
+
}).join("\n\n") || "Nenhum commit encontrado"}
|
|
127
|
+
|
|
128
|
+
## Instruções
|
|
129
|
+
|
|
130
|
+
Apresente o histórico de commits de forma organizada. UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
131
|
+
- Use \`git-history log\` para ver mais commits
|
|
132
|
+
- Use \`git-diff compare\` para comparar commits
|
|
133
|
+
- Use \`git-files read\` para ver arquivos em commits específicos`
|
|
134
|
+
}
|
|
135
|
+
}];
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
"git-remote": {
|
|
140
|
+
getMessages: (context) => [{
|
|
141
|
+
role: "user",
|
|
142
|
+
content: {
|
|
143
|
+
type: "text",
|
|
144
|
+
text: `# Remotes Configurados
|
|
145
|
+
|
|
146
|
+
## Remotes Disponíveis
|
|
147
|
+
|
|
148
|
+
${context.remotes?.map(r => `### ${r.name || r.remote || "N/A"}
|
|
149
|
+
- **URL**: ${r.url || "N/A"}
|
|
150
|
+
- **Tipo**: ${r.url?.includes("github.com") ? "GitHub" : r.url?.includes("gitea") ? "Gitea" : "Desconhecido"}
|
|
151
|
+
`).join("\n") || "Nenhum remote configurado"}
|
|
152
|
+
|
|
153
|
+
## Status dos Providers
|
|
154
|
+
|
|
155
|
+
- **GitHub configurado**: ${context.hasGitHub ? "Sim" : "Não"}
|
|
156
|
+
- **Gitea configurado**: ${context.hasGitea ? "Sim" : "Não"}
|
|
157
|
+
|
|
158
|
+
## Instruções
|
|
159
|
+
|
|
160
|
+
Apresente os remotes configurados e sugira configuração se necessário. UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
161
|
+
- Use \`git-remote list\` para ver remotes
|
|
162
|
+
- Use \`git-remote ensure\` para configurar remotes automaticamente
|
|
163
|
+
- Use \`git-workflow ensure-remotes\` como alternativa`
|
|
164
|
+
}
|
|
165
|
+
}]
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
"git-commit": {
|
|
169
|
+
getMessages: (context) => {
|
|
170
|
+
const userMessage = context.userMessage || "";
|
|
171
|
+
const suggestedMessage = userMessage || context.suggestedMessage || "";
|
|
172
|
+
|
|
173
|
+
return [{
|
|
174
|
+
role: "user",
|
|
175
|
+
content: {
|
|
176
|
+
type: "text",
|
|
177
|
+
text: `# Criar Commit${userMessage ? `\n\n## Mensagem do Usuário\n\n${userMessage}\n` : ""}
|
|
178
|
+
|
|
179
|
+
## Arquivos Staged (prontos para commit)
|
|
180
|
+
${context.staged?.map(f => `- ${f}`).join("\n") || "Nenhum arquivo staged"}
|
|
181
|
+
|
|
182
|
+
## Mudanças Staged
|
|
183
|
+
\`\`\`diff
|
|
184
|
+
${context.stagedDiff || "Use git-diff para ver mudanças"}
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
## Status Atual
|
|
188
|
+
- **Branch**: ${context.branch || "N/A"}
|
|
189
|
+
- **Arquivos staged**: ${context.staged?.length || 0}
|
|
190
|
+
- **Arquivos modificados (não staged)**: ${context.modified?.length || 0}
|
|
191
|
+
|
|
192
|
+
## Instruções
|
|
193
|
+
|
|
194
|
+
${context.staged?.length > 0
|
|
195
|
+
? `Crie um commit com as mudanças staged. ${userMessage ? `Use a mensagem fornecida pelo usuário: "${userMessage}"` : "Se não houver mensagem do usuário, sugira uma mensagem descritiva baseada nas mudanças."}
|
|
196
|
+
|
|
197
|
+
UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
198
|
+
- Use \`git-workflow commit\` com a mensagem apropriada
|
|
199
|
+
- NÃO configure email (o usuário não quer isso)
|
|
200
|
+
- Se houver arquivos modificados não staged, sugira usar \`git-workflow add\` primeiro`
|
|
201
|
+
: `Não há arquivos staged para commit. Execute primeiro: \`git-workflow add\` com os arquivos desejados.
|
|
202
|
+
|
|
203
|
+
UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
204
|
+
- Use \`git-workflow add\` para adicionar arquivos ao staging
|
|
205
|
+
- Depois use \`git-workflow commit\` para criar o commit`}`
|
|
206
|
+
}
|
|
207
|
+
}];
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
"git-push": {
|
|
212
|
+
getMessages: (context) => {
|
|
213
|
+
const forceFlag = context.userMessage?.toLowerCase().includes("force") ? true : false;
|
|
214
|
+
|
|
215
|
+
return [{
|
|
216
|
+
role: "user",
|
|
217
|
+
content: {
|
|
218
|
+
type: "text",
|
|
219
|
+
text: `# Push para Remotes
|
|
220
|
+
|
|
221
|
+
## Status Atual
|
|
222
|
+
- **Branch atual**: ${context.branch || "N/A"}
|
|
223
|
+
- **Commits locais não enviados**: ${context.unpushedCommits || "Desconhecido"}
|
|
224
|
+
- **Remotes configurados**: ${context.remotes?.map(r => r.name).join(", ") || "Nenhum"}
|
|
225
|
+
- **Force push necessário?**: ${forceFlag ? "Sim (solicitado pelo usuário)" : "Não"}
|
|
226
|
+
|
|
227
|
+
## Remotes Disponíveis
|
|
228
|
+
${context.remotes?.map(r => `- **${r.name}**: ${r.url}`).join("\n") || "Nenhum"}
|
|
229
|
+
|
|
230
|
+
## Instruções
|
|
231
|
+
|
|
232
|
+
Envie os commits locais para os remotes (GitHub/Gitea). UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
233
|
+
- Use \`git-workflow push\` para enviar para todos os remotes em paralelo
|
|
234
|
+
- ${forceFlag ? "Use force=true se necessário (foi solicitado)" : "Use force=true apenas se push for rejeitado"}
|
|
235
|
+
- Se não houver remotes configurados, use \`git-remote ensure\` primeiro
|
|
236
|
+
- Se não houver commits para enviar, informe o usuário`
|
|
237
|
+
}
|
|
238
|
+
}];
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
"git-cleanup": {
|
|
243
|
+
getMessages: (context) => [{
|
|
244
|
+
role: "user",
|
|
245
|
+
content: {
|
|
246
|
+
type: "text",
|
|
247
|
+
text: `# Limpar Arquivos Não Rastreados
|
|
248
|
+
|
|
249
|
+
## Arquivos Não Rastreados Detectados
|
|
250
|
+
${context.untrackedFiles?.map(f => `- ${f}`).join("\n") || "Nenhum arquivo não rastreado encontrado"}
|
|
251
|
+
|
|
252
|
+
## Total de Arquivos para Limpar
|
|
253
|
+
${context.untrackedFiles?.length || 0}
|
|
254
|
+
|
|
255
|
+
## Instruções
|
|
256
|
+
|
|
257
|
+
${context.untrackedFiles?.length > 0
|
|
258
|
+
? `Limpe os arquivos não rastreados do repositório. UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
259
|
+
- Use \`git-workflow clean\` para remover arquivos não rastreados
|
|
260
|
+
- Antes de limpar, certifique-se de que não são arquivos importantes
|
|
261
|
+
- Liste os arquivos que serão removidos antes de confirmar`
|
|
262
|
+
: `Não há arquivos não rastreados para limpar. O repositório está limpo.`}`
|
|
263
|
+
}
|
|
264
|
+
}]
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
"git-review": {
|
|
268
|
+
getMessages: (context) => {
|
|
269
|
+
const userMessage = context.userMessage ? `\n\n## Observação do Usuário\n\n${context.userMessage}\n` : "";
|
|
270
|
+
|
|
271
|
+
return [{
|
|
272
|
+
role: "user",
|
|
273
|
+
content: {
|
|
274
|
+
type: "text",
|
|
275
|
+
text: `# Code Review Request${userMessage}
|
|
276
|
+
|
|
277
|
+
Você é um code reviewer experiente. Analise as mudanças abaixo e forneça um review detalhado.
|
|
278
|
+
|
|
279
|
+
## Mudanças para Review
|
|
280
|
+
|
|
281
|
+
\`\`\`diff
|
|
282
|
+
${context.diff || "Nenhuma mudança detectada"}
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
## Arquivos Modificados
|
|
286
|
+
${context.files?.map(f => `- ${f}`).join("\n") || "Nenhum arquivo modificado"}
|
|
287
|
+
|
|
288
|
+
## Instruções de Review
|
|
289
|
+
|
|
290
|
+
Por favor, analise:
|
|
291
|
+
|
|
292
|
+
1. **🐛 Bugs Potenciais**: Identifique possíveis bugs ou erros lógicos
|
|
293
|
+
2. **🔒 Segurança**: Verifique vulnerabilidades de segurança
|
|
294
|
+
3. **⚡ Performance**: Aponte problemas de performance
|
|
295
|
+
4. **📖 Legibilidade**: Sugira melhorias de código limpo
|
|
296
|
+
5. **🧪 Testabilidade**: Comente sobre cobertura de testes
|
|
297
|
+
6. **✅ Pontos Positivos**: Destaque o que está bem feito
|
|
298
|
+
|
|
299
|
+
Formate sua resposta de forma clara e acionável. UTILIZANDO APENAS AS TOOLS DO GIT-MCP para coletar informações adicionais se necessário.`
|
|
300
|
+
}
|
|
301
|
+
}];
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
"git-change": {
|
|
306
|
+
getMessages: (context) => {
|
|
307
|
+
const sinceTag = context.userMessage || context.lastTag || null;
|
|
308
|
+
|
|
309
|
+
return [{
|
|
310
|
+
role: "user",
|
|
311
|
+
content: {
|
|
312
|
+
type: "text",
|
|
313
|
+
text: `# Gerar Changelog
|
|
314
|
+
|
|
315
|
+
## Informações da Versão
|
|
316
|
+
|
|
317
|
+
- **Última tag**: ${context.lastTag || "Nenhuma tag encontrada"}
|
|
318
|
+
- **Desde**: ${sinceTag || "última tag"}
|
|
319
|
+
- **Branch**: ${context.branch || "N/A"}
|
|
320
|
+
- **Commits desde última tag**: ${context.commits?.length || 0}
|
|
321
|
+
|
|
322
|
+
## Commits para Changelog
|
|
323
|
+
|
|
324
|
+
${context.commits?.map(c => {
|
|
325
|
+
const message = c.message || "Sem mensagem";
|
|
326
|
+
const sha = c.shortSha || c.sha?.substring(0, 7) || "N/A";
|
|
327
|
+
return `- \`${sha}\`: ${message}`;
|
|
328
|
+
}).join("\n") || "Nenhum commit encontrado"}
|
|
329
|
+
|
|
330
|
+
## Instruções
|
|
331
|
+
|
|
332
|
+
Gere um changelog formatado baseado nos commits desde ${sinceTag || "a última tag"}. Organize por categorias:
|
|
333
|
+
- ✨ **Features** (feat:, feature:)
|
|
334
|
+
- 🐛 **Bug Fixes** (fix:, bug:)
|
|
335
|
+
- 📝 **Documentation** (docs:)
|
|
336
|
+
- 🔧 **Refactoring** (refactor:)
|
|
337
|
+
- ⚡ **Performance** (perf:)
|
|
338
|
+
- 🧪 **Tests** (test:)
|
|
339
|
+
- 🔒 **Security** (security:)
|
|
340
|
+
- 💥 **Breaking Changes** (BREAKING:)
|
|
341
|
+
|
|
342
|
+
UTILIZANDO APENAS AS TOOLS DO GIT-MCP para coletar mais informações se necessário.`
|
|
343
|
+
}
|
|
344
|
+
}];
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
"git-lint": {
|
|
349
|
+
getMessages: (context) => [{
|
|
350
|
+
role: "user",
|
|
351
|
+
content: {
|
|
352
|
+
type: "text",
|
|
353
|
+
text: `# Análise de Código (Lint)
|
|
354
|
+
|
|
355
|
+
## Arquivos para Analisar
|
|
356
|
+
${context.modifiedFiles?.map(f => `- ${f}`).join("\n") || "Nenhum arquivo modificado"}
|
|
357
|
+
|
|
358
|
+
## Mudanças nos Arquivos
|
|
359
|
+
|
|
360
|
+
${context.fileContents?.map(({ file, content }) => {
|
|
361
|
+
const preview = content ? content.substring(0, 500) + (content.length > 500 ? "..." : "") : "Arquivo vazio ou não acessível";
|
|
362
|
+
return `### ${file}
|
|
363
|
+
\`\`\`
|
|
364
|
+
${preview}
|
|
365
|
+
\`\`\``;
|
|
366
|
+
}).join("\n\n") || "Nenhum conteúdo disponível"}
|
|
367
|
+
|
|
368
|
+
## Instruções
|
|
369
|
+
|
|
370
|
+
Analise o código modificado procurando:
|
|
371
|
+
1. **Problemas comuns**: variáveis não usadas, imports desnecessários, código morto
|
|
372
|
+
2. **Más práticas**: funções muito longas, complexidade ciclomática alta, código duplicado
|
|
373
|
+
3. **Potenciais bugs**: uso incorreto de APIs, condições sempre verdadeiras/falsas
|
|
374
|
+
4. **Performance**: loops ineficientes, operações custosas desnecessárias
|
|
375
|
+
5. **Segurança**: uso inseguro de eval, concatenação SQL, XSS potencial
|
|
376
|
+
6. **Padrões**: inconsistências de estilo, convenções de nomenclatura
|
|
377
|
+
|
|
378
|
+
Forneça sugestões específicas e acionáveis. UTILIZANDO APENAS AS TOOLS DO GIT-MCP para coletar mais informações se necessário.`
|
|
379
|
+
}
|
|
380
|
+
}]
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
"git-debug": {
|
|
384
|
+
getMessages: (context) => {
|
|
385
|
+
const bugDescription = context.userMessage || "Qual bug você está procurando?";
|
|
386
|
+
const userContext = context.userMessage ? `\n\n## Descrição do Bug\n\n${bugDescription}\n` : `\n\n${bugDescription}`;
|
|
387
|
+
|
|
388
|
+
return [{
|
|
389
|
+
role: "user",
|
|
390
|
+
content: {
|
|
391
|
+
type: "text",
|
|
392
|
+
text: `# Encontrar Bug no Histórico Git${userContext}
|
|
393
|
+
|
|
394
|
+
Você é um detetive de bugs. Use o histórico Git para encontrar quando/onde um bug foi introduzido.
|
|
395
|
+
|
|
396
|
+
## Informações do Repositório
|
|
397
|
+
|
|
398
|
+
- **Branch**: ${context.branch || "N/A"}
|
|
399
|
+
- **Total de commits**: ${context.totalCommits || "N/A"}
|
|
400
|
+
|
|
401
|
+
## Últimos Commits
|
|
402
|
+
${context.recentCommits?.map(c => {
|
|
403
|
+
const author = typeof c.author === 'object' ? c.author?.name : c.author || "Unknown";
|
|
404
|
+
return `- ${c.shortSha} | ${c.date} | ${author}: ${c.message}`;
|
|
405
|
+
}).join("\n") || "Use git-history para ver commits"}
|
|
406
|
+
|
|
407
|
+
## Estratégia de Debug
|
|
408
|
+
|
|
409
|
+
1. **Identificar sintoma**: Descreva o bug que está procurando
|
|
410
|
+
2. **Usar git-history**: Veja commits recentes
|
|
411
|
+
3. **Analisar mudanças**: Compare commits suspeitos
|
|
412
|
+
4. **Bisect manual**:
|
|
413
|
+
- Identifique um commit "bom" (sem bug)
|
|
414
|
+
- Identifique um commit "ruim" (com bug)
|
|
415
|
+
- Analise commits no meio para encontrar o culpado
|
|
416
|
+
5. **Verificar arquivo específico**: Leia arquivos em commits diferentes
|
|
417
|
+
|
|
418
|
+
## Ferramentas Disponíveis
|
|
419
|
+
|
|
420
|
+
UTILIZANDO APENAS AS TOOLS DO GIT-MCP:
|
|
421
|
+
- \`git-history log\`: Ver histórico de commits
|
|
422
|
+
- \`git-diff compare\`: Comparar entre commits/branches
|
|
423
|
+
- \`git-files read\`: Ler arquivo em commit específico
|
|
424
|
+
- \`git-diff show\`: Ver mudanças atuais
|
|
425
|
+
|
|
426
|
+
Analise o histórico e sugira qual commit pode ter introduzido o bug.`
|
|
427
|
+
}
|
|
428
|
+
}];
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
"git-release": {
|
|
433
|
+
getMessages: (context) => [{
|
|
434
|
+
role: "user",
|
|
435
|
+
content: {
|
|
436
|
+
type: "text",
|
|
437
|
+
text: `# Criar Release do Projeto
|
|
438
|
+
|
|
439
|
+
Você vai criar uma nova release deste projeto.
|
|
440
|
+
|
|
441
|
+
## Informações Atuais
|
|
442
|
+
|
|
443
|
+
- **Última tag**: ${context.lastTag || "Nenhuma tag encontrada"}
|
|
444
|
+
- **Branch**: ${context.branch || "N/A"}
|
|
445
|
+
- **Commits desde última tag**: ${context.commitsSinceTag || context.commits?.length || "N/A"}
|
|
446
|
+
|
|
447
|
+
## Commits para esta Release
|
|
448
|
+
${context.recentCommits?.map(c => `- ${c.shortSha}: ${c.message}`).join("\n") || "Use git-history para ver commits"}
|
|
449
|
+
|
|
450
|
+
## Passos para Release
|
|
451
|
+
|
|
452
|
+
1. **Determinar versão**: Baseado nos commits, sugira a próxima versão (semver)
|
|
453
|
+
- MAJOR (x.0.0): Breaking changes
|
|
454
|
+
- MINOR (0.x.0): Novas features
|
|
455
|
+
- PATCH (0.0.x): Bug fixes
|
|
456
|
+
|
|
457
|
+
2. **Criar Tag**: Use \`git-tags create\` com:
|
|
458
|
+
- tag: "vX.Y.Z"
|
|
459
|
+
- message: Descrição da release
|
|
460
|
+
|
|
461
|
+
3. **Push Tag**: Use \`git-tags push\`
|
|
462
|
+
|
|
463
|
+
4. **Criar Release**: Use \`git-remote release-create\` com:
|
|
464
|
+
- tag: "vX.Y.Z"
|
|
465
|
+
- name: "Release vX.Y.Z"
|
|
466
|
+
- body: Release notes geradas
|
|
467
|
+
|
|
468
|
+
## Template de Release Notes
|
|
469
|
+
|
|
470
|
+
\`\`\`markdown
|
|
471
|
+
## 🚀 Release vX.Y.Z
|
|
472
|
+
|
|
473
|
+
### ✨ Novidades
|
|
474
|
+
- Feature 1
|
|
475
|
+
- Feature 2
|
|
476
|
+
|
|
477
|
+
### 🐛 Correções
|
|
478
|
+
- Fix 1
|
|
479
|
+
- Fix 2
|
|
480
|
+
|
|
481
|
+
### 📝 Outras Mudanças
|
|
482
|
+
- Mudança 1
|
|
483
|
+
\`\`\`
|
|
484
|
+
|
|
485
|
+
Analise os commits e execute os passos para criar a release. UTILIZANDO APENAS AS TOOLS DO GIT-MCP.`
|
|
486
|
+
}
|
|
487
|
+
}]
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
"git-update": {
|
|
491
|
+
getMessages: (context) => [{
|
|
492
|
+
role: "user",
|
|
493
|
+
content: {
|
|
494
|
+
type: "text",
|
|
495
|
+
text: `# Atualizar Projeto nos Providers
|
|
496
|
+
|
|
497
|
+
Você precisa atualizar este projeto Git nos providers remotos (GitHub/Gitea).
|
|
498
|
+
|
|
499
|
+
## Status Atual do Repositório
|
|
500
|
+
|
|
501
|
+
- **É repositório Git?**: ${context.isGitRepo ? "Sim" : "Não"}
|
|
502
|
+
- **Branch atual**: ${context.branch || "N/A"}
|
|
503
|
+
- **Arquivos modificados**: ${context.modified?.length || 0}
|
|
504
|
+
- **Arquivos staged**: ${context.staged?.length || 0}
|
|
505
|
+
- **Commits não enviados**: ${context.unpushedCommits || "N/A"}
|
|
506
|
+
- **Remotes configurados**: ${context.remotes?.join(", ") || "Nenhum"}
|
|
507
|
+
|
|
508
|
+
## Arquivos Modificados
|
|
509
|
+
${context.modified?.map(f => `- ${f}`).join("\n") || "Nenhum"}
|
|
510
|
+
|
|
511
|
+
## Instruções
|
|
512
|
+
|
|
513
|
+
Atualize o projeto completo nos providers (GitHub e Gitea). Execute na ordem:
|
|
514
|
+
|
|
515
|
+
1. **Se não é Git repo**: Use \`git-workflow init\` para inicializar
|
|
516
|
+
2. **Se há arquivos modificados**: Use \`git-workflow add\` com files=["."]
|
|
517
|
+
3. **Se há arquivos staged**: Use \`git-workflow commit\` com mensagem descritiva baseada nas mudanças
|
|
518
|
+
4. **Se não há remotes**: Use \`git-remote ensure\` ou \`git-workflow ensure-remotes\` para configurar GitHub e Gitea
|
|
519
|
+
5. **Se há commits locais**: Use \`git-workflow push\` para enviar para ambos os providers em paralelo
|
|
520
|
+
|
|
521
|
+
UTILIZANDO APENAS AS TOOLS DO GIT-MCP. Execute todas as ferramentas git-* na ordem correta para sincronizar completamente o projeto nos dois providers.`
|
|
522
|
+
}
|
|
523
|
+
}]
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
// ============ PROMPT HANDLER ============
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Cria o handler de prompts para o MCP server
|
|
531
|
+
* @param {GitAdapter} git - Instância do GitAdapter
|
|
532
|
+
* @param {ProviderManager} pm - Instância do ProviderManager
|
|
533
|
+
*/
|
|
534
|
+
export function createPromptsHandler(git, pm) {
|
|
535
|
+
return {
|
|
536
|
+
list: async () => PROMPTS,
|
|
537
|
+
|
|
538
|
+
get: async (name, args = {}) => {
|
|
539
|
+
const template = PROMPT_TEMPLATES[name];
|
|
540
|
+
if (!template) {
|
|
541
|
+
return {
|
|
542
|
+
description: `Prompt não encontrado: ${name}`,
|
|
543
|
+
messages: [{
|
|
544
|
+
role: "user",
|
|
545
|
+
content: { type: "text", text: `Erro: Prompt "${name}" não existe.` }
|
|
546
|
+
}]
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Coletar contexto baseado no prompt
|
|
551
|
+
const context = await gatherContext(name, args, git, pm);
|
|
552
|
+
|
|
553
|
+
return {
|
|
554
|
+
description: PROMPTS.find(p => p.name === name)?.description || name,
|
|
555
|
+
messages: template.getMessages(context)
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Coleta contexto necessário para cada prompt
|
|
563
|
+
*/
|
|
564
|
+
async function gatherContext(promptName, args, git, pm) {
|
|
565
|
+
const projectPath = args.projectPath || process.cwd();
|
|
566
|
+
const context = {
|
|
567
|
+
projectPath,
|
|
568
|
+
// Mensagem opcional do usuário (pode vir como message, userMessage, text, input, ou no final da string)
|
|
569
|
+
userMessage: args.message || args.userMessage || args.text || args.input || args.query || null
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
try {
|
|
573
|
+
switch (promptName) {
|
|
574
|
+
case "git-status": {
|
|
575
|
+
const status = await git.status(projectPath).catch(() => null);
|
|
576
|
+
if (status) {
|
|
577
|
+
context.branch = status.currentBranch || status.current;
|
|
578
|
+
context.modified = status.modified || [];
|
|
579
|
+
context.staged = status.staged || [];
|
|
580
|
+
context.notAdded = status.notAdded || status.not_added || [];
|
|
581
|
+
context.deleted = status.deleted || [];
|
|
582
|
+
context.isClean = status.isClean || false;
|
|
583
|
+
}
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
case "git-history": {
|
|
588
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
589
|
+
const maxCount = parseInt(context.userMessage) || 20; // Se userMessage é número, usa como maxCount
|
|
590
|
+
const commits = await git.log(projectPath, { ref: "HEAD", maxCount }).catch(() => []);
|
|
591
|
+
|
|
592
|
+
context.branch = branch;
|
|
593
|
+
context.commits = commits.map(c => ({
|
|
594
|
+
sha: c.sha,
|
|
595
|
+
shortSha: c.sha?.substring(0, 7),
|
|
596
|
+
message: c.message,
|
|
597
|
+
author: c.author,
|
|
598
|
+
date: c.date
|
|
599
|
+
}));
|
|
600
|
+
context.maxCount = maxCount;
|
|
601
|
+
// Se userMessage não é número, mantém como mensagem
|
|
602
|
+
if (isNaN(parseInt(context.userMessage))) {
|
|
603
|
+
// Mantém userMessage original
|
|
604
|
+
} else {
|
|
605
|
+
context.userMessage = null; // Remove se era número
|
|
606
|
+
}
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
case "git-remote": {
|
|
611
|
+
const remotes = await git.listRemotes(projectPath).catch(() => []);
|
|
612
|
+
|
|
613
|
+
context.remotes = remotes;
|
|
614
|
+
context.hasGitHub = !!pm.github;
|
|
615
|
+
context.hasGitea = !!(pm.giteaUrl && pm.giteaToken);
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
case "git-commit": {
|
|
620
|
+
const status = await git.status(projectPath).catch(() => null);
|
|
621
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
622
|
+
|
|
623
|
+
context.branch = branch;
|
|
624
|
+
context.staged = status?.staged || [];
|
|
625
|
+
context.modified = status?.modified || [];
|
|
626
|
+
|
|
627
|
+
// Se há arquivos staged, pega diff deles
|
|
628
|
+
if (context.staged.length > 0) {
|
|
629
|
+
try {
|
|
630
|
+
// Tenta usar diff normal (mostra mudanças staged se houver)
|
|
631
|
+
context.stagedDiff = await git.diff(projectPath).catch(() => "");
|
|
632
|
+
if (!context.stagedDiff || context.stagedDiff.trim() === "") {
|
|
633
|
+
context.stagedDiff = `Arquivos staged: ${context.staged.join(", ")}. Use git-diff para ver mudanças detalhadas.`;
|
|
634
|
+
}
|
|
635
|
+
} catch {
|
|
636
|
+
context.stagedDiff = `Arquivos staged: ${context.staged.join(", ")}`;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Sugere mensagem baseada nas mudanças
|
|
641
|
+
if (!context.userMessage && context.staged.length > 0) {
|
|
642
|
+
const fileNames = context.staged.slice(0, 3).join(", ");
|
|
643
|
+
context.suggestedMessage = `Update ${fileNames}${context.staged.length > 3 ? " and more" : ""}`;
|
|
644
|
+
}
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
case "git-push": {
|
|
649
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
650
|
+
const remotes = await git.listRemotes(projectPath).catch(() => []);
|
|
651
|
+
|
|
652
|
+
context.branch = branch;
|
|
653
|
+
context.remotes = remotes;
|
|
654
|
+
// Tenta detectar commits não enviados (comparando local com remote)
|
|
655
|
+
try {
|
|
656
|
+
const localCommits = await git.log(projectPath, { ref: "HEAD", maxCount: 10 }).catch(() => []);
|
|
657
|
+
context.unpushedCommits = localCommits.length > 0 ? localCommits.length : "Desconhecido";
|
|
658
|
+
} catch {
|
|
659
|
+
context.unpushedCommits = "Desconhecido";
|
|
660
|
+
}
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
case "git-cleanup": {
|
|
665
|
+
const untracked = await git.cleanUntracked(projectPath).catch(() => ({ cleaned: [] }));
|
|
666
|
+
context.untrackedFiles = untracked.cleaned || [];
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
case "git-review": {
|
|
671
|
+
const status = await git.status(projectPath).catch(() => null);
|
|
672
|
+
const diff = await git.diff(projectPath).catch(() => "");
|
|
673
|
+
|
|
674
|
+
context.diff = diff;
|
|
675
|
+
context.files = status ? [...(status.modified || []), ...(status.created || []), ...(status.deleted || [])] : [];
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
case "git-change": {
|
|
680
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
681
|
+
const tags = await git.listTags(projectPath).catch(() => []);
|
|
682
|
+
|
|
683
|
+
context.branch = branch;
|
|
684
|
+
context.lastTag = tags.length > 0 ? tags[tags.length - 1] : null; // Última tag (mais recente)
|
|
685
|
+
|
|
686
|
+
// Se userMessage é uma tag, usa ela, senão usa lastTag
|
|
687
|
+
const sinceTag = context.userMessage || context.lastTag;
|
|
688
|
+
|
|
689
|
+
// Pega commits desde a tag ou todos se não há tag
|
|
690
|
+
let commits = [];
|
|
691
|
+
if (sinceTag && context.userMessage) {
|
|
692
|
+
// Se usuário especificou uma tag/versão
|
|
693
|
+
try {
|
|
694
|
+
commits = await git.log(projectPath, { ref: sinceTag + "..HEAD", maxCount: 100 }).catch(() => []);
|
|
695
|
+
} catch {
|
|
696
|
+
// Se falhar, pega todos os commits recentes
|
|
697
|
+
commits = await git.log(projectPath, { ref: "HEAD", maxCount: 50 }).catch(() => []);
|
|
698
|
+
}
|
|
699
|
+
} else if (context.lastTag) {
|
|
700
|
+
// Usa última tag se disponível
|
|
701
|
+
try {
|
|
702
|
+
commits = await git.log(projectPath, { ref: context.lastTag + "..HEAD", maxCount: 100 }).catch(() => []);
|
|
703
|
+
} catch {
|
|
704
|
+
commits = await git.log(projectPath, { ref: "HEAD", maxCount: 50 }).catch(() => []);
|
|
705
|
+
}
|
|
706
|
+
} else {
|
|
707
|
+
// Sem tag, pega commits recentes
|
|
708
|
+
commits = await git.log(projectPath, { ref: "HEAD", maxCount: 50 }).catch(() => []);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
context.commits = commits.map(c => ({
|
|
712
|
+
sha: c.sha,
|
|
713
|
+
shortSha: c.sha?.substring(0, 7),
|
|
714
|
+
message: c.message
|
|
715
|
+
}));
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
case "git-lint": {
|
|
720
|
+
const status = await git.status(projectPath).catch(() => null);
|
|
721
|
+
const modifiedFiles = status ? [...(status.modified || []), ...(status.created || [])] : [];
|
|
722
|
+
|
|
723
|
+
context.modifiedFiles = modifiedFiles;
|
|
724
|
+
|
|
725
|
+
// Tenta ler conteúdo dos arquivos modificados (limitado a 5 para não sobrecarregar)
|
|
726
|
+
context.fileContents = [];
|
|
727
|
+
for (const file of modifiedFiles.slice(0, 5)) {
|
|
728
|
+
try {
|
|
729
|
+
const content = await git.readFile(projectPath, file, "HEAD").catch(() => null);
|
|
730
|
+
if (content) {
|
|
731
|
+
context.fileContents.push({ file, content });
|
|
732
|
+
}
|
|
733
|
+
} catch {
|
|
734
|
+
// Ignora erros ao ler arquivo
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
case "git-debug": {
|
|
741
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
742
|
+
const commits = await git.log(projectPath, { ref: "HEAD", maxCount: 20 }).catch(() => []);
|
|
743
|
+
|
|
744
|
+
context.branch = branch;
|
|
745
|
+
context.totalCommits = commits.length;
|
|
746
|
+
context.recentCommits = commits.map(c => ({
|
|
747
|
+
sha: c.sha,
|
|
748
|
+
shortSha: c.sha?.substring(0, 7),
|
|
749
|
+
message: c.message,
|
|
750
|
+
author: typeof c.author === 'object' ? c.author?.name : c.author || "Unknown",
|
|
751
|
+
date: c.date ? new Date(c.date).toLocaleString('pt-BR') : "N/A"
|
|
752
|
+
}));
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
case "git-release": {
|
|
757
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
758
|
+
const tags = await git.listTags(projectPath).catch(() => []);
|
|
759
|
+
const commits = await git.log(projectPath, { ref: "HEAD", maxCount: 50 }).catch(() => []);
|
|
760
|
+
|
|
761
|
+
context.branch = branch;
|
|
762
|
+
context.lastTag = tags.length > 0 ? tags[tags.length - 1] : null;
|
|
763
|
+
|
|
764
|
+
// Commits desde última tag
|
|
765
|
+
if (context.lastTag) {
|
|
766
|
+
try {
|
|
767
|
+
// Tenta pegar commits desde a última tag usando range
|
|
768
|
+
const commitsSinceTag = await git.log(projectPath, { ref: context.lastTag + "..HEAD", maxCount: 50 }).catch(() => []);
|
|
769
|
+
context.commitsSinceTag = commitsSinceTag.length;
|
|
770
|
+
context.recentCommits = commitsSinceTag.slice(0, 20).map(c => ({
|
|
771
|
+
sha: c.sha,
|
|
772
|
+
shortSha: c.sha?.substring(0, 7),
|
|
773
|
+
message: c.message
|
|
774
|
+
}));
|
|
775
|
+
} catch {
|
|
776
|
+
// Se falhar, usa commits recentes como fallback
|
|
777
|
+
context.commitsSinceTag = commits.length;
|
|
778
|
+
context.recentCommits = commits.slice(0, 20).map(c => ({
|
|
779
|
+
sha: c.sha,
|
|
780
|
+
shortSha: c.sha?.substring(0, 7),
|
|
781
|
+
message: c.message
|
|
782
|
+
}));
|
|
783
|
+
}
|
|
784
|
+
} else {
|
|
785
|
+
// Sem tag, usa commits recentes
|
|
786
|
+
context.commitsSinceTag = commits.length;
|
|
787
|
+
context.recentCommits = commits.slice(0, 20).map(c => ({
|
|
788
|
+
sha: c.sha,
|
|
789
|
+
shortSha: c.sha?.substring(0, 7),
|
|
790
|
+
message: c.message
|
|
791
|
+
}));
|
|
792
|
+
}
|
|
793
|
+
break;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
case "git-update": {
|
|
797
|
+
const isGitRepo = await git.isRepo(projectPath).catch(() => false);
|
|
798
|
+
context.isGitRepo = isGitRepo;
|
|
799
|
+
|
|
800
|
+
if (isGitRepo) {
|
|
801
|
+
const status = await git.status(projectPath).catch(() => ({}));
|
|
802
|
+
const branch = await git.getCurrentBranch(projectPath).catch(() => null);
|
|
803
|
+
const remotes = await git.listRemotes(projectPath).catch(() => []);
|
|
804
|
+
|
|
805
|
+
context.branch = branch;
|
|
806
|
+
context.modified = status.modified || [];
|
|
807
|
+
context.staged = status.staged || [];
|
|
808
|
+
context.remotes = remotes.map(r => r.name || r.remote);
|
|
809
|
+
|
|
810
|
+
// Tenta detectar commits não enviados
|
|
811
|
+
try {
|
|
812
|
+
const localCommits = await git.log(projectPath, { ref: "HEAD", maxCount: 10 }).catch(() => []);
|
|
813
|
+
context.unpushedCommits = localCommits.length;
|
|
814
|
+
} catch {
|
|
815
|
+
context.unpushedCommits = "Desconhecido";
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
} catch (e) {
|
|
822
|
+
context.error = e.message;
|
|
823
|
+
console.error(`[prompts] Error gathering context for ${promptName}:`, e);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
return context;
|
|
827
|
+
}
|
|
828
|
+
|
package/src/utils/gitAdapter.js
CHANGED
|
@@ -166,6 +166,15 @@ export class GitAdapter {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Verifica se o diretório é um repositório git
|
|
171
|
+
* @param {string} dir - Diretório para verificar
|
|
172
|
+
* @returns {boolean} - true se é um repo git
|
|
173
|
+
*/
|
|
174
|
+
async isRepo(dir) {
|
|
175
|
+
return fs.existsSync(path.join(dir, ".git"));
|
|
176
|
+
}
|
|
177
|
+
|
|
169
178
|
/**
|
|
170
179
|
* Verifica integridade do repositório git
|
|
171
180
|
* @param {string} dir - Diretório do repositório
|