ttsc 0.31.1 → 0.31.2
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/lib/compiler/internal/build/BuildExecution.d.ts +4 -2
- package/lib/compiler/internal/build/BuildExecution.js +40 -12
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +5 -4
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +9 -7
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/internal/javascriptRuntimeCapabilities.d.ts +13 -4
- package/lib/internal/javascriptRuntimeCapabilities.js +56 -6
- package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
- package/lib/internal/pluginSource.d.ts +1 -0
- package/lib/internal/pluginSource.js +1 -0
- package/lib/internal/pluginSource.js.map +1 -1
- package/lib/internal/resolveNodeBinary.d.ts +6 -1
- package/lib/internal/resolveNodeBinary.js +6 -2
- package/lib/internal/resolveNodeBinary.js.map +1 -1
- package/lib/internal/runtimeExecutableIdentity.d.ts +22 -13
- package/lib/internal/runtimeExecutableIdentity.js +192 -102
- package/lib/internal/runtimeExecutableIdentity.js.map +1 -1
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +58 -4
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.d.ts +5 -1
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js +7 -2
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js.map +1 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js +8 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js.map +1 -1
- package/lib/plugin/internal/CapabilityResolutionFormat.d.ts +21 -62
- package/lib/plugin/internal/CapabilityResolutionFormat.js +15 -106
- package/lib/plugin/internal/CapabilityResolutionFormat.js.map +1 -1
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.d.ts +6 -0
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +4 -4
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.d.ts +12 -1
- package/lib/plugin/internal/load/loadProjectPlugins.js +80 -20
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/readCapabilityResolution.d.ts +6 -0
- package/lib/plugin/internal/readCapabilityResolution.js +8 -5
- package/lib/plugin/internal/readCapabilityResolution.js.map +1 -1
- package/lib/plugin/internal/source/GoEnvironmentReading.d.ts +9 -3
- package/lib/plugin/internal/source/GoEnvironmentReading.js +53 -7
- package/lib/plugin/internal/source/GoEnvironmentReading.js.map +1 -1
- package/lib/plugin/internal/source/NativeSourcePackages.d.ts +44 -6
- package/lib/plugin/internal/source/NativeSourcePackages.js +150 -8
- package/lib/plugin/internal/source/NativeSourcePackages.js.map +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +21 -3
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +32 -7
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
- package/lib/plugin/internal/source/PluginContentIdentities.d.ts +265 -0
- package/lib/plugin/internal/source/PluginContentIdentities.js +452 -0
- package/lib/plugin/internal/source/PluginContentIdentities.js.map +1 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.d.ts +63 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.js +128 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.js.map +1 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.d.ts +10 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js +12 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js.map +1 -1
- package/lib/plugin/internal/source/SourcePluginWorkspace.d.ts +5 -2
- package/lib/plugin/internal/source/SourcePluginWorkspace.js +5 -3
- package/lib/plugin/internal/source/SourcePluginWorkspace.js.map +1 -1
- package/lib/plugin/internal/source/buildSourcePlugin.d.ts +15 -2
- package/lib/plugin/internal/source/buildSourcePlugin.js +27 -4
- package/lib/plugin/internal/source/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/source/computeCacheKey.d.ts +21 -5
- package/lib/plugin/internal/source/computeCacheKey.js +71 -29
- package/lib/plugin/internal/source/computeCacheKey.js.map +1 -1
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.d.ts +7 -3
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.js +74 -35
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildEnvironment.d.ts +8 -3
- package/lib/plugin/internal/source/pluginBuildEnvironment.js +8 -4
- package/lib/plugin/internal/source/pluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js +12 -2
- package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildVersions.d.ts +2 -2
- package/lib/plugin/internal/source/pluginBuildVersions.js +4 -17
- package/lib/plugin/internal/source/pluginBuildVersions.js.map +1 -1
- package/lib/plugin/internal/source/pluginSourceState.d.ts +6 -2
- package/lib/plugin/internal/source/pluginSourceState.js +20 -8
- package/lib/plugin/internal/source/pluginSourceState.js.map +1 -1
- package/lib/plugin/internal/source/pluginSourceStateHolds.d.ts +7 -2
- package/lib/plugin/internal/source/pluginSourceStateHolds.js +12 -7
- package/lib/plugin/internal/source/pluginSourceStateHolds.js.map +1 -1
- package/lib/plugin/internal/source/processPluginBuildEnvironment.d.ts +7 -2
- package/lib/plugin/internal/source/processPluginBuildEnvironment.js +8 -3
- package/lib/plugin/internal/source/processPluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/provenPluginSourceDigest.d.ts +28 -0
- package/lib/plugin/internal/source/provenPluginSourceDigest.js +41 -0
- package/lib/plugin/internal/source/provenPluginSourceDigest.js.map +1 -0
- package/lib/plugin/internal/source/pruneCacheFileRoot.d.ts +3 -2
- package/lib/plugin/internal/source/pruneCacheFileRoot.js +3 -2
- package/lib/plugin/internal/source/pruneCacheFileRoot.js.map +1 -1
- package/lib/plugin/internal/source/ttscPackageVersion.d.ts +26 -0
- package/lib/plugin/internal/source/ttscPackageVersion.js +47 -0
- package/lib/plugin/internal/source/ttscPackageVersion.js.map +1 -0
- package/lib/plugin/internal/writeCapabilityResolution.d.ts +6 -0
- package/lib/plugin/internal/writeCapabilityResolution.js +11 -7
- package/lib/plugin/internal/writeCapabilityResolution.js.map +1 -1
- package/lib/plugin/resolveCapabilityPlugins.js +67 -15
- package/lib/plugin/resolveCapabilityPlugins.js.map +1 -1
- package/package.json +8 -8
- package/src/compiler/internal/build/BuildExecution.ts +46 -13
- package/src/compiler/internal/startResidentTransform.ts +12 -3
- package/src/compiler/internal/transformProjectInMemory.ts +10 -2
- package/src/internal/javascriptRuntimeCapabilities.ts +71 -5
- package/src/internal/pluginSource.ts +1 -0
- package/src/internal/resolveNodeBinary.ts +12 -1
- package/src/internal/runtimeExecutableIdentity.ts +227 -141
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +68 -3
- package/src/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.ts +11 -2
- package/src/launcher/internal/ttscserver/runTtscserver.ts +18 -1
- package/src/plugin/internal/CapabilityResolutionFormat.ts +23 -107
- package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +14 -4
- package/src/plugin/internal/load/loadProjectPlugins.ts +212 -94
- package/src/plugin/internal/readCapabilityResolution.ts +17 -6
- package/src/plugin/internal/source/GoEnvironmentReading.ts +74 -5
- package/src/plugin/internal/source/NativeSourcePackages.ts +262 -5
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +41 -5
- package/src/plugin/internal/source/PluginContentIdentities.ts +563 -0
- package/src/plugin/internal/source/PluginLoadAnswers.ts +151 -0
- package/src/plugin/internal/source/SourceBuildCacheLayout.ts +14 -0
- package/src/plugin/internal/source/SourcePluginWorkspace.ts +6 -1
- package/src/plugin/internal/source/buildSourcePlugin.ts +43 -3
- package/src/plugin/internal/source/computeCacheKey.ts +103 -47
- package/src/plugin/internal/source/hashPluginBuildEnvironment.ts +144 -29
- package/src/plugin/internal/source/pluginBuildEnvironment.ts +9 -2
- package/src/plugin/internal/source/pluginBuildEnvironmentWorker.ts +18 -2
- package/src/plugin/internal/source/pluginBuildVersions.ts +5 -26
- package/src/plugin/internal/source/pluginSourceState.ts +28 -12
- package/src/plugin/internal/source/pluginSourceStateHolds.ts +15 -8
- package/src/plugin/internal/source/processPluginBuildEnvironment.ts +8 -2
- package/src/plugin/internal/source/provenPluginSourceDigest.ts +45 -0
- package/src/plugin/internal/source/pruneCacheFileRoot.ts +3 -2
- package/src/plugin/internal/source/ttscPackageVersion.ts +45 -0
- package/src/plugin/internal/writeCapabilityResolution.ts +29 -8
- package/src/plugin/resolveCapabilityPlugins.ts +87 -13
|
@@ -3,64 +3,44 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { threadId } from "node:worker_threads";
|
|
5
5
|
|
|
6
|
+
import { PluginContentIdentities } from "../plugin/internal/source/PluginContentIdentities";
|
|
6
7
|
import { E2ETrace } from "./E2ETrace";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Fingerprint an absolute executable's spelling, target and actual bytes.
|
|
10
11
|
*
|
|
11
12
|
* A changed link, file, or read failure yields no reusable identity. Metadata
|
|
12
|
-
* brackets the streamed read
|
|
13
|
-
*
|
|
14
|
-
* snapshot guarantee.
|
|
13
|
+
* brackets the streamed read. Concurrent writes that evade every filesystem
|
|
14
|
+
* observation remain outside this snapshot guarantee.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
16
|
+
* With a record store, the bytes of an unchanged executable are proven from its
|
|
17
|
+
* metadata instead of streamed again (`PluginContentIdentities`, #1723): the
|
|
18
|
+
* recorded digest stands only while the physical file's identity, size and both
|
|
19
|
+
* stamps match the record and its modification stamp is separable from a
|
|
20
|
+
* reference the store minted. A plugin load asks for this identity several
|
|
21
|
+
* times, and every launch is a new process, so streaming an 85 MB runtime each
|
|
22
|
+
* time cost about 0.9 s per launch. Without a store, or when that proof is
|
|
23
|
+
* unavailable, the file is streamed as before.
|
|
24
24
|
*
|
|
25
|
-
* @
|
|
25
|
+
* @param runtime The executable, absolute.
|
|
26
|
+
* @param identities Optional record store of the caller's plugin cache.
|
|
27
|
+
* @evidence contracts/common.md#principled-implementation The identity joins lexical-link metadata, the selected physical file metadata and the SHA-256 of that file's bytes, streamed under metadata brackets or proven by a record whose separable signature still matches; descriptor and pathname observations must still agree after a read.
|
|
28
|
+
* @evidence contracts/common.md#clear-and-simple-design This one native owner supplies the same identity to runtime capability and plugin caches; the record store owns metadata reuse and a private helper owns the bracketed stream.
|
|
29
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Metadata alone never stands for bytes: reuse needs a record written under unchanged separable metadata around an actual read, which a same-tick rewrite or restored timestamps cannot satisfy because change time and the minted reference move.
|
|
30
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains absolute-path scope, failure meaning, the record proof and the remaining concurrent-mutation limitation, with separate prose and tags.
|
|
31
|
+
* @evidence contracts/portability.md#os-neutral-implementation Node native realpath and bigint stat preserve link/target identity on supported hosts; absolute paths use native platform semantics, and unreadable or non-regular targets cannot be reused.
|
|
32
|
+
* @evidence contracts/performance.md#efficient-algorithms A proven record costs three stats and one small file read; otherwise a sequential read hashes B bytes with one 64 KiB buffer instead of a complete executable allocation. Native path/realpath/stat observations and serialized metadata add text/lookup costs.
|
|
33
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Processes share an executable digest only through the record store's separable-signature proof; without a store every call streams the file.
|
|
34
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One descriptor and one fixed buffer belong to a streamed read; finally attempts closure after read/observation failures as well as success. A close failure returns no identity but cannot confirm native release. Opt-in opened/closed/close-failed observations carry one trace-only call id and actual descriptor, PID/thread and already observed physical identity. Records belong to the single-file collector.
|
|
26
35
|
*/
|
|
27
|
-
export function runtimeExecutableIdentity(
|
|
36
|
+
export function runtimeExecutableIdentity(
|
|
37
|
+
runtime: string,
|
|
38
|
+
identities?: PluginContentIdentities.Store,
|
|
39
|
+
): string | undefined {
|
|
28
40
|
if (!path.isAbsolute(runtime)) return undefined;
|
|
29
41
|
const startedAt = new Date().toISOString();
|
|
30
|
-
let descriptor: number | undefined;
|
|
31
|
-
let traceLease: Readonly<Record<string, string | number>> | undefined;
|
|
32
42
|
let stage = "lexical-stat";
|
|
33
|
-
|
|
34
|
-
reason: string,
|
|
35
|
-
expected?: string,
|
|
36
|
-
observed?: string,
|
|
37
|
-
observations?: { before: fs.BigIntStats; after: fs.BigIntStats },
|
|
38
|
-
) => {
|
|
39
|
-
E2ETrace.capabilityResolution("runtime-executable-identity-unavailable", {
|
|
40
|
-
runtime,
|
|
41
|
-
stage,
|
|
42
|
-
reason,
|
|
43
|
-
expected,
|
|
44
|
-
observed,
|
|
45
|
-
expectedAtimeNs:
|
|
46
|
-
observations === undefined
|
|
47
|
-
? undefined
|
|
48
|
-
: String(observations.before.atimeNs),
|
|
49
|
-
observedAtimeNs:
|
|
50
|
-
observations === undefined
|
|
51
|
-
? undefined
|
|
52
|
-
: String(observations.after.atimeNs),
|
|
53
|
-
expectedBirthtimeNs:
|
|
54
|
-
observations === undefined
|
|
55
|
-
? undefined
|
|
56
|
-
: String(observations.before.birthtimeNs),
|
|
57
|
-
observedBirthtimeNs:
|
|
58
|
-
observations === undefined
|
|
59
|
-
? undefined
|
|
60
|
-
: String(observations.after.birthtimeNs),
|
|
61
|
-
});
|
|
62
|
-
return undefined;
|
|
63
|
-
};
|
|
43
|
+
let refused: IUnavailable | undefined;
|
|
64
44
|
try {
|
|
65
45
|
const lexical = fs.lstatSync(runtime, { bigint: true });
|
|
66
46
|
stage = "physical-realpath";
|
|
@@ -68,93 +48,30 @@ export function runtimeExecutableIdentity(runtime: string): string | undefined {
|
|
|
68
48
|
stage = "physical-stat";
|
|
69
49
|
const physical = fs.statSync(physicalPath, { bigint: true });
|
|
70
50
|
if (!physical.isFile())
|
|
71
|
-
return unavailable(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
fileIdentity(physical),
|
|
96
|
-
fileIdentity(opened),
|
|
97
|
-
);
|
|
98
|
-
const hash = crypto.createHash("sha256");
|
|
99
|
-
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
100
|
-
let remaining = opened.size;
|
|
101
|
-
stage = "read";
|
|
102
|
-
while (remaining > 0n) {
|
|
103
|
-
const requested =
|
|
104
|
-
remaining > BigInt(buffer.length) ? buffer.length : Number(remaining);
|
|
105
|
-
const length = fs.readSync(descriptor, buffer, 0, requested, null);
|
|
106
|
-
if (length === 0)
|
|
107
|
-
return unavailable(
|
|
108
|
-
"premature-eof",
|
|
109
|
-
String(opened.size),
|
|
110
|
-
String(opened.size - remaining),
|
|
111
|
-
);
|
|
112
|
-
hash.update(buffer.subarray(0, length));
|
|
113
|
-
remaining -= BigInt(length);
|
|
114
|
-
}
|
|
115
|
-
stage = "post-read-opened-stat";
|
|
116
|
-
const afterOpened = fs.fstatSync(descriptor, { bigint: true });
|
|
117
|
-
if (fileIdentity(afterOpened) !== fileIdentity(opened))
|
|
118
|
-
return unavailable(
|
|
119
|
-
"opened-file-changed-during-read",
|
|
120
|
-
fileIdentity(opened),
|
|
121
|
-
fileIdentity(afterOpened),
|
|
122
|
-
{ before: opened, after: afterOpened },
|
|
123
|
-
);
|
|
124
|
-
stage = "post-read-realpath";
|
|
125
|
-
const afterPath = fs.realpathSync.native(runtime);
|
|
126
|
-
if (afterPath !== physicalPath)
|
|
127
|
-
return unavailable("physical-target-changed", physicalPath, afterPath);
|
|
128
|
-
stage = "post-read-lexical-stat";
|
|
129
|
-
const afterLexical = fs.lstatSync(runtime, { bigint: true });
|
|
130
|
-
if (fileIdentity(afterLexical) !== fileIdentity(lexical))
|
|
131
|
-
return unavailable(
|
|
132
|
-
"lexical-file-changed-during-read",
|
|
133
|
-
fileIdentity(lexical),
|
|
134
|
-
fileIdentity(afterLexical),
|
|
135
|
-
);
|
|
136
|
-
stage = "post-read-physical-stat";
|
|
137
|
-
const afterPhysical = fs.statSync(physicalPath, { bigint: true });
|
|
138
|
-
if (fileIdentity(afterPhysical) !== fileIdentity(physical))
|
|
139
|
-
return unavailable(
|
|
140
|
-
"physical-file-changed-during-read",
|
|
141
|
-
fileIdentity(physical),
|
|
142
|
-
fileIdentity(afterPhysical),
|
|
143
|
-
);
|
|
144
|
-
const digest = hash.digest("hex");
|
|
145
|
-
E2ETrace.capabilityResolution("runtime-executable-identity-observed", {
|
|
146
|
-
runtime,
|
|
147
|
-
physicalPath,
|
|
148
|
-
startedAt,
|
|
149
|
-
finishedAt: new Date().toISOString(),
|
|
150
|
-
lexical: fileIdentity(lexical),
|
|
151
|
-
physical: fileIdentity(physical),
|
|
152
|
-
digest,
|
|
153
|
-
openedAtimeNs: String(opened.atimeNs),
|
|
154
|
-
afterOpenedAtimeNs: String(afterOpened.atimeNs),
|
|
155
|
-
openedBirthtimeNs: String(opened.birthtimeNs),
|
|
156
|
-
afterOpenedBirthtimeNs: String(afterOpened.birthtimeNs),
|
|
157
|
-
});
|
|
51
|
+
return unavailable(runtime, {
|
|
52
|
+
stage,
|
|
53
|
+
reason: "not-regular",
|
|
54
|
+
observed: fileIdentity(physical),
|
|
55
|
+
});
|
|
56
|
+
const read = (): string => {
|
|
57
|
+
const streamed = streamDigest(runtime, physicalPath, physical, lexical, {
|
|
58
|
+
startedAt,
|
|
59
|
+
});
|
|
60
|
+
if (typeof streamed === "string") return streamed;
|
|
61
|
+
refused = streamed;
|
|
62
|
+
throw new Error(streamed.reason);
|
|
63
|
+
};
|
|
64
|
+
const digest =
|
|
65
|
+
identities === undefined
|
|
66
|
+
? read()
|
|
67
|
+
: PluginContentIdentities.digest(
|
|
68
|
+
identities,
|
|
69
|
+
"executable",
|
|
70
|
+
physicalPath,
|
|
71
|
+
(references) =>
|
|
72
|
+
PluginContentIdentities.fileObservation(references, physicalPath),
|
|
73
|
+
read,
|
|
74
|
+
);
|
|
158
75
|
return [
|
|
159
76
|
physicalPath,
|
|
160
77
|
fileIdentity(lexical),
|
|
@@ -163,10 +80,71 @@ export function runtimeExecutableIdentity(runtime: string): string | undefined {
|
|
|
163
80
|
].join("\0");
|
|
164
81
|
} catch (error) {
|
|
165
82
|
return unavailable(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
83
|
+
runtime,
|
|
84
|
+
refused ?? {
|
|
85
|
+
stage,
|
|
86
|
+
reason: "filesystem-error",
|
|
87
|
+
observed: error instanceof Error ? error.message : String(error),
|
|
88
|
+
},
|
|
169
89
|
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Why an identity could not be formed, at the stage that found it. */
|
|
94
|
+
interface IUnavailable {
|
|
95
|
+
stage: string;
|
|
96
|
+
reason: string;
|
|
97
|
+
expected?: string;
|
|
98
|
+
observed?: string;
|
|
99
|
+
observations?: { before: fs.BigIntStats; after: fs.BigIntStats };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function unavailable(runtime: string, failure: IUnavailable): undefined {
|
|
103
|
+
E2ETrace.capabilityResolution("runtime-executable-identity-unavailable", {
|
|
104
|
+
runtime,
|
|
105
|
+
stage: failure.stage,
|
|
106
|
+
reason: failure.reason,
|
|
107
|
+
expected: failure.expected,
|
|
108
|
+
observed: failure.observed,
|
|
109
|
+
expectedAtimeNs:
|
|
110
|
+
failure.observations === undefined
|
|
111
|
+
? undefined
|
|
112
|
+
: String(failure.observations.before.atimeNs),
|
|
113
|
+
observedAtimeNs:
|
|
114
|
+
failure.observations === undefined
|
|
115
|
+
? undefined
|
|
116
|
+
: String(failure.observations.after.atimeNs),
|
|
117
|
+
expectedBirthtimeNs:
|
|
118
|
+
failure.observations === undefined
|
|
119
|
+
? undefined
|
|
120
|
+
: String(failure.observations.before.birthtimeNs),
|
|
121
|
+
observedBirthtimeNs:
|
|
122
|
+
failure.observations === undefined
|
|
123
|
+
? undefined
|
|
124
|
+
: String(failure.observations.after.birthtimeNs),
|
|
125
|
+
});
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Stream the physical file's bytes between metadata observations of the open
|
|
131
|
+
* descriptor, the physical path and the lexical spelling, returning the digest
|
|
132
|
+
* or what moved. The descriptor is closed in finally; a failed close refuses
|
|
133
|
+
* the identity.
|
|
134
|
+
*/
|
|
135
|
+
function streamDigest(
|
|
136
|
+
runtime: string,
|
|
137
|
+
physicalPath: string,
|
|
138
|
+
physical: fs.BigIntStats,
|
|
139
|
+
lexical: fs.BigIntStats,
|
|
140
|
+
timing: { startedAt: string },
|
|
141
|
+
): string | IUnavailable {
|
|
142
|
+
let stage = "open";
|
|
143
|
+
let descriptor: number | undefined;
|
|
144
|
+
let traceLease: Readonly<Record<string, string | number>> | undefined;
|
|
145
|
+
let result: string | IUnavailable;
|
|
146
|
+
try {
|
|
147
|
+
result = observe();
|
|
170
148
|
} finally {
|
|
171
149
|
if (descriptor !== undefined) {
|
|
172
150
|
try {
|
|
@@ -185,13 +163,121 @@ export function runtimeExecutableIdentity(runtime: string): string | undefined {
|
|
|
185
163
|
error: error instanceof Error ? error.message : String(error),
|
|
186
164
|
},
|
|
187
165
|
);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"
|
|
191
|
-
|
|
192
|
-
error instanceof Error ? error.message : String(error),
|
|
166
|
+
// A digest whose descriptor could not be closed is refused, as before.
|
|
167
|
+
result = {
|
|
168
|
+
stage: "close",
|
|
169
|
+
reason: "descriptor-close-error",
|
|
170
|
+
observed: error instanceof Error ? error.message : String(error),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
|
|
177
|
+
function observe(): string | IUnavailable {
|
|
178
|
+
try {
|
|
179
|
+
descriptor = fs.openSync(physicalPath, "r");
|
|
180
|
+
if (process.env.TTSC_E2E_TRACE) {
|
|
181
|
+
traceLease = {
|
|
182
|
+
callId: String(++identityTraceOrdinal),
|
|
183
|
+
runtime,
|
|
184
|
+
physicalPath,
|
|
185
|
+
descriptor,
|
|
186
|
+
pid: process.pid,
|
|
187
|
+
threadId,
|
|
188
|
+
dev: String(physical.dev),
|
|
189
|
+
ino: String(physical.ino),
|
|
190
|
+
};
|
|
191
|
+
E2ETrace.capabilityResolution(
|
|
192
|
+
"runtime-executable-identity-opened",
|
|
193
|
+
traceLease,
|
|
193
194
|
);
|
|
194
195
|
}
|
|
196
|
+
stage = "opened-stat";
|
|
197
|
+
const opened = fs.fstatSync(descriptor, { bigint: true });
|
|
198
|
+
if (fileIdentity(opened) !== fileIdentity(physical))
|
|
199
|
+
return {
|
|
200
|
+
stage,
|
|
201
|
+
reason: "opened-file-changed",
|
|
202
|
+
expected: fileIdentity(physical),
|
|
203
|
+
observed: fileIdentity(opened),
|
|
204
|
+
};
|
|
205
|
+
const hash = crypto.createHash("sha256");
|
|
206
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
207
|
+
let remaining = opened.size;
|
|
208
|
+
stage = "read";
|
|
209
|
+
while (remaining > 0n) {
|
|
210
|
+
const requested =
|
|
211
|
+
remaining > BigInt(buffer.length) ? buffer.length : Number(remaining);
|
|
212
|
+
const length = fs.readSync(descriptor, buffer, 0, requested, null);
|
|
213
|
+
if (length === 0)
|
|
214
|
+
return {
|
|
215
|
+
stage,
|
|
216
|
+
reason: "premature-eof",
|
|
217
|
+
expected: String(opened.size),
|
|
218
|
+
observed: String(opened.size - remaining),
|
|
219
|
+
};
|
|
220
|
+
hash.update(buffer.subarray(0, length));
|
|
221
|
+
remaining -= BigInt(length);
|
|
222
|
+
}
|
|
223
|
+
stage = "post-read-opened-stat";
|
|
224
|
+
const afterOpened = fs.fstatSync(descriptor, { bigint: true });
|
|
225
|
+
if (fileIdentity(afterOpened) !== fileIdentity(opened))
|
|
226
|
+
return {
|
|
227
|
+
stage,
|
|
228
|
+
reason: "opened-file-changed-during-read",
|
|
229
|
+
expected: fileIdentity(opened),
|
|
230
|
+
observed: fileIdentity(afterOpened),
|
|
231
|
+
observations: { before: opened, after: afterOpened },
|
|
232
|
+
};
|
|
233
|
+
stage = "post-read-realpath";
|
|
234
|
+
const afterPath = fs.realpathSync.native(runtime);
|
|
235
|
+
if (afterPath !== physicalPath)
|
|
236
|
+
return {
|
|
237
|
+
stage,
|
|
238
|
+
reason: "physical-target-changed",
|
|
239
|
+
expected: physicalPath,
|
|
240
|
+
observed: afterPath,
|
|
241
|
+
};
|
|
242
|
+
stage = "post-read-lexical-stat";
|
|
243
|
+
const afterLexical = fs.lstatSync(runtime, { bigint: true });
|
|
244
|
+
if (fileIdentity(afterLexical) !== fileIdentity(lexical))
|
|
245
|
+
return {
|
|
246
|
+
stage,
|
|
247
|
+
reason: "lexical-file-changed-during-read",
|
|
248
|
+
expected: fileIdentity(lexical),
|
|
249
|
+
observed: fileIdentity(afterLexical),
|
|
250
|
+
};
|
|
251
|
+
stage = "post-read-physical-stat";
|
|
252
|
+
const afterPhysical = fs.statSync(physicalPath, { bigint: true });
|
|
253
|
+
if (fileIdentity(afterPhysical) !== fileIdentity(physical))
|
|
254
|
+
return {
|
|
255
|
+
stage,
|
|
256
|
+
reason: "physical-file-changed-during-read",
|
|
257
|
+
expected: fileIdentity(physical),
|
|
258
|
+
observed: fileIdentity(afterPhysical),
|
|
259
|
+
};
|
|
260
|
+
const digest = hash.digest("hex");
|
|
261
|
+
E2ETrace.capabilityResolution("runtime-executable-identity-observed", {
|
|
262
|
+
runtime,
|
|
263
|
+
physicalPath,
|
|
264
|
+
startedAt: timing.startedAt,
|
|
265
|
+
finishedAt: new Date().toISOString(),
|
|
266
|
+
lexical: fileIdentity(lexical),
|
|
267
|
+
physical: fileIdentity(physical),
|
|
268
|
+
digest,
|
|
269
|
+
openedAtimeNs: String(opened.atimeNs),
|
|
270
|
+
afterOpenedAtimeNs: String(afterOpened.atimeNs),
|
|
271
|
+
openedBirthtimeNs: String(opened.birthtimeNs),
|
|
272
|
+
afterOpenedBirthtimeNs: String(afterOpened.birthtimeNs),
|
|
273
|
+
});
|
|
274
|
+
return digest;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
return {
|
|
277
|
+
stage,
|
|
278
|
+
reason: "filesystem-error",
|
|
279
|
+
observed: error instanceof Error ? error.message : String(error),
|
|
280
|
+
};
|
|
195
281
|
}
|
|
196
282
|
}
|
|
197
283
|
}
|
|
@@ -15,11 +15,13 @@ import { runBuild } from "../../../compiler/internal/build/runBuild";
|
|
|
15
15
|
import { readProjectConfig } from "../../../compiler/internal/project/readProjectConfig";
|
|
16
16
|
import { resolveOwningProjectConfig } from "../../../compiler/internal/project/resolveOwningProjectConfig";
|
|
17
17
|
import { resolveTsgo } from "../../../compiler/internal/resolveTsgo";
|
|
18
|
+
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
18
19
|
import { spawnNative } from "../../../compiler/internal/spawnNative";
|
|
19
20
|
import { E2ETrace } from "../../../internal/E2ETrace";
|
|
20
21
|
import { createCanonicalTempDirectory } from "../../../internal/createCanonicalTempDirectory";
|
|
21
22
|
import { runtimeExecutableIdentity } from "../../../internal/runtimeExecutableIdentity";
|
|
22
23
|
import { moduleResolutionBaseSelects } from "../../../plugin/internal/load/moduleResolutionBaseSelects";
|
|
24
|
+
import { PluginContentIdentities } from "../../../plugin/internal/source/PluginContentIdentities";
|
|
23
25
|
import { recordCacheFileUse } from "../../../plugin/internal/source/recordCacheFileUse";
|
|
24
26
|
import { buildSingleRootProject } from "../buildSingleRootProject";
|
|
25
27
|
import { inlineServedSourceMap } from "../inlineServedSourceMap";
|
|
@@ -684,6 +686,17 @@ function observePluginDescriptorInputOnce(record: {
|
|
|
684
686
|
(record.hash !== undefined && record.hash !== observedHash) ||
|
|
685
687
|
(record.realpath !== undefined && record.realpath !== observedRealpath) ||
|
|
686
688
|
(record.signature !== undefined && record.signature !== afterSignature);
|
|
689
|
+
// A missing path's signature is its nearest existing ancestor's metadata,
|
|
690
|
+
// so a write anywhere in that ancestor refuses the proof; the trace names
|
|
691
|
+
// which observation moved.
|
|
692
|
+
if (unstable)
|
|
693
|
+
E2ETrace.capabilityResolution("plugin-descriptor-input-unstable", {
|
|
694
|
+
resolved: record.resolved,
|
|
695
|
+
recordedSignature: record.signature,
|
|
696
|
+
beforeSignature,
|
|
697
|
+
afterSignature,
|
|
698
|
+
hashChanged: record.hash !== undefined && record.hash !== observedHash,
|
|
699
|
+
});
|
|
687
700
|
return `${JSON.stringify({
|
|
688
701
|
...record,
|
|
689
702
|
hash: observedHash,
|
|
@@ -1479,12 +1492,63 @@ function orphanCacheRoot(): string {
|
|
|
1479
1492
|
* Read afresh at every use, never remembered by path: a long-lived process can
|
|
1480
1493
|
* lower orphans before and after the compiler at that path is replaced, and an
|
|
1481
1494
|
* entry lowered by the new one must not be recorded under the old one's key for
|
|
1482
|
-
* a later process to adopt.
|
|
1495
|
+
* a later process to adopt. A fresh use proves an unchanged compiler from the
|
|
1496
|
+
* run's plugin cache records (`runtimeRecordStore`), which observe its metadata
|
|
1497
|
+
* again each time.
|
|
1483
1498
|
*/
|
|
1484
1499
|
function compilerIdentity(binary: string): string {
|
|
1485
|
-
return
|
|
1500
|
+
return (
|
|
1501
|
+
runtimeExecutableIdentity(binary, runtimeRecordStore()) ??
|
|
1502
|
+
crypto.randomUUID()
|
|
1503
|
+
);
|
|
1486
1504
|
}
|
|
1487
1505
|
|
|
1506
|
+
/**
|
|
1507
|
+
* The record store of this run's plugin cache root, or `undefined` without one.
|
|
1508
|
+
*
|
|
1509
|
+
* WARNING (#1726): every ttsx process and every descriptor evaluation streamed
|
|
1510
|
+
* the whole compiler executable (24.5 MB) to key its orphan and dependency
|
|
1511
|
+
* builds, although the bytes had not changed since the last process. The root
|
|
1512
|
+
* is the one a descriptor evaluator's parent load selected
|
|
1513
|
+
* (`TTSC_PLUGIN_RECORD_ROOT`), or the cache root of this run's manifest; a
|
|
1514
|
+
* process with neither streams as before and never selects a root itself.
|
|
1515
|
+
*/
|
|
1516
|
+
function runtimeRecordStore(): PluginContentIdentities.Store | undefined {
|
|
1517
|
+
const descriptorRoot =
|
|
1518
|
+
process.env.TTSC_PLUGIN_DESCRIPTOR_LOAD === "1"
|
|
1519
|
+
? SidecarEnvironment.read(process.env, "TTSC_PLUGIN_RECORD_ROOT")
|
|
1520
|
+
: undefined;
|
|
1521
|
+
const owner = RuntimeManifestRegistry.runtimeManifests().find(
|
|
1522
|
+
(candidate) =>
|
|
1523
|
+
typeof candidate.orphanCacheDir === "string" &&
|
|
1524
|
+
candidate.orphanCacheDir.length !== 0,
|
|
1525
|
+
);
|
|
1526
|
+
const root =
|
|
1527
|
+
descriptorRoot !== undefined && path.isAbsolute(descriptorRoot)
|
|
1528
|
+
? descriptorRoot
|
|
1529
|
+
: owner === undefined
|
|
1530
|
+
? undefined
|
|
1531
|
+
: path.dirname(owner.orphanCacheDir!);
|
|
1532
|
+
if (root === undefined) return undefined;
|
|
1533
|
+
// One store per root serves the process: its references only grow older,
|
|
1534
|
+
// which can make fewer stamps separable but never more, and each identity
|
|
1535
|
+
// still observes the compiler's metadata afresh.
|
|
1536
|
+
if (runtimeStore?.root !== root)
|
|
1537
|
+
runtimeStore = {
|
|
1538
|
+
root,
|
|
1539
|
+
store: PluginContentIdentities.open({
|
|
1540
|
+
projectRoot: root,
|
|
1541
|
+
cacheDir: root,
|
|
1542
|
+
env: process.env,
|
|
1543
|
+
}),
|
|
1544
|
+
};
|
|
1545
|
+
return runtimeStore.store;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
let runtimeStore:
|
|
1549
|
+
| { root: string; store: PluginContentIdentities.Store | undefined }
|
|
1550
|
+
| undefined;
|
|
1551
|
+
|
|
1488
1552
|
/** The version of this ttsc package, which owns the orphan post-processing. */
|
|
1489
1553
|
function ownPackageVersion(): string {
|
|
1490
1554
|
if (ownPackageVersionCache === undefined) {
|
|
@@ -2020,6 +2084,7 @@ function dependencyCachePaths(
|
|
|
2020
2084
|
try {
|
|
2021
2085
|
compilerProof = runtimeExecutableIdentity(
|
|
2022
2086
|
resolveTsgo({ cwd: path.dirname(tsconfig) }).binary,
|
|
2087
|
+
runtimeRecordStore(),
|
|
2023
2088
|
);
|
|
2024
2089
|
} catch {
|
|
2025
2090
|
// An unobservable executable gets a unique, non-reusable generation key.
|
|
@@ -2045,7 +2110,7 @@ function dependencyCachePaths(
|
|
|
2045
2110
|
function assertCompilerStillCurrent(tsconfig: string, proof?: string): void {
|
|
2046
2111
|
if (proof === undefined) return;
|
|
2047
2112
|
const binary = resolveTsgo({ cwd: path.dirname(tsconfig) }).binary;
|
|
2048
|
-
const current = runtimeExecutableIdentity(binary);
|
|
2113
|
+
const current = runtimeExecutableIdentity(binary, runtimeRecordStore());
|
|
2049
2114
|
if (current !== proof) {
|
|
2050
2115
|
E2ETrace.capabilityResolution("runtime-compiler-publication-refused", {
|
|
2051
2116
|
tsconfig,
|
|
@@ -34,7 +34,8 @@ import { LSPProjectInputDigest } from "./LSPProjectInputDigest";
|
|
|
34
34
|
* detected drift; unavailable markers or changes between reads are not a proof
|
|
35
35
|
* that the complete filesystem stayed fixed throughout capture.
|
|
36
36
|
*
|
|
37
|
-
* @param loaded The plugin load of the session
|
|
37
|
+
* @param loaded The plugin load of the session, with the project whose plugin
|
|
38
|
+
* cache proves its plugin sources from records.
|
|
38
39
|
* @returns The inputs, or `undefined` when the load no longer describes the
|
|
39
40
|
* filesystem and the selection has to be loaded again.
|
|
40
41
|
* @evidence contracts/common.md#principled-implementation The manifest groups candidate/source-file digests by directory. Recorded content and physical-target proofs and all plugin-source states are compared again before return; a detected mismatch rejects capture, while sequential reads and unproven paths do not certify every post-load change.
|
|
@@ -53,6 +54,7 @@ export function captureLSPPluginSelectionInputs(loaded: {
|
|
|
53
54
|
hostInputRealpaths: Readonly<Record<string, string | null>>;
|
|
54
55
|
hostInputs: readonly string[];
|
|
55
56
|
pluginSources: Readonly<Record<string, string>>;
|
|
57
|
+
project?: { root: string };
|
|
56
58
|
}): ILSPPluginSelectionInputs | undefined {
|
|
57
59
|
const excluded = new Set(
|
|
58
60
|
loaded.deferredHostInputs.map((file) => path.resolve(file)),
|
|
@@ -85,8 +87,15 @@ export function captureLSPPluginSelectionInputs(loaded: {
|
|
|
85
87
|
)
|
|
86
88
|
)
|
|
87
89
|
return undefined;
|
|
90
|
+
// The load's project names the plugin cache whose records prove the sources
|
|
91
|
+
// and the SDK, so a session start does not read them again (#1725).
|
|
88
92
|
for (const [directory, state] of Object.entries(loaded.pluginSources))
|
|
89
|
-
if (
|
|
93
|
+
if (
|
|
94
|
+
!pluginSourceStateHolds(directory, state, {
|
|
95
|
+
projectRoot: loaded.project?.root,
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
return undefined;
|
|
90
99
|
return {
|
|
91
100
|
omittedNames: GoSourceInputs.OMITTED_SOURCE_FILE_NAMES,
|
|
92
101
|
omittedSuffixes: GoSourceInputs.OMITTED_SOURCE_FILE_SUFFIXES,
|
|
@@ -13,6 +13,7 @@ import { spawnNative } from "../../../compiler/internal/spawnNative";
|
|
|
13
13
|
import { E2ETrace } from "../../../internal/E2ETrace";
|
|
14
14
|
import { resolveNodeBinary } from "../../../internal/resolveNodeBinary";
|
|
15
15
|
import { loadProjectPlugins } from "../../../plugin/internal/load/loadProjectPlugins";
|
|
16
|
+
import type { PluginContentIdentities } from "../../../plugin/internal/source/PluginContentIdentities";
|
|
16
17
|
import type { ITtscLoadedNativePlugin } from "../../../structures/internal/ITtscLoadedNativePlugin";
|
|
17
18
|
import type { ITtscParsedProjectConfig } from "../../../structures/internal/ITtscParsedProjectConfig";
|
|
18
19
|
import type { ITtscProjectIdentity } from "../../../structures/internal/ITtscProjectIdentity";
|
|
@@ -165,6 +166,13 @@ type LSPExecutionContext = {
|
|
|
165
166
|
*/
|
|
166
167
|
selectionInputs?: ILSPPluginSelectionInputs;
|
|
167
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Record store the confirming plugin load opened, which proves the Node
|
|
171
|
+
* runtime from metadata instead of streaming it again (#1726); absent for a
|
|
172
|
+
* project without plugins, which gains no cache directory.
|
|
173
|
+
*/
|
|
174
|
+
identities?: PluginContentIdentities.Store;
|
|
175
|
+
|
|
168
176
|
tsgoBinary: string;
|
|
169
177
|
};
|
|
170
178
|
|
|
@@ -196,6 +204,7 @@ function resolveTtscserverEnv(launch: LSPLaunchOptions): TtscserverEnvironment {
|
|
|
196
204
|
const context = resolveLspExecutionContext(launch);
|
|
197
205
|
const env = lspSidecarEnvironment({
|
|
198
206
|
cwd: context.projectContext?.logicalProjectRoot ?? path.resolve(launch.cwd),
|
|
207
|
+
identities: context.identities,
|
|
199
208
|
pluginConfigOrigin: context.projectContext?.pluginConfigOrigin,
|
|
200
209
|
tsgoBinary: context.tsgoBinary,
|
|
201
210
|
});
|
|
@@ -244,6 +253,7 @@ function resolveTtscserverEnv(launch: LSPLaunchOptions): TtscserverEnvironment {
|
|
|
244
253
|
|
|
245
254
|
function lspSidecarEnvironment(options: {
|
|
246
255
|
cwd: string;
|
|
256
|
+
identities: PluginContentIdentities.Store | undefined;
|
|
247
257
|
pluginConfigOrigin: string | undefined;
|
|
248
258
|
tsgoBinary: string;
|
|
249
259
|
}): NodeJS.ProcessEnv {
|
|
@@ -253,7 +263,7 @@ function lspSidecarEnvironment(options: {
|
|
|
253
263
|
SidecarEnvironment.read(process.env, "TTSC_TTSX_BINARY") ??
|
|
254
264
|
path.join(__dirname, "..", "..", "..", "launcher", "ttsx.js"),
|
|
255
265
|
});
|
|
256
|
-
const node = resolveNodeBinary(env, options.cwd);
|
|
266
|
+
const node = resolveNodeBinary(env, options.cwd, options.identities);
|
|
257
267
|
SidecarEnvironment.write(env, "TTSC_NODE_BINARY", node);
|
|
258
268
|
SidecarEnvironment.write(
|
|
259
269
|
env,
|
|
@@ -305,6 +315,7 @@ function resolveLspExecutionContext(
|
|
|
305
315
|
resolveFrom: __filename,
|
|
306
316
|
});
|
|
307
317
|
const initialProjectInputs = captureInitialLSPProjectInputs({
|
|
318
|
+
identities: loaded.identities,
|
|
308
319
|
nativePlugins: loaded.nativePlugins,
|
|
309
320
|
pluginConfigOrigin,
|
|
310
321
|
project: selectedProject,
|
|
@@ -323,6 +334,7 @@ function resolveLspExecutionContext(
|
|
|
323
334
|
resolveFrom: __filename,
|
|
324
335
|
});
|
|
325
336
|
const confirmedProjectInputs = captureInitialLSPProjectInputs({
|
|
337
|
+
identities: confirmation.identities,
|
|
326
338
|
nativePlugins: confirmation.nativePlugins,
|
|
327
339
|
pluginConfigOrigin,
|
|
328
340
|
project: confirmedProject,
|
|
@@ -345,6 +357,9 @@ function resolveLspExecutionContext(
|
|
|
345
357
|
initialProjectInputs: confirmedProjectInputs,
|
|
346
358
|
nativePlugins: confirmation.nativePlugins,
|
|
347
359
|
selectionInputs,
|
|
360
|
+
...(confirmation.identities === undefined
|
|
361
|
+
? {}
|
|
362
|
+
: { identities: confirmation.identities }),
|
|
348
363
|
projectContext: {
|
|
349
364
|
...confirmedProject.identity,
|
|
350
365
|
...(pluginConfigOrigin === undefined ? {} : { pluginConfigOrigin }),
|
|
@@ -377,6 +392,7 @@ function loadLSPProjectPlugins(
|
|
|
377
392
|
}
|
|
378
393
|
|
|
379
394
|
function captureInitialLSPProjectInputs(options: {
|
|
395
|
+
identities: PluginContentIdentities.Store | undefined;
|
|
380
396
|
nativePlugins: readonly ITtscLoadedNativePlugin[];
|
|
381
397
|
pluginConfigOrigin: string | undefined;
|
|
382
398
|
project: ITtscParsedProjectConfig;
|
|
@@ -414,6 +430,7 @@ function captureInitialLSPProjectInputs(options: {
|
|
|
414
430
|
}
|
|
415
431
|
const env = lspSidecarEnvironment({
|
|
416
432
|
cwd: options.project.root,
|
|
433
|
+
identities: options.identities,
|
|
417
434
|
pluginConfigOrigin: options.pluginConfigOrigin,
|
|
418
435
|
tsgoBinary: options.tsgoBinary,
|
|
419
436
|
});
|