@mrclrchtr/supi-code-intelligence 6.1.0 → 6.2.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 +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/debug-identity.ts +11 -0
- package/node_modules/@mrclrchtr/supi-core/src/debug.ts +5 -0
- package/node_modules/@mrclrchtr/supi-lsp/README.md +21 -3
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- 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/debug-identity.ts +11 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug.ts +5 -0
- package/node_modules/@mrclrchtr/supi-lsp/package.json +4 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +12 -7
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +0 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-publication.ts +6 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +2 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +5 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +2 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +17 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +40 -18
- package/node_modules/@mrclrchtr/supi-lsp/src/config/config.ts +164 -30
- package/node_modules/@mrclrchtr/supi-lsp/src/config/lsp-settings.ts +9 -87
- package/node_modules/@mrclrchtr/supi-lsp/src/config/server-config.ts +0 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-scope.ts +4 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/config/types.ts +0 -29
- package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +7 -21
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-severity.ts +6 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-summary.ts +11 -14
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +0 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/stale-diagnostics.ts +0 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sentinels.ts +29 -49
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +4 -8
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-helpers.ts +1 -9
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-project-info.ts +6 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +9 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +26 -41
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +275 -99
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +4 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +59 -28
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +27 -19
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +26 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registration.ts +0 -17
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +83 -19
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +5 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/session/scanner.ts +24 -21
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +29 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/summary.ts +19 -40
- package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +13 -19
- package/node_modules/@mrclrchtr/supi-lsp/src/workspace-path-policy.ts +287 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +6 -18
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-identity.ts +11 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug.ts +5 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +1 -11
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/coordinates.ts +19 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/language.ts +5 -23
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/operation-support.ts +3 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +5 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +10 -20
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +7 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +9 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +134 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-name.ts +96 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +11 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +39 -56
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +9 -7
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/js-binding-pattern.ts +26 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +2 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-html-sql.ts +144 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline.ts +50 -37
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/scope.ts +138 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +0 -7
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +1 -14
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +0 -10
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +6 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +34 -10
- package/package.json +5 -5
- package/src/analysis/capability/capability-warnings.ts +4 -22
- package/src/analysis/search/ast-scan-timing.ts +4 -2
- package/src/analysis/search/ast-scan.ts +1 -1
- package/src/api.ts +1 -0
- package/src/extension.ts +4 -2
- package/src/session/health-refresh.ts +24 -2
- package/src/session/health-types.ts +19 -0
- package/src/session/input/health-refactor.ts +16 -14
- package/src/session/refactor-types.ts +14 -1
- package/src/session/refactor-workflow.ts +21 -16
- package/src/substrate/lsp/lifecycle.ts +0 -3
- package/src/substrate/lsp/maintenance.ts +4 -5
- package/src/substrate/lsp/settings.ts +6 -9
- package/src/substrate/lsp/state.ts +0 -2
- package/src/substrate/workspace-provider-host.ts +2 -2
- package/src/tool/code_health/file-scope-markdown.ts +43 -0
- package/src/tool/code_health/markdown.ts +66 -66
- package/src/tool/code_health/refresh-outcome.ts +46 -0
- package/src/tool/code_health/refresh-status.ts +166 -23
- package/src/tool/code_health/result.ts +1 -0
- package/src/tool/code_health/tui.ts +18 -5
- package/src/tool/code_refactor_apply/guidance.ts +3 -2
- package/src/tool/code_refactor_plan/guidance.ts +1 -1
- package/src/tool/register.ts +5 -2
- package/src/tool/schemas.ts +21 -11
- package/node_modules/@mrclrchtr/supi-lsp/src/config/server-actions.ts +0 -59
- package/node_modules/@mrclrchtr/supi-lsp/src/pattern-matcher.ts +0 -24
- package/node_modules/@mrclrchtr/supi-tree-sitter/scripts/generate-kotlin-wasm.mjs +0 -132
- package/node_modules/@mrclrchtr/supi-tree-sitter/scripts/generate-sql-wasm.mjs +0 -158
- package/node_modules/@mrclrchtr/supi-tree-sitter/scripts/vendor-wasm.mjs +0 -167
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -42
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-registration.ts +0 -37
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/service-registry.ts +0 -30
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/structure.ts +0 -8
|
@@ -96,7 +96,10 @@ export function createLspSemanticProvider(lsp: WorkspaceLspRuntime): SemanticPro
|
|
|
96
96
|
): Promise<CodeQueryResult<CodeSymbol[]>> {
|
|
97
97
|
const result = await lsp.workspaceSymbol(query, control, scopes);
|
|
98
98
|
return mapCodeQueryResult(result, (results) =>
|
|
99
|
-
results.
|
|
99
|
+
results.flatMap((symbol) => {
|
|
100
|
+
const mapped = toCodeSymbol(symbol as SymbolInformation);
|
|
101
|
+
return mapped ? [mapped] : [];
|
|
102
|
+
}),
|
|
100
103
|
);
|
|
101
104
|
},
|
|
102
105
|
|
|
@@ -30,20 +30,34 @@ function toCodeLocation(item: Location | LocationLink): CodeLocation | null {
|
|
|
30
30
|
const loc = item as Record<string, unknown>;
|
|
31
31
|
const uri = loc.uri ?? loc.targetUri;
|
|
32
32
|
if (typeof uri !== "string") return null;
|
|
33
|
-
const range = loc.targetSelectionRange ?? loc.targetRange ?? loc.range;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
33
|
+
const range = toValidRange(loc.targetSelectionRange ?? loc.targetRange ?? loc.range);
|
|
34
|
+
return range ? { uri, range } : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function toValidRange(value: unknown): SourceRange | null {
|
|
38
|
+
if (!value || typeof value !== "object") return null;
|
|
39
|
+
const range = value as { start?: unknown; end?: unknown };
|
|
40
|
+
const start = toValidPosition(range.start);
|
|
41
|
+
const end = toValidPosition(range.end);
|
|
42
|
+
return start && end && !isPositionBefore(end, start) ? { start, end } : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function toValidPosition(value: unknown): { line: number; character: number } | null {
|
|
46
|
+
if (!value || typeof value !== "object") return null;
|
|
47
|
+
const position = value as Record<string, unknown>;
|
|
48
|
+
return Number.isInteger(position.line) &&
|
|
49
|
+
(position.line as number) >= 0 &&
|
|
50
|
+
Number.isInteger(position.character) &&
|
|
51
|
+
(position.character as number) >= 0
|
|
52
|
+
? { line: position.line as number, character: position.character as number }
|
|
53
|
+
: null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isPositionBefore(
|
|
57
|
+
left: { line: number; character: number },
|
|
58
|
+
right: { line: number; character: number },
|
|
59
|
+
): boolean {
|
|
60
|
+
return left.line < right.line || (left.line === right.line && left.character < right.character);
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
const SYMBOL_KIND_NAMES: Record<number, string> = {
|
|
@@ -102,8 +116,19 @@ function flattenDocumentSymbols(
|
|
|
102
116
|
let document: DocumentSymbol | null = null;
|
|
103
117
|
if (isSymbolInformation(sym)) information = sym;
|
|
104
118
|
else document = sym;
|
|
105
|
-
const
|
|
106
|
-
if (!
|
|
119
|
+
const declarationRange = toValidRange(document?.range ?? information?.location.range);
|
|
120
|
+
if (!declarationRange) {
|
|
121
|
+
if (document?.children?.length) {
|
|
122
|
+
result.push(
|
|
123
|
+
...flattenDocumentSymbols(document.children, filePath, sym.name, {
|
|
124
|
+
sourceLines: context.sourceLines,
|
|
125
|
+
nesting: "nested",
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const declStart = declarationRange.start;
|
|
107
132
|
const nameStart = document
|
|
108
133
|
? resolveDocumentSymbolNameStart(document, context.sourceLines)
|
|
109
134
|
: null;
|
|
@@ -149,8 +174,9 @@ function resolveDocumentSymbolNameStart(
|
|
|
149
174
|
symbol: DocumentSymbol,
|
|
150
175
|
sourceLines: readonly string[] | null,
|
|
151
176
|
): { line: number; character: number } | null {
|
|
152
|
-
const
|
|
153
|
-
if (!
|
|
177
|
+
const selectionRange = toValidRange(symbol.selectionRange);
|
|
178
|
+
if (!selectionRange) return null;
|
|
179
|
+
const selectionStart = selectionRange.start;
|
|
154
180
|
if (!sourceLines) return selectionStart;
|
|
155
181
|
const sourceLine = sourceLines[selectionStart.line];
|
|
156
182
|
if (sourceLine === undefined) return null;
|
|
@@ -160,25 +186,30 @@ function resolveDocumentSymbolNameStart(
|
|
|
160
186
|
) {
|
|
161
187
|
return selectionStart;
|
|
162
188
|
}
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
const from =
|
|
166
|
-
|
|
189
|
+
const declarationRange = toValidRange(symbol.range);
|
|
190
|
+
if (!declarationRange) return null;
|
|
191
|
+
const from =
|
|
192
|
+
declarationRange.start.line === selectionStart.line ? declarationRange.start.character : 0;
|
|
193
|
+
const until =
|
|
194
|
+
declarationRange.end.line === selectionStart.line
|
|
195
|
+
? declarationRange.end.character
|
|
196
|
+
: sourceLine.length;
|
|
167
197
|
const character = sourceLine.indexOf(symbol.name, from);
|
|
168
198
|
if (character < 0 || character + symbol.name.length > until) return null;
|
|
169
199
|
return { line: selectionStart.line, character };
|
|
170
200
|
}
|
|
171
201
|
|
|
172
|
-
/** Map one workspace symbol to the shared representation. */
|
|
173
|
-
export function toCodeSymbol(sym: SymbolInformation): CodeSymbol {
|
|
174
|
-
const
|
|
202
|
+
/** Map one valid workspace symbol to the shared representation. */
|
|
203
|
+
export function toCodeSymbol(sym: SymbolInformation): CodeSymbol | null {
|
|
204
|
+
const location = toCodeLocation(sym.location);
|
|
205
|
+
if (!location) return null;
|
|
175
206
|
return {
|
|
176
207
|
name: sym.name,
|
|
177
208
|
kind: symbolKindName(sym.kind),
|
|
178
|
-
file: uriToFile(
|
|
209
|
+
file: uriToFile(location.uri),
|
|
179
210
|
declarationAnchor: {
|
|
180
|
-
line: start
|
|
181
|
-
character: start
|
|
211
|
+
line: location.range.start.line + 1,
|
|
212
|
+
character: location.range.start.character + 1,
|
|
182
213
|
},
|
|
183
214
|
container: sym.containerName ?? null,
|
|
184
215
|
};
|
|
@@ -9,14 +9,19 @@
|
|
|
9
9
|
|
|
10
10
|
// biome-ignore lint/style/noExcessiveLinesPerFile: session lifecycle, capability projection, and telemetry stay in one controller.
|
|
11
11
|
import type { WorkspaceRuntime } from "@mrclrchtr/supi-code-runtime/api";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
recordDebugEvent,
|
|
14
|
+
truncateDebugIdentity as truncateIdentity,
|
|
15
|
+
} from "@mrclrchtr/supi-core/debug";
|
|
13
16
|
import { loadConfig } from "../config/config.ts";
|
|
14
17
|
import { type LspSettings, loadLspSettings } from "../config/lsp-settings.ts";
|
|
15
18
|
import { clearTsconfigCache } from "../config/tsconfig-scope.ts";
|
|
16
19
|
import type { DetectedProjectServer, LspConfig, ProjectServerInfo } from "../config/types.ts";
|
|
17
|
-
import { truncateIdentity } from "../debug-telemetry.ts";
|
|
18
|
-
import { scanWorkspaceSentinels } from "../diagnostics/workspace-sentinels.ts";
|
|
19
20
|
import { LspManager, type ManagerLifecycleTransition } from "../manager/manager.ts";
|
|
21
|
+
import {
|
|
22
|
+
type AutomaticLspPathPolicy,
|
|
23
|
+
createAutomaticLspPathPolicy,
|
|
24
|
+
} from "../workspace-path-policy.ts";
|
|
20
25
|
import {
|
|
21
26
|
markLspCapabilitiesReady,
|
|
22
27
|
registerPendingLspCapabilities,
|
|
@@ -58,6 +63,7 @@ interface LspControllerReady {
|
|
|
58
63
|
projectServers: ProjectServerInfo[];
|
|
59
64
|
detectedServers: DetectedProjectServer[];
|
|
60
65
|
settings: LspSettings;
|
|
66
|
+
automaticPathPolicy: AutomaticLspPathPolicy;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
interface LspControllerDisabled {
|
|
@@ -207,7 +213,6 @@ export class LspRuntimeController {
|
|
|
207
213
|
*
|
|
208
214
|
* Always attempts detected servers unless they were explicitly disabled
|
|
209
215
|
* per language via `lsp.servers.<language>.enabled: false`.
|
|
210
|
-
* The global `lsp.enabled` and `lsp.active` keys are deprecated and ignored.
|
|
211
216
|
*
|
|
212
217
|
* Returns the start result and updates the controller's state.
|
|
213
218
|
*/
|
|
@@ -220,11 +225,6 @@ export class LspRuntimeController {
|
|
|
220
225
|
if (generation !== this.#readinessGeneration) return supersededStartResult();
|
|
221
226
|
|
|
222
227
|
const lspSettings = loadLspSettings(this.#cwd);
|
|
223
|
-
// Note: lspSettings.enabled is ignored — the global switch is deprecated.
|
|
224
|
-
// Per-language `lsp.servers.<language>.enabled: false` is the supported
|
|
225
|
-
// way to opt out and is already handled by loadConfig.
|
|
226
|
-
// lspSettings.active is also ignored — the allowlist is deprecated.
|
|
227
|
-
|
|
228
228
|
const config = loadConfig(this.#cwd);
|
|
229
229
|
|
|
230
230
|
try {
|
|
@@ -287,27 +287,35 @@ export class LspRuntimeController {
|
|
|
287
287
|
if (Object.keys(config.servers).length === 0) return this.setDisabled(generation);
|
|
288
288
|
this.#state = { kind: "pending" };
|
|
289
289
|
|
|
290
|
+
const automaticPathPolicy = createAutomaticLspPathPolicy(this.#cwd, settings.exclude);
|
|
290
291
|
let manager: LspManager;
|
|
291
|
-
manager = new LspManager(
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
manager = new LspManager(
|
|
293
|
+
config,
|
|
294
|
+
this.#cwd,
|
|
295
|
+
(transition) => {
|
|
296
|
+
this.handleManagerLifecycle(manager, generation, transition);
|
|
297
|
+
},
|
|
298
|
+
automaticPathPolicy,
|
|
299
|
+
);
|
|
294
300
|
this.#activeManager = manager;
|
|
295
301
|
this.#latestManagerTransition = null;
|
|
296
302
|
this.publishLifecycle("startup", false, []);
|
|
297
|
-
manager.setExcludePatterns(settings.exclude);
|
|
298
303
|
setWorkspaceLspRuntimeState(this.#cwd, { kind: "pending" });
|
|
299
304
|
|
|
300
|
-
const detectedServers = scanProjectCapabilities(
|
|
305
|
+
const detectedServers = scanProjectCapabilities(
|
|
306
|
+
config,
|
|
307
|
+
this.#cwd,
|
|
308
|
+
undefined,
|
|
309
|
+
automaticPathPolicy,
|
|
310
|
+
);
|
|
301
311
|
manager.registerDetectedServers(detectedServers);
|
|
302
|
-
await startDetectedServers(manager, detectedServers);
|
|
312
|
+
await startDetectedServers(manager, detectedServers, automaticPathPolicy);
|
|
303
313
|
if (generation !== this.#readinessGeneration) {
|
|
304
314
|
if (this.#activeManager === manager) this.#activeManager = null;
|
|
305
315
|
await manager.shutdownAll();
|
|
306
316
|
return supersededStartResult();
|
|
307
317
|
}
|
|
308
318
|
|
|
309
|
-
scanWorkspaceSentinels(this.#cwd);
|
|
310
|
-
|
|
311
319
|
const runtimeOwner = createWorkspaceLspRuntimeOwner(manager);
|
|
312
320
|
const workspaceRuntime = runtimeOwner.runtime;
|
|
313
321
|
setWorkspaceLspRuntimeState(this.#cwd, { kind: "ready", runtime: workspaceRuntime });
|
|
@@ -333,6 +341,7 @@ export class LspRuntimeController {
|
|
|
333
341
|
projectServers,
|
|
334
342
|
detectedServers,
|
|
335
343
|
settings,
|
|
344
|
+
automaticPathPolicy,
|
|
336
345
|
};
|
|
337
346
|
|
|
338
347
|
this.projectSemanticReadiness(workspaceRuntime, semanticReady);
|
|
@@ -397,7 +406,6 @@ export class LspRuntimeController {
|
|
|
397
406
|
projectServers: projectServers.map((server) => ({
|
|
398
407
|
...server,
|
|
399
408
|
fileTypes: [...server.fileTypes],
|
|
400
|
-
supportedActions: [...server.supportedActions],
|
|
401
409
|
openFiles: [...server.openFiles],
|
|
402
410
|
})),
|
|
403
411
|
};
|
|
@@ -452,6 +460,6 @@ export class LspRuntimeController {
|
|
|
452
460
|
getMissingServers(): Array<{ name: string; command: string }> {
|
|
453
461
|
if (this.#state.kind !== "ready") return [];
|
|
454
462
|
const config = loadConfig(this.#cwd);
|
|
455
|
-
return scanMissingServers(config, this.#cwd);
|
|
463
|
+
return scanMissingServers(config, this.#cwd, undefined, this.#state.automaticPathPolicy);
|
|
456
464
|
}
|
|
457
465
|
}
|
|
@@ -45,11 +45,37 @@ export interface OutstandingDiagnosticSummaryEntry {
|
|
|
45
45
|
hints: number;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Outcome of explicit process-crash recovery demand in one diagnostic pass.
|
|
50
|
+
*
|
|
51
|
+
* Routes are counted rather than client generations because process-crash
|
|
52
|
+
* recovery owns one budget per LSP route. `attemptedRoutes` is the number of
|
|
53
|
+
* crashed routes selected by the demand; a route can be failed already or
|
|
54
|
+
* have a shared replacement in progress when the demand observes it.
|
|
55
|
+
*/
|
|
56
|
+
export interface ProcessCrashRecoverySummary {
|
|
57
|
+
attemptedRoutes: number;
|
|
58
|
+
recoveredRoutes: number;
|
|
59
|
+
failedRoutes: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Create the empty outcome for a pass with no process-crash demand. */
|
|
63
|
+
export function emptyProcessCrashRecoverySummary(): ProcessCrashRecoverySummary {
|
|
64
|
+
return {
|
|
65
|
+
attemptedRoutes: 0,
|
|
66
|
+
recoveredRoutes: 0,
|
|
67
|
+
failedRoutes: 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
48
71
|
/** Result from a workspace diagnostic recovery pass. */
|
|
49
72
|
export interface RecoverDiagnosticsResult {
|
|
50
73
|
/** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
|
|
51
74
|
attemptedClients: number;
|
|
75
|
+
/** Clients restarted by stale-diagnostic recovery, not process-crash recovery. */
|
|
52
76
|
restartedClients: number;
|
|
77
|
+
/** Separate outcome for process-crash route recovery selected by this pass. */
|
|
78
|
+
processCrashRecovery: ProcessCrashRecoverySummary;
|
|
53
79
|
/** Evidence collected by the refresh and recovery operations. */
|
|
54
80
|
diagnosticEvidence: DiagnosticEvidenceSummary;
|
|
55
81
|
/** Final diagnostic report captured after all refresh and recovery work. */
|
|
@@ -26,23 +26,6 @@ export function registerPendingLspCapabilities(
|
|
|
26
26
|
runtime.registerSemanticPending(cwd, provider);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
* Register LSP capabilities for a workspace cwd as ready.
|
|
31
|
-
*
|
|
32
|
-
* Wraps WorkspaceLspRuntime into a SemanticProvider via the existing semantic
|
|
33
|
-
* adapter and publishes it into the shared workspace runtime so that
|
|
34
|
-
* code-intelligence and other consumers can discover semantic analysis
|
|
35
|
-
* availability.
|
|
36
|
-
*/
|
|
37
|
-
export function registerLspCapabilities(
|
|
38
|
-
runtime: WorkspaceRuntime,
|
|
39
|
-
cwd: string,
|
|
40
|
-
service: WorkspaceLspRuntime,
|
|
41
|
-
): void {
|
|
42
|
-
const provider = createLspSemanticProvider(service);
|
|
43
|
-
runtime.registerSemantic(cwd, provider);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
29
|
/** Promote an already-registered pending semantic provider to ready. */
|
|
47
30
|
export function markLspCapabilitiesReady(runtime: WorkspaceRuntime, cwd: string): void {
|
|
48
31
|
runtime.markSemanticReady(cwd);
|
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
throwIfCodeRequestInterrupted,
|
|
10
10
|
unavailableCodeQuery,
|
|
11
11
|
} from "@mrclrchtr/supi-code-runtime/api";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
recordDebugEvent,
|
|
14
|
+
truncateDebugIdentity as truncateIdentity,
|
|
15
|
+
} from "@mrclrchtr/supi-core/debug";
|
|
16
|
+
import { resolveToolPath as resolveSessionPath } from "@mrclrchtr/supi-core/path";
|
|
13
17
|
import { createSessionStateRegistry } from "@mrclrchtr/supi-core/session";
|
|
14
18
|
import type {
|
|
15
19
|
CodeAction,
|
|
@@ -26,11 +30,18 @@ import type {
|
|
|
26
30
|
WorkspaceEdit,
|
|
27
31
|
WorkspaceSymbol,
|
|
28
32
|
} from "../config/types.ts";
|
|
29
|
-
import { boundServerNames
|
|
33
|
+
import { boundServerNames } from "../debug-telemetry.ts";
|
|
34
|
+
import type {
|
|
35
|
+
WorkspaceSentinelScanOptions,
|
|
36
|
+
WorkspaceSentinelSyncResult,
|
|
37
|
+
} from "../diagnostics/workspace-sentinels.ts";
|
|
30
38
|
import type { LspManager } from "../manager/manager.ts";
|
|
31
|
-
import { resolveSessionPath } from "../utils.ts";
|
|
32
39
|
import { raceReadinessValue } from "./readiness.ts";
|
|
33
|
-
import type {
|
|
40
|
+
import type {
|
|
41
|
+
DiagnosticEvidenceSummary,
|
|
42
|
+
ProcessCrashRecoverySummary,
|
|
43
|
+
RecoverDiagnosticsResult,
|
|
44
|
+
} from "./runtime-diagnostics.ts";
|
|
34
45
|
import type {
|
|
35
46
|
RoutedMutationResponse,
|
|
36
47
|
SemanticReadinessResult,
|
|
@@ -42,15 +53,17 @@ export type {
|
|
|
42
53
|
ProcessCrashDiagnosticDemand,
|
|
43
54
|
WorkspaceLspDiagnosticSurface,
|
|
44
55
|
} from "./runtime-diagnostic-surface.ts";
|
|
45
|
-
export
|
|
46
|
-
DiagnosticEvidenceDocument,
|
|
47
|
-
DiagnosticEvidenceStatus,
|
|
48
|
-
DiagnosticEvidenceSummary,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
export {
|
|
57
|
+
type DiagnosticEvidenceDocument,
|
|
58
|
+
type DiagnosticEvidenceStatus,
|
|
59
|
+
type DiagnosticEvidenceSummary,
|
|
60
|
+
emptyProcessCrashRecoverySummary,
|
|
61
|
+
type OutstandingDiagnosticSummaryEntry,
|
|
62
|
+
type ProcessCrashRecoverySummary,
|
|
63
|
+
type RecoverDiagnosticsResult,
|
|
64
|
+
type WorkspaceDiagnosticReport,
|
|
65
|
+
type WorkspaceDiagnosticSnapshot,
|
|
66
|
+
type WorkspaceDiagnosticSummaryEntry,
|
|
54
67
|
} from "./runtime-diagnostics.ts";
|
|
55
68
|
export type {
|
|
56
69
|
RoutedMutationResponse,
|
|
@@ -67,6 +80,29 @@ function unavailableFileQuery<T>(operation: string, file: string): CodeQueryResu
|
|
|
67
80
|
return unavailableCodeQuery(`No routed LSP client could complete ${operation} for ${file}.`);
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
function hasProcessCrashRecovery(summary: ProcessCrashRecoverySummary): boolean {
|
|
84
|
+
return summary.attemptedRoutes > 0 || summary.recoveredRoutes > 0 || summary.failedRoutes > 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Combine the eager and current state for one readiness wait.
|
|
89
|
+
* A current failure replaces the older pending view; max avoids double-counting
|
|
90
|
+
* one route when both views describe the same recovery attempt.
|
|
91
|
+
*/
|
|
92
|
+
function mergeProcessCrashRecoverySummaries(
|
|
93
|
+
eager: ProcessCrashRecoverySummary | undefined,
|
|
94
|
+
current: ProcessCrashRecoverySummary | null,
|
|
95
|
+
): ProcessCrashRecoverySummary | undefined {
|
|
96
|
+
if (!eager) return current ?? undefined;
|
|
97
|
+
if (!current) return eager;
|
|
98
|
+
if (current.failedRoutes > 0) return current;
|
|
99
|
+
return {
|
|
100
|
+
attemptedRoutes: Math.max(eager.attemptedRoutes, current.attemptedRoutes),
|
|
101
|
+
recoveredRoutes: Math.max(eager.recoveredRoutes, current.recoveredRoutes),
|
|
102
|
+
failedRoutes: Math.max(eager.failedRoutes, current.failedRoutes),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
70
106
|
/** Emit one aggregate tsconfig scope-decision event after a recovery pass. */
|
|
71
107
|
function recordScopeDecisionEvent(manager: LspManager): void {
|
|
72
108
|
try {
|
|
@@ -246,25 +282,39 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
246
282
|
): Promise<SemanticReadinessResult> {
|
|
247
283
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
248
284
|
if (!this.manager.canServeFile(resolvedPath)) {
|
|
285
|
+
const processCrashRecovery = this.manager.getProcessCrashRecoverySummaryForFile(resolvedPath);
|
|
249
286
|
return {
|
|
250
287
|
kind: "unavailable",
|
|
251
288
|
reason: "No LSP client can serve this file",
|
|
289
|
+
...(processCrashRecovery ? { processCrashRecovery } : {}),
|
|
252
290
|
};
|
|
253
291
|
}
|
|
254
292
|
|
|
293
|
+
let eagerProcessCrashRecovery: ProcessCrashRecoverySummary | undefined;
|
|
255
294
|
const readiness = await raceReadinessValue(
|
|
256
|
-
this.manager.waitUntilFileReady(resolvedPath, control)
|
|
295
|
+
this.manager.waitUntilFileReady(resolvedPath, control, (summary) => {
|
|
296
|
+
eagerProcessCrashRecovery = summary;
|
|
297
|
+
}),
|
|
257
298
|
options.timeoutMs,
|
|
258
299
|
control,
|
|
259
300
|
);
|
|
260
|
-
if (readiness.kind !== "resolved")
|
|
261
|
-
|
|
301
|
+
if (readiness.kind !== "resolved") {
|
|
302
|
+
const processCrashRecovery = mergeProcessCrashRecoverySummaries(
|
|
303
|
+
eagerProcessCrashRecovery,
|
|
304
|
+
this.manager.getProcessCrashRecoverySummaryForFile(resolvedPath),
|
|
305
|
+
);
|
|
306
|
+
return processCrashRecovery ? { ...readiness, processCrashRecovery } : readiness;
|
|
307
|
+
}
|
|
308
|
+
const { client, processCrashRecovery } = readiness.value;
|
|
309
|
+
const recovery = hasProcessCrashRecovery(processCrashRecovery) ? { processCrashRecovery } : {};
|
|
310
|
+
if (!client) {
|
|
262
311
|
return {
|
|
263
312
|
kind: "unavailable",
|
|
264
313
|
reason: "The routed LSP client could not be started for this file",
|
|
314
|
+
...recovery,
|
|
265
315
|
};
|
|
266
316
|
}
|
|
267
|
-
return { kind: "ready" };
|
|
317
|
+
return { kind: "ready", ...recovery };
|
|
268
318
|
}
|
|
269
319
|
|
|
270
320
|
/**
|
|
@@ -294,9 +344,22 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
294
344
|
return this.manager.getKnownProjectServers([]);
|
|
295
345
|
}
|
|
296
346
|
|
|
297
|
-
/** Check whether
|
|
347
|
+
/** Check whether automatic LSP work can use and serve the source file. */
|
|
298
348
|
isSupportedSourceFile(filePath: string): boolean {
|
|
299
|
-
return this.manager.
|
|
349
|
+
return this.manager.isSupportedSourceFile(this.resolveFilePath(filePath));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Inventory automatic workspace sentinel and source paths. */
|
|
353
|
+
scanWorkspaceSentinels(options: WorkspaceSentinelScanOptions = {}): Map<string, number> {
|
|
354
|
+
return this.manager.scanWorkspaceSentinels(options);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Refresh the automatic workspace sentinel and source inventory. */
|
|
358
|
+
syncWorkspaceSentinelSnapshot(
|
|
359
|
+
previous: Map<string, number>,
|
|
360
|
+
options: WorkspaceSentinelScanOptions = {},
|
|
361
|
+
): WorkspaceSentinelSyncResult {
|
|
362
|
+
return this.manager.syncWorkspaceSentinelSnapshot(previous, options);
|
|
300
363
|
}
|
|
301
364
|
|
|
302
365
|
/** Track a file in its routed client without exposing that client. */
|
|
@@ -389,6 +452,7 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
389
452
|
elapsedMs: result.elapsedMs,
|
|
390
453
|
attemptedClients: result.attemptedClients,
|
|
391
454
|
restartedClients: result.restartedClients,
|
|
455
|
+
processCrashRecovery: result.processCrashRecovery,
|
|
392
456
|
attemptedServers: boundServerNames(result.attemptedServers ?? []),
|
|
393
457
|
restartedServers: boundServerNames(result.restartedServers ?? []),
|
|
394
458
|
...(result.restartReason ? { reason: result.restartReason } : {}),
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
recordDebugEvent,
|
|
3
|
+
truncateDebugIdentity as truncateIdentity,
|
|
4
|
+
} from "@mrclrchtr/supi-core/debug";
|
|
2
5
|
import type { ProjectServerInfo } from "../config/types.ts";
|
|
3
|
-
import { MAX_SERVERS
|
|
6
|
+
import { MAX_SERVERS } from "../debug-telemetry.ts";
|
|
4
7
|
import type { LspRuntimeTransition } from "./runtime-controller.ts";
|
|
5
8
|
|
|
6
9
|
/** One bounded server entry in a runtime-transition payload. */
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { dedupeTopmostRoots
|
|
3
|
+
import { dedupeTopmostRoots } from "@mrclrchtr/supi-core/project";
|
|
4
4
|
import type {
|
|
5
5
|
DetectedProjectServer,
|
|
6
6
|
LspConfig,
|
|
7
7
|
MissingServer,
|
|
8
|
-
ProjectServerInfo,
|
|
9
8
|
ServerConfig,
|
|
10
9
|
} from "../config/types.ts";
|
|
11
10
|
import type { LspManager } from "../manager/manager.ts";
|
|
12
11
|
import { commandExists } from "../utils.ts";
|
|
12
|
+
import {
|
|
13
|
+
type AutomaticLspPathPolicy,
|
|
14
|
+
createDefaultAutomaticLspPathPolicy,
|
|
15
|
+
walkAutomaticLspTree,
|
|
16
|
+
} from "../workspace-path-policy.ts";
|
|
13
17
|
|
|
14
18
|
const DEFAULT_MAX_DEPTH = 3;
|
|
15
19
|
|
|
@@ -17,8 +21,14 @@ export function scanProjectCapabilities(
|
|
|
17
21
|
config: LspConfig,
|
|
18
22
|
cwd: string,
|
|
19
23
|
maxDepth: number = DEFAULT_MAX_DEPTH,
|
|
24
|
+
policy: AutomaticLspPathPolicy = createDefaultAutomaticLspPathPolicy(cwd),
|
|
20
25
|
): DetectedProjectServer[] {
|
|
21
|
-
const { markerMatches, extensionBasedServers } = collectServerHints(
|
|
26
|
+
const { markerMatches, extensionBasedServers } = collectServerHints(
|
|
27
|
+
config,
|
|
28
|
+
cwd,
|
|
29
|
+
maxDepth,
|
|
30
|
+
policy,
|
|
31
|
+
);
|
|
22
32
|
|
|
23
33
|
return Object.entries(config.servers)
|
|
24
34
|
.flatMap(([serverName, server]) => {
|
|
@@ -45,11 +55,12 @@ function collectServerHints(
|
|
|
45
55
|
config: LspConfig,
|
|
46
56
|
cwd: string,
|
|
47
57
|
maxDepth: number,
|
|
58
|
+
policy: AutomaticLspPathPolicy,
|
|
48
59
|
): { markerMatches: Map<string, Set<string>>; extensionBasedServers: Set<string> } {
|
|
49
60
|
const ctx: HintContext = { markerMatches: new Map(), extensionBasedServers: new Set() };
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
inspectDirectory(directory,
|
|
62
|
+
walkAutomaticLspTree(policy, cwd, maxDepth, (directory, entries) => {
|
|
63
|
+
inspectDirectory(directory, new Set(entries.map((entry) => entry.name)), config.servers, ctx);
|
|
53
64
|
});
|
|
54
65
|
|
|
55
66
|
return { markerMatches: ctx.markerMatches, extensionBasedServers: ctx.extensionBasedServers };
|
|
@@ -103,15 +114,10 @@ function hasMatchingFile(directory: string, entryNames: Set<string>, fileTypes:
|
|
|
103
114
|
export async function startDetectedServers(
|
|
104
115
|
manager: LspManager,
|
|
105
116
|
detected: DetectedProjectServer[],
|
|
117
|
+
policy: AutomaticLspPathPolicy = createDefaultAutomaticLspPathPolicy(manager.getCwd()),
|
|
106
118
|
): Promise<void> {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
export function introspectCapabilities(
|
|
111
|
-
manager: LspManager,
|
|
112
|
-
detected: DetectedProjectServer[],
|
|
113
|
-
): ProjectServerInfo[] {
|
|
114
|
-
return manager.getKnownProjectServers(detected);
|
|
119
|
+
const eligible = detected.filter((entry) => policy.isEligible(entry.root, "directory"));
|
|
120
|
+
await Promise.all(eligible.map((entry) => manager.startServerForRoot(entry.name, entry.root)));
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
/**
|
|
@@ -123,17 +129,14 @@ export function scanMissingServers(
|
|
|
123
129
|
config: LspConfig,
|
|
124
130
|
cwd: string,
|
|
125
131
|
maxDepth: number = DEFAULT_MAX_DEPTH,
|
|
132
|
+
policy: AutomaticLspPathPolicy = createDefaultAutomaticLspPathPolicy(cwd),
|
|
126
133
|
): MissingServer[] {
|
|
127
134
|
const foundExtensions = new Set<string>();
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
for (const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
} catch {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
const ext = path.extname(name).slice(1).toLowerCase();
|
|
136
|
+
walkAutomaticLspTree(policy, cwd, maxDepth, (_directory, entries) => {
|
|
137
|
+
for (const entry of entries) {
|
|
138
|
+
if (!entry.isFile() && !entry.isSymbolicLink()) continue;
|
|
139
|
+
const ext = path.extname(entry.name).slice(1).toLowerCase();
|
|
137
140
|
if (ext) foundExtensions.add(ext);
|
|
138
141
|
}
|
|
139
142
|
});
|
|
@@ -13,7 +13,12 @@ import type {
|
|
|
13
13
|
WorkspaceEdit,
|
|
14
14
|
WorkspaceSymbol,
|
|
15
15
|
} from "../config/types.ts";
|
|
16
|
+
import type {
|
|
17
|
+
WorkspaceSentinelScanOptions,
|
|
18
|
+
WorkspaceSentinelSyncResult,
|
|
19
|
+
} from "../diagnostics/workspace-sentinels.ts";
|
|
16
20
|
import type { WorkspaceLspDiagnosticSurface } from "./runtime-diagnostic-surface.ts";
|
|
21
|
+
import type { ProcessCrashRecoverySummary } from "./runtime-diagnostics.ts";
|
|
17
22
|
|
|
18
23
|
export type WorkspaceLspRuntimeState =
|
|
19
24
|
| { kind: "ready"; runtime: WorkspaceLspRuntime }
|
|
@@ -23,9 +28,22 @@ export type WorkspaceLspRuntimeState =
|
|
|
23
28
|
| { kind: "unavailable"; reason: string };
|
|
24
29
|
|
|
25
30
|
export type SemanticReadinessResult =
|
|
26
|
-
| {
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
| {
|
|
32
|
+
kind: "ready";
|
|
33
|
+
/** Process-crash route recovery observed while establishing file readiness. */
|
|
34
|
+
processCrashRecovery?: ProcessCrashRecoverySummary;
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
kind: "timeout";
|
|
38
|
+
/** Process-crash route recovery observed before the readiness timeout. */
|
|
39
|
+
processCrashRecovery?: ProcessCrashRecoverySummary;
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
kind: "unavailable";
|
|
43
|
+
reason: string;
|
|
44
|
+
/** Process-crash route recovery observed before readiness became unavailable. */
|
|
45
|
+
processCrashRecovery?: ProcessCrashRecoverySummary;
|
|
46
|
+
};
|
|
29
47
|
|
|
30
48
|
/** One mutation response and the exact provider roots from its semantic route. */
|
|
31
49
|
export interface RoutedMutationResponse<T> {
|
|
@@ -96,7 +114,15 @@ export interface WorkspaceLspRuntime extends WorkspaceLspDiagnosticSurface {
|
|
|
96
114
|
control?: CodeRequestControl,
|
|
97
115
|
): Promise<SemanticReadinessResult>;
|
|
98
116
|
getProjectServers(): ProjectServerInfo[];
|
|
117
|
+
/** Check whether automatic LSP work can use and serve the source file. */
|
|
99
118
|
isSupportedSourceFile(filePath: string): boolean;
|
|
119
|
+
/** Inventory policy-eligible workspace sentinels and optional source files. */
|
|
120
|
+
scanWorkspaceSentinels(options?: WorkspaceSentinelScanOptions): Map<string, number>;
|
|
121
|
+
/** Refresh one policy-eligible workspace sentinel and source inventory. */
|
|
122
|
+
syncWorkspaceSentinelSnapshot(
|
|
123
|
+
previous: Map<string, number>,
|
|
124
|
+
options?: WorkspaceSentinelScanOptions,
|
|
125
|
+
): WorkspaceSentinelSyncResult;
|
|
100
126
|
trackFile(filePath: string): Promise<boolean>;
|
|
101
127
|
closeFile(filePath: string): void;
|
|
102
128
|
pruneMissingFiles(): readonly string[];
|