lsp-intelligence 0.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 +250 -0
- package/dist/engine/DocumentManager.d.ts +20 -0
- package/dist/engine/DocumentManager.js +73 -0
- package/dist/engine/DocumentManager.js.map +1 -0
- package/dist/engine/LspEngine.d.ts +50 -0
- package/dist/engine/LspEngine.js +339 -0
- package/dist/engine/LspEngine.js.map +1 -0
- package/dist/engine/positions.d.ts +31 -0
- package/dist/engine/positions.js +55 -0
- package/dist/engine/positions.js.map +1 -0
- package/dist/engine/types.d.ts +61 -0
- package/dist/engine/types.js +33 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/format/markdown.d.ts +5 -0
- package/dist/format/markdown.js +90 -0
- package/dist/format/markdown.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/composites/batchQuery.d.ts +1 -0
- package/dist/tools/composites/batchQuery.js +40 -0
- package/dist/tools/composites/batchQuery.js.map +1 -0
- package/dist/tools/composites/explainError.d.ts +1 -0
- package/dist/tools/composites/explainError.js +56 -0
- package/dist/tools/composites/explainError.js.map +1 -0
- package/dist/tools/composites/findTestFiles.d.ts +1 -0
- package/dist/tools/composites/findTestFiles.js +57 -0
- package/dist/tools/composites/findTestFiles.js.map +1 -0
- package/dist/tools/composites/impactTrace.d.ts +1 -0
- package/dist/tools/composites/impactTrace.js +149 -0
- package/dist/tools/composites/impactTrace.js.map +1 -0
- package/dist/tools/composites/inspectSymbol.d.ts +1 -0
- package/dist/tools/composites/inspectSymbol.js +60 -0
- package/dist/tools/composites/inspectSymbol.js.map +1 -0
- package/dist/tools/composites/semanticDiff.d.ts +1 -0
- package/dist/tools/composites/semanticDiff.js +135 -0
- package/dist/tools/composites/semanticDiff.js.map +1 -0
- package/dist/tools/context/gatherContext.d.ts +1 -0
- package/dist/tools/context/gatherContext.js +153 -0
- package/dist/tools/context/gatherContext.js.map +1 -0
- package/dist/tools/context/outline.d.ts +1 -0
- package/dist/tools/context/outline.js +56 -0
- package/dist/tools/context/outline.js.map +1 -0
- package/dist/tools/live/autoImport.d.ts +1 -0
- package/dist/tools/live/autoImport.js +123 -0
- package/dist/tools/live/autoImport.js.map +1 -0
- package/dist/tools/live/findUnusedExports.d.ts +1 -0
- package/dist/tools/live/findUnusedExports.js +69 -0
- package/dist/tools/live/findUnusedExports.js.map +1 -0
- package/dist/tools/live/liveDiagnostics.d.ts +1 -0
- package/dist/tools/live/liveDiagnostics.js +38 -0
- package/dist/tools/live/liveDiagnostics.js.map +1 -0
- package/dist/tools/primitives/callHierarchy.d.ts +1 -0
- package/dist/tools/primitives/callHierarchy.js +61 -0
- package/dist/tools/primitives/callHierarchy.js.map +1 -0
- package/dist/tools/primitives/completions.d.ts +1 -0
- package/dist/tools/primitives/completions.js +31 -0
- package/dist/tools/primitives/completions.js.map +1 -0
- package/dist/tools/primitives/diagnostics.d.ts +1 -0
- package/dist/tools/primitives/diagnostics.js +32 -0
- package/dist/tools/primitives/diagnostics.js.map +1 -0
- package/dist/tools/primitives/documentSymbols.d.ts +1 -0
- package/dist/tools/primitives/documentSymbols.js +42 -0
- package/dist/tools/primitives/documentSymbols.js.map +1 -0
- package/dist/tools/primitives/fileExports.d.ts +1 -0
- package/dist/tools/primitives/fileExports.js +69 -0
- package/dist/tools/primitives/fileExports.js.map +1 -0
- package/dist/tools/primitives/fileImports.d.ts +1 -0
- package/dist/tools/primitives/fileImports.js +58 -0
- package/dist/tools/primitives/fileImports.js.map +1 -0
- package/dist/tools/primitives/findImplementations.d.ts +1 -0
- package/dist/tools/primitives/findImplementations.js +36 -0
- package/dist/tools/primitives/findImplementations.js.map +1 -0
- package/dist/tools/primitives/findReferences.d.ts +1 -0
- package/dist/tools/primitives/findReferences.js +42 -0
- package/dist/tools/primitives/findReferences.js.map +1 -0
- package/dist/tools/primitives/gotoDefinition.d.ts +1 -0
- package/dist/tools/primitives/gotoDefinition.js +37 -0
- package/dist/tools/primitives/gotoDefinition.js.map +1 -0
- package/dist/tools/primitives/gotoTypeDefinition.d.ts +1 -0
- package/dist/tools/primitives/gotoTypeDefinition.js +35 -0
- package/dist/tools/primitives/gotoTypeDefinition.js.map +1 -0
- package/dist/tools/primitives/hover.d.ts +1 -0
- package/dist/tools/primitives/hover.js +37 -0
- package/dist/tools/primitives/hover.js.map +1 -0
- package/dist/tools/primitives/rename.d.ts +1 -0
- package/dist/tools/primitives/rename.js +56 -0
- package/dist/tools/primitives/rename.js.map +1 -0
- package/dist/tools/primitives/typeHierarchy.d.ts +1 -0
- package/dist/tools/primitives/typeHierarchy.js +49 -0
- package/dist/tools/primitives/typeHierarchy.js.map +1 -0
- package/dist/tools/primitives/workspaceSymbols.d.ts +1 -0
- package/dist/tools/primitives/workspaceSymbols.js +32 -0
- package/dist/tools/primitives/workspaceSymbols.js.map +1 -0
- package/dist/tools/registry.d.ts +19 -0
- package/dist/tools/registry.js +19 -0
- package/dist/tools/registry.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peri Levy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# lsp-intelligence
|
|
2
|
+
|
|
3
|
+
Type-aware code intelligence for AI agents — impact analysis, semantic diff, and context building via LSP.
|
|
4
|
+
|
|
5
|
+
**25 MCP tools** across 5 layers — from basic navigation to "what breaks if I change this?" in one call.
|
|
6
|
+
|
|
7
|
+
Currently supports **TypeScript and JavaScript** projects. The architecture supports other LSP servers — additional language support is planned.
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
AI coding agents use `grep` to understand code. Grep finds text, not meaning. It can't follow types through aliases, can't distinguish imports from function calls, and returns false positives from comments and strings.
|
|
12
|
+
|
|
13
|
+
`lsp-intelligence` gives agents the same code understanding that VS Code has — type-aware references, call hierarchies, impact analysis — via the [Model Context Protocol](https://modelcontextprotocol.io/) (MCP).
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
After [installation](#installation), try in Claude Code:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
"What breaks if I rename the UserService class?"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Under the hood, the agent calls:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{ "tool": "impact_trace", "arguments": { "symbol": "UserService" } }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or get a file overview without reading it:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{ "tool": "outline", "arguments": { "file_path": "/workspace/src/services/auth.ts" } }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> All tools that accept `file_path` require absolute paths. The `LSP_WORKSPACE_ROOT` env var tells the engine where your project lives.
|
|
36
|
+
|
|
37
|
+
## Capabilities
|
|
38
|
+
|
|
39
|
+
### LSP vs text search
|
|
40
|
+
|
|
41
|
+
| Query | Text search (grep) | lsp-intelligence |
|
|
42
|
+
|-------|-------------------|-----------------|
|
|
43
|
+
| Find all references to a function | Finds text matches | **Semantic references** — no false positives from comments or strings |
|
|
44
|
+
| Find references to a type alias | ⚠️ Includes substring matches (e.g. `UserServiceConfig` matches `UserService`) | **Exact symbol resolution** — only true references |
|
|
45
|
+
| Cross-package references in monorepo | ⚠️ Text matches only — includes false positives, can't distinguish import vs call vs type annotation | **Type-aware semantic references** across packages |
|
|
46
|
+
|
|
47
|
+
### What agents can do with LSP that they can't with grep
|
|
48
|
+
|
|
49
|
+
| Capability | Description |
|
|
50
|
+
|-----------|-------------|
|
|
51
|
+
| Follow type aliases | Trace through `ReturnType<typeof X>`, re-exports, and barrel files |
|
|
52
|
+
| Go to definition | Jump to the actual source, not just a text match |
|
|
53
|
+
| Call hierarchy | "Who calls this function?" / "What does this function call?" |
|
|
54
|
+
| Type signatures | Get the full type signature without reading the implementation |
|
|
55
|
+
| Impact analysis | "What breaks if I change this?" — one call, full answer |
|
|
56
|
+
| Semantic diff | Git changes → which symbols changed → blast radius per symbol |
|
|
57
|
+
| Context building | Trace an impact graph, extract only relevant code, token-budget the output |
|
|
58
|
+
| Rename preview | See every file that would change before committing a rename |
|
|
59
|
+
| Dead code detection | Find exports that nothing imports |
|
|
60
|
+
| Auto-import | Resolve the correct import path for any symbol |
|
|
61
|
+
|
|
62
|
+
### Performance
|
|
63
|
+
|
|
64
|
+
Tested on a TypeScript monorepo (9 packages, ~200k LOC):
|
|
65
|
+
|
|
66
|
+
| Metric | Value |
|
|
67
|
+
|--------|-------|
|
|
68
|
+
| Engine ready | ~10s (scales with repo size) |
|
|
69
|
+
| Queries after warmup | 100-300ms |
|
|
70
|
+
| 21 queries end-to-end | ~16s total |
|
|
71
|
+
|
|
72
|
+
The engine initializes once per session and stays warm. Warmup includes spawning TypeScript Server and pre-opening all monorepo packages. Queries start as soon as the index is available — no fixed delay.
|
|
73
|
+
|
|
74
|
+
## Tools
|
|
75
|
+
|
|
76
|
+
### Layer 1: Primitives (14 tools)
|
|
77
|
+
|
|
78
|
+
Direct LSP wrappers. Every tool accepts **symbol names** — agents never need to guess line numbers.
|
|
79
|
+
|
|
80
|
+
| Tool | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `find_references` | Find every usage of a symbol across the codebase. Semantic, not text. |
|
|
83
|
+
| `goto_definition` | Jump to where a symbol is defined. Follows imports and re-exports. |
|
|
84
|
+
| `goto_type_definition` | Find the type that defines a variable. |
|
|
85
|
+
| `hover` | Get full type signature and documentation. |
|
|
86
|
+
| `find_implementations` | Find concrete implementations of an interface. |
|
|
87
|
+
| `document_symbols` | List all symbols in a file. |
|
|
88
|
+
| `workspace_symbols` | Search for symbols by name across the workspace. |
|
|
89
|
+
| `call_hierarchy` | Trace incoming callers or outgoing callees. |
|
|
90
|
+
| `type_hierarchy` | Explore supertypes and subtypes. |
|
|
91
|
+
| `rename` | Preview a semantic rename across the codebase (dry-run by default). |
|
|
92
|
+
| `diagnostics` | Get type errors and warnings for a file. |
|
|
93
|
+
| `completions` | Code completion suggestions. |
|
|
94
|
+
| `file_imports` | List all imports of a file. |
|
|
95
|
+
| `file_exports` | List a file's public API including re-exports. |
|
|
96
|
+
|
|
97
|
+
### Layer 2: Composites (6 tools)
|
|
98
|
+
|
|
99
|
+
Combine multiple primitives into high-level operations.
|
|
100
|
+
|
|
101
|
+
| Tool | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `inspect_symbol` | Hover + definition + references in one call. Full context about any symbol. |
|
|
104
|
+
| `batch_query` | Look up multiple symbols at once. Saves round-trips when exploring. |
|
|
105
|
+
| `impact_trace` | Follow a symbol through type aliases and re-exports to find ALL transitive usages. Answers **"what breaks if I change X?"** in one call. |
|
|
106
|
+
| `semantic_diff` | Analyze git diff semantically: identify changed symbols and their blast radius. |
|
|
107
|
+
| `find_test_files` | Find all test/spec/stories files that reference a symbol. |
|
|
108
|
+
| `explain_error` | Turn a TypeScript error into actionable context: expected type, actual type, and fix suggestion. |
|
|
109
|
+
|
|
110
|
+
### Layer 3: Context Engine (2 tools)
|
|
111
|
+
|
|
112
|
+
Token-aware context building for agents.
|
|
113
|
+
|
|
114
|
+
| Tool | Description |
|
|
115
|
+
|------|-------------|
|
|
116
|
+
| `outline` | File structure with type signatures — understand a file without reading it. |
|
|
117
|
+
| `gather_context` | Trace impact graph from entry symbols, classify files as must-modify / verify-only / skip, return token-budgeted context. |
|
|
118
|
+
|
|
119
|
+
### Layer 4: Live Intelligence (3 tools)
|
|
120
|
+
|
|
121
|
+
Post-edit verification.
|
|
122
|
+
|
|
123
|
+
| Tool | Description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| `live_diagnostics` | Re-read a file after editing and check for new type errors. |
|
|
126
|
+
| `find_unused_exports` | Find exported symbols with zero cross-package importers. |
|
|
127
|
+
| `auto_import` | Resolve the correct import path for a symbol name. |
|
|
128
|
+
|
|
129
|
+
## Architecture
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
┌─────────────────────────────────────────────────────────┐
|
|
133
|
+
│ Layer 4: Live Intelligence [state-mutating] │
|
|
134
|
+
│ live_diagnostics, find_unused_exports, auto_import │
|
|
135
|
+
├─────────────────────────────────────────────────────────┤
|
|
136
|
+
│ Layer 3: Context Engine [read-only] │
|
|
137
|
+
│ gather_context, outline │
|
|
138
|
+
├─────────────────────────────────────────────────────────┤
|
|
139
|
+
│ Layer 2: Composites [read-only] │
|
|
140
|
+
│ impact_trace, semantic_diff, inspect_symbol, │
|
|
141
|
+
│ batch_query, find_test_files, explain_error │
|
|
142
|
+
├─────────────────────────────────────────────────────────┤
|
|
143
|
+
│ Layer 1: Primitives [read-only] │
|
|
144
|
+
│ find_references, hover, definition, call_hierarchy, │
|
|
145
|
+
│ type_hierarchy, rename, diagnostics, symbols, etc. │
|
|
146
|
+
├─────────────────────────────────────────────────────────┤
|
|
147
|
+
│ Layer 0: LSP Engine [infrastructure] │
|
|
148
|
+
│ TypeScript Server spawn, monorepo preopen, │
|
|
149
|
+
│ symbol resolver, document manager │
|
|
150
|
+
└─────────────────────────────────────────────────────────┘
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Each layer only depends on layers below it.
|
|
154
|
+
|
|
155
|
+
### Monorepo Support
|
|
156
|
+
|
|
157
|
+
Works with any monorepo structure out of the box:
|
|
158
|
+
|
|
159
|
+
- `packages/`, `apps/`, `libs/`, `modules/`, `services/` directory conventions
|
|
160
|
+
- `pnpm-workspace.yaml`
|
|
161
|
+
- `package.json` workspaces (yarn, npm)
|
|
162
|
+
|
|
163
|
+
At startup, the engine discovers all workspace packages and pre-opens one file per package. This triggers TypeScript Server to build configured projects for every package, enabling cross-package reference finding — a common challenge with LSP tooling in monorepos.
|
|
164
|
+
|
|
165
|
+
### Symbol-Name Resolution
|
|
166
|
+
|
|
167
|
+
Every tool accepts `{ symbol: "UserService" }` instead of requiring `{ file_path, line, column }`. The engine resolves names to positions via `workspace/symbol` with priority sorting. Agents never need to guess line numbers.
|
|
168
|
+
|
|
169
|
+
## Installation
|
|
170
|
+
|
|
171
|
+
Requires **Node.js 20+**.
|
|
172
|
+
|
|
173
|
+
### Option 1: Claude Code plugin (recommended)
|
|
174
|
+
|
|
175
|
+
Installs the MCP server, hooks, and skills (`/impact`, `/context`, `/check`) as a single package.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
claude plugin add perilevy/lsp-intelligence
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
> The full experience — the agent gets code intelligence tools, guided workflows via skills, and automatic hooks.
|
|
182
|
+
|
|
183
|
+
### Option 2: MCP server only
|
|
184
|
+
|
|
185
|
+
For other AI agents (Copilot, Cursor, etc.) or if you only want the raw tools without hooks and skills.
|
|
186
|
+
|
|
187
|
+
Add to your `.mcp.json`:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"mcpServers": {
|
|
192
|
+
"lsp": {
|
|
193
|
+
"command": "npx",
|
|
194
|
+
"args": ["-y", "lsp-intelligence"],
|
|
195
|
+
"env": {
|
|
196
|
+
"LSP_WORKSPACE_ROOT": "${CLAUDE_PROJECT_DIR}"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Option 3: From source
|
|
204
|
+
|
|
205
|
+
For contributors or debugging.
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
git clone https://github.com/perilevy/lsp-intelligence.git
|
|
209
|
+
cd lsp-intelligence
|
|
210
|
+
yarn install && yarn build
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Then in `.mcp.json`:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"mcpServers": {
|
|
218
|
+
"lsp": {
|
|
219
|
+
"command": "node",
|
|
220
|
+
"args": ["/absolute/path/to/lsp-intelligence/dist/index.js"],
|
|
221
|
+
"env": {
|
|
222
|
+
"LSP_WORKSPACE_ROOT": "${CLAUDE_PROJECT_DIR}"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Development
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
git clone https://github.com/perilevy/lsp-intelligence.git
|
|
233
|
+
cd lsp-intelligence
|
|
234
|
+
yarn install
|
|
235
|
+
yarn build # compile TypeScript → dist/
|
|
236
|
+
yarn test # vitest
|
|
237
|
+
yarn typecheck # TypeScript strict mode — no emit
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Testing
|
|
241
|
+
|
|
242
|
+
Tests verify cross-package reference resolution, symbol-name lookup, type alias tracing, impact trace traversal, context building, and output formatting — all against a self-contained 3-package fixture monorepo at `test-fixtures/monorepo/`. No external dependencies needed.
|
|
243
|
+
|
|
244
|
+
## Dependencies
|
|
245
|
+
|
|
246
|
+
All dependencies are installed automatically. Under the hood: [`typescript-language-server`](https://github.com/typescript-language-server/typescript-language-server) for LSP, [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) for MCP, and supporting libraries from Microsoft. Uses your project's own TypeScript version.
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MessageConnection } from 'vscode-jsonrpc';
|
|
2
|
+
import type { Diagnostic } from 'vscode-languageserver-protocol';
|
|
3
|
+
export declare class DocumentManager {
|
|
4
|
+
private openDocs;
|
|
5
|
+
private diagnosticsCache;
|
|
6
|
+
/**
|
|
7
|
+
* Ensure a file is open in the LSP server. If already open, no-op.
|
|
8
|
+
* Returns the file content.
|
|
9
|
+
*/
|
|
10
|
+
ensureOpen(filePath: string, connection: MessageConnection): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Re-read a file from disk and send didChange. For live diagnostics after edits.
|
|
13
|
+
*/
|
|
14
|
+
refreshFromDisk(filePath: string, connection: MessageConnection): Promise<string>;
|
|
15
|
+
getContent(uri: string): string | undefined;
|
|
16
|
+
isOpen(uri: string): boolean;
|
|
17
|
+
cacheDiagnostics(uri: string, diagnostics: Diagnostic[]): void;
|
|
18
|
+
getCachedDiagnostics(uri: string): Diagnostic[];
|
|
19
|
+
private detectLanguage;
|
|
20
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { pathToUri, uriToPath } from './positions.js';
|
|
3
|
+
export class DocumentManager {
|
|
4
|
+
openDocs = new Map();
|
|
5
|
+
diagnosticsCache = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Ensure a file is open in the LSP server. If already open, no-op.
|
|
8
|
+
* Returns the file content.
|
|
9
|
+
*/
|
|
10
|
+
async ensureOpen(filePath, connection) {
|
|
11
|
+
const uri = pathToUri(filePath);
|
|
12
|
+
const existing = this.openDocs.get(uri);
|
|
13
|
+
if (existing)
|
|
14
|
+
return existing.content;
|
|
15
|
+
const content = fs.readFileSync(uriToPath(uri), 'utf-8');
|
|
16
|
+
const languageId = this.detectLanguage(filePath);
|
|
17
|
+
const doc = { uri, version: 1, content, languageId };
|
|
18
|
+
this.openDocs.set(uri, doc);
|
|
19
|
+
connection.sendNotification('textDocument/didOpen', {
|
|
20
|
+
textDocument: {
|
|
21
|
+
uri,
|
|
22
|
+
languageId,
|
|
23
|
+
version: doc.version,
|
|
24
|
+
text: content,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return content;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Re-read a file from disk and send didChange. For live diagnostics after edits.
|
|
31
|
+
*/
|
|
32
|
+
async refreshFromDisk(filePath, connection) {
|
|
33
|
+
const uri = pathToUri(filePath);
|
|
34
|
+
const content = fs.readFileSync(uriToPath(uri), 'utf-8');
|
|
35
|
+
const existing = this.openDocs.get(uri);
|
|
36
|
+
if (existing) {
|
|
37
|
+
existing.version++;
|
|
38
|
+
existing.content = content;
|
|
39
|
+
connection.sendNotification('textDocument/didChange', {
|
|
40
|
+
textDocument: { uri, version: existing.version },
|
|
41
|
+
contentChanges: [{ text: content }],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await this.ensureOpen(filePath, connection);
|
|
46
|
+
}
|
|
47
|
+
return content;
|
|
48
|
+
}
|
|
49
|
+
getContent(uri) {
|
|
50
|
+
return this.openDocs.get(uri)?.content;
|
|
51
|
+
}
|
|
52
|
+
isOpen(uri) {
|
|
53
|
+
return this.openDocs.has(uri);
|
|
54
|
+
}
|
|
55
|
+
cacheDiagnostics(uri, diagnostics) {
|
|
56
|
+
this.diagnosticsCache.set(uri, diagnostics);
|
|
57
|
+
}
|
|
58
|
+
getCachedDiagnostics(uri) {
|
|
59
|
+
return this.diagnosticsCache.get(uri) ?? [];
|
|
60
|
+
}
|
|
61
|
+
detectLanguage(filePath) {
|
|
62
|
+
if (filePath.endsWith('.tsx'))
|
|
63
|
+
return 'typescriptreact';
|
|
64
|
+
if (filePath.endsWith('.ts'))
|
|
65
|
+
return 'typescript';
|
|
66
|
+
if (filePath.endsWith('.jsx'))
|
|
67
|
+
return 'javascriptreact';
|
|
68
|
+
if (filePath.endsWith('.js') || filePath.endsWith('.mjs') || filePath.endsWith('.cjs'))
|
|
69
|
+
return 'javascript';
|
|
70
|
+
return 'typescript';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=DocumentManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocumentManager.js","sourceRoot":"","sources":["../../src/engine/DocumentManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { DocumentManager } from './DocumentManager.js';
|
|
2
|
+
import type { ResolvedLocation } from './types.js';
|
|
3
|
+
export declare class LspEngine {
|
|
4
|
+
private connection;
|
|
5
|
+
private process;
|
|
6
|
+
private capabilities;
|
|
7
|
+
private _ready;
|
|
8
|
+
private _resolveReady;
|
|
9
|
+
private _rejectReady;
|
|
10
|
+
readonly docManager: DocumentManager;
|
|
11
|
+
readonly workspaceRoot: string;
|
|
12
|
+
gitAvailable: boolean;
|
|
13
|
+
constructor(workspaceRoot: string);
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Send an LSP request. Waits for engine to be ready first.
|
|
17
|
+
*/
|
|
18
|
+
request<R>(method: string, params: unknown, timeoutMs?: number): Promise<R>;
|
|
19
|
+
/**
|
|
20
|
+
* Ensure a file is open and return its URI + content.
|
|
21
|
+
*/
|
|
22
|
+
prepareFile(filePath: string): Promise<{
|
|
23
|
+
uri: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a symbol name to a file position using workspace/symbol.
|
|
28
|
+
*/
|
|
29
|
+
resolveSymbol(name: string, fileHint?: string): Promise<ResolvedLocation>;
|
|
30
|
+
/**
|
|
31
|
+
* Discover monorepo packages and open one file per package.
|
|
32
|
+
*/
|
|
33
|
+
private preopenPackages;
|
|
34
|
+
/**
|
|
35
|
+
* Discover workspace packages from any monorepo structure.
|
|
36
|
+
* Supports: packages/, apps/, libs/, pnpm-workspace.yaml, lerna.json, rush.json
|
|
37
|
+
*/
|
|
38
|
+
private discoverWorkspacePackages;
|
|
39
|
+
/**
|
|
40
|
+
* Build initializationOptions for typescript-language-server.
|
|
41
|
+
* Points tsserver.path to the consumer's TypeScript if available.
|
|
42
|
+
*/
|
|
43
|
+
private buildInitOptions;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a binary — check bundled node_modules/.bin first, then global PATH.
|
|
46
|
+
*/
|
|
47
|
+
private resolveBinary;
|
|
48
|
+
private findFirstTsFile;
|
|
49
|
+
shutdown(): Promise<void>;
|
|
50
|
+
}
|