@mrclrchtr/supi-code-intelligence 1.3.1 → 1.4.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 +13 -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 +13 -13
- 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 +13 -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 +13 -13
- 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 -7
- 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} +104 -12
- 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 +138 -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 +224 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/tool/service-actions.ts +258 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/{ui.ts → ui/ui.ts} +4 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +11 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +46 -39
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{runtime.ts → session/runtime.ts} +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/{session.ts → session/session.ts} +4 -4
- 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 +22 -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 +6 -29
- 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 +1 -1
- package/src/pattern-structured.ts +20 -22
- package/src/providers/semantic-provider.ts +34 -0
- package/src/providers/structural-provider.ts +14 -0
- package/src/target-resolution.ts +26 -35
- package/src/tool/guidance.ts +21 -0
- 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
|
+
}
|
|
@@ -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;
|
|
@@ -27,6 +27,17 @@ export function uriToFile(uri: string): string {
|
|
|
27
27
|
return filePath;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a tool-style file path against the active session cwd.
|
|
32
|
+
*
|
|
33
|
+
* Built-in pi file tools accept a leading `@` prefix in path arguments, so LSP
|
|
34
|
+
* helpers strip that prefix as well before resolving relative paths.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveSessionPath(cwd: string, filePath: string): string {
|
|
37
|
+
const normalizedPath = filePath.startsWith("@") ? filePath.slice(1) : filePath;
|
|
38
|
+
return path.resolve(cwd, normalizedPath);
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
// ── Language ID Detection ─────────────────────────────────────────────
|
|
31
42
|
|
|
32
43
|
const EXT_TO_LANGUAGE: Record<string, string> = {
|
|
@@ -1,72 +1,79 @@
|
|
|
1
1
|
# @mrclrchtr/supi-tree-sitter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Adds a `tree_sitter` tool to the [pi coding agent](https://github.com/earendil-works/pi) for parser-based structural code analysis.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## What you get
|
|
5
|
+
## Install
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
```bash
|
|
8
|
+
pi install npm:@mrclrchtr/supi-tree-sitter
|
|
9
|
+
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
For local development:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
```bash
|
|
14
|
+
pi install ./packages/supi-tree-sitter
|
|
15
|
+
```
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
After editing the source, run `/reload`.
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
## What you get
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
After install, pi gets one tool:
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
- `tree_sitter` — inspect code structure through Tree-sitter parsers instead of plain text search
|
|
22
24
|
|
|
23
|
-
##
|
|
25
|
+
## `tree_sitter` actions
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
| Action | What it is for | Current language coverage |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `outline` | List structural declarations such as functions, classes, interfaces, and methods | JavaScript / TypeScript only |
|
|
30
|
+
| `imports` | List import statements | JavaScript / TypeScript only |
|
|
31
|
+
| `exports` | List export declarations, re-exports, and export assignments | JavaScript / TypeScript only |
|
|
32
|
+
| `node_at` | Show the syntax node at a position, including ancestry | Any supported grammar |
|
|
33
|
+
| `query` | Run a custom Tree-sitter query against a file | Any supported grammar |
|
|
34
|
+
| `callees` | Find outgoing calls from the enclosing function or method at a position | Supported for most grammars, but not all |
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
Coordinates use **1-based** line and character columns. Character positions use UTF-16 code units.
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
## Supported file families
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|--------|-------------|
|
|
35
|
-
| `outline` | List functions, classes, interfaces in a file |
|
|
36
|
-
| `callees` | Find all function calls from a position |
|
|
37
|
-
| `imports` / `exports` | See what a file imports and exports |
|
|
38
|
-
| `node_at` | Inspect the AST node at any line/column |
|
|
39
|
-
| `query` | Run a custom Tree-sitter query |
|
|
40
|
+
The current tool description covers:
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
- JavaScript / TypeScript (`.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts`)
|
|
43
|
+
- Python (`.py`, `.pyi`)
|
|
44
|
+
- Rust (`.rs`)
|
|
45
|
+
- Go (`.go`, `.mod`)
|
|
46
|
+
- C / C++ (`.c`, `.h`, `.cpp`, `.hpp`, `.cc`, `.cxx`, `.hxx`, `.c++`, `.h++`)
|
|
47
|
+
- Java (`.java`)
|
|
48
|
+
- Kotlin (`.kt`, `.kts`)
|
|
49
|
+
- Ruby (`.rb`)
|
|
50
|
+
- Bash / shell (`.sh`, `.bash`, `.zsh`)
|
|
51
|
+
- HTML (`.html`, `.htm`, `.xhtml`)
|
|
52
|
+
- R (`.r`)
|
|
53
|
+
- SQL (`.sql`)
|
|
42
54
|
|
|
43
55
|
## Package surfaces
|
|
44
56
|
|
|
45
|
-
- `@mrclrchtr/supi-tree-sitter/api` — reusable parsing
|
|
57
|
+
- `@mrclrchtr/supi-tree-sitter/api` — reusable parsing session factory and shared result types
|
|
46
58
|
- `@mrclrchtr/supi-tree-sitter/extension` — pi extension entrypoint
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
## For extension developers
|
|
51
|
-
|
|
52
|
-
This package exports a reusable session-scoped parsing service:
|
|
60
|
+
Example:
|
|
53
61
|
|
|
54
62
|
```ts
|
|
55
63
|
import { createTreeSitterSession } from "@mrclrchtr/supi-tree-sitter/api";
|
|
56
64
|
|
|
57
65
|
const session = createTreeSitterSession("/project");
|
|
58
66
|
|
|
59
|
-
|
|
60
|
-
const result = await session.canParse("src/index.ts");
|
|
61
|
-
|
|
62
|
-
// Get structural outline
|
|
67
|
+
const parseable = await session.canParse("src/index.ts");
|
|
63
68
|
const outline = await session.outline("src/index.ts");
|
|
64
|
-
|
|
65
|
-
// Trace outgoing calls from a position
|
|
66
69
|
const callees = await session.calleesAt("src/index.ts", 42, 10);
|
|
67
70
|
|
|
68
|
-
// Always clean up
|
|
69
71
|
session.dispose();
|
|
70
72
|
```
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
## Source
|
|
75
|
+
|
|
76
|
+
- `src/tree-sitter.ts` — tool registration and action handling
|
|
77
|
+
- `src/runtime.ts` — parser and query runtime
|
|
78
|
+
- `src/session.ts` — reusable session API
|
|
79
|
+
- `src/outline.ts`, `src/imports.ts`, `src/exports.ts`, `src/node-at.ts`, `src/callees.ts` — structural analyses
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import type { Language, Parser, Tree } from "web-tree-sitter";
|
|
6
|
-
import { nodeToRange } from "
|
|
7
|
-
import { detectGrammar, resolveGrammarWasmPath } from "
|
|
8
|
-
import type { GrammarId, QueryCapture, TreeSitterResult } from "
|
|
6
|
+
import { nodeToRange } from "../coordinates.ts";
|
|
7
|
+
import { detectGrammar, resolveGrammarWasmPath } from "../language.ts";
|
|
8
|
+
import type { GrammarId, QueryCapture, TreeSitterResult } from "../types.ts";
|
|
9
9
|
|
|
10
10
|
interface ParserEntry {
|
|
11
11
|
parser: Parser;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// Session factory — creates a TreeSitterSession bound to a working directory.
|
|
2
2
|
|
|
3
|
-
import { detectGrammar, isJsTsGrammar } from "
|
|
4
|
-
import { TreeSitterRuntime } from "./runtime.ts";
|
|
3
|
+
import { detectGrammar, isJsTsGrammar } from "../language.ts";
|
|
5
4
|
import {
|
|
6
5
|
extractExports,
|
|
7
6
|
extractImports,
|
|
8
7
|
extractOutline,
|
|
9
8
|
lookupCalleesAt,
|
|
10
9
|
lookupNodeAt,
|
|
11
|
-
} from "
|
|
10
|
+
} from "../tool/structure.ts";
|
|
12
11
|
import type {
|
|
13
12
|
CalleesAtResult,
|
|
14
13
|
ExportRecord,
|
|
@@ -18,7 +17,8 @@ import type {
|
|
|
18
17
|
QueryCapture,
|
|
19
18
|
TreeSitterResult,
|
|
20
19
|
TreeSitterSession,
|
|
21
|
-
} from "
|
|
20
|
+
} from "../types.ts";
|
|
21
|
+
import { TreeSitterRuntime } from "./runtime.ts";
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Create a new Tree-sitter session bound to the given working directory.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Structural callee extraction — enclosing-scope lookup with per-language queries.
|
|
2
2
|
|
|
3
|
-
import { detectGrammar } from "
|
|
4
|
-
import type { TreeSitterRuntime } from "
|
|
5
|
-
import type { GrammarId, SourceRange, TreeSitterResult } from "
|
|
3
|
+
import { detectGrammar } from "../language.ts";
|
|
4
|
+
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
|
+
import type { GrammarId, SourceRange, TreeSitterResult } from "../types.ts";
|
|
6
6
|
|
|
7
7
|
/** Result shape returned by lookupCalleesAt. */
|
|
8
8
|
export interface CalleesAtResult {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Export extraction for supported files.
|
|
2
2
|
|
|
3
|
-
import { nodeToRange } from "
|
|
4
|
-
import type { TreeSitterRuntime } from "
|
|
5
|
-
import type { SyntaxNodeLike } from "
|
|
6
|
-
import type { ExportRecord, TreeSitterResult } from "
|
|
3
|
+
import { nodeToRange } from "../coordinates.ts";
|
|
4
|
+
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
|
+
import type { SyntaxNodeLike } from "../syntax-node.ts";
|
|
6
|
+
import type { ExportRecord, TreeSitterResult } from "../types.ts";
|
|
7
7
|
|
|
8
8
|
/** Extract export records from a supported file. */
|
|
9
9
|
export async function extractExports(
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Prompt guidance and tool description for the tree_sitter tool.
|
|
2
|
+
//
|
|
3
|
+
// Note: We intentionally do NOT include cross-tool routing (e.g., "use lsp for
|
|
4
|
+
// type info") because this package can be installed standalone without supi-lsp.
|
|
5
|
+
|
|
6
|
+
export const toolDescription = `Tree-sitter tool — parser-level structure and syntax queries for supported files.
|
|
7
|
+
|
|
8
|
+
Actions: outline, imports, exports, node_at, query, callees.
|
|
9
|
+
|
|
10
|
+
Use tree_sitter for exact syntax nodes, shallow structure, parsed imports/exports, outgoing calls, or custom AST queries within one file. file is required for all actions. line and character are 1-based UTF-16 coordinates for node_at and callees. query is required for query. outline, imports, and exports are JavaScript/TypeScript-only; node_at and query work across supported grammars; callees works for many grammars. Relative paths resolve from the session working directory.`;
|
|
11
|
+
|
|
12
|
+
export const promptGuidelines = [
|
|
13
|
+
"Use tree_sitter.outline(file), tree_sitter.imports(file), or tree_sitter.exports(file) for shallow JavaScript or TypeScript structure without reading the whole file.",
|
|
14
|
+
"Use tree_sitter.node_at(file, line, character) for the exact syntax node and ancestry at a known position.",
|
|
15
|
+
"Use tree_sitter.callees(file, line, character) for outgoing calls from the enclosing function or method at a known position.",
|
|
16
|
+
"Use tree_sitter.query(file, query) for custom Tree-sitter patterns when the built-in actions are not specific enough.",
|
|
17
|
+
"Use tree_sitter for syntax, node types, source ranges, and other parser-backed structure within one supported file.",
|
|
18
|
+
"Do not use tree_sitter for type information, cross-file references, semantic renames, or codebase-wide orientation.",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export const promptSnippet =
|
|
22
|
+
"tree_sitter — parser-backed single-file structure, node lookup, callees, and AST queries";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Import extraction for supported files.
|
|
2
2
|
|
|
3
|
-
import { nodeToRange } from "
|
|
4
|
-
import type { TreeSitterRuntime } from "
|
|
5
|
-
import type { SyntaxNodeLike } from "
|
|
6
|
-
import type { ImportRecord, TreeSitterResult } from "
|
|
3
|
+
import { nodeToRange } from "../coordinates.ts";
|
|
4
|
+
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
|
+
import type { SyntaxNodeLike } from "../syntax-node.ts";
|
|
6
|
+
import type { ImportRecord, TreeSitterResult } from "../types.ts";
|
|
7
7
|
|
|
8
8
|
/** Extract import records from a supported file. */
|
|
9
9
|
export async function extractImports(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Node-at-position lookup.
|
|
2
2
|
|
|
3
|
-
import { nodeToRange, publicToTreeSitter, splitSourceLines } from "
|
|
4
|
-
import type { TreeSitterRuntime } from "
|
|
5
|
-
import type { NodeAtResult, SourceRange, TreeSitterResult } from "
|
|
3
|
+
import { nodeToRange, publicToTreeSitter, splitSourceLines } from "../coordinates.ts";
|
|
4
|
+
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
|
+
import type { NodeAtResult, SourceRange, TreeSitterResult } from "../types.ts";
|
|
6
6
|
|
|
7
7
|
const MAX_ANCESTRY = 10;
|
|
8
8
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Outline extraction for supported files.
|
|
2
2
|
|
|
3
|
-
import { nodeToRange } from "
|
|
4
|
-
import type { SyntaxNodeLike } from "
|
|
5
|
-
import type { OutlineItem } from "
|
|
3
|
+
import { nodeToRange } from "../coordinates.ts";
|
|
4
|
+
import type { SyntaxNodeLike } from "../syntax-node.ts";
|
|
5
|
+
import type { OutlineItem } from "../types.ts";
|
|
6
6
|
|
|
7
7
|
/** Node types that can be extracted directly as outline items. */
|
|
8
8
|
const OUTLINE_DECLARATION_NODE_TYPES = new Set([
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
4
4
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
|
+
import { detectGrammar, isJsTsGrammar } from "./language.ts";
|
|
7
|
+
import { TreeSitterRuntime } from "./session/runtime.ts";
|
|
6
8
|
import {
|
|
7
9
|
formatNonSuccess,
|
|
8
10
|
formatOutlineItemsCapped,
|
|
@@ -11,11 +13,10 @@ import {
|
|
|
11
13
|
truncatedNotice,
|
|
12
14
|
truncateText,
|
|
13
15
|
validationError,
|
|
14
|
-
} from "./formatting.ts";
|
|
15
|
-
import {
|
|
16
|
-
import { collectOutline } from "./outline.ts";
|
|
17
|
-
import {
|
|
18
|
-
import { extractExports, extractImports, lookupCalleesAt, lookupNodeAt } from "./structure.ts";
|
|
16
|
+
} from "./tool/formatting.ts";
|
|
17
|
+
import { promptGuidelines, promptSnippet, toolDescription } from "./tool/guidance.ts";
|
|
18
|
+
import { collectOutline } from "./tool/outline.ts";
|
|
19
|
+
import { extractExports, extractImports, lookupCalleesAt, lookupNodeAt } from "./tool/structure.ts";
|
|
19
20
|
|
|
20
21
|
const TreeSitterActionEnum = StringEnum([
|
|
21
22
|
"outline",
|
|
@@ -26,30 +27,6 @@ const TreeSitterActionEnum = StringEnum([
|
|
|
26
27
|
"callees",
|
|
27
28
|
] as const);
|
|
28
29
|
|
|
29
|
-
const toolDescription = `Tree-sitter tool — provides structural AST analysis for supported files.
|
|
30
|
-
|
|
31
|
-
Actions:
|
|
32
|
-
- outline: Extract structural declarations (functions, classes, interfaces, etc.). JavaScript/TypeScript only.
|
|
33
|
-
- imports: List import statements with module specifiers. JavaScript/TypeScript only.
|
|
34
|
-
- exports: List export declarations, re-exports, and export assignments with names and kinds. JavaScript/TypeScript only.
|
|
35
|
-
- node_at: Find the syntax node at a position. Params: file, line, character
|
|
36
|
-
- query: Run a Tree-sitter query. Params: file, query
|
|
37
|
-
- callees: Find outgoing function/method calls from a position. Params: file, line, character. Supported for most grammars.
|
|
38
|
-
|
|
39
|
-
Coordinates are 1-based (line, character), compatible with the lsp tool convention.
|
|
40
|
-
Character is a UTF-16 code-unit column.
|
|
41
|
-
Relative file paths resolve from the session working directory.
|
|
42
|
-
|
|
43
|
-
Supported extensions: .ts, .tsx, .js, .jsx, .mts, .cts, .mjs, .cjs, .py, .pyi, .rs, .go, .mod, .c, .h, .cpp, .hpp, .cc, .cxx, .hxx, .c++, .h++, .java, .kt, .kts, .rb, .sh, .bash, .zsh, .html, .htm, .xhtml, .r, .sql`;
|
|
44
|
-
|
|
45
|
-
const promptGuidelines = [
|
|
46
|
-
"Use tree_sitter for structural syntax-tree analysis: extracting declarations, imports, exports, node-at-position lookup, and custom queries.",
|
|
47
|
-
"Prefer tree_sitter when you need AST node types, exact source ranges, or parser-level structure that semantic language-server tooling does not expose.",
|
|
48
|
-
"tree_sitter is a standalone structural analysis tool; use semantic language-server features separately when they are available for hover, definitions, references, or diagnostics.",
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
const promptSnippet = `Use the tree_sitter tool for structural code analysis — outline, imports, exports, node-at-position lookup, and custom queries.`;
|
|
52
|
-
|
|
53
30
|
export default function treeSitterExtension(pi: ExtensionAPI) {
|
|
54
31
|
let runtime: TreeSitterRuntime | undefined;
|
|
55
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-code-intelligence",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "SuPi Code Intelligence extension — architecture briefs, caller/callee analysis, impact assessment, and pattern search for pi",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"src/**/*.ts"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@mrclrchtr/supi-core": "1.
|
|
23
|
-
"@mrclrchtr/supi-
|
|
24
|
-
"@mrclrchtr/supi-
|
|
22
|
+
"@mrclrchtr/supi-core": "1.4.0",
|
|
23
|
+
"@mrclrchtr/supi-lsp": "1.4.0",
|
|
24
|
+
"@mrclrchtr/supi-tree-sitter": "1.4.0"
|
|
25
25
|
},
|
|
26
26
|
"bundledDependencies": [
|
|
27
27
|
"@mrclrchtr/supi-core",
|