@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.
- package/LICENSE +21 -0
- package/README.md +460 -328
- package/dist/.tsbuildinfo +1 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +7 -35
- package/dist/prompts/gitPrompts.d.ts +20 -1
- package/dist/prompts/gitPrompts.d.ts.map +1 -1
- package/dist/prompts/gitPrompts.js +49 -9
- package/dist/prompts/gitPrompts.js.map +1 -1
- package/dist/providers/giteaProvider.d.ts +1 -18
- package/dist/providers/giteaProvider.js +1 -87
- package/dist/providers/githubProvider.d.ts +0 -1
- package/dist/providers/githubProvider.js +0 -1
- package/dist/providers/providerManager.d.ts +0 -15
- package/dist/providers/providerManager.js +0 -65
- package/dist/resources/toolsGuide.d.ts +0 -1
- package/dist/resources/toolsGuide.js +1701 -1702
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -1
- package/dist/tools/gitAnalytics.d.ts +0 -29
- package/dist/tools/gitAnalytics.js +4 -39
- package/dist/tools/gitArchive.d.ts +0 -30
- package/dist/tools/gitArchive.d.ts.map +1 -1
- package/dist/tools/gitArchive.js +1 -32
- package/dist/tools/gitArchive.js.map +1 -1
- package/dist/tools/gitBackup.d.ts +2 -35
- package/dist/tools/gitBackup.d.ts.map +1 -1
- package/dist/tools/gitBackup.js +7 -41
- package/dist/tools/gitBackup.js.map +1 -1
- package/dist/tools/gitBranches.d.ts +0 -49
- package/dist/tools/gitBranches.js +28 -92
- package/dist/tools/gitChangelog.d.ts +37 -1
- package/dist/tools/gitChangelog.d.ts.map +1 -1
- package/dist/tools/gitChangelog.js +67 -2
- package/dist/tools/gitChangelog.js.map +1 -1
- package/dist/tools/gitConfig.d.ts +2 -31
- package/dist/tools/gitConfig.js +9 -38
- package/dist/tools/gitFiles.d.ts +0 -37
- package/dist/tools/gitFiles.js +1 -39
- package/dist/tools/gitFix.d.ts +1 -4
- package/dist/tools/gitFix.js +32 -62
- package/dist/tools/gitFix.tool.d.ts +2 -26
- package/dist/tools/gitFix.tool.js +61 -85
- package/dist/tools/gitHistory.d.ts +5 -18
- package/dist/tools/gitHistory.js +208 -193
- package/dist/tools/gitIgnore.d.ts +0 -24
- package/dist/tools/gitIgnore.js +113 -136
- package/dist/tools/gitIssues.d.ts +0 -79
- package/dist/tools/gitIssues.js +16 -123
- package/dist/tools/gitLog.d.ts +30 -1
- package/dist/tools/gitLog.d.ts.map +1 -1
- package/dist/tools/gitLog.js +46 -2
- package/dist/tools/gitLog.js.map +1 -1
- package/dist/tools/gitMonitor.d.ts +0 -29
- package/dist/tools/gitMonitor.js +18 -47
- package/dist/tools/gitPackages.d.ts +146 -34
- package/dist/tools/gitPackages.js +147 -280
- package/dist/tools/gitPulls.d.ts +0 -66
- package/dist/tools/gitPulls.d.ts.map +1 -1
- package/dist/tools/gitPulls.js +7 -93
- package/dist/tools/gitPulls.js.map +1 -1
- package/dist/tools/gitPush.d.ts +0 -1
- package/dist/tools/gitPush.js +0 -1
- package/dist/tools/gitRelease.d.ts +0 -49
- package/dist/tools/gitRelease.js +6 -122
- package/dist/tools/gitRemote.d.ts +1 -31
- package/dist/tools/gitRemote.js +17 -59
- package/dist/tools/gitReset.d.ts +0 -25
- package/dist/tools/gitReset.js +8 -33
- package/dist/tools/gitStash.d.ts +2 -35
- package/dist/tools/gitStash.js +26 -56
- package/dist/tools/gitSync.d.ts +0 -29
- package/dist/tools/gitSync.js +20 -65
- package/dist/tools/gitTags.d.ts +0 -37
- package/dist/tools/gitTags.d.ts.map +1 -1
- package/dist/tools/gitTags.js +26 -53
- package/dist/tools/gitTags.js.map +1 -1
- package/dist/tools/gitUpdate.d.ts +6 -11
- package/dist/tools/gitUpdate.js +304 -61
- package/dist/tools/gitUpload.d.ts +1 -24
- package/dist/tools/gitUpload.js +50 -45
- package/dist/tools/gitWorkflow.d.ts +0 -27
- package/dist/tools/gitWorkflow.js +55 -87
- package/dist/types.d.ts +0 -7
- package/dist/types.js +0 -1
- package/dist/utils/apiHelpers.d.ts +0 -1
- package/dist/utils/apiHelpers.js +0 -1
- package/dist/utils/errors.d.ts +0 -1
- package/dist/utils/errors.js +0 -1
- package/dist/utils/gitAdapter.d.ts +14 -13
- package/dist/utils/gitAdapter.d.ts.map +1 -1
- package/dist/utils/gitAdapter.js +47 -9
- package/dist/utils/gitAdapter.js.map +1 -1
- package/dist/utils/repoHelpers.d.ts +0 -2
- package/dist/utils/repoHelpers.js +3 -16
- package/dist/utils/safetyController.d.ts +0 -1
- package/dist/utils/safetyController.js +0 -1
- package/dist/utils/safetyController.js.map +1 -1
- package/package.json +87 -96
package/dist/tools/gitHistory.js
CHANGED
|
@@ -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 =
|
|
23
|
+
const git = simpleGit({ baseDir: projectPath });
|
|
23
24
|
switch (action) {
|
|
24
|
-
case '
|
|
25
|
-
|
|
26
|
-
return this.trackChange(git, projectPath, params, ctx);
|
|
27
|
-
|
|
28
|
-
case '
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
case '
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
case '
|
|
37
|
-
|
|
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
|
-
|
|
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 = {
|
|
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
|
-
|
|
47
|
-
const
|
|
48
|
-
const
|
|
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
|
|
52
|
-
|
|
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
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
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({
|
|
66
|
-
|
|
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 = {
|
|
70
|
-
|
|
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`, {
|
|
76
|
-
|
|
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 = {
|
|
80
|
-
|
|
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 {
|
|
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) =>
|
|
101
|
-
|
|
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 = {
|
|
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 =
|
|
112
|
-
const giteaOwner =
|
|
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({
|
|
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 = {
|
|
153
|
-
|
|
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 = {
|
|
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
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|