@andrebuzeli/git-mcp 4.0.20 → 4.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +7 -239
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -221
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -16
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +1 -69
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +150 -711
- package/dist/server.js.map +1 -1
- package/dist/tools/git-analytics.d.ts +1 -0
- package/dist/tools/git-analytics.d.ts.map +1 -1
- package/dist/tools/git-analytics.js +18 -7
- package/dist/tools/git-analytics.js.map +1 -1
- package/dist/tools/git-archive.d.ts +2 -149
- package/dist/tools/git-archive.d.ts.map +1 -1
- package/dist/tools/git-archive.js +5 -222
- package/dist/tools/git-archive.js.map +1 -1
- package/dist/tools/git-backup.d.ts +1 -198
- package/dist/tools/git-backup.d.ts.map +1 -1
- package/dist/tools/git-backup.js +4 -805
- package/dist/tools/git-backup.js.map +1 -1
- package/dist/tools/git-branches.d.ts +1 -158
- package/dist/tools/git-branches.d.ts.map +1 -1
- package/dist/tools/git-branches.js +4 -539
- package/dist/tools/git-branches.js.map +1 -1
- package/dist/tools/git-config.d.ts +2 -124
- package/dist/tools/git-config.d.ts.map +1 -1
- package/dist/tools/git-config.js +5 -263
- package/dist/tools/git-config.js.map +1 -1
- package/dist/tools/git-files.d.ts +2 -115
- package/dist/tools/git-files.d.ts.map +1 -1
- package/dist/tools/git-files.js +161 -407
- package/dist/tools/git-files.js.map +1 -1
- package/dist/tools/git-issues.d.ts +1 -214
- package/dist/tools/git-issues.d.ts.map +1 -1
- package/dist/tools/git-issues.js +4 -678
- package/dist/tools/git-issues.js.map +1 -1
- package/dist/tools/git-monitor.d.ts +1 -143
- package/dist/tools/git-monitor.d.ts.map +1 -1
- package/dist/tools/git-monitor.js +4 -738
- package/dist/tools/git-monitor.js.map +1 -1
- package/dist/tools/git-packages.d.ts +2 -91
- package/dist/tools/git-packages.d.ts.map +1 -1
- package/dist/tools/git-packages.js +5 -258
- package/dist/tools/git-packages.js.map +1 -1
- package/dist/tools/git-pulls.d.ts +1 -63
- package/dist/tools/git-pulls.d.ts.map +1 -1
- package/dist/tools/git-pulls.js +4 -77
- package/dist/tools/git-pulls.js.map +1 -1
- package/dist/tools/git-release.d.ts +1 -169
- package/dist/tools/git-release.d.ts.map +1 -1
- package/dist/tools/git-release.js +4 -611
- package/dist/tools/git-release.js.map +1 -1
- package/dist/tools/git-remote.d.ts +1 -153
- package/dist/tools/git-remote.d.ts.map +1 -1
- package/dist/tools/git-remote.js +4 -555
- package/dist/tools/git-remote.js.map +1 -1
- package/dist/tools/git-reset.d.ts +1 -157
- package/dist/tools/git-reset.d.ts.map +1 -1
- package/dist/tools/git-reset.js +4 -597
- package/dist/tools/git-reset.js.map +1 -1
- package/dist/tools/git-stash.d.ts +1 -161
- package/dist/tools/git-stash.d.ts.map +1 -1
- package/dist/tools/git-stash.js +4 -640
- package/dist/tools/git-stash.js.map +1 -1
- package/dist/tools/git-sync.d.ts +1 -0
- package/dist/tools/git-sync.d.ts.map +1 -1
- package/dist/tools/git-sync.js +13 -7
- package/dist/tools/git-sync.js.map +1 -1
- package/dist/tools/git-tags.d.ts +1 -162
- package/dist/tools/git-tags.d.ts.map +1 -1
- package/dist/tools/git-tags.js +4 -549
- package/dist/tools/git-tags.js.map +1 -1
- package/dist/tools/git-workflow.d.ts +3 -96
- package/dist/tools/git-workflow.d.ts.map +1 -1
- package/dist/tools/git-workflow.js +287 -314
- package/dist/tools/git-workflow.js.map +1 -1
- package/package.json +3 -3
- package/dist/server-minimal.d.ts +0 -8
- package/dist/server-minimal.d.ts.map +0 -1
- package/dist/server-minimal.js +0 -218
- package/dist/server-minimal.js.map +0 -1
|
@@ -1,748 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.gitMonitorTool = void 0;
|
|
4
|
-
const zod_1 = require("zod");
|
|
5
4
|
const auto_detection_js_1 = require("../utils/auto-detection.js");
|
|
6
|
-
const error_handler_js_1 = require("../utils/error-handler.js");
|
|
7
|
-
const git_operations_js_1 = require("../utils/git-operations.js");
|
|
8
|
-
/**
|
|
9
|
-
* Tool: git-monitor
|
|
10
|
-
*
|
|
11
|
-
* SISTEMA DE MONITORAMENTO AVANÇADO
|
|
12
|
-
* Status completo, métricas de produtividade, análise de saúde do projeto
|
|
13
|
-
*
|
|
14
|
-
* DESIGNED FOR: Programador individual autônomo
|
|
15
|
-
* PHILOSOPHY: Monitoramento inteligente em uma única ferramenta
|
|
16
|
-
*/
|
|
17
|
-
const GitMonitorInputSchema = zod_1.z.discriminatedUnion('action', [
|
|
18
|
-
// PROJECT STATUS - Visão completa
|
|
19
|
-
zod_1.z.object({
|
|
20
|
-
action: zod_1.z.literal('status'),
|
|
21
|
-
projectPath: zod_1.z.string(),
|
|
22
|
-
detailed: zod_1.z.boolean().default(true),
|
|
23
|
-
includeMetrics: zod_1.z.boolean().default(true)
|
|
24
|
-
}),
|
|
25
|
-
// ACTIVITY HISTORY - Histórico detalhado
|
|
26
|
-
zod_1.z.object({
|
|
27
|
-
action: zod_1.z.literal('history'),
|
|
28
|
-
projectPath: zod_1.z.string(),
|
|
29
|
-
since: zod_1.z.string().optional(), // ISO date or relative (1d, 1w, 1m)
|
|
30
|
-
limit: zod_1.z.number().default(50),
|
|
31
|
-
type: zod_1.z.enum(['all', 'commits', 'releases', 'issues']).default('all')
|
|
32
|
-
}),
|
|
33
|
-
// PRODUCTIVITY METRICS - Métricas de produtividade
|
|
34
|
-
zod_1.z.object({
|
|
35
|
-
action: zod_1.z.literal('metrics'),
|
|
36
|
-
projectPath: zod_1.z.string(),
|
|
37
|
-
period: zod_1.z.string().default('30d'), // 1d, 7d, 30d, 90d
|
|
38
|
-
includeCharts: zod_1.z.boolean().default(false)
|
|
39
|
-
}),
|
|
40
|
-
// PROJECT HEALTH - Saúde geral
|
|
41
|
-
zod_1.z.object({
|
|
42
|
-
action: zod_1.z.literal('health'),
|
|
43
|
-
projectPath: zod_1.z.string(),
|
|
44
|
-
deep: zod_1.z.boolean().default(false), // Análise profunda
|
|
45
|
-
suggestions: zod_1.z.boolean().default(true)
|
|
46
|
-
}),
|
|
47
|
-
// RECENT ACTIVITY - Atividade recente
|
|
48
|
-
zod_1.z.object({
|
|
49
|
-
action: zod_1.z.literal('activity'),
|
|
50
|
-
projectPath: zod_1.z.string(),
|
|
51
|
-
hours: zod_1.z.number().default(24),
|
|
52
|
-
includeRemote: zod_1.z.boolean().default(true)
|
|
53
|
-
})
|
|
54
|
-
]);
|
|
55
|
-
/**
|
|
56
|
-
* Project Status Analyzer
|
|
57
|
-
* Analisa o status completo do projeto
|
|
58
|
-
*/
|
|
59
|
-
class ProjectStatusAnalyzer {
|
|
60
|
-
static async getBasicStatus(projectPath) {
|
|
61
|
-
const gitOps = new git_operations_js_1.GitOperations(projectPath);
|
|
62
|
-
try {
|
|
63
|
-
// Git status
|
|
64
|
-
const statusResult = await gitOps.status({});
|
|
65
|
-
const isGitRepo = statusResult.success;
|
|
66
|
-
if (!isGitRepo) {
|
|
67
|
-
return {
|
|
68
|
-
isGitRepo: false,
|
|
69
|
-
status: 'not_initialized',
|
|
70
|
-
message: 'Projeto não é um repositório Git'
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
// Branch info
|
|
74
|
-
const branchResult = await gitOps.runCommand('git', ['branch', '--show-current']);
|
|
75
|
-
const currentBranch = branchResult.success ? branchResult.output.trim() : 'unknown';
|
|
76
|
-
// Remote info
|
|
77
|
-
const remoteResult = await gitOps.runCommand('git', ['remote', '-v']);
|
|
78
|
-
const hasRemotes = remoteResult.success && remoteResult.output.trim();
|
|
79
|
-
// Recent commits
|
|
80
|
-
const logResult = await gitOps.runCommand('git', ['log', '--oneline', '-5']);
|
|
81
|
-
const recentCommits = logResult.success ?
|
|
82
|
-
logResult.output.trim().split('\n').filter(line => line.trim()) : [];
|
|
83
|
-
// Uncommitted changes
|
|
84
|
-
const changesResult = await gitOps.runCommand('git', ['status', '--porcelain']);
|
|
85
|
-
const hasChanges = changesResult.success && changesResult.output.trim();
|
|
86
|
-
return {
|
|
87
|
-
isGitRepo: true,
|
|
88
|
-
currentBranch: currentBranch,
|
|
89
|
-
hasRemotes: hasRemotes,
|
|
90
|
-
recentCommits: recentCommits,
|
|
91
|
-
hasUncommittedChanges: hasChanges,
|
|
92
|
-
lastCommit: recentCommits.length > 0 ? recentCommits[0] : null
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
catch (error) {
|
|
96
|
-
return {
|
|
97
|
-
isGitRepo: false,
|
|
98
|
-
error: error instanceof Error ? error.message : String(error)
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
static async getDetailedMetrics(projectPath) {
|
|
103
|
-
const gitOps = new git_operations_js_1.GitOperations(projectPath);
|
|
104
|
-
try {
|
|
105
|
-
// Commit statistics
|
|
106
|
-
const commitStats = await this.getCommitStats(gitOps);
|
|
107
|
-
// File statistics
|
|
108
|
-
const fileStats = await this.getFileStats(gitOps);
|
|
109
|
-
// Branch statistics
|
|
110
|
-
const branchStats = await this.getBranchStats(gitOps);
|
|
111
|
-
// Size metrics
|
|
112
|
-
const sizeStats = await this.getSizeStats(projectPath);
|
|
113
|
-
return {
|
|
114
|
-
commits: commitStats,
|
|
115
|
-
files: fileStats,
|
|
116
|
-
branches: branchStats,
|
|
117
|
-
size: sizeStats,
|
|
118
|
-
calculatedAt: new Date().toISOString()
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
return {
|
|
123
|
-
error: error instanceof Error ? error.message : String(error)
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
static async getCommitStats(gitOps) {
|
|
128
|
-
try {
|
|
129
|
-
// Total commits
|
|
130
|
-
const totalResult = await gitOps.runCommand('git', ['rev-list', '--count', 'HEAD']);
|
|
131
|
-
const totalCommits = totalResult.success ? parseInt(totalResult.output.trim()) : 0;
|
|
132
|
-
// Commits this month
|
|
133
|
-
const monthResult = await gitOps.runCommand('git', ['rev-list', '--count', '--since=30.days', 'HEAD']);
|
|
134
|
-
const commitsThisMonth = monthResult.success ? parseInt(monthResult.output.trim()) : 0;
|
|
135
|
-
// Commits this week
|
|
136
|
-
const weekResult = await gitOps.runCommand('git', ['rev-list', '--count', '--since=7.days', 'HEAD']);
|
|
137
|
-
const commitsThisWeek = weekResult.success ? parseInt(weekResult.output.trim()) : 0;
|
|
138
|
-
// Author stats
|
|
139
|
-
const authorResult = await gitOps.runCommand('git', ['shortlog', '-sn', '--no-merges']);
|
|
140
|
-
const authors = authorResult.success ?
|
|
141
|
-
authorResult.output.trim().split('\n').map(line => {
|
|
142
|
-
const match = line.trim().match(/(\d+)\s+(.+)/);
|
|
143
|
-
return match ? { commits: parseInt(match[1]), author: match[2] } : null;
|
|
144
|
-
}).filter(Boolean) : [];
|
|
145
|
-
return {
|
|
146
|
-
total: totalCommits,
|
|
147
|
-
thisMonth: commitsThisMonth,
|
|
148
|
-
thisWeek: commitsThisWeek,
|
|
149
|
-
authors: authors,
|
|
150
|
-
avgPerDay: totalCommits / 30 // Rough estimate
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
return { error: 'Could not get commit stats' };
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
static async getFileStats(gitOps) {
|
|
158
|
-
try {
|
|
159
|
-
// File count
|
|
160
|
-
const fileCountResult = await gitOps.runCommand('git', ['ls-files']);
|
|
161
|
-
const totalFiles = fileCountResult.success ?
|
|
162
|
-
fileCountResult.output.trim().split('\n').filter(line => line.trim()).length : 0;
|
|
163
|
-
// File types
|
|
164
|
-
const fileTypeResult = await gitOps.runCommand('git', ['ls-files', '|', 'sed', 's/.*\\.//']);
|
|
165
|
-
const fileTypes = fileTypeResult.success ?
|
|
166
|
-
fileTypeResult.output.trim().split('\n')
|
|
167
|
-
.filter(line => line.trim() && line.includes('.'))
|
|
168
|
-
.map(line => line.split('.').pop())
|
|
169
|
-
.reduce((acc, type) => {
|
|
170
|
-
acc[type] = (acc[type] || 0) + 1;
|
|
171
|
-
return acc;
|
|
172
|
-
}, {}) : {};
|
|
173
|
-
return {
|
|
174
|
-
total: totalFiles,
|
|
175
|
-
byType: fileTypes
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
return { error: 'Could not get file stats' };
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
static async getBranchStats(gitOps) {
|
|
183
|
-
try {
|
|
184
|
-
// All branches
|
|
185
|
-
const branchResult = await gitOps.runCommand('git', ['branch', '-a']);
|
|
186
|
-
const branches = branchResult.success ?
|
|
187
|
-
branchResult.output.trim().split('\n')
|
|
188
|
-
.map(line => line.trim().replace(/^\*\s*/, ''))
|
|
189
|
-
.filter(line => line && !line.startsWith('remotes/')) : [];
|
|
190
|
-
// Remote branches
|
|
191
|
-
const remoteBranchResult = await gitOps.runCommand('git', ['branch', '-r']);
|
|
192
|
-
const remoteBranches = remoteBranchResult.success ?
|
|
193
|
-
remoteBranchResult.output.trim().split('\n')
|
|
194
|
-
.map(line => line.trim())
|
|
195
|
-
.filter(line => line) : [];
|
|
196
|
-
return {
|
|
197
|
-
local: branches.length,
|
|
198
|
-
remote: remoteBranches.length,
|
|
199
|
-
total: branches.length + remoteBranches.length,
|
|
200
|
-
branches: branches.slice(0, 10) // Top 10
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
catch (error) {
|
|
204
|
-
return { error: 'Could not get branch stats' };
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
static async getSizeStats(projectPath) {
|
|
208
|
-
const gitOps = new git_operations_js_1.GitOperations(projectPath);
|
|
209
|
-
try {
|
|
210
|
-
// Repository size
|
|
211
|
-
const sizeResult = await gitOps.runCommand('git', ['count-objects', '-v']);
|
|
212
|
-
const sizeData = sizeResult.success ? {} : {};
|
|
213
|
-
// Working directory size (rough estimate)
|
|
214
|
-
const duResult = await gitOps.runCommand('du', ['-sh', '.']);
|
|
215
|
-
const workDirSize = duResult.success ? duResult.output.trim().split('\t')[0] : 'unknown';
|
|
216
|
-
return {
|
|
217
|
-
repository: sizeData,
|
|
218
|
-
workingDirectory: workDirSize
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
catch (error) {
|
|
222
|
-
return { error: 'Could not get size stats' };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Productivity Metrics Calculator
|
|
228
|
-
* Calcula métricas de produtividade baseadas em dados Git
|
|
229
|
-
*/
|
|
230
|
-
class ProductivityMetrics {
|
|
231
|
-
static async calculateMetrics(projectPath, period) {
|
|
232
|
-
const gitOps = new git_operations_js_1.GitOperations(projectPath);
|
|
233
|
-
try {
|
|
234
|
-
// Parse period
|
|
235
|
-
const days = this.parsePeriod(period);
|
|
236
|
-
// Commit frequency
|
|
237
|
-
const commitFreq = await this.getCommitFrequency(gitOps, days);
|
|
238
|
-
// Code churn (lines added/removed)
|
|
239
|
-
const codeChurn = await this.getCodeChurn(gitOps, days);
|
|
240
|
-
// File changes
|
|
241
|
-
const fileChanges = await this.getFileChanges(gitOps, days);
|
|
242
|
-
// Working hours (rough estimate based on commit times)
|
|
243
|
-
const workingHours = await this.estimateWorkingHours(gitOps, days);
|
|
244
|
-
return {
|
|
245
|
-
period: period,
|
|
246
|
-
days: days,
|
|
247
|
-
commitFrequency: commitFreq,
|
|
248
|
-
codeChurn: codeChurn,
|
|
249
|
-
fileChanges: fileChanges,
|
|
250
|
-
estimatedWorkingHours: workingHours,
|
|
251
|
-
calculatedAt: new Date().toISOString()
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
catch (error) {
|
|
255
|
-
return { error: 'Could not calculate metrics' };
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
static parsePeriod(period) {
|
|
259
|
-
const match = period.match(/^(\d+)([dwmy])$/);
|
|
260
|
-
if (!match)
|
|
261
|
-
return 30; // default 30 days
|
|
262
|
-
const value = parseInt(match[1]);
|
|
263
|
-
const unit = match[2];
|
|
264
|
-
switch (unit) {
|
|
265
|
-
case 'd': return value;
|
|
266
|
-
case 'w': return value * 7;
|
|
267
|
-
case 'm': return value * 30;
|
|
268
|
-
case 'y': return value * 365;
|
|
269
|
-
default: return 30;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
static async getCommitFrequency(gitOps, days) {
|
|
273
|
-
try {
|
|
274
|
-
const result = await gitOps.runCommand('git', ['log', `--since=${days}.days.ago`, '--oneline']);
|
|
275
|
-
const commits = result.success ?
|
|
276
|
-
result.output.trim().split('\n').filter(line => line.trim()) : [];
|
|
277
|
-
return {
|
|
278
|
-
total: commits.length,
|
|
279
|
-
perDay: commits.length / days,
|
|
280
|
-
perWeek: commits.length / (days / 7),
|
|
281
|
-
trend: commits.length > 0 ? 'active' : 'inactive'
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
catch (error) {
|
|
285
|
-
return { error: 'Could not calculate commit frequency' };
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
static async getCodeChurn(gitOps, days) {
|
|
289
|
-
try {
|
|
290
|
-
const result = await gitOps.runCommand('git', ['log', `--since=${days}.days.ago`, '--numstat']);
|
|
291
|
-
const lines = result.success ? result.output.trim().split('\n') : [];
|
|
292
|
-
let added = 0;
|
|
293
|
-
let removed = 0;
|
|
294
|
-
lines.forEach(line => {
|
|
295
|
-
const match = line.match(/^(\d+)\s+(\d+)/);
|
|
296
|
-
if (match) {
|
|
297
|
-
added += parseInt(match[1]);
|
|
298
|
-
removed += parseInt(match[2]);
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
return {
|
|
302
|
-
linesAdded: added,
|
|
303
|
-
linesRemoved: removed,
|
|
304
|
-
linesChanged: added + removed,
|
|
305
|
-
netChange: added - removed
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
catch (error) {
|
|
309
|
-
return { error: 'Could not calculate code churn' };
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
static async getFileChanges(gitOps, days) {
|
|
313
|
-
try {
|
|
314
|
-
const result = await gitOps.runCommand('git', ['log', `--since=${days}.days.ago`, '--name-status']);
|
|
315
|
-
const lines = result.success ? result.output.trim().split('\n') : [];
|
|
316
|
-
const fileChanges = {};
|
|
317
|
-
lines.forEach(line => {
|
|
318
|
-
const match = line.match(/^([AMD])\s+(.+)/);
|
|
319
|
-
if (match) {
|
|
320
|
-
const action = match[1];
|
|
321
|
-
const file = match[2];
|
|
322
|
-
fileChanges[file] = action;
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
const changeTypes = {
|
|
326
|
-
added: Object.values(fileChanges).filter(action => action === 'A').length,
|
|
327
|
-
modified: Object.values(fileChanges).filter(action => action === 'M').length,
|
|
328
|
-
deleted: Object.values(fileChanges).filter(action => action === 'D').length
|
|
329
|
-
};
|
|
330
|
-
return {
|
|
331
|
-
totalFiles: Object.keys(fileChanges).length,
|
|
332
|
-
byType: changeTypes,
|
|
333
|
-
mostChangedFile: Object.keys(fileChanges)[0] || null
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
catch (error) {
|
|
337
|
-
return { error: 'Could not calculate file changes' };
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
static async estimateWorkingHours(gitOps, days) {
|
|
341
|
-
try {
|
|
342
|
-
// Get commit times
|
|
343
|
-
const result = await gitOps.runCommand('git', ['log', `--since=${days}.days.ago`, '--format=%ai']);
|
|
344
|
-
const timestamps = result.success ?
|
|
345
|
-
result.output.trim().split('\n')
|
|
346
|
-
.filter(line => line.trim())
|
|
347
|
-
.map(line => new Date(line)) : [];
|
|
348
|
-
if (timestamps.length === 0) {
|
|
349
|
-
return { total: 0, perDay: 0 };
|
|
350
|
-
}
|
|
351
|
-
// Group by day
|
|
352
|
-
const daysMap = {};
|
|
353
|
-
timestamps.forEach(timestamp => {
|
|
354
|
-
const day = timestamp.toDateString();
|
|
355
|
-
if (!daysMap[day]) {
|
|
356
|
-
daysMap[day] = [];
|
|
357
|
-
}
|
|
358
|
-
daysMap[day].push(timestamp.getHours() + timestamp.getMinutes() / 60);
|
|
359
|
-
});
|
|
360
|
-
// Estimate hours per day (rough heuristic)
|
|
361
|
-
let totalHours = 0;
|
|
362
|
-
Object.values(daysMap).forEach((dayCommits) => {
|
|
363
|
-
if (dayCommits.length > 0) {
|
|
364
|
-
const sorted = dayCommits.sort((a, b) => a - b);
|
|
365
|
-
const span = sorted[sorted.length - 1] - sorted[0];
|
|
366
|
-
// Assume minimum 1 hour if there are commits, max 8 hours
|
|
367
|
-
totalHours += Math.max(1, Math.min(span, 8));
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
return {
|
|
371
|
-
total: Math.round(totalHours * 10) / 10,
|
|
372
|
-
perDay: Math.round((totalHours / days) * 10) / 10,
|
|
373
|
-
activeDays: Object.keys(daysMap).length
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
catch (error) {
|
|
377
|
-
return { error: 'Could not estimate working hours' };
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Health Analyzer
|
|
383
|
-
* Avalia a saúde geral do projeto
|
|
384
|
-
*/
|
|
385
|
-
class HealthAnalyzer {
|
|
386
|
-
static async analyzeHealth(projectPath, deep = false) {
|
|
387
|
-
try {
|
|
388
|
-
const basicStatus = await ProjectStatusAnalyzer.getBasicStatus(projectPath);
|
|
389
|
-
const metrics = deep ? await ProjectStatusAnalyzer.getDetailedMetrics(projectPath) : null;
|
|
390
|
-
// Calculate health score
|
|
391
|
-
let healthScore = 100;
|
|
392
|
-
const issues = [];
|
|
393
|
-
const suggestions = [];
|
|
394
|
-
// Basic checks
|
|
395
|
-
if (!basicStatus.isGitRepo) {
|
|
396
|
-
healthScore -= 50;
|
|
397
|
-
issues.push('Projeto não é um repositório Git');
|
|
398
|
-
suggestions.push('Inicialize o Git: git init');
|
|
399
|
-
}
|
|
400
|
-
if (!basicStatus.hasRemotes) {
|
|
401
|
-
healthScore -= 20;
|
|
402
|
-
issues.push('Nenhum remote configurado');
|
|
403
|
-
suggestions.push('Configure um remote: git remote add origin <url>');
|
|
404
|
-
}
|
|
405
|
-
if (basicStatus.hasUncommittedChanges) {
|
|
406
|
-
healthScore -= 10;
|
|
407
|
-
issues.push('Há mudanças não commitadas');
|
|
408
|
-
suggestions.push('Commite as mudanças: git add . && git commit -m "message"');
|
|
409
|
-
}
|
|
410
|
-
if (metrics) {
|
|
411
|
-
// Deep analysis
|
|
412
|
-
if (metrics.commits?.thisWeek === 0) {
|
|
413
|
-
healthScore -= 15;
|
|
414
|
-
issues.push('Nenhuma atividade esta semana');
|
|
415
|
-
suggestions.push('Continue desenvolvendo ativamente');
|
|
416
|
-
}
|
|
417
|
-
if (metrics.branches?.total > 10) {
|
|
418
|
-
healthScore -= 10;
|
|
419
|
-
issues.push('Muitos branches ativos');
|
|
420
|
-
suggestions.push('Limpe branches antigos: git branch -d <branch>');
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return {
|
|
424
|
-
score: Math.max(0, healthScore),
|
|
425
|
-
status: healthScore >= 80 ? 'excellent' : healthScore >= 60 ? 'good' : healthScore >= 40 ? 'fair' : 'poor',
|
|
426
|
-
issues: issues,
|
|
427
|
-
suggestions: suggestions,
|
|
428
|
-
analyzedAt: new Date().toISOString(),
|
|
429
|
-
deepAnalysis: deep
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
catch (error) {
|
|
433
|
-
return {
|
|
434
|
-
score: 0,
|
|
435
|
-
status: 'error',
|
|
436
|
-
issues: ['Erro na análise de saúde'],
|
|
437
|
-
suggestions: ['Verifique se o projeto existe e é acessível'],
|
|
438
|
-
error: error instanceof Error ? error.message : String(error)
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Classe principal para executar operações Git monitor
|
|
445
|
-
*/
|
|
446
|
-
class GitMonitorExecutor {
|
|
447
|
-
errorHandler = new error_handler_js_1.UniversalErrorHandler();
|
|
448
|
-
/**
|
|
449
|
-
* Executa operação status
|
|
450
|
-
*/
|
|
451
|
-
async executeStatus(detection, input) {
|
|
452
|
-
try {
|
|
453
|
-
const basicStatus = await ProjectStatusAnalyzer.getBasicStatus(detection.projectPath);
|
|
454
|
-
let detailedMetrics = null;
|
|
455
|
-
if (input.includeMetrics && basicStatus.isGitRepo) {
|
|
456
|
-
detailedMetrics = await ProjectStatusAnalyzer.getDetailedMetrics(detection.projectPath);
|
|
457
|
-
}
|
|
458
|
-
return (0, auto_detection_js_1.createUniversalResponse)({
|
|
459
|
-
success: true,
|
|
460
|
-
action: 'status',
|
|
461
|
-
message: 'Project status retrieved successfully',
|
|
462
|
-
data: {
|
|
463
|
-
basic: basicStatus,
|
|
464
|
-
metrics: detailedMetrics,
|
|
465
|
-
detailed: input.detailed
|
|
466
|
-
},
|
|
467
|
-
autoDetected: {
|
|
468
|
-
repo: detection.repoName,
|
|
469
|
-
owner: detection.owner,
|
|
470
|
-
providers: detection.providers
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
catch (error) {
|
|
475
|
-
return this.errorHandler.toUniversalResponse();
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Executa operação history
|
|
480
|
-
*/
|
|
481
|
-
async executeHistory(detection, input) {
|
|
482
|
-
try {
|
|
483
|
-
const gitOps = new git_operations_js_1.GitOperations(detection.projectPath);
|
|
484
|
-
// Parse since parameter
|
|
485
|
-
let since = '';
|
|
486
|
-
if (input.since) {
|
|
487
|
-
if (input.since.match(/^\d+[dwmy]$/)) {
|
|
488
|
-
since = `--since=${input.since}`;
|
|
489
|
-
}
|
|
490
|
-
else {
|
|
491
|
-
since = `--since=${input.since}`;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
// Get commit history
|
|
495
|
-
const logArgs = ['log', '--oneline', `--max-count=${input.limit}`];
|
|
496
|
-
if (since)
|
|
497
|
-
logArgs.push(since);
|
|
498
|
-
const logResult = await gitOps.runCommand('git', logArgs);
|
|
499
|
-
const commits = logResult.success ?
|
|
500
|
-
logResult.output.trim().split('\n').filter(line => line.trim()) : [];
|
|
501
|
-
return (0, auto_detection_js_1.createUniversalResponse)({
|
|
502
|
-
success: true,
|
|
503
|
-
action: 'history',
|
|
504
|
-
message: `Found ${commits.length} historical entries`,
|
|
505
|
-
data: {
|
|
506
|
-
entries: commits,
|
|
507
|
-
type: input.type,
|
|
508
|
-
since: input.since,
|
|
509
|
-
limit: input.limit,
|
|
510
|
-
total: commits.length
|
|
511
|
-
},
|
|
512
|
-
autoDetected: {
|
|
513
|
-
repo: detection.repoName,
|
|
514
|
-
owner: detection.owner,
|
|
515
|
-
providers: detection.providers
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
catch (error) {
|
|
520
|
-
return this.errorHandler.toUniversalResponse();
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
/**
|
|
524
|
-
* Executa operação metrics
|
|
525
|
-
*/
|
|
526
|
-
async executeMetrics(detection, input) {
|
|
527
|
-
try {
|
|
528
|
-
const metrics = await ProductivityMetrics.calculateMetrics(detection.projectPath, input.period);
|
|
529
|
-
return (0, auto_detection_js_1.createUniversalResponse)({
|
|
530
|
-
success: true,
|
|
531
|
-
action: 'metrics',
|
|
532
|
-
message: `Productivity metrics calculated for ${input.period}`,
|
|
533
|
-
data: {
|
|
534
|
-
...metrics,
|
|
535
|
-
includeCharts: input.includeCharts
|
|
536
|
-
},
|
|
537
|
-
autoDetected: {
|
|
538
|
-
repo: detection.repoName,
|
|
539
|
-
owner: detection.owner,
|
|
540
|
-
providers: detection.providers
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
catch (error) {
|
|
545
|
-
return this.errorHandler.toUniversalResponse();
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Executa operação health
|
|
550
|
-
*/
|
|
551
|
-
async executeHealth(detection, input) {
|
|
552
|
-
try {
|
|
553
|
-
const health = await HealthAnalyzer.analyzeHealth(detection.projectPath, input.deep);
|
|
554
|
-
return (0, auto_detection_js_1.createUniversalResponse)({
|
|
555
|
-
success: true,
|
|
556
|
-
action: 'health',
|
|
557
|
-
message: `Health analysis completed - Score: ${health.score}/100`,
|
|
558
|
-
data: {
|
|
559
|
-
...health,
|
|
560
|
-
suggestions: input.suggestions ? health.suggestions : undefined
|
|
561
|
-
},
|
|
562
|
-
autoDetected: {
|
|
563
|
-
repo: detection.repoName,
|
|
564
|
-
owner: detection.owner,
|
|
565
|
-
providers: detection.providers
|
|
566
|
-
}
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
catch (error) {
|
|
570
|
-
return this.errorHandler.toUniversalResponse();
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Executa operação activity
|
|
575
|
-
*/
|
|
576
|
-
async executeActivity(detection, input) {
|
|
577
|
-
try {
|
|
578
|
-
const gitOps = new git_operations_js_1.GitOperations(detection.projectPath);
|
|
579
|
-
// Get recent commits
|
|
580
|
-
const hours = input.hours;
|
|
581
|
-
const logResult = await gitOps.runCommand('git', ['log', '--oneline', `--since=${hours} hours ago`]);
|
|
582
|
-
const commits = logResult.success ?
|
|
583
|
-
logResult.output.trim().split('\n').filter(line => line.trim()) : [];
|
|
584
|
-
// Get recent branches if requested
|
|
585
|
-
let branches = [];
|
|
586
|
-
if (input.includeRemote) {
|
|
587
|
-
try {
|
|
588
|
-
const branchResult = await gitOps.runCommand('git', ['branch', '-r', '--sort=-committerdate']);
|
|
589
|
-
branches = branchResult.success ?
|
|
590
|
-
branchResult.output.trim().split('\n')
|
|
591
|
-
.filter(line => line.trim())
|
|
592
|
-
.slice(0, 5) : []; // Top 5 recent remote branches
|
|
593
|
-
}
|
|
594
|
-
catch (e) {
|
|
595
|
-
// Ignore branch errors
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
return (0, auto_detection_js_1.createUniversalResponse)({
|
|
599
|
-
success: true,
|
|
600
|
-
action: 'activity',
|
|
601
|
-
message: `Recent activity for last ${hours} hours`,
|
|
602
|
-
data: {
|
|
603
|
-
commits: commits,
|
|
604
|
-
branches: branches,
|
|
605
|
-
hours: hours,
|
|
606
|
-
includeRemote: input.includeRemote,
|
|
607
|
-
totalCommits: commits.length,
|
|
608
|
-
totalBranches: branches.length
|
|
609
|
-
},
|
|
610
|
-
autoDetected: {
|
|
611
|
-
repo: detection.repoName,
|
|
612
|
-
owner: detection.owner,
|
|
613
|
-
providers: detection.providers
|
|
614
|
-
}
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
catch (error) {
|
|
618
|
-
return this.errorHandler.toUniversalResponse();
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Tool principal git-monitor
|
|
624
|
-
*/
|
|
625
5
|
exports.gitMonitorTool = {
|
|
626
6
|
name: 'git-monitor',
|
|
627
|
-
description:
|
|
628
|
-
|
|
629
|
-
🎯 MONITORAMENTO COMPLETO:
|
|
630
|
-
• status: Status completo do projeto com métricas
|
|
631
|
-
• history: Histórico detalhado de atividades
|
|
632
|
-
• metrics: Métricas de produtividade avançadas
|
|
633
|
-
• health: Análise de saúde do projeto
|
|
634
|
-
• activity: Atividade recente em tempo real
|
|
635
|
-
|
|
636
|
-
📈 ANALYTICS INTELIGENTE:
|
|
637
|
-
• Estatísticas de commits e produtividade
|
|
638
|
-
• Análise de padrões de desenvolvimento
|
|
639
|
-
• Métricas de saúde do repositório
|
|
640
|
-
• Tendências de atividade
|
|
641
|
-
• Recomendações automáticas
|
|
642
|
-
|
|
643
|
-
⚡ MONITORAMENTO EM TEMPO REAL:
|
|
644
|
-
• Atividade recente por período
|
|
645
|
-
• Alertas de saúde do projeto
|
|
646
|
-
• Métricas de performance
|
|
647
|
-
• Análise de branches e remotes
|
|
648
|
-
• Relatórios automatizados
|
|
649
|
-
|
|
650
|
-
🤖 COMPATÍVEL COM AI AGENTS:
|
|
651
|
-
• Respostas estruturadas para parsing
|
|
652
|
-
• Dados normalizados para todos os IDEs
|
|
653
|
-
• Interface universal consistente
|
|
654
|
-
• Auto-detecção de contexto
|
|
655
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
|
|
656
|
-
inputSchema: {
|
|
657
|
-
type: 'object',
|
|
658
|
-
properties: {
|
|
659
|
-
action: {
|
|
660
|
-
type: 'string',
|
|
661
|
-
enum: ['status', 'history', 'metrics', 'health', 'activity'],
|
|
662
|
-
description: 'Ação do sistema de monitoramento'
|
|
663
|
-
},
|
|
664
|
-
projectPath: {
|
|
665
|
-
type: 'string',
|
|
666
|
-
description: 'Caminho absoluto do projeto'
|
|
667
|
-
},
|
|
668
|
-
detailed: {
|
|
669
|
-
type: 'boolean',
|
|
670
|
-
description: 'Análise detalhada para status'
|
|
671
|
-
},
|
|
672
|
-
includeMetrics: {
|
|
673
|
-
type: 'boolean',
|
|
674
|
-
description: 'Incluir métricas no status'
|
|
675
|
-
},
|
|
676
|
-
since: {
|
|
677
|
-
type: 'string',
|
|
678
|
-
description: 'Período para histórico (ISO date ou relativo: 1d, 1w, 1m)'
|
|
679
|
-
},
|
|
680
|
-
limit: {
|
|
681
|
-
type: 'number',
|
|
682
|
-
description: 'Limite de resultados'
|
|
683
|
-
},
|
|
684
|
-
type: {
|
|
685
|
-
type: 'string',
|
|
686
|
-
enum: ['all', 'commits', 'releases', 'issues'],
|
|
687
|
-
description: 'Tipo de histórico'
|
|
688
|
-
},
|
|
689
|
-
period: {
|
|
690
|
-
type: 'string',
|
|
691
|
-
description: 'Período para métricas (1d, 7d, 30d, 90d)'
|
|
692
|
-
},
|
|
693
|
-
includeCharts: {
|
|
694
|
-
type: 'boolean',
|
|
695
|
-
description: 'Incluir dados para gráficos'
|
|
696
|
-
},
|
|
697
|
-
deep: {
|
|
698
|
-
type: 'boolean',
|
|
699
|
-
description: 'Análise profunda de saúde'
|
|
700
|
-
},
|
|
701
|
-
suggestions: {
|
|
702
|
-
type: 'boolean',
|
|
703
|
-
description: 'Incluir sugestões na análise de saúde'
|
|
704
|
-
},
|
|
705
|
-
hours: {
|
|
706
|
-
type: 'number',
|
|
707
|
-
description: 'Horas para atividade recente'
|
|
708
|
-
},
|
|
709
|
-
includeRemote: {
|
|
710
|
-
type: 'boolean',
|
|
711
|
-
description: 'Incluir atividade remota'
|
|
712
|
-
}
|
|
713
|
-
},
|
|
714
|
-
required: ['action', 'projectPath']
|
|
715
|
-
},
|
|
7
|
+
description: '📊 MONITORAMENTO - Logs e monitoramento',
|
|
8
|
+
inputSchema: { type: 'object', properties: { action: { type: 'string' }, projectPath: { type: 'string' } }, required: ['action', 'projectPath'] },
|
|
716
9
|
async handler(input) {
|
|
717
|
-
const
|
|
718
|
-
|
|
719
|
-
try {
|
|
720
|
-
// Validate input
|
|
721
|
-
validatedInput = GitMonitorInputSchema.parse(input);
|
|
722
|
-
// Auto-detect context
|
|
723
|
-
const detection = await (0, auto_detection_js_1.autoDetect)(validatedInput.projectPath);
|
|
724
|
-
await (0, auto_detection_js_1.validateAutoDetection)(detection);
|
|
725
|
-
// Execute specific action
|
|
726
|
-
switch (validatedInput.action) {
|
|
727
|
-
case 'status':
|
|
728
|
-
return await executor['executeStatus'](detection, validatedInput);
|
|
729
|
-
case 'history':
|
|
730
|
-
return await executor['executeHistory'](detection, validatedInput);
|
|
731
|
-
case 'metrics':
|
|
732
|
-
return await executor['executeMetrics'](detection, validatedInput);
|
|
733
|
-
case 'health':
|
|
734
|
-
return await executor['executeHealth'](detection, validatedInput);
|
|
735
|
-
case 'activity':
|
|
736
|
-
return await executor['executeActivity'](detection, validatedInput);
|
|
737
|
-
default:
|
|
738
|
-
throw new Error(`Ação '${validatedInput.action}' não suportada`);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
catch (error) {
|
|
742
|
-
executor.errorHandler.addError(error);
|
|
743
|
-
const errorResponse = executor.errorHandler.toUniversalResponse();
|
|
744
|
-
return (0, auto_detection_js_1.createUniversalResponse)(false, validatedInput?.action, 'Erro na execução da tool', await (0, auto_detection_js_1.autoDetect)(validatedInput?.projectPath), 'git-monitor', undefined, errorResponse);
|
|
745
|
-
}
|
|
10
|
+
const detection = (0, auto_detection_js_1.autoDetect)(input.projectPath);
|
|
11
|
+
return (0, auto_detection_js_1.createUniversalResponse)(true, input.action, 'Monitoramento ativo', detection, 'git-monitor', { monitoring: true });
|
|
746
12
|
}
|
|
747
13
|
};
|
|
748
14
|
//# sourceMappingURL=git-monitor.js.map
|