@tng-sh/mcp-server 1.0.0 → 1.0.3
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 +39 -7
- package/dist/index.js +287 -149
- package/dist/index.js.map +1 -1
- package/dist/tools/audit.d.ts +4 -7
- package/dist/tools/audit.d.ts.map +1 -1
- package/dist/tools/audit.js +38 -45
- package/dist/tools/audit.js.map +1 -1
- package/dist/tools/call_sites.d.ts +17 -0
- package/dist/tools/call_sites.d.ts.map +1 -0
- package/dist/tools/call_sites.js +115 -0
- package/dist/tools/call_sites.js.map +1 -0
- package/dist/tools/clones.d.ts +3 -7
- package/dist/tools/clones.d.ts.map +1 -1
- package/dist/tools/clones.js +35 -45
- package/dist/tools/clones.js.map +1 -1
- package/dist/tools/deadcode.d.ts +5 -8
- package/dist/tools/deadcode.d.ts.map +1 -1
- package/dist/tools/deadcode.js +63 -50
- package/dist/tools/deadcode.js.map +1 -1
- package/dist/tools/generate.d.ts +4 -7
- package/dist/tools/generate.d.ts.map +1 -1
- package/dist/tools/generate.js +38 -45
- package/dist/tools/generate.js.map +1 -1
- package/dist/tools/impact.d.ts +17 -0
- package/dist/tools/impact.d.ts.map +1 -0
- package/dist/tools/impact.js +217 -0
- package/dist/tools/impact.js.map +1 -0
- package/dist/tools/trace.d.ts +4 -7
- package/dist/tools/trace.d.ts.map +1 -1
- package/dist/tools/trace.js +39 -46
- package/dist/tools/trace.js.map +1 -1
- package/dist/tools/utils.d.ts +19 -1
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +54 -2
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/xray.d.ts +3 -7
- package/dist/tools/xray.d.ts.map +1 -1
- package/dist/tools/xray.js +34 -44
- package/dist/tools/xray.js.map +1 -1
- package/package.json +9 -3
package/dist/tools/deadcode.js
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
import { exec, execFile } from 'child_process';
|
|
2
2
|
import { promisify } from 'util';
|
|
3
|
-
import {
|
|
4
|
-
import { findProjectRoot, getTngCommandConfig, getShellEnv, shellEscape } from './utils.js';
|
|
3
|
+
import { findProjectRoot, getTngCommandConfig, getShellEnv, shellEscape, buildMcpResponse, resolveFilePath, safeJsonParse } from './utils.js';
|
|
5
4
|
const execAsync = promisify(exec);
|
|
6
5
|
const execFileAsync = promisify(execFile);
|
|
7
6
|
export async function detectDeadCode(args) {
|
|
8
|
-
const { file_path, project_root } = args;
|
|
7
|
+
const { file_path, project_root, all } = args;
|
|
8
|
+
const responseFormat = args.response_format || (args.raw_json ? 'json' : 'text');
|
|
9
9
|
try {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const hasFile = typeof file_path === 'string' && file_path.trim().length > 0;
|
|
11
|
+
if (!all && !hasFile) {
|
|
12
|
+
return buildMcpResponse({
|
|
13
|
+
tool: 'detect_deadcode',
|
|
14
|
+
text: 'Error: file_path is required unless all=true is set to scan the entire project.',
|
|
15
|
+
isError: true,
|
|
16
|
+
format: responseFormat,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (all && !project_root) {
|
|
20
|
+
return buildMcpResponse({
|
|
21
|
+
tool: 'detect_deadcode',
|
|
22
|
+
text: 'Error: project_root is required when all=true to run project-wide dead code detection.',
|
|
23
|
+
isError: true,
|
|
24
|
+
format: responseFormat,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const absoluteFilePath = hasFile ? resolveFilePath(file_path, project_root) : null;
|
|
28
|
+
const cwd = project_root || (absoluteFilePath ? findProjectRoot(absoluteFilePath) : null) || process.cwd();
|
|
29
|
+
const tngCommand = getTngCommandConfig(cwd, hasFile ? file_path : undefined);
|
|
13
30
|
// Build dead code command with JSON output
|
|
14
|
-
const baseArgs = ['--deadcode', '--json'
|
|
31
|
+
const baseArgs = ['--deadcode', '--json'];
|
|
32
|
+
if (all) {
|
|
33
|
+
baseArgs.push('--all');
|
|
34
|
+
}
|
|
35
|
+
if (hasFile && !all) {
|
|
36
|
+
baseArgs.push('-f', file_path);
|
|
37
|
+
}
|
|
15
38
|
const command = tngCommand.shell
|
|
16
39
|
? `${tngCommand.cmd} ${baseArgs.map(shellEscape).join(' ')}`
|
|
17
40
|
: `${tngCommand.cmd} ${[...tngCommand.args, ...baseArgs].map(shellEscape).join(' ')}`;
|
|
@@ -56,54 +79,47 @@ export async function detectDeadCode(args) {
|
|
|
56
79
|
line.includes('"issue_type"') ||
|
|
57
80
|
line.includes('"issues"') ||
|
|
58
81
|
(line.startsWith('[') && line.includes('"type"')))) {
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
const parsed = safeJsonParse(line);
|
|
83
|
+
if (parsed) {
|
|
84
|
+
result = parsed;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
61
87
|
}
|
|
62
88
|
}
|
|
63
89
|
}
|
|
64
90
|
if (!result) {
|
|
65
|
-
return {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
text: `No dead code detection results returned. Raw output:\n${stdout.substring(0, 500)}`,
|
|
70
|
-
},
|
|
71
|
-
],
|
|
91
|
+
return buildMcpResponse({
|
|
92
|
+
tool: 'detect_deadcode',
|
|
93
|
+
text: `No dead code detection results returned. Raw output:\n${stdout.substring(0, 500)}`,
|
|
94
|
+
raw: stdout,
|
|
72
95
|
isError: true,
|
|
73
|
-
|
|
96
|
+
format: responseFormat,
|
|
97
|
+
});
|
|
74
98
|
}
|
|
75
|
-
const formattedOutput = formatDeadCodeResult(result, file_path);
|
|
76
|
-
return {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
],
|
|
83
|
-
};
|
|
99
|
+
const formattedOutput = formatDeadCodeResult(result, hasFile ? file_path : (all ? 'project' : 'unknown'));
|
|
100
|
+
return buildMcpResponse({
|
|
101
|
+
tool: 'detect_deadcode',
|
|
102
|
+
text: formattedOutput,
|
|
103
|
+
raw: result,
|
|
104
|
+
format: responseFormat,
|
|
105
|
+
});
|
|
84
106
|
}
|
|
85
107
|
catch (error) {
|
|
86
108
|
if (error.code === 'ENOENT') {
|
|
87
|
-
return {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
type: 'text',
|
|
91
|
-
text: `Error: TNG CLI not found in project. Please install TNG first.`,
|
|
92
|
-
},
|
|
93
|
-
],
|
|
109
|
+
return buildMcpResponse({
|
|
110
|
+
tool: 'detect_deadcode',
|
|
111
|
+
text: `Error: TNG CLI not found in project. Please install TNG first.`,
|
|
94
112
|
isError: true,
|
|
95
|
-
|
|
113
|
+
format: responseFormat,
|
|
114
|
+
});
|
|
96
115
|
}
|
|
97
116
|
if (error.killed) {
|
|
98
|
-
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
type: 'text',
|
|
102
|
-
text: `Error: Dead code detection timed out after 3 minutes.`,
|
|
103
|
-
},
|
|
104
|
-
],
|
|
117
|
+
return buildMcpResponse({
|
|
118
|
+
tool: 'detect_deadcode',
|
|
119
|
+
text: `Error: Dead code detection timed out after 3 minutes.`,
|
|
105
120
|
isError: true,
|
|
106
|
-
|
|
121
|
+
format: responseFormat,
|
|
122
|
+
});
|
|
107
123
|
}
|
|
108
124
|
let errorMessage = error.message;
|
|
109
125
|
try {
|
|
@@ -123,15 +139,12 @@ export async function detectDeadCode(args) {
|
|
|
123
139
|
}
|
|
124
140
|
}
|
|
125
141
|
catch { }
|
|
126
|
-
return {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
type: 'text',
|
|
130
|
-
text: `Error detecting dead code in ${file_path}: ${errorMessage}`,
|
|
131
|
-
},
|
|
132
|
-
],
|
|
142
|
+
return buildMcpResponse({
|
|
143
|
+
tool: 'detect_deadcode',
|
|
144
|
+
text: `Error detecting dead code in ${file_path}: ${errorMessage}`,
|
|
133
145
|
isError: true,
|
|
134
|
-
|
|
146
|
+
format: responseFormat,
|
|
147
|
+
});
|
|
135
148
|
}
|
|
136
149
|
}
|
|
137
150
|
function formatDeadCodeResult(result, filePath) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deadcode.js","sourceRoot":"","sources":["../../src/tools/deadcode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"deadcode.js","sourceRoot":"","sources":["../../src/tools/deadcode.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/generate.d.ts
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
interface GenerateTestArgs {
|
|
2
2
|
file_path: string;
|
|
3
3
|
method_name: string;
|
|
4
|
+
class_name?: string;
|
|
4
5
|
test_type?: string;
|
|
5
6
|
project_root?: string;
|
|
7
|
+
response_format?: 'text' | 'json' | 'both';
|
|
8
|
+
raw_json?: boolean;
|
|
6
9
|
}
|
|
7
10
|
export declare function generateTest(args: GenerateTestArgs): Promise<{
|
|
8
11
|
content: {
|
|
9
12
|
type: "text";
|
|
10
13
|
text: string;
|
|
11
14
|
}[];
|
|
12
|
-
isError: boolean;
|
|
13
|
-
} | {
|
|
14
|
-
content: {
|
|
15
|
-
type: "text";
|
|
16
|
-
text: string;
|
|
17
|
-
}[];
|
|
18
|
-
isError?: undefined;
|
|
15
|
+
isError: boolean | undefined;
|
|
19
16
|
}>;
|
|
20
17
|
export {};
|
|
21
18
|
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/tools/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/tools/generate.ts"],"names":[],"mappings":"AAOA,UAAU,gBAAgB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB;;;;;;GAkJxD"}
|
package/dist/tools/generate.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { exec, execFile } from 'child_process';
|
|
2
2
|
import { promisify } from 'util';
|
|
3
|
-
import {
|
|
4
|
-
import { findProjectRoot, getTngCommandConfig, detectLanguage, getShellEnv, shellEscape } from './utils.js';
|
|
3
|
+
import { findProjectRoot, getTngCommandConfig, detectLanguage, getShellEnv, shellEscape, buildMcpResponse, resolveFilePath, safeJsonParse } from './utils.js';
|
|
5
4
|
const execAsync = promisify(exec);
|
|
6
5
|
const execFileAsync = promisify(execFile);
|
|
7
6
|
export async function generateTest(args) {
|
|
8
|
-
const { file_path, method_name, test_type, project_root } = args;
|
|
7
|
+
const { file_path, method_name, class_name, test_type, project_root } = args;
|
|
8
|
+
const responseFormat = args.response_format || (args.raw_json ? 'json' : 'text');
|
|
9
9
|
try {
|
|
10
10
|
// Resolve to absolute path if relative
|
|
11
|
-
const absoluteFilePath =
|
|
11
|
+
const absoluteFilePath = resolveFilePath(file_path, project_root);
|
|
12
12
|
const cwd = project_root || findProjectRoot(absoluteFilePath) || process.cwd();
|
|
13
13
|
const tngCommand = getTngCommandConfig(cwd, file_path);
|
|
14
14
|
const baseArgs = ['--json', '-f', file_path, '-m', method_name];
|
|
15
|
+
if (class_name) {
|
|
16
|
+
baseArgs.push('--class', class_name);
|
|
17
|
+
}
|
|
15
18
|
if (test_type) {
|
|
16
19
|
baseArgs.push('--type', test_type);
|
|
17
20
|
}
|
|
@@ -54,40 +57,37 @@ export async function generateTest(args) {
|
|
|
54
57
|
catch (e) {
|
|
55
58
|
// Try parsing the whole output as single JSON (fallback)
|
|
56
59
|
if (line.includes('{') && (line.includes('file_path') || line.includes('test_code'))) {
|
|
57
|
-
|
|
60
|
+
const parsed = safeJsonParse(line);
|
|
61
|
+
if (parsed) {
|
|
62
|
+
result = parsed;
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
if (!result) {
|
|
62
|
-
return {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
text: `No test generation results returned. Raw output:\n${stdout.substring(0, 500)}`,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
68
|
+
return buildMcpResponse({
|
|
69
|
+
tool: 'generate_test',
|
|
70
|
+
text: `No test generation results returned. Raw output:\n${stdout.substring(0, 500)}`,
|
|
71
|
+
raw: stdout,
|
|
69
72
|
isError: true,
|
|
70
|
-
|
|
73
|
+
format: responseFormat,
|
|
74
|
+
});
|
|
71
75
|
}
|
|
72
76
|
// Format the response
|
|
73
77
|
const formattedOutput = formatGenerateTestResult(result);
|
|
74
|
-
return {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
],
|
|
81
|
-
};
|
|
78
|
+
return buildMcpResponse({
|
|
79
|
+
tool: 'generate_test',
|
|
80
|
+
text: formattedOutput,
|
|
81
|
+
raw: result,
|
|
82
|
+
format: responseFormat,
|
|
83
|
+
});
|
|
82
84
|
}
|
|
83
85
|
catch (error) {
|
|
84
86
|
// Handle specific error cases
|
|
85
87
|
if (error.code === 'ENOENT') {
|
|
86
|
-
return {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
type: 'text',
|
|
90
|
-
text: `Error: TNG CLI not found in project. Please install TNG first:
|
|
88
|
+
return buildMcpResponse({
|
|
89
|
+
tool: 'generate_test',
|
|
90
|
+
text: `Error: TNG CLI not found in project. Please install TNG first:
|
|
91
91
|
|
|
92
92
|
**For Ruby projects:**
|
|
93
93
|
\`gem install tng\` or add to Gemfile: \`gem 'tng'\`
|
|
@@ -99,21 +99,17 @@ export async function generateTest(args) {
|
|
|
99
99
|
\`npm install tng-js\`
|
|
100
100
|
|
|
101
101
|
Then configure your API key.`,
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
102
|
isError: true,
|
|
105
|
-
|
|
103
|
+
format: responseFormat,
|
|
104
|
+
});
|
|
106
105
|
}
|
|
107
106
|
if (error.killed) {
|
|
108
|
-
return {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
type: 'text',
|
|
112
|
-
text: `Error: Test generation timed out after 10 minutes.`,
|
|
113
|
-
},
|
|
114
|
-
],
|
|
107
|
+
return buildMcpResponse({
|
|
108
|
+
tool: 'generate_test',
|
|
109
|
+
text: `Error: Test generation timed out after 10 minutes.`,
|
|
115
110
|
isError: true,
|
|
116
|
-
|
|
111
|
+
format: responseFormat,
|
|
112
|
+
});
|
|
117
113
|
}
|
|
118
114
|
// Extract error message
|
|
119
115
|
let errorMessage = error.message;
|
|
@@ -134,17 +130,14 @@ Then configure your API key.`,
|
|
|
134
130
|
}
|
|
135
131
|
}
|
|
136
132
|
catch { }
|
|
137
|
-
return {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
type: 'text',
|
|
141
|
-
text: `Error generating tests for ${file_path}#${method_name}: ${errorMessage}
|
|
133
|
+
return buildMcpResponse({
|
|
134
|
+
tool: 'generate_test',
|
|
135
|
+
text: `Error generating tests for ${file_path}#${method_name}: ${errorMessage}
|
|
142
136
|
|
|
143
137
|
Make sure TNG is properly installed and configured in your project.`,
|
|
144
|
-
},
|
|
145
|
-
],
|
|
146
138
|
isError: true,
|
|
147
|
-
|
|
139
|
+
format: responseFormat,
|
|
140
|
+
});
|
|
148
141
|
}
|
|
149
142
|
}
|
|
150
143
|
function formatGenerateTestResult(result) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/tools/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/tools/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface ImpactArgs {
|
|
2
|
+
file_path: string;
|
|
3
|
+
method_name: string;
|
|
4
|
+
class_name?: string;
|
|
5
|
+
project_root?: string;
|
|
6
|
+
response_format?: 'text' | 'json' | 'both';
|
|
7
|
+
raw_json?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function impactMethod(args: ImpactArgs): Promise<{
|
|
10
|
+
content: {
|
|
11
|
+
type: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
}[];
|
|
14
|
+
isError: boolean | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=impact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"impact.d.ts","sourceRoot":"","sources":["../../src/tools/impact.ts"],"names":[],"mappings":"AAOA,UAAU,UAAU;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU;;;;;;GAoIlD"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { exec, execFile } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { findProjectRoot, getTngCommandConfig, getShellEnv, shellEscape, buildMcpResponse, resolveFilePath, safeJsonParse } from './utils.js';
|
|
4
|
+
const execAsync = promisify(exec);
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
export async function impactMethod(args) {
|
|
7
|
+
const { file_path, method_name, class_name, project_root } = args;
|
|
8
|
+
const responseFormat = args.response_format || (args.raw_json ? 'json' : 'text');
|
|
9
|
+
try {
|
|
10
|
+
const absoluteFilePath = resolveFilePath(file_path, project_root);
|
|
11
|
+
const cwd = project_root || findProjectRoot(absoluteFilePath) || process.cwd();
|
|
12
|
+
const tngCommand = getTngCommandConfig(cwd, file_path);
|
|
13
|
+
const baseArgs = ['--impact', '--json', '-f', file_path, '-m', method_name];
|
|
14
|
+
if (class_name) {
|
|
15
|
+
baseArgs.push('--class', class_name);
|
|
16
|
+
}
|
|
17
|
+
const command = tngCommand.shell
|
|
18
|
+
? `${tngCommand.cmd} ${baseArgs.map(shellEscape).join(' ')}`
|
|
19
|
+
: `${tngCommand.cmd} ${[...tngCommand.args, ...baseArgs].map(shellEscape).join(' ')}`;
|
|
20
|
+
console.error(`[TNG MCP] Running: ${command}`);
|
|
21
|
+
console.error(`[TNG MCP] CWD: ${cwd}`);
|
|
22
|
+
const { stdout, stderr } = tngCommand.shell
|
|
23
|
+
? await execAsync(command, {
|
|
24
|
+
cwd,
|
|
25
|
+
env: getShellEnv(),
|
|
26
|
+
timeout: 180000,
|
|
27
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
28
|
+
})
|
|
29
|
+
: await execFileAsync(tngCommand.cmd, [...tngCommand.args, ...baseArgs], {
|
|
30
|
+
cwd,
|
|
31
|
+
env: getShellEnv(),
|
|
32
|
+
timeout: 180000,
|
|
33
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
34
|
+
});
|
|
35
|
+
if (stderr && !stderr.includes('TNG')) {
|
|
36
|
+
console.error('[TNG MCP] stderr:', stderr);
|
|
37
|
+
}
|
|
38
|
+
const lines = stdout.trim().split('\n');
|
|
39
|
+
let result = null;
|
|
40
|
+
for (const line of lines) {
|
|
41
|
+
if (!line.trim())
|
|
42
|
+
continue;
|
|
43
|
+
try {
|
|
44
|
+
const event = JSON.parse(line);
|
|
45
|
+
if (event.type === 'result') {
|
|
46
|
+
result = event;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
if (event.type === 'error' || event.type === 'auth_error') {
|
|
50
|
+
throw new Error(event.message || 'Impact analysis failed');
|
|
51
|
+
}
|
|
52
|
+
if (event.status || event.breaking_changes || event.informational_changes || event.diffs) {
|
|
53
|
+
result = event;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
if (line.includes('{') && (line.includes('"impact"') || line.includes('"diffs"') || line.includes('"breaking_changes"') || line.includes('"status"'))) {
|
|
59
|
+
const parsed = safeJsonParse(line);
|
|
60
|
+
if (parsed) {
|
|
61
|
+
result = parsed;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!result) {
|
|
68
|
+
return buildMcpResponse({
|
|
69
|
+
tool: 'impact_method',
|
|
70
|
+
text: `No impact results returned. Raw output:\n${stdout.substring(0, 500)}`,
|
|
71
|
+
raw: stdout,
|
|
72
|
+
isError: true,
|
|
73
|
+
format: responseFormat,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const formattedOutput = formatImpactResult(result, file_path, method_name, class_name);
|
|
77
|
+
return buildMcpResponse({
|
|
78
|
+
tool: 'impact_method',
|
|
79
|
+
text: formattedOutput,
|
|
80
|
+
raw: result,
|
|
81
|
+
format: responseFormat,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error.code === 'ENOENT') {
|
|
86
|
+
return buildMcpResponse({
|
|
87
|
+
tool: 'impact_method',
|
|
88
|
+
text: `Error: TNG CLI not found in project. Please install TNG first.`,
|
|
89
|
+
isError: true,
|
|
90
|
+
format: responseFormat,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (error.killed) {
|
|
94
|
+
return buildMcpResponse({
|
|
95
|
+
tool: 'impact_method',
|
|
96
|
+
text: `Error: Impact analysis timed out after 3 minutes.`,
|
|
97
|
+
isError: true,
|
|
98
|
+
format: responseFormat,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
let errorMessage = error.message;
|
|
102
|
+
try {
|
|
103
|
+
const errorOutput = error.stdout || error.stderr || '';
|
|
104
|
+
const lines = errorOutput.split('\n');
|
|
105
|
+
for (const line of lines) {
|
|
106
|
+
if (!line.trim())
|
|
107
|
+
continue;
|
|
108
|
+
try {
|
|
109
|
+
const event = JSON.parse(line);
|
|
110
|
+
if (event.type === 'error' || event.type === 'auth_error') {
|
|
111
|
+
errorMessage = event.message || errorMessage;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
if (event.error) {
|
|
115
|
+
errorMessage = event.error;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch { }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch { }
|
|
123
|
+
return buildMcpResponse({
|
|
124
|
+
tool: 'impact_method',
|
|
125
|
+
text: `Error running impact analysis for ${file_path}#${method_name}: ${errorMessage}`,
|
|
126
|
+
isError: true,
|
|
127
|
+
format: responseFormat,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function formatImpactResult(result, filePath, methodName, className) {
|
|
132
|
+
const status = result.status || 'unknown';
|
|
133
|
+
const fullName = className ? `${className}#${methodName}` : methodName;
|
|
134
|
+
const file = result.file || filePath;
|
|
135
|
+
const breaking = Array.isArray(result.breaking_changes) ? result.breaking_changes : [];
|
|
136
|
+
const info = Array.isArray(result.informational_changes) ? result.informational_changes : [];
|
|
137
|
+
const diffs = Array.isArray(result.diffs) ? result.diffs : [];
|
|
138
|
+
const impacted = Array.isArray(result.impacted_files) ? result.impacted_files : [];
|
|
139
|
+
const willBreak = result.will_break === true;
|
|
140
|
+
const willBreakReasons = Array.isArray(result.will_break_reasons) ? result.will_break_reasons : [];
|
|
141
|
+
const maybeBreak = result.maybe_break === true;
|
|
142
|
+
const maybeBreakReasons = Array.isArray(result.maybe_break_reasons) ? result.maybe_break_reasons : [];
|
|
143
|
+
let output = `# Impact Analysis for ${fullName}\n\n`;
|
|
144
|
+
output += `**File:** ${file}\n\n`;
|
|
145
|
+
output += `**Status:** ${status}\n\n`;
|
|
146
|
+
if (willBreak || maybeBreak) {
|
|
147
|
+
output += `## Risk Summary\n\n`;
|
|
148
|
+
if (willBreak) {
|
|
149
|
+
output += `- **Will break:** yes\n`;
|
|
150
|
+
}
|
|
151
|
+
if (maybeBreak) {
|
|
152
|
+
output += `- **Maybe break:** yes\n`;
|
|
153
|
+
}
|
|
154
|
+
if (willBreakReasons.length > 0) {
|
|
155
|
+
output += `- **Reasons (will break):** ${willBreakReasons.join('; ')}\n`;
|
|
156
|
+
}
|
|
157
|
+
if (maybeBreakReasons.length > 0) {
|
|
158
|
+
output += `- **Reasons (maybe break):** ${maybeBreakReasons.join('; ')}\n`;
|
|
159
|
+
}
|
|
160
|
+
output += '\n';
|
|
161
|
+
}
|
|
162
|
+
if (breaking.length > 0) {
|
|
163
|
+
output += `## Breaking Changes (${breaking.length})\n\n`;
|
|
164
|
+
breaking.forEach((item, idx) => {
|
|
165
|
+
const kind = item.type || item.kind || 'change';
|
|
166
|
+
const message = item.message || item.description || kind;
|
|
167
|
+
output += `${idx + 1}. **${kind}**: ${message}\n`;
|
|
168
|
+
});
|
|
169
|
+
output += '\n';
|
|
170
|
+
}
|
|
171
|
+
if (info.length > 0) {
|
|
172
|
+
output += `## Informational Changes (${info.length})\n\n`;
|
|
173
|
+
info.forEach((item, idx) => {
|
|
174
|
+
const kind = item.type || item.kind || 'change';
|
|
175
|
+
const message = item.message || item.description || kind;
|
|
176
|
+
output += `${idx + 1}. **${kind}**: ${message}\n`;
|
|
177
|
+
});
|
|
178
|
+
output += '\n';
|
|
179
|
+
}
|
|
180
|
+
if (breaking.length === 0 && info.length === 0 && diffs.length > 0) {
|
|
181
|
+
const bySeverity = {};
|
|
182
|
+
diffs.forEach((d) => {
|
|
183
|
+
const severity = d.severity || 'info';
|
|
184
|
+
if (!bySeverity[severity])
|
|
185
|
+
bySeverity[severity] = [];
|
|
186
|
+
bySeverity[severity].push(d);
|
|
187
|
+
});
|
|
188
|
+
output += `## Changes (${diffs.length})\n\n`;
|
|
189
|
+
Object.keys(bySeverity).sort().forEach((severity) => {
|
|
190
|
+
const items = bySeverity[severity];
|
|
191
|
+
output += `### ${severity.toUpperCase()} (${items.length})\n\n`;
|
|
192
|
+
items.forEach((item, idx) => {
|
|
193
|
+
const kind = item.type || item.kind || 'change';
|
|
194
|
+
const name = item.name ? ` (${item.name})` : '';
|
|
195
|
+
const message = item.message || item.description || kind;
|
|
196
|
+
output += `${idx + 1}. **${kind}**${name}: ${message}\n`;
|
|
197
|
+
});
|
|
198
|
+
output += '\n';
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (impacted.length > 0) {
|
|
202
|
+
output += `## Impacted Files (${impacted.length})\n\n`;
|
|
203
|
+
impacted.forEach((entry, idx) => {
|
|
204
|
+
const loc = entry.file ? `${entry.file}:${entry.line || ''}` : entry.path || 'Unknown location';
|
|
205
|
+
output += `${idx + 1}. **${loc}**\n`;
|
|
206
|
+
if (entry.code) {
|
|
207
|
+
output += ` \`\`\`\n ${String(entry.code).trim()}\n \`\`\`\n`;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
output += '\n';
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
output += `## Impacted Files\n\nNone detected in this project.\n`;
|
|
214
|
+
}
|
|
215
|
+
return output;
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=impact.js.map
|