@mrclrchtr/supi-code-intelligence 4.10.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/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/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 +71 -11
- 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 +365 -297
- 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 +161 -33
- 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 +17 -7
- 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/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/package.json +6 -3
- 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 +45 -1
- package/src/analysis/refactor/mutation-authority.ts +143 -0
- 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 -2
- 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 -351
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
// biome-ignore-all lint/style/noExcessiveLinesPerFile: one private protocol module defines and validates the full closed contract
|
|
2
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
3
|
+
import { isDebugOperationId } from "@mrclrchtr/supi-core/debug";
|
|
4
|
+
import type { TreeSitterResult } from "../types.ts";
|
|
5
|
+
import type { StructuralTimingEvent } from "./structural-timing.ts";
|
|
6
|
+
|
|
7
|
+
/** Version of the private parent/Structural Worker message contract. */
|
|
8
|
+
export const STRUCTURAL_WORKER_PROTOCOL_VERSION = 1 as const;
|
|
9
|
+
|
|
10
|
+
/** Fixed internal bounds for one Structural Worker lifecycle. */
|
|
11
|
+
export const STRUCTURAL_WORKER_LIMITS = Object.freeze({
|
|
12
|
+
maxQueuedRequests: 32,
|
|
13
|
+
maxMessageBytes: 512 * 1024,
|
|
14
|
+
targetChunkBytes: 256 * 1024,
|
|
15
|
+
maxResultBytes: 16 * 1024 * 1024,
|
|
16
|
+
maxAtomicValueBytes: 256 * 1024,
|
|
17
|
+
hardStopGraceMs: 250,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type StructuralWorkerOperation =
|
|
21
|
+
| { readonly operation: "canParse"; readonly file: string }
|
|
22
|
+
| { readonly operation: "query"; readonly file: string; readonly query: string }
|
|
23
|
+
| {
|
|
24
|
+
readonly operation: "outline" | "imports" | "exports" | "callSites";
|
|
25
|
+
readonly file: string;
|
|
26
|
+
}
|
|
27
|
+
| {
|
|
28
|
+
readonly operation: "nodeAt";
|
|
29
|
+
readonly file: string;
|
|
30
|
+
readonly line: number;
|
|
31
|
+
readonly character: number;
|
|
32
|
+
}
|
|
33
|
+
| {
|
|
34
|
+
readonly operation: "calleesAt";
|
|
35
|
+
readonly file: string;
|
|
36
|
+
readonly line: number;
|
|
37
|
+
readonly character: number;
|
|
38
|
+
readonly depth?: "direct" | "deep";
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export interface StructuralWorkerRequestMessage {
|
|
42
|
+
readonly kind: "request";
|
|
43
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
44
|
+
readonly generation: number;
|
|
45
|
+
readonly requestId: string;
|
|
46
|
+
readonly input: StructuralWorkerOperation;
|
|
47
|
+
readonly operationId?: string;
|
|
48
|
+
readonly deadline?: number;
|
|
49
|
+
readonly cancellationFlag: SharedArrayBuffer;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface StructuralWorkerCancelMessage {
|
|
53
|
+
readonly kind: "cancel";
|
|
54
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
55
|
+
readonly generation: number;
|
|
56
|
+
readonly requestId: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface StructuralWorkerChunkAckMessage {
|
|
60
|
+
readonly kind: "chunk-ack";
|
|
61
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
62
|
+
readonly generation: number;
|
|
63
|
+
readonly requestId: string;
|
|
64
|
+
readonly sequence: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ParentToStructuralWorkerMessage =
|
|
68
|
+
| StructuralWorkerRequestMessage
|
|
69
|
+
| StructuralWorkerCancelMessage
|
|
70
|
+
| StructuralWorkerChunkAckMessage;
|
|
71
|
+
|
|
72
|
+
export interface StructuralWorkerReadyMessage {
|
|
73
|
+
readonly kind: "ready";
|
|
74
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
75
|
+
readonly generation: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface StructuralWorkerStartupFailureMessage {
|
|
79
|
+
readonly kind: "startup-failure";
|
|
80
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
81
|
+
readonly generation: number;
|
|
82
|
+
readonly message: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface StructuralWorkerChunkMessage {
|
|
86
|
+
readonly kind: "chunk";
|
|
87
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
88
|
+
readonly generation: number;
|
|
89
|
+
readonly requestId: string;
|
|
90
|
+
readonly sequence: number;
|
|
91
|
+
readonly final: boolean;
|
|
92
|
+
readonly encodedBytes: number;
|
|
93
|
+
readonly payload: Uint8Array;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface StructuralWorkerObservationMessage {
|
|
97
|
+
readonly kind: "observation";
|
|
98
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
99
|
+
readonly generation: number;
|
|
100
|
+
readonly requestId: string;
|
|
101
|
+
readonly observation: StructuralTimingEvent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface StructuralWorkerTerminalMessage {
|
|
105
|
+
readonly kind: "terminal";
|
|
106
|
+
readonly version: typeof STRUCTURAL_WORKER_PROTOCOL_VERSION;
|
|
107
|
+
readonly generation: number;
|
|
108
|
+
readonly requestId: string;
|
|
109
|
+
readonly outcome: "completed" | "cancelled" | "timeout";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type StructuralWorkerToParentMessage =
|
|
113
|
+
| StructuralWorkerReadyMessage
|
|
114
|
+
| StructuralWorkerStartupFailureMessage
|
|
115
|
+
| StructuralWorkerChunkMessage
|
|
116
|
+
| StructuralWorkerObservationMessage
|
|
117
|
+
| StructuralWorkerTerminalMessage;
|
|
118
|
+
|
|
119
|
+
export type StructuralProtocolValidation<T> =
|
|
120
|
+
| { readonly kind: "valid"; readonly message: T }
|
|
121
|
+
| { readonly kind: "invalid"; readonly reason: string };
|
|
122
|
+
|
|
123
|
+
/** Validate an untrusted request before the Structural Worker executes it. */
|
|
124
|
+
export function validateStructuralWorkerRequest(
|
|
125
|
+
value: unknown,
|
|
126
|
+
): StructuralProtocolValidation<StructuralWorkerRequestMessage> {
|
|
127
|
+
if (!isRecord(value)) return invalid("Structural Worker request must be an object");
|
|
128
|
+
const required = ["kind", "version", "generation", "requestId", "input", "cancellationFlag"];
|
|
129
|
+
const allowed = new Set([...required, "operationId", "deadline"]);
|
|
130
|
+
if (
|
|
131
|
+
required.some((key) => !(key in value)) ||
|
|
132
|
+
Object.keys(value).some((key) => !allowed.has(key))
|
|
133
|
+
) {
|
|
134
|
+
return invalid("Invalid structural request envelope");
|
|
135
|
+
}
|
|
136
|
+
if (
|
|
137
|
+
value.kind !== "request" ||
|
|
138
|
+
value.version !== STRUCTURAL_WORKER_PROTOCOL_VERSION ||
|
|
139
|
+
!isPositiveInteger(value.generation) ||
|
|
140
|
+
!isRequestId(value.requestId) ||
|
|
141
|
+
!isRecord(value.input) ||
|
|
142
|
+
!(value.cancellationFlag instanceof SharedArrayBuffer) ||
|
|
143
|
+
value.cancellationFlag.byteLength !== Int32Array.BYTES_PER_ELEMENT ||
|
|
144
|
+
(value.deadline !== undefined &&
|
|
145
|
+
(typeof value.deadline !== "number" || !Number.isFinite(value.deadline))) ||
|
|
146
|
+
(value.operationId !== undefined && !isDebugOperationId(value.operationId))
|
|
147
|
+
) {
|
|
148
|
+
return invalid("Invalid structural request");
|
|
149
|
+
}
|
|
150
|
+
return valid(value as unknown as StructuralWorkerRequestMessage);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Encode one complete structural result into fixed-size binary chunks. */
|
|
154
|
+
export function encodeStructuralResult(result: TreeSitterResult<unknown>): Uint8Array[] {
|
|
155
|
+
assertPlainProtocolValue(result);
|
|
156
|
+
const bytes = Buffer.from(JSON.stringify(result), "utf8");
|
|
157
|
+
if (bytes.byteLength > STRUCTURAL_WORKER_LIMITS.maxResultBytes) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Structural result exceeds the ${STRUCTURAL_WORKER_LIMITS.maxResultBytes}-byte limit`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const chunks: Uint8Array[] = [];
|
|
163
|
+
for (
|
|
164
|
+
let offset = 0;
|
|
165
|
+
offset < bytes.byteLength;
|
|
166
|
+
offset += STRUCTURAL_WORKER_LIMITS.targetChunkBytes
|
|
167
|
+
) {
|
|
168
|
+
const end = Math.min(offset + STRUCTURAL_WORKER_LIMITS.targetChunkBytes, bytes.byteLength);
|
|
169
|
+
chunks.push(Uint8Array.from(bytes.subarray(offset, end)));
|
|
170
|
+
}
|
|
171
|
+
return chunks.length > 0 ? chunks : [new Uint8Array()];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Reconstruct one complete structural result from validated binary chunks. */
|
|
175
|
+
export function decodeStructuralResult<T>(chunks: readonly Uint8Array[]): TreeSitterResult<T> {
|
|
176
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
|
|
177
|
+
if (total > STRUCTURAL_WORKER_LIMITS.maxResultBytes) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Structural result exceeds the ${STRUCTURAL_WORKER_LIMITS.maxResultBytes}-byte limit`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const parsed: unknown = JSON.parse(
|
|
183
|
+
Buffer.concat(
|
|
184
|
+
chunks.map((chunk) => Buffer.from(chunk)),
|
|
185
|
+
total,
|
|
186
|
+
).toString("utf8"),
|
|
187
|
+
);
|
|
188
|
+
assertTreeSitterResult(parsed);
|
|
189
|
+
return parsed as TreeSitterResult<T>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Validate an untrusted message received from a Structural Worker. */
|
|
193
|
+
export function validateWorkerToParentMessage(
|
|
194
|
+
value: unknown,
|
|
195
|
+
): StructuralProtocolValidation<StructuralWorkerToParentMessage> {
|
|
196
|
+
if (!isRecord(value)) return invalid("Structural Worker message must be an object");
|
|
197
|
+
if (value.version !== STRUCTURAL_WORKER_PROTOCOL_VERSION) {
|
|
198
|
+
return invalid("Unsupported Structural Worker protocol version");
|
|
199
|
+
}
|
|
200
|
+
if (!isPositiveInteger(value.generation)) return invalid("Invalid Worker generation");
|
|
201
|
+
switch (value.kind) {
|
|
202
|
+
case "ready":
|
|
203
|
+
return hasExactKeys(value, ["kind", "version", "generation"])
|
|
204
|
+
? valid(value as unknown as StructuralWorkerReadyMessage)
|
|
205
|
+
: invalid("Invalid ready message");
|
|
206
|
+
case "startup-failure":
|
|
207
|
+
return hasExactKeys(value, ["kind", "version", "generation", "message"]) &&
|
|
208
|
+
isBoundedString(value.message, 1_024)
|
|
209
|
+
? valid(value as unknown as StructuralWorkerStartupFailureMessage)
|
|
210
|
+
: invalid("Invalid startup failure");
|
|
211
|
+
case "chunk":
|
|
212
|
+
return validateChunk(value);
|
|
213
|
+
case "observation":
|
|
214
|
+
return validateObservation(value);
|
|
215
|
+
case "terminal":
|
|
216
|
+
return validateTerminal(value);
|
|
217
|
+
default:
|
|
218
|
+
return invalid("Unknown Structural Worker message kind");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Build the exact request control represented by one Worker request. */
|
|
223
|
+
export interface StructuralWorkerRequestControl extends CodeRequestControl {
|
|
224
|
+
readonly cancellationFlag: Int32Array;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function validateChunk(
|
|
228
|
+
value: Record<string, unknown>,
|
|
229
|
+
): StructuralProtocolValidation<StructuralWorkerChunkMessage> {
|
|
230
|
+
if (
|
|
231
|
+
!hasExactKeys(value, [
|
|
232
|
+
"kind",
|
|
233
|
+
"version",
|
|
234
|
+
"generation",
|
|
235
|
+
"requestId",
|
|
236
|
+
"sequence",
|
|
237
|
+
"final",
|
|
238
|
+
"encodedBytes",
|
|
239
|
+
"payload",
|
|
240
|
+
])
|
|
241
|
+
) {
|
|
242
|
+
return invalid("Invalid chunk envelope");
|
|
243
|
+
}
|
|
244
|
+
if (!isRequestId(value.requestId)) return invalid("Invalid request id");
|
|
245
|
+
if (!Number.isSafeInteger(value.sequence) || Number(value.sequence) < 0) {
|
|
246
|
+
return invalid("Invalid chunk sequence");
|
|
247
|
+
}
|
|
248
|
+
if (typeof value.final !== "boolean") return invalid("Invalid final chunk marker");
|
|
249
|
+
if (!(value.payload instanceof Uint8Array)) return invalid("Invalid chunk payload");
|
|
250
|
+
if (value.encodedBytes !== value.payload.byteLength) return invalid("Invalid chunk byte count");
|
|
251
|
+
if (value.payload.byteLength > STRUCTURAL_WORKER_LIMITS.targetChunkBytes) {
|
|
252
|
+
return invalid("Structural Worker chunk exceeds the byte limit");
|
|
253
|
+
}
|
|
254
|
+
if (
|
|
255
|
+
estimateChunkMessageBytes(value.payload.byteLength) > STRUCTURAL_WORKER_LIMITS.maxMessageBytes
|
|
256
|
+
) {
|
|
257
|
+
return invalid("Structural Worker message exceeds the byte limit");
|
|
258
|
+
}
|
|
259
|
+
return valid(value as unknown as StructuralWorkerChunkMessage);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function validateObservation(
|
|
263
|
+
value: Record<string, unknown>,
|
|
264
|
+
): StructuralProtocolValidation<StructuralWorkerObservationMessage> {
|
|
265
|
+
if (!hasExactKeys(value, ["kind", "version", "generation", "requestId", "observation"])) {
|
|
266
|
+
return invalid("Invalid observation envelope");
|
|
267
|
+
}
|
|
268
|
+
if (!isRequestId(value.requestId)) return invalid("Invalid request id");
|
|
269
|
+
if (!isStructuralTimingEvent(value.observation)) return invalid("Invalid structural observation");
|
|
270
|
+
return valid(value as unknown as StructuralWorkerObservationMessage);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function validateTerminal(
|
|
274
|
+
value: Record<string, unknown>,
|
|
275
|
+
): StructuralProtocolValidation<StructuralWorkerTerminalMessage> {
|
|
276
|
+
if (!hasExactKeys(value, ["kind", "version", "generation", "requestId", "outcome"])) {
|
|
277
|
+
return invalid("Invalid terminal envelope");
|
|
278
|
+
}
|
|
279
|
+
if (!isRequestId(value.requestId)) return invalid("Invalid request id");
|
|
280
|
+
if (
|
|
281
|
+
value.outcome !== "completed" &&
|
|
282
|
+
value.outcome !== "cancelled" &&
|
|
283
|
+
value.outcome !== "timeout"
|
|
284
|
+
) {
|
|
285
|
+
return invalid("Invalid terminal outcome");
|
|
286
|
+
}
|
|
287
|
+
return valid(value as unknown as StructuralWorkerTerminalMessage);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: every sanitized nested timing field is validated at one trust boundary
|
|
291
|
+
function isStructuralTimingEvent(value: unknown): value is StructuralTimingEvent {
|
|
292
|
+
if (!isRecord(value) || !isRecord(value.data) || !isRecord(value.data.timing)) return false;
|
|
293
|
+
const expected =
|
|
294
|
+
value.operationId === undefined
|
|
295
|
+
? ["source", "level", "category", "message", "data"]
|
|
296
|
+
: ["operationId", "source", "level", "category", "message", "data"];
|
|
297
|
+
if (!hasExactKeys(value, expected)) return false;
|
|
298
|
+
if (value.operationId !== undefined && !isDebugOperationId(value.operationId)) return false;
|
|
299
|
+
if (value.source !== "tree-sitter" || value.level !== "debug") return false;
|
|
300
|
+
if (
|
|
301
|
+
value.category !== "structural.parse.timing" &&
|
|
302
|
+
value.category !== "structural.query.timing"
|
|
303
|
+
) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
if (
|
|
307
|
+
!isBoundedString(value.message, 96) ||
|
|
308
|
+
!/^Tree-sitter (?:parse|query) [a-z-]+$/.test(value.message)
|
|
309
|
+
) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
if (!isGrammar(value.data.grammar)) return false;
|
|
313
|
+
if (value.data.cache !== undefined && !isCacheObservation(value.data.cache)) return false;
|
|
314
|
+
const timing = value.data.timing;
|
|
315
|
+
if (!hasExactKeys(timing, ["durationMs", "phasesMs"]) || !isFiniteDuration(timing.durationMs)) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
if (!isRecord(timing.phasesMs) || Object.keys(timing.phasesMs).length > 8) return false;
|
|
319
|
+
if (
|
|
320
|
+
Object.entries(timing.phasesMs).some(
|
|
321
|
+
([phase, duration]) => !/^[a-z-]{1,32}$/.test(phase) || !isFiniteDuration(duration),
|
|
322
|
+
)
|
|
323
|
+
) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
return value.category === "structural.parse.timing"
|
|
327
|
+
? isParseTimingData(value.data)
|
|
328
|
+
: isQueryTimingData(value.data);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function assertTreeSitterResult(value: unknown): asserts value is TreeSitterResult<unknown> {
|
|
332
|
+
if (!isRecord(value) || typeof value.kind !== "string")
|
|
333
|
+
throw new Error("Invalid structural result");
|
|
334
|
+
if (value.kind === "success" && "data" in value) return;
|
|
335
|
+
if (
|
|
336
|
+
value.kind === "unsupported-language" ||
|
|
337
|
+
value.kind === "file-access-error" ||
|
|
338
|
+
value.kind === "validation-error" ||
|
|
339
|
+
value.kind === "runtime-error"
|
|
340
|
+
) {
|
|
341
|
+
if (typeof value.message === "string") return;
|
|
342
|
+
}
|
|
343
|
+
throw new Error("Invalid structural result");
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function assertPlainProtocolValue(value: unknown, seen = new Set<object>()): void {
|
|
347
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return;
|
|
348
|
+
if (typeof value === "number") {
|
|
349
|
+
if (!Number.isFinite(value)) throw new Error("Structural result contains a non-finite number");
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (typeof value !== "object") throw new Error("Structural result contains an unsupported value");
|
|
353
|
+
if (seen.has(value)) throw new Error("Structural result contains a cycle");
|
|
354
|
+
seen.add(value);
|
|
355
|
+
if (Array.isArray(value)) {
|
|
356
|
+
for (const item of value) assertPlainProtocolValue(item, seen);
|
|
357
|
+
seen.delete(value);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (Object.getPrototypeOf(value) !== Object.prototype) {
|
|
361
|
+
const size = Buffer.byteLength(JSON.stringify(value) ?? "", "utf8");
|
|
362
|
+
if (size > STRUCTURAL_WORKER_LIMITS.maxAtomicValueBytes) {
|
|
363
|
+
throw new Error("Structural result contains an oversize indivisible value");
|
|
364
|
+
}
|
|
365
|
+
throw new Error("Structural result contains a non-plain value");
|
|
366
|
+
}
|
|
367
|
+
for (const item of Object.values(value)) assertPlainProtocolValue(item, seen);
|
|
368
|
+
seen.delete(value);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function isParseTimingData(data: Record<string, unknown>): boolean {
|
|
372
|
+
const expected =
|
|
373
|
+
data.cache === undefined
|
|
374
|
+
? ["operation", "grammar", "parserState", "outcome", "timing"]
|
|
375
|
+
: ["operation", "grammar", "parserState", "outcome", "cache", "timing"];
|
|
376
|
+
if (!hasExactKeys(data, expected)) return false;
|
|
377
|
+
return (
|
|
378
|
+
data.operation === "parse" &&
|
|
379
|
+
(data.parserState === "cold" ||
|
|
380
|
+
data.parserState === "initializing" ||
|
|
381
|
+
data.parserState === "reused") &&
|
|
382
|
+
["cancelled", "completed", "file-access-error", "runtime-error", "timeout"].includes(
|
|
383
|
+
String(data.outcome),
|
|
384
|
+
)
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function isQueryTimingData(data: Record<string, unknown>): boolean {
|
|
389
|
+
if (!hasExactKeys(data, ["operation", "grammar", "outcome", "captureCount", "cache", "timing"])) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
return (
|
|
393
|
+
data.operation === "query" &&
|
|
394
|
+
Number.isSafeInteger(data.captureCount) &&
|
|
395
|
+
Number(data.captureCount) >= 0 &&
|
|
396
|
+
["cancelled", "completed", "runtime-error", "timeout", "validation-error"].includes(
|
|
397
|
+
String(data.outcome),
|
|
398
|
+
)
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function isCacheObservation(value: unknown): boolean {
|
|
403
|
+
return (
|
|
404
|
+
isRecord(value) &&
|
|
405
|
+
hasExactKeys(value, ["state", "retained", "evictionCount"]) &&
|
|
406
|
+
(value.state === "hit" || value.state === "miss" || value.state === "replacement") &&
|
|
407
|
+
typeof value.retained === "boolean" &&
|
|
408
|
+
Number.isSafeInteger(value.evictionCount) &&
|
|
409
|
+
Number(value.evictionCount) >= 0
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function isGrammar(value: unknown): boolean {
|
|
414
|
+
return isBoundedString(value, 16) && /^[a-z]+$/.test(value);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function isFiniteDuration(value: unknown): boolean {
|
|
418
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function hasExactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {
|
|
422
|
+
const actual = Object.keys(value).sort();
|
|
423
|
+
return actual.length === expected.length && expected.every((key) => actual.includes(key));
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function isBoundedString(value: unknown, maxLength: number): value is string {
|
|
427
|
+
return typeof value === "string" && value.length > 0 && value.length <= maxLength;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function estimateChunkMessageBytes(payloadBytes: number): number {
|
|
431
|
+
return payloadBytes + 1024;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
435
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function isPositiveInteger(value: unknown): value is number {
|
|
439
|
+
return Number.isSafeInteger(value) && Number(value) > 0;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function isRequestId(value: unknown): value is string {
|
|
443
|
+
return typeof value === "string" && value.length > 0 && value.length <= 128;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function valid<T>(message: T): StructuralProtocolValidation<T> {
|
|
447
|
+
return { kind: "valid", message };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function invalid(reason: string): StructuralProtocolValidation<never> {
|
|
451
|
+
return { kind: "invalid", reason };
|
|
452
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** File-wide call-site extraction using per-grammar tree-sitter queries. */
|
|
2
2
|
|
|
3
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
3
4
|
import { detectGrammar } from "../language.ts";
|
|
4
|
-
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
5
|
import type { CallSiteMatch, GrammarId, TreeSitterResult } from "../types.ts";
|
|
6
|
+
import type { TreeSitterRuntime } from "../worker/runtime.ts";
|
|
6
7
|
|
|
7
8
|
// ── Per-grammar call-site queries ─────────────────────────────────────
|
|
8
9
|
|
|
@@ -48,6 +49,7 @@ export function supportsCallSitesGrammar(grammarId: GrammarId): boolean {
|
|
|
48
49
|
export async function extractCallSites(
|
|
49
50
|
runtime: TreeSitterRuntime,
|
|
50
51
|
filePath: string,
|
|
52
|
+
control?: CodeRequestControl,
|
|
51
53
|
): Promise<TreeSitterResult<CallSiteMatch[]>> {
|
|
52
54
|
const grammarId = detectGrammar(filePath);
|
|
53
55
|
if (!grammarId) {
|
|
@@ -67,7 +69,7 @@ export async function extractCallSites(
|
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
const queryResult = await runtime.queryFile(filePath, queryStr);
|
|
72
|
+
const queryResult = await runtime.queryFile(filePath, queryStr, control);
|
|
71
73
|
if (queryResult.kind !== "success") return queryResult;
|
|
72
74
|
|
|
73
75
|
const captures = queryResult.data;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Structural callee extraction — enclosing-scope lookup with per-language queries.
|
|
2
2
|
|
|
3
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
3
4
|
import { detectGrammar } from "../language.ts";
|
|
4
|
-
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
5
|
import type { GrammarId, SourceRange, TreeSitterResult } from "../types.ts";
|
|
6
|
+
import { queryParsedFile, type TreeSitterRuntime } from "../worker/runtime.ts";
|
|
6
7
|
|
|
7
8
|
/** Result shape returned by lookupCalleesAt. */
|
|
8
9
|
export interface CalleesAtResult {
|
|
@@ -174,6 +175,7 @@ export async function lookupCalleesAt(
|
|
|
174
175
|
line: number,
|
|
175
176
|
character: number,
|
|
176
177
|
depth: "direct" | "deep" = "direct",
|
|
178
|
+
control?: CodeRequestControl,
|
|
177
179
|
): Promise<TreeSitterResult<CalleesAtResult>> {
|
|
178
180
|
// Validate coordinates and grammar
|
|
179
181
|
const validation = validateCalleeInput(filePath, line, character);
|
|
@@ -181,10 +183,10 @@ export async function lookupCalleesAt(
|
|
|
181
183
|
const { grammarId } = validation;
|
|
182
184
|
|
|
183
185
|
// Parse the file
|
|
184
|
-
const parseResult = await runtime.parseFile(filePath);
|
|
186
|
+
const parseResult = await runtime.parseFile(filePath, control);
|
|
185
187
|
if (parseResult.kind !== "success") return parseResult;
|
|
186
188
|
|
|
187
|
-
const { tree } = parseResult.data;
|
|
189
|
+
const { tree, source } = parseResult.data;
|
|
188
190
|
|
|
189
191
|
try {
|
|
190
192
|
const scopes = ENCLOSING_SCOPE_TYPES[grammarId];
|
|
@@ -214,7 +216,13 @@ export async function lookupCalleesAt(
|
|
|
214
216
|
};
|
|
215
217
|
}
|
|
216
218
|
|
|
217
|
-
const queryResult = await runtime
|
|
219
|
+
const queryResult = await queryParsedFile(runtime, {
|
|
220
|
+
grammarId,
|
|
221
|
+
tree,
|
|
222
|
+
source,
|
|
223
|
+
queryString: queryStr,
|
|
224
|
+
control,
|
|
225
|
+
});
|
|
218
226
|
if (queryResult.kind !== "success") {
|
|
219
227
|
return {
|
|
220
228
|
kind: "runtime-error",
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
// Export extraction for supported files.
|
|
2
2
|
|
|
3
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
3
4
|
import { nodeToRange } from "../coordinates.ts";
|
|
4
|
-
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
5
|
import type { SyntaxNodeLike } from "../syntax-node.ts";
|
|
6
6
|
import type { ExportRecord, TreeSitterResult } from "../types.ts";
|
|
7
|
+
import type { TreeSitterRuntime } from "../worker/runtime.ts";
|
|
7
8
|
|
|
8
9
|
/** Extract export records from a supported file. */
|
|
9
10
|
export async function extractExports(
|
|
10
11
|
runtime: TreeSitterRuntime,
|
|
11
12
|
filePath: string,
|
|
13
|
+
control?: CodeRequestControl,
|
|
12
14
|
): Promise<TreeSitterResult<ExportRecord[]>> {
|
|
13
|
-
const parseResult = await runtime.parseFile(filePath);
|
|
15
|
+
const parseResult = await runtime.parseFile(filePath, control);
|
|
14
16
|
if (parseResult.kind !== "success") return parseResult;
|
|
15
17
|
|
|
16
18
|
const { tree, source } = parseResult.data;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
// Import extraction for supported files.
|
|
2
2
|
|
|
3
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
3
4
|
import { nodeToRange } from "../coordinates.ts";
|
|
4
|
-
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
5
|
import type { SyntaxNodeLike } from "../syntax-node.ts";
|
|
6
6
|
import type { ImportRecord, TreeSitterResult } from "../types.ts";
|
|
7
|
+
import type { TreeSitterRuntime } from "../worker/runtime.ts";
|
|
7
8
|
|
|
8
9
|
/** Extract import records from a supported file. */
|
|
9
10
|
export async function extractImports(
|
|
10
11
|
runtime: TreeSitterRuntime,
|
|
11
12
|
filePath: string,
|
|
13
|
+
control?: CodeRequestControl,
|
|
12
14
|
): Promise<TreeSitterResult<ImportRecord[]>> {
|
|
13
|
-
const parseResult = await runtime.parseFile(filePath);
|
|
15
|
+
const parseResult = await runtime.parseFile(filePath, control);
|
|
14
16
|
if (parseResult.kind !== "success") return parseResult;
|
|
15
17
|
|
|
16
18
|
const { tree, source } = parseResult.data;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Node-at-position lookup.
|
|
2
2
|
|
|
3
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
3
4
|
import { nodeToRange, publicToTreeSitter, splitSourceLines } from "../coordinates.ts";
|
|
4
|
-
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
5
5
|
import type { NodeAtResult, SourceRange, TreeSitterResult } from "../types.ts";
|
|
6
|
+
import type { TreeSitterRuntime } from "../worker/runtime.ts";
|
|
6
7
|
|
|
7
8
|
const MAX_ANCESTRY = 10;
|
|
8
9
|
|
|
@@ -11,8 +12,9 @@ export async function lookupNodeAt(
|
|
|
11
12
|
runtime: TreeSitterRuntime,
|
|
12
13
|
filePath: string,
|
|
13
14
|
line: number,
|
|
14
|
-
character: number,
|
|
15
|
+
...position: [character: number, control?: CodeRequestControl]
|
|
15
16
|
): Promise<TreeSitterResult<NodeAtResult>> {
|
|
17
|
+
const [character, control] = position;
|
|
16
18
|
if (!Number.isInteger(line) || line < 1) {
|
|
17
19
|
return { kind: "validation-error", message: "line must be a positive 1-based integer" };
|
|
18
20
|
}
|
|
@@ -20,7 +22,7 @@ export async function lookupNodeAt(
|
|
|
20
22
|
return { kind: "validation-error", message: "character must be a positive 1-based integer" };
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
const parseResult = await runtime.parseFile(filePath);
|
|
25
|
+
const parseResult = await runtime.parseFile(filePath, control);
|
|
24
26
|
if (parseResult.kind !== "success") return parseResult;
|
|
25
27
|
|
|
26
28
|
const { tree, source } = parseResult.data;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Public tree-sitter package types.
|
|
2
2
|
|
|
3
|
+
import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
|
|
4
|
+
|
|
3
5
|
/** 1-based source range compatible with LSP position convention. */
|
|
4
6
|
export interface SourceRange {
|
|
5
7
|
startLine: number;
|
|
@@ -73,38 +75,57 @@ export interface CallSiteMatch {
|
|
|
73
75
|
startLine: number;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* Shared Tree-sitter service surface, independent of lifecycle ownership.
|
|
80
|
+
* Optional request control cooperatively stops reads, parser progress, query
|
|
81
|
+
* progress, and cache publication without exposing raw WASM resources.
|
|
82
|
+
*/
|
|
77
83
|
export interface TreeSitterService {
|
|
78
84
|
/** Validate that a supported file can be read and parsed; does not expose the raw tree. */
|
|
79
|
-
canParse(
|
|
85
|
+
canParse(
|
|
86
|
+
file: string,
|
|
87
|
+
control?: CodeRequestControl,
|
|
88
|
+
): Promise<TreeSitterResult<{ file: string; language: string }>>;
|
|
80
89
|
/** Run a Tree-sitter query and return all captures. */
|
|
81
|
-
query(
|
|
90
|
+
query(
|
|
91
|
+
file: string,
|
|
92
|
+
queryString: string,
|
|
93
|
+
control?: CodeRequestControl,
|
|
94
|
+
): Promise<TreeSitterResult<QueryCapture[]>>;
|
|
82
95
|
/**
|
|
83
96
|
* Extract shallow declarations, including supported nested code members,
|
|
84
97
|
* HTML ids, and SQL schema members.
|
|
85
98
|
*/
|
|
86
|
-
outline(file: string): Promise<TreeSitterResult<OutlineItem[]>>;
|
|
99
|
+
outline(file: string, control?: CodeRequestControl): Promise<TreeSitterResult<OutlineItem[]>>;
|
|
87
100
|
/** Extract static ES import declarations. */
|
|
88
|
-
imports(file: string): Promise<TreeSitterResult<ImportRecord[]>>;
|
|
101
|
+
imports(file: string, control?: CodeRequestControl): Promise<TreeSitterResult<ImportRecord[]>>;
|
|
89
102
|
/** Extract exported declarations, named exports, re-exports, and TS export assignments. */
|
|
90
|
-
exports(file: string): Promise<TreeSitterResult<ExportRecord[]>>;
|
|
103
|
+
exports(file: string, control?: CodeRequestControl): Promise<TreeSitterResult<ExportRecord[]>>;
|
|
91
104
|
/** Return the smallest syntax node at a 1-based UTF-16 position. */
|
|
92
|
-
nodeAt(
|
|
105
|
+
nodeAt(
|
|
106
|
+
file: string,
|
|
107
|
+
line: number,
|
|
108
|
+
character: number,
|
|
109
|
+
control?: CodeRequestControl,
|
|
110
|
+
): Promise<TreeSitterResult<NodeAtResult>>;
|
|
93
111
|
/** Extract structural outgoing calls from the enclosing scope at a position. */
|
|
94
112
|
calleesAt(
|
|
95
113
|
file: string,
|
|
96
114
|
line: number,
|
|
97
115
|
character: number,
|
|
98
|
-
|
|
116
|
+
depthOrOptions?:
|
|
117
|
+
| "direct"
|
|
118
|
+
| "deep"
|
|
119
|
+
| { depth?: "direct" | "deep"; control?: CodeRequestControl },
|
|
99
120
|
): Promise<TreeSitterResult<CalleesAtResult>>;
|
|
100
121
|
/** Extract all call-site identifiers in a file. */
|
|
101
|
-
callSites(file: string): Promise<TreeSitterResult<CallSiteMatch[]>>;
|
|
122
|
+
callSites(file: string, control?: CodeRequestControl): Promise<TreeSitterResult<CallSiteMatch[]>>;
|
|
102
123
|
}
|
|
103
124
|
|
|
104
|
-
/** Owned Tree-sitter session that must release its
|
|
125
|
+
/** Owned Tree-sitter session that must release its Worker resources. */
|
|
105
126
|
export interface TreeSitterSession extends TreeSitterService {
|
|
106
|
-
/**
|
|
107
|
-
dispose(): void
|
|
127
|
+
/** Terminate and await the Structural Worker owned by this session. */
|
|
128
|
+
dispose(): Promise<void>;
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
/** Session-scoped shared structural service published by the extension runtime. */
|