@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,215 @@
|
|
|
1
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
2
|
+
import { startDebugTimer } from "@mrclrchtr/supi-core/debug";
|
|
3
|
+
import { boundCwd, truncateIdentity } from "../debug-telemetry.ts";
|
|
4
|
+
|
|
5
|
+
type DiagnosticCollection = "cache" | "fallback" | "none" | "pull" | "push";
|
|
6
|
+
type DiagnosticFreshness = "not-observed" | "observed";
|
|
7
|
+
type DiagnosticOutcome = "completed" | "incomplete" | "skipped" | "timed-out";
|
|
8
|
+
type DiagnosticPullOutcome = "completed" | "failed" | "not-supported" | "not-used" | "timed-out";
|
|
9
|
+
type DiagnosticPushOutcome = "not-used" | "published" | "released" | "settled" | "timed-out";
|
|
10
|
+
type DiagnosticSettleOutcome = "not-used" | "published" | "quiet" | "released" | "timed-out";
|
|
11
|
+
type DiagnosticTimingOperation = "refresh-open" | "sync-file";
|
|
12
|
+
|
|
13
|
+
/** Result of waiting for a quiet push-diagnostic window. */
|
|
14
|
+
export interface DiagnosticSettleResult {
|
|
15
|
+
readonly outcome: "quiet" | "released" | "timed-out";
|
|
16
|
+
readonly freshness: DiagnosticFreshness;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Result of waiting for one file's push diagnostics. */
|
|
20
|
+
export type DiagnosticPushWaitOutcome = "published" | "released" | "timed-out";
|
|
21
|
+
|
|
22
|
+
interface DiagnosticTimingData {
|
|
23
|
+
readonly collection: DiagnosticCollection;
|
|
24
|
+
readonly documentCount: number;
|
|
25
|
+
readonly fallback: boolean;
|
|
26
|
+
readonly freshness: DiagnosticFreshness;
|
|
27
|
+
readonly outcome: DiagnosticOutcome;
|
|
28
|
+
readonly pull: DiagnosticPullOutcome;
|
|
29
|
+
readonly push: DiagnosticPushOutcome;
|
|
30
|
+
readonly reopen: number;
|
|
31
|
+
readonly settle: DiagnosticSettleOutcome;
|
|
32
|
+
readonly timedOut: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Internal pull failure that retains timeout state and failed document URIs. */
|
|
36
|
+
export class DiagnosticPullError extends Error {
|
|
37
|
+
constructor(
|
|
38
|
+
readonly timedOut: boolean,
|
|
39
|
+
readonly failedUris: readonly string[] = [],
|
|
40
|
+
) {
|
|
41
|
+
super("pull diagnostics incomplete");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Bounded identity for one diagnostic timing observation. */
|
|
46
|
+
export interface DiagnosticTimingIdentity {
|
|
47
|
+
/** Configured server name. */
|
|
48
|
+
readonly server?: string;
|
|
49
|
+
/** Absolute workspace root. */
|
|
50
|
+
readonly cwd?: string;
|
|
51
|
+
/** Workspace-relative file path; sync-file operations only. */
|
|
52
|
+
readonly file?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Record one diagnostic operation without diagnostic text or document content.
|
|
57
|
+
*
|
|
58
|
+
* The observer owns result classification so diagnostic control flow does not
|
|
59
|
+
* duplicate the event shape. Identity is bounded and workspace-relative.
|
|
60
|
+
*/
|
|
61
|
+
export class DiagnosticObserver {
|
|
62
|
+
readonly #timer = startDebugTimer();
|
|
63
|
+
#pull: "failed" | "not-supported" | "timed-out";
|
|
64
|
+
#reopened = 0;
|
|
65
|
+
|
|
66
|
+
constructor(
|
|
67
|
+
readonly operation: DiagnosticTimingOperation,
|
|
68
|
+
readonly supportsPull: boolean,
|
|
69
|
+
readonly control?: CodeRequestControl,
|
|
70
|
+
readonly identity?: DiagnosticTimingIdentity,
|
|
71
|
+
) {
|
|
72
|
+
this.#pull = supportsPull ? "failed" : "not-supported";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
synchronized(): void {
|
|
76
|
+
this.#timer.mark("synchronize");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
skipped(documentCount: number): void {
|
|
80
|
+
this.#finish({
|
|
81
|
+
collection: "none",
|
|
82
|
+
documentCount,
|
|
83
|
+
fallback: false,
|
|
84
|
+
freshness: "not-observed",
|
|
85
|
+
outcome: "skipped",
|
|
86
|
+
pull: "not-used",
|
|
87
|
+
push: "not-used",
|
|
88
|
+
reopen: 0,
|
|
89
|
+
settle: "not-used",
|
|
90
|
+
timedOut: false,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
cacheReused(documentCount: number): void {
|
|
95
|
+
this.#finish({
|
|
96
|
+
collection: "cache",
|
|
97
|
+
documentCount,
|
|
98
|
+
fallback: false,
|
|
99
|
+
freshness: "observed",
|
|
100
|
+
outcome: "completed",
|
|
101
|
+
pull: "not-used",
|
|
102
|
+
push: "not-used",
|
|
103
|
+
reopen: 0,
|
|
104
|
+
settle: "not-used",
|
|
105
|
+
timedOut: false,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
pullCompleted(documentCount: number): void {
|
|
110
|
+
this.#finish(
|
|
111
|
+
{
|
|
112
|
+
collection: "pull",
|
|
113
|
+
documentCount,
|
|
114
|
+
fallback: false,
|
|
115
|
+
freshness: "observed",
|
|
116
|
+
outcome: "completed",
|
|
117
|
+
pull: "completed",
|
|
118
|
+
push: "not-used",
|
|
119
|
+
reopen: 0,
|
|
120
|
+
settle: "not-used",
|
|
121
|
+
timedOut: false,
|
|
122
|
+
},
|
|
123
|
+
"pull",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
pullFailed(error: unknown): void {
|
|
128
|
+
this.#pull = isDiagnosticTimeout(error) ? "timed-out" : "failed";
|
|
129
|
+
this.#timer.mark("pull");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
pullTimedOut(): void {
|
|
133
|
+
this.#pull = "timed-out";
|
|
134
|
+
this.#timer.mark("pull");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Record that the reopen-resync fallback re-opened unconfirmed documents. */
|
|
138
|
+
reopened(count: number): void {
|
|
139
|
+
this.#reopened += count;
|
|
140
|
+
this.#timer.mark("reopen");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
pushSettled(documentCount: number, settle: DiagnosticSettleResult): void {
|
|
144
|
+
const timedOut = settle.outcome === "timed-out";
|
|
145
|
+
const completed = settle.outcome === "quiet" && settle.freshness === "observed";
|
|
146
|
+
this.#finish(
|
|
147
|
+
{
|
|
148
|
+
collection: this.supportsPull ? "fallback" : "push",
|
|
149
|
+
documentCount,
|
|
150
|
+
fallback: this.supportsPull,
|
|
151
|
+
freshness: settle.freshness,
|
|
152
|
+
outcome: completed ? "completed" : timedOut ? "timed-out" : "incomplete",
|
|
153
|
+
pull: this.#pull,
|
|
154
|
+
push: timedOut ? "timed-out" : settle.outcome === "released" ? "released" : "settled",
|
|
155
|
+
reopen: this.#reopened,
|
|
156
|
+
settle: settle.outcome,
|
|
157
|
+
timedOut: timedOut || this.#pull === "timed-out",
|
|
158
|
+
},
|
|
159
|
+
"push-settle",
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
pushWaitCompleted(documentCount: number, push: DiagnosticPushWaitOutcome): void {
|
|
164
|
+
const timedOut = push === "timed-out";
|
|
165
|
+
this.#finish(
|
|
166
|
+
{
|
|
167
|
+
collection: this.supportsPull ? "fallback" : "push",
|
|
168
|
+
documentCount,
|
|
169
|
+
fallback: this.supportsPull,
|
|
170
|
+
freshness: push === "published" ? "observed" : "not-observed",
|
|
171
|
+
outcome: push === "published" ? "completed" : timedOut ? "timed-out" : "incomplete",
|
|
172
|
+
pull: this.#pull,
|
|
173
|
+
push,
|
|
174
|
+
reopen: this.#reopened,
|
|
175
|
+
settle: push,
|
|
176
|
+
timedOut: timedOut || this.#pull === "timed-out",
|
|
177
|
+
},
|
|
178
|
+
"push-settle",
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#finish(data: DiagnosticTimingData, finalPhase?: "pull" | "push-settle" | "synchronize"): void {
|
|
183
|
+
const { reopen, ...observation } = data;
|
|
184
|
+
this.#timer.finish(
|
|
185
|
+
() => ({
|
|
186
|
+
operationId: this.control?.operationId,
|
|
187
|
+
source: "lsp",
|
|
188
|
+
level: "debug",
|
|
189
|
+
category: "diagnostics.timing",
|
|
190
|
+
message: `LSP diagnostic ${this.operation} ${data.outcome}`,
|
|
191
|
+
cwd: boundCwd(this.identity?.cwd),
|
|
192
|
+
data: {
|
|
193
|
+
operation: this.operation,
|
|
194
|
+
...observation,
|
|
195
|
+
// Reopen fallback usage is recorded only when it happened; the
|
|
196
|
+
// default event shape stays stable for consumers of #322 telemetry.
|
|
197
|
+
...(reopen > 0 ? { reopen } : {}),
|
|
198
|
+
...(this.identity?.server !== undefined
|
|
199
|
+
? { server: truncateIdentity(this.identity.server) }
|
|
200
|
+
: {}),
|
|
201
|
+
...(this.identity?.file !== undefined
|
|
202
|
+
? { file: truncateIdentity(this.identity.file) }
|
|
203
|
+
: {}),
|
|
204
|
+
},
|
|
205
|
+
}),
|
|
206
|
+
finalPhase,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Return whether a diagnostic failure represents a timeout without retaining its message. */
|
|
212
|
+
export function isDiagnosticTimeout(error: unknown): boolean {
|
|
213
|
+
if (error instanceof DiagnosticPullError) return error.timedOut;
|
|
214
|
+
return error instanceof Error && /\btimed? ?out\b|\btimeout\b/i.test(error.message);
|
|
215
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CodeRequestControl,
|
|
3
|
+
CodeRequestDeadlineError,
|
|
4
|
+
throwIfCodeRequestInterrupted,
|
|
5
|
+
} from "@mrclrchtr/supi-code-runtime/api";
|
|
6
|
+
import type {
|
|
7
|
+
DiagnosticPushWaitOutcome,
|
|
8
|
+
DiagnosticSettleResult,
|
|
9
|
+
} from "./client-diagnostic-timing.ts";
|
|
10
|
+
|
|
11
|
+
type DiagnosticWaiter = (outcome: "published" | "released") => void;
|
|
12
|
+
|
|
13
|
+
/** One cancellable wait for diagnostic state change. */
|
|
14
|
+
export interface DiagnosticStateWait {
|
|
15
|
+
readonly promise: Promise<void>;
|
|
16
|
+
cancel(): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface DiagnosticSettleOptions {
|
|
20
|
+
readonly syncStart: number;
|
|
21
|
+
readonly maxWaitMs: number;
|
|
22
|
+
readonly quietMs: number;
|
|
23
|
+
readonly settleEpoch: number;
|
|
24
|
+
readonly isComplete: () => boolean;
|
|
25
|
+
readonly latestReceived: () => number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Own diagnostic waiters and their timers for one LSP client. */
|
|
29
|
+
export class DiagnosticWaitRegistry {
|
|
30
|
+
readonly #pushWaiters = new Map<string, DiagnosticWaiter[]>();
|
|
31
|
+
readonly #stateWaiters = new Set<() => void>();
|
|
32
|
+
readonly #settleWaiters = new Set<() => void>();
|
|
33
|
+
#settleEpoch = 0;
|
|
34
|
+
|
|
35
|
+
get settleEpoch(): number {
|
|
36
|
+
return this.#settleEpoch;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Wait for a diagnostic publication or a lifecycle release for one URI. */
|
|
40
|
+
waitForPush(
|
|
41
|
+
uri: string,
|
|
42
|
+
timeoutMs: number,
|
|
43
|
+
control?: CodeRequestControl,
|
|
44
|
+
): Promise<DiagnosticPushWaitOutcome> {
|
|
45
|
+
const deadlineRemaining =
|
|
46
|
+
control?.deadline === undefined ? undefined : control.deadline - Date.now();
|
|
47
|
+
const bindMs =
|
|
48
|
+
deadlineRemaining === undefined ? timeoutMs : Math.min(timeoutMs, deadlineRemaining);
|
|
49
|
+
if (control?.signal?.aborted) {
|
|
50
|
+
return Promise.reject(control.signal.reason ?? new Error("Diagnostic push wait cancelled"));
|
|
51
|
+
}
|
|
52
|
+
if (bindMs <= 0) {
|
|
53
|
+
if (deadlineRemaining !== undefined && deadlineRemaining < timeoutMs) {
|
|
54
|
+
return Promise.reject(new CodeRequestDeadlineError());
|
|
55
|
+
}
|
|
56
|
+
return Promise.resolve("timed-out");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return new Promise<DiagnosticPushWaitOutcome>((resolve, reject) => {
|
|
60
|
+
const cleanup = () => {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
if (abortHandler) control?.signal?.removeEventListener("abort", abortHandler);
|
|
63
|
+
};
|
|
64
|
+
const waiter: DiagnosticWaiter = (outcome) => {
|
|
65
|
+
cleanup();
|
|
66
|
+
this.#removePushWaiter(uri, waiter);
|
|
67
|
+
resolve(outcome);
|
|
68
|
+
};
|
|
69
|
+
const timer = setTimeout(() => {
|
|
70
|
+
this.#removePushWaiter(uri, waiter);
|
|
71
|
+
cleanup();
|
|
72
|
+
if (deadlineRemaining !== undefined && deadlineRemaining < timeoutMs) {
|
|
73
|
+
reject(new CodeRequestDeadlineError());
|
|
74
|
+
} else {
|
|
75
|
+
resolve("timed-out");
|
|
76
|
+
}
|
|
77
|
+
}, bindMs);
|
|
78
|
+
let abortHandler: (() => void) | undefined;
|
|
79
|
+
abortHandler = () => {
|
|
80
|
+
cleanup();
|
|
81
|
+
this.#removePushWaiter(uri, waiter);
|
|
82
|
+
reject(control?.signal?.reason ?? new Error("Diagnostic push wait cancelled"));
|
|
83
|
+
};
|
|
84
|
+
if (control?.signal?.aborted) abortHandler();
|
|
85
|
+
else control?.signal?.addEventListener("abort", abortHandler, { once: true });
|
|
86
|
+
const waiters = this.#pushWaiters.get(uri) ?? [];
|
|
87
|
+
waiters.push(waiter);
|
|
88
|
+
this.#pushWaiters.set(uri, waiters);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Wait until any diagnostic or lifecycle state changes. */
|
|
93
|
+
waitForChange(): DiagnosticStateWait {
|
|
94
|
+
let finish = () => {};
|
|
95
|
+
const promise = new Promise<void>((resolve) => {
|
|
96
|
+
finish = () => {
|
|
97
|
+
this.#stateWaiters.delete(finish);
|
|
98
|
+
resolve();
|
|
99
|
+
};
|
|
100
|
+
this.#stateWaiters.add(finish);
|
|
101
|
+
});
|
|
102
|
+
return { promise, cancel: finish };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Release pending push waiters for one URI. */
|
|
106
|
+
releaseFile(uri: string, outcome: "published" | "released" = "released"): void {
|
|
107
|
+
const waiters = this.#pushWaiters.get(uri);
|
|
108
|
+
if (waiters) {
|
|
109
|
+
this.#pushWaiters.delete(uri);
|
|
110
|
+
for (const waiter of waiters) waiter(outcome);
|
|
111
|
+
}
|
|
112
|
+
this.#notifyStateWaiters();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Release all pending push waiters. */
|
|
116
|
+
releaseAll(): void {
|
|
117
|
+
for (const uri of Array.from(this.#pushWaiters.keys())) this.releaseFile(uri);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Cancel the active settle generation and release its timers. */
|
|
121
|
+
cancelSettle(): void {
|
|
122
|
+
this.#settleEpoch++;
|
|
123
|
+
this.notifySettle();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Notify settle operations that diagnostic state changed. */
|
|
127
|
+
notifySettle(): void {
|
|
128
|
+
for (const release of Array.from(this.#settleWaiters)) release();
|
|
129
|
+
this.#notifyStateWaiters();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Wait for fresh diagnostic state to become quiet or reach its deadline. */
|
|
133
|
+
async waitForSettle(
|
|
134
|
+
options: DiagnosticSettleOptions,
|
|
135
|
+
control?: CodeRequestControl,
|
|
136
|
+
): Promise<DiagnosticSettleResult> {
|
|
137
|
+
const { syncStart, maxWaitMs, quietMs, settleEpoch, isComplete, latestReceived } = options;
|
|
138
|
+
const deadlineRemaining =
|
|
139
|
+
control?.deadline === undefined ? undefined : control.deadline - Date.now();
|
|
140
|
+
const deadline =
|
|
141
|
+
deadlineRemaining === undefined
|
|
142
|
+
? syncStart + maxWaitMs
|
|
143
|
+
: Math.min(syncStart + maxWaitMs, control?.deadline ?? syncStart + maxWaitMs);
|
|
144
|
+
while (Date.now() < deadline) {
|
|
145
|
+
throwIfCodeRequestInterrupted(control);
|
|
146
|
+
if (this.#settleEpoch !== settleEpoch) {
|
|
147
|
+
return { outcome: "released", freshness: "not-observed" };
|
|
148
|
+
}
|
|
149
|
+
const observedAt = latestReceived();
|
|
150
|
+
const elapsed = Date.now() - observedAt;
|
|
151
|
+
const complete = isComplete();
|
|
152
|
+
if (observedAt > 0 && complete && elapsed >= quietMs) {
|
|
153
|
+
return { outcome: "quiet", freshness: "observed" };
|
|
154
|
+
}
|
|
155
|
+
const waitMs =
|
|
156
|
+
observedAt > 0 && complete
|
|
157
|
+
? Math.min(quietMs - elapsed, deadline - Date.now())
|
|
158
|
+
: deadline - Date.now();
|
|
159
|
+
await this.#waitForStateChange(waitMs, control);
|
|
160
|
+
}
|
|
161
|
+
// A bound absolute deadline makes the settle outcome a deadline
|
|
162
|
+
// interruption instead of an ordinary relative timeout.
|
|
163
|
+
throwIfCodeRequestInterrupted(control);
|
|
164
|
+
return {
|
|
165
|
+
outcome: "timed-out",
|
|
166
|
+
freshness: latestReceived() > 0 ? "observed" : "not-observed",
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Wait until diagnostic state changes or the timeout expires. */
|
|
171
|
+
#waitForStateChange(timeoutMs: number, control?: CodeRequestControl): Promise<void> {
|
|
172
|
+
if (timeoutMs <= 0) return Promise.resolve();
|
|
173
|
+
if (control?.signal?.aborted) {
|
|
174
|
+
return Promise.reject(control.signal.reason ?? new Error("Settle wait cancelled"));
|
|
175
|
+
}
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
let abortHandler: (() => void) | undefined;
|
|
178
|
+
const finish = () => {
|
|
179
|
+
clearTimeout(timer);
|
|
180
|
+
if (abortHandler) control?.signal?.removeEventListener("abort", abortHandler);
|
|
181
|
+
this.#settleWaiters.delete(finish);
|
|
182
|
+
resolve();
|
|
183
|
+
};
|
|
184
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
185
|
+
abortHandler = () => {
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
this.#settleWaiters.delete(finish);
|
|
188
|
+
reject(control?.signal?.reason ?? new Error("Settle wait cancelled"));
|
|
189
|
+
};
|
|
190
|
+
control?.signal?.addEventListener("abort", abortHandler, { once: true });
|
|
191
|
+
this.#settleWaiters.add(finish);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
#notifyStateWaiters(): void {
|
|
196
|
+
for (const release of Array.from(this.#stateWaiters)) release();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#removePushWaiter(uri: string, waiter: DiagnosticWaiter): void {
|
|
200
|
+
const waiters = this.#pushWaiters.get(uri);
|
|
201
|
+
if (!waiters) return;
|
|
202
|
+
const next = waiters.filter((entry) => entry !== waiter);
|
|
203
|
+
if (next.length > 0) this.#pushWaiters.set(uri, next);
|
|
204
|
+
else this.#pushWaiters.delete(uri);
|
|
205
|
+
}
|
|
206
|
+
}
|