@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.
- package/README.md +461 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +113 -0
- package/dist/init.js.map +1 -0
- package/dist/tools/audit.d.ts +21 -0
- package/dist/tools/audit.d.ts.map +1 -0
- package/dist/tools/audit.js +204 -0
- package/dist/tools/audit.js.map +1 -0
- package/dist/tools/clones.d.ts +20 -0
- package/dist/tools/clones.d.ts.map +1 -0
- package/dist/tools/clones.js +202 -0
- package/dist/tools/clones.js.map +1 -0
- package/dist/tools/config.d.ts +30 -0
- package/dist/tools/config.d.ts.map +1 -0
- package/dist/tools/config.js +51 -0
- package/dist/tools/config.js.map +1 -0
- package/dist/tools/deadcode.d.ts +19 -0
- package/dist/tools/deadcode.d.ts.map +1 -0
- package/dist/tools/deadcode.js +223 -0
- package/dist/tools/deadcode.js.map +1 -0
- package/dist/tools/generate.d.ts +21 -0
- package/dist/tools/generate.d.ts.map +1 -0
- package/dist/tools/generate.js +186 -0
- package/dist/tools/generate.js.map +1 -0
- package/dist/tools/list.d.ts +18 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +147 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/trace.d.ts +20 -0
- package/dist/tools/trace.d.ts.map +1 -0
- package/dist/tools/trace.js +194 -0
- package/dist/tools/trace.js.map +1 -0
- package/dist/tools/utils.d.ts +19 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +143 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools/xray.d.ts +20 -0
- package/dist/tools/xray.d.ts.map +1 -0
- package/dist/tools/xray.js +187 -0
- package/dist/tools/xray.js.map +1 -0
- 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
|
package/dist/init.js.map
ADDED
|
@@ -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":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5G,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAClC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAS1C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAe;IAC7C,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEjE,IAAI,CAAC;QACD,uCAAuC;QACvC,MAAM,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAE5C,oCAAoC;QACpC,MAAM,GAAG,GAAG,YAAY,IAAI,eAAe,CAAC,gBAAgB,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAE/E,kCAAkC;QAClC,MAAM,UAAU,GAAG,mBAAmB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAE3E,0CAA0C;QAC1C,IAAI,SAAS,EAAE,CAAC;YACZ,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK;YAC5B,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YAC5D,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAE1F,OAAO,CAAC,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,kBAAkB,GAAG,EAAE,CAAC,CAAC;QAEvC,mBAAmB;QACnB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,KAAK;YACvC,CAAC,CAAC,MAAM,SAAS,CAAC,OAAO,EAAE;gBACvB,GAAG,EAAE,wBAAwB;gBAC7B,GAAG,EAAE,WAAW,EAAE;gBAClB,OAAO,EAAE,MAAM,EAAE,mCAAmC;gBACpD,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,cAAc;aAC9C,CAAC;YACF,CAAC,CAAC,MAAM,aAAa,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,EAAE;gBACrE,GAAG;gBACH,GAAG,EAAE,WAAW,EAAE;gBAClB,OAAO,EAAE,MAAM;gBACf,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;aAC9B,CAAC,CAAC;QAEP,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;QAED,iCAAiC;QACjC,uEAAuE;QACvE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,MAAM,GAAG,IAAI,CAAC;QAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC3B,IAAI,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC1B,MAAM,GAAG,KAAK,CAAC;oBACf,MAAM;gBACV,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACxD,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,cAAc,CAAC,CAAC;gBACrD,CAAC;YACL,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACT,yDAAyD;gBACzD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAChD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC;YACL,CAAC;QACL,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,2CAA2C,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;qBAC9E;iBACJ;gBACD,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;QAED,8BAA8B;QAC9B,MAAM,eAAe,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAElD,OAAO;YACH,OAAO,EAAE;gBACL;oBACI,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,eAAe;iBACxB;aACJ;SACJ,CAAC;IACN,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,8BAA8B;QAC9B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;;;;;;;;;;;qEAWuC;qBAChD;iBACJ;gBACD,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACf,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,yCAAyC;qBAClD;iBACJ;gBACD,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;QAED,wBAAwB;QACxB,IAAI,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;QACjC,IAAI,CAAC;YACD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;oBAAE,SAAS;gBAC3B,IAAI,CAAC;oBACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBACxD,YAAY,GAAG,KAAK,CAAC,OAAO,IAAI,YAAY,CAAC;wBAC7C,MAAM;oBACV,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC,CAAC,CAAC;YACf,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,CAAC;QAEX,OAAO;YACH,OAAO,EAAE;gBACL;oBACI,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,kBAAkB,SAAS,IAAI,WAAW,KAAK,YAAY;;oEAEjB;iBACnD;aACJ;YACD,OAAO,EAAE,IAAI;SAChB,CAAC;IACN,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAW;IAClC,gEAAgE;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,IAAI,SAAS,CAAC;IACnD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,IAAI,SAAS,CAAC;IACjD,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,IAAI,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;IAE/E,IAAI,MAAM,GAAG,uBAAuB,SAAS,IAAI,UAAU,MAAM,CAAC;IAElE,yBAAyB;IACzB,IAAI,UAAU,EAAE,CAAC;QACb,iEAAiE;QACjE,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,IAAI,yBAAyB,IAAI,KAAK,UAAU,cAAc,CAAC;IACzE,CAAC;IAED,gBAAgB;IAChB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,oBAAoB,MAAM,CAAC,MAAM,OAAO,CAAC;QAEnD,MAAM,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,KAAa,EAAE,EAAE;YACzC,MAAM,IAAI,OAAO,KAAK,GAAG,CAAC,KAAK,KAAK,CAAC,QAAQ,IAAI,SAAS,gBAAgB,KAAK,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC;YACzG,MAAM,IAAI,oBAAoB,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,IAAI,gBAAgB,IAAI,CAAC;YAEzF,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACjB,MAAM,IAAI,sBAAsB,KAAK,CAAC,QAAQ,IAAI,CAAC;YACvD,CAAC;YAED,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;gBACZ,MAAM,IAAI,sBAAsB,KAAK,CAAC,GAAG,IAAI,CAAC;YAClD,CAAC;YAED,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBAClB,MAAM,IAAI,kBAAkB,KAAK,CAAC,SAAS,IAAI,CAAC;YACpD,CAAC;YAED,MAAM,IAAI,IAAI,CAAC;QACnB,CAAC,CAAC,CAAC;IACP,CAAC;SAAM,CAAC;QACJ,MAAM,IAAI,0BAA0B,CAAC;IACzC,CAAC;IAED,mBAAmB;IACnB,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,iBAAiB,UAAU,CAAC,MAAM,OAAO,CAAC;QAEpD,UAAU,CAAC,OAAO,CAAC,CAAC,QAAa,EAAE,KAAa,EAAE,EAAE;YAChD,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,KAAK,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,OAAO,IAAI,CAAC;YACxE,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACrB,MAAM,IAAI,QAAQ,QAAQ,CAAC,SAAS,IAAI,CAAC;YAC7C,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,IAAI,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -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"}
|