@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
package/node_modules/@mrclrchtr/supi-lsp/src/{service-registry.ts → session/service-registry.ts}
RENAMED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Peer extensions can import `getSessionLspService` from the package root
|
|
3
3
|
// to reuse the active LSP runtime without starting duplicate servers.
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import type { LspManager } from "./manager/manager.ts";
|
|
5
|
+
import { createSessionStateRegistry } from "@mrclrchtr/supi-core/api";
|
|
7
6
|
import type {
|
|
7
|
+
CodeAction,
|
|
8
8
|
Diagnostic,
|
|
9
9
|
DocumentSymbol,
|
|
10
10
|
Hover,
|
|
@@ -13,11 +13,43 @@ import type {
|
|
|
13
13
|
Position,
|
|
14
14
|
ProjectServerInfo,
|
|
15
15
|
SymbolInformation,
|
|
16
|
+
WorkspaceEdit,
|
|
16
17
|
WorkspaceSymbol,
|
|
17
|
-
} from "
|
|
18
|
+
} from "../config/types.ts";
|
|
19
|
+
import type { LspManager } from "../manager/manager.ts";
|
|
20
|
+
import { resolveSessionPath } from "../utils.ts";
|
|
21
|
+
|
|
22
|
+
/** Workspace diagnostic summary grouped by file. */
|
|
23
|
+
export interface WorkspaceDiagnosticSummaryEntry {
|
|
24
|
+
file: string;
|
|
25
|
+
errors: number;
|
|
26
|
+
warnings: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Outstanding diagnostics grouped by file, including info and hint counts. */
|
|
30
|
+
export interface OutstandingDiagnosticSummaryEntry {
|
|
31
|
+
file: string;
|
|
32
|
+
total: number;
|
|
33
|
+
errors: number;
|
|
34
|
+
warnings: number;
|
|
35
|
+
information: number;
|
|
36
|
+
hints: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Result from a workspace diagnostic recovery pass. */
|
|
40
|
+
export interface RecoverDiagnosticsResult {
|
|
41
|
+
refreshedClients: number;
|
|
42
|
+
restartedClients: number;
|
|
43
|
+
staleAssessment: {
|
|
44
|
+
suspected: boolean;
|
|
45
|
+
matchedFiles: Array<{ file: string; diagnostics: Diagnostic[] }>;
|
|
46
|
+
warning: string | null;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
18
49
|
|
|
19
50
|
export type SessionLspServiceState =
|
|
20
51
|
| { kind: "ready"; service: SessionLspService }
|
|
52
|
+
| { kind: "inactive"; service: SessionLspService }
|
|
21
53
|
| { kind: "pending" }
|
|
22
54
|
| { kind: "disabled" }
|
|
23
55
|
| { kind: "unavailable"; reason: string };
|
|
@@ -25,7 +57,9 @@ export type SessionLspServiceState =
|
|
|
25
57
|
/**
|
|
26
58
|
* Public wrapper around {@link LspManager} that exposes stable semantic operations.
|
|
27
59
|
* File path inputs may be absolute or session-cwd-relative; a leading `@` is stripped
|
|
28
|
-
* to match pi's built-in path-tool convention.
|
|
60
|
+
* to match pi's built-in path-tool convention. Position arguments use raw 0-based LSP
|
|
61
|
+
* coordinates; use `toLspPosition()` from `@mrclrchtr/supi-lsp/api` when starting from
|
|
62
|
+
* user-facing 1-based line and character values.
|
|
29
63
|
*/
|
|
30
64
|
export class SessionLspService {
|
|
31
65
|
constructor(private readonly manager: LspManager) {}
|
|
@@ -77,77 +111,119 @@ export class SessionLspService {
|
|
|
77
111
|
return this.manager.workspaceSymbol(query);
|
|
78
112
|
}
|
|
79
113
|
|
|
114
|
+
async rename(
|
|
115
|
+
filePath: string,
|
|
116
|
+
position: Position,
|
|
117
|
+
newName: string,
|
|
118
|
+
): Promise<WorkspaceEdit | null> {
|
|
119
|
+
const resolvedPath = this.resolveFilePath(filePath);
|
|
120
|
+
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
121
|
+
if (!client) return null;
|
|
122
|
+
return client.rename(resolvedPath, position, newName);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async codeActions(filePath: string, position: Position): Promise<CodeAction[] | null> {
|
|
126
|
+
const resolvedPath = this.resolveFilePath(filePath);
|
|
127
|
+
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
128
|
+
if (!client) return null;
|
|
129
|
+
|
|
130
|
+
const range = { start: position, end: position };
|
|
131
|
+
const diagnostics = client
|
|
132
|
+
.getDiagnostics(resolvedPath)
|
|
133
|
+
.filter((diagnostic) => diagnostic.range.start.line <= position.line)
|
|
134
|
+
.filter((diagnostic) => diagnostic.range.end.line >= position.line);
|
|
135
|
+
|
|
136
|
+
return client.codeActions(resolvedPath, range, { diagnostics });
|
|
137
|
+
}
|
|
138
|
+
|
|
80
139
|
// ── Project / runtime awareness ─────────────────────────────────────
|
|
81
140
|
|
|
82
141
|
getProjectServers(): ProjectServerInfo[] {
|
|
83
142
|
return this.manager.getKnownProjectServers([]);
|
|
84
143
|
}
|
|
85
144
|
|
|
145
|
+
/** Check whether the file can be served semantically for explicit LSP operations. */
|
|
86
146
|
isSupportedSourceFile(filePath: string): boolean {
|
|
87
|
-
return this.manager.
|
|
147
|
+
return this.manager.canServeFile(this.resolveFilePath(filePath));
|
|
88
148
|
}
|
|
89
149
|
|
|
90
150
|
// ── Diagnostics ─────────────────────────────────────────────────────
|
|
91
151
|
|
|
152
|
+
/** Sync a file through LSP and return diagnostics up to the supplied severity threshold. */
|
|
153
|
+
async fileDiagnostics(filePath: string, maxSeverity: number = 4): Promise<Diagnostic[] | null> {
|
|
154
|
+
const resolvedPath = this.resolveFilePath(filePath);
|
|
155
|
+
if (!this.manager.canServeFile(resolvedPath)) return null;
|
|
156
|
+
return this.manager.syncFileAndGetDiagnostics(resolvedPath, maxSeverity);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Get a lightweight workspace diagnostic summary for all tracked files. */
|
|
160
|
+
getWorkspaceDiagnosticSummary(): WorkspaceDiagnosticSummaryEntry[] {
|
|
161
|
+
return this.manager.getDiagnosticSummary();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Get outstanding diagnostics grouped by file at or above the supplied severity threshold. */
|
|
92
165
|
getOutstandingDiagnostics(
|
|
93
166
|
maxSeverity: number = 1,
|
|
94
167
|
): Array<{ file: string; diagnostics: Diagnostic[] }> {
|
|
95
168
|
return this.manager.getOutstandingDiagnostics(maxSeverity);
|
|
96
169
|
}
|
|
97
170
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
): import("./manager/manager-types.ts").OutstandingDiagnosticSummaryEntry[] {
|
|
171
|
+
/** Get outstanding diagnostic counts grouped by file. */
|
|
172
|
+
getOutstandingDiagnosticSummary(maxSeverity: number = 1): OutstandingDiagnosticSummaryEntry[] {
|
|
101
173
|
return this.manager.getOutstandingDiagnosticSummary(maxSeverity);
|
|
102
174
|
}
|
|
103
175
|
|
|
104
|
-
/**
|
|
105
|
-
|
|
106
|
-
|
|
176
|
+
/** Trigger a workspace-wide diagnostics refresh and stale-state recovery pass. */
|
|
177
|
+
async recoverDiagnostics(options?: {
|
|
178
|
+
restartIfStillStale?: boolean;
|
|
179
|
+
maxWaitMs?: number;
|
|
180
|
+
quietMs?: number;
|
|
181
|
+
}): Promise<RecoverDiagnosticsResult> {
|
|
182
|
+
return this.manager.recoverWorkspaceDiagnostics(options);
|
|
107
183
|
}
|
|
108
184
|
|
|
109
185
|
private resolveFilePath(filePath: string): string {
|
|
110
|
-
|
|
111
|
-
return path.resolve(this.manager.getCwd(), normalizedPath);
|
|
186
|
+
return resolveSessionPath(this.manager.getCwd(), filePath);
|
|
112
187
|
}
|
|
113
188
|
}
|
|
114
189
|
|
|
115
190
|
// ── Registry ──────────────────────────────────────────────────────────
|
|
116
191
|
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
function getRegistry(): Map<string, SessionLspServiceState> {
|
|
120
|
-
const globalScope = globalThis as typeof globalThis & Record<symbol, unknown>;
|
|
121
|
-
const existing = globalScope[REGISTRY_KEY];
|
|
122
|
-
if (existing instanceof Map) return existing as Map<string, SessionLspServiceState>;
|
|
123
|
-
|
|
124
|
-
const registry = new Map<string, SessionLspServiceState>();
|
|
125
|
-
globalScope[REGISTRY_KEY] = registry;
|
|
126
|
-
return registry;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function normalizeCwd(cwd: string): string {
|
|
130
|
-
return path.resolve(cwd);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const registry = getRegistry();
|
|
192
|
+
const WAIT_INTERVAL_MS = 25;
|
|
193
|
+
const registry = createSessionStateRegistry<SessionLspServiceState>("supi-lsp/session-registry");
|
|
134
194
|
|
|
135
195
|
/** Publish the LSP service state for a session cwd. */
|
|
136
196
|
export function setSessionLspServiceState(cwd: string, state: SessionLspServiceState): void {
|
|
137
|
-
registry.set(
|
|
197
|
+
registry.set(cwd, state);
|
|
138
198
|
}
|
|
139
199
|
|
|
140
200
|
/** Acquire the LSP service state for a session cwd. */
|
|
141
201
|
export function getSessionLspService(cwd: string): SessionLspServiceState {
|
|
142
202
|
return (
|
|
143
|
-
registry.get(
|
|
203
|
+
registry.get(cwd) ?? {
|
|
144
204
|
kind: "unavailable",
|
|
145
205
|
reason: "No LSP session initialized for this workspace",
|
|
146
206
|
}
|
|
147
207
|
);
|
|
148
208
|
}
|
|
149
209
|
|
|
210
|
+
/** Wait briefly for a pending session-scoped LSP service to become ready. */
|
|
211
|
+
export async function waitForSessionLspService(
|
|
212
|
+
cwd: string,
|
|
213
|
+
timeoutMs: number = 250,
|
|
214
|
+
): Promise<SessionLspServiceState> {
|
|
215
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
216
|
+
let state = getSessionLspService(cwd);
|
|
217
|
+
|
|
218
|
+
while (state.kind === "pending" && Date.now() < deadline) {
|
|
219
|
+
await new Promise((resolve) => setTimeout(resolve, WAIT_INTERVAL_MS));
|
|
220
|
+
state = getSessionLspService(cwd);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return state;
|
|
224
|
+
}
|
|
225
|
+
|
|
150
226
|
/** Remove the LSP service state for a session cwd. */
|
|
151
227
|
export function clearSessionLspService(cwd: string): void {
|
|
152
|
-
registry.
|
|
228
|
+
registry.clear(cwd);
|
|
153
229
|
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
loadSupiConfigForScope,
|
|
9
9
|
registerConfigSettings,
|
|
10
10
|
} from "@mrclrchtr/supi-core/api";
|
|
11
|
-
import { loadConfig } from "
|
|
11
|
+
import { loadConfig } from "../config/config.ts";
|
|
12
12
|
|
|
13
13
|
// ── Types ────────────────────────────────────────────────────
|
|
14
14
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// LSP tree navigation persistence — restores tool activation state across /tree navigation.
|
|
2
|
+
|
|
3
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import type { LspManager } from "../manager/manager.ts";
|
|
5
|
+
import { LSP_TOOL_NAMES } from "../tool/names.ts";
|
|
6
|
+
import { SessionLspService, setSessionLspServiceState } from "./service-registry.ts";
|
|
7
|
+
|
|
8
|
+
/** Shape of the entry persisted via `pi.appendEntry()`. */
|
|
9
|
+
export interface LspStateEntry {
|
|
10
|
+
active: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Restore LSP activation state from the current branch after /tree navigation. */
|
|
14
|
+
export function registerTreePersistHandlers(
|
|
15
|
+
pi: ExtensionAPI,
|
|
16
|
+
state: { lspActive: boolean; manager?: LspManager | null },
|
|
17
|
+
): void {
|
|
18
|
+
pi.on("session_tree", async (_event, ctx) => {
|
|
19
|
+
const branch = ctx.sessionManager.getBranch();
|
|
20
|
+
const isActive = findLastLspState(branch)?.active === true;
|
|
21
|
+
|
|
22
|
+
syncBranchToolActivation(pi, isActive);
|
|
23
|
+
syncBranchServiceState(state.manager, isActive);
|
|
24
|
+
state.lspActive = isActive;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function findLastLspState(branch: Array<{ type: string; customType?: string; data?: unknown }>) {
|
|
29
|
+
let lastEntry: LspStateEntry | undefined;
|
|
30
|
+
for (const entry of branch) {
|
|
31
|
+
if (entry.type === "custom" && entry.customType === "lsp-active") {
|
|
32
|
+
lastEntry = entry.data as LspStateEntry | undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return lastEntry;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function syncBranchToolActivation(pi: ExtensionAPI, isActive: boolean): void {
|
|
39
|
+
const activeTools = pi.getActiveTools();
|
|
40
|
+
if (isActive) {
|
|
41
|
+
const missing = LSP_TOOL_NAMES.filter((toolName) => !activeTools.includes(toolName));
|
|
42
|
+
if (missing.length > 0) {
|
|
43
|
+
pi.setActiveTools([...activeTools, ...missing]);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const nextTools = activeTools.filter(
|
|
49
|
+
(toolName) => !LSP_TOOL_NAMES.includes(toolName as (typeof LSP_TOOL_NAMES)[number]),
|
|
50
|
+
);
|
|
51
|
+
if (nextTools.length !== activeTools.length) {
|
|
52
|
+
pi.setActiveTools(nextTools);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function syncBranchServiceState(manager: LspManager | null | undefined, isActive: boolean): void {
|
|
57
|
+
if (!manager) return;
|
|
58
|
+
|
|
59
|
+
setSessionLspServiceState(manager.getCwd(), {
|
|
60
|
+
kind: isActive ? "ready" : "inactive",
|
|
61
|
+
service: new SessionLspService(manager),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Persist that LSP is active in the session tree. */
|
|
66
|
+
export function persistLspActiveState(pi: ExtensionAPI, state: { lspActive: boolean }): void {
|
|
67
|
+
state.lspActive = true;
|
|
68
|
+
pi.appendEntry<LspStateEntry>("lsp-active", { active: true });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Persist that LSP is inactive in the session tree. */
|
|
72
|
+
export function persistLspInactiveState(pi: ExtensionAPI, state: { lspActive: boolean }): void {
|
|
73
|
+
state.lspActive = false;
|
|
74
|
+
pi.appendEntry<LspStateEntry>("lsp-active", { active: false });
|
|
75
|
+
}
|
|
@@ -84,7 +84,7 @@ export function isPathRelevant(filePath: string, relevantPaths: string[], cwd: s
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
import { isFileExcludedByTsconfig } from "./tsconfig-scope.ts";
|
|
87
|
+
import { isFileExcludedByTsconfig } from "./config/tsconfig-scope.ts";
|
|
88
88
|
|
|
89
89
|
/** Check whether a file path is inside the project tree (within cwd, not node_modules/.pnpm/out-of-tree).
|
|
90
90
|
* Does NOT check tsconfig exclusion — use `shouldIgnoreLspPath` for diagnostics/guidance filtering. */
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Prompt guidance and tool descriptions for the expert LSP toolset.
|
|
2
|
+
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import type { ProjectServerInfo } from "../config/types.ts";
|
|
5
|
+
import { LSP_LOOKUP_TOOL, type LspToolName } from "./names.ts";
|
|
6
|
+
import { LSP_TOOL_DEFINITION_SPECS } from "./tool-specs.ts";
|
|
7
|
+
|
|
8
|
+
export interface LspToolPromptSurface {
|
|
9
|
+
description: string;
|
|
10
|
+
promptSnippet: string;
|
|
11
|
+
promptGuidelines: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type LspToolPromptSurfaceMap = Record<LspToolName, LspToolPromptSurface>;
|
|
15
|
+
|
|
16
|
+
export const defaultLspToolPromptSurfaces = buildLspToolPromptSurfaces([], ".");
|
|
17
|
+
|
|
18
|
+
export function buildLspToolPromptSurfaces(
|
|
19
|
+
servers: ProjectServerInfo[],
|
|
20
|
+
cwd: string,
|
|
21
|
+
): LspToolPromptSurfaceMap {
|
|
22
|
+
const coverageGuidelines = buildCoverageGuidelines(servers, cwd);
|
|
23
|
+
|
|
24
|
+
return Object.fromEntries(
|
|
25
|
+
LSP_TOOL_DEFINITION_SPECS.map((spec) => [
|
|
26
|
+
spec.name,
|
|
27
|
+
{
|
|
28
|
+
description: spec.description,
|
|
29
|
+
promptSnippet: spec.promptSnippet,
|
|
30
|
+
promptGuidelines:
|
|
31
|
+
"includeCoverageGuidelines" in spec && spec.includeCoverageGuidelines
|
|
32
|
+
? [...spec.basePromptGuidelines, ...coverageGuidelines]
|
|
33
|
+
: [...spec.basePromptGuidelines],
|
|
34
|
+
} satisfies LspToolPromptSurface,
|
|
35
|
+
]),
|
|
36
|
+
) as LspToolPromptSurfaceMap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildCoverageGuidelines(servers: ProjectServerInfo[], cwd: string): string[] {
|
|
40
|
+
const active = servers
|
|
41
|
+
.filter((server) => server.status === "running")
|
|
42
|
+
.map((server) => {
|
|
43
|
+
const root = displayRoot(server.root, cwd);
|
|
44
|
+
const fileTypes = server.fileTypes.map((entry) => `.${entry}`).join(",");
|
|
45
|
+
const actions = server.supportedActions.join(",");
|
|
46
|
+
const actionText = actions.length > 0 ? ` | actions: ${actions}` : "";
|
|
47
|
+
return `lsp server coverage: ${server.name} | root: ${root} | files: ${fileTypes}${actionText}`;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const unavailable = servers
|
|
51
|
+
.filter((server) => server.status !== "running")
|
|
52
|
+
.map((server) => server.name);
|
|
53
|
+
|
|
54
|
+
const dynamic = [...active];
|
|
55
|
+
if (unavailable.length > 0) {
|
|
56
|
+
dynamic.push(
|
|
57
|
+
`lsp server unavailable: ${unavailable.join(",")} — install or enable to extend semantic coverage`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return dynamic;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function displayRoot(root: string, cwd: string): string {
|
|
65
|
+
const relative = path.relative(cwd, root);
|
|
66
|
+
if (relative === "") return ".";
|
|
67
|
+
if (relative.startsWith(`..${path.sep}`) || relative === "..") return root;
|
|
68
|
+
return relative.replaceAll(path.sep, "/");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Compatibility exports for older internal tests and helper imports.
|
|
72
|
+
export const toolDescription = defaultLspToolPromptSurfaces[LSP_LOOKUP_TOOL].description;
|
|
73
|
+
export const promptSnippet = defaultLspToolPromptSurfaces[LSP_LOOKUP_TOOL].promptSnippet;
|
|
74
|
+
export const promptGuidelines = defaultLspToolPromptSurfaces[LSP_LOOKUP_TOOL].promptGuidelines;
|
|
75
|
+
|
|
76
|
+
export function buildProjectGuidelines(servers: ProjectServerInfo[], cwd: string): string[] {
|
|
77
|
+
return buildLspToolPromptSurfaces(servers, cwd)[LSP_LOOKUP_TOOL].promptGuidelines;
|
|
78
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Stable LSP tool names shared across registration, guidance, and runtime state.
|
|
2
|
+
|
|
3
|
+
export const LSP_LOOKUP_TOOL = "lsp_lookup";
|
|
4
|
+
export const LSP_DOCUMENT_SYMBOLS_TOOL = "lsp_document_symbols";
|
|
5
|
+
export const LSP_WORKSPACE_SYMBOLS_TOOL = "lsp_workspace_symbols";
|
|
6
|
+
export const LSP_DIAGNOSTICS_TOOL = "lsp_diagnostics";
|
|
7
|
+
export const LSP_REFACTOR_TOOL = "lsp_refactor";
|
|
8
|
+
export const LSP_RECOVER_TOOL = "lsp_recover";
|
|
9
|
+
|
|
10
|
+
export const LSP_TOOL_NAMES = [
|
|
11
|
+
LSP_LOOKUP_TOOL,
|
|
12
|
+
LSP_DOCUMENT_SYMBOLS_TOOL,
|
|
13
|
+
LSP_WORKSPACE_SYMBOLS_TOOL,
|
|
14
|
+
LSP_DIAGNOSTICS_TOOL,
|
|
15
|
+
LSP_REFACTOR_TOOL,
|
|
16
|
+
LSP_RECOVER_TOOL,
|
|
17
|
+
] as const;
|
|
18
|
+
|
|
19
|
+
export type LspToolName = (typeof LSP_TOOL_NAMES)[number];
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
AgentToolUpdateCallback,
|
|
3
|
+
EditToolInput,
|
|
4
|
+
ExtensionAPI,
|
|
5
|
+
ExtensionContext,
|
|
6
|
+
ReadToolInput,
|
|
7
|
+
WriteToolInput,
|
|
8
|
+
} from "@earendil-works/pi-coding-agent";
|
|
2
9
|
import { createEditTool, createReadTool, createWriteTool } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
10
|
+
import type { Diagnostic } from "../config/types.ts";
|
|
11
|
+
import { augmentDiagnostics } from "../diagnostics/diagnostic-augmentation.ts";
|
|
12
|
+
import { formatGroupedDiagnostics } from "../diagnostics/diagnostics.ts";
|
|
13
|
+
import { splitSuppressionDiagnostics } from "../diagnostics/suppression-diagnostics.ts";
|
|
14
|
+
import type { LspManager } from "../manager/manager.ts";
|
|
15
|
+
import { resolveSessionPath } from "../utils.ts";
|
|
8
16
|
|
|
9
17
|
interface LspOverrideState {
|
|
10
18
|
getInlineSeverity(): number;
|
|
11
19
|
getManager(): LspManager | null;
|
|
12
|
-
|
|
20
|
+
isActive(): boolean;
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
export function registerLspAwareToolOverrides(pi: ExtensionAPI, state: LspOverrideState): void {
|
|
@@ -20,11 +28,17 @@ export function registerLspAwareToolOverrides(pi: ExtensionAPI, state: LspOverri
|
|
|
20
28
|
pi.registerTool({
|
|
21
29
|
...readMeta,
|
|
22
30
|
// biome-ignore lint/complexity/useMaxParams: pi ToolDefinition.execute signature
|
|
23
|
-
async execute(
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
async execute(
|
|
32
|
+
toolCallId: string,
|
|
33
|
+
params: ReadToolInput,
|
|
34
|
+
signal: AbortSignal | undefined,
|
|
35
|
+
onUpdate: AgentToolUpdateCallback | undefined,
|
|
36
|
+
ctx: ExtensionContext,
|
|
37
|
+
) {
|
|
38
|
+
const originalRead = createReadTool(ctx.cwd);
|
|
26
39
|
const result = await originalRead.execute(toolCallId, params, signal, onUpdate);
|
|
27
|
-
|
|
40
|
+
if (!state.isActive()) return result;
|
|
41
|
+
await ensureFileOpen(state.getManager(), ctx.cwd, params.path);
|
|
28
42
|
return result;
|
|
29
43
|
},
|
|
30
44
|
});
|
|
@@ -32,15 +46,21 @@ export function registerLspAwareToolOverrides(pi: ExtensionAPI, state: LspOverri
|
|
|
32
46
|
pi.registerTool({
|
|
33
47
|
...writeMeta,
|
|
34
48
|
// biome-ignore lint/complexity/useMaxParams: pi ToolDefinition.execute signature
|
|
35
|
-
async execute(
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
async execute(
|
|
50
|
+
toolCallId: string,
|
|
51
|
+
params: WriteToolInput,
|
|
52
|
+
signal: AbortSignal | undefined,
|
|
53
|
+
onUpdate: AgentToolUpdateCallback | undefined,
|
|
54
|
+
ctx: ExtensionContext,
|
|
55
|
+
) {
|
|
56
|
+
const originalWrite = createWriteTool(ctx.cwd);
|
|
38
57
|
const result = await originalWrite.execute(toolCallId, params, signal, onUpdate);
|
|
58
|
+
if (!state.isActive()) return result;
|
|
39
59
|
return appendInlineDiagnostics({
|
|
40
60
|
manager: state.getManager(),
|
|
41
61
|
filePath: params.path,
|
|
42
62
|
inlineSeverity: state.getInlineSeverity(),
|
|
43
|
-
cwd,
|
|
63
|
+
cwd: ctx.cwd,
|
|
44
64
|
result,
|
|
45
65
|
});
|
|
46
66
|
},
|
|
@@ -49,15 +69,21 @@ export function registerLspAwareToolOverrides(pi: ExtensionAPI, state: LspOverri
|
|
|
49
69
|
pi.registerTool({
|
|
50
70
|
...editMeta,
|
|
51
71
|
// biome-ignore lint/complexity/useMaxParams: pi ToolDefinition.execute signature
|
|
52
|
-
async execute(
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
async execute(
|
|
73
|
+
toolCallId: string,
|
|
74
|
+
params: EditToolInput,
|
|
75
|
+
signal: AbortSignal | undefined,
|
|
76
|
+
onUpdate: AgentToolUpdateCallback | undefined,
|
|
77
|
+
ctx: ExtensionContext,
|
|
78
|
+
) {
|
|
79
|
+
const originalEdit = createEditTool(ctx.cwd);
|
|
55
80
|
const result = await originalEdit.execute(toolCallId, params, signal, onUpdate);
|
|
81
|
+
if (!state.isActive()) return result;
|
|
56
82
|
return appendInlineDiagnostics({
|
|
57
83
|
manager: state.getManager(),
|
|
58
84
|
filePath: params.path,
|
|
59
85
|
inlineSeverity: state.getInlineSeverity(),
|
|
60
|
-
cwd,
|
|
86
|
+
cwd: ctx.cwd,
|
|
61
87
|
result,
|
|
62
88
|
});
|
|
63
89
|
},
|
|
@@ -78,17 +104,18 @@ async function appendInlineDiagnostics<T extends { content: unknown[]; details:
|
|
|
78
104
|
if (!options.manager) return options.result;
|
|
79
105
|
|
|
80
106
|
try {
|
|
107
|
+
const resolvedFilePath = resolveSessionPath(options.cwd, options.filePath);
|
|
81
108
|
const effectiveSeverity = Math.max(options.inlineSeverity, 2);
|
|
82
109
|
const entries = await options.manager.syncFileAndGetCascadingDiagnostics(
|
|
83
|
-
|
|
110
|
+
resolvedFilePath,
|
|
84
111
|
effectiveSeverity,
|
|
85
112
|
);
|
|
86
113
|
if (entries.length === 0) return options.result;
|
|
87
114
|
|
|
88
115
|
const primaryDiagnostics =
|
|
89
|
-
entries.find((entry) => entry.file ===
|
|
116
|
+
entries.find((entry) => entry.file === resolvedFilePath)?.diagnostics ?? [];
|
|
90
117
|
const augmentation = await augmentDiagnostics(
|
|
91
|
-
|
|
118
|
+
resolvedFilePath,
|
|
92
119
|
splitSuppressionDiagnostics(primaryDiagnostics, options.inlineSeverity).regular,
|
|
93
120
|
options.manager,
|
|
94
121
|
options.cwd,
|
|
@@ -162,11 +189,15 @@ export function buildInlineDiagnosticsMessage(
|
|
|
162
189
|
return sections.join("\n\n");
|
|
163
190
|
}
|
|
164
191
|
|
|
165
|
-
async function ensureFileOpen(
|
|
192
|
+
async function ensureFileOpen(
|
|
193
|
+
manager: LspManager | null,
|
|
194
|
+
cwd: string,
|
|
195
|
+
filePath: string,
|
|
196
|
+
): Promise<void> {
|
|
166
197
|
if (!manager) return;
|
|
167
198
|
|
|
168
199
|
try {
|
|
169
|
-
await manager.ensureFileOpen(filePath);
|
|
200
|
+
await manager.ensureFileOpen(resolveSessionPath(cwd, filePath));
|
|
170
201
|
} catch {
|
|
171
202
|
// Never block the agent on LSP errors
|
|
172
203
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { getSessionLspService } from "../session/service-registry.ts";
|
|
3
|
+
import type { LspToolPromptSurfaceMap } from "./guidance.ts";
|
|
4
|
+
import { LSP_TOOL_DEFINITION_SPECS } from "./tool-specs.ts";
|
|
5
|
+
|
|
6
|
+
/** Register the expert LSP toolset. Tools are re-registered on session_start to refresh guidance. */
|
|
7
|
+
export function registerLspTools(pi: ExtensionAPI, promptSurfaces: LspToolPromptSurfaceMap): void {
|
|
8
|
+
for (const spec of LSP_TOOL_DEFINITION_SPECS) {
|
|
9
|
+
const surface = promptSurfaces[spec.name];
|
|
10
|
+
pi.registerTool({
|
|
11
|
+
name: spec.name,
|
|
12
|
+
label: spec.label,
|
|
13
|
+
description: surface.description,
|
|
14
|
+
promptSnippet: surface.promptSnippet,
|
|
15
|
+
promptGuidelines: surface.promptGuidelines,
|
|
16
|
+
parameters: spec.parameters,
|
|
17
|
+
execute: createToolExecutor(spec.run),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getReadyService(cwd: string) {
|
|
23
|
+
const state = getSessionLspService(cwd);
|
|
24
|
+
return state.kind === "ready" ? state.service : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function describeUnavailableService(cwd: string): string {
|
|
28
|
+
const state = getSessionLspService(cwd);
|
|
29
|
+
switch (state.kind) {
|
|
30
|
+
case "pending":
|
|
31
|
+
return "LSP is still starting for this workspace. Retry in a moment.";
|
|
32
|
+
case "inactive":
|
|
33
|
+
return `LSP is inactive on the current session branch for ${cwd}.`;
|
|
34
|
+
case "disabled":
|
|
35
|
+
return `LSP is disabled for ${cwd}.`;
|
|
36
|
+
case "unavailable":
|
|
37
|
+
return state.reason;
|
|
38
|
+
default:
|
|
39
|
+
return "LSP not initialized. Start a new session first.";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function createToolExecutor(
|
|
44
|
+
run: (
|
|
45
|
+
service: NonNullable<ReturnType<typeof getReadyService>>,
|
|
46
|
+
cwd: string,
|
|
47
|
+
params: unknown,
|
|
48
|
+
) => Promise<string>,
|
|
49
|
+
) {
|
|
50
|
+
// biome-ignore lint/complexity/useMaxParams: pi ToolDefinition.execute signature
|
|
51
|
+
return async (
|
|
52
|
+
_toolCallId: string,
|
|
53
|
+
params: unknown,
|
|
54
|
+
_signal: AbortSignal | undefined,
|
|
55
|
+
_onUpdate: unknown,
|
|
56
|
+
ctx: ExtensionContext,
|
|
57
|
+
) => {
|
|
58
|
+
const service = getReadyService(ctx.cwd);
|
|
59
|
+
const text = service
|
|
60
|
+
? await run(service, ctx.cwd, params)
|
|
61
|
+
: describeUnavailableService(ctx.cwd);
|
|
62
|
+
return makeTextResult(text);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function makeTextResult(text: string) {
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text" as const, text }],
|
|
69
|
+
details: {},
|
|
70
|
+
};
|
|
71
|
+
}
|