@mrclrchtr/supi-code-intelligence 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -32
- package/node_modules/@mrclrchtr/supi-core/README.md +52 -41
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +15 -13
- package/node_modules/@mrclrchtr/supi-core/src/{config-settings.ts → config/config-settings.ts} +2 -2
- package/node_modules/@mrclrchtr/{supi-lsp/node_modules/@mrclrchtr/supi-core/src → supi-core/src/context}/context-provider-registry.ts +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/extension.ts +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +15 -13
- package/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +40 -0
- package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +42 -10
- package/node_modules/@mrclrchtr/{supi-lsp/node_modules/@mrclrchtr/supi-core/src → supi-core/src/settings}/settings-registry.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/README.md +58 -39
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +52 -41
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/api.ts +15 -13
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/{config-settings.ts → config/config-settings.ts} +2 -2
- package/node_modules/@mrclrchtr/{supi-core/src → supi-lsp/node_modules/@mrclrchtr/supi-core/src/context}/context-provider-registry.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/extension.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/index.ts +15 -13
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +40 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +42 -10
- package/node_modules/@mrclrchtr/{supi-core/src → supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings}/settings-registry.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +16 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-refresh.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +27 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +61 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-scope.ts +244 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/{types.ts → config/types.ts} +4 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/coordinates.ts +11 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-augmentation.ts +5 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-context.ts +115 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-display.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-summary.ts +3 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostics.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/stale-diagnostics.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/suppression-diagnostics.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/{workspace-sentinels.ts → diagnostics/workspace-sentinels.ts} +2 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/format.ts +2 -23
- package/node_modules/@mrclrchtr/supi-lsp/src/index.ts +18 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/lsp.ts +72 -120
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-helpers.ts +4 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-project-info.ts +10 -21
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +158 -6
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +202 -43
- package/node_modules/@mrclrchtr/supi-lsp/src/{lsp-state.ts → session/lsp-state.ts} +22 -11
- package/node_modules/@mrclrchtr/supi-lsp/src/{scanner.ts → session/scanner.ts} +3 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/{service-registry.ts → session/service-registry.ts} +109 -33
- package/node_modules/@mrclrchtr/supi-lsp/src/{settings-registration.ts → session/settings-registration.ts} +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/session/tree-persist.ts +75 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/summary.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/tool/guidance.ts +78 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/tool/names.ts +19 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/{overrides.ts → tool/overrides.ts} +55 -24
- package/node_modules/@mrclrchtr/supi-lsp/src/tool/register-tools.ts +71 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/tool/service-actions.ts +258 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/tool/tool-specs.ts +248 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/{ui.ts → ui/ui.ts} +4 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +5 -23
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +58 -39
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +107 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +44 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/api.ts +85 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +76 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +186 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/context/context-messages.ts +119 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/context/context-provider-registry.ts +36 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/context/context-tag.ts +31 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +255 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/extension.ts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/index.ts +85 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +40 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/project-roots.ts +170 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +86 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/session-utils.ts +29 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +15 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +41 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +226 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/terminal.ts +60 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +8 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +6 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +6 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{runtime.ts → session/runtime.ts} +6 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/service-registry.ts +30 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{session.ts → session/session.ts} +20 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/action-specs.ts +92 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{callees.ts → tool/callees.ts} +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{exports.ts → tool/exports.ts} +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{formatting.ts → tool/formatting.ts} +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/guidance.ts +31 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{imports.ts → tool/imports.ts} +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{node-at.ts → tool/node-at.ts} +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{outline.ts → tool/outline.ts} +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tree-sitter.ts +118 -91
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +13 -2
- package/package.json +4 -4
- package/src/actions/affected-action.ts +4 -4
- package/src/actions/brief-action.ts +12 -13
- package/src/actions/callees-action.ts +14 -10
- package/src/actions/callers-action.ts +4 -4
- package/src/actions/implementations-action.ts +4 -4
- package/src/code-intelligence.ts +4 -11
- package/src/pattern-structured.ts +20 -22
- package/src/providers/semantic-provider.ts +34 -0
- package/src/providers/structural-provider.ts +26 -0
- package/src/search-helpers.ts +4 -15
- package/src/target-resolution.ts +26 -35
- package/src/tool/action-specs.ts +66 -0
- package/src/tool/guidance.ts +18 -0
- package/src/tool-actions.ts +23 -40
- package/node_modules/@mrclrchtr/supi-lsp/src/guidance.ts +0 -163
- package/node_modules/@mrclrchtr/supi-lsp/src/search-fallback.ts +0 -98
- package/node_modules/@mrclrchtr/supi-lsp/src/tool-actions.ts +0 -430
- package/node_modules/@mrclrchtr/supi-lsp/src/tree-persist.ts +0 -48
- package/node_modules/@mrclrchtr/supi-lsp/src/tsconfig-scope.ts +0 -156
- package/src/guidance.ts +0 -42
- /package/node_modules/@mrclrchtr/supi-core/src/{config.ts → config/config.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{context-messages.ts → context/context-messages.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{context-tag.ts → context/context-tag.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{settings-command.ts → settings/settings-command.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{settings-ui.ts → settings/settings-ui.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/{config.ts → config/config.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/{context-messages.ts → context/context-messages.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/{context-tag.ts → context/context-tag.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/{settings-command.ts → settings/settings-command.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/{settings-ui.ts → settings/settings-ui.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/src/{capabilities.ts → config/capabilities.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/src/{config.ts → config/config.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/src/{defaults.json → config/defaults.json} +0 -0
- /package/node_modules/@mrclrchtr/supi-lsp/src/{renderer.ts → ui/renderer.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-tree-sitter/src/{structure.ts → tool/structure.ts} +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// Service-backed LSP tool actions used by the public expert toolset.
|
|
2
|
+
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import type { Position } from "../config/types.ts";
|
|
6
|
+
import { formatDiagnostics } from "../diagnostics/diagnostics.ts";
|
|
7
|
+
import {
|
|
8
|
+
formatCodeActions,
|
|
9
|
+
formatDocumentSymbols,
|
|
10
|
+
formatHover,
|
|
11
|
+
formatLocations,
|
|
12
|
+
formatSymbolInformation,
|
|
13
|
+
formatWorkspaceEdit,
|
|
14
|
+
formatWorkspaceSymbols,
|
|
15
|
+
normalizeLocations,
|
|
16
|
+
} from "../format.ts";
|
|
17
|
+
import type { SessionLspService } from "../session/service-registry.ts";
|
|
18
|
+
import { resolveSessionPath } from "../utils.ts";
|
|
19
|
+
|
|
20
|
+
export type LspLookupKind = "hover" | "definition" | "references" | "implementation";
|
|
21
|
+
export type LspRefactorKind = "rename" | "code_actions";
|
|
22
|
+
|
|
23
|
+
export interface LspLookupToolParams {
|
|
24
|
+
kind: LspLookupKind;
|
|
25
|
+
file: string;
|
|
26
|
+
line: number;
|
|
27
|
+
character: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface LspDocumentSymbolsToolParams {
|
|
31
|
+
file: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface LspWorkspaceSymbolsToolParams {
|
|
35
|
+
query: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface LspDiagnosticsToolParams {
|
|
39
|
+
file?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface LspRefactorToolParams {
|
|
43
|
+
kind: LspRefactorKind;
|
|
44
|
+
file: string;
|
|
45
|
+
line: number;
|
|
46
|
+
character: number;
|
|
47
|
+
newName?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validatePositivePosition(line: number, character: number): string | null {
|
|
51
|
+
if (!Number.isInteger(line) || line < 1) {
|
|
52
|
+
return "Validation error: `line` must be a positive 1-based integer.";
|
|
53
|
+
}
|
|
54
|
+
if (!Number.isInteger(character) || character < 1) {
|
|
55
|
+
return "Validation error: `character` must be a positive 1-based integer.";
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function toZeroBased(line: number, character: number): Position {
|
|
61
|
+
return { line: line - 1, character: character - 1 };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function validateFile(service: SessionLspService, cwd: string, file: string): string | null {
|
|
65
|
+
const resolvedPath = resolveSessionPath(cwd, file);
|
|
66
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
67
|
+
return `File not found: \`${file}\``;
|
|
68
|
+
}
|
|
69
|
+
if (!service.isSupportedSourceFile(file)) {
|
|
70
|
+
return noServerMessage(resolvedPath);
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function noServerMessage(filePath: string): string {
|
|
76
|
+
return `No LSP server available for this file type (${path.extname(filePath) || "unknown"})`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function formatUnexpectedFailure(label: string, error: unknown): string {
|
|
80
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
81
|
+
return `LSP ${label} failed: ${message}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: semantic lookup dispatch stays clearer as a single position-based switch.
|
|
85
|
+
export async function executeLookup(
|
|
86
|
+
service: SessionLspService,
|
|
87
|
+
cwd: string,
|
|
88
|
+
params: LspLookupToolParams,
|
|
89
|
+
): Promise<string> {
|
|
90
|
+
try {
|
|
91
|
+
const positionError = validatePositivePosition(params.line, params.character);
|
|
92
|
+
if (positionError) return positionError;
|
|
93
|
+
|
|
94
|
+
const fileError = validateFile(service, cwd, params.file);
|
|
95
|
+
if (fileError) return fileError;
|
|
96
|
+
|
|
97
|
+
const position = toZeroBased(params.line, params.character);
|
|
98
|
+
switch (params.kind) {
|
|
99
|
+
case "hover": {
|
|
100
|
+
const hover = await service.hover(params.file, position);
|
|
101
|
+
return hover ? formatHover(hover) : "No hover information available at this position.";
|
|
102
|
+
}
|
|
103
|
+
case "definition": {
|
|
104
|
+
const result = await service.definition(params.file, position);
|
|
105
|
+
if (!result) return "No definition found.";
|
|
106
|
+
const locations = normalizeLocations(result);
|
|
107
|
+
return locations.length > 0
|
|
108
|
+
? formatLocations("Definition", locations, cwd)
|
|
109
|
+
: "No definition found.";
|
|
110
|
+
}
|
|
111
|
+
case "references": {
|
|
112
|
+
const references = await service.references(params.file, position);
|
|
113
|
+
return references && references.length > 0
|
|
114
|
+
? formatLocations("References", references, cwd)
|
|
115
|
+
: "No references found.";
|
|
116
|
+
}
|
|
117
|
+
case "implementation": {
|
|
118
|
+
const result = await service.implementation(params.file, position);
|
|
119
|
+
if (!result) return "No implementation found.";
|
|
120
|
+
const locations = normalizeLocations(result);
|
|
121
|
+
return locations.length > 0
|
|
122
|
+
? formatLocations("Implementation", locations, cwd)
|
|
123
|
+
: "No implementation found.";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return formatUnexpectedFailure("lookup", error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function executeDocumentSymbols(
|
|
132
|
+
service: SessionLspService,
|
|
133
|
+
cwd: string,
|
|
134
|
+
params: LspDocumentSymbolsToolParams,
|
|
135
|
+
): Promise<string> {
|
|
136
|
+
try {
|
|
137
|
+
const fileError = validateFile(service, cwd, params.file);
|
|
138
|
+
if (fileError) return fileError;
|
|
139
|
+
|
|
140
|
+
const symbols = await service.documentSymbols(params.file);
|
|
141
|
+
if (!symbols || symbols.length === 0) return "No document symbols found.";
|
|
142
|
+
|
|
143
|
+
if ("children" in symbols[0] || "selectionRange" in symbols[0]) {
|
|
144
|
+
return formatDocumentSymbols(symbols as import("../config/types.ts").DocumentSymbol[], 0);
|
|
145
|
+
}
|
|
146
|
+
return formatSymbolInformation(
|
|
147
|
+
symbols as import("../config/types.ts").SymbolInformation[],
|
|
148
|
+
cwd,
|
|
149
|
+
);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
return formatUnexpectedFailure("document symbol lookup", error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function executeWorkspaceSymbols(
|
|
156
|
+
service: SessionLspService,
|
|
157
|
+
cwd: string,
|
|
158
|
+
params: LspWorkspaceSymbolsToolParams,
|
|
159
|
+
): Promise<string> {
|
|
160
|
+
try {
|
|
161
|
+
const query = params.query.trim();
|
|
162
|
+
if (query.length === 0) {
|
|
163
|
+
return "Validation error: `query` must be a non-empty string.";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const symbols = await service.workspaceSymbol(query);
|
|
167
|
+
if (!symbols) return "Workspace symbol search is not supported by the active language servers.";
|
|
168
|
+
if (symbols.length === 0) return `No symbols found for query \`${query}\`.`;
|
|
169
|
+
|
|
170
|
+
return formatWorkspaceSymbols(symbols, cwd);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return formatUnexpectedFailure("workspace symbol lookup", error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function executeDiagnostics(
|
|
177
|
+
service: SessionLspService,
|
|
178
|
+
cwd: string,
|
|
179
|
+
params: LspDiagnosticsToolParams,
|
|
180
|
+
): Promise<string> {
|
|
181
|
+
try {
|
|
182
|
+
if (params.file) {
|
|
183
|
+
const resolvedPath = resolveSessionPath(cwd, params.file);
|
|
184
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
185
|
+
return `File not found: \`${params.file}\``;
|
|
186
|
+
}
|
|
187
|
+
if (!service.isSupportedSourceFile(params.file)) {
|
|
188
|
+
return noServerMessage(resolvedPath);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const diagnostics = await service.fileDiagnostics(params.file, 4);
|
|
192
|
+
if (!diagnostics) return noServerMessage(resolvedPath);
|
|
193
|
+
return formatDiagnostics(resolvedPath, diagnostics, cwd);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const summary = service.getWorkspaceDiagnosticSummary();
|
|
197
|
+
if (summary.length === 0) return "No diagnostics across any files.";
|
|
198
|
+
|
|
199
|
+
const lines = ["## Diagnostics Summary", ""];
|
|
200
|
+
for (const entry of summary) {
|
|
201
|
+
lines.push(`- **${entry.file}**: ${entry.errors} error(s), ${entry.warnings} warning(s)`);
|
|
202
|
+
}
|
|
203
|
+
return lines.join("\n");
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return formatUnexpectedFailure("diagnostics", error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function executeRefactor(
|
|
210
|
+
service: SessionLspService,
|
|
211
|
+
cwd: string,
|
|
212
|
+
params: LspRefactorToolParams,
|
|
213
|
+
): Promise<string> {
|
|
214
|
+
try {
|
|
215
|
+
const positionError = validatePositivePosition(params.line, params.character);
|
|
216
|
+
if (positionError) return positionError;
|
|
217
|
+
|
|
218
|
+
const fileError = validateFile(service, cwd, params.file);
|
|
219
|
+
if (fileError) return fileError;
|
|
220
|
+
|
|
221
|
+
const position = toZeroBased(params.line, params.character);
|
|
222
|
+
|
|
223
|
+
if (params.kind === "rename") {
|
|
224
|
+
if (!params.newName || params.newName.trim().length === 0) {
|
|
225
|
+
return "Validation error: `newName` is required for rename.";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const edit = await service.rename(params.file, position, params.newName.trim());
|
|
229
|
+
return edit ? formatWorkspaceEdit(edit, cwd) : "Rename not available at this position.";
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const actions = await service.codeActions(params.file, position);
|
|
233
|
+
return actions && actions.length > 0
|
|
234
|
+
? formatCodeActions(actions)
|
|
235
|
+
: "No code actions available at this position.";
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return formatUnexpectedFailure("refactor", error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export async function executeRecover(service: SessionLspService): Promise<string> {
|
|
242
|
+
try {
|
|
243
|
+
const result = await service.recoverDiagnostics({ restartIfStillStale: true });
|
|
244
|
+
const refreshed = pluralize(result.refreshedClients, "client");
|
|
245
|
+
const restarted = pluralize(result.restartedClients, "client");
|
|
246
|
+
const status = result.staleAssessment.suspected
|
|
247
|
+
? "stale diagnostics still suspected"
|
|
248
|
+
: "stale diagnostics cleared";
|
|
249
|
+
const warning = result.staleAssessment.warning ? ` — ${result.staleAssessment.warning}` : "";
|
|
250
|
+
return `LSP recovery complete: refreshed ${refreshed}, restarted ${restarted}, ${status}${warning}.`;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
return formatUnexpectedFailure("recovery", error);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function pluralize(count: number, word: string): string {
|
|
257
|
+
return `${count} ${word}${count === 1 ? "" : "s"}`;
|
|
258
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
|
+
import { type TSchema, Type } from "typebox";
|
|
3
|
+
import type { ServerCapabilities } from "../config/types.ts";
|
|
4
|
+
import type { SessionLspService } from "../session/service-registry.ts";
|
|
5
|
+
import {
|
|
6
|
+
LSP_DIAGNOSTICS_TOOL,
|
|
7
|
+
LSP_DOCUMENT_SYMBOLS_TOOL,
|
|
8
|
+
LSP_LOOKUP_TOOL,
|
|
9
|
+
LSP_RECOVER_TOOL,
|
|
10
|
+
LSP_REFACTOR_TOOL,
|
|
11
|
+
LSP_WORKSPACE_SYMBOLS_TOOL,
|
|
12
|
+
type LspToolName,
|
|
13
|
+
} from "./names.ts";
|
|
14
|
+
import {
|
|
15
|
+
executeDiagnostics,
|
|
16
|
+
executeDocumentSymbols,
|
|
17
|
+
executeLookup,
|
|
18
|
+
executeRecover,
|
|
19
|
+
executeRefactor,
|
|
20
|
+
executeWorkspaceSymbols,
|
|
21
|
+
} from "./service-actions.ts";
|
|
22
|
+
|
|
23
|
+
const FileParam = Type.String({ description: "File path (relative or absolute)" });
|
|
24
|
+
const LineParam = Type.Number({ description: "1-based line number", minimum: 1 });
|
|
25
|
+
const CharacterParam = Type.Number({ description: "1-based column number", minimum: 1 });
|
|
26
|
+
const QueryParam = Type.String({ description: "Symbol query string" });
|
|
27
|
+
const NewNameParam = Type.String({ description: "New name for rename" });
|
|
28
|
+
|
|
29
|
+
export const LSP_LOOKUP_KIND_NAMES = [
|
|
30
|
+
"hover",
|
|
31
|
+
"definition",
|
|
32
|
+
"references",
|
|
33
|
+
"implementation",
|
|
34
|
+
] as const;
|
|
35
|
+
export const LSP_REFACTOR_KIND_NAMES = ["rename", "code_actions"] as const;
|
|
36
|
+
|
|
37
|
+
const LookupKindEnum = StringEnum(LSP_LOOKUP_KIND_NAMES);
|
|
38
|
+
const RefactorKindEnum = StringEnum(LSP_REFACTOR_KIND_NAMES);
|
|
39
|
+
|
|
40
|
+
const LookupParameters = Type.Object(
|
|
41
|
+
{
|
|
42
|
+
kind: LookupKindEnum,
|
|
43
|
+
file: FileParam,
|
|
44
|
+
line: LineParam,
|
|
45
|
+
character: CharacterParam,
|
|
46
|
+
},
|
|
47
|
+
{ additionalProperties: false },
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const DocumentSymbolsParameters = Type.Object(
|
|
51
|
+
{
|
|
52
|
+
file: FileParam,
|
|
53
|
+
},
|
|
54
|
+
{ additionalProperties: false },
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const WorkspaceSymbolsParameters = Type.Object(
|
|
58
|
+
{
|
|
59
|
+
query: QueryParam,
|
|
60
|
+
},
|
|
61
|
+
{ additionalProperties: false },
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const DiagnosticsParameters = Type.Object(
|
|
65
|
+
{
|
|
66
|
+
file: Type.Optional(FileParam),
|
|
67
|
+
},
|
|
68
|
+
{ additionalProperties: false },
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const RefactorParameters = Type.Object(
|
|
72
|
+
{
|
|
73
|
+
kind: RefactorKindEnum,
|
|
74
|
+
file: FileParam,
|
|
75
|
+
line: LineParam,
|
|
76
|
+
character: CharacterParam,
|
|
77
|
+
newName: Type.Optional(NewNameParam),
|
|
78
|
+
},
|
|
79
|
+
{ additionalProperties: false },
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const RecoverParameters = Type.Object({}, { additionalProperties: false });
|
|
83
|
+
|
|
84
|
+
export interface LspToolDefinitionSpec {
|
|
85
|
+
name: LspToolName;
|
|
86
|
+
label: string;
|
|
87
|
+
description: string;
|
|
88
|
+
promptSnippet: string;
|
|
89
|
+
basePromptGuidelines: string[];
|
|
90
|
+
parameters: TSchema;
|
|
91
|
+
run: (service: SessionLspService, cwd: string, params: unknown) => Promise<string>;
|
|
92
|
+
includeCoverageGuidelines?: boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const LSP_TOOL_DEFINITION_SPECS = [
|
|
96
|
+
{
|
|
97
|
+
name: LSP_LOOKUP_TOOL,
|
|
98
|
+
label: "LSP Lookup",
|
|
99
|
+
description:
|
|
100
|
+
"Language Server Protocol lookup tool — semantic hover, definition, references, and implementation for supported files. Use lsp_lookup when you know the file and 1-based line/character position and need semantic drill-down rather than text search.",
|
|
101
|
+
promptSnippet:
|
|
102
|
+
"lsp_lookup — semantic hover/definition/references/implementation at a known file position",
|
|
103
|
+
basePromptGuidelines: [
|
|
104
|
+
'Use lsp_lookup with `kind: "hover"` for semantic type or symbol information at a known `file`, `line`, and `character`.',
|
|
105
|
+
'Use lsp_lookup with `kind: "definition"`, `"references"`, or `"implementation"` for semantic navigation at a known position.',
|
|
106
|
+
"Use lsp_lookup after code_intel or tree_sitter has already narrowed the target file and position.",
|
|
107
|
+
],
|
|
108
|
+
parameters: LookupParameters,
|
|
109
|
+
run: (service, cwd, params) =>
|
|
110
|
+
executeLookup(service, cwd, params as Parameters<typeof executeLookup>[2]),
|
|
111
|
+
includeCoverageGuidelines: true,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: LSP_DOCUMENT_SYMBOLS_TOOL,
|
|
115
|
+
label: "LSP Document Symbols",
|
|
116
|
+
description:
|
|
117
|
+
"Language Server Protocol document symbols tool — list semantic declarations in one supported file. Use lsp_document_symbols when you need a symbol-aware outline rather than raw text structure.",
|
|
118
|
+
promptSnippet: "lsp_document_symbols — semantic declarations for one supported file",
|
|
119
|
+
basePromptGuidelines: [
|
|
120
|
+
"Use lsp_document_symbols(file) for semantic declarations in one supported file.",
|
|
121
|
+
],
|
|
122
|
+
parameters: DocumentSymbolsParameters,
|
|
123
|
+
run: (service, cwd, params) =>
|
|
124
|
+
executeDocumentSymbols(service, cwd, params as Parameters<typeof executeDocumentSymbols>[2]),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: LSP_WORKSPACE_SYMBOLS_TOOL,
|
|
128
|
+
label: "LSP Workspace Symbols",
|
|
129
|
+
description:
|
|
130
|
+
"Language Server Protocol workspace symbols tool — semantic symbol-name lookup across the current project. Use lsp_workspace_symbols to find declarations by name before opening a specific file.",
|
|
131
|
+
promptSnippet: "lsp_workspace_symbols — semantic symbol-name lookup across the project",
|
|
132
|
+
basePromptGuidelines: [
|
|
133
|
+
"Use lsp_workspace_symbols(query) for semantic symbol-name lookup across the current project.",
|
|
134
|
+
],
|
|
135
|
+
parameters: WorkspaceSymbolsParameters,
|
|
136
|
+
run: (service, cwd, params) =>
|
|
137
|
+
executeWorkspaceSymbols(
|
|
138
|
+
service,
|
|
139
|
+
cwd,
|
|
140
|
+
params as Parameters<typeof executeWorkspaceSymbols>[2],
|
|
141
|
+
),
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: LSP_DIAGNOSTICS_TOOL,
|
|
145
|
+
label: "LSP Diagnostics",
|
|
146
|
+
description:
|
|
147
|
+
"Language Server Protocol diagnostics tool — current diagnostics for one file or a workspace summary. Use lsp_diagnostics for semantic compiler or language-server issues instead of guessing from text alone.",
|
|
148
|
+
promptSnippet: "lsp_diagnostics — current diagnostics for one file or the workspace",
|
|
149
|
+
basePromptGuidelines: [
|
|
150
|
+
"Use lsp_diagnostics(file?) when you need current diagnostics for one file or a workspace-level summary.",
|
|
151
|
+
],
|
|
152
|
+
parameters: DiagnosticsParameters,
|
|
153
|
+
run: (service, cwd, params) =>
|
|
154
|
+
executeDiagnostics(service, cwd, params as Parameters<typeof executeDiagnostics>[2]),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: LSP_REFACTOR_TOOL,
|
|
158
|
+
label: "LSP Refactor",
|
|
159
|
+
description:
|
|
160
|
+
"Language Server Protocol refactor tool — semantic rename planning and code actions at a known file position. Use lsp_refactor when you need language-server-backed edits or quick-fix suggestions.",
|
|
161
|
+
promptSnippet: "lsp_refactor — semantic rename planning and code actions at a known position",
|
|
162
|
+
basePromptGuidelines: [
|
|
163
|
+
'Use lsp_refactor with `kind: "rename"` for semantic rename planning at a known `file`, `line`, and `character`.',
|
|
164
|
+
'Use lsp_refactor with `kind: "code_actions"` for semantic fixes or refactors at a known position.',
|
|
165
|
+
],
|
|
166
|
+
parameters: RefactorParameters,
|
|
167
|
+
run: (service, cwd, params) =>
|
|
168
|
+
executeRefactor(service, cwd, params as Parameters<typeof executeRefactor>[2]),
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: LSP_RECOVER_TOOL,
|
|
172
|
+
label: "LSP Recover",
|
|
173
|
+
description:
|
|
174
|
+
"Language Server Protocol recover tool — refresh diagnostics after workspace changes and stale language-server state. Use lsp_recover when new files, generated types, or config updates leave diagnostics out of sync.",
|
|
175
|
+
promptSnippet: "lsp_recover — refresh stale diagnostics after workspace changes",
|
|
176
|
+
basePromptGuidelines: [
|
|
177
|
+
"Use lsp_recover() when diagnostics look stale after workspace-level changes or generated-file updates.",
|
|
178
|
+
],
|
|
179
|
+
parameters: RecoverParameters,
|
|
180
|
+
run: (service) => executeRecover(service),
|
|
181
|
+
},
|
|
182
|
+
] as const satisfies readonly LspToolDefinitionSpec[];
|
|
183
|
+
|
|
184
|
+
const LSP_TOOL_SPEC_MAP = new Map<LspToolName, LspToolDefinitionSpec>(
|
|
185
|
+
LSP_TOOL_DEFINITION_SPECS.map((spec) => [spec.name, spec]),
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
export function getLspToolDefinitionSpec(toolName: LspToolName): LspToolDefinitionSpec {
|
|
189
|
+
const spec = LSP_TOOL_SPEC_MAP.get(toolName);
|
|
190
|
+
if (!spec) {
|
|
191
|
+
throw new Error(`Unknown LSP tool: ${toolName}`);
|
|
192
|
+
}
|
|
193
|
+
return spec;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
interface LspServerSupportedActionSpec {
|
|
197
|
+
label: string;
|
|
198
|
+
isSupported: (capabilities: ServerCapabilities | null | undefined) => boolean;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const LSP_SERVER_SUPPORTED_ACTION_SPECS: readonly LspServerSupportedActionSpec[] = [
|
|
202
|
+
{
|
|
203
|
+
label: "diagnostics [optional file]",
|
|
204
|
+
isSupported: () => true,
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
label: "hover(file,line,char)",
|
|
208
|
+
isSupported: (capabilities) => Boolean(capabilities?.hoverProvider),
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
label: "definition(file,line,char)",
|
|
212
|
+
isSupported: (capabilities) => Boolean(capabilities?.definitionProvider),
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
label: "references(file,line,char)",
|
|
216
|
+
isSupported: (capabilities) => Boolean(capabilities?.referencesProvider),
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
label: "implementation(file,line,char)",
|
|
220
|
+
isSupported: (capabilities) => Boolean(capabilities?.implementationProvider),
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
label: "symbols(file)",
|
|
224
|
+
isSupported: (capabilities) => Boolean(capabilities?.documentSymbolProvider),
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
label: "workspace_symbols(query)",
|
|
228
|
+
isSupported: (capabilities) => Boolean(capabilities?.workspaceSymbolProvider),
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
label: "rename(file,line,char,newName)",
|
|
232
|
+
isSupported: (capabilities) => Boolean(capabilities?.renameProvider),
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
label: "code_actions(file,line,char)",
|
|
236
|
+
isSupported: (capabilities) => Boolean(capabilities?.codeActionProvider),
|
|
237
|
+
},
|
|
238
|
+
] as const;
|
|
239
|
+
|
|
240
|
+
export function getSupportedLspServerActions(
|
|
241
|
+
capabilities: ServerCapabilities | null | undefined,
|
|
242
|
+
): string[] {
|
|
243
|
+
if (!capabilities) return [];
|
|
244
|
+
|
|
245
|
+
return LSP_SERVER_SUPPORTED_ACTION_SPECS.filter((spec) => spec.isSupported(capabilities)).map(
|
|
246
|
+
(spec) => spec.label,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
@@ -2,10 +2,10 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import { DynamicBorder } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import type { OverlayHandle } from "@earendil-works/pi-tui";
|
|
4
4
|
import { Container, Spacer, Text } from "@earendil-works/pi-tui";
|
|
5
|
-
import type {
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
8
|
-
import {
|
|
5
|
+
import type { Diagnostic, ProjectServerInfo } from "../config/types.ts";
|
|
6
|
+
import { DiagnosticSeverity } from "../config/types.ts";
|
|
7
|
+
import type { LspManager } from "../manager/manager.ts";
|
|
8
|
+
import type { OutstandingDiagnosticSummaryEntry } from "../manager/manager-types.ts";
|
|
9
9
|
|
|
10
10
|
export interface LspInspectorState {
|
|
11
11
|
handle: OverlayHandle | null;
|
|
@@ -2,30 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
// ── URI Handling ──────────────────────────────────────────────────────
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
return `file://${resolved}`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Convert a file:// URI to a file path. */
|
|
17
|
-
export function uriToFile(uri: string): string {
|
|
18
|
-
if (!uri.startsWith("file://")) return uri;
|
|
19
|
-
let filePath = decodeURIComponent(uri.slice(7));
|
|
20
|
-
if (
|
|
21
|
-
process.platform === "win32" &&
|
|
22
|
-
filePath.startsWith("/") &&
|
|
23
|
-
/^[A-Za-z]:/.test(filePath.slice(1))
|
|
24
|
-
) {
|
|
25
|
-
filePath = filePath.slice(1);
|
|
26
|
-
}
|
|
27
|
-
return filePath;
|
|
28
|
-
}
|
|
6
|
+
export {
|
|
7
|
+
fileToUri,
|
|
8
|
+
resolveToolPath as resolveSessionPath,
|
|
9
|
+
uriToFile,
|
|
10
|
+
} from "@mrclrchtr/supi-core/api";
|
|
29
11
|
|
|
30
12
|
// ── Language ID Detection ─────────────────────────────────────────────
|
|
31
13
|
|