@andrebuzeli/git-mcp 6.2.3 → 6.3.1

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/dist/index.js CHANGED
@@ -29,6 +29,7 @@ const gitAnalytics_1 = require("./tools/gitAnalytics");
29
29
  const gitUpload_1 = require("./tools/gitUpload");
30
30
  const gitUpdate_1 = require("./tools/gitUpdate");
31
31
  const gitHistory_1 = require("./tools/gitHistory");
32
+ const gitFix_tool_1 = require("./tools/gitFix.tool");
32
33
  const toolsGuide_1 = __importDefault(require("./resources/toolsGuide"));
33
34
  async function main() {
34
35
  // Load optional mcp.json configuration (will populate process.env if values present)
@@ -40,7 +41,7 @@ async function main() {
40
41
  if (process.env.DEBUG) {
41
42
  console.error('Provider validation:', JSON.stringify(validation, null, 2));
42
43
  }
43
- // Register all 20 Git tools
44
+ // Register all 21 Git tools
44
45
  const tools = [
45
46
  new gitWorkflow_1.GitWorkflowTool(),
46
47
  new gitFiles_1.GitFilesTool(),
@@ -62,6 +63,7 @@ async function main() {
62
63
  new gitUpload_1.GitUploadTool(),
63
64
  new gitUpdate_1.GitUpdateTool(),
64
65
  new gitHistory_1.GitHistoryTool(),
66
+ new gitFix_tool_1.GitFixTool(),
65
67
  ];
66
68
  // Register resources
67
69
  const resources = [
@@ -75,7 +77,7 @@ async function main() {
75
77
  // Create MCP Server with STDIO transport
76
78
  const server = new index_js_1.Server({
77
79
  name: '@andrebuzeli/git-mcp',
78
- version: '6.2.2',
80
+ version: '6.3.1',
79
81
  });
80
82
  // Register tool list handler
81
83
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
@@ -0,0 +1,3 @@
1
+ export declare function handleGitFix(args: any): Promise<{
2
+ content: any[];
3
+ }>;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.handleGitFix = handleGitFix;
7
+ const simple_git_1 = __importDefault(require("simple-git"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const promises_1 = __importDefault(require("fs/promises"));
10
+ const fs_1 = require("fs");
11
+ async function handleGitFix(args) {
12
+ try {
13
+ const { projectPath, githubRepo, giteaRepo, autoDetect = true } = args;
14
+ if (!projectPath) {
15
+ throw new Error('projectPath é obrigatório');
16
+ }
17
+ const absolutePath = path_1.default.resolve(projectPath);
18
+ if (!(0, fs_1.existsSync)(absolutePath)) {
19
+ throw new Error(`Caminho não existe: ${absolutePath}`);
20
+ }
21
+ const git = (0, simple_git_1.default)(absolutePath);
22
+ const result = {
23
+ success: false,
24
+ projectPath: absolutePath,
25
+ fixed: [],
26
+ warnings: [],
27
+ errors: [],
28
+ remotes: {
29
+ before: [],
30
+ after: []
31
+ }
32
+ };
33
+ // Verificar se é um repositório Git
34
+ let isGitRepo = false;
35
+ try {
36
+ await git.status();
37
+ isGitRepo = true;
38
+ result.fixed.push('✅ Repositório Git válido encontrado');
39
+ }
40
+ catch (err) {
41
+ if (err.message.includes('not a git repository')) {
42
+ result.warnings.push('⚠️ Não é um repositório Git - inicializando...');
43
+ await git.init();
44
+ result.fixed.push('✅ Git inicializado');
45
+ isGitRepo = true;
46
+ }
47
+ else {
48
+ throw err;
49
+ }
50
+ }
51
+ // Capturar remotes antes
52
+ const remotesBefore = await git.getRemotes(true);
53
+ result.remotes.before = remotesBefore.map(r => ({ name: r.name, url: r.refs.fetch || '' }));
54
+ // Obter usernames das env vars (OBRIGATÓRIO usar as credenciais fornecidas)
55
+ const githubUsername = process.env.GITHUB_USERNAME;
56
+ const giteaUsername = process.env.GITEA_USERNAME;
57
+ if (!githubUsername || !giteaUsername) {
58
+ throw new Error('GITHUB_USERNAME e GITEA_USERNAME são obrigatórios nas env vars');
59
+ }
60
+ // Auto-detectar repos se solicitado
61
+ let finalGithubRepo = githubRepo;
62
+ let finalGiteaRepo = giteaRepo;
63
+ let detectedRepoName = null;
64
+ if (autoDetect && remotesBefore.length > 0) {
65
+ for (const remote of remotesBefore) {
66
+ const url = remote.refs.fetch || '';
67
+ // Detectar APENAS o nome do repo (sem username)
68
+ if (url.includes('github.com') && !detectedRepoName) {
69
+ const match = url.match(/github\.com[:/][^/]+\/([^/.]+)/);
70
+ if (match) {
71
+ detectedRepoName = match[1];
72
+ result.fixed.push(`🔍 Nome do repo auto-detectado: ${detectedRepoName}`);
73
+ }
74
+ }
75
+ // Detectar de Gitea
76
+ if ((url.includes('nas-ubuntu') || url.includes('gitea')) && !detectedRepoName) {
77
+ const match = url.match(/\/[^/]+\/([^/.]+)(?:\.git)?$/);
78
+ if (match) {
79
+ detectedRepoName = match[1];
80
+ result.fixed.push(`🔍 Nome do repo auto-detectado: ${detectedRepoName}`);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ // Construir repos usando os usernames CORRETOS das env vars
86
+ if (detectedRepoName) {
87
+ finalGithubRepo = finalGithubRepo || `${githubUsername}/${detectedRepoName}`;
88
+ finalGiteaRepo = finalGiteaRepo || `${giteaUsername}/${detectedRepoName}`;
89
+ result.fixed.push(`✅ GitHub repo: ${finalGithubRepo}`);
90
+ result.fixed.push(`✅ Gitea repo: ${finalGiteaRepo}`);
91
+ }
92
+ // Se não detectou repos, usar o nome da pasta
93
+ if (!finalGithubRepo || !finalGiteaRepo) {
94
+ const folderName = path_1.default.basename(absolutePath);
95
+ if (!finalGithubRepo) {
96
+ finalGithubRepo = `${githubUsername}/${folderName}`;
97
+ }
98
+ if (!finalGiteaRepo) {
99
+ finalGiteaRepo = `${giteaUsername}/${folderName}`;
100
+ }
101
+ result.warnings.push(`⚠️ Repo não detectado - usando nome da pasta: ${folderName}`);
102
+ result.fixed.push(`✅ GitHub repo: ${finalGithubRepo}`);
103
+ result.fixed.push(`✅ Gitea repo: ${finalGiteaRepo}`);
104
+ }
105
+ // Remover remotes antigos
106
+ const remotesToRemove = ['origin', 'github', 'gitea'];
107
+ for (const remoteName of remotesToRemove) {
108
+ const exists = remotesBefore.find(r => r.name === remoteName);
109
+ if (exists) {
110
+ await git.removeRemote(remoteName);
111
+ result.fixed.push(`🗑️ Removido remote antigo: ${remoteName}`);
112
+ }
113
+ }
114
+ // Adicionar novos remotes no padrão dual
115
+ const giteaUrl = process.env.GITEA_URL || 'http://nas-ubuntu:9999';
116
+ const githubUrl = `https://github.com/${finalGithubRepo}.git`;
117
+ const giteaRepoUrl = `${giteaUrl}/${finalGiteaRepo}.git`;
118
+ await git.addRemote('github', githubUrl);
119
+ result.fixed.push(`✅ Adicionado remote GitHub: ${githubUrl}`);
120
+ await git.addRemote('gitea', giteaRepoUrl);
121
+ result.fixed.push(`✅ Adicionado remote Gitea: ${giteaRepoUrl}`);
122
+ // Configurar origin como push múltiplo
123
+ await git.addRemote('origin', githubUrl);
124
+ await git.addConfig('remote.origin.pushurl', giteaRepoUrl, false, 'local');
125
+ result.fixed.push(`✅ Configurado origin para push dual (GitHub + Gitea)`);
126
+ // Capturar remotes depois
127
+ const remotesAfter = await git.getRemotes(true);
128
+ result.remotes.after = remotesAfter.map(r => ({ name: r.name, url: r.refs.fetch || '' }));
129
+ // Verificar se há commits
130
+ try {
131
+ await git.log();
132
+ result.fixed.push('✅ Histórico de commits preservado');
133
+ }
134
+ catch (err) {
135
+ result.warnings.push('⚠️ Sem commits ainda - faça o primeiro commit');
136
+ }
137
+ // Criar/atualizar .gitignore se necessário
138
+ const gitignorePath = path_1.default.join(absolutePath, '.gitignore');
139
+ if (!(0, fs_1.existsSync)(gitignorePath)) {
140
+ const defaultGitignore = `node_modules/
141
+ dist/
142
+ .env
143
+ *.log
144
+ .DS_Store
145
+ `;
146
+ await promises_1.default.writeFile(gitignorePath, defaultGitignore, 'utf-8');
147
+ result.fixed.push('✅ Criado .gitignore padrão');
148
+ }
149
+ result.success = true;
150
+ return {
151
+ content: [{
152
+ type: 'text',
153
+ text: JSON.stringify(result, null, 2)
154
+ }]
155
+ };
156
+ }
157
+ catch (error) {
158
+ return {
159
+ content: [{
160
+ type: 'text',
161
+ text: JSON.stringify({
162
+ success: false,
163
+ error: error.message,
164
+ stack: error.stack
165
+ }, null, 2)
166
+ }]
167
+ };
168
+ }
169
+ }
@@ -0,0 +1,8 @@
1
+ import { Tool } from '../types';
2
+ export declare class GitFixTool implements Tool {
3
+ name: string;
4
+ description: string;
5
+ handle(args: any): Promise<{
6
+ content: any[];
7
+ }>;
8
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitFixTool = void 0;
4
+ const gitFix_1 = require("./gitFix");
5
+ class GitFixTool {
6
+ constructor() {
7
+ this.name = 'git-fix';
8
+ this.description = `Fix local Git repository to work with dual-provider system (GitHub + Gitea).
9
+
10
+ 🔧 WHAT IT DOES:
11
+ - Converts existing Git repos to dual-provider system
12
+ - Auto-detects GitHub/Gitea remotes from existing configuration
13
+ - Removes old remotes and configures new dual-push system
14
+ - Initializes Git if not already a repository
15
+ - Creates standard .gitignore if missing
16
+
17
+ 📋 PARAMETERS:
18
+ - projectPath (required): Absolute path to the Git repository
19
+ - githubRepo (optional): GitHub repo in format "owner/repo" (auto-detected if not provided)
20
+ - giteaRepo (optional): Gitea repo in format "owner/repo" (auto-detected if not provided)
21
+ - autoDetect (optional): Auto-detect repos from existing remotes (default: true)
22
+
23
+ 🎯 WHEN TO USE:
24
+ - You have an existing Git repo not configured for dual-provider
25
+ - Need to migrate from single remote to dual-push system
26
+ - Want to standardize repo configuration for git-mcp tools
27
+
28
+ ✅ WHAT GETS FIXED:
29
+ 1. Verifies/initializes Git repository
30
+ 2. Captures current remotes (before)
31
+ 3. Auto-detects GitHub/Gitea repos from URLs
32
+ 4. Removes old remotes (origin, github, gitea)
33
+ 5. Adds new 'github' remote
34
+ 6. Adds new 'gitea' remote
35
+ 7. Configures 'origin' for dual-push (GitHub + Gitea)
36
+ 8. Creates .gitignore if missing
37
+ 9. Shows before/after comparison
38
+
39
+ 📊 RESULT STRUCTURE:
40
+ {
41
+ success: boolean,
42
+ projectPath: string,
43
+ fixed: string[], // Actions performed
44
+ warnings: string[], // Non-critical issues
45
+ errors: string[], // Critical issues
46
+ remotes: {
47
+ before: [...], // Remotes before fix
48
+ after: [...] // Remotes after fix
49
+ }
50
+ }
51
+
52
+ 💡 EXAMPLE:
53
+ {
54
+ "projectPath": "/path/to/my-project",
55
+ "autoDetect": true
56
+ }
57
+
58
+ 🔍 AUTO-DETECTION:
59
+ - Scans existing remotes for github.com URLs → extracts owner/repo
60
+ - Scans existing remotes for Gitea URLs → extracts owner/repo
61
+ - Falls back to folder name if no remotes found
62
+
63
+ ⚠️ REQUIREMENTS:
64
+ - GITHUB_USERNAME and GITEA_USERNAME env vars for fallback
65
+ - GITEA_URL env var (default: http://nas-ubuntu:9999)
66
+ - Git must be installed and accessible
67
+ `;
68
+ }
69
+ async handle(args) {
70
+ return (0, gitFix_1.handleGitFix)(args);
71
+ }
72
+ }
73
+ exports.GitFixTool = GitFixTool;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrebuzeli/git-mcp",
3
- "version": "6.2.3",
3
+ "version": "6.3.1",
4
4
  "description": "Professional MCP server for Git operations - STDIO UNIVERSAL: works in ANY IDE (Cursor, VSCode, Claude Desktop). Fully autonomous with intelligent error handling. Auto-detects branches, owner, repo. User-friendly error messages. Dual-provider execution (GitHub + Gitea)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",