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