@treedy/lsp-mcp 0.1.10 → 0.2.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/dist/index.js +332 -19
- package/dist/index.js.map +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19839,6 +19839,7 @@ class StdioServerTransport {
|
|
|
19839
19839
|
import { createRequire as createRequire2 } from "module";
|
|
19840
19840
|
import * as fs2 from "fs";
|
|
19841
19841
|
import * as path2 from "path";
|
|
19842
|
+
import { execSync } from "child_process";
|
|
19842
19843
|
|
|
19843
19844
|
// src/config.ts
|
|
19844
19845
|
import * as path from "path";
|
|
@@ -19958,6 +19959,33 @@ function getEnvString(name, defaultValue) {
|
|
|
19958
19959
|
return process.env[name] ?? defaultValue;
|
|
19959
19960
|
}
|
|
19960
19961
|
function inferLanguageFromPath(filePath, config2) {
|
|
19962
|
+
if (fs.existsSync(filePath)) {
|
|
19963
|
+
try {
|
|
19964
|
+
const stat = fs.statSync(filePath);
|
|
19965
|
+
if (stat.isDirectory()) {
|
|
19966
|
+
if (config2.languages.typescript?.enabled && (fs.existsSync(path.join(filePath, "tsconfig.json")) || fs.existsSync(path.join(filePath, "package.json")))) {
|
|
19967
|
+
return "typescript";
|
|
19968
|
+
}
|
|
19969
|
+
if (config2.languages.python?.enabled && (fs.existsSync(path.join(filePath, "pyproject.toml")) || fs.existsSync(path.join(filePath, "requirements.txt")) || fs.existsSync(path.join(filePath, "setup.py")) || fs.existsSync(path.join(filePath, "venv")) || fs.existsSync(path.join(filePath, ".venv")))) {
|
|
19970
|
+
return "python";
|
|
19971
|
+
}
|
|
19972
|
+
if (config2.languages.vue?.enabled && (fs.existsSync(path.join(filePath, "vite.config.ts")) || fs.existsSync(path.join(filePath, "vue.config.js")))) {
|
|
19973
|
+
return "vue";
|
|
19974
|
+
}
|
|
19975
|
+
try {
|
|
19976
|
+
const entries = fs.readdirSync(filePath);
|
|
19977
|
+
for (const entry of entries) {
|
|
19978
|
+
if (entry.endsWith(".ts") && config2.languages.typescript?.enabled)
|
|
19979
|
+
return "typescript";
|
|
19980
|
+
if (entry.endsWith(".py") && config2.languages.python?.enabled)
|
|
19981
|
+
return "python";
|
|
19982
|
+
if (entry.endsWith(".vue") && config2.languages.vue?.enabled)
|
|
19983
|
+
return "vue";
|
|
19984
|
+
}
|
|
19985
|
+
} catch {}
|
|
19986
|
+
}
|
|
19987
|
+
} catch (e) {}
|
|
19988
|
+
}
|
|
19961
19989
|
const ext = filePath.substring(filePath.lastIndexOf("."));
|
|
19962
19990
|
for (const [lang, langConfig] of Object.entries(config2.languages)) {
|
|
19963
19991
|
if (langConfig?.enabled && langConfig.extensions.includes(ext)) {
|
|
@@ -21539,6 +21567,18 @@ Analyze Python and TypeScript code for structure, types, and errors.
|
|
|
21539
21567
|
|
|
21540
21568
|
## Tools
|
|
21541
21569
|
|
|
21570
|
+
### project_structure
|
|
21571
|
+
|
|
21572
|
+
Get a visual tree structure of the project, highlighting key files.
|
|
21573
|
+
|
|
21574
|
+
\`\`\`
|
|
21575
|
+
project_structure(path=None)
|
|
21576
|
+
\`\`\`
|
|
21577
|
+
|
|
21578
|
+
**Use when:**
|
|
21579
|
+
- Starting a new task to understand project layout
|
|
21580
|
+
- Finding entry points (main.py, package.json)
|
|
21581
|
+
|
|
21542
21582
|
### symbols
|
|
21543
21583
|
|
|
21544
21584
|
Extract all symbols (classes, functions, variables) from a file.
|
|
@@ -21565,6 +21605,18 @@ diagnostics(path)
|
|
|
21565
21605
|
- Validating refactoring didn't break anything
|
|
21566
21606
|
- Finding issues before running tests
|
|
21567
21607
|
|
|
21608
|
+
### git_diagnostics
|
|
21609
|
+
|
|
21610
|
+
Check for errors ONLY in files changed in Git (working tree + staged).
|
|
21611
|
+
|
|
21612
|
+
\`\`\`
|
|
21613
|
+
git_diagnostics()
|
|
21614
|
+
\`\`\`
|
|
21615
|
+
|
|
21616
|
+
**Use when:**
|
|
21617
|
+
- Fast feedback loop after editing code
|
|
21618
|
+
- "Did I break anything I just touched?"
|
|
21619
|
+
|
|
21568
21620
|
### search
|
|
21569
21621
|
|
|
21570
21622
|
Search for patterns across the codebase using regex. Returns positions in LSP format (file, line, column).
|
|
@@ -21782,7 +21834,7 @@ function registerPrompts(server) {
|
|
|
21782
21834
|
text: `Please explore the project at '${path2 || "current workspace"}'.
|
|
21783
21835
|
|
|
21784
21836
|
Recommended Workflow:
|
|
21785
|
-
1.
|
|
21837
|
+
1. Use 'project_structure' to visualize the directory hierarchy and identify key files.
|
|
21786
21838
|
2. Identify key entry points (e.g., main.py, index.ts, App.vue, pyproject.toml, package.json).
|
|
21787
21839
|
3. Use 'summarize_file' on these entry points to extract high-level symbols (classes/functions) without reading full content.
|
|
21788
21840
|
4. Report back with a structural summary of the project.`
|
|
@@ -21802,7 +21854,7 @@ Recommended Workflow:
|
|
|
21802
21854
|
text: `Please debug and analyze the file '${file}'.
|
|
21803
21855
|
|
|
21804
21856
|
Recommended Workflow:
|
|
21805
|
-
1. Run 'diagnostics' on the file to identify syntax errors, type mismatches, or unused imports.
|
|
21857
|
+
1. Run 'diagnostics' on the file (or 'git_diagnostics' to check recent changes) to identify syntax errors, type mismatches, or unused imports.
|
|
21806
21858
|
2. Use 'read_file_with_hints' to read the content. This will reveal inferred types and parameter names, making it easier to spot logic errors.
|
|
21807
21859
|
3. If errors are found, check specific locations with 'code_action' to see if auto-fixes (like 'Organize Imports') are available.
|
|
21808
21860
|
4. Explain the findings and propose fixes.`
|
|
@@ -21824,6 +21876,8 @@ Recommended Workflow:
|
|
|
21824
21876
|
### 1. Smart Exploration
|
|
21825
21877
|
Instead of reading raw code, use:
|
|
21826
21878
|
\`\`\`
|
|
21879
|
+
project_structure() → See file hierarchy
|
|
21880
|
+
workspace_symbol("User") → Find where "User" class is
|
|
21827
21881
|
summarize_file(file) → Get outline of classes/functions
|
|
21828
21882
|
read_file_with_hints(file) → Read code with type/param annotations
|
|
21829
21883
|
\`\`\`
|
|
@@ -21831,14 +21885,15 @@ read_file_with_hints(file) → Read code with type/param annotations
|
|
|
21831
21885
|
### 2. Search → LSP Tools
|
|
21832
21886
|
\`\`\`
|
|
21833
21887
|
search("ClassName") → get positions
|
|
21888
|
+
peek_definition(file, line, col) → See definition code immediately
|
|
21834
21889
|
hover(file, line, column) → get type info
|
|
21835
|
-
definition(...) → jump to definition
|
|
21836
21890
|
references(...) → find usages
|
|
21837
21891
|
\`\`\`
|
|
21838
21892
|
|
|
21839
21893
|
### 3. Debug & Fix
|
|
21840
21894
|
\`\`\`
|
|
21841
|
-
|
|
21895
|
+
git_diagnostics() → Check errors in changed files
|
|
21896
|
+
diagnostics(path) → Check full path
|
|
21842
21897
|
code_action(file, line, col) → Get quick fixes (e.g. Organize Imports)
|
|
21843
21898
|
run_code_action(...) → Apply fix
|
|
21844
21899
|
\`\`\`
|
|
@@ -21865,6 +21920,106 @@ var server = new McpServer({
|
|
|
21865
21920
|
version: packageJson.version
|
|
21866
21921
|
});
|
|
21867
21922
|
registerPrompts(server);
|
|
21923
|
+
function getProjectStructure(dirPath, depth = 0, maxDepth = 3) {
|
|
21924
|
+
const IGNORED_DIRS = new Set([".git", "node_modules", "dist", "build", "coverage", "__pycache__", ".venv", ".idea", ".vscode", ".next", ".nuxt"]);
|
|
21925
|
+
const KEY_FILES = new Set(["package.json", "tsconfig.json", "pyproject.toml", "requirements.txt", "README.md", "Dockerfile", "docker-compose.yml", "cargo.toml", "go.mod", "gemfile"]);
|
|
21926
|
+
if (depth > maxDepth)
|
|
21927
|
+
return "";
|
|
21928
|
+
let output = "";
|
|
21929
|
+
let entries;
|
|
21930
|
+
try {
|
|
21931
|
+
entries = fs2.readdirSync(dirPath, { withFileTypes: true });
|
|
21932
|
+
} catch (e) {
|
|
21933
|
+
return "";
|
|
21934
|
+
}
|
|
21935
|
+
entries.sort((a, b) => {
|
|
21936
|
+
if (a.isDirectory() && !b.isDirectory())
|
|
21937
|
+
return -1;
|
|
21938
|
+
if (!a.isDirectory() && b.isDirectory())
|
|
21939
|
+
return 1;
|
|
21940
|
+
return a.name.localeCompare(b.name);
|
|
21941
|
+
});
|
|
21942
|
+
for (const entry of entries) {
|
|
21943
|
+
if (entry.name.startsWith("."))
|
|
21944
|
+
continue;
|
|
21945
|
+
if (IGNORED_DIRS.has(entry.name))
|
|
21946
|
+
continue;
|
|
21947
|
+
const isDir = entry.isDirectory();
|
|
21948
|
+
const indent = " ".repeat(depth);
|
|
21949
|
+
const marker = isDir ? "\uD83D\uDCC1 " : "\uD83D\uDCC4 ";
|
|
21950
|
+
const isKeyFile = KEY_FILES.has(entry.name.toLowerCase());
|
|
21951
|
+
const extra = isKeyFile ? " (config)" : "";
|
|
21952
|
+
output += `${indent}${marker}${entry.name}${extra}
|
|
21953
|
+
`;
|
|
21954
|
+
if (isDir) {
|
|
21955
|
+
output += getProjectStructure(path2.join(dirPath, entry.name), depth + 1, maxDepth);
|
|
21956
|
+
}
|
|
21957
|
+
}
|
|
21958
|
+
return output;
|
|
21959
|
+
}
|
|
21960
|
+
function getGitChangedFiles(cwd) {
|
|
21961
|
+
try {
|
|
21962
|
+
const gitRoot = execSync("git rev-parse --show-toplevel", { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
21963
|
+
const files = new Set;
|
|
21964
|
+
try {
|
|
21965
|
+
const stdout = execSync("git diff --name-only", { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
21966
|
+
stdout.split(`
|
|
21967
|
+
`).forEach((f) => {
|
|
21968
|
+
if (f.trim())
|
|
21969
|
+
files.add(path2.resolve(gitRoot, f.trim()));
|
|
21970
|
+
});
|
|
21971
|
+
} catch (e) {}
|
|
21972
|
+
try {
|
|
21973
|
+
const stdout = execSync("git diff --staged --name-only", { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
21974
|
+
stdout.split(`
|
|
21975
|
+
`).forEach((f) => {
|
|
21976
|
+
if (f.trim())
|
|
21977
|
+
files.add(path2.resolve(gitRoot, f.trim()));
|
|
21978
|
+
});
|
|
21979
|
+
} catch (e) {}
|
|
21980
|
+
return Array.from(files);
|
|
21981
|
+
} catch (error2) {
|
|
21982
|
+
return [];
|
|
21983
|
+
}
|
|
21984
|
+
}
|
|
21985
|
+
function validateAndFixPosition(filePath, line, column) {
|
|
21986
|
+
try {
|
|
21987
|
+
if (!fs2.existsSync(filePath))
|
|
21988
|
+
return { line, column };
|
|
21989
|
+
const stats = fs2.statSync(filePath);
|
|
21990
|
+
if (stats.size > 1024 * 1024)
|
|
21991
|
+
return { line, column };
|
|
21992
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
21993
|
+
const lines = content.split(`
|
|
21994
|
+
`);
|
|
21995
|
+
let newLine = line;
|
|
21996
|
+
let warning = "";
|
|
21997
|
+
if (newLine > lines.length) {
|
|
21998
|
+
newLine = lines.length;
|
|
21999
|
+
warning = `Line ${line} out of bounds (max ${lines.length}). Clamped to ${newLine}.`;
|
|
22000
|
+
}
|
|
22001
|
+
if (newLine < 1) {
|
|
22002
|
+
newLine = 1;
|
|
22003
|
+
warning = `Line ${line} must be positive. Clamped to 1.`;
|
|
22004
|
+
}
|
|
22005
|
+
const lineContent = lines[newLine - 1] || "";
|
|
22006
|
+
let newColumn = column;
|
|
22007
|
+
const maxCol = lineContent.length + 1;
|
|
22008
|
+
if (newColumn > maxCol) {
|
|
22009
|
+
newColumn = maxCol;
|
|
22010
|
+
const w = `Column ${column} out of bounds (max ${maxCol}). Clamped to ${newColumn}.`;
|
|
22011
|
+
warning = warning ? `${warning} ${w}` : w;
|
|
22012
|
+
}
|
|
22013
|
+
if (newColumn < 1) {
|
|
22014
|
+
newColumn = 1;
|
|
22015
|
+
const w = `Column ${column} must be positive. Clamped to 1.`;
|
|
22016
|
+
warning = warning ? `${warning} ${w}` : w;
|
|
22017
|
+
}
|
|
22018
|
+
return { line: newLine, column: newColumn, warning: warning || undefined };
|
|
22019
|
+
} catch (e) {
|
|
22020
|
+
return { line, column };
|
|
22021
|
+
}
|
|
22022
|
+
}
|
|
21868
22023
|
async function startAndRegisterBackend(language) {
|
|
21869
22024
|
if (startedBackends.has(language)) {
|
|
21870
22025
|
const status2 = backendManager.getStatus()[language];
|
|
@@ -21926,7 +22081,11 @@ var UNIFIED_TOOLS = [
|
|
|
21926
22081
|
{ name: "summarize_file", description: "Get a high-level outline of a file (classes, functions, methods) to understand its structure without reading the full content.", schema: { file: exports_external.string() } },
|
|
21927
22082
|
{ name: "read_file_with_hints", description: "Read file content with inlay hints (type annotations, parameter names) inserted as comments. Useful for understanding complex code.", schema: { file: exports_external.string() } },
|
|
21928
22083
|
{ name: "code_action", description: "Get available code actions (refactors and quick fixes) at a specific position", schema: { file: exports_external.string(), line: exports_external.number().int().positive(), column: exports_external.number().int().positive() } },
|
|
21929
|
-
{ name: "run_code_action", description: "Apply a code action (refactor or quick fix)", schema: { file: exports_external.string(), line: exports_external.number().int().positive(), column: exports_external.number().int().positive(), kind: exports_external.enum(["refactor", "quickfix"]), name: exports_external.string(), actionName: exports_external.string().optional(), preview: exports_external.boolean().default(false).optional() } }
|
|
22084
|
+
{ name: "run_code_action", description: "Apply a code action (refactor or quick fix)", schema: { file: exports_external.string(), line: exports_external.number().int().positive(), column: exports_external.number().int().positive(), kind: exports_external.enum(["refactor", "quickfix"]), name: exports_external.string(), actionName: exports_external.string().optional(), preview: exports_external.boolean().default(false).optional() } },
|
|
22085
|
+
{ name: "workspace_symbol", description: "Search for a symbol (class, function, etc.) across the entire workspace. Returns locations that can be used with peek_definition.", schema: { query: exports_external.string() } },
|
|
22086
|
+
{ name: "peek_definition", description: "Go to definition and return the surrounding code context immediately. Reduces round-trips compared to definition() + read_file().", schema: { file: exports_external.string(), line: exports_external.number().int().positive(), column: exports_external.number().int().positive() } },
|
|
22087
|
+
{ name: "project_structure", description: "Get a visual tree structure of the project to understand hierarchy and identify key files. Ignores build artifacts.", schema: { path: exports_external.string().optional() } },
|
|
22088
|
+
{ name: "git_diagnostics", description: "Check for errors/warnings ONLY in files changed in Git (working tree + staged). Useful for checking your changes.", schema: {} }
|
|
21930
22089
|
];
|
|
21931
22090
|
function applyInlayHints(content, hints, language) {
|
|
21932
22091
|
const lines = content.split(`
|
|
@@ -22044,30 +22203,131 @@ function preRegisterTools() {
|
|
|
22044
22203
|
description: `${tool.description} (unified tool, routes automatically by file extension)`,
|
|
22045
22204
|
inputSchema: tool.schema
|
|
22046
22205
|
}, async (args) => {
|
|
22206
|
+
let paramWarning;
|
|
22207
|
+
if (typeof args.line === "number" && typeof args.column === "number") {
|
|
22208
|
+
const targetFile = args.file || args.path;
|
|
22209
|
+
if (targetFile) {
|
|
22210
|
+
let checkPath = targetFile;
|
|
22211
|
+
if (!path2.isAbsolute(checkPath) && activeWorkspacePath) {
|
|
22212
|
+
checkPath = path2.join(activeWorkspacePath, checkPath);
|
|
22213
|
+
} else if (!path2.isAbsolute(checkPath)) {
|
|
22214
|
+
checkPath = path2.resolve(checkPath);
|
|
22215
|
+
}
|
|
22216
|
+
const fixed = validateAndFixPosition(checkPath, args.line, args.column);
|
|
22217
|
+
if (fixed.warning) {
|
|
22218
|
+
console.error(`[lsp-mcp] Auto-corrected params for ${tool.name}: ${fixed.warning}`);
|
|
22219
|
+
args.line = fixed.line;
|
|
22220
|
+
args.column = fixed.column;
|
|
22221
|
+
paramWarning = `(Auto-corrected: ${fixed.warning})`;
|
|
22222
|
+
}
|
|
22223
|
+
}
|
|
22224
|
+
}
|
|
22225
|
+
if (tool.name === "project_structure") {
|
|
22226
|
+
const targetPath = args.path || activeWorkspacePath || process.cwd();
|
|
22227
|
+
const tree = getProjectStructure(targetPath);
|
|
22228
|
+
return {
|
|
22229
|
+
content: [{ type: "text", text: `Project Structure for ${targetPath}:
|
|
22230
|
+
|
|
22231
|
+
${tree}` }]
|
|
22232
|
+
};
|
|
22233
|
+
}
|
|
22234
|
+
if (tool.name === "git_diagnostics") {
|
|
22235
|
+
const cwd = activeWorkspacePath || process.cwd();
|
|
22236
|
+
const changedFiles = getGitChangedFiles(cwd);
|
|
22237
|
+
if (changedFiles.length === 0) {
|
|
22238
|
+
return { content: [{ type: "text", text: "No changed files found in git." }] };
|
|
22239
|
+
}
|
|
22240
|
+
const results = [];
|
|
22241
|
+
for (const file of changedFiles) {
|
|
22242
|
+
const language2 = inferLanguageFromPath(file, config2);
|
|
22243
|
+
if (!language2)
|
|
22244
|
+
continue;
|
|
22245
|
+
if (!startedBackends.has(language2)) {
|
|
22246
|
+
try {
|
|
22247
|
+
await backendManager.getBackend(language2);
|
|
22248
|
+
startedBackends.add(language2);
|
|
22249
|
+
} catch (e) {
|
|
22250
|
+
results.push(`Could not check ${path2.basename(file)}: Backend failed to start`);
|
|
22251
|
+
continue;
|
|
22252
|
+
}
|
|
22253
|
+
}
|
|
22254
|
+
try {
|
|
22255
|
+
const relativePath = path2.relative(cwd, file);
|
|
22256
|
+
const res = await backendManager.callTool(language2, "diagnostics", { path: relativePath });
|
|
22257
|
+
const parsed = JSON.parse(res.content[0].text);
|
|
22258
|
+
if (parsed.error) {
|
|
22259
|
+
results.push(`⚠️ ${path2.basename(file)}: Backend error: ${parsed.error}`);
|
|
22260
|
+
continue;
|
|
22261
|
+
}
|
|
22262
|
+
let diagnostics = [];
|
|
22263
|
+
if (Array.isArray(parsed))
|
|
22264
|
+
diagnostics = parsed;
|
|
22265
|
+
else if (parsed.diagnostics && Array.isArray(parsed.diagnostics))
|
|
22266
|
+
diagnostics = parsed.diagnostics;
|
|
22267
|
+
else {
|
|
22268
|
+
console.error(`[lsp-mcp] Unexpected diagnostics format for ${file}:`, parsed);
|
|
22269
|
+
results.push(`⚠️ ${path2.basename(file)}: Unexpected response format`);
|
|
22270
|
+
continue;
|
|
22271
|
+
}
|
|
22272
|
+
if (diagnostics.length === 0) {
|
|
22273
|
+
results.push(`✅ ${path2.basename(file)}: No errors`);
|
|
22274
|
+
} else {
|
|
22275
|
+
const errors4 = diagnostics.map((d) => ` - [Line ${d.range?.start?.line ?? d.line ?? "?"}] ${d.message}`).join(`
|
|
22276
|
+
`);
|
|
22277
|
+
results.push(`❌ ${path2.basename(file)}:
|
|
22278
|
+
${errors4}`);
|
|
22279
|
+
}
|
|
22280
|
+
} catch (e) {
|
|
22281
|
+
results.push(`⚠️ ${path2.basename(file)}: Check failed (${e})`);
|
|
22282
|
+
}
|
|
22283
|
+
}
|
|
22284
|
+
return { content: [{ type: "text", text: `Git Diagnostics Report:
|
|
22285
|
+
|
|
22286
|
+
${results.join(`
|
|
22287
|
+
|
|
22288
|
+
`)}` }] };
|
|
22289
|
+
}
|
|
22047
22290
|
const filePath = args.file || args.path;
|
|
22048
|
-
if (tool.name === "search" && !filePath) {
|
|
22291
|
+
if ((tool.name === "search" || tool.name === "workspace_symbol") && !filePath) {
|
|
22049
22292
|
const languages = Object.keys(config2.languages).filter((lang) => config2.languages[lang].enabled);
|
|
22050
22293
|
const results = [];
|
|
22051
22294
|
for (const lang of languages) {
|
|
22052
22295
|
if (startedBackends.has(lang)) {
|
|
22053
22296
|
try {
|
|
22054
|
-
const res = await backendManager.callTool(lang,
|
|
22055
|
-
|
|
22297
|
+
const res = await backendManager.callTool(lang, tool.name, args);
|
|
22298
|
+
const parsed = JSON.parse(res.content[0].text);
|
|
22299
|
+
let items = [];
|
|
22300
|
+
if (Array.isArray(parsed))
|
|
22301
|
+
items = parsed;
|
|
22302
|
+
else if (parsed.matches)
|
|
22303
|
+
items = parsed.matches;
|
|
22304
|
+
else if (parsed.symbols)
|
|
22305
|
+
items = parsed.symbols;
|
|
22306
|
+
if (items.length > 0) {
|
|
22307
|
+
results.push(...items.map((i) => ({ ...i, language: lang })));
|
|
22308
|
+
}
|
|
22056
22309
|
} catch (e) {}
|
|
22057
22310
|
}
|
|
22058
22311
|
}
|
|
22059
22312
|
if (results.length === 0) {
|
|
22060
|
-
return { content: [{ type: "text", text: JSON.stringify({ matches: [], count: 0, message: "No
|
|
22313
|
+
return { content: [{ type: "text", text: JSON.stringify({ matches: [], count: 0, message: "No matches found or no active backends." }) }] };
|
|
22061
22314
|
}
|
|
22062
|
-
|
|
22063
|
-
return { content: [{ type: "text", text: JSON.stringify({ matches: allMatches, count: allMatches.length }) }] };
|
|
22315
|
+
return { content: [{ type: "text", text: JSON.stringify({ matches: results, count: results.length }) }] };
|
|
22064
22316
|
}
|
|
22065
22317
|
if (!filePath) {
|
|
22066
22318
|
return {
|
|
22067
22319
|
content: [{ type: "text", text: JSON.stringify({ error: "Missing 'file' or 'path' argument required for unified routing" }) }]
|
|
22068
22320
|
};
|
|
22069
22321
|
}
|
|
22070
|
-
|
|
22322
|
+
let absPath = filePath;
|
|
22323
|
+
if (!path2.isAbsolute(filePath)) {
|
|
22324
|
+
if (activeWorkspacePath) {
|
|
22325
|
+
absPath = path2.join(activeWorkspacePath, filePath);
|
|
22326
|
+
} else {
|
|
22327
|
+
absPath = path2.resolve(filePath);
|
|
22328
|
+
}
|
|
22329
|
+
}
|
|
22330
|
+
const language = inferLanguageFromPath(absPath, config2);
|
|
22071
22331
|
if (!language) {
|
|
22072
22332
|
return {
|
|
22073
22333
|
content: [
|
|
@@ -22114,7 +22374,7 @@ function preRegisterTools() {
|
|
|
22114
22374
|
};
|
|
22115
22375
|
}
|
|
22116
22376
|
}
|
|
22117
|
-
if (tool.name !== "summarize_file" && tool.name !== "read_file_with_hints") {
|
|
22377
|
+
if (tool.name !== "summarize_file" && tool.name !== "read_file_with_hints" && tool.name !== "peek_definition") {
|
|
22118
22378
|
const availableTools = await backendManager.getTools(language);
|
|
22119
22379
|
const supportsTool = availableTools.some((t) => t.name === tool.name);
|
|
22120
22380
|
if (!supportsTool) {
|
|
@@ -22155,16 +22415,69 @@ ${summary || "(No symbols found)"}`
|
|
|
22155
22415
|
};
|
|
22156
22416
|
}
|
|
22157
22417
|
}
|
|
22418
|
+
if (tool.name === "peek_definition") {
|
|
22419
|
+
try {
|
|
22420
|
+
const result = await backendManager.callTool(language, "definition", args);
|
|
22421
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
22422
|
+
if (parsed.error) {
|
|
22423
|
+
return { content: [{ type: "text", text: JSON.stringify(parsed) }] };
|
|
22424
|
+
}
|
|
22425
|
+
let locs = Array.isArray(parsed) ? parsed : [parsed];
|
|
22426
|
+
if (parsed.matches)
|
|
22427
|
+
locs = parsed.matches;
|
|
22428
|
+
if (!locs || locs.length === 0) {
|
|
22429
|
+
return { content: [{ type: "text", text: JSON.stringify({ message: "No definition found" }) }] };
|
|
22430
|
+
}
|
|
22431
|
+
const def = locs[0];
|
|
22432
|
+
const defPath = def.file || def.uri;
|
|
22433
|
+
if (!defPath) {
|
|
22434
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "Invalid definition result", raw: parsed }) }] };
|
|
22435
|
+
}
|
|
22436
|
+
let defAbsPath = defPath;
|
|
22437
|
+
if (!path2.isAbsolute(defPath) && activeWorkspacePath) {
|
|
22438
|
+
defAbsPath = path2.join(activeWorkspacePath, defPath);
|
|
22439
|
+
}
|
|
22440
|
+
if (!fs2.existsSync(defAbsPath)) {
|
|
22441
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Definition file not found: ${defAbsPath}`, location: def }) }] };
|
|
22442
|
+
}
|
|
22443
|
+
const fileContent = fs2.readFileSync(defAbsPath, "utf-8");
|
|
22444
|
+
const lines = fileContent.split(`
|
|
22445
|
+
`);
|
|
22446
|
+
const targetLine = def.line;
|
|
22447
|
+
const lineIdx = targetLine - 1;
|
|
22448
|
+
const CONTEXT_LINES = 10;
|
|
22449
|
+
const startIdx = Math.max(0, lineIdx - CONTEXT_LINES);
|
|
22450
|
+
const endIdx = Math.min(lines.length, lineIdx + CONTEXT_LINES + 1);
|
|
22451
|
+
const contextSnippet = lines.slice(startIdx, endIdx).map((line, i) => {
|
|
22452
|
+
const currentLineNum = startIdx + i + 1;
|
|
22453
|
+
const marker = currentLineNum === targetLine ? " >" : " ";
|
|
22454
|
+
return `${marker} ${currentLineNum.toString().padEnd(4)} | ${line}`;
|
|
22455
|
+
}).join(`
|
|
22456
|
+
`);
|
|
22457
|
+
const responseText = `Definition found in ${defPath} at line ${targetLine}:
|
|
22458
|
+
|
|
22459
|
+
` + "```" + (language === "python" ? "python" : "typescript") + `
|
|
22460
|
+
` + contextSnippet + `
|
|
22461
|
+
` + "```";
|
|
22462
|
+
return {
|
|
22463
|
+
content: [{ type: "text", text: responseText }]
|
|
22464
|
+
};
|
|
22465
|
+
} catch (error2) {
|
|
22466
|
+
return {
|
|
22467
|
+
content: [{ type: "text", text: JSON.stringify({ error: `Failed to peek definition: ${error2}` }) }]
|
|
22468
|
+
};
|
|
22469
|
+
}
|
|
22470
|
+
}
|
|
22158
22471
|
if (tool.name === "read_file_with_hints") {
|
|
22159
22472
|
try {
|
|
22160
|
-
let
|
|
22473
|
+
let absPath2 = filePath;
|
|
22161
22474
|
if (!path2.isAbsolute(filePath) && activeWorkspacePath) {
|
|
22162
|
-
|
|
22475
|
+
absPath2 = path2.join(activeWorkspacePath, filePath);
|
|
22163
22476
|
}
|
|
22164
|
-
if (!fs2.existsSync(
|
|
22165
|
-
return { content: [{ type: "text", text: JSON.stringify({ error: `File not found: ${
|
|
22477
|
+
if (!fs2.existsSync(absPath2)) {
|
|
22478
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `File not found: ${absPath2}` }) }] };
|
|
22166
22479
|
}
|
|
22167
|
-
const content = fs2.readFileSync(
|
|
22480
|
+
const content = fs2.readFileSync(absPath2, "utf-8");
|
|
22168
22481
|
const result = await backendManager.callTool(language, "inlay_hints", args);
|
|
22169
22482
|
const parsed = JSON.parse(result.content[0].text);
|
|
22170
22483
|
if (parsed.error) {
|
|
@@ -22275,4 +22588,4 @@ main().catch((error2) => {
|
|
|
22275
22588
|
process.exit(1);
|
|
22276
22589
|
});
|
|
22277
22590
|
|
|
22278
|
-
//# debugId=
|
|
22591
|
+
//# debugId=CC41A27AB80DC0BB64756E2164756E21
|