ttsc 0.31.0 → 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/cmd/platform/main.go +2 -2
- package/internal/sourceprocess/contain_windows.go +10 -13
- package/internal/sourceprocess/started_windows.go +41 -0
- package/internal/sourceprocess/windows_started_publication_distinguishes_pending_from_refusal_test.go +76 -0
- package/internal/watchhelper/run.go +30 -20
- package/internal/watchhelper/run_other.go +4 -4
- package/internal/watchhelper/run_windows.go +471 -0
- package/internal/watchhelper/watchhelper.go +8 -2
- package/internal/watchhelper/windows_notifications_preserve_mutations_without_access_noise_test.go +506 -0
- 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/nativeBinary.d.ts +3 -3
- package/lib/internal/nativeBinary.js +3 -3
- 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 +24 -14
- package/lib/plugin/internal/load/loadProjectPlugins.js +141 -56
- 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 +48 -0
- package/lib/plugin/internal/source/GoEnvironmentReading.js +156 -0
- package/lib/plugin/internal/source/GoEnvironmentReading.js.map +1 -0
- package/lib/plugin/internal/source/NativeSourcePackages.d.ts +51 -13
- package/lib/plugin/internal/source/NativeSourcePackages.js +182 -27
- package/lib/plugin/internal/source/NativeSourcePackages.js.map +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +42 -3
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +68 -7
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.d.ts +5 -3
- package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.js +14 -8
- package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.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 +53 -19
- package/lib/plugin/internal/source/SourcePluginWorkspace.js +111 -22
- package/lib/plugin/internal/source/SourcePluginWorkspace.js.map +1 -1
- package/lib/plugin/internal/source/buildSourcePlugin.d.ts +34 -18
- package/lib/plugin/internal/source/buildSourcePlugin.js +52 -24
- package/lib/plugin/internal/source/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/source/computeCacheKey.d.ts +25 -7
- package/lib/plugin/internal/source/computeCacheKey.js +85 -34
- 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 +75 -102
- 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/pluginModuleReplaceDirectories.d.ts +6 -5
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js +10 -17
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.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/nativeBinary.ts +3 -3
- 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 +421 -211
- package/src/plugin/internal/readCapabilityResolution.ts +17 -6
- package/src/plugin/internal/source/GoEnvironmentReading.ts +178 -0
- package/src/plugin/internal/source/NativeSourcePackages.ts +365 -48
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +83 -5
- package/src/plugin/internal/source/PluginBuildEnvironmentWitness.ts +18 -8
- 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 +148 -25
- package/src/plugin/internal/source/buildSourcePlugin.ts +104 -36
- package/src/plugin/internal/source/computeCacheKey.ts +129 -55
- package/src/plugin/internal/source/hashPluginBuildEnvironment.ts +152 -105
- 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/pluginModuleReplaceDirectories.ts +13 -25
- 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
|
@@ -5,6 +5,7 @@ import { createCanonicalTempDirectory } from "../../../internal/createCanonicalT
|
|
|
5
5
|
import { resolveNodeBinary } from "../../../internal/resolveNodeBinary";
|
|
6
6
|
import { hasProjectPluginEntries } from "../../../plugin/internal/load/hasProjectPluginEntries";
|
|
7
7
|
import { loadProjectPlugins } from "../../../plugin/internal/load/loadProjectPlugins";
|
|
8
|
+
import { PluginContentIdentities } from "../../../plugin/internal/source/PluginContentIdentities";
|
|
8
9
|
import type { ITtscLoadedNativePlugin } from "../../../structures/internal/ITtscLoadedNativePlugin";
|
|
9
10
|
import type { ITtscParsedProjectConfig } from "../../../structures/internal/ITtscParsedProjectConfig";
|
|
10
11
|
import type { ITtscProjectInputSnapshot } from "../../../structures/internal/ITtscProjectInputSnapshot";
|
|
@@ -70,19 +71,37 @@ export namespace BuildExecution {
|
|
|
70
71
|
* Merge extra environment variables over `process.env`, always injecting
|
|
71
72
|
* `TTSC_NODE_BINARY` selected by the runtime capability owner. Explicit
|
|
72
73
|
* compatible overrides can select a different Node executable; this is not
|
|
73
|
-
* necessarily the current process binary.
|
|
74
|
+
* necessarily the current process binary. An invocation that loaded plugins
|
|
75
|
+
* passes its record store, so the runtime is proven from metadata instead of
|
|
76
|
+
* streamed again before every native spawn (#1723).
|
|
74
77
|
*/
|
|
75
78
|
function mergeEnv(
|
|
76
|
-
extra
|
|
77
|
-
cwd: string
|
|
79
|
+
extra: NodeJS.ProcessEnv | undefined,
|
|
80
|
+
cwd: string,
|
|
81
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
78
82
|
...later: readonly (NodeJS.ProcessEnv | undefined)[]
|
|
79
83
|
): NodeJS.ProcessEnv {
|
|
80
84
|
const env = SidecarEnvironment.merge(process.env, extra, ...later);
|
|
81
|
-
const node = resolveNodeBinary(env, cwd);
|
|
85
|
+
const node = resolveNodeBinary(env, cwd, identities);
|
|
82
86
|
SidecarEnvironment.write(env, "TTSC_NODE_BINARY", node);
|
|
83
87
|
return env;
|
|
84
88
|
}
|
|
85
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Merge extra environment variables over `process.env` for a spawn of the
|
|
92
|
+
* selected TypeScript-Go compiler itself.
|
|
93
|
+
*
|
|
94
|
+
* WARNING (#1726): the compiler never reads `TTSC_NODE_BINARY`, which only
|
|
95
|
+
* plugin sidecars consume (`mergeEnv`). Selecting it streamed the 85 MB Node
|
|
96
|
+
* executable twice and probed it on every launch, plugins or not, about 0.2 s
|
|
97
|
+
* of a 0.5 s build without plugins.
|
|
98
|
+
*/
|
|
99
|
+
function compilerEnv(
|
|
100
|
+
extra: NodeJS.ProcessEnv | undefined,
|
|
101
|
+
): NodeJS.ProcessEnv {
|
|
102
|
+
return SidecarEnvironment.merge(process.env, extra);
|
|
103
|
+
}
|
|
104
|
+
|
|
86
105
|
/**
|
|
87
106
|
* Build the environment for a native plugin spawn. Injects `TTSC_TSGO_BINARY`
|
|
88
107
|
* and `TTSC_TTSX_BINARY` alongside the base env from `mergeEnv`, plus
|
|
@@ -123,6 +142,7 @@ export namespace BuildExecution {
|
|
|
123
142
|
path.join(__dirname, "..", "..", "..", "launcher", "ttsx.js"),
|
|
124
143
|
},
|
|
125
144
|
execution.projectRoot,
|
|
145
|
+
execution.identities,
|
|
126
146
|
extra,
|
|
127
147
|
// The invocation's resolved compiler owns the final environment layer.
|
|
128
148
|
{ TTSC_TSGO_BINARY: execution.tsgo.binary },
|
|
@@ -453,7 +473,7 @@ export namespace BuildExecution {
|
|
|
453
473
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The caught resolution failure is legitimate only for commands not requiring a project; ordinary compilation failures do not enter this bypass.
|
|
454
474
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain project-independent commands, existing-project behavior and null applicability; the catch comment states its deliberate broad premise.
|
|
455
475
|
* @evidence contracts/portability.md#os-neutral-implementation Invocation cwd is resolved natively and spawnNative receives executable/argv separately with platform-aware environment merging.
|
|
456
|
-
* @evidence contracts/performance.md#efficient-algorithms Flag selection scans forwarded argument/name text before config IO. An applicable lane includes native cwd/config resolution, binary
|
|
476
|
+
* @evidence contracts/performance.md#efficient-algorithms Flag selection scans forwarded argument/name text before config IO. An applicable lane includes native cwd/config resolution, binary lookup, argv/env composition without runtime capability work (#1726), complete captured output and diagnostic normalization; one requested command does not bound its native duration or output bytes.
|
|
457
477
|
*
|
|
458
478
|
* @evidenceExclude contracts/performance.md#reuse-equivalent-work A project probe and effectful terminal invocation establish no retained or shared cross-request result.
|
|
459
479
|
*
|
|
@@ -482,7 +502,7 @@ export namespace BuildExecution {
|
|
|
482
502
|
const tsgo = resolveTsgo({ ...options, cwd });
|
|
483
503
|
const res = spawnNative(tsgo.binary, [...(options.passthrough ?? [])], {
|
|
484
504
|
cwd,
|
|
485
|
-
env:
|
|
505
|
+
env: compilerEnv(options.env),
|
|
486
506
|
encoding: "utf8",
|
|
487
507
|
});
|
|
488
508
|
if (res.error) {
|
|
@@ -796,7 +816,7 @@ export namespace BuildExecution {
|
|
|
796
816
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Supported compiler options express the check contract without intercepting writes or replacing compiler APIs; spawn errors remain errors.
|
|
797
817
|
* @evidence contracts/common.md#meaningful-documentation Native prose explains the no-emit use and load-bearing argument precedence.
|
|
798
818
|
* @evidence contracts/portability.md#os-neutral-implementation spawnNative uses the selected executable, separate argv and project cwd; environment composition handles native variable aliases and output text decoding is explicit UTF-8.
|
|
799
|
-
* @evidence contracts/performance.md#efficient-algorithms One argv composition includes delegated option-presence classification, threading/isolation text and argument copies. Environment composition
|
|
819
|
+
* @evidence contracts/performance.md#efficient-algorithms One argv composition includes delegated option-presence classification, threading/isolation text and argument copies. Environment composition only layers variables; the compiler reads no Node selection, so no runtime capability probe precedes the launch (#1726). Complete capture/decoding and diagnostic normalization follow. Work/storage depend on argument/env/path/report bytes and native child work, without an asserted measured cost ranking.
|
|
800
820
|
*
|
|
801
821
|
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This executes the requested compiler pass; equivalence with other phases must be established by orchestration rather than caching a result here.
|
|
802
822
|
*
|
|
@@ -822,7 +842,7 @@ export namespace BuildExecution {
|
|
|
822
842
|
],
|
|
823
843
|
{
|
|
824
844
|
cwd: execution.compilerSelection.compilerArgsCwd,
|
|
825
|
-
env:
|
|
845
|
+
env: compilerEnv(options.env),
|
|
826
846
|
encoding: "utf8",
|
|
827
847
|
},
|
|
828
848
|
);
|
|
@@ -856,7 +876,7 @@ export namespace BuildExecution {
|
|
|
856
876
|
options: RunBuildOptions,
|
|
857
877
|
args: readonly string[],
|
|
858
878
|
): TtscBuildResult {
|
|
859
|
-
const env =
|
|
879
|
+
const env = compilerEnv(options.env);
|
|
860
880
|
const userOptions = readEffectiveCompilerOptions(
|
|
861
881
|
execution.project,
|
|
862
882
|
options.passthrough,
|
|
@@ -1183,19 +1203,31 @@ export namespace BuildExecution {
|
|
|
1183
1203
|
const tsgo = resolveTsgo({ ...options, cwd: projectRoot });
|
|
1184
1204
|
let pluginSetupFailure: TtscBuildResult | undefined;
|
|
1185
1205
|
let nativePlugins: ITtscLoadedNativePlugin[] = [];
|
|
1206
|
+
// Opened only for an invocation that loads plugins, so a project without
|
|
1207
|
+
// any never gains a cache directory; the load and every later native spawn
|
|
1208
|
+
// of this invocation prove their unchanged inputs through it (#1722, #1723).
|
|
1209
|
+
let identities: PluginContentIdentities.Store | undefined;
|
|
1186
1210
|
try {
|
|
1187
1211
|
if (
|
|
1188
1212
|
compilerSelection.inspectionError === undefined &&
|
|
1189
1213
|
hasProjectPluginEntries(project, options.plugins)
|
|
1190
1214
|
) {
|
|
1215
|
+
const cacheDir =
|
|
1216
|
+
options.cacheDir ??
|
|
1217
|
+
SidecarEnvironment.read(options.env, "TTSC_CACHE_DIR");
|
|
1218
|
+
const env = inheritedSidecarEnv(options.env, options.binary);
|
|
1219
|
+
identities = PluginContentIdentities.open({
|
|
1220
|
+
projectRoot,
|
|
1221
|
+
cacheDir,
|
|
1222
|
+
env,
|
|
1223
|
+
});
|
|
1191
1224
|
nativePlugins = loadProjectPlugins({
|
|
1192
1225
|
binary: resolveBinary(options) ?? "",
|
|
1193
|
-
cacheDir
|
|
1194
|
-
options.cacheDir ??
|
|
1195
|
-
SidecarEnvironment.read(options.env, "TTSC_CACHE_DIR"),
|
|
1226
|
+
cacheDir,
|
|
1196
1227
|
cwd,
|
|
1197
1228
|
entries: options.plugins,
|
|
1198
|
-
env
|
|
1229
|
+
env,
|
|
1230
|
+
identities,
|
|
1199
1231
|
onWatchInputs: options.onWatchInputs,
|
|
1200
1232
|
pluginConfigDir: options.pluginConfigDir,
|
|
1201
1233
|
projectRoot,
|
|
@@ -1215,6 +1247,7 @@ export namespace BuildExecution {
|
|
|
1215
1247
|
return {
|
|
1216
1248
|
compilerSelection,
|
|
1217
1249
|
cwd,
|
|
1250
|
+
...(identities === undefined ? {} : { identities }),
|
|
1218
1251
|
nativePlugins,
|
|
1219
1252
|
pluginConfigDir: resolvePluginConfigDir({
|
|
1220
1253
|
cwd,
|
|
@@ -2,6 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import { resolveNodeBinary } from "../../internal/resolveNodeBinary";
|
|
4
4
|
import { loadProjectPlugins } from "../../plugin/internal/load/loadProjectPlugins";
|
|
5
|
+
import type { PluginContentIdentities } from "../../plugin/internal/source/PluginContentIdentities";
|
|
5
6
|
import type { ITtscCompilerContext } from "../../structures/ITtscCompilerContext";
|
|
6
7
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
7
8
|
import { ResidentTransformProcess } from "./ResidentTransformProcess";
|
|
@@ -94,7 +95,13 @@ export function startResidentTransform(
|
|
|
94
95
|
],
|
|
95
96
|
binary: host.binary,
|
|
96
97
|
cwd: project.root,
|
|
97
|
-
env: residentEnv(
|
|
98
|
+
env: residentEnv(
|
|
99
|
+
context,
|
|
100
|
+
project.root,
|
|
101
|
+
tsgoBinary,
|
|
102
|
+
loaded.nativePlugins,
|
|
103
|
+
loaded.identities,
|
|
104
|
+
),
|
|
98
105
|
});
|
|
99
106
|
return { process: resident, projectRoot: project.root };
|
|
100
107
|
}
|
|
@@ -106,13 +113,15 @@ export function startResidentTransform(
|
|
|
106
113
|
* plugin config anchor (an embedder compiling through a generated wrapper
|
|
107
114
|
* tsconfig) so config-file discovery walks the real project instead of the
|
|
108
115
|
* wrapper's temp-dir ancestry, and forwards linked transform plugins via
|
|
109
|
-
* `TTSC_LINKED_PLUGINS_JSON`.
|
|
116
|
+
* `TTSC_LINKED_PLUGINS_JSON`. The load's record store proves the Node runtime
|
|
117
|
+
* from metadata instead of streaming it again (#1723).
|
|
110
118
|
*/
|
|
111
119
|
function residentEnv(
|
|
112
120
|
context: ITtscCompilerContext,
|
|
113
121
|
projectRoot: string,
|
|
114
122
|
tsgoBinary: string,
|
|
115
123
|
nativePlugins: readonly ITtscLoadedNativePlugin[],
|
|
124
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
116
125
|
): NodeJS.ProcessEnv {
|
|
117
126
|
const pluginConfigDir = resolvePluginConfigDir(context);
|
|
118
127
|
const env = SidecarEnvironment.merge(
|
|
@@ -128,7 +137,7 @@ function residentEnv(
|
|
|
128
137
|
context.env,
|
|
129
138
|
{ TTSC_TSGO_BINARY: tsgoBinary },
|
|
130
139
|
);
|
|
131
|
-
const node = resolveNodeBinary(env, projectRoot);
|
|
140
|
+
const node = resolveNodeBinary(env, projectRoot, identities);
|
|
132
141
|
SidecarEnvironment.write(env, "TTSC_NODE_BINARY", node);
|
|
133
142
|
// The anchor is per-invocation state owned by this host: when this run
|
|
134
143
|
// declared none (and the caller's env does not name one), drop any value
|
|
@@ -5,6 +5,7 @@ import { collectProjectHostInputs } from "../../plugin/internal/load/collectProj
|
|
|
5
5
|
import { hashHostInputPaths } from "../../plugin/internal/load/hashHostInputPaths";
|
|
6
6
|
import { loadProjectPlugins } from "../../plugin/internal/load/loadProjectPlugins";
|
|
7
7
|
import { realpathHostInputPaths } from "../../plugin/internal/load/realpathHostInputPaths";
|
|
8
|
+
import type { PluginContentIdentities } from "../../plugin/internal/source/PluginContentIdentities";
|
|
8
9
|
import type { ITtscCompilerContext } from "../../structures/ITtscCompilerContext";
|
|
9
10
|
import type { ITtscCompilerTransformation } from "../../structures/ITtscCompilerTransformation";
|
|
10
11
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
@@ -301,6 +302,7 @@ function transformProjectWithPlugins(
|
|
|
301
302
|
tsgoBinary,
|
|
302
303
|
loaded.nativePlugins,
|
|
303
304
|
checks,
|
|
305
|
+
loaded.identities,
|
|
304
306
|
);
|
|
305
307
|
const checkedHostInputs = mergeHostInputs(
|
|
306
308
|
loaded.hostInputs,
|
|
@@ -414,6 +416,7 @@ function transformProjectWithPlugins(
|
|
|
414
416
|
tsgoBinary,
|
|
415
417
|
loaded.nativePlugins,
|
|
416
418
|
plugin,
|
|
419
|
+
loaded.identities,
|
|
417
420
|
),
|
|
418
421
|
},
|
|
419
422
|
);
|
|
@@ -688,6 +691,7 @@ function runNativeChecks(
|
|
|
688
691
|
tsgoBinary: string,
|
|
689
692
|
nativePlugins: readonly ITtscLoadedNativePlugin[],
|
|
690
693
|
checks: readonly ITtscLoadedNativePlugin[],
|
|
694
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
691
695
|
): TtscBuildResult {
|
|
692
696
|
let result: TtscBuildResult = {
|
|
693
697
|
diagnostics: [],
|
|
@@ -716,6 +720,7 @@ function runNativeChecks(
|
|
|
716
720
|
tsgoBinary,
|
|
717
721
|
nativePlugins,
|
|
718
722
|
plugin,
|
|
723
|
+
identities,
|
|
719
724
|
),
|
|
720
725
|
},
|
|
721
726
|
);
|
|
@@ -804,7 +809,9 @@ function serializeNativePlugins(
|
|
|
804
809
|
* the caller declared a plugin config anchor (an embedder compiling through a
|
|
805
810
|
* generated wrapper tsconfig) so config-file discovery walks the real project
|
|
806
811
|
* instead of the wrapper's temp-dir ancestry. For transform plugins, also
|
|
807
|
-
* passes `TTSC_LINKED_PLUGINS_JSON` when linked sources are present.
|
|
812
|
+
* passes `TTSC_LINKED_PLUGINS_JSON` when linked sources are present. The load's
|
|
813
|
+
* record store proves the Node runtime from metadata instead of streaming it
|
|
814
|
+
* before every spawn of every generation (#1723).
|
|
808
815
|
*/
|
|
809
816
|
function nativePluginEnv(
|
|
810
817
|
options: ITtscCompilerContext,
|
|
@@ -812,6 +819,7 @@ function nativePluginEnv(
|
|
|
812
819
|
tsgoBinary: string,
|
|
813
820
|
nativePlugins?: readonly ITtscLoadedNativePlugin[],
|
|
814
821
|
plugin?: ITtscLoadedNativePlugin,
|
|
822
|
+
identities?: PluginContentIdentities.Store,
|
|
815
823
|
): NodeJS.ProcessEnv {
|
|
816
824
|
const pluginConfigDir = resolvePluginConfigDir(options);
|
|
817
825
|
const env = SidecarEnvironment.merge(
|
|
@@ -827,7 +835,7 @@ function nativePluginEnv(
|
|
|
827
835
|
options.env,
|
|
828
836
|
{ TTSC_TSGO_BINARY: tsgoBinary },
|
|
829
837
|
);
|
|
830
|
-
const node = resolveNodeBinary(env, projectRoot);
|
|
838
|
+
const node = resolveNodeBinary(env, projectRoot, identities);
|
|
831
839
|
SidecarEnvironment.write(env, "TTSC_NODE_BINARY", node);
|
|
832
840
|
// The anchor is per-invocation state owned by this host: when this run
|
|
833
841
|
// declared none (and the caller's env does not name one), drop any value
|
|
@@ -4,6 +4,8 @@ import path from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { captureProcessOutput } from "../compiler/internal/captureProcessOutput";
|
|
6
6
|
import { SidecarEnvironment } from "../compiler/internal/sharedHost/SidecarEnvironment";
|
|
7
|
+
import type { PluginContentIdentities } from "../plugin/internal/source/PluginContentIdentities";
|
|
8
|
+
import { PluginLoadAnswers } from "../plugin/internal/source/PluginLoadAnswers";
|
|
7
9
|
import { E2ETrace } from "./E2ETrace";
|
|
8
10
|
import type { IJavaScriptRuntimeCapabilities } from "./IJavaScriptRuntimeCapabilities";
|
|
9
11
|
import { OwnedSynchronousProcess } from "./OwnedSynchronousProcess";
|
|
@@ -20,28 +22,56 @@ import { spawnSyncWithLowDescriptors } from "./spawnSyncWithLowDescriptors";
|
|
|
20
22
|
* Cache-ineligible candidates do not acquire executable proofs used only by
|
|
21
23
|
* cache lookup and publication.
|
|
22
24
|
*
|
|
23
|
-
*
|
|
25
|
+
* With a record store, the executable identity is proven from metadata and a
|
|
26
|
+
* probe answer recorded for that identity is reused by a later process (#1723);
|
|
27
|
+
* a recorded answer must still name an executable this runtime is.
|
|
28
|
+
*
|
|
29
|
+
* @param runtime The interpreter to probe.
|
|
30
|
+
* @param env Caller environment merged over this process's.
|
|
31
|
+
* @param cwd Working directory of the probe.
|
|
32
|
+
* @param identities Optional record store of the caller's plugin cache.
|
|
33
|
+
* @evidence contracts/common.md#principled-implementation A child reports its own feature availability and executable; byte-aware before/after identity and same-executable proof authorize reuse only for a stable absolute runtime without NODE_OPTIONS preload authority, in process or through an answer recorded under that identity.
|
|
24
34
|
* @evidence contracts/common.md#clear-and-simple-design One probe owner coordinates identity, spawning and parsing; the shared fingerprint helper owns file-content proof and the low-descriptor helper owns the POSIX launch distinction.
|
|
25
35
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Feature availability comes from the actual interpreter rather than its name; descriptor fallback handles a supported kernel constraint and failures produce unsupported capabilities, not fabricated success.
|
|
26
36
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain measured capabilities, reuse restrictions and freshness, with comments separating platform launch and cache permission from tags.
|
|
27
37
|
* @evidence contracts/portability.md#os-neutral-implementation Shared environment merge and lookup apply native name identity to caller precedence and NODE_OPTIONS preload authority, including Windows aliases; Node spawn receives an executable and argv without shell syntax, and only POSIX descriptor exhaustion uses the isolated broker.
|
|
28
|
-
* @evidence contracts/performance.md#efficient-algorithms Environment merge/name handling first decides cache eligibility. Eligible hits read B executable bytes; eligible misses acquire before/after
|
|
29
|
-
* @evidence contracts/performance.md#reuse-equivalent-work Stable absolute candidates that report their own executable share measured capability results, including false feature flags; changed executable bytes, link/target identity, preload options or wrapper identity require another probe, while failed probes without executable identity are not reused.
|
|
38
|
+
* @evidence contracts/performance.md#efficient-algorithms Environment merge/name handling first decides cache eligibility. Eligible hits prove the executable from a record (three stats and one small read) or read B executable bytes; eligible misses acquire before/after identities around the actual probe. Ineligible calls retain the fresh child without reading executable bytes solely for the forbidden cache. Probe spawning/parsing, a possible descriptor-exhaustion retry and capture-file reads add text/environment/native lookup costs and transient output storage; this adapter sets no explicit byte quota.
|
|
39
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Stable absolute candidates that report their own executable share measured capability results, including false feature flags, within the process and across processes through the record store keyed by the full identity; changed executable bytes, link/target identity, preload options or wrapper identity require another probe, while failed probes without executable identity are not reused.
|
|
30
40
|
* @evidence contracts/performance.md#bound-retention-and-release-resources The synchronous probe owns child completion and fallback captures; finally attempts capture close/removal, whose helper suppresses cleanup failures, so native/file release is unconfirmed on failure. Capability entries retain absolute spellings and path/identity text with no eviction quota; failed identity validation can remove an entry. Returned capability copies transfer to callers.
|
|
31
41
|
*/
|
|
32
42
|
export function javascriptRuntimeCapabilities(
|
|
33
43
|
runtime: string,
|
|
34
44
|
env: NodeJS.ProcessEnv,
|
|
35
45
|
cwd: string,
|
|
46
|
+
identities?: PluginContentIdentities.Store,
|
|
36
47
|
): IJavaScriptRuntimeCapabilities {
|
|
37
48
|
const effectiveEnv = SidecarEnvironment.merge(process.env, env);
|
|
38
49
|
const cacheKey = runtimeCapabilityCacheKey(runtime, effectiveEnv);
|
|
39
50
|
const beforeIdentity =
|
|
40
|
-
cacheKey === undefined
|
|
51
|
+
cacheKey === undefined
|
|
52
|
+
? undefined
|
|
53
|
+
: runtimeExecutableIdentity(runtime, identities);
|
|
41
54
|
if (cacheKey !== undefined && beforeIdentity !== undefined) {
|
|
42
55
|
const cached = runtimeCapabilityCache.get(cacheKey);
|
|
43
56
|
if (cached?.identity === beforeIdentity) return { ...cached.capabilities };
|
|
44
57
|
runtimeCapabilityCache.delete(cacheKey);
|
|
58
|
+
// WARNING (#1723): a launch is a new process, so the memo above is empty
|
|
59
|
+
// on every CLI run. The same proven executable answers the same probe; the
|
|
60
|
+
// record store carries that answer across processes.
|
|
61
|
+
const recorded = recordedCapabilities(
|
|
62
|
+
PluginLoadAnswers.read(identities, RUNTIME_CAPABILITIES, [
|
|
63
|
+
cacheKey,
|
|
64
|
+
beforeIdentity,
|
|
65
|
+
]),
|
|
66
|
+
runtime,
|
|
67
|
+
);
|
|
68
|
+
if (recorded !== undefined) {
|
|
69
|
+
runtimeCapabilityCache.set(cacheKey, {
|
|
70
|
+
capabilities: { ...recorded },
|
|
71
|
+
identity: beforeIdentity,
|
|
72
|
+
});
|
|
73
|
+
return recorded;
|
|
74
|
+
}
|
|
45
75
|
}
|
|
46
76
|
const args = [
|
|
47
77
|
"-e",
|
|
@@ -113,7 +143,9 @@ export function javascriptRuntimeCapabilities(
|
|
|
113
143
|
// This removes a process spawn from the common path without
|
|
114
144
|
// authorizing a replaced or redirected runtime in a long-lived host.
|
|
115
145
|
const afterIdentity =
|
|
116
|
-
cacheKey === undefined
|
|
146
|
+
cacheKey === undefined
|
|
147
|
+
? undefined
|
|
148
|
+
: runtimeExecutableIdentity(runtime, identities);
|
|
117
149
|
if (
|
|
118
150
|
cacheKey !== undefined &&
|
|
119
151
|
capabilities.executable !== undefined &&
|
|
@@ -125,10 +157,44 @@ export function javascriptRuntimeCapabilities(
|
|
|
125
157
|
capabilities: { ...capabilities },
|
|
126
158
|
identity: afterIdentity,
|
|
127
159
|
});
|
|
160
|
+
PluginLoadAnswers.write(
|
|
161
|
+
identities,
|
|
162
|
+
RUNTIME_CAPABILITIES,
|
|
163
|
+
[cacheKey, afterIdentity],
|
|
164
|
+
capabilities,
|
|
165
|
+
);
|
|
128
166
|
}
|
|
129
167
|
return capabilities;
|
|
130
168
|
}
|
|
131
169
|
|
|
170
|
+
/** Answer family of measured runtime capabilities (`PluginLoadAnswers`). */
|
|
171
|
+
const RUNTIME_CAPABILITIES = "javascript-runtime-capabilities";
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* A recorded probe answer in the shape the probe produces, still naming an
|
|
175
|
+
* executable this runtime is, or `undefined`.
|
|
176
|
+
*/
|
|
177
|
+
function recordedCapabilities(
|
|
178
|
+
value: unknown,
|
|
179
|
+
runtime: string,
|
|
180
|
+
): IJavaScriptRuntimeCapabilities | undefined {
|
|
181
|
+
if (typeof value !== "object" || value === null) return undefined;
|
|
182
|
+
const recorded = value as Partial<IJavaScriptRuntimeCapabilities>;
|
|
183
|
+
if (
|
|
184
|
+
typeof recorded.bun !== "boolean" ||
|
|
185
|
+
typeof recorded.registerHooks !== "boolean" ||
|
|
186
|
+
typeof recorded.executable !== "string" ||
|
|
187
|
+
!path.isAbsolute(recorded.executable) ||
|
|
188
|
+
!sameRuntimeExecutable(runtime, recorded.executable)
|
|
189
|
+
)
|
|
190
|
+
return undefined;
|
|
191
|
+
return {
|
|
192
|
+
bun: recorded.bun,
|
|
193
|
+
executable: recorded.executable,
|
|
194
|
+
registerHooks: recorded.registerHooks,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
132
198
|
type RuntimeCapabilityCacheEntry = {
|
|
133
199
|
capabilities: IJavaScriptRuntimeCapabilities;
|
|
134
200
|
identity: string;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* The rules that find ttsc's platform binary (an absolute `TTSC_BINARY`, the
|
|
5
5
|
* per-platform package, then the repository's own dev layout) are ttsc's alone.
|
|
6
6
|
* A tool host that runs one of that binary's helper commands, as
|
|
7
|
-
* `@ttsc/unplugin` runs its
|
|
8
|
-
* helper always comes from the binary ttsc itself uses and no consumer
|
|
9
|
-
* a copy of the rules.
|
|
7
|
+
* `@ttsc/unplugin` runs its native watch helpers, imports them from here, so
|
|
8
|
+
* the helper always comes from the binary ttsc itself uses and no consumer
|
|
9
|
+
* carries a copy of the rules.
|
|
10
10
|
*/
|
|
11
11
|
export { resolveBinary } from "../compiler/internal/resolveBinary";
|
|
@@ -22,5 +22,6 @@ export * from "../plugin/internal/source/pluginSourceDigest";
|
|
|
22
22
|
export * from "../plugin/internal/source/pluginSourceState";
|
|
23
23
|
export * from "../plugin/internal/source/pluginSourceStateHolds";
|
|
24
24
|
export * from "../plugin/internal/source/processPluginBuildEnvironment";
|
|
25
|
+
export * from "../plugin/internal/source/provenPluginSourceDigest";
|
|
25
26
|
export * from "../plugin/internal/source/PluginBuildEnvironmentReadings";
|
|
26
27
|
export * from "../plugin/internal/source/prunesPluginSourceDirectory";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SidecarEnvironment } from "../compiler/internal/sharedHost/SidecarEnvironment";
|
|
2
|
+
import type { PluginContentIdentities } from "../plugin/internal/source/PluginContentIdentities";
|
|
2
3
|
import { javascriptRuntimeCapabilities } from "./javascriptRuntimeCapabilities";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -7,6 +8,10 @@ import { javascriptRuntimeCapabilities } from "./javascriptRuntimeCapabilities";
|
|
|
7
8
|
* Bun can directly evaluate a descriptor, but it does not implement the
|
|
8
9
|
* synchronous `module.registerHooks` contract used by those loaders.
|
|
9
10
|
*
|
|
11
|
+
* @param env Effective environment naming `TTSC_NODE_BINARY`.
|
|
12
|
+
* @param cwd Working directory of the probes.
|
|
13
|
+
* @param identities Optional record store that lets probes of an unchanged
|
|
14
|
+
* runtime be answered across processes (#1723).
|
|
10
15
|
* @evidence contracts/common.md#principled-implementation Ordered candidates are accepted only after an actual runtime probe reports non-Bun registerHooks support and its absolute executable; names alone do not establish the loader capability.
|
|
11
16
|
* @evidence contracts/common.md#clear-and-simple-design Candidate precedence and duplicate suppression remain here, while the shared probe owns launch, capability parsing and freshness policy.
|
|
12
17
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The node spelling is a supported final discovery candidate, not an assumed successful runtime; incompatible candidates are skipped without patching modules or globals.
|
|
@@ -19,6 +24,7 @@ import { javascriptRuntimeCapabilities } from "./javascriptRuntimeCapabilities";
|
|
|
19
24
|
export function resolveNodeBinary(
|
|
20
25
|
env: NodeJS.ProcessEnv = process.env,
|
|
21
26
|
cwd: string = process.cwd(),
|
|
27
|
+
identities?: PluginContentIdentities.Store,
|
|
22
28
|
): string | undefined {
|
|
23
29
|
const candidates = [
|
|
24
30
|
SidecarEnvironment.read(env, "TTSC_NODE_BINARY"),
|
|
@@ -31,7 +37,12 @@ export function resolveNodeBinary(
|
|
|
31
37
|
if (candidate === undefined || candidate.trim() === "") continue;
|
|
32
38
|
if (seen.has(candidate)) continue;
|
|
33
39
|
seen.add(candidate);
|
|
34
|
-
const capabilities = javascriptRuntimeCapabilities(
|
|
40
|
+
const capabilities = javascriptRuntimeCapabilities(
|
|
41
|
+
candidate,
|
|
42
|
+
env,
|
|
43
|
+
cwd,
|
|
44
|
+
identities,
|
|
45
|
+
);
|
|
35
46
|
if (
|
|
36
47
|
!capabilities.bun &&
|
|
37
48
|
capabilities.registerHooks &&
|