@tng-sh/mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +461 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +189 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/init.d.ts +2 -0
  7. package/dist/init.d.ts.map +1 -0
  8. package/dist/init.js +113 -0
  9. package/dist/init.js.map +1 -0
  10. package/dist/tools/audit.d.ts +21 -0
  11. package/dist/tools/audit.d.ts.map +1 -0
  12. package/dist/tools/audit.js +204 -0
  13. package/dist/tools/audit.js.map +1 -0
  14. package/dist/tools/clones.d.ts +20 -0
  15. package/dist/tools/clones.d.ts.map +1 -0
  16. package/dist/tools/clones.js +202 -0
  17. package/dist/tools/clones.js.map +1 -0
  18. package/dist/tools/config.d.ts +30 -0
  19. package/dist/tools/config.d.ts.map +1 -0
  20. package/dist/tools/config.js +51 -0
  21. package/dist/tools/config.js.map +1 -0
  22. package/dist/tools/deadcode.d.ts +19 -0
  23. package/dist/tools/deadcode.d.ts.map +1 -0
  24. package/dist/tools/deadcode.js +223 -0
  25. package/dist/tools/deadcode.js.map +1 -0
  26. package/dist/tools/generate.d.ts +21 -0
  27. package/dist/tools/generate.d.ts.map +1 -0
  28. package/dist/tools/generate.js +186 -0
  29. package/dist/tools/generate.js.map +1 -0
  30. package/dist/tools/list.d.ts +18 -0
  31. package/dist/tools/list.d.ts.map +1 -0
  32. package/dist/tools/list.js +147 -0
  33. package/dist/tools/list.js.map +1 -0
  34. package/dist/tools/trace.d.ts +20 -0
  35. package/dist/tools/trace.d.ts.map +1 -0
  36. package/dist/tools/trace.js +194 -0
  37. package/dist/tools/trace.js.map +1 -0
  38. package/dist/tools/utils.d.ts +19 -0
  39. package/dist/tools/utils.d.ts.map +1 -0
  40. package/dist/tools/utils.js +143 -0
  41. package/dist/tools/utils.js.map +1 -0
  42. package/dist/tools/xray.d.ts +20 -0
  43. package/dist/tools/xray.d.ts.map +1 -0
  44. package/dist/tools/xray.js +187 -0
  45. package/dist/tools/xray.js.map +1 -0
  46. package/package.json +44 -0
package/dist/init.js ADDED
@@ -0,0 +1,113 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import { dirname } from 'path';
4
+ function commandExists(cmd) {
5
+ try {
6
+ execSync(`command -v ${cmd}`, { stdio: 'ignore', timeout: 1000 });
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ function getBinaryDir(cmd) {
14
+ try {
15
+ const fullPath = execSync(`which ${cmd}`, { encoding: 'utf8', timeout: 1000 }).trim();
16
+ if (fullPath && existsSync(fullPath)) {
17
+ return dirname(fullPath);
18
+ }
19
+ return null;
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ function buildEnv() {
26
+ const env = {};
27
+ // 1. Capture current PATH and discover where key binaries live
28
+ const path = process.env.PATH || '';
29
+ const home = process.env.HOME || '';
30
+ // Dynamically find where the user's TNG-related tools are actually installed
31
+ const discoveredPaths = [
32
+ getBinaryDir('tng'),
33
+ getBinaryDir('ruby'),
34
+ getBinaryDir('uv'),
35
+ getBinaryDir('node'),
36
+ `${home}/.local/bin`, // uv default install location
37
+ ].filter((p) => !!p && !path.includes(p) && existsSync(p));
38
+ // 2. Build the final PATH string and deduplicate EVERYTHING
39
+ const combinedPath = [...new Set(discoveredPaths)].length > 0
40
+ ? `${[...new Set(discoveredPaths)].join(':')}:${path}`
41
+ : path;
42
+ env.PATH = combinedPath
43
+ .split(':')
44
+ .filter((val, index, self) => val && self.indexOf(val) === index)
45
+ .join(':');
46
+ // 2. Ruby Magic - Auto-detect gem environment
47
+ if (commandExists('ruby')) {
48
+ try {
49
+ const gemHome = execSync('gem env home', { encoding: 'utf8', timeout: 2000 }).trim();
50
+ const gemPath = execSync('gem env path', { encoding: 'utf8', timeout: 2000 }).trim();
51
+ if (gemHome)
52
+ env.GEM_HOME = gemHome;
53
+ if (gemPath)
54
+ env.GEM_PATH = gemPath;
55
+ }
56
+ catch (e) {
57
+ // Ruby exists but gem env failed (maybe mismatched version Manager)
58
+ }
59
+ }
60
+ // 3. Command specific overrides
61
+ if (commandExists('bundle')) {
62
+ env.TNG_COMMAND_RUBY = 'bundle';
63
+ env.TNG_COMMAND_RUBY_ARGS = 'exec,tng';
64
+ }
65
+ if (commandExists('uv')) {
66
+ env.TNG_COMMAND_PYTHON = 'uv';
67
+ env.TNG_COMMAND_PYTHON_ARGS = 'run,tng';
68
+ }
69
+ if (commandExists('npx')) {
70
+ env.TNG_COMMAND_JS = 'npx';
71
+ env.TNG_COMMAND_JS_ARGS = '-p,@tng-sh/js,tng';
72
+ env.TNG_COMMAND_TS = 'npx';
73
+ env.TNG_COMMAND_TS_ARGS = '-p,@tng-sh/js,tng';
74
+ }
75
+ return env;
76
+ }
77
+ function formatJson(obj) {
78
+ return JSON.stringify(obj, null, 2);
79
+ }
80
+ function buildMcpConfig(command, args, env, key = "mcpServers") {
81
+ return {
82
+ [key]: {
83
+ "tng-mcp": {
84
+ command,
85
+ args,
86
+ env,
87
+ },
88
+ },
89
+ };
90
+ }
91
+ function printSection(title, body) {
92
+ console.log(`\n${title}\n${'-'.repeat(title.length)}\n${body}`);
93
+ }
94
+ export function runInit() {
95
+ const env = buildEnv();
96
+ const command = 'npx';
97
+ const args = ['@tng-sh/mcp-server'];
98
+ printSection('Detected Environment', [
99
+ `bundle: ${commandExists('bundle') ? 'yes' : 'no'}`,
100
+ `uv: ${commandExists('uv') ? 'yes' : 'no'}`,
101
+ `npx: ${commandExists('npx') ? 'yes' : 'no'}`,
102
+ ].join('\n'));
103
+ printSection('Claude Desktop', formatJson(buildMcpConfig(command, args, env)));
104
+ printSection('ChatGPT Desktop', formatJson(buildMcpConfig(command, args, env)));
105
+ printSection('Cursor (.cursor/mcp_config.json)', formatJson(buildMcpConfig(command, args, env)));
106
+ printSection('Antigravity (~/.gemini/antigravity/mcp_config.json)', formatJson(buildMcpConfig(command, args, env)));
107
+ printSection('OpenCode (~/.codex/config.toml equivalent JSON)', formatJson(buildMcpConfig(command, args, env, "mcp_servers")));
108
+ console.log('\nNotes\n-----');
109
+ console.log('- If a command shows "no", install it or set TNG_COMMAND_* manually.');
110
+ console.log('- For version managers, ensure PATH includes your shims.');
111
+ return 0;
112
+ }
113
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ interface AuditArgs {
2
+ file_path: string;
3
+ method_name: string;
4
+ test_type?: string;
5
+ project_root?: string;
6
+ }
7
+ export declare function auditMethod(args: AuditArgs): Promise<{
8
+ content: {
9
+ type: "text";
10
+ text: string;
11
+ }[];
12
+ isError: boolean;
13
+ } | {
14
+ content: {
15
+ type: "text";
16
+ text: string;
17
+ }[];
18
+ isError?: undefined;
19
+ }>;
20
+ export {};
21
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAQA,UAAU,SAAS;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,SAAS;;;;;;;;;;;;GA8JhD"}
@@ -0,0 +1,204 @@
1
+ import { exec, execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { resolve } from 'path';
4
+ import { findProjectRoot, getTngCommandConfig, detectLanguage, getShellEnv, shellEscape } from './utils.js';
5
+ const execAsync = promisify(exec);
6
+ const execFileAsync = promisify(execFile);
7
+ export async function auditMethod(args) {
8
+ const { file_path, method_name, test_type, project_root } = args;
9
+ try {
10
+ // Resolve to absolute path if relative
11
+ const absoluteFilePath = resolve(file_path);
12
+ // Find project root if not provided
13
+ const cwd = project_root || findProjectRoot(absoluteFilePath) || process.cwd();
14
+ // Find TNG command in the project
15
+ const tngCommand = getTngCommandConfig(cwd, file_path);
16
+ const baseArgs = ['--audit', '--json', '-f', file_path, '-m', method_name];
17
+ // Add --type for Python/JS/TS if provided
18
+ if (test_type) {
19
+ baseArgs.push('--type', test_type);
20
+ }
21
+ const command = tngCommand.shell
22
+ ? `${tngCommand.cmd} ${baseArgs.map(shellEscape).join(' ')}`
23
+ : `${tngCommand.cmd} ${[...tngCommand.args, ...baseArgs].map(shellEscape).join(' ')}`;
24
+ console.error(`[TNG MCP] Running: ${command}`);
25
+ console.error(`[TNG MCP] CWD: ${cwd}`);
26
+ // Call the TNG CLI
27
+ const { stdout, stderr } = tngCommand.shell
28
+ ? await execAsync(command, {
29
+ cwd, // Run from project root
30
+ env: getShellEnv(),
31
+ timeout: 600000, // 10 minutes (to match generation)
32
+ maxBuffer: 10 * 1024 * 1024, // 10MB buffer
33
+ })
34
+ : await execFileAsync(tngCommand.cmd, [...tngCommand.args, ...baseArgs], {
35
+ cwd,
36
+ env: getShellEnv(),
37
+ timeout: 600000,
38
+ maxBuffer: 10 * 1024 * 1024,
39
+ });
40
+ if (stderr && !stderr.includes('TNG')) {
41
+ console.error('[TNG MCP] stderr:', stderr);
42
+ }
43
+ // Parse the JSON output from TNG
44
+ // TNG CLI returns JSON events line by line, we need the "result" event
45
+ const lines = stdout.trim().split('\n');
46
+ let result = null;
47
+ for (const line of lines) {
48
+ if (!line.trim())
49
+ continue;
50
+ try {
51
+ const event = JSON.parse(line);
52
+ if (event.type === 'result') {
53
+ result = event;
54
+ break;
55
+ }
56
+ if (event.type === 'error' || event.type === 'auth_error') {
57
+ throw new Error(event.message || 'Audit failed');
58
+ }
59
+ }
60
+ catch (e) {
61
+ // Try parsing the whole output as single JSON (fallback)
62
+ if (line.includes('{') && line.includes('issues')) {
63
+ result = JSON.parse(line);
64
+ }
65
+ }
66
+ }
67
+ if (!result) {
68
+ return {
69
+ content: [
70
+ {
71
+ type: 'text',
72
+ text: `No audit results returned. Raw output:\n${stdout.substring(0, 500)}`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ };
77
+ }
78
+ // Format the response for MCP
79
+ const formattedOutput = formatAuditResult(result);
80
+ return {
81
+ content: [
82
+ {
83
+ type: 'text',
84
+ text: formattedOutput,
85
+ },
86
+ ],
87
+ };
88
+ }
89
+ catch (error) {
90
+ // Handle specific error cases
91
+ if (error.code === 'ENOENT') {
92
+ return {
93
+ content: [
94
+ {
95
+ type: 'text',
96
+ text: `Error: TNG CLI not found in project. Please install TNG first:
97
+
98
+ **For Ruby projects:**
99
+ \`gem install tng\` or add to Gemfile: \`gem 'tng'\`
100
+
101
+ **For Python projects:**
102
+ \`pip install tng-python\` or \`uv add tng-python\`
103
+
104
+ **For Node.js projects:**
105
+ \`npm install tng-js\`
106
+
107
+ Then configure your API key by running the appropriate init command.`,
108
+ },
109
+ ],
110
+ isError: true,
111
+ };
112
+ }
113
+ if (error.killed) {
114
+ return {
115
+ content: [
116
+ {
117
+ type: 'text',
118
+ text: `Error: Audit timed out after 5 minutes.`,
119
+ },
120
+ ],
121
+ isError: true,
122
+ };
123
+ }
124
+ // Extract error message
125
+ let errorMessage = error.message;
126
+ try {
127
+ const errorOutput = error.stdout || error.stderr || '';
128
+ const lines = errorOutput.split('\n');
129
+ for (const line of lines) {
130
+ if (!line.trim())
131
+ continue;
132
+ try {
133
+ const event = JSON.parse(line);
134
+ if (event.type === 'error' || event.type === 'auth_error') {
135
+ errorMessage = event.message || errorMessage;
136
+ break;
137
+ }
138
+ }
139
+ catch { }
140
+ }
141
+ }
142
+ catch { }
143
+ return {
144
+ content: [
145
+ {
146
+ type: 'text',
147
+ text: `Error auditing ${file_path}#${method_name}: ${errorMessage}
148
+
149
+ Make sure TNG is properly installed and configured in your project.`,
150
+ },
151
+ ],
152
+ isError: true,
153
+ };
154
+ }
155
+ }
156
+ function formatAuditResult(result) {
157
+ // VSCode plugin expects result to have issues, behaviours, etc.
158
+ const issues = result.issues || [];
159
+ const behaviours = result.behaviours || [];
160
+ const methodName = result.method_name || 'Unknown';
161
+ const className = result.class_name || 'Unknown';
162
+ const sourceCode = result.method_source_with_lines || result.source_code || '';
163
+ let output = `# Audit Results for ${className}#${methodName}\n\n`;
164
+ // Add method source code
165
+ if (sourceCode) {
166
+ // Try to find the file path in the result, or default to unknown
167
+ const lang = detectLanguage(result.file_path || '');
168
+ output += `## Source Code\n\`\`\`${lang}\n${sourceCode}\n\`\`\`\n\n`;
169
+ }
170
+ // Format issues
171
+ if (issues.length > 0) {
172
+ output += `## Issues Found (${issues.length})\n\n`;
173
+ issues.forEach((issue, index) => {
174
+ output += `### ${index + 1}. ${issue.category || 'General'} - Severity: ${issue.severity || 'Medium'}\n`;
175
+ output += `**Description:** ${issue.description || issue.summary || 'No description'}\n`;
176
+ if (issue.location) {
177
+ output += `**Location:** Line ${issue.location}\n`;
178
+ }
179
+ if (issue.fix) {
180
+ output += `**Suggested Fix:** ${issue.fix}\n`;
181
+ }
182
+ if (issue.reasoning) {
183
+ output += `**Reasoning:** ${issue.reasoning}\n`;
184
+ }
185
+ output += '\n';
186
+ });
187
+ }
188
+ else {
189
+ output += `## ✅ No Issues Found\n\n`;
190
+ }
191
+ // Format behaviors
192
+ if (behaviours.length > 0) {
193
+ output += `## Behaviors (${behaviours.length})\n\n`;
194
+ behaviours.forEach((behavior, index) => {
195
+ output += `${index + 1}. ${behavior.description || behavior.summary}\n`;
196
+ if (behavior.reasoning) {
197
+ output += ` - ${behavior.reasoning}\n`;
198
+ }
199
+ });
200
+ output += '\n';
201
+ }
202
+ return output;
203
+ }
204
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ interface ClonesArgs {
2
+ file_path: string;
3
+ level?: string;
4
+ project_root?: string;
5
+ }
6
+ export declare function detectClones(args: ClonesArgs): Promise<{
7
+ content: {
8
+ type: "text";
9
+ text: string;
10
+ }[];
11
+ isError: boolean;
12
+ } | {
13
+ content: {
14
+ type: "text";
15
+ text: string;
16
+ }[];
17
+ isError?: undefined;
18
+ }>;
19
+ export {};
20
+ //# sourceMappingURL=clones.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clones.d.ts","sourceRoot":"","sources":["../../src/tools/clones.ts"],"names":[],"mappings":"AAQA,UAAU,UAAU;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU;;;;;;;;;;;;GAgKlD"}
@@ -0,0 +1,202 @@
1
+ import { exec, execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { resolve } from 'path';
4
+ import { findProjectRoot, getTngCommandConfig, detectLanguage, getShellEnv, shellEscape } from './utils.js';
5
+ const execAsync = promisify(exec);
6
+ const execFileAsync = promisify(execFile);
7
+ export async function detectClones(args) {
8
+ const { file_path, level = 'all', project_root } = args;
9
+ try {
10
+ const absoluteFilePath = resolve(file_path);
11
+ const cwd = project_root || findProjectRoot(absoluteFilePath) || process.cwd();
12
+ const tngCommand = getTngCommandConfig(cwd, file_path);
13
+ // Build clones command with JSON output
14
+ const baseArgs = ['--clones', '--json', '-f', file_path];
15
+ if (level && level !== 'all') {
16
+ baseArgs.push('--level', level);
17
+ }
18
+ const command = tngCommand.shell
19
+ ? `${tngCommand.cmd} ${baseArgs.map(shellEscape).join(' ')}`
20
+ : `${tngCommand.cmd} ${[...tngCommand.args, ...baseArgs].map(shellEscape).join(' ')}`;
21
+ console.error(`[TNG MCP] Running: ${command}`);
22
+ console.error(`[TNG MCP] CWD: ${cwd}`);
23
+ const { stdout, stderr } = tngCommand.shell
24
+ ? await execAsync(command, {
25
+ cwd,
26
+ env: getShellEnv(),
27
+ timeout: 180000, // 3 minutes
28
+ maxBuffer: 10 * 1024 * 1024,
29
+ })
30
+ : await execFileAsync(tngCommand.cmd, [...tngCommand.args, ...baseArgs], {
31
+ cwd,
32
+ env: getShellEnv(),
33
+ timeout: 180000,
34
+ maxBuffer: 10 * 1024 * 1024,
35
+ });
36
+ if (stderr && !stderr.includes('TNG')) {
37
+ console.error('[TNG MCP] stderr:', stderr);
38
+ }
39
+ // Parse JSON output
40
+ const lines = stdout.trim().split('\n');
41
+ let result = null;
42
+ for (const line of lines) {
43
+ if (!line.trim())
44
+ continue;
45
+ try {
46
+ const event = JSON.parse(line);
47
+ if (event.type === 'result' || event.type === 'clones' || event.clones || event.duplicates || event.matches || Array.isArray(event)) {
48
+ result = event;
49
+ break;
50
+ }
51
+ if (event.type === 'error' || event.type === 'auth_error') {
52
+ throw new Error(event.message || 'Clone detection failed');
53
+ }
54
+ }
55
+ catch (e) {
56
+ // Try parsing as single JSON
57
+ if (line.includes('{') && (line.includes('"clones"') ||
58
+ line.includes('"duplicates"') ||
59
+ line.includes('"matches"') ||
60
+ (line.startsWith('[') && line.includes('"start1"')))) {
61
+ result = JSON.parse(line);
62
+ break;
63
+ }
64
+ }
65
+ }
66
+ if (!result) {
67
+ return {
68
+ content: [
69
+ {
70
+ type: 'text',
71
+ text: `No clone detection results returned. Raw output:\n${stdout.substring(0, 500)}`,
72
+ },
73
+ ],
74
+ isError: true,
75
+ };
76
+ }
77
+ // Enhancement: Read file to attach snippets if missing (Rust CLI only returns lines)
78
+ try {
79
+ const fs = await import('fs/promises');
80
+ const fileContent = await fs.readFile(absoluteFilePath, 'utf8');
81
+ const fileLines = fileContent.split('\n');
82
+ const matches = Array.isArray(result) ? result : (result.clones || result.duplicates || result.matches || []);
83
+ matches.forEach((m) => {
84
+ if (m.start1 && m.end1 && !m.snippet1) {
85
+ m.snippet1 = fileLines.slice(m.start1 - 1, m.end1).join('\n');
86
+ }
87
+ if (m.start2 && m.end2 && !m.snippet2) {
88
+ m.snippet2 = fileLines.slice(m.start2 - 1, m.end2).join('\n');
89
+ }
90
+ });
91
+ }
92
+ catch (e) {
93
+ console.error('[TNG MCP] Failed to read file for snippets:', e);
94
+ }
95
+ const formattedOutput = formatClonesResult(result, file_path, level);
96
+ return {
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ text: formattedOutput,
101
+ },
102
+ ],
103
+ };
104
+ }
105
+ catch (error) {
106
+ if (error.code === 'ENOENT') {
107
+ return {
108
+ content: [
109
+ {
110
+ type: 'text',
111
+ text: `Error: TNG CLI not found in project. Please install TNG first.`,
112
+ },
113
+ ],
114
+ isError: true,
115
+ };
116
+ }
117
+ if (error.killed) {
118
+ return {
119
+ content: [
120
+ {
121
+ type: 'text',
122
+ text: `Error: Clone detection timed out after 3 minutes.`,
123
+ },
124
+ ],
125
+ isError: true,
126
+ };
127
+ }
128
+ let errorMessage = error.message;
129
+ try {
130
+ const errorOutput = error.stdout || error.stderr || '';
131
+ const lines = errorOutput.split('\n');
132
+ for (const line of lines) {
133
+ if (!line.trim())
134
+ continue;
135
+ try {
136
+ const event = JSON.parse(line);
137
+ if (event.type === 'error' || event.type === 'auth_error') {
138
+ errorMessage = event.message || errorMessage;
139
+ break;
140
+ }
141
+ }
142
+ catch { }
143
+ }
144
+ }
145
+ catch { }
146
+ return {
147
+ content: [
148
+ {
149
+ type: 'text',
150
+ text: `Error detecting clones in ${file_path}: ${errorMessage}`,
151
+ },
152
+ ],
153
+ isError: true,
154
+ };
155
+ }
156
+ }
157
+ function formatClonesResult(result, filePath, level) {
158
+ const clones = Array.isArray(result) ? result : (result.clones || result.duplicates || result.matches || []);
159
+ const totalClones = Array.isArray(clones) ? clones.length : 0;
160
+ const lang = detectLanguage(filePath);
161
+ let output = `# Clone Detection Results for ${filePath}\n\n`;
162
+ output += `**Detection Level:** ${getLevelDescription(level)}\n`;
163
+ output += `**Total Clone Pairs Found:** ${totalClones}\n\n`;
164
+ if (totalClones === 0) {
165
+ output += `## ✅ No Code Duplicates Found\n\n`;
166
+ output += `Great! This file has no detected code clones at the ${level} level.\n`;
167
+ return output;
168
+ }
169
+ output += `## Detected Clones\n\n`;
170
+ clones.forEach((clone, index) => {
171
+ const cloneNum = index + 1;
172
+ const cloneType = clone.algo || clone.type || clone.level || 'mixed';
173
+ const similarity = clone.similarity || clone.score || (clone.complexity_score ? `${clone.complexity_score} complexity` : 'N/A');
174
+ output += `### ${cloneNum}. [${cloneType.toUpperCase()}] Similarity: ${similarity}\n`;
175
+ output += `*Found duplicate logic between lines ${clone.start1}-${clone.end1} and ${clone.start2}-${clone.end2}.*\n\n`;
176
+ if (clone.snippet1) {
177
+ output += `**Instance 1 (Lines ${clone.start1}-${clone.end1}):**\n`;
178
+ output += `\`\`\`${lang}\n${clone.snippet1.trim()}\n\`\`\`\n\n`;
179
+ }
180
+ if (clone.snippet2) {
181
+ output += `**Instance 2 (Lines ${clone.start2}-${clone.end2}):**\n`;
182
+ output += `\`\`\`${lang}\n${clone.snippet2.trim()}\n\`\`\`\n\n`;
183
+ }
184
+ output += '---\n\n';
185
+ });
186
+ output += `> **Recommendation:** Consider refactoring these duplicated blocks into a shared helper function or utility module to improve maintainability.\n`;
187
+ return output;
188
+ }
189
+ function getLevelDescription(level) {
190
+ switch (level) {
191
+ case '1':
192
+ return 'Level 1 - Token-based (Near-exact match, catches copy-paste)';
193
+ case '2':
194
+ return 'Level 2 - Structural (AST-based, catches logic clones)';
195
+ case '3':
196
+ return 'Level 3 - Fuzzy (Catches patterns with small variations)';
197
+ case 'all':
198
+ default:
199
+ return 'All Levels (Comprehensive detection)';
200
+ }
201
+ }
202
+ //# sourceMappingURL=clones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clones.js","sourceRoot":"","sources":["../../src/tools/clones.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export interface TngConfig {
2
+ ruby?: {
3
+ command?: string;
4
+ };
5
+ python?: {
6
+ command?: string;
7
+ };
8
+ javascript?: {
9
+ command?: string;
10
+ };
11
+ env?: Record<string, string>;
12
+ }
13
+ /**
14
+ * Load TNG configuration from the user's config file.
15
+ * Looks for config in:
16
+ * 1. ~/.config/tng-mcp/config.json
17
+ * 2. ~/.tng-mcp.json
18
+ */
19
+ export declare function loadConfig(): TngConfig;
20
+ /**
21
+ * Get the configured command for a specific language.
22
+ * Returns undefined if not configured.
23
+ */
24
+ export declare function getConfiguredCommand(language: 'ruby' | 'python' | 'javascript'): string | undefined;
25
+ /**
26
+ * Get custom environment variables from config.
27
+ * These will be merged with process.env when running commands.
28
+ */
29
+ export declare function getConfiguredEnv(): Record<string, string>;
30
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/tools/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACtB,IAAI,CAAC,EAAE;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,UAAU,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAID;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAwBtC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,CAGnG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGzD"}