claude-ide-bridge 1.1.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/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/activityLog.d.ts +26 -0
- package/dist/activityLog.js +76 -0
- package/dist/activityLog.js.map +1 -0
- package/dist/bridge.d.ts +19 -0
- package/dist/bridge.js +277 -0
- package/dist/bridge.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.js +221 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +20 -0
- package/dist/errors.js.map +1 -0
- package/dist/extensionClient.d.ts +193 -0
- package/dist/extensionClient.js +698 -0
- package/dist/extensionClient.js.map +1 -0
- package/dist/fileLock.d.ts +12 -0
- package/dist/fileLock.js +30 -0
- package/dist/fileLock.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/lockfile.d.ts +12 -0
- package/dist/lockfile.js +127 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +68 -0
- package/dist/logger.js.map +1 -0
- package/dist/probe.d.ts +22 -0
- package/dist/probe.js +45 -0
- package/dist/probe.js.map +1 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.js +265 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/activityLog.d.ts +39 -0
- package/dist/tools/activityLog.js +49 -0
- package/dist/tools/activityLog.js.map +1 -0
- package/dist/tools/aiComments.d.ts +26 -0
- package/dist/tools/aiComments.js +196 -0
- package/dist/tools/aiComments.js.map +1 -0
- package/dist/tools/bridgeStatus.d.ts +21 -0
- package/dist/tools/bridgeStatus.js +41 -0
- package/dist/tools/bridgeStatus.js.map +1 -0
- package/dist/tools/checkDocumentDirty.d.ts +28 -0
- package/dist/tools/checkDocumentDirty.js +61 -0
- package/dist/tools/checkDocumentDirty.js.map +1 -0
- package/dist/tools/clipboard.d.ts +50 -0
- package/dist/tools/clipboard.js +82 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/closeTabs.d.ts +49 -0
- package/dist/tools/closeTabs.js +77 -0
- package/dist/tools/closeTabs.js.map +1 -0
- package/dist/tools/debug.d.ts +154 -0
- package/dist/tools/debug.js +248 -0
- package/dist/tools/debug.js.map +1 -0
- package/dist/tools/decorations.d.ts +92 -0
- package/dist/tools/decorations.js +150 -0
- package/dist/tools/decorations.js.map +1 -0
- package/dist/tools/diffDebugger.d.ts +62 -0
- package/dist/tools/diffDebugger.js +245 -0
- package/dist/tools/diffDebugger.js.map +1 -0
- package/dist/tools/editText.d.ts +80 -0
- package/dist/tools/editText.js +274 -0
- package/dist/tools/editText.js.map +1 -0
- package/dist/tools/fileOperations.d.ts +111 -0
- package/dist/tools/fileOperations.js +280 -0
- package/dist/tools/fileOperations.js.map +1 -0
- package/dist/tools/fileWatcher.d.ts +54 -0
- package/dist/tools/fileWatcher.js +100 -0
- package/dist/tools/fileWatcher.js.map +1 -0
- package/dist/tools/findFiles.d.ts +31 -0
- package/dist/tools/findFiles.js +119 -0
- package/dist/tools/findFiles.js.map +1 -0
- package/dist/tools/fixAllLintErrors.d.ts +29 -0
- package/dist/tools/fixAllLintErrors.js +114 -0
- package/dist/tools/fixAllLintErrors.js.map +1 -0
- package/dist/tools/flowGuardian.d.ts +61 -0
- package/dist/tools/flowGuardian.js +311 -0
- package/dist/tools/flowGuardian.js.map +1 -0
- package/dist/tools/formatDocument.d.ts +30 -0
- package/dist/tools/formatDocument.js +132 -0
- package/dist/tools/formatDocument.js.map +1 -0
- package/dist/tools/formatFile.d.ts +28 -0
- package/dist/tools/formatFile.js +110 -0
- package/dist/tools/formatFile.js.map +1 -0
- package/dist/tools/getBufferContent.d.ts +38 -0
- package/dist/tools/getBufferContent.js +100 -0
- package/dist/tools/getBufferContent.js.map +1 -0
- package/dist/tools/getCurrentSelection.d.ts +43 -0
- package/dist/tools/getCurrentSelection.js +75 -0
- package/dist/tools/getCurrentSelection.js.map +1 -0
- package/dist/tools/getDiagnostics.d.ts +38 -0
- package/dist/tools/getDiagnostics.js +204 -0
- package/dist/tools/getDiagnostics.js.map +1 -0
- package/dist/tools/getDocumentSymbols.d.ts +27 -0
- package/dist/tools/getDocumentSymbols.js +133 -0
- package/dist/tools/getDocumentSymbols.js.map +1 -0
- package/dist/tools/getFileTree.d.ts +36 -0
- package/dist/tools/getFileTree.js +111 -0
- package/dist/tools/getFileTree.js.map +1 -0
- package/dist/tools/getGitDiff.d.ts +34 -0
- package/dist/tools/getGitDiff.js +57 -0
- package/dist/tools/getGitDiff.js.map +1 -0
- package/dist/tools/getGitLog.d.ts +30 -0
- package/dist/tools/getGitLog.js +65 -0
- package/dist/tools/getGitLog.js.map +1 -0
- package/dist/tools/getGitStatus.d.ts +26 -0
- package/dist/tools/getGitStatus.js +95 -0
- package/dist/tools/getGitStatus.js.map +1 -0
- package/dist/tools/getOpenEditors.d.ts +21 -0
- package/dist/tools/getOpenEditors.js +84 -0
- package/dist/tools/getOpenEditors.js.map +1 -0
- package/dist/tools/getProjectInfo.d.ts +20 -0
- package/dist/tools/getProjectInfo.js +315 -0
- package/dist/tools/getProjectInfo.js.map +1 -0
- package/dist/tools/getToolCapabilities.d.ts +23 -0
- package/dist/tools/getToolCapabilities.js +249 -0
- package/dist/tools/getToolCapabilities.js.map +1 -0
- package/dist/tools/getWorkspaceFolders.d.ts +21 -0
- package/dist/tools/getWorkspaceFolders.js +47 -0
- package/dist/tools/getWorkspaceFolders.js.map +1 -0
- package/dist/tools/gitHistory.d.ts +78 -0
- package/dist/tools/gitHistory.js +151 -0
- package/dist/tools/gitHistory.js.map +1 -0
- package/dist/tools/gitWrite.d.ts +335 -0
- package/dist/tools/gitWrite.js +859 -0
- package/dist/tools/gitWrite.js.map +1 -0
- package/dist/tools/github/actions.d.ts +67 -0
- package/dist/tools/github/actions.js +155 -0
- package/dist/tools/github/actions.js.map +1 -0
- package/dist/tools/github/index.d.ts +4 -0
- package/dist/tools/github/index.js +5 -0
- package/dist/tools/github/index.js.map +1 -0
- package/dist/tools/github/issues.d.ts +140 -0
- package/dist/tools/github/issues.js +279 -0
- package/dist/tools/github/issues.js.map +1 -0
- package/dist/tools/github/pr.d.ts +101 -0
- package/dist/tools/github/pr.js +215 -0
- package/dist/tools/github/pr.js.map +1 -0
- package/dist/tools/github/review.d.ts +101 -0
- package/dist/tools/github/review.js +292 -0
- package/dist/tools/github/review.js.map +1 -0
- package/dist/tools/github/shared.d.ts +4 -0
- package/dist/tools/github/shared.js +12 -0
- package/dist/tools/github/shared.js.map +1 -0
- package/dist/tools/github.d.ts +308 -0
- package/dist/tools/github.js +656 -0
- package/dist/tools/github.js.map +1 -0
- package/dist/tools/hoverAtCursor.d.ts +22 -0
- package/dist/tools/hoverAtCursor.js +51 -0
- package/dist/tools/hoverAtCursor.js.map +1 -0
- package/dist/tools/httpClient.d.ts +83 -0
- package/dist/tools/httpClient.js +335 -0
- package/dist/tools/httpClient.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.js +246 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/inlayHints.d.ts +38 -0
- package/dist/tools/inlayHints.js +56 -0
- package/dist/tools/inlayHints.js.map +1 -0
- package/dist/tools/linters/biome.d.ts +2 -0
- package/dist/tools/linters/biome.js +44 -0
- package/dist/tools/linters/biome.js.map +1 -0
- package/dist/tools/linters/cargo.d.ts +2 -0
- package/dist/tools/linters/cargo.js +45 -0
- package/dist/tools/linters/cargo.js.map +1 -0
- package/dist/tools/linters/eslint.d.ts +2 -0
- package/dist/tools/linters/eslint.js +59 -0
- package/dist/tools/linters/eslint.js.map +1 -0
- package/dist/tools/linters/govet.d.ts +2 -0
- package/dist/tools/linters/govet.js +37 -0
- package/dist/tools/linters/govet.js.map +1 -0
- package/dist/tools/linters/pyright.d.ts +2 -0
- package/dist/tools/linters/pyright.js +34 -0
- package/dist/tools/linters/pyright.js.map +1 -0
- package/dist/tools/linters/ruff.d.ts +2 -0
- package/dist/tools/linters/ruff.js +30 -0
- package/dist/tools/linters/ruff.js.map +1 -0
- package/dist/tools/linters/types.d.ts +16 -0
- package/dist/tools/linters/types.js +2 -0
- package/dist/tools/linters/types.js.map +1 -0
- package/dist/tools/linters/typescript.d.ts +2 -0
- package/dist/tools/linters/typescript.js +38 -0
- package/dist/tools/linters/typescript.js.map +1 -0
- package/dist/tools/lsp.d.ts +310 -0
- package/dist/tools/lsp.js +684 -0
- package/dist/tools/lsp.js.map +1 -0
- package/dist/tools/notebook.d.ts +95 -0
- package/dist/tools/notebook.js +144 -0
- package/dist/tools/notebook.js.map +1 -0
- package/dist/tools/openDiff.d.ts +41 -0
- package/dist/tools/openDiff.js +116 -0
- package/dist/tools/openDiff.js.map +1 -0
- package/dist/tools/openFile.d.ts +34 -0
- package/dist/tools/openFile.js +102 -0
- package/dist/tools/openFile.js.map +1 -0
- package/dist/tools/organizeImports.d.ts +29 -0
- package/dist/tools/organizeImports.js +64 -0
- package/dist/tools/organizeImports.js.map +1 -0
- package/dist/tools/planPersistence.d.ts +196 -0
- package/dist/tools/planPersistence.js +437 -0
- package/dist/tools/planPersistence.js.map +1 -0
- package/dist/tools/replaceBlock.d.ts +40 -0
- package/dist/tools/replaceBlock.js +105 -0
- package/dist/tools/replaceBlock.js.map +1 -0
- package/dist/tools/runCommand.d.ts +43 -0
- package/dist/tools/runCommand.js +141 -0
- package/dist/tools/runCommand.js.map +1 -0
- package/dist/tools/runTests.d.ts +32 -0
- package/dist/tools/runTests.js +160 -0
- package/dist/tools/runTests.js.map +1 -0
- package/dist/tools/saveDocument.d.ts +28 -0
- package/dist/tools/saveDocument.js +58 -0
- package/dist/tools/saveDocument.js.map +1 -0
- package/dist/tools/searchAndReplace.d.ts +50 -0
- package/dist/tools/searchAndReplace.js +203 -0
- package/dist/tools/searchAndReplace.js.map +1 -0
- package/dist/tools/searchWorkspace.d.ts +52 -0
- package/dist/tools/searchWorkspace.js +159 -0
- package/dist/tools/searchWorkspace.js.map +1 -0
- package/dist/tools/setActiveWorkspaceFolder.d.ts +28 -0
- package/dist/tools/setActiveWorkspaceFolder.js +32 -0
- package/dist/tools/setActiveWorkspaceFolder.js.map +1 -0
- package/dist/tools/tasks.d.ts +56 -0
- package/dist/tools/tasks.js +89 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/terminal.d.ts +241 -0
- package/dist/tools/terminal.js +539 -0
- package/dist/tools/terminal.js.map +1 -0
- package/dist/tools/testRunners/cargoTest.d.ts +2 -0
- package/dist/tools/testRunners/cargoTest.js +123 -0
- package/dist/tools/testRunners/cargoTest.js.map +1 -0
- package/dist/tools/testRunners/goTest.d.ts +2 -0
- package/dist/tools/testRunners/goTest.js +106 -0
- package/dist/tools/testRunners/goTest.js.map +1 -0
- package/dist/tools/testRunners/pytest.d.ts +2 -0
- package/dist/tools/testRunners/pytest.js +133 -0
- package/dist/tools/testRunners/pytest.js.map +1 -0
- package/dist/tools/testRunners/types.d.ts +18 -0
- package/dist/tools/testRunners/types.js +2 -0
- package/dist/tools/testRunners/types.js.map +1 -0
- package/dist/tools/testRunners/vitestJest.d.ts +3 -0
- package/dist/tools/testRunners/vitestJest.js +178 -0
- package/dist/tools/testRunners/vitestJest.js.map +1 -0
- package/dist/tools/typeHierarchy.d.ts +45 -0
- package/dist/tools/typeHierarchy.js +65 -0
- package/dist/tools/typeHierarchy.js.map +1 -0
- package/dist/tools/utils.d.ts +54 -0
- package/dist/tools/utils.js +267 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools/vscodeCommands.d.ts +59 -0
- package/dist/tools/vscodeCommands.js +108 -0
- package/dist/tools/vscodeCommands.js.map +1 -0
- package/dist/tools/watchDiagnostics.d.ts +32 -0
- package/dist/tools/watchDiagnostics.js +87 -0
- package/dist/tools/watchDiagnostics.js.map +1 -0
- package/dist/tools/workspaceSettings.d.ts +67 -0
- package/dist/tools/workspaceSettings.js +102 -0
- package/dist/tools/workspaceSettings.js.map +1 -0
- package/dist/tools/workspaceSnapshots.d.ts +174 -0
- package/dist/tools/workspaceSnapshots.js +474 -0
- package/dist/tools/workspaceSnapshots.js.map +1 -0
- package/dist/transport.d.ts +57 -0
- package/dist/transport.js +417 -0
- package/dist/transport.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/wsUtils.d.ts +9 -0
- package/dist/wsUtils.js +54 -0
- package/dist/wsUtils.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { ExtensionTimeoutError, } from "../extensionClient.js";
|
|
3
|
+
import { error, execSafe, extensionRequired, languageIdFromPath, optionalInt, requireInt, requireString, resolveFilePath, success, } from "./utils.js";
|
|
4
|
+
const lspCache = new Map();
|
|
5
|
+
const LSP_CACHE_TTL_MS = 3_000;
|
|
6
|
+
const LSP_CACHE_MAX = 100;
|
|
7
|
+
function lspCacheGet(key, currentMtimeMs) {
|
|
8
|
+
const entry = lspCache.get(key);
|
|
9
|
+
if (!entry)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (Date.now() > entry.expiresAt || entry.mtimeMs !== currentMtimeMs) {
|
|
12
|
+
lspCache.delete(key);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
// LRU: move to end so FIFO eviction keeps most-recently-used entries
|
|
16
|
+
lspCache.delete(key);
|
|
17
|
+
lspCache.set(key, entry);
|
|
18
|
+
return entry.result;
|
|
19
|
+
}
|
|
20
|
+
function lspCacheSet(key, result, mtimeMs) {
|
|
21
|
+
if (lspCache.size >= LSP_CACHE_MAX) {
|
|
22
|
+
// Evict oldest entry
|
|
23
|
+
const firstKey = lspCache.keys().next().value;
|
|
24
|
+
if (firstKey !== undefined)
|
|
25
|
+
lspCache.delete(firstKey);
|
|
26
|
+
}
|
|
27
|
+
lspCache.set(key, {
|
|
28
|
+
result,
|
|
29
|
+
mtimeMs,
|
|
30
|
+
expiresAt: Date.now() + LSP_CACHE_TTL_MS,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// Language-specific regex patterns for symbol definitions
|
|
34
|
+
const DEFINITION_PATTERNS = {
|
|
35
|
+
typescript: String.raw `(export\s+)?(class|interface|type|enum|function|const|let|var|async\s+function)\s+`,
|
|
36
|
+
typescriptreact: String.raw `(export\s+)?(class|interface|type|enum|function|const|let|var|async\s+function)\s+`,
|
|
37
|
+
javascript: String.raw `(export\s+)?(class|function|const|let|var|async\s+function)\s+`,
|
|
38
|
+
javascriptreact: String.raw `(export\s+)?(class|function|const|let|var|async\s+function)\s+`,
|
|
39
|
+
python: String.raw `(class|def|async\s+def)\s+`,
|
|
40
|
+
rust: String.raw `(pub\s+)?(fn|struct|enum|trait|impl|type|mod|const|static)\s+`,
|
|
41
|
+
go: String.raw `(func|type|var|const)\s+`,
|
|
42
|
+
};
|
|
43
|
+
const LANG_GLOBS = {
|
|
44
|
+
typescript: "*.{ts,tsx}",
|
|
45
|
+
typescriptreact: "*.{ts,tsx}",
|
|
46
|
+
javascript: "*.{js,jsx,mjs,cjs}",
|
|
47
|
+
javascriptreact: "*.{js,jsx,mjs,cjs}",
|
|
48
|
+
python: "*.py",
|
|
49
|
+
rust: "*.rs",
|
|
50
|
+
go: "*.go",
|
|
51
|
+
};
|
|
52
|
+
export function escapeRegex(s) {
|
|
53
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
54
|
+
}
|
|
55
|
+
/** Extract the word (symbol name) at a given 1-based line/column from file content */
|
|
56
|
+
export function wordAtPosition(content, line, column) {
|
|
57
|
+
const lines = content.split("\n");
|
|
58
|
+
const lineText = lines[line - 1];
|
|
59
|
+
if (!lineText)
|
|
60
|
+
return null;
|
|
61
|
+
const col = column - 1;
|
|
62
|
+
// Expand outward from column to find word boundaries
|
|
63
|
+
const wordRegex = /[\w$]/;
|
|
64
|
+
let start = col;
|
|
65
|
+
let end = col;
|
|
66
|
+
while (start > 0 && wordRegex.test(lineText[start - 1]))
|
|
67
|
+
start--;
|
|
68
|
+
while (end < lineText.length && wordRegex.test(lineText[end]))
|
|
69
|
+
end++;
|
|
70
|
+
const word = lineText.slice(start, end);
|
|
71
|
+
return word.length > 0 ? word : null;
|
|
72
|
+
}
|
|
73
|
+
async function grepForSymbol(workspace, pattern, glob, maxResults) {
|
|
74
|
+
const args = ["-n", "--column", "-H", "--no-heading"];
|
|
75
|
+
if (glob) {
|
|
76
|
+
args.push("--glob", glob);
|
|
77
|
+
}
|
|
78
|
+
args.push("-e", pattern, workspace);
|
|
79
|
+
const result = await execSafe("rg", args, {
|
|
80
|
+
cwd: workspace,
|
|
81
|
+
timeout: 10_000,
|
|
82
|
+
maxBuffer: 256 * 1024,
|
|
83
|
+
});
|
|
84
|
+
const matches = [];
|
|
85
|
+
for (const line of result.stdout.split("\n")) {
|
|
86
|
+
if (!line)
|
|
87
|
+
continue;
|
|
88
|
+
// Format: filepath:line:column:text
|
|
89
|
+
const m = line.match(/^(.+?):(\d+):(\d+):(.*)$/);
|
|
90
|
+
if (m) {
|
|
91
|
+
matches.push({
|
|
92
|
+
filePath: m[1],
|
|
93
|
+
line: Number.parseInt(m[2], 10),
|
|
94
|
+
column: Number.parseInt(m[3], 10),
|
|
95
|
+
text: m[4].trim(),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (matches.length >= maxResults)
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
return matches;
|
|
102
|
+
}
|
|
103
|
+
export function createGoToDefinitionTool(workspace, extensionClient) {
|
|
104
|
+
return {
|
|
105
|
+
schema: {
|
|
106
|
+
name: "goToDefinition",
|
|
107
|
+
description: "Go to the definition of a symbol at a given position. Uses VS Code LSP when connected, falls back to lexical grep search otherwise (may include false positives).",
|
|
108
|
+
annotations: { readOnlyHint: true },
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: "object",
|
|
111
|
+
properties: {
|
|
112
|
+
filePath: {
|
|
113
|
+
type: "string",
|
|
114
|
+
description: "Absolute or workspace-relative file path",
|
|
115
|
+
},
|
|
116
|
+
line: {
|
|
117
|
+
type: "integer",
|
|
118
|
+
description: "Line number (1-based)",
|
|
119
|
+
},
|
|
120
|
+
column: {
|
|
121
|
+
type: "integer",
|
|
122
|
+
description: "Column number (1-based)",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
required: ["filePath", "line", "column"],
|
|
126
|
+
additionalProperties: false,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
handler: async (args, signal) => {
|
|
130
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
131
|
+
const line = requireInt(args, "line");
|
|
132
|
+
const column = requireInt(args, "column");
|
|
133
|
+
// Try extension first (semantic)
|
|
134
|
+
if (extensionClient.isConnected()) {
|
|
135
|
+
try {
|
|
136
|
+
// Check cache
|
|
137
|
+
const stat = await fs.promises.stat(filePath).catch(() => null);
|
|
138
|
+
const cacheKey = `def:${filePath}:${line}:${column}`;
|
|
139
|
+
if (stat) {
|
|
140
|
+
const cached = lspCacheGet(cacheKey, stat.mtimeMs);
|
|
141
|
+
if (cached !== undefined)
|
|
142
|
+
return success(cached);
|
|
143
|
+
}
|
|
144
|
+
const result = await extensionClient.goToDefinition(filePath, line, column, signal);
|
|
145
|
+
if (result === null) {
|
|
146
|
+
return success({
|
|
147
|
+
found: false,
|
|
148
|
+
message: "No definition found at this position",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (stat)
|
|
152
|
+
lspCacheSet(cacheKey, result, stat.mtimeMs);
|
|
153
|
+
return success(result);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (!(err instanceof ExtensionTimeoutError))
|
|
157
|
+
throw err;
|
|
158
|
+
// Timeout — fall through to grep fallback
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Grep fallback: extract symbol at position, search for definition patterns
|
|
162
|
+
try {
|
|
163
|
+
const content = await fs.promises.readFile(filePath, "utf-8");
|
|
164
|
+
const symbol = wordAtPosition(content, line, column);
|
|
165
|
+
if (!symbol) {
|
|
166
|
+
return success({
|
|
167
|
+
found: false,
|
|
168
|
+
message: "No symbol found at this position",
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
const langId = languageIdFromPath(filePath);
|
|
172
|
+
const defPattern = DEFINITION_PATTERNS[langId];
|
|
173
|
+
const glob = LANG_GLOBS[langId];
|
|
174
|
+
// Search for definition-like patterns: "class Foo", "function Foo", etc.
|
|
175
|
+
const pattern = defPattern
|
|
176
|
+
? `${defPattern}${escapeRegex(symbol)}\\b`
|
|
177
|
+
: `(class|function|def|fn|type|interface|struct|const|let|var)\\s+${escapeRegex(symbol)}\\b`;
|
|
178
|
+
const matches = await grepForSymbol(workspace, pattern, glob, 10);
|
|
179
|
+
if (matches.length === 0) {
|
|
180
|
+
return success({
|
|
181
|
+
found: false,
|
|
182
|
+
source: "lexical-grep",
|
|
183
|
+
message: `No definition-like pattern found for "${symbol}"`,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return success({
|
|
187
|
+
found: true,
|
|
188
|
+
source: "lexical-grep",
|
|
189
|
+
symbol,
|
|
190
|
+
definitions: matches.map((m) => ({
|
|
191
|
+
filePath: m.filePath,
|
|
192
|
+
line: m.line,
|
|
193
|
+
column: m.column,
|
|
194
|
+
text: m.text,
|
|
195
|
+
})),
|
|
196
|
+
warning: "Results are from text search, not semantic analysis — may include false positives",
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
return error(`Grep fallback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export function createFindReferencesTool(workspace, extensionClient) {
|
|
206
|
+
return {
|
|
207
|
+
schema: {
|
|
208
|
+
name: "findReferences",
|
|
209
|
+
description: "Find all references to a symbol at a given position. Uses VS Code LSP when connected, falls back to lexical grep search otherwise (may include false positives from identically-named symbols).",
|
|
210
|
+
annotations: { readOnlyHint: true },
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: "object",
|
|
213
|
+
properties: {
|
|
214
|
+
filePath: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "Absolute or workspace-relative file path",
|
|
217
|
+
},
|
|
218
|
+
line: {
|
|
219
|
+
type: "integer",
|
|
220
|
+
description: "Line number (1-based)",
|
|
221
|
+
},
|
|
222
|
+
column: {
|
|
223
|
+
type: "integer",
|
|
224
|
+
description: "Column number (1-based)",
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
required: ["filePath", "line", "column"],
|
|
228
|
+
additionalProperties: false,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
handler: async (args, signal) => {
|
|
232
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
233
|
+
const line = requireInt(args, "line");
|
|
234
|
+
const column = requireInt(args, "column");
|
|
235
|
+
// Try extension first (semantic)
|
|
236
|
+
if (extensionClient.isConnected()) {
|
|
237
|
+
try {
|
|
238
|
+
const result = await extensionClient.findReferences(filePath, line, column, signal);
|
|
239
|
+
if (result === null) {
|
|
240
|
+
return success({ found: false, references: [] });
|
|
241
|
+
}
|
|
242
|
+
return success(result);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
if (!(err instanceof ExtensionTimeoutError))
|
|
246
|
+
throw err;
|
|
247
|
+
// Timeout — fall through to grep fallback
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Grep fallback: find all occurrences of the word
|
|
251
|
+
try {
|
|
252
|
+
const content = await fs.promises.readFile(filePath, "utf-8");
|
|
253
|
+
const symbol = wordAtPosition(content, line, column);
|
|
254
|
+
if (!symbol) {
|
|
255
|
+
return success({
|
|
256
|
+
found: false,
|
|
257
|
+
references: [],
|
|
258
|
+
message: "No symbol found at this position",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
const langId = languageIdFromPath(filePath);
|
|
262
|
+
const glob = LANG_GLOBS[langId];
|
|
263
|
+
// Word-boundary search for exact symbol name
|
|
264
|
+
const pattern = `\\b${escapeRegex(symbol)}\\b`;
|
|
265
|
+
const matches = await grepForSymbol(workspace, pattern, glob, 100);
|
|
266
|
+
return success({
|
|
267
|
+
found: matches.length > 0,
|
|
268
|
+
source: "lexical-grep",
|
|
269
|
+
symbol,
|
|
270
|
+
references: matches.map((m) => ({
|
|
271
|
+
filePath: m.filePath,
|
|
272
|
+
line: m.line,
|
|
273
|
+
column: m.column,
|
|
274
|
+
text: m.text,
|
|
275
|
+
})),
|
|
276
|
+
count: matches.length,
|
|
277
|
+
warning: "Results are from text search — may include false positives from identically-named symbols in different scopes",
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
return error(`Grep fallback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
export function createGetHoverTool(workspace, extensionClient) {
|
|
287
|
+
return {
|
|
288
|
+
schema: {
|
|
289
|
+
name: "getHover",
|
|
290
|
+
extensionRequired: true,
|
|
291
|
+
description: "Get hover information (type info, documentation) for a symbol at a given position. Requires the VS Code extension to be connected.",
|
|
292
|
+
annotations: { readOnlyHint: true },
|
|
293
|
+
inputSchema: {
|
|
294
|
+
type: "object",
|
|
295
|
+
properties: {
|
|
296
|
+
filePath: {
|
|
297
|
+
type: "string",
|
|
298
|
+
description: "Absolute or workspace-relative file path",
|
|
299
|
+
},
|
|
300
|
+
line: {
|
|
301
|
+
type: "integer",
|
|
302
|
+
description: "Line number (1-based)",
|
|
303
|
+
},
|
|
304
|
+
column: {
|
|
305
|
+
type: "integer",
|
|
306
|
+
description: "Column number (1-based)",
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
required: ["filePath", "line", "column"],
|
|
310
|
+
additionalProperties: false,
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
handler: async (args, signal) => {
|
|
314
|
+
if (!extensionClient.isConnected()) {
|
|
315
|
+
return extensionRequired("LSP features");
|
|
316
|
+
}
|
|
317
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
318
|
+
const line = requireInt(args, "line");
|
|
319
|
+
const column = requireInt(args, "column");
|
|
320
|
+
try {
|
|
321
|
+
// Check cache
|
|
322
|
+
const stat = await fs.promises.stat(filePath).catch(() => null);
|
|
323
|
+
const cacheKey = `hover:${filePath}:${line}:${column}`;
|
|
324
|
+
if (stat) {
|
|
325
|
+
const cached = lspCacheGet(cacheKey, stat.mtimeMs);
|
|
326
|
+
if (cached !== undefined)
|
|
327
|
+
return success(cached);
|
|
328
|
+
}
|
|
329
|
+
const result = await extensionClient.getHover(filePath, line, column, signal);
|
|
330
|
+
if (result === null) {
|
|
331
|
+
return success({
|
|
332
|
+
found: false,
|
|
333
|
+
message: "No hover information at this position",
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (stat)
|
|
337
|
+
lspCacheSet(cacheKey, result, stat.mtimeMs);
|
|
338
|
+
return success(result);
|
|
339
|
+
}
|
|
340
|
+
catch (err) {
|
|
341
|
+
if (err instanceof ExtensionTimeoutError) {
|
|
342
|
+
return error("Extension timed out — the language server may be slow or unresponsive");
|
|
343
|
+
}
|
|
344
|
+
throw err;
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
export function createGetCodeActionsTool(workspace, extensionClient) {
|
|
350
|
+
return {
|
|
351
|
+
schema: {
|
|
352
|
+
name: "getCodeActions",
|
|
353
|
+
extensionRequired: true,
|
|
354
|
+
description: "Get available code actions (quick fixes, refactorings) for a range in a file. Requires the VS Code extension to be connected.",
|
|
355
|
+
annotations: { readOnlyHint: true },
|
|
356
|
+
inputSchema: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
filePath: {
|
|
360
|
+
type: "string",
|
|
361
|
+
description: "Absolute or workspace-relative file path",
|
|
362
|
+
},
|
|
363
|
+
startLine: {
|
|
364
|
+
type: "integer",
|
|
365
|
+
description: "Start line (1-based)",
|
|
366
|
+
},
|
|
367
|
+
startColumn: {
|
|
368
|
+
type: "integer",
|
|
369
|
+
description: "Start column (1-based)",
|
|
370
|
+
},
|
|
371
|
+
endLine: {
|
|
372
|
+
type: "integer",
|
|
373
|
+
description: "End line (1-based)",
|
|
374
|
+
},
|
|
375
|
+
endColumn: {
|
|
376
|
+
type: "integer",
|
|
377
|
+
description: "End column (1-based)",
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
required: [
|
|
381
|
+
"filePath",
|
|
382
|
+
"startLine",
|
|
383
|
+
"startColumn",
|
|
384
|
+
"endLine",
|
|
385
|
+
"endColumn",
|
|
386
|
+
],
|
|
387
|
+
additionalProperties: false,
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
handler: async (args) => {
|
|
391
|
+
if (!extensionClient.isConnected()) {
|
|
392
|
+
return extensionRequired("LSP features");
|
|
393
|
+
}
|
|
394
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
395
|
+
const startLine = requireInt(args, "startLine");
|
|
396
|
+
const startColumn = requireInt(args, "startColumn");
|
|
397
|
+
const endLine = requireInt(args, "endLine");
|
|
398
|
+
const endColumn = requireInt(args, "endColumn");
|
|
399
|
+
try {
|
|
400
|
+
const result = await extensionClient.getCodeActions(filePath, startLine, startColumn, endLine, endColumn);
|
|
401
|
+
if (result === null) {
|
|
402
|
+
return success({ actions: [] });
|
|
403
|
+
}
|
|
404
|
+
return success(result);
|
|
405
|
+
}
|
|
406
|
+
catch (err) {
|
|
407
|
+
if (err instanceof ExtensionTimeoutError) {
|
|
408
|
+
return error("Extension timed out — the language server may be slow or unresponsive");
|
|
409
|
+
}
|
|
410
|
+
throw err;
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
export function createApplyCodeActionTool(workspace, extensionClient) {
|
|
416
|
+
return {
|
|
417
|
+
schema: {
|
|
418
|
+
name: "applyCodeAction",
|
|
419
|
+
extensionRequired: true,
|
|
420
|
+
description: "Apply a code action (quick fix, refactoring) by title. First use getCodeActions to see available actions, then use this tool to apply one. Requires the VS Code extension.",
|
|
421
|
+
annotations: { destructiveHint: true },
|
|
422
|
+
inputSchema: {
|
|
423
|
+
type: "object",
|
|
424
|
+
properties: {
|
|
425
|
+
filePath: {
|
|
426
|
+
type: "string",
|
|
427
|
+
description: "Absolute or workspace-relative file path",
|
|
428
|
+
},
|
|
429
|
+
startLine: {
|
|
430
|
+
type: "integer",
|
|
431
|
+
description: "Start line (1-based)",
|
|
432
|
+
},
|
|
433
|
+
startColumn: {
|
|
434
|
+
type: "integer",
|
|
435
|
+
description: "Start column (1-based)",
|
|
436
|
+
},
|
|
437
|
+
endLine: {
|
|
438
|
+
type: "integer",
|
|
439
|
+
description: "End line (1-based)",
|
|
440
|
+
},
|
|
441
|
+
endColumn: {
|
|
442
|
+
type: "integer",
|
|
443
|
+
description: "End column (1-based)",
|
|
444
|
+
},
|
|
445
|
+
actionTitle: {
|
|
446
|
+
type: "string",
|
|
447
|
+
description: "Exact title of the code action to apply (from getCodeActions output)",
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
required: [
|
|
451
|
+
"filePath",
|
|
452
|
+
"startLine",
|
|
453
|
+
"startColumn",
|
|
454
|
+
"endLine",
|
|
455
|
+
"endColumn",
|
|
456
|
+
"actionTitle",
|
|
457
|
+
],
|
|
458
|
+
additionalProperties: false,
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
handler: async (args) => {
|
|
462
|
+
if (!extensionClient.isConnected()) {
|
|
463
|
+
return extensionRequired("LSP features");
|
|
464
|
+
}
|
|
465
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
466
|
+
const actionTitle = requireString(args, "actionTitle", 500);
|
|
467
|
+
const startLine = requireInt(args, "startLine");
|
|
468
|
+
const startColumn = requireInt(args, "startColumn");
|
|
469
|
+
const endLine = requireInt(args, "endLine");
|
|
470
|
+
const endColumn = requireInt(args, "endColumn");
|
|
471
|
+
try {
|
|
472
|
+
const result = await extensionClient.applyCodeAction(filePath, startLine, startColumn, endLine, endColumn, actionTitle);
|
|
473
|
+
if (result === null) {
|
|
474
|
+
return error("Extension returned no result — code action may not be available");
|
|
475
|
+
}
|
|
476
|
+
return success(result);
|
|
477
|
+
}
|
|
478
|
+
catch (err) {
|
|
479
|
+
if (err instanceof ExtensionTimeoutError) {
|
|
480
|
+
return error("Extension timed out — code action may require more time");
|
|
481
|
+
}
|
|
482
|
+
throw err;
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
export function createRenameSymbolTool(workspace, extensionClient) {
|
|
488
|
+
return {
|
|
489
|
+
schema: {
|
|
490
|
+
name: "renameSymbol",
|
|
491
|
+
extensionRequired: true,
|
|
492
|
+
description: "Rename a symbol at a given position across all files using the LSP rename provider. Returns list of affected files and edit counts. Requires the VS Code extension.",
|
|
493
|
+
annotations: { destructiveHint: true },
|
|
494
|
+
inputSchema: {
|
|
495
|
+
type: "object",
|
|
496
|
+
properties: {
|
|
497
|
+
filePath: {
|
|
498
|
+
type: "string",
|
|
499
|
+
description: "Absolute or workspace-relative file path",
|
|
500
|
+
},
|
|
501
|
+
line: {
|
|
502
|
+
type: "integer",
|
|
503
|
+
description: "Line number (1-based)",
|
|
504
|
+
},
|
|
505
|
+
column: {
|
|
506
|
+
type: "integer",
|
|
507
|
+
description: "Column number (1-based)",
|
|
508
|
+
},
|
|
509
|
+
newName: {
|
|
510
|
+
type: "string",
|
|
511
|
+
description: "New name for the symbol",
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
required: ["filePath", "line", "column", "newName"],
|
|
515
|
+
additionalProperties: false,
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
handler: async (args) => {
|
|
519
|
+
if (!extensionClient.isConnected()) {
|
|
520
|
+
return extensionRequired("LSP features");
|
|
521
|
+
}
|
|
522
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
523
|
+
const newName = requireString(args, "newName", 256);
|
|
524
|
+
if (/[\x00-\x1f]/.test(newName)) {
|
|
525
|
+
return error("newName must not contain control characters");
|
|
526
|
+
}
|
|
527
|
+
const line = requireInt(args, "line");
|
|
528
|
+
const column = requireInt(args, "column");
|
|
529
|
+
try {
|
|
530
|
+
const result = await extensionClient.renameSymbol(filePath, line, column, newName);
|
|
531
|
+
if (result === null) {
|
|
532
|
+
return error("Extension returned no result — symbol may not be renameable at this position");
|
|
533
|
+
}
|
|
534
|
+
return success(result);
|
|
535
|
+
}
|
|
536
|
+
catch (err) {
|
|
537
|
+
if (err instanceof ExtensionTimeoutError) {
|
|
538
|
+
return error("Extension timed out — rename may require more time on large projects");
|
|
539
|
+
}
|
|
540
|
+
throw err;
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
export function createGetCallHierarchyTool(workspace, extensionClient) {
|
|
546
|
+
return {
|
|
547
|
+
schema: {
|
|
548
|
+
name: "getCallHierarchy",
|
|
549
|
+
extensionRequired: true,
|
|
550
|
+
description: "Get the call hierarchy for a function or method — who calls it (incoming) and what it calls (outgoing). " +
|
|
551
|
+
'Use direction="incoming" to find all callers of a function, "outgoing" to see everything it calls, or "both" (default). ' +
|
|
552
|
+
"Requires the VS Code extension to be connected.",
|
|
553
|
+
annotations: { readOnlyHint: true },
|
|
554
|
+
inputSchema: {
|
|
555
|
+
type: "object",
|
|
556
|
+
properties: {
|
|
557
|
+
filePath: {
|
|
558
|
+
type: "string",
|
|
559
|
+
description: "Absolute or workspace-relative file path",
|
|
560
|
+
},
|
|
561
|
+
line: {
|
|
562
|
+
type: "integer",
|
|
563
|
+
description: "Line number (1-based)",
|
|
564
|
+
},
|
|
565
|
+
column: {
|
|
566
|
+
type: "integer",
|
|
567
|
+
description: "Column number (1-based)",
|
|
568
|
+
},
|
|
569
|
+
direction: {
|
|
570
|
+
type: "string",
|
|
571
|
+
enum: ["incoming", "outgoing", "both"],
|
|
572
|
+
description: '"incoming" = callers of this function, "outgoing" = functions this calls, "both" = all (default)',
|
|
573
|
+
},
|
|
574
|
+
maxResults: {
|
|
575
|
+
type: "integer",
|
|
576
|
+
description: "Maximum callers/callees to return per direction (default: 50, max: 200)",
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
required: ["filePath", "line", "column"],
|
|
580
|
+
additionalProperties: false,
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
handler: async (args) => {
|
|
584
|
+
if (!extensionClient.isConnected()) {
|
|
585
|
+
return extensionRequired("getCallHierarchy");
|
|
586
|
+
}
|
|
587
|
+
const filePath = resolveFilePath(requireString(args, "filePath"), workspace);
|
|
588
|
+
const line = requireInt(args, "line");
|
|
589
|
+
const column = requireInt(args, "column");
|
|
590
|
+
const rawDirection = typeof args.direction === "string" ? args.direction : "both";
|
|
591
|
+
if (!["incoming", "outgoing", "both"].includes(rawDirection)) {
|
|
592
|
+
return error('direction must be "incoming", "outgoing", or "both"');
|
|
593
|
+
}
|
|
594
|
+
const maxResults = optionalInt(args, "maxResults", 1, 200) ?? 50;
|
|
595
|
+
try {
|
|
596
|
+
const result = await extensionClient.getCallHierarchy(filePath, line, column, rawDirection, maxResults);
|
|
597
|
+
if (result === null) {
|
|
598
|
+
return success({
|
|
599
|
+
found: false,
|
|
600
|
+
message: "No call hierarchy available at this position — ensure a language server is active",
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
return success(result);
|
|
604
|
+
}
|
|
605
|
+
catch (err) {
|
|
606
|
+
if (err instanceof ExtensionTimeoutError) {
|
|
607
|
+
return error("Extension timed out — the language server may be slow or unresponsive");
|
|
608
|
+
}
|
|
609
|
+
throw err;
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
export function createSearchWorkspaceSymbolsTool(workspace, extensionClient) {
|
|
615
|
+
return {
|
|
616
|
+
schema: {
|
|
617
|
+
name: "searchWorkspaceSymbols",
|
|
618
|
+
description: "Search for symbols (classes, functions, variables, interfaces) by name across the entire workspace. Uses VS Code LSP when connected (semantically accurate), falls back to ripgrep pattern matching otherwise.",
|
|
619
|
+
annotations: { readOnlyHint: true },
|
|
620
|
+
inputSchema: {
|
|
621
|
+
type: "object",
|
|
622
|
+
properties: {
|
|
623
|
+
query: {
|
|
624
|
+
type: "string",
|
|
625
|
+
description: "Symbol name or partial name to search for",
|
|
626
|
+
},
|
|
627
|
+
maxResults: {
|
|
628
|
+
type: "integer",
|
|
629
|
+
description: "Maximum results to return (default: 50, max: 200)",
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
required: ["query"],
|
|
633
|
+
additionalProperties: false,
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
handler: async (args) => {
|
|
637
|
+
const query = requireString(args, "query", 256);
|
|
638
|
+
if (query.trim().length === 0) {
|
|
639
|
+
return error("query must not be empty");
|
|
640
|
+
}
|
|
641
|
+
const maxResults = optionalInt(args, "maxResults", 1, 200) ?? 50;
|
|
642
|
+
// Try extension first (semantic)
|
|
643
|
+
if (extensionClient.isConnected()) {
|
|
644
|
+
try {
|
|
645
|
+
const result = await extensionClient.searchSymbols(query, maxResults);
|
|
646
|
+
if (result === null) {
|
|
647
|
+
return success({ symbols: [], count: 0 });
|
|
648
|
+
}
|
|
649
|
+
return success(result);
|
|
650
|
+
}
|
|
651
|
+
catch (err) {
|
|
652
|
+
if (!(err instanceof ExtensionTimeoutError))
|
|
653
|
+
throw err;
|
|
654
|
+
// Timeout — fall through to grep fallback
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
// Grep fallback: search for definition patterns matching the query
|
|
658
|
+
try {
|
|
659
|
+
const escaped = escapeRegex(query);
|
|
660
|
+
// Generic definition pattern covering common languages
|
|
661
|
+
const pattern = `(export\\s+)?(class|interface|type|enum|function|const|let|var|async\\s+function|def|async\\s+def|fn|struct|trait|impl|mod)\\s+${escaped}`;
|
|
662
|
+
// Scope search to common source file types to avoid scanning binaries/node_modules
|
|
663
|
+
const defaultGlob = "*.{ts,tsx,js,jsx,mjs,cjs,py,rs,go,java,c,cpp,h,hpp,rb,php,swift,kt,scala}";
|
|
664
|
+
const matches = await grepForSymbol(workspace, pattern, defaultGlob, maxResults);
|
|
665
|
+
return success({
|
|
666
|
+
source: "lexical-grep",
|
|
667
|
+
symbols: matches.map((m) => ({
|
|
668
|
+
name: query,
|
|
669
|
+
filePath: m.filePath,
|
|
670
|
+
line: m.line,
|
|
671
|
+
column: m.column,
|
|
672
|
+
text: m.text,
|
|
673
|
+
})),
|
|
674
|
+
count: matches.length,
|
|
675
|
+
warning: "Results are from text pattern matching, not semantic symbol resolution",
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
catch (err) {
|
|
679
|
+
return error(`Grep fallback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
//# sourceMappingURL=lsp.js.map
|