@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.
@@ -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
+