@performance-agent/mcp-server 1.0.1
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/README.md +503 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +300 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/code-analyzer/analyzers/javascript-analyzer.d.ts +36 -0
- package/dist/tools/code-analyzer/analyzers/javascript-analyzer.d.ts.map +1 -0
- package/dist/tools/code-analyzer/analyzers/javascript-analyzer.js +241 -0
- package/dist/tools/code-analyzer/analyzers/javascript-analyzer.js.map +1 -0
- package/dist/tools/code-analyzer/analyzers/python-analyzer.d.ts +30 -0
- package/dist/tools/code-analyzer/analyzers/python-analyzer.d.ts.map +1 -0
- package/dist/tools/code-analyzer/analyzers/python-analyzer.js +142 -0
- package/dist/tools/code-analyzer/analyzers/python-analyzer.js.map +1 -0
- package/dist/tools/code-analyzer/git-helper.d.ts +52 -0
- package/dist/tools/code-analyzer/git-helper.d.ts.map +1 -0
- package/dist/tools/code-analyzer/git-helper.js +124 -0
- package/dist/tools/code-analyzer/git-helper.js.map +1 -0
- package/dist/tools/code-analyzer/index.d.ts +45 -0
- package/dist/tools/code-analyzer/index.d.ts.map +1 -0
- package/dist/tools/code-analyzer/index.js +213 -0
- package/dist/tools/code-analyzer/index.js.map +1 -0
- package/dist/tools/code-analyzer/types.d.ts +54 -0
- package/dist/tools/code-analyzer/types.d.ts.map +1 -0
- package/dist/tools/code-analyzer/types.js +5 -0
- package/dist/tools/code-analyzer/types.js.map +1 -0
- package/dist/tools/function-profiler/index.d.ts +11 -0
- package/dist/tools/function-profiler/index.d.ts.map +1 -0
- package/dist/tools/function-profiler/index.js +192 -0
- package/dist/tools/function-profiler/index.js.map +1 -0
- package/dist/tools/function-profiler/javascript-profiler.d.ts +27 -0
- package/dist/tools/function-profiler/javascript-profiler.d.ts.map +1 -0
- package/dist/tools/function-profiler/javascript-profiler.js +141 -0
- package/dist/tools/function-profiler/javascript-profiler.js.map +1 -0
- package/dist/tools/function-profiler/python-profiler.d.ts +31 -0
- package/dist/tools/function-profiler/python-profiler.d.ts.map +1 -0
- package/dist/tools/function-profiler/python-profiler.js +212 -0
- package/dist/tools/function-profiler/python-profiler.js.map +1 -0
- package/dist/tools/function-profiler/types.d.ts +41 -0
- package/dist/tools/function-profiler/types.d.ts.map +1 -0
- package/dist/tools/function-profiler/types.js +5 -0
- package/dist/tools/function-profiler/types.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python code complexity analyzer using radon
|
|
3
|
+
*/
|
|
4
|
+
import { exec } from 'child_process';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
export class PythonAnalyzer {
|
|
8
|
+
threshold;
|
|
9
|
+
constructor(threshold = 10) {
|
|
10
|
+
this.threshold = threshold;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if radon is installed
|
|
14
|
+
*/
|
|
15
|
+
async isRadonInstalled() {
|
|
16
|
+
try {
|
|
17
|
+
await execAsync('radon --version');
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Analyze Python file complexity
|
|
26
|
+
*/
|
|
27
|
+
async analyzeFile(filePath) {
|
|
28
|
+
const radonInstalled = await this.isRadonInstalled();
|
|
29
|
+
if (!radonInstalled) {
|
|
30
|
+
console.warn('⚠️ radon not installed. Install with: pip install radon');
|
|
31
|
+
return this.analyzeFallback(filePath);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const { stdout } = await execAsync(`radon cc "${filePath}" -j -s`);
|
|
35
|
+
if (!stdout.trim()) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const radonResult = JSON.parse(stdout);
|
|
39
|
+
const results = [];
|
|
40
|
+
for (const [file, functions] of Object.entries(radonResult)) {
|
|
41
|
+
for (const func of functions) {
|
|
42
|
+
results.push({
|
|
43
|
+
file: filePath,
|
|
44
|
+
function: func.name,
|
|
45
|
+
line: func.lineno,
|
|
46
|
+
complexity: func.complexity,
|
|
47
|
+
risk_level: this.getRiskLevel(func.complexity),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(`Failed to analyze Python file ${filePath}:`, error.message);
|
|
55
|
+
return this.analyzeFallback(filePath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Fallback analyzer using simple regex patterns
|
|
60
|
+
* Not as accurate but doesn't require external tools
|
|
61
|
+
*/
|
|
62
|
+
async analyzeFallback(filePath) {
|
|
63
|
+
try {
|
|
64
|
+
const fs = await import('fs-extra');
|
|
65
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
66
|
+
const lines = content.split('\n');
|
|
67
|
+
const results = [];
|
|
68
|
+
let currentFunction = '';
|
|
69
|
+
let functionLine = 0;
|
|
70
|
+
let complexity = 1;
|
|
71
|
+
for (let i = 0; i < lines.length; i++) {
|
|
72
|
+
const line = lines[i].trim();
|
|
73
|
+
// Detect function definition
|
|
74
|
+
if (line.startsWith('def ') && line.includes('(')) {
|
|
75
|
+
// Save previous function
|
|
76
|
+
if (currentFunction) {
|
|
77
|
+
results.push({
|
|
78
|
+
file: filePath,
|
|
79
|
+
function: currentFunction,
|
|
80
|
+
line: functionLine,
|
|
81
|
+
complexity: complexity,
|
|
82
|
+
risk_level: this.getRiskLevel(complexity),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// Start new function
|
|
86
|
+
const match = line.match(/def\s+(\w+)\s*\(/);
|
|
87
|
+
currentFunction = match ? match[1] : 'unknown';
|
|
88
|
+
functionLine = i + 1;
|
|
89
|
+
complexity = 1;
|
|
90
|
+
}
|
|
91
|
+
// Count complexity indicators
|
|
92
|
+
if (currentFunction) {
|
|
93
|
+
if (line.includes('if ') || line.includes('elif '))
|
|
94
|
+
complexity++;
|
|
95
|
+
if (line.includes('for ') || line.includes('while '))
|
|
96
|
+
complexity++;
|
|
97
|
+
if (line.includes(' and ') || line.includes(' or '))
|
|
98
|
+
complexity++;
|
|
99
|
+
if (line.includes('except '))
|
|
100
|
+
complexity++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Save last function
|
|
104
|
+
if (currentFunction) {
|
|
105
|
+
results.push({
|
|
106
|
+
file: filePath,
|
|
107
|
+
function: currentFunction,
|
|
108
|
+
line: functionLine,
|
|
109
|
+
complexity: complexity,
|
|
110
|
+
risk_level: this.getRiskLevel(complexity),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
console.error(`Fallback analysis failed for ${filePath}:`, error);
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Determine risk level based on complexity score
|
|
122
|
+
*/
|
|
123
|
+
getRiskLevel(complexity) {
|
|
124
|
+
if (complexity < 5)
|
|
125
|
+
return 'low';
|
|
126
|
+
if (complexity < this.threshold)
|
|
127
|
+
return 'medium';
|
|
128
|
+
if (complexity < this.threshold * 2)
|
|
129
|
+
return 'high';
|
|
130
|
+
return 'very_high';
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get installation instructions for radon
|
|
134
|
+
*/
|
|
135
|
+
getInstallInstructions() {
|
|
136
|
+
return 'Install radon for accurate Python complexity analysis:\n' +
|
|
137
|
+
' pip install radon\n' +
|
|
138
|
+
' or\n' +
|
|
139
|
+
' pip3 install radon';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=python-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-analyzer.js","sourceRoot":"","sources":["../../../../src/tools/code-analyzer/analyzers/python-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git helper utilities for working with local repositories
|
|
3
|
+
*/
|
|
4
|
+
export declare class GitHelper {
|
|
5
|
+
private git;
|
|
6
|
+
private repoPath;
|
|
7
|
+
constructor(repoPath: string);
|
|
8
|
+
/**
|
|
9
|
+
* Get changed files for staged changes
|
|
10
|
+
*/
|
|
11
|
+
getStagedFiles(): Promise<string[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Get changed files from last commit
|
|
14
|
+
*/
|
|
15
|
+
getLastCommitFiles(): Promise<{
|
|
16
|
+
files: string[];
|
|
17
|
+
sha: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Get uncommitted changes (staged + unstaged + untracked)
|
|
21
|
+
*/
|
|
22
|
+
getUncommittedFiles(): Promise<string[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Get changed files for specific commit
|
|
25
|
+
*/
|
|
26
|
+
getCommitFiles(commitSha: string): Promise<string[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Check if path is a valid git repository
|
|
29
|
+
*/
|
|
30
|
+
isGitRepo(): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* Get repository root path
|
|
33
|
+
*/
|
|
34
|
+
getRepoRoot(): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Get file content at specific commit
|
|
37
|
+
*/
|
|
38
|
+
getFileAtCommit(filePath: string, commitSha: string): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Get current branch name
|
|
41
|
+
*/
|
|
42
|
+
getCurrentBranch(): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve absolute file path
|
|
45
|
+
*/
|
|
46
|
+
resolveFilePath(file: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Check if file exists
|
|
49
|
+
*/
|
|
50
|
+
fileExists(filePath: string): Promise<boolean>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=git-helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-helper.d.ts","sourceRoot":"","sources":["../../../src/tools/code-analyzer/git-helper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM;IAK5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAKzC;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAcrE;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAwB9C;;OAEG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAK1D;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IASnC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IASpC;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAS3E;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IASzC;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIrC;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAIrD"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git helper utilities for working with local repositories
|
|
3
|
+
*/
|
|
4
|
+
import { simpleGit } from 'simple-git';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs-extra';
|
|
7
|
+
export class GitHelper {
|
|
8
|
+
git;
|
|
9
|
+
repoPath;
|
|
10
|
+
constructor(repoPath) {
|
|
11
|
+
this.repoPath = repoPath;
|
|
12
|
+
this.git = simpleGit(repoPath);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get changed files for staged changes
|
|
16
|
+
*/
|
|
17
|
+
async getStagedFiles() {
|
|
18
|
+
const diff = await this.git.diff(['--cached', '--name-only']);
|
|
19
|
+
return diff.split('\n').filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get changed files from last commit
|
|
23
|
+
*/
|
|
24
|
+
async getLastCommitFiles() {
|
|
25
|
+
const log = await this.git.log(['-1']);
|
|
26
|
+
const sha = log.latest?.hash || '';
|
|
27
|
+
if (!sha) {
|
|
28
|
+
return { files: [], sha: '' };
|
|
29
|
+
}
|
|
30
|
+
const diff = await this.git.diff([`${sha}~1`, sha, '--name-only']);
|
|
31
|
+
const files = diff.split('\n').filter(Boolean);
|
|
32
|
+
return { files, sha };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get uncommitted changes (staged + unstaged + untracked)
|
|
36
|
+
*/
|
|
37
|
+
async getUncommittedFiles() {
|
|
38
|
+
const files = new Set();
|
|
39
|
+
// Get unstaged modified files
|
|
40
|
+
const unstaged = await this.git.diff(['--name-only']);
|
|
41
|
+
unstaged.split('\n').filter(Boolean).forEach(f => files.add(f));
|
|
42
|
+
// Get staged files (including new files)
|
|
43
|
+
const staged = await this.git.diff(['--cached', '--name-only']);
|
|
44
|
+
staged.split('\n').filter(Boolean).forEach(f => files.add(f));
|
|
45
|
+
// Get untracked files using git ls-files (includes files in untracked directories)
|
|
46
|
+
const untracked = await this.git.raw(['ls-files', '--others', '--exclude-standard']);
|
|
47
|
+
untracked.split('\n').filter(Boolean).forEach(f => files.add(f));
|
|
48
|
+
// Also add from status for completeness
|
|
49
|
+
const status = await this.git.status();
|
|
50
|
+
status.not_added.forEach(f => files.add(f));
|
|
51
|
+
status.created.forEach(f => files.add(f));
|
|
52
|
+
status.modified.forEach(f => files.add(f));
|
|
53
|
+
return Array.from(files);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get changed files for specific commit
|
|
57
|
+
*/
|
|
58
|
+
async getCommitFiles(commitSha) {
|
|
59
|
+
const diff = await this.git.diff([`${commitSha}~1`, commitSha, '--name-only']);
|
|
60
|
+
return diff.split('\n').filter(Boolean);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if path is a valid git repository
|
|
64
|
+
*/
|
|
65
|
+
async isGitRepo() {
|
|
66
|
+
try {
|
|
67
|
+
await this.git.revparse(['--git-dir']);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get repository root path
|
|
76
|
+
*/
|
|
77
|
+
async getRepoRoot() {
|
|
78
|
+
try {
|
|
79
|
+
const root = await this.git.revparse(['--show-toplevel']);
|
|
80
|
+
return root.trim();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return this.repoPath;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get file content at specific commit
|
|
88
|
+
*/
|
|
89
|
+
async getFileAtCommit(filePath, commitSha) {
|
|
90
|
+
try {
|
|
91
|
+
const content = await this.git.show([`${commitSha}:${filePath}`]);
|
|
92
|
+
return content;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw new Error(`Failed to get file ${filePath} at commit ${commitSha}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get current branch name
|
|
100
|
+
*/
|
|
101
|
+
async getCurrentBranch() {
|
|
102
|
+
try {
|
|
103
|
+
const branch = await this.git.revparse(['--abbrev-ref', 'HEAD']);
|
|
104
|
+
return branch.trim();
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return 'unknown';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Resolve absolute file path
|
|
112
|
+
*/
|
|
113
|
+
resolveFilePath(file) {
|
|
114
|
+
return path.isAbsolute(file) ? file : path.join(this.repoPath, file);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if file exists
|
|
118
|
+
*/
|
|
119
|
+
async fileExists(filePath) {
|
|
120
|
+
const absolutePath = this.resolveFilePath(filePath);
|
|
121
|
+
return fs.pathExists(absolutePath);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=git-helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-helper.js","sourceRoot":"","sources":["../../../src/tools/code-analyzer/git-helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Complexity Analyzer
|
|
3
|
+
* Main entry point for analyzing code complexity in local git repositories
|
|
4
|
+
*/
|
|
5
|
+
import { AnalyzerArgs, AnalysisReport } from './types.js';
|
|
6
|
+
export declare class CodeComplexityAnalyzer {
|
|
7
|
+
private gitHelper;
|
|
8
|
+
private pythonAnalyzer;
|
|
9
|
+
private jsAnalyzer;
|
|
10
|
+
private threshold;
|
|
11
|
+
constructor(repoPath: string, threshold?: number);
|
|
12
|
+
/**
|
|
13
|
+
* Main analysis entry point
|
|
14
|
+
*/
|
|
15
|
+
analyze(args: AnalyzerArgs): Promise<AnalysisReport>;
|
|
16
|
+
/**
|
|
17
|
+
* Get changed files based on analysis mode
|
|
18
|
+
*/
|
|
19
|
+
private getChangedFiles;
|
|
20
|
+
/**
|
|
21
|
+
* Filter files by language
|
|
22
|
+
*/
|
|
23
|
+
private filterByLanguage;
|
|
24
|
+
/**
|
|
25
|
+
* Analyze individual file
|
|
26
|
+
*/
|
|
27
|
+
private analyzeFile;
|
|
28
|
+
/**
|
|
29
|
+
* Generate analysis report
|
|
30
|
+
*/
|
|
31
|
+
private generateReport;
|
|
32
|
+
/**
|
|
33
|
+
* Generate empty report when no files to analyze
|
|
34
|
+
*/
|
|
35
|
+
private generateEmptyReport;
|
|
36
|
+
/**
|
|
37
|
+
* Generate actionable recommendations
|
|
38
|
+
*/
|
|
39
|
+
private generateRecommendations;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Exported function for MCP server
|
|
43
|
+
*/
|
|
44
|
+
export declare function analyzeCodeComplexity(args: AnalyzerArgs): Promise<AnalysisReport>;
|
|
45
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/code-analyzer/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EACL,YAAY,EACZ,cAAc,EAIf,MAAM,YAAY,CAAC;AAEpB,qBAAa,sBAAsB;IACjC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,SAAS,CAAS;gBAEd,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAE,MAAW;IAOpD;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IA0D1D;;OAEG;YACW,eAAe;IA4B7B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;YACW,WAAW;IAkBzB;;OAEG;IACH,OAAO,CAAC,cAAc;IAgDtB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAkDhC;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CAGzB"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Complexity Analyzer
|
|
3
|
+
* Main entry point for analyzing code complexity in local git repositories
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { GitHelper } from './git-helper.js';
|
|
7
|
+
import { PythonAnalyzer } from './analyzers/python-analyzer.js';
|
|
8
|
+
import { JavaScriptAnalyzer } from './analyzers/javascript-analyzer.js';
|
|
9
|
+
export class CodeComplexityAnalyzer {
|
|
10
|
+
gitHelper;
|
|
11
|
+
pythonAnalyzer;
|
|
12
|
+
jsAnalyzer;
|
|
13
|
+
threshold;
|
|
14
|
+
constructor(repoPath, threshold = 10) {
|
|
15
|
+
this.gitHelper = new GitHelper(repoPath);
|
|
16
|
+
this.pythonAnalyzer = new PythonAnalyzer(threshold);
|
|
17
|
+
this.jsAnalyzer = new JavaScriptAnalyzer(threshold);
|
|
18
|
+
this.threshold = threshold;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Main analysis entry point
|
|
22
|
+
*/
|
|
23
|
+
async analyze(args) {
|
|
24
|
+
const { repo_path, mode = 'last_commit', commit_sha, threshold = 10, language = 'all', } = args;
|
|
25
|
+
// Validate git repository
|
|
26
|
+
const isGitRepo = await this.gitHelper.isGitRepo();
|
|
27
|
+
if (!isGitRepo) {
|
|
28
|
+
throw new Error(`Not a git repository: ${repo_path}`);
|
|
29
|
+
}
|
|
30
|
+
// Get changed files based on mode
|
|
31
|
+
const { files: changedFiles, sha: commitSha } = await this.getChangedFiles(mode, commit_sha);
|
|
32
|
+
// Filter by language
|
|
33
|
+
const filesToAnalyze = this.filterByLanguage(changedFiles, language);
|
|
34
|
+
if (filesToAnalyze.length === 0) {
|
|
35
|
+
return this.generateEmptyReport(repo_path, commitSha, mode);
|
|
36
|
+
}
|
|
37
|
+
// Analyze each file
|
|
38
|
+
const allResults = [];
|
|
39
|
+
for (const file of filesToAnalyze) {
|
|
40
|
+
const filePath = this.gitHelper.resolveFilePath(file);
|
|
41
|
+
if (!(await this.gitHelper.fileExists(file))) {
|
|
42
|
+
console.warn(`⚠️ File not found: ${file}`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const results = await this.analyzeFile(filePath);
|
|
47
|
+
allResults.push(...results);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error(`Failed to analyze ${file}:`, error.message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Generate report
|
|
54
|
+
return this.generateReport(repo_path, commitSha, mode, filesToAnalyze.length, allResults, threshold);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get changed files based on analysis mode
|
|
58
|
+
*/
|
|
59
|
+
async getChangedFiles(mode, commitSha) {
|
|
60
|
+
switch (mode) {
|
|
61
|
+
case 'staged':
|
|
62
|
+
const stagedFiles = await this.gitHelper.getStagedFiles();
|
|
63
|
+
return { files: stagedFiles };
|
|
64
|
+
case 'last_commit':
|
|
65
|
+
return await this.gitHelper.getLastCommitFiles();
|
|
66
|
+
case 'uncommitted':
|
|
67
|
+
const uncommittedFiles = await this.gitHelper.getUncommittedFiles();
|
|
68
|
+
return { files: uncommittedFiles };
|
|
69
|
+
case 'commit_sha':
|
|
70
|
+
if (!commitSha) {
|
|
71
|
+
throw new Error('commit_sha required when mode=commit_sha');
|
|
72
|
+
}
|
|
73
|
+
const commitFiles = await this.gitHelper.getCommitFiles(commitSha);
|
|
74
|
+
return { files: commitFiles, sha: commitSha };
|
|
75
|
+
default:
|
|
76
|
+
throw new Error(`Unknown mode: ${mode}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Filter files by language
|
|
81
|
+
*/
|
|
82
|
+
filterByLanguage(files, language) {
|
|
83
|
+
if (language === 'all') {
|
|
84
|
+
return files.filter((f) => /\.(py|js|ts|tsx|jsx)$/i.test(f));
|
|
85
|
+
}
|
|
86
|
+
const extensions = {
|
|
87
|
+
python: ['.py'],
|
|
88
|
+
javascript: ['.js', '.jsx'],
|
|
89
|
+
typescript: ['.ts', '.tsx'],
|
|
90
|
+
};
|
|
91
|
+
const exts = extensions[language] || [];
|
|
92
|
+
return files.filter((f) => exts.some((ext) => f.endsWith(ext)));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Analyze individual file
|
|
96
|
+
*/
|
|
97
|
+
async analyzeFile(filePath) {
|
|
98
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
99
|
+
switch (ext) {
|
|
100
|
+
case '.py':
|
|
101
|
+
return this.pythonAnalyzer.analyzeFile(filePath);
|
|
102
|
+
case '.js':
|
|
103
|
+
case '.jsx':
|
|
104
|
+
case '.ts':
|
|
105
|
+
case '.tsx':
|
|
106
|
+
return this.jsAnalyzer.analyzeFile(filePath);
|
|
107
|
+
default:
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Generate analysis report
|
|
113
|
+
*/
|
|
114
|
+
generateReport(repoPath, commitSha, mode, filesAnalyzed, results, threshold) {
|
|
115
|
+
const totalFunctions = results.length;
|
|
116
|
+
const avgComplexity = totalFunctions > 0
|
|
117
|
+
? results.reduce((sum, r) => sum + r.complexity, 0) / totalFunctions
|
|
118
|
+
: 0;
|
|
119
|
+
const maxComplexity = totalFunctions > 0 ? Math.max(...results.map((r) => r.complexity)) : 0;
|
|
120
|
+
const violations = results.filter((r) => r.complexity >= threshold);
|
|
121
|
+
// Calculate risk distribution
|
|
122
|
+
const summary = {
|
|
123
|
+
low_risk: results.filter((r) => r.risk_level === 'low').length,
|
|
124
|
+
medium_risk: results.filter((r) => r.risk_level === 'medium').length,
|
|
125
|
+
high_risk: results.filter((r) => r.risk_level === 'high').length,
|
|
126
|
+
very_high_risk: results.filter((r) => r.risk_level === 'very_high').length,
|
|
127
|
+
};
|
|
128
|
+
// Generate recommendations
|
|
129
|
+
const recommendations = this.generateRecommendations(violations, totalFunctions, threshold);
|
|
130
|
+
return {
|
|
131
|
+
repo_path: repoPath,
|
|
132
|
+
commit_sha: commitSha,
|
|
133
|
+
mode,
|
|
134
|
+
timestamp: new Date().toISOString(),
|
|
135
|
+
files_analyzed: filesAnalyzed,
|
|
136
|
+
total_functions: totalFunctions,
|
|
137
|
+
avg_complexity: Math.round(avgComplexity * 10) / 10,
|
|
138
|
+
max_complexity: maxComplexity,
|
|
139
|
+
threshold_violations: violations.length,
|
|
140
|
+
details: results.sort((a, b) => b.complexity - a.complexity),
|
|
141
|
+
recommendations,
|
|
142
|
+
summary,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Generate empty report when no files to analyze
|
|
147
|
+
*/
|
|
148
|
+
generateEmptyReport(repoPath, commitSha, mode) {
|
|
149
|
+
return {
|
|
150
|
+
repo_path: repoPath,
|
|
151
|
+
commit_sha: commitSha,
|
|
152
|
+
mode,
|
|
153
|
+
timestamp: new Date().toISOString(),
|
|
154
|
+
files_analyzed: 0,
|
|
155
|
+
total_functions: 0,
|
|
156
|
+
avg_complexity: 0,
|
|
157
|
+
max_complexity: 0,
|
|
158
|
+
threshold_violations: 0,
|
|
159
|
+
details: [],
|
|
160
|
+
recommendations: ['No code files to analyze in the selected mode.'],
|
|
161
|
+
summary: {
|
|
162
|
+
low_risk: 0,
|
|
163
|
+
medium_risk: 0,
|
|
164
|
+
high_risk: 0,
|
|
165
|
+
very_high_risk: 0,
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Generate actionable recommendations
|
|
171
|
+
*/
|
|
172
|
+
generateRecommendations(violations, totalFunctions, threshold) {
|
|
173
|
+
const recommendations = [];
|
|
174
|
+
if (violations.length === 0) {
|
|
175
|
+
recommendations.push('✅ All functions are within acceptable complexity limits!');
|
|
176
|
+
recommendations.push(` ${totalFunctions} function(s) analyzed, all below threshold of ${threshold}.`);
|
|
177
|
+
return recommendations;
|
|
178
|
+
}
|
|
179
|
+
// Header
|
|
180
|
+
recommendations.push(`⚠️ Found ${violations.length} function(s) exceeding complexity threshold of ${threshold}:`);
|
|
181
|
+
recommendations.push('');
|
|
182
|
+
// Top violations
|
|
183
|
+
const topViolations = violations
|
|
184
|
+
.sort((a, b) => b.complexity - a.complexity)
|
|
185
|
+
.slice(0, 5);
|
|
186
|
+
topViolations.forEach((v, index) => {
|
|
187
|
+
const emoji = v.risk_level === 'very_high' ? '🔴' : '🟡';
|
|
188
|
+
const fileName = path.basename(v.file);
|
|
189
|
+
recommendations.push(`${emoji} ${index + 1}. ${v.function} (${fileName}:${v.line})`);
|
|
190
|
+
recommendations.push(` Complexity: ${v.complexity} | Risk: ${v.risk_level}`);
|
|
191
|
+
});
|
|
192
|
+
if (violations.length > 5) {
|
|
193
|
+
recommendations.push('');
|
|
194
|
+
recommendations.push(` ... and ${violations.length - 5} more`);
|
|
195
|
+
}
|
|
196
|
+
// Suggestions
|
|
197
|
+
recommendations.push('');
|
|
198
|
+
recommendations.push('💡 Suggestions:');
|
|
199
|
+
recommendations.push(' • Break down complex functions into smaller, focused ones');
|
|
200
|
+
recommendations.push(' • Extract conditional logic into separate helper functions');
|
|
201
|
+
recommendations.push(' • Consider using design patterns to reduce complexity');
|
|
202
|
+
recommendations.push(' • Add unit tests for high-complexity functions');
|
|
203
|
+
return recommendations;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Exported function for MCP server
|
|
208
|
+
*/
|
|
209
|
+
export async function analyzeCodeComplexity(args) {
|
|
210
|
+
const analyzer = new CodeComplexityAnalyzer(args.repo_path, args.threshold);
|
|
211
|
+
return analyzer.analyze(args);
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/code-analyzer/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for code complexity analyzer
|
|
3
|
+
*/
|
|
4
|
+
export type AnalysisMode = 'staged' | 'last_commit' | 'uncommitted' | 'commit_sha';
|
|
5
|
+
export type RiskLevel = 'low' | 'medium' | 'high' | 'very_high';
|
|
6
|
+
export type Language = 'python' | 'javascript' | 'typescript' | 'all';
|
|
7
|
+
export interface ComplexityResult {
|
|
8
|
+
file: string;
|
|
9
|
+
function: string;
|
|
10
|
+
line: number;
|
|
11
|
+
complexity: number;
|
|
12
|
+
risk_level: RiskLevel;
|
|
13
|
+
loc?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface AnalysisReport {
|
|
16
|
+
repo_path: string;
|
|
17
|
+
commit_sha?: string;
|
|
18
|
+
mode: AnalysisMode;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
files_analyzed: number;
|
|
21
|
+
total_functions: number;
|
|
22
|
+
avg_complexity: number;
|
|
23
|
+
max_complexity: number;
|
|
24
|
+
threshold_violations: number;
|
|
25
|
+
details: ComplexityResult[];
|
|
26
|
+
recommendations: string[];
|
|
27
|
+
summary: {
|
|
28
|
+
low_risk: number;
|
|
29
|
+
medium_risk: number;
|
|
30
|
+
high_risk: number;
|
|
31
|
+
very_high_risk: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface AnalyzerArgs {
|
|
35
|
+
repo_path: string;
|
|
36
|
+
mode?: AnalysisMode;
|
|
37
|
+
commit_sha?: string;
|
|
38
|
+
threshold?: number;
|
|
39
|
+
language?: Language;
|
|
40
|
+
include_suggestions?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface RadonFunctionResult {
|
|
43
|
+
name: string;
|
|
44
|
+
lineno: number;
|
|
45
|
+
complexity: number;
|
|
46
|
+
rank: string;
|
|
47
|
+
}
|
|
48
|
+
export interface LizardFunctionResult {
|
|
49
|
+
name: string;
|
|
50
|
+
start_line: number;
|
|
51
|
+
cyclomatic_complexity: number;
|
|
52
|
+
nloc: number;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|