@mrclrchtr/supi-code-intelligence 4.9.0 → 5.0.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 +2 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
- package/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
- package/node_modules/@mrclrchtr/supi-core/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
- package/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
- package/node_modules/@mrclrchtr/supi-core/src/debug-timing.ts +34 -21
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
- package/node_modules/@mrclrchtr/supi-lsp/README.md +80 -5
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
- 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-code-runtime/src/api.ts +9 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +2 -0
- 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/config/config.ts +31 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-timing.ts +34 -21
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
- package/node_modules/@mrclrchtr/supi-lsp/package.json +7 -6
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +10 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +206 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +78 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +114 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +372 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +14 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +62 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +491 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +9 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +215 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +206 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +370 -266
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +52 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +185 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-file-state.ts +25 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +467 -115
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +238 -11
- package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +10 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/config/defaults.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +45 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +38 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +79 -9
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +13 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +300 -24
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +5 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +464 -96
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-refactor-provider.ts +130 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +45 -329
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/refactor-planning.ts +57 -120
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-edit-normalizer.ts +320 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +207 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/readiness.ts +72 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +151 -26
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +40 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +50 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +136 -120
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +49 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +102 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +26 -6
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
- 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-code-runtime/src/api.ts +9 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +2 -0
- 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/config/config.ts +31 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-timing.ts +34 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/LICENSE +21 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/README.md +258 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/babel.cjs +257 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/jiti.cjs +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-cli.mjs +34 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-hooks.mjs +124 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-native.mjs +121 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.d.mts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.mjs +4 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-static.mjs +23 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.cjs +30 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.cts +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.mts +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.mjs +29 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/types.d.ts +420 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/package.json +146 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm +0 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm.map +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm +0 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm.map +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +7 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/kotlin/tree-sitter-kotlin.wasm.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/sql/tree-sitter-sql.wasm.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +0 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +16 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +65 -87
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +47 -95
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-timing.ts +147 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client-lifecycle.ts +39 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +561 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-message-size.ts +24 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +452 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +4 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +12 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +4 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/imports.ts +4 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +5 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +33 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/blocking-test-bootstrap.mjs +34 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/bootstrap.mjs +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store-helpers.ts +23 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +400 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/request-control.ts +48 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-parser-helpers.ts +24 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-query-helpers.ts +43 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +421 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +116 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +201 -0
- package/package.json +5 -5
- package/src/analysis/health/diagnostics.ts +236 -24
- package/src/analysis/health/recovery.ts +6 -2
- package/src/analysis/provider.ts +58 -0
- package/src/analysis/readiness.ts +30 -9
- package/src/analysis/refactor/apply.ts +59 -20
- package/src/analysis/refactor/mutation-authority.ts +143 -0
- package/src/analysis/refactor/position.ts +47 -0
- package/src/analysis/refactor/safety.ts +18 -10
- package/src/analysis/relations/callees.ts +9 -1
- package/src/analysis/relations/types.ts +5 -2
- package/src/analysis/search/ast-scan-timing.ts +9 -4
- package/src/analysis/search/ast-scan.ts +1 -1
- package/src/analysis/search/deadline.ts +2 -2
- package/src/analysis/search/pattern-analysis.ts +46 -32
- package/src/analysis/search/pattern.ts +12 -2
- package/src/analysis/target/anchored.ts +20 -11
- package/src/analysis/target/file.ts +18 -11
- package/src/analysis/target/identity.ts +19 -3
- package/src/analysis/target/symbol.ts +36 -15
- package/src/api.ts +4 -0
- package/src/diagnostics/evidence.ts +51 -0
- package/src/session/capability-adapter.ts +12 -3
- package/src/session/find-workflow.ts +17 -7
- package/src/session/graph/collect.ts +18 -2
- package/src/session/graph-workflow.ts +19 -12
- package/src/session/health-refresh.ts +148 -0
- package/src/session/health-types.ts +37 -15
- package/src/session/health-workflow.ts +37 -39
- package/src/session/inspect/collect.ts +20 -3
- package/src/session/inspect-workflow.ts +10 -5
- package/src/session/orientation/collect.ts +10 -1
- package/src/session/orientation/context-facts.ts +3 -1
- package/src/session/orientation/context-sections.ts +20 -7
- package/src/session/orientation/gather.ts +17 -11
- package/src/session/orientation-types.ts +2 -1
- package/src/session/orientation-workflow.ts +15 -8
- package/src/session/refactor-plans.ts +2 -0
- package/src/session/refactor-workflow.ts +59 -14
- package/src/session/session.ts +4 -1
- package/src/session/target-workflow.ts +54 -23
- package/src/session/workflow-control.ts +7 -3
- package/src/substrate/lsp/lifecycle.ts +26 -46
- package/src/substrate/lsp/maintenance.ts +199 -25
- package/src/substrate/lsp/state.ts +2 -2
- package/src/substrate/workspace-provider-host.ts +25 -3
- package/src/tool/find/execute.ts +7 -1
- package/src/tool/find/render.ts +20 -3
- package/src/tool/find/tui.ts +23 -21
- package/src/tool/graph/execute.ts +23 -3
- package/src/tool/graph/tui.ts +59 -46
- package/src/tool/health/execute.ts +7 -2
- package/src/tool/health/markdown.ts +56 -14
- package/src/tool/health/refresh-status.ts +105 -0
- package/src/tool/health/tui.ts +95 -98
- package/src/tool/infra/workflow-control.ts +8 -0
- package/src/tool/inspect/execute.ts +7 -1
- package/src/tool/inspect/tui.ts +26 -18
- package/src/tool/orientation/execute.ts +21 -3
- package/src/tool/orientation/tui.ts +51 -35
- package/src/tool/refactor-apply/execute.ts +3 -0
- package/src/tool/refactor-apply/tui.ts +43 -25
- package/src/tool/refactor-plan/execute.ts +4 -0
- package/src/tool/refactor-plan/tui.ts +33 -20
- package/src/tool/register.ts +127 -22
- package/src/tool/resolve/execute.ts +18 -1
- package/src/tool/resolve/tui.ts +42 -24
- package/src/tool/result/display.ts +107 -0
- package/src/tool/result/errors.ts +20 -17
- package/src/tool/result/find.ts +52 -8
- package/src/tool/result/graph.ts +44 -1
- package/src/tool/result/health.ts +53 -1
- package/src/tool/result/inspect.ts +113 -1
- package/src/tool/result/orientation.ts +66 -14
- package/src/tool/result/refactor.ts +36 -4
- package/src/tool/result/resolve.ts +44 -7
- package/src/tool/result/types.ts +20 -0
- package/src/types/execution.ts +18 -5
- package/src/types/index.ts +8 -1
- package/src/ui/status-command.ts +5 -3
- package/src/ui/status-overlay.ts +4 -0
- package/src/ui/tui/common.ts +108 -10
- package/src/ui/tui/display.ts +48 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime.ts +0 -247
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Diagnostic } from "../config/types.ts";
|
|
2
|
+
import type { DiagnosticEvidenceSummary } from "../diagnostics/evidence.ts";
|
|
3
|
+
|
|
4
|
+
export type {
|
|
5
|
+
DiagnosticEvidenceDocument,
|
|
6
|
+
DiagnosticEvidenceStatus,
|
|
7
|
+
DiagnosticEvidenceSummary,
|
|
8
|
+
} from "../diagnostics/evidence.ts";
|
|
9
|
+
|
|
10
|
+
/** Workspace diagnostic snapshot with explicit cache freshness and coverage. */
|
|
11
|
+
export interface WorkspaceDiagnosticSnapshot<T> {
|
|
12
|
+
entries: T[];
|
|
13
|
+
current: boolean;
|
|
14
|
+
evidence: DiagnosticEvidenceSummary;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Workspace diagnostic summary grouped by file. */
|
|
18
|
+
export interface WorkspaceDiagnosticSummaryEntry {
|
|
19
|
+
file: string;
|
|
20
|
+
errors: number;
|
|
21
|
+
warnings: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Outstanding diagnostics grouped by file, including info and hint counts. */
|
|
25
|
+
export interface OutstandingDiagnosticSummaryEntry {
|
|
26
|
+
file: string;
|
|
27
|
+
total: number;
|
|
28
|
+
errors: number;
|
|
29
|
+
warnings: number;
|
|
30
|
+
information: number;
|
|
31
|
+
hints: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Result from a workspace diagnostic recovery pass. */
|
|
35
|
+
export interface RecoverDiagnosticsResult {
|
|
36
|
+
/** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
|
|
37
|
+
attemptedClients: number;
|
|
38
|
+
restartedClients: number;
|
|
39
|
+
/** Final document-level evidence from the last refresh in this recovery pass. */
|
|
40
|
+
diagnosticEvidence: DiagnosticEvidenceSummary;
|
|
41
|
+
/** Failure from the first refresh, when no later pass replaced it. */
|
|
42
|
+
refreshFailureReason?: string;
|
|
43
|
+
/** Wall-clock duration of the whole recovery pass, for telemetry. */
|
|
44
|
+
elapsedMs: number;
|
|
45
|
+
staleAssessment: {
|
|
46
|
+
suspected: boolean;
|
|
47
|
+
matchedFiles: Array<{ file: string; diagnostics: Diagnostic[] }>;
|
|
48
|
+
warning: string | null;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
// Shared session-scoped LSP service registry reused by peer extensions.
|
|
2
2
|
|
|
3
|
+
// biome-ignore lint/style/noExcessiveLinesPerFile: session registry, runtime recovery, and telemetry stay in one file; splitting would hide the recovery contract.
|
|
3
4
|
import {
|
|
4
5
|
type CodeQueryResult,
|
|
6
|
+
type CodeRequestControl,
|
|
7
|
+
isCodeRequestInterruption,
|
|
5
8
|
mapCodeQueryResult,
|
|
9
|
+
throwIfCodeRequestInterrupted,
|
|
6
10
|
unavailableCodeQuery,
|
|
7
11
|
} from "@mrclrchtr/supi-code-runtime/api";
|
|
12
|
+
import { recordDebugEvent } from "@mrclrchtr/supi-core/debug";
|
|
8
13
|
import { createSessionStateRegistry } from "@mrclrchtr/supi-core/session";
|
|
9
14
|
import type {
|
|
10
15
|
CodeAction,
|
|
@@ -21,9 +26,34 @@ import type {
|
|
|
21
26
|
WorkspaceEdit,
|
|
22
27
|
WorkspaceSymbol,
|
|
23
28
|
} from "../config/types.ts";
|
|
29
|
+
import { boundServerNames, truncateIdentity } from "../debug-telemetry.ts";
|
|
24
30
|
import type { LspManager } from "../manager/manager.ts";
|
|
25
31
|
import { resolveSessionPath } from "../utils.ts";
|
|
26
32
|
import { raceReadinessValue } from "./readiness.ts";
|
|
33
|
+
import type { DiagnosticEvidenceSummary, RecoverDiagnosticsResult } from "./runtime-diagnostics.ts";
|
|
34
|
+
import type {
|
|
35
|
+
RoutedMutationResponse,
|
|
36
|
+
SemanticReadinessResult,
|
|
37
|
+
WorkspaceLspRuntime,
|
|
38
|
+
WorkspaceLspRuntimeState,
|
|
39
|
+
} from "./workspace-lsp-runtime.ts";
|
|
40
|
+
|
|
41
|
+
export type { WorkspaceLspDiagnosticSurface } from "./runtime-diagnostic-surface.ts";
|
|
42
|
+
export type {
|
|
43
|
+
DiagnosticEvidenceDocument,
|
|
44
|
+
DiagnosticEvidenceStatus,
|
|
45
|
+
DiagnosticEvidenceSummary,
|
|
46
|
+
OutstandingDiagnosticSummaryEntry,
|
|
47
|
+
RecoverDiagnosticsResult,
|
|
48
|
+
WorkspaceDiagnosticSnapshot,
|
|
49
|
+
WorkspaceDiagnosticSummaryEntry,
|
|
50
|
+
} from "./runtime-diagnostics.ts";
|
|
51
|
+
export type {
|
|
52
|
+
RoutedMutationResponse,
|
|
53
|
+
SemanticReadinessResult,
|
|
54
|
+
WorkspaceLspRuntime,
|
|
55
|
+
WorkspaceLspRuntimeState,
|
|
56
|
+
} from "./workspace-lsp-runtime.ts";
|
|
27
57
|
|
|
28
58
|
function isRange(value: Position | Range): value is Range {
|
|
29
59
|
return "start" in value && "end" in value;
|
|
@@ -33,99 +63,6 @@ function unavailableFileQuery<T>(operation: string, file: string): CodeQueryResu
|
|
|
33
63
|
return unavailableCodeQuery(`No routed LSP client could complete ${operation} for ${file}.`);
|
|
34
64
|
}
|
|
35
65
|
|
|
36
|
-
/** Workspace diagnostic summary grouped by file. */
|
|
37
|
-
export interface WorkspaceDiagnosticSummaryEntry {
|
|
38
|
-
file: string;
|
|
39
|
-
errors: number;
|
|
40
|
-
warnings: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Outstanding diagnostics grouped by file, including info and hint counts. */
|
|
44
|
-
export interface OutstandingDiagnosticSummaryEntry {
|
|
45
|
-
file: string;
|
|
46
|
-
total: number;
|
|
47
|
-
errors: number;
|
|
48
|
-
warnings: number;
|
|
49
|
-
information: number;
|
|
50
|
-
hints: number;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Result from a workspace diagnostic recovery pass. */
|
|
54
|
-
export interface RecoverDiagnosticsResult {
|
|
55
|
-
/** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
|
|
56
|
-
attemptedClients: number;
|
|
57
|
-
restartedClients: number;
|
|
58
|
-
staleAssessment: {
|
|
59
|
-
suspected: boolean;
|
|
60
|
-
matchedFiles: Array<{ file: string; diagnostics: Diagnostic[] }>;
|
|
61
|
-
warning: string | null;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export type WorkspaceLspRuntimeState =
|
|
66
|
-
| { kind: "ready"; runtime: WorkspaceLspRuntime }
|
|
67
|
-
| { kind: "inactive"; runtime: WorkspaceLspRuntime }
|
|
68
|
-
| { kind: "pending" }
|
|
69
|
-
| { kind: "disabled" }
|
|
70
|
-
| { kind: "unavailable"; reason: string };
|
|
71
|
-
|
|
72
|
-
export type SemanticReadinessResult =
|
|
73
|
-
| { kind: "ready" }
|
|
74
|
-
| { kind: "timeout" }
|
|
75
|
-
| { kind: "unavailable"; reason: string };
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Workspace-scoped LSP interface that owns routing, readiness, semantic operations,
|
|
79
|
-
* diagnostics, and recovery without exposing clients or the mutable manager.
|
|
80
|
-
* File path inputs may be absolute or session-cwd-relative; a leading `@` is stripped
|
|
81
|
-
* to match pi's built-in path-tool convention. Position arguments use raw 0-based LSP
|
|
82
|
-
* coordinates; use `toLspPosition()` from `@mrclrchtr/supi-lsp/api` when starting from
|
|
83
|
-
* user-facing 1-based line and character values.
|
|
84
|
-
*/
|
|
85
|
-
export interface WorkspaceLspRuntime {
|
|
86
|
-
hover(filePath: string, position: Position): Promise<CodeQueryResult<Hover | null>>;
|
|
87
|
-
definition(
|
|
88
|
-
filePath: string,
|
|
89
|
-
position: Position,
|
|
90
|
-
): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>>;
|
|
91
|
-
references(filePath: string, position: Position): Promise<CodeQueryResult<Location[]>>;
|
|
92
|
-
implementation(
|
|
93
|
-
filePath: string,
|
|
94
|
-
position: Position,
|
|
95
|
-
): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>>;
|
|
96
|
-
documentSymbols(
|
|
97
|
-
filePath: string,
|
|
98
|
-
): Promise<CodeQueryResult<DocumentSymbol[] | SymbolInformation[]>>;
|
|
99
|
-
workspaceSymbol(query: string): Promise<CodeQueryResult<SymbolInformation[] | WorkspaceSymbol[]>>;
|
|
100
|
-
rename(filePath: string, position: Position, newName: string): Promise<WorkspaceEdit | null>;
|
|
101
|
-
codeActions(filePath: string, positionOrRange: Position | Range): Promise<CodeAction[] | null>;
|
|
102
|
-
/** Succeeds only when the concrete routed client exists and is query-ready. */
|
|
103
|
-
waitUntilReadyForFile(
|
|
104
|
-
filePath: string,
|
|
105
|
-
options?: { timeoutMs?: number },
|
|
106
|
-
): Promise<SemanticReadinessResult>;
|
|
107
|
-
/** Succeeds only when at least one concrete workspace client is active and query-ready. */
|
|
108
|
-
waitUntilReadyForWorkspace(options?: { timeoutMs?: number }): Promise<SemanticReadinessResult>;
|
|
109
|
-
getProjectServers(): ProjectServerInfo[];
|
|
110
|
-
isSupportedSourceFile(filePath: string): boolean;
|
|
111
|
-
trackFile(filePath: string): Promise<boolean>;
|
|
112
|
-
closeFile(filePath: string): void;
|
|
113
|
-
pruneMissingFiles(): readonly string[];
|
|
114
|
-
noteWorkspaceChanges(changes: FileEvent[]): void;
|
|
115
|
-
fileDiagnostics(filePath: string, maxSeverity?: number): Promise<CodeQueryResult<Diagnostic[]>>;
|
|
116
|
-
refreshOpenDiagnostics(options?: { maxWaitMs?: number; quietMs?: number }): Promise<void>;
|
|
117
|
-
getWorkspaceDiagnosticSummary(): WorkspaceDiagnosticSummaryEntry[];
|
|
118
|
-
getOutstandingDiagnostics(
|
|
119
|
-
maxSeverity?: number,
|
|
120
|
-
): Array<{ file: string; diagnostics: Diagnostic[] }>;
|
|
121
|
-
getOutstandingDiagnosticSummary(maxSeverity?: number): OutstandingDiagnosticSummaryEntry[];
|
|
122
|
-
recoverDiagnostics(options?: {
|
|
123
|
-
restartIfStillStale?: boolean;
|
|
124
|
-
maxWaitMs?: number;
|
|
125
|
-
quietMs?: number;
|
|
126
|
-
}): Promise<RecoverDiagnosticsResult>;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
66
|
class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
130
67
|
constructor(private readonly manager: LspManager) {}
|
|
131
68
|
|
|
@@ -136,29 +73,38 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
136
73
|
|
|
137
74
|
// ── Semantic lookups ────────────────────────────────────────────────
|
|
138
75
|
|
|
139
|
-
async hover(
|
|
76
|
+
async hover(
|
|
77
|
+
filePath: string,
|
|
78
|
+
position: Position,
|
|
79
|
+
control?: CodeRequestControl,
|
|
80
|
+
): Promise<CodeQueryResult<Hover | null>> {
|
|
140
81
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
141
82
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
142
83
|
if (!client) return unavailableFileQuery("hover", resolvedPath);
|
|
143
|
-
return client.hover(resolvedPath, position);
|
|
84
|
+
return client.hover(resolvedPath, position, control);
|
|
144
85
|
}
|
|
145
86
|
|
|
146
87
|
async definition(
|
|
147
88
|
filePath: string,
|
|
148
89
|
position: Position,
|
|
90
|
+
control?: CodeRequestControl,
|
|
149
91
|
): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>> {
|
|
150
92
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
151
93
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
152
94
|
if (!client) return unavailableFileQuery("definition", resolvedPath);
|
|
153
|
-
return client.definition(resolvedPath, position);
|
|
95
|
+
return client.definition(resolvedPath, position, control);
|
|
154
96
|
}
|
|
155
97
|
|
|
156
|
-
async references(
|
|
98
|
+
async references(
|
|
99
|
+
filePath: string,
|
|
100
|
+
position: Position,
|
|
101
|
+
control?: CodeRequestControl,
|
|
102
|
+
): Promise<CodeQueryResult<Location[]>> {
|
|
157
103
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
158
104
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
159
105
|
if (!client) return unavailableFileQuery("references", resolvedPath);
|
|
160
106
|
return mapCodeQueryResult(
|
|
161
|
-
await client.references(resolvedPath, position),
|
|
107
|
+
await client.references(resolvedPath, position, control),
|
|
162
108
|
(data) => data ?? [],
|
|
163
109
|
);
|
|
164
110
|
}
|
|
@@ -166,43 +112,58 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
166
112
|
async implementation(
|
|
167
113
|
filePath: string,
|
|
168
114
|
position: Position,
|
|
115
|
+
control?: CodeRequestControl,
|
|
169
116
|
): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>> {
|
|
170
117
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
171
118
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
172
119
|
if (!client) return unavailableFileQuery("implementation", resolvedPath);
|
|
173
|
-
return client.implementation(resolvedPath, position);
|
|
120
|
+
return client.implementation(resolvedPath, position, control);
|
|
174
121
|
}
|
|
175
122
|
|
|
176
123
|
async documentSymbols(
|
|
177
124
|
filePath: string,
|
|
125
|
+
control?: CodeRequestControl,
|
|
178
126
|
): Promise<CodeQueryResult<DocumentSymbol[] | SymbolInformation[]>> {
|
|
179
127
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
180
128
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
181
129
|
if (!client) return unavailableFileQuery("document symbols", resolvedPath);
|
|
182
|
-
return mapCodeQueryResult(
|
|
130
|
+
return mapCodeQueryResult(
|
|
131
|
+
await client.documentSymbols(resolvedPath, control),
|
|
132
|
+
(data) => data ?? [],
|
|
133
|
+
);
|
|
183
134
|
}
|
|
184
135
|
|
|
185
136
|
async workspaceSymbol(
|
|
186
137
|
query: string,
|
|
138
|
+
control?: CodeRequestControl,
|
|
187
139
|
): Promise<CodeQueryResult<SymbolInformation[] | WorkspaceSymbol[]>> {
|
|
188
|
-
return this.manager.workspaceSymbol(query);
|
|
140
|
+
return this.manager.workspaceSymbol(query, control);
|
|
189
141
|
}
|
|
190
142
|
|
|
191
143
|
async rename(
|
|
192
144
|
filePath: string,
|
|
193
145
|
position: Position,
|
|
194
146
|
newName: string,
|
|
195
|
-
|
|
147
|
+
control?: CodeRequestControl,
|
|
148
|
+
): Promise<RoutedMutationResponse<WorkspaceEdit | null> | null> {
|
|
196
149
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
197
150
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
198
151
|
if (!client) return null;
|
|
199
|
-
return
|
|
152
|
+
return {
|
|
153
|
+
value: await client.rename(resolvedPath, position, newName, control),
|
|
154
|
+
authorizedMutationRoots: [client.root],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
getOpenDocumentVersion(filePath: string): number | null {
|
|
159
|
+
return this.manager.getOpenDocumentVersion(this.resolveFilePath(filePath));
|
|
200
160
|
}
|
|
201
161
|
|
|
202
162
|
async codeActions(
|
|
203
163
|
filePath: string,
|
|
204
164
|
positionOrRange: Position | Range,
|
|
205
|
-
|
|
165
|
+
control?: CodeRequestControl,
|
|
166
|
+
): Promise<RoutedMutationResponse<CodeAction[] | null> | null> {
|
|
206
167
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
207
168
|
const client = await this.manager.ensureFileOpen(resolvedPath);
|
|
208
169
|
if (!client) return null;
|
|
@@ -215,7 +176,10 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
215
176
|
.filter((diagnostic) => diagnostic.range.end.line >= range.start.line)
|
|
216
177
|
.filter((diagnostic) => diagnostic.range.start.line <= range.end.line);
|
|
217
178
|
|
|
218
|
-
return
|
|
179
|
+
return {
|
|
180
|
+
value: await client.codeActions(resolvedPath, range, { diagnostics }, control),
|
|
181
|
+
authorizedMutationRoots: [client.root],
|
|
182
|
+
};
|
|
219
183
|
}
|
|
220
184
|
|
|
221
185
|
/**
|
|
@@ -225,6 +189,7 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
225
189
|
async waitUntilReadyForFile(
|
|
226
190
|
filePath: string,
|
|
227
191
|
options: { timeoutMs?: number } = {},
|
|
192
|
+
control?: CodeRequestControl,
|
|
228
193
|
): Promise<SemanticReadinessResult> {
|
|
229
194
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
230
195
|
if (!this.manager.canServeFile(resolvedPath)) {
|
|
@@ -235,8 +200,9 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
235
200
|
}
|
|
236
201
|
|
|
237
202
|
const readiness = await raceReadinessValue(
|
|
238
|
-
this.manager.waitUntilFileReady(resolvedPath),
|
|
203
|
+
this.manager.waitUntilFileReady(resolvedPath, control),
|
|
239
204
|
options.timeoutMs,
|
|
205
|
+
control,
|
|
240
206
|
);
|
|
241
207
|
if (readiness.kind !== "resolved") return readiness;
|
|
242
208
|
if (readiness.value === null) {
|
|
@@ -254,10 +220,12 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
254
220
|
*/
|
|
255
221
|
async waitUntilReadyForWorkspace(
|
|
256
222
|
options: { timeoutMs?: number } = {},
|
|
223
|
+
control?: CodeRequestControl,
|
|
257
224
|
): Promise<SemanticReadinessResult> {
|
|
258
225
|
const readiness = await raceReadinessValue(
|
|
259
|
-
this.manager.waitUntilWorkspaceReady(),
|
|
226
|
+
this.manager.waitUntilWorkspaceReady(control),
|
|
260
227
|
options.timeoutMs,
|
|
228
|
+
control,
|
|
261
229
|
);
|
|
262
230
|
if (readiness.kind !== "resolved") return readiness;
|
|
263
231
|
if (readiness.value === 0) {
|
|
@@ -297,7 +265,7 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
297
265
|
/** Notify routed clients of workspace file changes and reset pull state. */
|
|
298
266
|
noteWorkspaceChanges(changes: FileEvent[]): void {
|
|
299
267
|
this.manager.clearAllPullResultIds();
|
|
300
|
-
this.manager.
|
|
268
|
+
this.manager.noteWorkspaceChanges(changes);
|
|
301
269
|
}
|
|
302
270
|
|
|
303
271
|
async #shutdown(): Promise<void> {
|
|
@@ -310,34 +278,36 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
310
278
|
async fileDiagnostics(
|
|
311
279
|
filePath: string,
|
|
312
280
|
maxSeverity: number = 4,
|
|
281
|
+
control?: CodeRequestControl,
|
|
313
282
|
): Promise<CodeQueryResult<Diagnostic[]>> {
|
|
314
283
|
const resolvedPath = this.resolveFilePath(filePath);
|
|
315
284
|
if (!this.manager.canServeFile(resolvedPath)) {
|
|
316
285
|
return unavailableFileQuery("diagnostics", resolvedPath);
|
|
317
286
|
}
|
|
318
|
-
return this.manager.syncFileAndGetDiagnostics(resolvedPath, maxSeverity);
|
|
287
|
+
return this.manager.syncFileAndGetDiagnostics(resolvedPath, maxSeverity, control);
|
|
319
288
|
}
|
|
320
289
|
|
|
321
290
|
/** Re-sync every open document and wait for diagnostics to settle. */
|
|
322
|
-
async refreshOpenDiagnostics(
|
|
323
|
-
|
|
291
|
+
async refreshOpenDiagnostics(
|
|
292
|
+
options?: { maxWaitMs?: number; quietMs?: number },
|
|
293
|
+
control?: CodeRequestControl,
|
|
294
|
+
): Promise<DiagnosticEvidenceSummary> {
|
|
295
|
+
return this.manager.refreshOpenDiagnostics({ ...options, ...control });
|
|
324
296
|
}
|
|
325
297
|
|
|
326
298
|
/** Get a lightweight workspace diagnostic summary for all tracked files. */
|
|
327
|
-
getWorkspaceDiagnosticSummary()
|
|
328
|
-
return this.manager.
|
|
299
|
+
getWorkspaceDiagnosticSummary() {
|
|
300
|
+
return this.manager.getDiagnosticSnapshot();
|
|
329
301
|
}
|
|
330
302
|
|
|
331
303
|
/** Get outstanding diagnostics grouped by file at or above the supplied severity threshold. */
|
|
332
|
-
getOutstandingDiagnostics(
|
|
333
|
-
maxSeverity
|
|
334
|
-
): Array<{ file: string; diagnostics: Diagnostic[] }> {
|
|
335
|
-
return this.manager.getOutstandingDiagnostics(maxSeverity);
|
|
304
|
+
getOutstandingDiagnostics(maxSeverity: number = 1) {
|
|
305
|
+
return this.manager.getOutstandingDiagnosticsSnapshot(maxSeverity);
|
|
336
306
|
}
|
|
337
307
|
|
|
338
308
|
/** Get outstanding diagnostic counts grouped by file. */
|
|
339
|
-
getOutstandingDiagnosticSummary(maxSeverity: number = 1)
|
|
340
|
-
return this.manager.
|
|
309
|
+
getOutstandingDiagnosticSummary(maxSeverity: number = 1) {
|
|
310
|
+
return this.manager.getOutstandingDiagnosticSummarySnapshot(maxSeverity);
|
|
341
311
|
}
|
|
342
312
|
|
|
343
313
|
/** Trigger a workspace-wide diagnostics refresh and stale-state recovery pass. */
|
|
@@ -345,8 +315,50 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
|
|
|
345
315
|
restartIfStillStale?: boolean;
|
|
346
316
|
maxWaitMs?: number;
|
|
347
317
|
quietMs?: number;
|
|
318
|
+
control?: CodeRequestControl;
|
|
348
319
|
}): Promise<RecoverDiagnosticsResult> {
|
|
349
|
-
|
|
320
|
+
const recoveryStartedAt = Date.now();
|
|
321
|
+
try {
|
|
322
|
+
const result = await this.manager.recoverWorkspaceDiagnostics(options);
|
|
323
|
+
const outcome = result.refreshFailureReason ? "failed" : "completed";
|
|
324
|
+
recordDebugEvent({
|
|
325
|
+
source: "lsp",
|
|
326
|
+
level: "debug",
|
|
327
|
+
category: "runtime.recovery",
|
|
328
|
+
message: `LSP diagnostic recovery ${outcome}`,
|
|
329
|
+
cwd: truncateIdentity(this.manager.getCwd()),
|
|
330
|
+
data: {
|
|
331
|
+
outcome,
|
|
332
|
+
elapsedMs: result.elapsedMs,
|
|
333
|
+
attemptedClients: result.attemptedClients,
|
|
334
|
+
restartedClients: result.restartedClients,
|
|
335
|
+
attemptedServers: boundServerNames(result.attemptedServers ?? []),
|
|
336
|
+
restartedServers: boundServerNames(result.restartedServers ?? []),
|
|
337
|
+
...(result.restartReason ? { reason: result.restartReason } : {}),
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
return result;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
// A cancelled pass has no result object, so telemetry records the
|
|
343
|
+
// cancelled outcome, the elapsed time, and the server names that are
|
|
344
|
+
// still running at cancellation. Restart identity is unavailable
|
|
345
|
+
// because the pass produced no result.
|
|
346
|
+
if (isCodeRequestInterruption(error, options?.control)) {
|
|
347
|
+
recordDebugEvent({
|
|
348
|
+
source: "lsp",
|
|
349
|
+
level: "debug",
|
|
350
|
+
category: "runtime.recovery",
|
|
351
|
+
message: "LSP diagnostic recovery cancelled",
|
|
352
|
+
cwd: truncateIdentity(this.manager.getCwd()),
|
|
353
|
+
data: {
|
|
354
|
+
outcome: "cancelled",
|
|
355
|
+
elapsedMs: Date.now() - recoveryStartedAt,
|
|
356
|
+
attemptedServers: boundServerNames(this.manager.getRunningClientNames()),
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
350
362
|
}
|
|
351
363
|
|
|
352
364
|
private resolveFilePath(filePath: string): string {
|
|
@@ -380,15 +392,19 @@ export function getWorkspaceLspRuntime(cwd: string): WorkspaceLspRuntimeState {
|
|
|
380
392
|
export async function waitForWorkspaceLspRuntime(
|
|
381
393
|
cwd: string,
|
|
382
394
|
timeoutMs: number = 250,
|
|
395
|
+
control?: CodeRequestControl,
|
|
383
396
|
): Promise<WorkspaceLspRuntimeState> {
|
|
384
397
|
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
385
398
|
let state = getWorkspaceLspRuntime(cwd);
|
|
386
399
|
|
|
387
400
|
while (state.kind === "pending" && Date.now() < deadline) {
|
|
401
|
+
throwIfCodeRequestInterrupted(control);
|
|
388
402
|
await new Promise((resolve) => setTimeout(resolve, WAIT_INTERVAL_MS));
|
|
389
403
|
state = getWorkspaceLspRuntime(cwd);
|
|
390
404
|
}
|
|
391
405
|
|
|
406
|
+
// A cancelled poll must not hand a runtime to a caller that no longer awaits.
|
|
407
|
+
throwIfCodeRequestInterrupted(control);
|
|
392
408
|
return state;
|
|
393
409
|
}
|
|
394
410
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { recordDebugEvent } from "@mrclrchtr/supi-core/debug";
|
|
2
|
+
import type { ProjectServerInfo } from "../config/types.ts";
|
|
3
|
+
import { MAX_SERVERS, truncateIdentity } from "../debug-telemetry.ts";
|
|
4
|
+
import type { LspRuntimeTransition } from "./runtime-controller.ts";
|
|
5
|
+
|
|
6
|
+
/** One bounded server entry in a runtime-transition payload. */
|
|
7
|
+
export interface TransitionServerEntry {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly status: ProjectServerInfo["status"];
|
|
10
|
+
readonly ready: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Bound a project-server snapshot to MAX_SERVERS name/status/ready entries. */
|
|
14
|
+
function boundedServerEntries(
|
|
15
|
+
projectServers: readonly ProjectServerInfo[],
|
|
16
|
+
): TransitionServerEntry[] {
|
|
17
|
+
return projectServers.slice(0, MAX_SERVERS).map((server) => ({
|
|
18
|
+
name: truncateIdentity(server.name),
|
|
19
|
+
status: server.status,
|
|
20
|
+
ready: server.ready,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Record bounded aggregate telemetry for one runtime transition. */
|
|
25
|
+
export function recordLspRuntimeTransition(cwd: string, transition: LspRuntimeTransition): void {
|
|
26
|
+
const readyClients = transition.projectServers.filter(
|
|
27
|
+
(server) => server.status === "running" && server.ready,
|
|
28
|
+
).length;
|
|
29
|
+
const trackedFiles = transition.projectServers.reduce(
|
|
30
|
+
(count, server) => count + server.openFiles.length,
|
|
31
|
+
0,
|
|
32
|
+
);
|
|
33
|
+
recordDebugEvent({
|
|
34
|
+
source: "lsp",
|
|
35
|
+
level: transition.kind === "crash" ? "warning" : "debug",
|
|
36
|
+
category: "runtime.transition",
|
|
37
|
+
message: `LSP runtime transition: ${transition.kind}`,
|
|
38
|
+
cwd: truncateIdentity(cwd),
|
|
39
|
+
data: {
|
|
40
|
+
generation: transition.generation,
|
|
41
|
+
kind: transition.kind,
|
|
42
|
+
semanticReady: transition.semanticReady,
|
|
43
|
+
readyClients,
|
|
44
|
+
totalClients: transition.projectServers.length,
|
|
45
|
+
trackedFiles,
|
|
46
|
+
servers: boundedServerEntries(transition.projectServers),
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { CodeQueryResult, CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
2
|
+
import type {
|
|
3
|
+
CodeAction,
|
|
4
|
+
DocumentSymbol,
|
|
5
|
+
FileEvent,
|
|
6
|
+
Hover,
|
|
7
|
+
Location,
|
|
8
|
+
LocationLink,
|
|
9
|
+
Position,
|
|
10
|
+
ProjectServerInfo,
|
|
11
|
+
Range,
|
|
12
|
+
SymbolInformation,
|
|
13
|
+
WorkspaceEdit,
|
|
14
|
+
WorkspaceSymbol,
|
|
15
|
+
} from "../config/types.ts";
|
|
16
|
+
import type { WorkspaceLspDiagnosticSurface } from "./runtime-diagnostic-surface.ts";
|
|
17
|
+
|
|
18
|
+
export type WorkspaceLspRuntimeState =
|
|
19
|
+
| { kind: "ready"; runtime: WorkspaceLspRuntime }
|
|
20
|
+
| { kind: "inactive"; runtime: WorkspaceLspRuntime }
|
|
21
|
+
| { kind: "pending" }
|
|
22
|
+
| { kind: "disabled" }
|
|
23
|
+
| { kind: "unavailable"; reason: string };
|
|
24
|
+
|
|
25
|
+
export type SemanticReadinessResult =
|
|
26
|
+
| { kind: "ready" }
|
|
27
|
+
| { kind: "timeout" }
|
|
28
|
+
| { kind: "unavailable"; reason: string };
|
|
29
|
+
|
|
30
|
+
/** One mutation response and the exact provider roots from its semantic route. */
|
|
31
|
+
export interface RoutedMutationResponse<T> {
|
|
32
|
+
/** Provider response from the routed client. */
|
|
33
|
+
readonly value: T;
|
|
34
|
+
/** Roots that the routed client owns for this mutation response. */
|
|
35
|
+
readonly authorizedMutationRoots: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Workspace-scoped LSP interface that owns routing, readiness, semantic operations,
|
|
40
|
+
* diagnostics, and recovery without exposing clients or the mutable manager.
|
|
41
|
+
* File paths can be absolute or session-cwd-relative. A leading `@` is removed to
|
|
42
|
+
* match Pi's built-in path-tool convention. Positions use raw 0-based LSP coordinates.
|
|
43
|
+
* Provider request control is accepted
|
|
44
|
+
* as metadata only in this expansion and is not interpreted by the runtime.
|
|
45
|
+
*/
|
|
46
|
+
export interface WorkspaceLspRuntime extends WorkspaceLspDiagnosticSurface {
|
|
47
|
+
hover(
|
|
48
|
+
filePath: string,
|
|
49
|
+
position: Position,
|
|
50
|
+
control?: CodeRequestControl,
|
|
51
|
+
): Promise<CodeQueryResult<Hover | null>>;
|
|
52
|
+
definition(
|
|
53
|
+
filePath: string,
|
|
54
|
+
position: Position,
|
|
55
|
+
control?: CodeRequestControl,
|
|
56
|
+
): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>>;
|
|
57
|
+
references(
|
|
58
|
+
filePath: string,
|
|
59
|
+
position: Position,
|
|
60
|
+
control?: CodeRequestControl,
|
|
61
|
+
): Promise<CodeQueryResult<Location[]>>;
|
|
62
|
+
implementation(
|
|
63
|
+
filePath: string,
|
|
64
|
+
position: Position,
|
|
65
|
+
control?: CodeRequestControl,
|
|
66
|
+
): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>>;
|
|
67
|
+
documentSymbols(
|
|
68
|
+
filePath: string,
|
|
69
|
+
control?: CodeRequestControl,
|
|
70
|
+
): Promise<CodeQueryResult<DocumentSymbol[] | SymbolInformation[]>>;
|
|
71
|
+
workspaceSymbol(
|
|
72
|
+
query: string,
|
|
73
|
+
control?: CodeRequestControl,
|
|
74
|
+
): Promise<CodeQueryResult<SymbolInformation[] | WorkspaceSymbol[]>>;
|
|
75
|
+
rename(
|
|
76
|
+
filePath: string,
|
|
77
|
+
position: Position,
|
|
78
|
+
newName: string,
|
|
79
|
+
control?: CodeRequestControl,
|
|
80
|
+
): Promise<RoutedMutationResponse<WorkspaceEdit | null> | null>;
|
|
81
|
+
codeActions(
|
|
82
|
+
filePath: string,
|
|
83
|
+
positionOrRange: Position | Range,
|
|
84
|
+
control?: CodeRequestControl,
|
|
85
|
+
): Promise<RoutedMutationResponse<CodeAction[] | null> | null>;
|
|
86
|
+
getOpenDocumentVersion(filePath: string): number | null;
|
|
87
|
+
waitUntilReadyForFile(
|
|
88
|
+
filePath: string,
|
|
89
|
+
options?: { timeoutMs?: number },
|
|
90
|
+
control?: CodeRequestControl,
|
|
91
|
+
): Promise<SemanticReadinessResult>;
|
|
92
|
+
waitUntilReadyForWorkspace(
|
|
93
|
+
options?: { timeoutMs?: number },
|
|
94
|
+
control?: CodeRequestControl,
|
|
95
|
+
): Promise<SemanticReadinessResult>;
|
|
96
|
+
getProjectServers(): ProjectServerInfo[];
|
|
97
|
+
isSupportedSourceFile(filePath: string): boolean;
|
|
98
|
+
trackFile(filePath: string): Promise<boolean>;
|
|
99
|
+
closeFile(filePath: string): void;
|
|
100
|
+
pruneMissingFiles(): readonly string[];
|
|
101
|
+
noteWorkspaceChanges(changes: FileEvent[]): void;
|
|
102
|
+
}
|