@andre.buzeli/git-mcp 16.0.5 → 16.0.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andre.buzeli/git-mcp",
3
- "version": "16.0.5",
3
+ "version": "16.0.8",
4
4
  "private": false,
5
5
  "description": "MCP server para Git com operações locais e sincronização paralela GitHub/Gitea",
6
6
  "license": "MIT",
@@ -93,7 +93,9 @@ export class ProviderManager {
93
93
  }
94
94
 
95
95
  async getRemoteUrls(repoName, organization) {
96
- const cacheKey = `urls_${organization || ""}_${repoName}`;
96
+ // When organization is specified, prefix repo name (no actual org needed)
97
+ const effectiveName = organization ? `${organization}---${repoName}` : repoName;
98
+ const cacheKey = `urls_${effectiveName}`;
97
99
  const now = Date.now();
98
100
 
99
101
  // Verificar cache
@@ -106,20 +108,20 @@ export class ProviderManager {
106
108
 
107
109
  const urls = {};
108
110
 
109
- // GitHub URL
111
+ // GitHub URL — always personal account
110
112
  if (this.github) {
111
- const owner = organization || await this.getGitHubOwner();
113
+ const owner = await this.getGitHubOwner();
112
114
  if (owner) {
113
- urls.github = `https://github.com/${owner}/${repoName}.git`;
115
+ urls.github = `https://github.com/${owner}/${effectiveName}.git`;
114
116
  }
115
117
  }
116
118
 
117
- // Gitea URL
119
+ // Gitea URL — always personal account
118
120
  if (this.giteaUrl && this.giteaToken) {
119
- const owner = organization || await this.getGiteaOwner();
121
+ const owner = await this.getGiteaOwner();
120
122
  if (owner) {
121
123
  const base = this.giteaUrl.replace(/\/$/, "");
122
- urls.gitea = `${base}/${owner}/${repoName}.git`;
124
+ urls.gitea = `${base}/${owner}/${effectiveName}.git`;
123
125
  }
124
126
  }
125
127
 
@@ -130,76 +132,27 @@ export class ProviderManager {
130
132
  }
131
133
 
132
134
  async ensureRepos({ repoName, createIfMissing = true, description = "Managed by git-mcpv2", isPublic = false, organization }) {
133
- // Por padrão, repositórios são PRIVADOS. Use isPublic=true para público.
135
+ // When organization is specified, prefix repo name (e.g., "MCP---GIT_MCP")
136
+ const effectiveName = organization ? `${organization}---${repoName}` : repoName;
134
137
  const isPrivate = !isPublic;
135
138
  const results = { github: null, gitea: null };
136
- // GitHub
139
+
140
+ // GitHub — always personal account
137
141
  if (this.github) {
138
- const owner = organization || await this.getGitHubOwner();
142
+ const owner = await this.getGitHubOwner();
139
143
  if (owner) {
140
144
  try {
141
- const full = `${owner}/${repoName}`;
142
145
  try {
143
- await this.github.rest.repos.get({ owner, repo: repoName });
144
- results.github = { ok: true, repo: full, created: false };
146
+ await this.github.rest.repos.get({ owner, repo: effectiveName });
147
+ results.github = { ok: true, repo: `${owner}/${effectiveName}`, created: false };
145
148
  } catch {
146
149
  if (createIfMissing) {
147
- let cr;
148
- if (organization) {
149
- // Tentar criar repo na organização
150
- try {
151
- cr = await this.github.rest.repos.createInOrg({
152
- org: organization,
153
- name: repoName,
154
- description,
155
- private: isPrivate,
156
- auto_init: false,
157
- });
158
- } catch (orgRepoErr) {
159
- const errMsg = String(orgRepoErr?.message || orgRepoErr).toLowerCase();
160
- // Se org não existe, criar a org primeiro e depois o repo
161
- if (errMsg.includes("not found") || errMsg.includes("404")) {
162
- console.error(`[ProviderManager] GitHub org '${organization}' not found, creating...`);
163
- try {
164
- await this.github.rest.orgs.createForAuthenticatedUser
165
- ? await this.github.request("POST /user/orgs", { login: organization, profile_name: organization })
166
- : null;
167
- } catch (orgCreateErr) {
168
- // GitHub free users can't create orgs via API, try alternative
169
- console.error(`[ProviderManager] GitHub org creation failed: ${orgCreateErr?.message}. Trying as user repo with org topic...`);
170
- }
171
- // Retry repo creation in org
172
- try {
173
- cr = await this.github.rest.repos.createInOrg({
174
- org: organization,
175
- name: repoName,
176
- description,
177
- private: isPrivate,
178
- auto_init: false,
179
- });
180
- } catch {
181
- // Fallback: create as personal repo if org creation not possible
182
- console.error(`[ProviderManager] Fallback: creating '${repoName}' as personal repo (GitHub org '${organization}' unavailable)`);
183
- cr = await this.github.rest.repos.createForAuthenticatedUser({
184
- name: repoName,
185
- description: `[org:${organization}] ${description}`,
186
- private: isPrivate,
187
- auto_init: false,
188
- });
189
- }
190
- } else {
191
- throw orgRepoErr;
192
- }
193
- }
194
- } else {
195
- // Criar repo no usuário pessoal
196
- cr = await this.github.rest.repos.createForAuthenticatedUser({
197
- name: repoName,
198
- description,
199
- private: isPrivate,
200
- auto_init: false,
201
- });
202
- }
150
+ const cr = await this.github.rest.repos.createForAuthenticatedUser({
151
+ name: effectiveName,
152
+ description,
153
+ private: isPrivate,
154
+ auto_init: false,
155
+ });
203
156
  results.github = { ok: true, repo: cr.data.full_name, created: true };
204
157
  } else {
205
158
  results.github = { ok: false, error: "missing" };
@@ -210,52 +163,26 @@ export class ProviderManager {
210
163
  }
211
164
  }
212
165
  }
213
- // Gitea
166
+
167
+ // Gitea — always personal account
214
168
  if (this.giteaUrl && this.giteaToken) {
215
- const owner = organization || await this.getGiteaOwner();
169
+ const owner = await this.getGiteaOwner();
216
170
  if (owner) {
217
171
  try {
218
172
  const base = this.giteaUrl.replace(/\/$/, "");
219
- const getRepo = await axios.get(`${base}/api/v1/repos/${owner}/${repoName}`,
173
+ const getRepo = await axios.get(`${base}/api/v1/repos/${owner}/${effectiveName}`,
220
174
  { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
221
175
  if (getRepo.status === 200) {
222
- results.gitea = { ok: true, repo: `${owner}/${repoName}`, created: false };
176
+ results.gitea = { ok: true, repo: `${owner}/${effectiveName}`, created: false };
223
177
  }
224
178
  } catch (e) {
225
179
  if (createIfMissing) {
226
180
  try {
227
- let createUrl;
228
- if (organization) {
229
- // Verificar se org existe, criar se não existir
230
- try {
231
- await axios.get(`${this.giteaUrl}/api/v1/orgs/${organization}`,
232
- { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
233
- } catch (orgCheckErr) {
234
- // Org não existe, criar
235
- console.error(`[ProviderManager] Gitea org '${organization}' not found, creating...`);
236
- try {
237
- await axios.post(`${this.giteaUrl}/api/v1/orgs`, {
238
- username: organization,
239
- full_name: organization,
240
- description: `Organization ${organization}`,
241
- visibility: isPublic ? "public" : "limited",
242
- }, { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
243
- console.error(`[ProviderManager] Gitea org '${organization}' created successfully`);
244
- } catch (orgCreateErr) {
245
- const msg = String(orgCreateErr?.message || orgCreateErr).toLowerCase();
246
- if (!msg.includes("already exists") && !msg.includes("409")) {
247
- console.error(`[ProviderManager] Gitea org creation failed: ${orgCreateErr?.message}`);
248
- }
249
- }
250
- }
251
- createUrl = `${this.giteaUrl}/api/v1/orgs/${organization}/repos`;
252
- } else {
253
- createUrl = `${this.giteaUrl}/api/v1/user/repos`;
254
- }
255
- const cr = await axios.post(createUrl,
256
- { name: repoName, description, private: isPrivate, auto_init: false },
181
+ const base = this.giteaUrl.replace(/\/$/, "");
182
+ const cr = await axios.post(`${base}/api/v1/user/repos`,
183
+ { name: effectiveName, description, private: isPrivate, auto_init: false },
257
184
  { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
258
- results.gitea = { ok: true, repo: `${cr.data?.owner?.login || owner}/${repoName}`, created: true };
185
+ results.gitea = { ok: true, repo: `${cr.data?.owner?.login || owner}/${effectiveName}`, created: true };
259
186
  } catch (err) {
260
187
  results.gitea = { ok: false, error: String(err?.message || err) };
261
188
  }
@@ -616,9 +616,16 @@ export class GitAdapter {
616
616
  }
617
617
 
618
618
  async pushParallel(dir, branch, force = false, organization) {
619
- await this.ensureRemotes(dir, { organization });
619
+ // Check if remotes already configured (caller may have set correct fallback URLs)
620
620
  const remotesStr = await this._exec(dir, ["remote"]);
621
- const remotes = remotesStr.split("\n").filter(r => ["github", "gitea"].includes(r.trim()));
621
+ let remotes = remotesStr.split("\n").filter(r => ["github", "gitea"].includes(r.trim()));
622
+
623
+ // Only setup remotes if none exist — caller is responsible for correct URLs
624
+ if (remotes.length === 0) {
625
+ await this.ensureRemotes(dir, { organization });
626
+ const newStr = await this._exec(dir, ["remote"]);
627
+ remotes = newStr.split("\n").filter(r => ["github", "gitea"].includes(r.trim()));
628
+ }
622
629
 
623
630
  if (remotes.length === 0) {
624
631
  throw createError("REMOTE_NOT_FOUND", { message: "Nenhum remote github/gitea configurado" });
@@ -643,10 +650,13 @@ export class GitAdapter {
643
650
  try {
644
651
  console.error(`[GitAdapter] Auto-fix: repositório não existe no remote '${remote}', criando automaticamente...`);
645
652
  const repoName = getRepoNameFromPath(dir);
646
- const ensured = await this.pm.ensureRepos({ repoName, createIfMissing: true, isPublic: false });
653
+ const ensured = await this.pm.ensureRepos({ repoName, createIfMissing: true, isPublic: false, organization });
647
654
 
648
- // Atualiza remotes após criar repo
649
- await this.ensureRemotes(dir, {});
655
+ // Atualiza remotes após criar repo — use actual result URLs
656
+ const ghUrl = ensured.github?.ok && ensured.github.repo ? `https://github.com/${ensured.github.repo}.git` : "";
657
+ const gtBase = this.pm.giteaUrl?.replace(/\/$/, "");
658
+ const gtUrl = ensured.gitea?.ok && ensured.gitea.repo && gtBase ? `${gtBase}/${ensured.gitea.repo}.git` : "";
659
+ await this.ensureRemotes(dir, { githubUrl: ghUrl, giteaUrl: gtUrl, organization });
650
660
 
651
661
  // Tenta push novamente
652
662
  await this.pushOne(dir, remote, branch, force, true); // Usa -u para criar branch também