@treedy/lsp-mcp 0.2.0 → 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 +291 -13
- package/dist/index.js.map +4 -4
- 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";
|
|
@@ -21566,6 +21567,18 @@ Analyze Python and TypeScript code for structure, types, and errors.
|
|
|
21566
21567
|
|
|
21567
21568
|
## Tools
|
|
21568
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
|
+
|
|
21569
21582
|
### symbols
|
|
21570
21583
|
|
|
21571
21584
|
Extract all symbols (classes, functions, variables) from a file.
|
|
@@ -21592,6 +21605,18 @@ diagnostics(path)
|
|
|
21592
21605
|
- Validating refactoring didn't break anything
|
|
21593
21606
|
- Finding issues before running tests
|
|
21594
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
|
+
|
|
21595
21620
|
### search
|
|
21596
21621
|
|
|
21597
21622
|
Search for patterns across the codebase using regex. Returns positions in LSP format (file, line, column).
|
|
@@ -21809,7 +21834,7 @@ function registerPrompts(server) {
|
|
|
21809
21834
|
text: `Please explore the project at '${path2 || "current workspace"}'.
|
|
21810
21835
|
|
|
21811
21836
|
Recommended Workflow:
|
|
21812
|
-
1.
|
|
21837
|
+
1. Use 'project_structure' to visualize the directory hierarchy and identify key files.
|
|
21813
21838
|
2. Identify key entry points (e.g., main.py, index.ts, App.vue, pyproject.toml, package.json).
|
|
21814
21839
|
3. Use 'summarize_file' on these entry points to extract high-level symbols (classes/functions) without reading full content.
|
|
21815
21840
|
4. Report back with a structural summary of the project.`
|
|
@@ -21829,7 +21854,7 @@ Recommended Workflow:
|
|
|
21829
21854
|
text: `Please debug and analyze the file '${file}'.
|
|
21830
21855
|
|
|
21831
21856
|
Recommended Workflow:
|
|
21832
|
-
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.
|
|
21833
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.
|
|
21834
21859
|
3. If errors are found, check specific locations with 'code_action' to see if auto-fixes (like 'Organize Imports') are available.
|
|
21835
21860
|
4. Explain the findings and propose fixes.`
|
|
@@ -21851,6 +21876,8 @@ Recommended Workflow:
|
|
|
21851
21876
|
### 1. Smart Exploration
|
|
21852
21877
|
Instead of reading raw code, use:
|
|
21853
21878
|
\`\`\`
|
|
21879
|
+
project_structure() → See file hierarchy
|
|
21880
|
+
workspace_symbol("User") → Find where "User" class is
|
|
21854
21881
|
summarize_file(file) → Get outline of classes/functions
|
|
21855
21882
|
read_file_with_hints(file) → Read code with type/param annotations
|
|
21856
21883
|
\`\`\`
|
|
@@ -21858,14 +21885,15 @@ read_file_with_hints(file) → Read code with type/param annotations
|
|
|
21858
21885
|
### 2. Search → LSP Tools
|
|
21859
21886
|
\`\`\`
|
|
21860
21887
|
search("ClassName") → get positions
|
|
21888
|
+
peek_definition(file, line, col) → See definition code immediately
|
|
21861
21889
|
hover(file, line, column) → get type info
|
|
21862
|
-
definition(...) → jump to definition
|
|
21863
21890
|
references(...) → find usages
|
|
21864
21891
|
\`\`\`
|
|
21865
21892
|
|
|
21866
21893
|
### 3. Debug & Fix
|
|
21867
21894
|
\`\`\`
|
|
21868
|
-
|
|
21895
|
+
git_diagnostics() → Check errors in changed files
|
|
21896
|
+
diagnostics(path) → Check full path
|
|
21869
21897
|
code_action(file, line, col) → Get quick fixes (e.g. Organize Imports)
|
|
21870
21898
|
run_code_action(...) → Apply fix
|
|
21871
21899
|
\`\`\`
|
|
@@ -21892,6 +21920,106 @@ var server = new McpServer({
|
|
|
21892
21920
|
version: packageJson.version
|
|
21893
21921
|
});
|
|
21894
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
|
+
}
|
|
21895
22023
|
async function startAndRegisterBackend(language) {
|
|
21896
22024
|
if (startedBackends.has(language)) {
|
|
21897
22025
|
const status2 = backendManager.getStatus()[language];
|
|
@@ -21953,7 +22081,11 @@ var UNIFIED_TOOLS = [
|
|
|
21953
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() } },
|
|
21954
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() } },
|
|
21955
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() } },
|
|
21956
|
-
{ 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: {} }
|
|
21957
22089
|
];
|
|
21958
22090
|
function applyInlayHints(content, hints, language) {
|
|
21959
22091
|
const lines = content.split(`
|
|
@@ -22071,23 +22203,116 @@ function preRegisterTools() {
|
|
|
22071
22203
|
description: `${tool.description} (unified tool, routes automatically by file extension)`,
|
|
22072
22204
|
inputSchema: tool.schema
|
|
22073
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
|
+
}
|
|
22074
22290
|
const filePath = args.file || args.path;
|
|
22075
|
-
if (tool.name === "search" && !filePath) {
|
|
22291
|
+
if ((tool.name === "search" || tool.name === "workspace_symbol") && !filePath) {
|
|
22076
22292
|
const languages = Object.keys(config2.languages).filter((lang) => config2.languages[lang].enabled);
|
|
22077
22293
|
const results = [];
|
|
22078
22294
|
for (const lang of languages) {
|
|
22079
22295
|
if (startedBackends.has(lang)) {
|
|
22080
22296
|
try {
|
|
22081
|
-
const res = await backendManager.callTool(lang,
|
|
22082
|
-
|
|
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
|
+
}
|
|
22083
22309
|
} catch (e) {}
|
|
22084
22310
|
}
|
|
22085
22311
|
}
|
|
22086
22312
|
if (results.length === 0) {
|
|
22087
|
-
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." }) }] };
|
|
22088
22314
|
}
|
|
22089
|
-
|
|
22090
|
-
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 }) }] };
|
|
22091
22316
|
}
|
|
22092
22317
|
if (!filePath) {
|
|
22093
22318
|
return {
|
|
@@ -22149,7 +22374,7 @@ function preRegisterTools() {
|
|
|
22149
22374
|
};
|
|
22150
22375
|
}
|
|
22151
22376
|
}
|
|
22152
|
-
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") {
|
|
22153
22378
|
const availableTools = await backendManager.getTools(language);
|
|
22154
22379
|
const supportsTool = availableTools.some((t) => t.name === tool.name);
|
|
22155
22380
|
if (!supportsTool) {
|
|
@@ -22190,6 +22415,59 @@ ${summary || "(No symbols found)"}`
|
|
|
22190
22415
|
};
|
|
22191
22416
|
}
|
|
22192
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
|
+
}
|
|
22193
22471
|
if (tool.name === "read_file_with_hints") {
|
|
22194
22472
|
try {
|
|
22195
22473
|
let absPath2 = filePath;
|
|
@@ -22310,4 +22588,4 @@ main().catch((error2) => {
|
|
|
22310
22588
|
process.exit(1);
|
|
22311
22589
|
});
|
|
22312
22590
|
|
|
22313
|
-
//# debugId=
|
|
22591
|
+
//# debugId=CC41A27AB80DC0BB64756E2164756E21
|