@andrebuzeli/git-mcp 9.2.0 → 10.0.0

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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +460 -328
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/config.d.ts +0 -1
  5. package/dist/config.js +0 -1
  6. package/dist/index.d.ts +0 -1
  7. package/dist/index.js +7 -35
  8. package/dist/prompts/gitPrompts.d.ts +20 -1
  9. package/dist/prompts/gitPrompts.d.ts.map +1 -1
  10. package/dist/prompts/gitPrompts.js +49 -9
  11. package/dist/prompts/gitPrompts.js.map +1 -1
  12. package/dist/providers/giteaProvider.d.ts +1 -18
  13. package/dist/providers/giteaProvider.js +1 -87
  14. package/dist/providers/githubProvider.d.ts +0 -1
  15. package/dist/providers/githubProvider.js +0 -1
  16. package/dist/providers/providerManager.d.ts +0 -15
  17. package/dist/providers/providerManager.js +0 -65
  18. package/dist/resources/toolsGuide.d.ts +0 -1
  19. package/dist/resources/toolsGuide.js +1701 -1702
  20. package/dist/server.d.ts +0 -1
  21. package/dist/server.js +0 -1
  22. package/dist/tools/gitAnalytics.d.ts +0 -29
  23. package/dist/tools/gitAnalytics.js +4 -39
  24. package/dist/tools/gitArchive.d.ts +0 -30
  25. package/dist/tools/gitArchive.d.ts.map +1 -1
  26. package/dist/tools/gitArchive.js +1 -32
  27. package/dist/tools/gitArchive.js.map +1 -1
  28. package/dist/tools/gitBackup.d.ts +2 -35
  29. package/dist/tools/gitBackup.d.ts.map +1 -1
  30. package/dist/tools/gitBackup.js +7 -41
  31. package/dist/tools/gitBackup.js.map +1 -1
  32. package/dist/tools/gitBranches.d.ts +0 -49
  33. package/dist/tools/gitBranches.js +28 -92
  34. package/dist/tools/gitChangelog.d.ts +37 -1
  35. package/dist/tools/gitChangelog.d.ts.map +1 -1
  36. package/dist/tools/gitChangelog.js +67 -2
  37. package/dist/tools/gitChangelog.js.map +1 -1
  38. package/dist/tools/gitConfig.d.ts +2 -31
  39. package/dist/tools/gitConfig.js +9 -38
  40. package/dist/tools/gitFiles.d.ts +0 -37
  41. package/dist/tools/gitFiles.js +1 -39
  42. package/dist/tools/gitFix.d.ts +1 -4
  43. package/dist/tools/gitFix.js +32 -62
  44. package/dist/tools/gitFix.tool.d.ts +2 -26
  45. package/dist/tools/gitFix.tool.js +61 -85
  46. package/dist/tools/gitHistory.d.ts +5 -18
  47. package/dist/tools/gitHistory.js +208 -193
  48. package/dist/tools/gitIgnore.d.ts +0 -24
  49. package/dist/tools/gitIgnore.js +113 -136
  50. package/dist/tools/gitIssues.d.ts +0 -79
  51. package/dist/tools/gitIssues.js +16 -123
  52. package/dist/tools/gitLog.d.ts +30 -1
  53. package/dist/tools/gitLog.d.ts.map +1 -1
  54. package/dist/tools/gitLog.js +46 -2
  55. package/dist/tools/gitLog.js.map +1 -1
  56. package/dist/tools/gitMonitor.d.ts +0 -29
  57. package/dist/tools/gitMonitor.js +18 -47
  58. package/dist/tools/gitPackages.d.ts +146 -34
  59. package/dist/tools/gitPackages.js +147 -280
  60. package/dist/tools/gitPulls.d.ts +0 -66
  61. package/dist/tools/gitPulls.d.ts.map +1 -1
  62. package/dist/tools/gitPulls.js +7 -93
  63. package/dist/tools/gitPulls.js.map +1 -1
  64. package/dist/tools/gitPush.d.ts +0 -1
  65. package/dist/tools/gitPush.js +0 -1
  66. package/dist/tools/gitRelease.d.ts +0 -49
  67. package/dist/tools/gitRelease.js +6 -122
  68. package/dist/tools/gitRemote.d.ts +1 -31
  69. package/dist/tools/gitRemote.js +17 -59
  70. package/dist/tools/gitReset.d.ts +0 -25
  71. package/dist/tools/gitReset.js +8 -33
  72. package/dist/tools/gitStash.d.ts +2 -35
  73. package/dist/tools/gitStash.js +26 -56
  74. package/dist/tools/gitSync.d.ts +0 -29
  75. package/dist/tools/gitSync.js +20 -65
  76. package/dist/tools/gitTags.d.ts +0 -37
  77. package/dist/tools/gitTags.d.ts.map +1 -1
  78. package/dist/tools/gitTags.js +26 -53
  79. package/dist/tools/gitTags.js.map +1 -1
  80. package/dist/tools/gitUpdate.d.ts +6 -11
  81. package/dist/tools/gitUpdate.js +304 -61
  82. package/dist/tools/gitUpload.d.ts +1 -24
  83. package/dist/tools/gitUpload.js +50 -45
  84. package/dist/tools/gitWorkflow.d.ts +0 -27
  85. package/dist/tools/gitWorkflow.js +55 -87
  86. package/dist/types.d.ts +0 -7
  87. package/dist/types.js +0 -1
  88. package/dist/utils/apiHelpers.d.ts +0 -1
  89. package/dist/utils/apiHelpers.js +0 -1
  90. package/dist/utils/errors.d.ts +0 -1
  91. package/dist/utils/errors.js +0 -1
  92. package/dist/utils/gitAdapter.d.ts +14 -13
  93. package/dist/utils/gitAdapter.d.ts.map +1 -1
  94. package/dist/utils/gitAdapter.js +47 -9
  95. package/dist/utils/gitAdapter.js.map +1 -1
  96. package/dist/utils/repoHelpers.d.ts +0 -2
  97. package/dist/utils/repoHelpers.js +3 -16
  98. package/dist/utils/safetyController.d.ts +0 -1
  99. package/dist/utils/safetyController.js +0 -1
  100. package/dist/utils/safetyController.js.map +1 -1
  101. package/package.json +87 -96
@@ -1,83 +1,152 @@
1
+ import simpleGit from 'simple-git';
1
2
  import { MCPError } from '../utils/errors.js';
2
3
  import axios from 'axios';
3
4
  import * as fs from 'fs/promises';
4
5
  import * as path from 'path';
5
6
  import { getRepoNameFromPath } from '../utils/repoHelpers.js';
7
+ /**
8
+ * Git History Tool - Mantém histórico detalhado de TODAS alterações
9
+ * Modo DUAL automático - cria issues de histórico em GitHub e Gitea
10
+ * Rastreabilidade completa de cada mudança local
11
+ */
6
12
  export class GitHistoryTool {
7
13
  constructor() {
8
14
  this.name = 'git-history';
9
15
  this.description = 'Maintain detailed history of all project changes with remote tracking via issues - automatic dual-provider execution';
10
- this.inputSchema = {
11
- type: 'object',
12
- properties: { projectPath: { type: 'string' } },
13
- required: ['projectPath'],
14
- additionalProperties: true,
15
- };
16
16
  }
17
17
  async handle(params, ctx) {
18
18
  const projectPath = params.projectPath;
19
- if (!projectPath)
19
+ if (!projectPath) {
20
20
  throw new MCPError('VALIDATION_ERROR', 'projectPath is required');
21
+ }
21
22
  const action = params.action || 'track';
22
- const git = ctx.gitAdapter;
23
+ const git = simpleGit({ baseDir: projectPath });
23
24
  switch (action) {
24
- case 'record':
25
- case 'track':
26
- return this.trackChange(git, projectPath, params, ctx);
27
- case 'list':
28
- case 'report':
29
- return this.generateReport(projectPath, params, ctx);
30
- case 'get':
31
- return this.getHistoryEntry(projectPath, params, ctx);
32
- case 'search':
33
- return this.searchHistory(projectPath, params, ctx);
34
- case 'stats':
35
- return this.getStats(projectPath, params, ctx);
36
- case 'generate_changelog':
37
- return this.generateChangelog(git, projectPath, params, ctx);
25
+ case 'track': {
26
+ // Rastrear mudança específica e criar histórico remoto
27
+ return await this.trackChange(git, projectPath, params, ctx);
28
+ }
29
+ case 'list': {
30
+ // Listar histórico local
31
+ return await this.listLocalHistory(projectPath);
32
+ }
33
+ case 'sync': {
34
+ // Sincronizar histórico local com remoto
35
+ return await this.syncHistory(git, projectPath, params, ctx);
36
+ }
37
+ case 'report': {
38
+ // Gerar relatório consolidado
39
+ return await this.generateReport(projectPath, params, ctx);
40
+ }
38
41
  default:
39
- const validActions = ["record", "list", "get", "search", "stats"];
40
- throw new MCPError('VALIDATION_ERROR', `Unsupported action: ${action}. Valid actions: ${validActions.join(', ')}`);
42
+ throw new MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
41
43
  }
42
44
  }
43
45
  async trackChange(git, projectPath, params, ctx) {
44
- const results = { success: true, timestamp: new Date().toISOString(), projectPath, action: 'track', providers: {}, traceability: { changeDetails: {}, localHistory: null, errors: [] } };
46
+ const results = {
47
+ success: true,
48
+ timestamp: new Date().toISOString(),
49
+ projectPath,
50
+ action: 'track',
51
+ providers: {},
52
+ traceability: {
53
+ changeDetails: {},
54
+ localHistory: null,
55
+ remoteHistory: {},
56
+ errors: [],
57
+ }
58
+ };
45
59
  try {
46
- const status = await git.status(projectPath);
47
- const log = await git.log(projectPath, { maxCount: 1 });
48
- const lastCommit = log[0];
60
+ // 1. Coletar detalhes da mudança
61
+ const status = await git.status();
62
+ const log = await git.log({ maxCount: 1 });
63
+ const lastCommit = log.latest;
49
64
  results.traceability.changeDetails = {
50
65
  branch: status.current,
51
- lastCommit: lastCommit || null,
52
- currentStatus: { modified: status.modified, created: status.created, deleted: status.deleted, staged: status.modified.concat(status.created, status.deleted), conflicted: status.conflicted },
66
+ lastCommit: lastCommit ? {
67
+ hash: lastCommit.hash,
68
+ date: lastCommit.date,
69
+ message: lastCommit.message,
70
+ author: lastCommit.author_name,
71
+ email: lastCommit.author_email,
72
+ } : null,
73
+ currentStatus: {
74
+ modified: status.modified,
75
+ created: status.created,
76
+ deleted: status.deleted,
77
+ staged: status.staged,
78
+ conflicted: status.conflicted,
79
+ },
53
80
  description: params.description || params.message || 'Change tracked via git-history',
54
81
  tags: params.tags || [],
55
82
  category: params.category || 'general',
56
83
  };
57
- results.traceability.localHistory = await this.saveLocalHistory(projectPath, results.traceability.changeDetails);
58
- const githubOwner = await ctx.providerManager.getGitHubUsername();
59
- const giteaOwner = await ctx.providerManager.getGiteaUsername();
84
+ // 2. Salvar no histórico local
85
+ const localHistoryFile = await this.saveLocalHistory(projectPath, results.traceability.changeDetails);
86
+ results.traceability.localHistory = localHistoryFile;
87
+ // 3. Criar issue de histórico em ambos providers
88
+ const githubOwner = params.owner || process.env.GITHUB_USERNAME;
89
+ const giteaOwner = params.owner || process.env.GITEA_USERNAME;
60
90
  const repo = params.repo || getRepoNameFromPath(projectPath);
61
91
  const historyTitle = params.title || `[${results.traceability.changeDetails.category}] ${results.traceability.changeDetails.description}`;
62
92
  const historyBody = this.formatHistoryBody(results.traceability.changeDetails, params);
93
+ // GITHUB
63
94
  if (ctx.providerManager.github) {
64
95
  try {
65
- const issue = await ctx.providerManager.github.rest.issues.create({ owner: githubOwner, repo, title: historyTitle, body: historyBody, labels: ['git-history', results.traceability.changeDetails.category, ...(results.traceability.changeDetails.tags || [])] });
66
- results.providers.github = { success: true, issue: { number: issue.data.number, url: issue.data.html_url, id: issue.data.id } };
96
+ const issue = await ctx.providerManager.github.rest.issues.create({
97
+ owner: githubOwner,
98
+ repo,
99
+ title: historyTitle,
100
+ body: historyBody,
101
+ labels: ['git-history', results.traceability.changeDetails.category, ...results.traceability.changeDetails.tags],
102
+ });
103
+ results.providers.github = {
104
+ success: true,
105
+ issue: {
106
+ number: issue.data.number,
107
+ url: issue.data.html_url,
108
+ id: issue.data.id,
109
+ }
110
+ };
67
111
  }
68
112
  catch (err) {
69
- results.providers.github = { success: false, error: err.message };
70
- results.traceability.errors.push({ provider: 'github', error: err.message, timestamp: new Date().toISOString() });
113
+ results.providers.github = {
114
+ success: false,
115
+ error: err.message,
116
+ };
117
+ results.traceability.errors.push({
118
+ provider: 'github',
119
+ error: err.message,
120
+ timestamp: new Date().toISOString(),
121
+ });
71
122
  }
72
123
  }
124
+ // GITEA
73
125
  if (ctx.providerManager.giteaBaseUrl) {
74
126
  try {
75
- const issue = await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues`, { title: historyTitle, body: historyBody }, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
76
- results.providers.gitea = { success: true, issue: { number: issue.data.number, url: issue.data.html_url, id: issue.data.id } };
127
+ const issue = await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues`, {
128
+ title: historyTitle,
129
+ body: historyBody,
130
+ }, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
131
+ results.providers.gitea = {
132
+ success: true,
133
+ issue: {
134
+ number: issue.data.number,
135
+ url: issue.data.html_url,
136
+ id: issue.data.id,
137
+ }
138
+ };
77
139
  }
78
140
  catch (err) {
79
- results.providers.gitea = { success: false, error: err.message };
80
- results.traceability.errors.push({ provider: 'gitea', error: err.message, timestamp: new Date().toISOString() });
141
+ results.providers.gitea = {
142
+ success: false,
143
+ error: err.message,
144
+ };
145
+ results.traceability.errors.push({
146
+ provider: 'gitea',
147
+ error: err.message,
148
+ timestamp: new Date().toISOString(),
149
+ });
81
150
  }
82
151
  }
83
152
  return results;
@@ -93,38 +162,64 @@ export class GitHistoryTool {
93
162
  await fs.access(historyDir);
94
163
  }
95
164
  catch {
96
- return { success: true, history: [], message: 'No history found' };
165
+ return {
166
+ success: true,
167
+ history: [],
168
+ message: 'No history found',
169
+ };
97
170
  }
98
171
  const files = await fs.readdir(historyDir);
99
172
  const historyFiles = files.filter(f => f.startsWith('history-') && f.endsWith('.json'));
100
- const history = await Promise.all(historyFiles.map(async (file) => JSON.parse(await fs.readFile(path.join(historyDir, file), 'utf-8'))));
101
- return { success: true, count: history.length, history: history.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) };
173
+ const history = await Promise.all(historyFiles.map(async (file) => {
174
+ const content = await fs.readFile(path.join(historyDir, file), 'utf-8');
175
+ return JSON.parse(content);
176
+ }));
177
+ return {
178
+ success: true,
179
+ count: history.length,
180
+ history: history.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()),
181
+ };
102
182
  }
103
183
  catch (err) {
104
184
  throw new MCPError('LIST_ERROR', `Failed to list history: ${err.message}`);
105
185
  }
106
186
  }
107
- async syncHistory(projectPath, params, ctx) {
108
- const results = { success: true, timestamp: new Date().toISOString(), action: 'sync', synced: 0, providers: { github: {}, gitea: {} }, errors: [] };
187
+ async syncHistory(git, projectPath, params, ctx) {
188
+ const results = {
189
+ success: true,
190
+ timestamp: new Date().toISOString(),
191
+ action: 'sync',
192
+ synced: 0,
193
+ providers: { github: {}, gitea: {} },
194
+ errors: [],
195
+ };
109
196
  try {
110
197
  const localHistory = await this.listLocalHistory(projectPath);
111
- const githubOwner = await ctx.providerManager.getGitHubUsername();
112
- const giteaOwner = await ctx.providerManager.getGiteaUsername();
198
+ const githubOwner = params.owner || process.env.GITHUB_USERNAME;
199
+ const giteaOwner = params.owner || process.env.GITEA_USERNAME;
113
200
  const repo = params.repo || getRepoNameFromPath(projectPath);
114
201
  for (const historyEntry of localHistory.history) {
115
202
  if (!historyEntry.synced) {
116
203
  try {
117
204
  const title = `[history-sync] ${historyEntry.description}`;
118
205
  const body = this.formatHistoryBody(historyEntry, params);
206
+ // Sync to GitHub
119
207
  if (ctx.providerManager.github) {
120
208
  try {
121
- await ctx.providerManager.github.rest.issues.create({ owner: githubOwner, repo, title, body, labels: ['git-history', 'synced'] });
209
+ await ctx.providerManager.github.rest.issues.create({
210
+ owner: githubOwner,
211
+ repo,
212
+ title,
213
+ body,
214
+ labels: ['git-history', 'synced'],
215
+ });
122
216
  results.synced++;
123
217
  }
124
218
  catch (err) {
125
219
  results.errors.push({ provider: 'github', error: err.message });
126
220
  }
127
221
  }
222
+ // Sync to Gitea
128
223
  if (ctx.providerManager.giteaBaseUrl) {
129
224
  try {
130
225
  await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues`, { title, body }, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
@@ -149,8 +244,24 @@ export class GitHistoryTool {
149
244
  async generateReport(projectPath, params, ctx) {
150
245
  try {
151
246
  const localHistory = await this.listLocalHistory(projectPath);
152
- const report = { success: true, timestamp: new Date().toISOString(), projectPath, summary: { totalChanges: localHistory.count, byCategory: {}, byMonth: {}, recentChanges: localHistory.history.slice(0, 10) } };
153
- localHistory.history.forEach((entry) => { const cat = entry.category || 'general'; report.summary.byCategory[cat] = (report.summary.byCategory[cat] || 0) + 1; const month = new Date(entry.timestamp).toISOString().slice(0, 7); report.summary.byMonth[month] = (report.summary.byMonth[month] || 0) + 1; });
247
+ const report = {
248
+ success: true,
249
+ timestamp: new Date().toISOString(),
250
+ projectPath,
251
+ summary: {
252
+ totalChanges: localHistory.count,
253
+ byCategory: {},
254
+ byMonth: {},
255
+ recentChanges: localHistory.history.slice(0, 10),
256
+ }
257
+ };
258
+ // Agrupar por categoria
259
+ localHistory.history.forEach((entry) => {
260
+ const cat = entry.category || 'general';
261
+ report.summary.byCategory[cat] = (report.summary.byCategory[cat] || 0) + 1;
262
+ const month = new Date(entry.timestamp).toISOString().slice(0, 7);
263
+ report.summary.byMonth[month] = (report.summary.byMonth[month] || 0) + 1;
264
+ });
154
265
  return report;
155
266
  }
156
267
  catch (err) {
@@ -161,151 +272,55 @@ export class GitHistoryTool {
161
272
  const historyDir = path.join(projectPath, '.git-mcp-history');
162
273
  await fs.mkdir(historyDir, { recursive: true });
163
274
  const historyFile = path.join(historyDir, `history-${Date.now()}.json`);
164
- const historyEntry = { timestamp: new Date().toISOString(), ...changeDetails, synced: false };
275
+ const historyEntry = {
276
+ timestamp: new Date().toISOString(),
277
+ ...changeDetails,
278
+ synced: false,
279
+ };
165
280
  await fs.writeFile(historyFile, JSON.stringify(historyEntry, null, 2), 'utf-8');
166
281
  return historyFile;
167
282
  }
168
283
  formatHistoryBody(changeDetails, params) {
169
- return `## Git History Entry\n\nTimestamp: ${changeDetails.timestamp || new Date().toISOString()}\nCategory: ${changeDetails.category || 'general'}\nBranch: ${changeDetails.branch || 'N/A'}\n\nDescription:\n${changeDetails.description || 'No description provided'}\n`;
170
- }
171
- async generateChangelog(git, projectPath, params, ctx) {
172
- const outputFile = params.outputFile || 'CHANGELOG.md';
173
- const format = params.format || 'keepachangelog';
174
- const since = params.since || 'last-tag';
175
- const results = { success: true, timestamp: new Date().toISOString(), projectPath, action: 'generate_changelog', outputFile, format, changelog: null };
176
- try {
177
- let commits = [];
178
- if (since === 'last-tag') {
179
- const tags = await git.listTags(projectPath);
180
- if (tags.length > 0) {
181
- const lastTag = tags[0];
182
- commits = await git.log(projectPath, { ref: 'HEAD', since: lastTag });
183
- }
184
- else {
185
- commits = await git.log(projectPath);
186
- }
187
- }
188
- else {
189
- commits = await git.log(projectPath, { since });
190
- }
191
- const grouped = this.groupCommitsByType(commits);
192
- const changelogContent = format === 'keepachangelog' ? this.formatKeepAChangelog(grouped, params) : this.formatConventionalChangelog(grouped, params);
193
- results.changelog = changelogContent;
194
- await fs.writeFile(path.join(projectPath, outputFile), changelogContent, 'utf-8');
195
- await git.add(projectPath, [outputFile]);
196
- results.commitHash = await git.commit(projectPath, 'docs: Update CHANGELOG.md');
197
- const remotes = await git.listRemotes(projectPath);
198
- const currentBranch = await git.getCurrentBranch(projectPath);
199
- for (const remote of remotes) {
200
- if (remote.name === 'github' || remote.name === 'gitea' || remote.name === 'origin') {
201
- try {
202
- await git.push(projectPath, remote.name, currentBranch, true);
203
- }
204
- catch (err) { /* ignore push errors for changelog generation */ }
205
- }
206
- }
207
- return results;
208
- }
209
- catch (err) {
210
- throw new MCPError('CHANGELOG_ERROR', `Failed to generate changelog: ${err.message}`);
211
- }
212
- }
213
- groupCommitsByType(commits) { const groups = { added: [], fixed: [], changed: [], removed: [], deprecated: [], security: [], other: [] }; for (const commit of commits) {
214
- const message = commit.commit?.message || commit.message || '';
215
- const firstLine = message.split('\n')[0].toLowerCase();
216
- if (firstLine.includes('feat') || firstLine.includes('add'))
217
- groups.added.push(commit);
218
- else if (firstLine.includes('fix') || firstLine.includes('bug'))
219
- groups.fixed.push(commit);
220
- else if (firstLine.includes('change') || firstLine.includes('update') || firstLine.includes('refactor'))
221
- groups.changed.push(commit);
222
- else if (firstLine.includes('remove') || firstLine.includes('delete'))
223
- groups.removed.push(commit);
224
- else if (firstLine.includes('deprecate'))
225
- groups.deprecated.push(commit);
226
- else if (firstLine.includes('security') || firstLine.includes('vuln'))
227
- groups.security.push(commit);
228
- else
229
- groups.other.push(commit);
230
- } return groups; }
231
- formatKeepAChangelog(grouped, params) { let text = ''; for (const key of Object.keys(grouped)) {
232
- if (grouped[key].length > 0) {
233
- text += `### ${key}\n`;
234
- for (const c of grouped[key]) {
235
- const msg = (c.commit?.message || c.message || '').split('\n')[0];
236
- text += `- ${msg}\n`;
237
- }
238
- text += '\n';
239
- }
240
- } return `# Changelog\n\n${text}`; }
241
- formatConventionalChangelog(grouped, params) { return this.formatKeepAChangelog(grouped, params); }
242
- async getHistoryEntry(projectPath, params, ctx) {
243
- const historyId = params.historyId;
244
- if (!historyId)
245
- throw new MCPError('VALIDATION_ERROR', 'historyId is required for get action');
246
- const historyFile = path.join(projectPath, '.git', 'git-history.json');
247
- try {
248
- const content = await fs.readFile(historyFile, 'utf-8');
249
- const history = JSON.parse(content);
250
- const entry = history.find((h) => h.id === historyId);
251
- if (!entry) {
252
- throw new MCPError('NOT_FOUND', `History entry ${historyId} not found`);
253
- }
254
- return { success: true, entry };
255
- }
256
- catch (err) {
257
- if (err.code === 'ENOENT') {
258
- throw new MCPError('NOT_FOUND', 'No history file found');
259
- }
260
- throw err;
261
- }
262
- }
263
- async searchHistory(projectPath, params, ctx) {
264
- const query = params.query;
265
- if (!query)
266
- throw new MCPError('VALIDATION_ERROR', 'query is required for search action');
267
- const historyFile = path.join(projectPath, '.git', 'git-history.json');
268
- try {
269
- const content = await fs.readFile(historyFile, 'utf-8');
270
- const history = JSON.parse(content);
271
- const results = history.filter((entry) => {
272
- const searchText = JSON.stringify(entry).toLowerCase();
273
- return searchText.includes(query.toLowerCase());
274
- });
275
- return { success: true, results, count: results.length };
276
- }
277
- catch (err) {
278
- if (err.code === 'ENOENT') {
279
- return { success: true, results: [], count: 0 };
280
- }
281
- throw err;
282
- }
283
- }
284
- async getStats(projectPath, params, ctx) {
285
- const historyFile = path.join(projectPath, '.git', 'git-history.json');
286
- try {
287
- const content = await fs.readFile(historyFile, 'utf-8');
288
- const history = JSON.parse(content);
289
- const stats = {
290
- total: history.length,
291
- byCategory: {},
292
- byBranch: {},
293
- recentChanges: history.slice(-10).reverse()
294
- };
295
- history.forEach((entry) => {
296
- const category = entry.changeDetails?.category || 'unknown';
297
- const branch = entry.changeDetails?.branch || 'unknown';
298
- stats.byCategory[category] = (stats.byCategory[category] || 0) + 1;
299
- stats.byBranch[branch] = (stats.byBranch[branch] || 0) + 1;
300
- });
301
- return { success: true, stats };
302
- }
303
- catch (err) {
304
- if (err.code === 'ENOENT') {
305
- return { success: true, stats: { total: 0, byCategory: {}, byBranch: {}, recentChanges: [] } };
306
- }
307
- throw err;
308
- }
284
+ return `
285
+ ## 📜 Git History Entry
286
+
287
+ **Timestamp:** ${changeDetails.timestamp || new Date().toISOString()}
288
+ **Category:** ${changeDetails.category || 'general'}
289
+ **Branch:** ${changeDetails.branch || 'N/A'}
290
+
291
+ ### 📝 Description
292
+ ${changeDetails.description || 'No description provided'}
293
+
294
+ ### 🔧 Last Commit
295
+ ${changeDetails.lastCommit ? `
296
+ - **Hash:** \`${changeDetails.lastCommit.hash}\`
297
+ - **Author:** ${changeDetails.lastCommit.author} (${changeDetails.lastCommit.email})
298
+ - **Date:** ${changeDetails.lastCommit.date}
299
+ - **Message:** ${changeDetails.lastCommit.message}
300
+ ` : 'No recent commit'}
301
+
302
+ ### 📊 Current Status
303
+ ${changeDetails.currentStatus ? `
304
+ - **Modified:** ${changeDetails.currentStatus.modified?.length || 0} files
305
+ - **Created:** ${changeDetails.currentStatus.created?.length || 0} files
306
+ - **Deleted:** ${changeDetails.currentStatus.deleted?.length || 0} files
307
+ - **Staged:** ${changeDetails.currentStatus.staged?.length || 0} files
308
+ - **Conflicted:** ${changeDetails.currentStatus.conflicted?.length || 0} files
309
+ ` : 'No status available'}
310
+
311
+ ${changeDetails.currentStatus?.modified?.length > 0 ? `
312
+ ### 📁 Modified Files
313
+ ${changeDetails.currentStatus.modified.map((f) => `- ${f}`).join('\n')}
314
+ ` : ''}
315
+
316
+ ${changeDetails.tags?.length > 0 ? `
317
+ ### 🏷️ Tags
318
+ ${changeDetails.tags.map((t) => `\`${t}\``).join(', ')}
319
+ ` : ''}
320
+
321
+ ---
322
+ *Generated by git-mcp git-history tool*
323
+ *Tracked at: ${changeDetails.timestamp || new Date().toISOString()}*
324
+ `;
309
325
  }
310
326
  }
311
- //# sourceMappingURL=gitHistory.js.map
@@ -6,29 +6,6 @@ import { Tool, MCPContext } from '../types.js';
6
6
  export declare class GitIgnoreTool implements Tool {
7
7
  name: string;
8
8
  description: string;
9
- inputSchema: {
10
- type: "object";
11
- properties: {
12
- projectPath: {
13
- type: string;
14
- description: string;
15
- };
16
- action: {
17
- type: string;
18
- description: string;
19
- enum: string[];
20
- };
21
- patterns: {
22
- type: string;
23
- items: {
24
- type: string;
25
- };
26
- description: string;
27
- };
28
- };
29
- required: string[];
30
- additionalProperties: boolean;
31
- };
32
9
  handle(params: Record<string, any>, ctx: MCPContext): Promise<{
33
10
  success: boolean;
34
11
  path: string;
@@ -212,4 +189,3 @@ export declare class GitIgnoreTool implements Tool {
212
189
  }>;
213
190
  private getTemplate;
214
191
  }
215
- //# sourceMappingURL=gitIgnore.d.ts.map