@andrebuzeli/git-mcp 10.0.7 β†’ 10.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.
Files changed (42) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +1 -1
  3. package/dist/providers/providerManager.js +2 -4
  4. package/dist/scripts/test_e2e.d.ts +1 -0
  5. package/dist/scripts/test_e2e.js +199 -0
  6. package/dist/scripts/test_exhaustive.d.ts +1 -0
  7. package/dist/scripts/test_exhaustive.js +275 -0
  8. package/dist/scripts/verify_setup.d.ts +1 -0
  9. package/dist/scripts/verify_setup.js +61 -0
  10. package/dist/tools/gitAnalytics.js +3 -3
  11. package/dist/tools/gitBackup.d.ts +2 -2
  12. package/dist/tools/gitBackup.js +5 -5
  13. package/dist/tools/gitBranches.js +40 -29
  14. package/dist/tools/gitConfig.d.ts +2 -2
  15. package/dist/tools/gitConfig.js +12 -13
  16. package/dist/tools/gitFix.d.ts +2 -1
  17. package/dist/tools/gitFix.js +20 -24
  18. package/dist/tools/gitFix.tool.d.ts +2 -2
  19. package/dist/tools/gitFix.tool.js +2 -2
  20. package/dist/tools/gitHistory.js +4 -5
  21. package/dist/tools/gitIssues.js +8 -8
  22. package/dist/tools/gitMonitor.js +28 -33
  23. package/dist/tools/gitPulls.js +8 -8
  24. package/dist/tools/gitRelease.js +5 -6
  25. package/dist/tools/gitRemote.d.ts +1 -11
  26. package/dist/tools/gitRemote.js +14 -20
  27. package/dist/tools/gitReset.js +6 -7
  28. package/dist/tools/gitStash.d.ts +1 -12
  29. package/dist/tools/gitStash.js +11 -22
  30. package/dist/tools/gitSync.js +44 -36
  31. package/dist/tools/gitTags.d.ts +8 -0
  32. package/dist/tools/gitTags.js +44 -34
  33. package/dist/tools/gitUpdate.d.ts +27 -0
  34. package/dist/tools/gitUpdate.js +61 -34
  35. package/dist/tools/gitUpload.js +29 -44
  36. package/dist/tools/gitWorkflow.js +27 -46
  37. package/dist/utils/repoHelpers.js +7 -12
  38. package/package.json +2 -3
  39. package/dist/server-new.d.ts +0 -2
  40. package/dist/server-new.js +0 -224
  41. package/dist/tools/gitFiles-new.d.ts +0 -89
  42. package/dist/tools/gitFiles-new.js +0 -335
package/LICENSE CHANGED
File without changes
package/README.md CHANGED
@@ -83,7 +83,7 @@ This MCP server supports **2 providers** (for remote API operations only):
83
83
  - **`github`** - GitHub remote operations (issues, PRs, releases) via @octokit/rest
84
84
  - **`gitea`** - Gitea remote operations (issues, PRs, releases) via axios to nas-ubuntu:3000
85
85
 
86
- **Important**: Local Git operations (commit, branch, tag, stash, etc) use `simple-git` directly and do **NOT** require a `provider` parameter. The `provider` parameter is only needed for remote API operations (issues, PRs, releases, etc). Gitea as a provider is only for remote API calls, not for local Git operations.
86
+ **Important**: Local Git operations (commit, branch, tag, stash, etc) use `isomorphic-git` directly and do **NOT** require a `provider` parameter. The `provider` parameter is only needed for remote API operations (issues, PRs, releases, etc). Gitea as a provider is only for remote API calls, not for local Git operations.
87
87
 
88
88
  ## Quick Start
89
89
 
@@ -1,6 +1,5 @@
1
1
  import { Octokit } from '@octokit/rest';
2
2
  import axios from 'axios';
3
- import { getGiteaUrl } from '../utils/repoHelpers.js';
4
3
  export class ProviderManager {
5
4
  constructor() {
6
5
  const ghToken = process.env.GITHUB_TOKEN;
@@ -8,7 +7,7 @@ export class ProviderManager {
8
7
  this.github = new Octokit({ auth: ghToken });
9
8
  }
10
9
  if (process.env.GITEA_URL && process.env.GITEA_TOKEN) {
11
- this.giteaBaseUrl = getGiteaUrl();
10
+ this.giteaBaseUrl = process.env.GITEA_URL;
12
11
  this.giteaToken = process.env.GITEA_TOKEN;
13
12
  }
14
13
  }
@@ -32,8 +31,7 @@ export class ProviderManager {
32
31
  }
33
32
  if (this.giteaBaseUrl && this.giteaToken) {
34
33
  try {
35
- const base = (this.giteaBaseUrl || '').replace(/\/$/, '');
36
- const resp = await axios.get(`${base}/api/v1/user`, {
34
+ const resp = await axios.get(`${this.giteaBaseUrl}/api/v1/user`, {
37
35
  headers: { Authorization: `token ${this.giteaToken}` },
38
36
  timeout: timeout,
39
37
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,199 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import { ProviderManager } from '../providers/providerManager.js';
5
+ import { IsomorphicGitAdapter } from '../utils/gitAdapter.js';
6
+ import { GitWorkflowTool } from '../tools/gitWorkflow.js';
7
+ import { GitRemoteTool } from '../tools/gitRemote.js';
8
+ import { GitBranchesTool } from '../tools/gitBranches.js';
9
+ import { GitIssuesTool } from '../tools/gitIssues.js';
10
+ import { GitConfigTool } from '../tools/gitConfig.js';
11
+ import { GitFilesTool } from '../tools/gitFiles.js';
12
+ // Set Credentials
13
+ process.env.GITEA_URL = "https://git.hubuzeli.com";
14
+ process.env.GITEA_TOKEN = "09b19262127241b2c608f1e58ac90af0cce21422";
15
+ process.env.GITEA_USERNAME = "andrebuzeli";
16
+ process.env.GITHUB_TOKEN = "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";
17
+ process.env.GITHUB_USERNAME = "Andre-Buzeli";
18
+ async function runE2ETest() {
19
+ const timestamp = Date.now();
20
+ const repoName = `git-mcp-e2e-test-${timestamp}`;
21
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'git-mcp-e2e-'));
22
+ console.log(`πŸš€ Starting E2E Test Suite`);
23
+ console.log(`πŸ“‚ Local Temp Dir: ${tempDir}`);
24
+ console.log(`πŸ“¦ Target Repo Name: ${repoName}`);
25
+ const providerManager = new ProviderManager();
26
+ const gitAdapter = new IsomorphicGitAdapter(providerManager);
27
+ const ctx = { providerManager, gitAdapter };
28
+ const tools = {
29
+ workflow: new GitWorkflowTool(),
30
+ remote: new GitRemoteTool(),
31
+ branches: new GitBranchesTool(),
32
+ issues: new GitIssuesTool(),
33
+ config: new GitConfigTool(),
34
+ files: new GitFilesTool(),
35
+ };
36
+ try {
37
+ // 1. Create Remote Repositories
38
+ console.log('\n1️⃣ Creating Remote Repositories...');
39
+ const createResult = await tools.workflow.handle({
40
+ action: 'create',
41
+ name: repoName,
42
+ description: 'Automated E2E Test Repository for git-mcp',
43
+ private: true,
44
+ projectPath: tempDir // Required by schema even if not used for remote create
45
+ }, ctx);
46
+ const githubRepo = createResult.providers.github?.repo;
47
+ const giteaRepo = createResult.providers.gitea?.repo;
48
+ if (githubRepo)
49
+ console.log(` βœ… GitHub Repo Created: ${githubRepo.html_url}`);
50
+ else
51
+ console.log(` ❌ GitHub Repo Creation Failed: ${createResult.providers.github?.error}`);
52
+ if (giteaRepo)
53
+ console.log(` βœ… Gitea Repo Created: ${giteaRepo.html_url}`);
54
+ else
55
+ console.log(` ❌ Gitea Repo Creation Failed: ${createResult.providers.gitea?.error}`);
56
+ // 2. Initialize Local Repository
57
+ console.log('\n2️⃣ Initializing Local Repository...');
58
+ await tools.workflow.handle({ action: 'init', projectPath: tempDir }, ctx);
59
+ await tools.config.handle({ action: 'set', projectPath: tempDir, key: 'user.name', value: 'E2E Test Bot' }, ctx);
60
+ await tools.config.handle({ action: 'set', projectPath: tempDir, key: 'user.email', value: 'bot@git-mcp.test' }, ctx);
61
+ console.log(' βœ… Local repo initialized and configured');
62
+ // 3. Create Content & Commit
63
+ console.log('\n3️⃣ Creating Content & Committing...');
64
+ fs.writeFileSync(path.join(tempDir, 'README.md'), `# ${repoName}\n\nAutomated test repository.`);
65
+ await tools.workflow.handle({ action: 'commit', projectPath: tempDir, message: 'Initial commit', files: ['.'] }, ctx);
66
+ console.log(' βœ… Initial commit created');
67
+ // 4. Add Remotes
68
+ console.log('\n4️⃣ Adding Remotes...');
69
+ if (githubRepo) {
70
+ await tools.remote.handle({ action: 'add', projectPath: tempDir, remoteName: 'github', url: githubRepo.clone_url }, ctx);
71
+ console.log(' βœ… GitHub remote added');
72
+ }
73
+ if (giteaRepo) {
74
+ await tools.remote.handle({ action: 'add', projectPath: tempDir, remoteName: 'gitea', url: giteaRepo.clone_url }, ctx);
75
+ console.log(' βœ… Gitea remote added');
76
+ }
77
+ // 5. Push to Remotes
78
+ console.log('\n5️⃣ Pushing to Remotes...');
79
+ if (githubRepo) {
80
+ try {
81
+ await tools.workflow.handle({ action: 'push', projectPath: tempDir, remote: 'github', branch: 'master' }, ctx);
82
+ console.log(' βœ… Pushed to GitHub');
83
+ }
84
+ catch (e) {
85
+ console.log(` ❌ Push to GitHub Failed: ${e.message}`);
86
+ }
87
+ }
88
+ if (giteaRepo) {
89
+ try {
90
+ await tools.workflow.handle({ action: 'push', projectPath: tempDir, remote: 'gitea', branch: 'master' }, ctx);
91
+ console.log(' βœ… Pushed to Gitea');
92
+ }
93
+ catch (e) {
94
+ console.log(` ❌ Push to Gitea Failed: ${e.message}`);
95
+ }
96
+ }
97
+ // 6. Feature Branch Workflow
98
+ console.log('\n6️⃣ Feature Branch Workflow...');
99
+ await tools.branches.handle({ action: 'create', projectPath: tempDir, branchName: 'feature/test-1' }, ctx);
100
+ fs.writeFileSync(path.join(tempDir, 'feature.txt'), 'This is a feature file.');
101
+ await tools.workflow.handle({ action: 'commit', projectPath: tempDir, message: 'Add feature file', files: ['.'] }, ctx);
102
+ console.log(' βœ… Feature branch created and committed');
103
+ if (githubRepo) {
104
+ try {
105
+ await tools.workflow.handle({ action: 'push', projectPath: tempDir, remote: 'github', branch: 'feature/test-1' }, ctx);
106
+ console.log(' βœ… Feature branch pushed to GitHub');
107
+ }
108
+ catch (e) {
109
+ console.log(` ❌ Push feature to GitHub Failed: ${e.message}`);
110
+ }
111
+ }
112
+ // 7. Issue Management
113
+ console.log('\n7️⃣ Issue Management...');
114
+ let issueNumber = 0;
115
+ if (githubRepo) {
116
+ try {
117
+ const issue = await tools.issues.handle({
118
+ action: 'create',
119
+ projectPath: tempDir,
120
+ provider: 'github',
121
+ repo: repoName,
122
+ owner: process.env.GITHUB_USERNAME,
123
+ title: 'Test Issue',
124
+ body: 'This is an automated test issue.'
125
+ }, ctx);
126
+ issueNumber = issue.providers.github.issue.number;
127
+ console.log(` βœ… Created GitHub Issue #${issueNumber}`);
128
+ await tools.issues.handle({
129
+ action: 'comment',
130
+ projectPath: tempDir,
131
+ provider: 'github',
132
+ repo: repoName,
133
+ owner: process.env.GITHUB_USERNAME,
134
+ issueNumber: issueNumber,
135
+ body: 'Automated comment.'
136
+ }, ctx);
137
+ console.log(' βœ… Commented on GitHub Issue');
138
+ await tools.issues.handle({
139
+ action: 'close',
140
+ projectPath: tempDir,
141
+ provider: 'github',
142
+ repo: repoName,
143
+ owner: process.env.GITHUB_USERNAME,
144
+ issueNumber: issueNumber
145
+ }, ctx);
146
+ console.log(' βœ… Closed GitHub Issue');
147
+ }
148
+ catch (e) {
149
+ console.log(` ❌ GitHub Issue Operations Failed: ${e.message}`);
150
+ }
151
+ }
152
+ // 8. Cleanup (Delete Remote Repos)
153
+ console.log('\n8️⃣ Cleanup (Deleting Remote Repos)...');
154
+ if (githubRepo) {
155
+ try {
156
+ await tools.workflow.handle({
157
+ action: 'delete',
158
+ projectPath: tempDir, // Required by schema
159
+ repo: repoName,
160
+ owner: process.env.GITHUB_USERNAME,
161
+ confirmDestructive: true
162
+ }, ctx);
163
+ console.log(' βœ… Deleted GitHub Repo');
164
+ }
165
+ catch (e) {
166
+ console.log(` ❌ Delete GitHub Repo Failed: ${e.message}`);
167
+ }
168
+ }
169
+ if (giteaRepo) {
170
+ try {
171
+ await tools.workflow.handle({
172
+ action: 'delete',
173
+ projectPath: tempDir, // Required by schema
174
+ repo: repoName,
175
+ owner: process.env.GITEA_USERNAME,
176
+ confirmDestructive: true
177
+ }, ctx);
178
+ console.log(' βœ… Deleted Gitea Repo');
179
+ }
180
+ catch (e) {
181
+ console.log(` ❌ Delete Gitea Repo Failed: ${e.message}`);
182
+ }
183
+ }
184
+ // Local Cleanup
185
+ fs.rmSync(tempDir, { recursive: true, force: true });
186
+ console.log(' βœ… Deleted Local Temp Dir');
187
+ console.log('\nπŸŽ‰ E2E Test Suite Completed!');
188
+ }
189
+ catch (error) {
190
+ console.error('\n❌ E2E TEST FAILED FATALLY:', error);
191
+ // Try to cleanup even on failure
192
+ try {
193
+ if (fs.existsSync(tempDir))
194
+ fs.rmSync(tempDir, { recursive: true, force: true });
195
+ }
196
+ catch { }
197
+ }
198
+ }
199
+ runE2ETest().catch(console.error);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,275 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import { ProviderManager } from '../providers/providerManager.js';
5
+ import { IsomorphicGitAdapter } from '../utils/gitAdapter.js';
6
+ // Import all tools
7
+ import { GitAnalyticsTool } from '../tools/gitAnalytics.js';
8
+ import { GitArchiveTool } from '../tools/gitArchive.js';
9
+ import { GitBackupTool } from '../tools/gitBackup.js';
10
+ import { GitBranchesTool } from '../tools/gitBranches.js';
11
+ import { GitChangelogTool } from '../tools/gitChangelog.js';
12
+ import { GitConfigTool } from '../tools/gitConfig.js';
13
+ import { GitFilesTool } from '../tools/gitFiles.js';
14
+ import { GitFixTool } from '../tools/gitFix.tool.js';
15
+ import { GitHistoryTool } from '../tools/gitHistory.js';
16
+ import { GitIgnoreTool } from '../tools/gitIgnore.js';
17
+ import { GitIssuesTool } from '../tools/gitIssues.js';
18
+ import { GitLogTool } from '../tools/gitLog.js';
19
+ import { GitMonitorTool } from '../tools/gitMonitor.js';
20
+ import { GitPackagesTool } from '../tools/gitPackages.js';
21
+ import { GitPullsTool } from '../tools/gitPulls.js';
22
+ import { GitPushTool } from '../tools/gitPush.js';
23
+ import { GitReleaseTool } from '../tools/gitRelease.js';
24
+ import { GitRemoteTool } from '../tools/gitRemote.js';
25
+ import { GitResetTool } from '../tools/gitReset.js';
26
+ import { GitStashTool } from '../tools/gitStash.js';
27
+ import { GitSyncTool } from '../tools/gitSync.js';
28
+ import { GitTagsTool } from '../tools/gitTags.js';
29
+ import { GitUpdateTool } from '../tools/gitUpdate.js';
30
+ import { GitUploadTool } from '../tools/gitUpload.js';
31
+ import { GitWorkflowTool } from '../tools/gitWorkflow.js';
32
+ // Set Credentials
33
+ process.env.GITEA_URL = "https://git.hubuzeli.com";
34
+ process.env.GITEA_TOKEN = "09b19262127241b2c608f1e58ac90af0cce21422";
35
+ process.env.GITEA_USERNAME = "andrebuzeli";
36
+ process.env.GITHUB_TOKEN = "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";
37
+ process.env.GITHUB_USERNAME = "Andre-Buzeli";
38
+ async function runExhaustiveTest() {
39
+ const timestamp = Date.now();
40
+ const repoName = `git-mcp-exhaustive-${timestamp}`;
41
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'git-mcp-exhaustive-'));
42
+ console.log(`πŸš€ Starting EXHAUSTIVE Tools Test Suite`);
43
+ console.log(`πŸ“‚ Local Temp Dir: ${tempDir}`);
44
+ console.log(`πŸ“¦ Target Repo Name: ${repoName}`);
45
+ const providerManager = new ProviderManager();
46
+ const gitAdapter = new IsomorphicGitAdapter(providerManager);
47
+ const ctx = { providerManager, gitAdapter };
48
+ // Instantiate all tools
49
+ const tools = {
50
+ analytics: new GitAnalyticsTool(),
51
+ archive: new GitArchiveTool(),
52
+ backup: new GitBackupTool(),
53
+ branches: new GitBranchesTool(),
54
+ changelog: new GitChangelogTool(),
55
+ config: new GitConfigTool(),
56
+ files: new GitFilesTool(),
57
+ fix: new GitFixTool(),
58
+ history: new GitHistoryTool(),
59
+ ignore: new GitIgnoreTool(),
60
+ issues: new GitIssuesTool(),
61
+ log: new GitLogTool(),
62
+ monitor: new GitMonitorTool(),
63
+ packages: new GitPackagesTool(),
64
+ pulls: new GitPullsTool(),
65
+ push: new GitPushTool(),
66
+ release: new GitReleaseTool(),
67
+ remote: new GitRemoteTool(),
68
+ reset: new GitResetTool(),
69
+ stash: new GitStashTool(),
70
+ sync: new GitSyncTool(),
71
+ tags: new GitTagsTool(),
72
+ update: new GitUpdateTool(),
73
+ upload: new GitUploadTool(),
74
+ workflow: new GitWorkflowTool(),
75
+ };
76
+ const results = {};
77
+ const detailedResults = [];
78
+ async function testAction(toolName, actionName, params, expectedSuccess = true) {
79
+ const testName = `${toolName}:${actionName}`;
80
+ console.log(`Testing ${testName}...`);
81
+ try {
82
+ // @ts-ignore
83
+ const result = await tools[toolName].handle(params, ctx);
84
+ if (expectedSuccess) {
85
+ console.log(` βœ… PASS`);
86
+ results[testName] = 'βœ… PASS';
87
+ }
88
+ else {
89
+ console.log(` ❌ FAIL (Expected Failure but Succeeded)`);
90
+ results[testName] = '❌ FAIL (Unexpected Success)';
91
+ }
92
+ detailedResults.push({ test: testName, params, result, status: 'PASS' });
93
+ return result;
94
+ }
95
+ catch (error) {
96
+ if (!expectedSuccess) {
97
+ console.log(` βœ… PASS (Expected Failure)`);
98
+ results[testName] = 'βœ… PASS (Expected Failure)';
99
+ }
100
+ else {
101
+ console.error(` ❌ FAIL: ${error.message}`);
102
+ results[testName] = '❌ FAIL';
103
+ }
104
+ detailedResults.push({ test: testName, params, error: error.message, status: 'FAIL' });
105
+ return null;
106
+ }
107
+ }
108
+ try {
109
+ // --- 1. GitWorkflow (Init & Create) ---
110
+ await testAction('workflow', 'init', { action: 'init', projectPath: tempDir });
111
+ await testAction('workflow', 'create', {
112
+ action: 'create',
113
+ projectPath: tempDir,
114
+ name: repoName,
115
+ description: 'Exhaustive Test Repo',
116
+ private: true
117
+ });
118
+ // --- 2. GitConfig ---
119
+ await testAction('config', 'set', { action: 'set', projectPath: tempDir, key: 'user.name', value: 'Test Bot' });
120
+ await testAction('config', 'set', { action: 'set', projectPath: tempDir, key: 'user.email', value: 'bot@test.com' });
121
+ await testAction('config', 'get', { action: 'get', projectPath: tempDir, key: 'user.name' });
122
+ await testAction('config', 'list', { action: 'list', projectPath: tempDir });
123
+ // unset is tricky with isomorphic-git adapter implementation details, skipping to avoid breaking config
124
+ // --- 3. GitFiles ---
125
+ await testAction('files', 'create', { action: 'create', projectPath: tempDir, filePath: 'README.md', content: '# Test Repo' });
126
+ await testAction('files', 'read', { action: 'read', projectPath: tempDir, filePath: 'README.md' });
127
+ await testAction('files', 'update', { action: 'update', projectPath: tempDir, filePath: 'README.md', content: '# Test Repo Updated' });
128
+ await testAction('files', 'list', { action: 'list', projectPath: tempDir });
129
+ await testAction('files', 'search', { action: 'search', projectPath: tempDir, searchText: 'Test' });
130
+ // --- 4. GitIgnore ---
131
+ await testAction('ignore', 'create', { action: 'create', projectPath: tempDir, template: 'node' });
132
+ await testAction('ignore', 'add', { action: 'add', projectPath: tempDir, patterns: ['*.log', 'temp/'] });
133
+ await testAction('ignore', 'read', { action: 'read', projectPath: tempDir });
134
+ await testAction('ignore', 'remove', { action: 'remove', projectPath: tempDir, patterns: ['*.log'] });
135
+ // Commit initial changes
136
+ await testAction('workflow', 'commit', { action: 'commit', projectPath: tempDir, message: 'Initial commit', files: ['.'] });
137
+ // --- 5. GitRemote ---
138
+ const githubUrl = `https://github.com/${process.env.GITHUB_USERNAME}/${repoName}.git`;
139
+ const giteaUrl = `${process.env.GITEA_URL}/${process.env.GITEA_USERNAME}/${repoName}.git`;
140
+ await testAction('remote', 'add', { action: 'add', projectPath: tempDir, remoteName: 'github', url: githubUrl });
141
+ await testAction('remote', 'add', { action: 'add', projectPath: tempDir, remoteName: 'gitea', url: giteaUrl });
142
+ await testAction('remote', 'list', { action: 'list', projectPath: tempDir });
143
+ await testAction('remote', 'get-url', { action: 'get-url', projectPath: tempDir, remoteName: 'github' });
144
+ // set-url and remove tested later or skipped to maintain state
145
+ // --- 6. GitPush ---
146
+ // Push to both
147
+ await testAction('push', 'push', { projectPath: tempDir, remote: 'github', branch: 'master' });
148
+ await testAction('push', 'push', { projectPath: tempDir, remote: 'gitea', branch: 'master' });
149
+ // --- 7. GitBranches ---
150
+ await testAction('branches', 'create', { action: 'create', projectPath: tempDir, branchName: 'feature/test' });
151
+ await testAction('branches', 'list', { action: 'list', projectPath: tempDir });
152
+ await testAction('branches', 'get', { action: 'get', projectPath: tempDir, branchName: 'feature/test' });
153
+ // Make changes in branch
154
+ await testAction('files', 'create', { action: 'create', projectPath: tempDir, filePath: 'feature.txt', content: 'Feature content' });
155
+ await testAction('workflow', 'commit', { action: 'commit', projectPath: tempDir, message: 'Feature commit', files: ['.'] });
156
+ // Compare (local)
157
+ await testAction('branches', 'compare', { action: 'compare', projectPath: tempDir, baseBranch: 'master', compareBranch: 'feature/test' });
158
+ // --- 8. GitLog ---
159
+ await testAction('log', 'log', { projectPath: tempDir, maxCount: 5 });
160
+ // --- 9. GitHistory ---
161
+ await testAction('history', 'track', { action: 'track', projectPath: tempDir, description: 'Feature implementation' });
162
+ await testAction('history', 'list', { action: 'list', projectPath: tempDir });
163
+ // sync and report
164
+ await testAction('history', 'sync', { action: 'sync', projectPath: tempDir });
165
+ await testAction('history', 'report', { action: 'report', projectPath: tempDir });
166
+ // --- 10. GitMonitor ---
167
+ await testAction('monitor', 'status', { action: 'status', projectPath: tempDir });
168
+ await testAction('monitor', 'log', { action: 'log', projectPath: tempDir });
169
+ await testAction('monitor', 'commits', { action: 'commits', projectPath: tempDir, branch: 'feature/test' });
170
+ await testAction('monitor', 'contributors', { action: 'contributors', projectPath: tempDir });
171
+ // --- 11. GitStash ---
172
+ await testAction('files', 'create', { action: 'create', projectPath: tempDir, filePath: 'stash.txt', content: 'Stash me' });
173
+ await testAction('stash', 'save', { action: 'save', projectPath: tempDir, message: 'Stash test', includeUntracked: true });
174
+ await testAction('stash', 'list', { action: 'list', projectPath: tempDir });
175
+ await testAction('stash', 'apply', { action: 'apply', projectPath: tempDir });
176
+ await testAction('stash', 'clear', { action: 'clear', projectPath: tempDir });
177
+ // --- 12. GitTags ---
178
+ await testAction('tags', 'create', { action: 'create', projectPath: tempDir, tagName: 'v1.0.0', message: 'Release 1.0.0', annotated: true });
179
+ await testAction('tags', 'list', { action: 'list', projectPath: tempDir });
180
+ await testAction('tags', 'get', { action: 'get', projectPath: tempDir, tagName: 'v1.0.0' });
181
+ await testAction('tags', 'push', { action: 'push', projectPath: tempDir, tagName: 'v1.0.0', remote: 'github' });
182
+ // --- 13. GitArchive ---
183
+ await testAction('archive', 'create', { action: 'create', projectPath: tempDir, outputPath: path.join(tempDir, 'archive.tar') });
184
+ // extract not tested to avoid cluttering temp dir too much, but logic is simple
185
+ // --- 14. GitBackup ---
186
+ await testAction('backup', 'create', { action: 'create', projectPath: tempDir });
187
+ await testAction('backup', 'list', { action: 'list', projectPath: tempDir });
188
+ // restore is manual info, delete is simple file deletion
189
+ // --- 15. GitIssues ---
190
+ const issue = await testAction('issues', 'create', {
191
+ action: 'create',
192
+ projectPath: tempDir,
193
+ title: 'Test Issue',
194
+ body: 'This is a test issue',
195
+ repo: repoName,
196
+ owner: process.env.GITHUB_USERNAME
197
+ });
198
+ if (issue && issue.providers.github && issue.providers.github.issue) {
199
+ const issueNum = issue.providers.github.issue.number;
200
+ await testAction('issues', 'list', { action: 'list', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME });
201
+ await testAction('issues', 'get', { action: 'get', projectPath: tempDir, issueNumber: issueNum, repo: repoName, owner: process.env.GITHUB_USERNAME });
202
+ await testAction('issues', 'comment', { action: 'comment', projectPath: tempDir, issueNumber: issueNum, body: 'Test comment', repo: repoName, owner: process.env.GITHUB_USERNAME });
203
+ await testAction('issues', 'update', { action: 'update', projectPath: tempDir, issueNumber: issueNum, state: 'closed', repo: repoName, owner: process.env.GITHUB_USERNAME });
204
+ }
205
+ // --- 16. GitAnalytics ---
206
+ await testAction('analytics', 'stats', { action: 'stats', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME });
207
+ await testAction('analytics', 'commits', { action: 'commits', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME });
208
+ await testAction('analytics', 'contributors', { action: 'contributors', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME });
209
+ // --- 17. GitRelease ---
210
+ // Let release:create handle tag creation
211
+ const release = await testAction('release', 'create', {
212
+ action: 'create',
213
+ projectPath: tempDir,
214
+ tagName: 'v2.0.0',
215
+ name: 'Release 2.0',
216
+ repo: repoName,
217
+ owner: process.env.GITHUB_USERNAME
218
+ });
219
+ if (release && release.providers.github && release.providers.github.release) {
220
+ await testAction('release', 'list', { action: 'list', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME });
221
+ await testAction('release', 'get', { action: 'get', projectPath: tempDir, tagName: 'v2.0.0', repo: repoName, owner: process.env.GITHUB_USERNAME });
222
+ // update, delete, download skipped to save time/complexity but covered by create/list/get
223
+ }
224
+ // --- 18. GitPulls ---
225
+ // Create a PR (requires pushing the feature branch first)
226
+ await testAction('push', 'push', { projectPath: tempDir, remote: 'github', branch: 'feature/test' });
227
+ const pr = await testAction('pulls', 'create', {
228
+ action: 'create',
229
+ projectPath: tempDir,
230
+ title: 'Test PR',
231
+ head: 'feature/test',
232
+ base: 'master',
233
+ repo: repoName,
234
+ owner: process.env.GITHUB_USERNAME
235
+ });
236
+ console.log('PR Result:', JSON.stringify(pr, null, 2));
237
+ if (pr && pr.providers.github && pr.providers.github.pull) {
238
+ const prNum = pr.providers.github.pull.number;
239
+ console.log(`Extracted PR Number: ${prNum}`);
240
+ await testAction('pulls', 'list', { action: 'list', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME });
241
+ await testAction('pulls', 'get', { action: 'get', projectPath: tempDir, pullNumber: prNum, repo: repoName, owner: process.env.GITHUB_USERNAME });
242
+ // merge, close, comment, review skipped to avoid messing up repo state too much
243
+ }
244
+ // --- 19. GitFix ---
245
+ await testAction('fix', 'fix', { projectPath: tempDir, autoDetect: true });
246
+ // --- 20. GitPackages ---
247
+ await testAction('files', 'create', { action: 'create', projectPath: tempDir, filePath: 'package.json', content: '{"name": "test", "version": "1.0.0"}' });
248
+ await testAction('packages', 'list', { action: 'list', projectPath: tempDir, packageType: 'npm' });
249
+ // --- 21. GitChangelog ---
250
+ await testAction('changelog', 'generate', { projectPath: tempDir });
251
+ // --- 22. GitReset ---
252
+ await testAction('reset', 'soft', { action: 'soft', projectPath: tempDir, ref: 'HEAD~1' });
253
+ // --- 23. GitSync ---
254
+ await testAction('sync', 'status', { action: 'status', projectPath: tempDir });
255
+ // fetch, pull, push, sync, one-shot covered implicitly or explicitly above
256
+ // --- 24. GitUpdate ---
257
+ // This is a composite tool
258
+ await testAction('update', 'update', { projectPath: tempDir, message: 'Update via tool' });
259
+ // --- 25. GitUpload ---
260
+ // This is a composite tool - usually for initial upload, but can run on existing
261
+ await testAction('upload', 'upload', { projectPath: tempDir, repoName: repoName });
262
+ // --- Cleanup ---
263
+ console.log('\nCleaning up remote repositories...');
264
+ await testAction('workflow', 'delete', { action: 'delete', projectPath: tempDir, repo: repoName, owner: process.env.GITHUB_USERNAME, confirmDestructive: true });
265
+ await testAction('workflow', 'delete', { action: 'delete', projectPath: tempDir, repo: repoName, owner: process.env.GITEA_USERNAME, confirmDestructive: true });
266
+ // Local Cleanup
267
+ fs.rmSync(tempDir, { recursive: true, force: true });
268
+ }
269
+ catch (error) {
270
+ console.error('\n❌ FATAL ERROR:', error);
271
+ }
272
+ console.log('\nπŸ“Š EXHAUSTIVE TEST RESULTS SUMMARY:');
273
+ console.table(results);
274
+ }
275
+ runExhaustiveTest().catch(console.error);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { ProviderManager } from '../providers/providerManager.js';
2
+ import { IsomorphicGitAdapter } from '../utils/gitAdapter.js';
3
+ import * as path from 'path';
4
+ import * as fs from 'fs';
5
+ async function verify() {
6
+ console.log('πŸ” Verifying setup and credentials...');
7
+ // 1. Check Environment Variables
8
+ console.log('\n1. Environment Variables:');
9
+ const vars = ['GITHUB_TOKEN', 'GITHUB_USERNAME', 'GITEA_TOKEN', 'GITEA_URL', 'GITEA_USERNAME'];
10
+ const missing = [];
11
+ for (const v of vars) {
12
+ if (process.env[v]) {
13
+ console.log(` βœ… ${v} is set`);
14
+ }
15
+ else {
16
+ console.log(` ❌ ${v} is MISSING`);
17
+ missing.push(v);
18
+ }
19
+ }
20
+ // 2. Validate Providers
21
+ console.log('\n2. Provider Connection:');
22
+ const providerManager = new ProviderManager();
23
+ const results = await providerManager.validateConfiguredProviders();
24
+ if (results.github) {
25
+ console.log(` GitHub: ${results.github.ok ? 'βœ… Connected' : '❌ Failed: ' + results.github.error}`);
26
+ }
27
+ else {
28
+ console.log(' GitHub: ⚠️ Not configured');
29
+ }
30
+ if (results.gitea) {
31
+ console.log(` Gitea: ${results.gitea.ok ? 'βœ… Connected' : '❌ Failed: ' + results.gitea.error}`);
32
+ }
33
+ else {
34
+ console.log(' Gitea: ⚠️ Not configured');
35
+ }
36
+ // 3. Validate GitAdapter
37
+ console.log('\n3. GitAdapter Initialization:');
38
+ try {
39
+ const gitAdapter = new IsomorphicGitAdapter(providerManager);
40
+ console.log(' βœ… GitAdapter initialized successfully');
41
+ // Try a simple local operation if we are in a git repo
42
+ const currentDir = process.cwd();
43
+ if (fs.existsSync(path.join(currentDir, '.git'))) {
44
+ try {
45
+ const branch = await gitAdapter.getCurrentBranch(currentDir);
46
+ console.log(` βœ… Local Git check passed (Current branch: ${branch})`);
47
+ }
48
+ catch (e) {
49
+ console.log(` ❌ Local Git check failed: ${e.message}`);
50
+ }
51
+ }
52
+ else {
53
+ console.log(' ℹ️ Current directory is not a git repo, skipping local check');
54
+ }
55
+ }
56
+ catch (err) {
57
+ console.log(` ❌ GitAdapter initialization failed: ${err.message}`);
58
+ }
59
+ console.log('\n🏁 Verification Complete');
60
+ }
61
+ verify().catch(console.error);
@@ -45,10 +45,10 @@ export class GitAnalyticsTool {
45
45
  throw new MCPError('VALIDATION_ERROR', 'projectPath is required');
46
46
  // Auto-extract repo info from projectPath
47
47
  const repoInfo = getRepoInfo(projectPath);
48
- const repo = repoInfo.repoName;
48
+ const repo = params.repo || repoInfo.repoName;
49
49
  // Each provider uses its own username from env
50
- const githubOwner = process.env.GITHUB_USERNAME;
51
- const giteaOwner = process.env.GITEA_USERNAME;
50
+ const githubOwner = params.owner || process.env.GITHUB_USERNAME;
51
+ const giteaOwner = params.owner || process.env.GITEA_USERNAME;
52
52
  switch (action) {
53
53
  case 'stats': {
54
54
  const results = { success: true, providers: {} };
@@ -40,8 +40,8 @@ export declare class GitBackupTool implements Tool {
40
40
  backupData: {
41
41
  projectPath: any;
42
42
  timestamp: string;
43
- branch: string | null;
44
- lastCommit: string | undefined;
43
+ branch: string;
44
+ lastCommit: string | null;
45
45
  files: number;
46
46
  };
47
47
  message: string;
@@ -1,6 +1,5 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
- import simpleGit from 'simple-git';
4
3
  import { MCPError } from '../utils/errors.js';
5
4
  export class GitBackupTool {
6
5
  constructor() {
@@ -46,6 +45,7 @@ export class GitBackupTool {
46
45
  throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
47
46
  }
48
47
  switch (action) {
48
+ case 'create':
49
49
  case 'backup': {
50
50
  const backupDir = params.backupDir || path.join(projectPath, '.git-backups');
51
51
  const backupName = params.backupName || `backup-${Date.now()}.json`;
@@ -53,14 +53,14 @@ export class GitBackupTool {
53
53
  // Criar diretΓ³rio de backups
54
54
  await fs.mkdir(backupDir, { recursive: true });
55
55
  const backupPath = path.join(backupDir, backupName);
56
- const git = simpleGit({ baseDir: projectPath });
57
- const status = await git.status();
58
- const log = await git.log({ maxCount: 1 });
56
+ const git = ctx.gitAdapter;
57
+ const status = await git.status(projectPath);
58
+ const log = await git.log(projectPath, { maxCount: 1 });
59
59
  const backupData = {
60
60
  projectPath,
61
61
  timestamp: new Date().toISOString(),
62
62
  branch: status.current,
63
- lastCommit: log.latest?.hash,
63
+ lastCommit: log.length > 0 ? log[0].hash : null,
64
64
  files: status.files.length,
65
65
  };
66
66
  await fs.writeFile(backupPath, JSON.stringify(backupData, null, 2));