ttsc 0.32.1 → 0.33.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/cmd/ttsc-cache/account.go +94 -0
- package/cmd/ttsc-cache/interruption_test.go +176 -0
- package/cmd/ttsc-cache/main.go +252 -0
- package/cmd/ttsc-cache/merge.go +324 -0
- package/cmd/ttsc-cache/merge_test.go +161 -0
- package/cmd/ttsc-cache/prepare.go +330 -0
- package/cmd/ttsc-cache/prepare_test.go +456 -0
- package/cmd/ttsc-cache/protocol_test.go +119 -0
- package/cmd/ttsc-cache/publisher_seal_test.go +135 -0
- package/cmd/ttsc-cache/seal.go +427 -0
- package/cmd/ttsc-cache/stock_go_failure_test.go +94 -0
- package/cmd/ttsc-cache/stock_go_test.go +163 -0
- package/cmd/ttsc-cache/store.go +249 -0
- package/cmd/ttsc-cache/store_test.go +104 -0
- package/cmd/ttsc-cache/tuple.go +107 -0
- package/cmd/ttsc-cache/tuple_test.go +62 -0
- package/cmd/ttsc-cache/usage.go +73 -0
- package/driver/configloaderscratch/canonical_directory_other.go +34 -0
- package/driver/configloaderscratch/canonical_directory_windows.go +60 -0
- package/driver/configloaderscratch/identity_temp_base.go +81 -0
- package/driver/configloaderscratch/identity_temp_base_posix_test.go +124 -0
- package/driver/configloaderscratch/identity_temp_base_windows_test.go +156 -0
- package/driver/emit_provenance.go +7 -5
- package/driver/resolutioninputs/recorder.cjs +16 -4
- package/driver/rewrite.go +25 -16
- package/driver/write_file_if_changed.go +69 -0
- package/driver/write_file_if_changed_test.go +148 -0
- package/internal/packageartifacts/manifest.go +288 -0
- package/internal/packageartifacts/manifest_test.go +127 -0
- package/lib/compiler/internal/build/BuildExecution.d.ts +11 -7
- package/lib/compiler/internal/build/BuildExecution.js +22 -8
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/build/ResidentCheckWatchSession.d.ts +10 -10
- package/lib/compiler/internal/build/ResidentCheckWatchSession.js +19 -14
- package/lib/compiler/internal/build/ResidentCheckWatchSession.js.map +1 -1
- package/lib/compiler/internal/build/RunBuildOptions.d.ts +8 -1
- package/lib/compiler/internal/build/TsgoArguments.d.ts +16 -0
- package/lib/compiler/internal/build/TsgoArguments.js +19 -0
- package/lib/compiler/internal/build/TsgoArguments.js.map +1 -1
- package/lib/compiler/internal/captureProcessOutput.d.ts +16 -13
- package/lib/compiler/internal/captureProcessOutput.js +22 -14
- package/lib/compiler/internal/captureProcessOutput.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +3 -1
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +5 -1
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/launcher/internal/runtime/PluginDescriptorInputReport.d.ts +43 -0
- package/lib/launcher/internal/runtime/PluginDescriptorInputReport.js +106 -0
- package/lib/launcher/internal/runtime/PluginDescriptorInputReport.js.map +1 -0
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +15 -29
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js +1 -0
- package/lib/launcher/internal/ttscserver/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/watch/WatchTopology.js +5 -4
- package/lib/launcher/internal/watch/WatchTopology.js.map +1 -1
- package/lib/plugin/internal/CapabilityResolutionFormat.js +4 -3
- package/lib/plugin/internal/CapabilityResolutionFormat.js.map +1 -1
- package/lib/plugin/internal/load/COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE.js +6 -0
- package/lib/plugin/internal/load/COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE.js.map +1 -1
- package/lib/plugin/internal/load/PLUGIN_DESCRIPTOR_SHIM_SOURCE.js +6 -0
- package/lib/plugin/internal/load/PLUGIN_DESCRIPTOR_SHIM_SOURCE.js.map +1 -1
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +3 -3
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
- package/lib/plugin/internal/load/descriptorRecordEnvironment.d.ts +15 -0
- package/lib/plugin/internal/load/descriptorRecordEnvironment.js +24 -0
- package/lib/plugin/internal/load/descriptorRecordEnvironment.js.map +1 -0
- package/lib/plugin/internal/load/loadProjectPlugins.js +28 -26
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/source/SourceBuildCacheLayout.d.ts +2 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js +2 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js.map +1 -1
- package/lib/plugin/internal/source/SourcePackageArtifacts.d.ts +145 -0
- package/lib/plugin/internal/source/SourcePackageArtifacts.js +612 -0
- package/lib/plugin/internal/source/SourcePackageArtifacts.js.map +1 -0
- package/lib/plugin/internal/source/buildSourcePlugin.js +54 -4
- package/lib/plugin/internal/source/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/source/prunePackageArtifactRoot.d.ts +19 -0
- package/lib/plugin/internal/source/prunePackageArtifactRoot.js +95 -0
- package/lib/plugin/internal/source/prunePackageArtifactRoot.js.map +1 -0
- package/lib/plugin/internal/source/resolveCleanTargets.js +1 -1
- package/lib/plugin/internal/source/resolveCleanTargets.js.map +1 -1
- package/lib/plugin/internal/source/resolveSourceBuildCachePaths.js +9 -4
- package/lib/plugin/internal/source/resolveSourceBuildCachePaths.js.map +1 -1
- package/lib/plugin/internal/source/selectedRecordIdentityTempParent.d.ts +18 -0
- package/lib/plugin/internal/source/selectedRecordIdentityTempParent.js +46 -0
- package/lib/plugin/internal/source/selectedRecordIdentityTempParent.js.map +1 -0
- package/package.json +8 -8
- package/src/compiler/internal/build/BuildExecution.ts +30 -10
- package/src/compiler/internal/build/ResidentCheckWatchSession.ts +23 -22
- package/src/compiler/internal/build/RunBuildOptions.ts +9 -1
- package/src/compiler/internal/build/TsgoArguments.ts +22 -0
- package/src/compiler/internal/captureProcessOutput.ts +28 -14
- package/src/compiler/internal/startResidentTransform.ts +7 -1
- package/src/compiler/internal/transformProjectInMemory.ts +9 -1
- package/src/launcher/internal/runtime/PluginDescriptorInputReport.ts +100 -0
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +57 -55
- package/src/launcher/internal/ttscserver/runTtscserver.ts +5 -0
- package/src/launcher/internal/watch/WatchTopology.ts +5 -4
- package/src/plugin/internal/CapabilityResolutionFormat.ts +4 -3
- package/src/plugin/internal/load/COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE.ts +4 -0
- package/src/plugin/internal/load/PLUGIN_DESCRIPTOR_SHIM_SOURCE.ts +4 -0
- package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +3 -3
- package/src/plugin/internal/load/descriptorRecordEnvironment.ts +24 -0
- package/src/plugin/internal/load/loadProjectPlugins.ts +45 -29
- package/src/plugin/internal/source/SourceBuildCacheLayout.ts +3 -0
- package/src/plugin/internal/source/SourcePackageArtifacts.ts +787 -0
- package/src/plugin/internal/source/buildSourcePlugin.ts +82 -12
- package/src/plugin/internal/source/prunePackageArtifactRoot.ts +100 -0
- package/src/plugin/internal/source/resolveCleanTargets.ts +1 -0
- package/src/plugin/internal/source/resolveSourceBuildCachePaths.ts +11 -4
- package/src/plugin/internal/source/selectedRecordIdentityTempParent.ts +40 -0
|
@@ -32,6 +32,7 @@ import { DependencyBuildGeneration } from "./DependencyBuildGeneration";
|
|
|
32
32
|
import { OwnedProjectSource } from "./OwnedProjectSource";
|
|
33
33
|
import type { OwningModuleOptions } from "./OwningModuleOptions";
|
|
34
34
|
import { PluginDescriptorInputObservation } from "./PluginDescriptorInputObservation";
|
|
35
|
+
import { PluginDescriptorInputReport } from "./PluginDescriptorInputReport";
|
|
35
36
|
import type { ResolveResult } from "./ResolveResult";
|
|
36
37
|
import { RuntimeEmitProvenance } from "./RuntimeEmitProvenance";
|
|
37
38
|
import { RuntimeEntrySources } from "./RuntimeEntrySources";
|
|
@@ -392,7 +393,7 @@ function observePluginDescriptorResolutionCandidates(
|
|
|
392
393
|
);
|
|
393
394
|
return {
|
|
394
395
|
commit: (selectedURL) => {
|
|
395
|
-
|
|
396
|
+
PluginDescriptorInputReport.append(
|
|
396
397
|
observation
|
|
397
398
|
.commit(
|
|
398
399
|
selectedURL === undefined
|
|
@@ -431,7 +432,7 @@ function observePluginDescriptorResolutionCandidates(
|
|
|
431
432
|
DESCRIPTOR_PROBE_EXTENSIONS,
|
|
432
433
|
),
|
|
433
434
|
);
|
|
434
|
-
|
|
435
|
+
PluginDescriptorInputReport.append([
|
|
435
436
|
...local,
|
|
436
437
|
...(reached === -1 ? roots : roots.slice(0, reached + 1)).flatMap(
|
|
437
438
|
(root) => root.lines,
|
|
@@ -567,7 +568,8 @@ function observePluginDescriptorResolutionCandidates(
|
|
|
567
568
|
* active for direct-evaluator user preloads after hook installation. The exact
|
|
568
569
|
* generated evaluator entry bypasses these hooks and suspends recording only
|
|
569
570
|
* while its synchronous implementation imports load; descriptor imports then
|
|
570
|
-
* resume it.
|
|
571
|
+
* resume it. A selected file needs positive content and physical proof even
|
|
572
|
+
* when an earlier candidate enumeration did not name it.
|
|
571
573
|
*/
|
|
572
574
|
function recordPluginDescriptorResolution(
|
|
573
575
|
specifier: string,
|
|
@@ -578,11 +580,14 @@ function recordPluginDescriptorResolution(
|
|
|
578
580
|
const resolved = runtimeFilePath(resolvedURL);
|
|
579
581
|
if (resolved === undefined) return;
|
|
580
582
|
const parent = runtimeFilePath(parentURL);
|
|
581
|
-
recordPluginDescriptorInput(
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
583
|
+
recordPluginDescriptorInput(
|
|
584
|
+
{
|
|
585
|
+
...(parent === undefined ? {} : { parent }),
|
|
586
|
+
resolved,
|
|
587
|
+
specifier,
|
|
588
|
+
},
|
|
589
|
+
true,
|
|
590
|
+
);
|
|
586
591
|
for (
|
|
587
592
|
let directory = path.dirname(resolved);
|
|
588
593
|
;
|
|
@@ -599,38 +604,47 @@ function recordPluginDescriptorResolution(
|
|
|
599
604
|
}
|
|
600
605
|
}
|
|
601
606
|
|
|
602
|
-
function recordPluginDescriptorInput(
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
607
|
+
function recordPluginDescriptorInput(
|
|
608
|
+
record: {
|
|
609
|
+
hash?: string | null;
|
|
610
|
+
parent?: string;
|
|
611
|
+
realpath?: string | null;
|
|
612
|
+
resolved: string;
|
|
613
|
+
signature?: string;
|
|
614
|
+
specifier?: string;
|
|
615
|
+
unstable?: boolean;
|
|
616
|
+
},
|
|
617
|
+
requirePresent: boolean = false,
|
|
618
|
+
): void {
|
|
619
|
+
PluginDescriptorInputReport.append(
|
|
620
|
+
observePluginDescriptorInput(record, requirePresent),
|
|
621
|
+
);
|
|
612
622
|
}
|
|
613
623
|
|
|
614
624
|
/**
|
|
615
625
|
* Observe one path and every symbolic link among its lexical ancestors, as the
|
|
616
|
-
* lines `
|
|
626
|
+
* lines `PluginDescriptorInputReport.append` reports, without reporting them
|
|
627
|
+
* yet.
|
|
617
628
|
*/
|
|
618
|
-
function observePluginDescriptorInput(
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
629
|
+
function observePluginDescriptorInput(
|
|
630
|
+
record: {
|
|
631
|
+
hash?: string | null;
|
|
632
|
+
parent?: string;
|
|
633
|
+
realpath?: string | null;
|
|
634
|
+
resolved: string;
|
|
635
|
+
signature?: string;
|
|
636
|
+
specifier?: string;
|
|
637
|
+
unstable?: boolean;
|
|
638
|
+
},
|
|
639
|
+
requirePresent: boolean = false,
|
|
640
|
+
): string[] {
|
|
627
641
|
if (process.env.TTSC_PLUGIN_DESCRIPTOR_INPUTS_ACTIVE !== "1") return [];
|
|
628
642
|
const lines: string[] = [];
|
|
629
643
|
const observe = (line: string | undefined): void => {
|
|
630
644
|
if (line !== undefined) lines.push(line);
|
|
631
645
|
else PluginDescriptorInputObservation.invalidate();
|
|
632
646
|
};
|
|
633
|
-
observe(observePluginDescriptorInputOnce(record));
|
|
647
|
+
observe(observePluginDescriptorInputOnce(record, requirePresent));
|
|
634
648
|
const resolved = path.resolve(record.resolved);
|
|
635
649
|
const parsed = path.parse(resolved);
|
|
636
650
|
let current = parsed.root;
|
|
@@ -649,33 +663,19 @@ function observePluginDescriptorInput(record: {
|
|
|
649
663
|
return lines;
|
|
650
664
|
}
|
|
651
665
|
|
|
652
|
-
/** Report observed lines to the parent loader, in the order given. */
|
|
653
|
-
function appendPluginDescriptorInputs(lines: readonly string[]): void {
|
|
654
|
-
if (lines.length === 0) return;
|
|
655
|
-
if (process.env.TTSC_PLUGIN_DESCRIPTOR_INPUTS_ACTIVE !== "1") return;
|
|
656
|
-
PluginDescriptorInputObservation.record(lines);
|
|
657
|
-
const out = process.env.TTSC_PLUGIN_DESCRIPTOR_INPUTS_OUT;
|
|
658
|
-
if (out === undefined || out.length === 0) {
|
|
659
|
-
PluginDescriptorInputObservation.invalidate();
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
try {
|
|
663
|
-
fs.appendFileSync(out, lines.join(""), "utf8");
|
|
664
|
-
} catch {
|
|
665
|
-
PluginDescriptorInputObservation.invalidate();
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
|
|
669
666
|
/** Observe one path without recursively revisiting its lexical ancestors. */
|
|
670
|
-
function observePluginDescriptorInputOnce(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
667
|
+
function observePluginDescriptorInputOnce(
|
|
668
|
+
record: {
|
|
669
|
+
hash?: string | null;
|
|
670
|
+
parent?: string;
|
|
671
|
+
realpath?: string | null;
|
|
672
|
+
resolved: string;
|
|
673
|
+
signature?: string;
|
|
674
|
+
specifier?: string;
|
|
675
|
+
unstable?: boolean;
|
|
676
|
+
},
|
|
677
|
+
requirePresent: boolean = false,
|
|
678
|
+
): string | undefined {
|
|
679
679
|
try {
|
|
680
680
|
const beforeSignature = pluginDescriptorInputMetadataSignature(
|
|
681
681
|
record.resolved,
|
|
@@ -687,6 +687,8 @@ function observePluginDescriptorInputOnce(record: {
|
|
|
687
687
|
);
|
|
688
688
|
const unstable =
|
|
689
689
|
record.unstable === true ||
|
|
690
|
+
(requirePresent &&
|
|
691
|
+
(observedHash === null || observedRealpath === null)) ||
|
|
690
692
|
beforeSignature === undefined ||
|
|
691
693
|
afterSignature === undefined ||
|
|
692
694
|
beforeSignature !== afterSignature ||
|
|
@@ -265,6 +265,11 @@ function lspSidecarEnvironment(options: {
|
|
|
265
265
|
});
|
|
266
266
|
const node = resolveNodeBinary(env, options.cwd, options.identities);
|
|
267
267
|
SidecarEnvironment.write(env, "TTSC_NODE_BINARY", node);
|
|
268
|
+
SidecarEnvironment.write(
|
|
269
|
+
env,
|
|
270
|
+
"TTSC_NATIVE_PLUGIN_RECORD_ROOT",
|
|
271
|
+
options.identities?.root,
|
|
272
|
+
);
|
|
268
273
|
SidecarEnvironment.write(
|
|
269
274
|
env,
|
|
270
275
|
"TTSC_PLUGIN_CONFIG_DIR",
|
|
@@ -2740,17 +2740,18 @@ function projectInputDeclarationKey(
|
|
|
2740
2740
|
*
|
|
2741
2741
|
* Modification time and size avoid a read on an ordinary broad scan. A strong
|
|
2742
2742
|
* event compares the fingerprint, so a timestamp collision cannot hide an edit
|
|
2743
|
-
* and a metadata-only notification does not create a build.
|
|
2744
|
-
*
|
|
2743
|
+
* and a metadata-only notification does not create a build. Exact device and
|
|
2744
|
+
* inode values detect replacement even when Windows file IDs exceed the safe
|
|
2745
|
+
* integer range; they also identify a POSIX per-file watcher's owner.
|
|
2745
2746
|
*/
|
|
2746
2747
|
function compilerFileSnapshot(
|
|
2747
2748
|
location: string,
|
|
2748
2749
|
fingerprint: string,
|
|
2749
2750
|
): CompilerFileSnapshot {
|
|
2750
2751
|
try {
|
|
2751
|
-
const stats = fs.statSync(location);
|
|
2752
|
+
const stats = fs.statSync(location, { bigint: true });
|
|
2752
2753
|
return {
|
|
2753
|
-
content: `${stats.
|
|
2754
|
+
content: `${stats.mtimeNs}:${stats.size}`,
|
|
2754
2755
|
fingerprint,
|
|
2755
2756
|
owner: `${stats.dev}:${stats.ino}`,
|
|
2756
2757
|
};
|
|
@@ -40,10 +40,11 @@ export namespace CapabilityResolutionFormat {
|
|
|
40
40
|
* runtime observation envelope, so a partial side channel cannot authorize an
|
|
41
41
|
* answer for reuse, and the shared module recorder's independent completion
|
|
42
42
|
* proof, including its public require.resolve hook capability. Mapped import
|
|
43
|
-
* candidates retain their pre-resolution witnesses
|
|
44
|
-
*
|
|
43
|
+
* candidates retain their pre-resolution witnesses. A selected file without
|
|
44
|
+
* positive content and physical proof now withdraws reuse, so entries from
|
|
45
|
+
* before that producer rule must be discovered again.
|
|
45
46
|
*/
|
|
46
|
-
const FORMAT = "ttsc-capability-resolution-
|
|
47
|
+
const FORMAT = "ttsc-capability-resolution-v8";
|
|
47
48
|
|
|
48
49
|
/**
|
|
49
50
|
* The character that joins fields a path could otherwise forge.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
PLUGIN_INPUT_OBSERVATION_PATH,
|
|
3
5
|
RESOLUTION_INPUT_RECORDER_PATH,
|
|
@@ -24,6 +26,7 @@ export const COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE = [
|
|
|
24
26
|
`const path = require("node:path");`,
|
|
25
27
|
`const vm = require("node:vm");`,
|
|
26
28
|
`const { PluginDescriptorInputObservation } = require.cache[${JSON.stringify(PLUGIN_INPUT_OBSERVATION_PATH)}]?.exports ?? require(${JSON.stringify(PLUGIN_INPUT_OBSERVATION_PATH)});`,
|
|
29
|
+
`const { PluginDescriptorInputReport } = require(${JSON.stringify(path.resolve(path.dirname(PLUGIN_INPUT_OBSERVATION_PATH), "PluginDescriptorInputReport.js"))});`,
|
|
27
30
|
`const { fileURLToPath } = require("node:url");`,
|
|
28
31
|
`const { createResolutionInputRecorder, requireResolveConsultsHooks } = (() => {`,
|
|
29
32
|
` const file = ${JSON.stringify(RESOLUTION_INPUT_RECORDER_PATH)};`,
|
|
@@ -164,6 +167,7 @@ export const COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE = [
|
|
|
164
167
|
// that influence.
|
|
165
168
|
` const serializedDescriptor = JSON.stringify(descriptor);`,
|
|
166
169
|
` const recorded = recorder.finish();`,
|
|
170
|
+
` PluginDescriptorInputReport.finish();`,
|
|
167
171
|
` const observation = PluginDescriptorInputObservation.snapshot();`,
|
|
168
172
|
` observation.complete = observation.complete && recorded.complete === true;`,
|
|
169
173
|
` const payload = { inputHashes: recorded.hashes, inputRealpaths: recorded.realpaths, inputs: recorded.inputs, observation };`,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
1
3
|
import { PLUGIN_INPUT_OBSERVATION_PATH } from "./RESOLUTION_INPUT_RECORDER_PATH";
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -22,6 +24,7 @@ export const PLUGIN_DESCRIPTOR_SHIM_SOURCE = [
|
|
|
22
24
|
// factory could have said.
|
|
23
25
|
`try {`,
|
|
24
26
|
` const { PluginDescriptorInputObservation } = createRequire(import.meta.url).cache[${JSON.stringify(PLUGIN_INPUT_OBSERVATION_PATH)}].exports;`,
|
|
27
|
+
` const { PluginDescriptorInputReport } = createRequire(import.meta.url)(${JSON.stringify(path.resolve(path.dirname(PLUGIN_INPUT_OBSERVATION_PATH), "PluginDescriptorInputReport.js"))});`,
|
|
25
28
|
// Runtime hooks are installed before this shim loads. Arm their internal
|
|
26
29
|
// side channel only for the descriptor import itself, after this shim's own
|
|
27
30
|
// imports have resolved, so ttsc implementation files never become project
|
|
@@ -38,6 +41,7 @@ export const PLUGIN_DESCRIPTOR_SHIM_SOURCE = [
|
|
|
38
41
|
` throw new Error("ttsc: plugin descriptor declares unsupported JS transform functions; declare a native backend instead");`,
|
|
39
42
|
` }`,
|
|
40
43
|
` const serializedDescriptor = JSON.stringify(descriptor);`,
|
|
44
|
+
` PluginDescriptorInputReport.finish();`,
|
|
41
45
|
` const payload = { observation: PluginDescriptorInputObservation.snapshot() };`,
|
|
42
46
|
` if (serializedDescriptor !== undefined) payload.descriptor = JSON.parse(serializedDescriptor);`,
|
|
43
47
|
` writeFileSync(process.env.TTSC_PLUGIN_DESCRIPTOR_OUT, JSON.stringify(payload));`,
|
|
@@ -352,9 +352,9 @@ export namespace PluginDescriptorEvaluationCache {
|
|
|
352
352
|
* Entry format tag. Moves when the entry shape or its proof rule changes, so
|
|
353
353
|
* an entry written under another rule is evaluated again.
|
|
354
354
|
*/
|
|
355
|
-
// Earlier generations could
|
|
356
|
-
//
|
|
357
|
-
const FORMAT = "ttsc-descriptor-evaluation-
|
|
355
|
+
// Earlier generations could prove a selected file's disappearance as a
|
|
356
|
+
// missing candidate, so their apparently complete proofs are not reusable.
|
|
357
|
+
const FORMAT = "ttsc-descriptor-evaluation-v8";
|
|
358
358
|
|
|
359
359
|
interface IEntry {
|
|
360
360
|
evaluation: IEvaluation;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supplies a descriptor child with this load's selected record root. An absent
|
|
5
|
+
* store removes inherited spellings of the private channel, including Windows
|
|
6
|
+
* case aliases, so a nested child cannot adopt an earlier load's cache root.
|
|
7
|
+
*
|
|
8
|
+
* @evidence contracts/common.md#principled-implementation The selected store is the only authority for the child channel; SidecarEnvironment.write removes inherited aliases when it is absent.
|
|
9
|
+
* @evidence contracts/common.md#clear-and-simple-design One environment constructor serves direct and ttsx descriptor evaluators and their cache identity.
|
|
10
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The helper copies the caller's environment and changes only ttsc's private channel instead of mutating process.env or inventing a cache root.
|
|
11
|
+
* @evidence contracts/common.md#meaningful-documentation The comment identifies ownership of the channel and the nested-process failure prevented by clearing it.
|
|
12
|
+
* @evidence contracts/portability.md#os-neutral-implementation SidecarEnvironment applies Windows native case-insensitive identity while preserving POSIX variable spelling.
|
|
13
|
+
* @evidence contracts/performance.md#efficient-algorithms Copying E environment entries and removing matching Windows aliases takes O(E) time and memory; descriptor setup already materializes an environment for each child.
|
|
14
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The selected store and effective environment are invocation-specific, so no prior constructed child environment is reused.
|
|
15
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The returned environment lives only with one descriptor spawn or cache identity and retains no external resource.
|
|
16
|
+
*/
|
|
17
|
+
export function descriptorRecordEnvironment(
|
|
18
|
+
env: NodeJS.ProcessEnv,
|
|
19
|
+
recordRoot: string | undefined,
|
|
20
|
+
): NodeJS.ProcessEnv {
|
|
21
|
+
const child = { ...env };
|
|
22
|
+
SidecarEnvironment.write(child, "TTSC_PLUGIN_RECORD_ROOT", recordRoot);
|
|
23
|
+
return child;
|
|
24
|
+
}
|
|
@@ -35,6 +35,7 @@ import { pluginBuildVersions } from "../source/pluginBuildVersions";
|
|
|
35
35
|
import { pluginModuleReplaceDirectories } from "../source/pluginModuleReplaceDirectories";
|
|
36
36
|
import { pluginSourceState } from "../source/pluginSourceState";
|
|
37
37
|
import { resolvePluginGoModule } from "../source/resolvePluginGoModule";
|
|
38
|
+
import { selectedRecordIdentityTempParent } from "../source/selectedRecordIdentityTempParent";
|
|
38
39
|
import { COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE } from "./COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE";
|
|
39
40
|
import { PLUGIN_DESCRIPTOR_SHIM_SOURCE } from "./PLUGIN_DESCRIPTOR_SHIM_SOURCE";
|
|
40
41
|
import { PluginDescriptorAdmission } from "./PluginDescriptorAdmission";
|
|
@@ -44,6 +45,7 @@ import { ProjectPluginEntries } from "./ProjectPluginEntries";
|
|
|
44
45
|
import { collectProjectHostInputs } from "./collectProjectHostInputs";
|
|
45
46
|
import { composePluginSources } from "./composePluginSources";
|
|
46
47
|
import { declaresHostInputReads } from "./declaresHostInputReads";
|
|
48
|
+
import { descriptorRecordEnvironment } from "./descriptorRecordEnvironment";
|
|
47
49
|
import { hashHostInputPaths } from "./hashHostInputPaths";
|
|
48
50
|
import { moduleResolutionBaseSelects } from "./moduleResolutionBaseSelects";
|
|
49
51
|
import { pluginLabel } from "./pluginLabel";
|
|
@@ -1547,9 +1549,11 @@ function loadCommonJsDescriptor(
|
|
|
1547
1549
|
cwd: descriptorCache.projectRoot,
|
|
1548
1550
|
// Everything the child receives besides the per-evaluation output paths.
|
|
1549
1551
|
env: {
|
|
1550
|
-
...
|
|
1552
|
+
...descriptorRecordEnvironment(
|
|
1553
|
+
effectiveEnv,
|
|
1554
|
+
descriptorCache.identities?.root,
|
|
1555
|
+
),
|
|
1551
1556
|
...(node === undefined ? {} : { TTSC_NODE_BINARY: node }),
|
|
1552
|
-
...descriptorRecordRoot(descriptorCache.identities),
|
|
1553
1557
|
TTSC_TTSX_BINARY: ttsx,
|
|
1554
1558
|
},
|
|
1555
1559
|
projectRoot: descriptorCache.projectRoot,
|
|
@@ -1579,7 +1583,7 @@ function loadCommonJsDescriptor(
|
|
|
1579
1583
|
PluginDescriptorEvaluationCache.locate(cacheAuthority) === cacheFile
|
|
1580
1584
|
)
|
|
1581
1585
|
return cached;
|
|
1582
|
-
const dir = createEvaluationTempDir();
|
|
1586
|
+
const dir = createEvaluationTempDir(descriptorCache.identities);
|
|
1583
1587
|
const out = path.join(dir, "descriptor.json");
|
|
1584
1588
|
const inputsOut = path.join(dir, "descriptor-inputs.ndjson");
|
|
1585
1589
|
const diagnostics = path.join(dir, "descriptor.stderr");
|
|
@@ -1635,11 +1639,13 @@ function loadCommonJsDescriptor(
|
|
|
1635
1639
|
{
|
|
1636
1640
|
cwd: descriptorCache.projectRoot,
|
|
1637
1641
|
env: {
|
|
1638
|
-
...
|
|
1642
|
+
...descriptorRecordEnvironment(
|
|
1643
|
+
effectiveEnv,
|
|
1644
|
+
descriptorCache.identities?.root,
|
|
1645
|
+
),
|
|
1639
1646
|
// The direct evaluator may be Bun, but ttsx and native config
|
|
1640
1647
|
// loaders require a real Node runtime with synchronous hooks.
|
|
1641
1648
|
...(node === undefined ? {} : { TTSC_NODE_BINARY: node }),
|
|
1642
|
-
...descriptorRecordRoot(descriptorCache.identities),
|
|
1643
1649
|
TTSC_TTSX_BINARY: ttsx,
|
|
1644
1650
|
TTSC_PLUGIN_CONTEXT: JSON.stringify(context),
|
|
1645
1651
|
TTSC_PLUGIN_DESCRIPTOR_LOAD: "1",
|
|
@@ -2038,7 +2044,7 @@ function loadDescriptorViaTtsx(
|
|
|
2038
2044
|
if (node === undefined || ttsx === undefined || ttsx.length === 0) {
|
|
2039
2045
|
return undefined;
|
|
2040
2046
|
}
|
|
2041
|
-
const dir = createEvaluationTempDir();
|
|
2047
|
+
const dir = createEvaluationTempDir(descriptorCache.identities);
|
|
2042
2048
|
const out = path.join(dir, "descriptor.json");
|
|
2043
2049
|
const inputsOut = path.join(dir, "descriptor-inputs.ndjson");
|
|
2044
2050
|
const shim = path.join(dir, "load-descriptor.mts");
|
|
@@ -2067,12 +2073,14 @@ function loadDescriptorViaTtsx(
|
|
|
2067
2073
|
cwd: descriptorCache.projectRoot,
|
|
2068
2074
|
encoding: "utf8",
|
|
2069
2075
|
env: {
|
|
2070
|
-
...
|
|
2076
|
+
...descriptorRecordEnvironment(
|
|
2077
|
+
effectiveEnv,
|
|
2078
|
+
descriptorCache.identities?.root,
|
|
2079
|
+
),
|
|
2071
2080
|
// Carry ttsc's own node/ttsx locators explicitly so the child (which
|
|
2072
2081
|
// may recurse into further descriptor loads) finds them even when the
|
|
2073
2082
|
// instance-env snapshot predates `withPluginLoaderEnv`.
|
|
2074
2083
|
TTSC_NODE_BINARY: node,
|
|
2075
|
-
...descriptorRecordRoot(descriptorCache.identities),
|
|
2076
2084
|
TTSC_TTSX_BINARY: ttsx,
|
|
2077
2085
|
TTSC_PLUGIN_CONTEXT: JSON.stringify({
|
|
2078
2086
|
binary: context.binary,
|
|
@@ -2157,20 +2165,6 @@ interface TtsxDescriptorResolutionRecord {
|
|
|
2157
2165
|
unstable?: boolean;
|
|
2158
2166
|
}
|
|
2159
2167
|
|
|
2160
|
-
/**
|
|
2161
|
-
* The private variable that hands a descriptor evaluator the plugin cache root
|
|
2162
|
-
* this load's record store selected, so the child proves the compiler it runs
|
|
2163
|
-
* from that root's records instead of streaming it (#1726) and never selects a
|
|
2164
|
-
* cache root of its own. Absent without a store.
|
|
2165
|
-
*/
|
|
2166
|
-
function descriptorRecordRoot(
|
|
2167
|
-
identities: PluginContentIdentities.Store | undefined,
|
|
2168
|
-
): { TTSC_PLUGIN_RECORD_ROOT?: string } {
|
|
2169
|
-
return identities === undefined
|
|
2170
|
-
? {}
|
|
2171
|
-
: { TTSC_PLUGIN_RECORD_ROOT: identities.root };
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
2168
|
/**
|
|
2175
2169
|
* Expand the ttsx runtime's selected module edges into the same exact and
|
|
2176
2170
|
* missing resolution inputs used by the direct isolated evaluator.
|
|
@@ -2197,22 +2191,38 @@ function readTtsxDescriptorInputs(
|
|
|
2197
2191
|
const signatures = new Map<string, string>();
|
|
2198
2192
|
const unstableInputs = new Set<string>();
|
|
2199
2193
|
let complete = false;
|
|
2200
|
-
let
|
|
2194
|
+
let envelopeText: string | undefined;
|
|
2201
2195
|
if (
|
|
2202
2196
|
PluginPackageResolution.isRecord(observation) &&
|
|
2203
2197
|
Array.isArray(observation.lines) &&
|
|
2204
2198
|
observation.lines.every((line: unknown) => typeof line === "string")
|
|
2205
2199
|
) {
|
|
2206
2200
|
complete = observation.complete === true;
|
|
2207
|
-
|
|
2201
|
+
envelopeText = observation.lines.join("");
|
|
2208
2202
|
}
|
|
2203
|
+
let reportText: string | undefined;
|
|
2209
2204
|
try {
|
|
2210
|
-
|
|
2205
|
+
reportText = fs.readFileSync(file, "utf8");
|
|
2211
2206
|
} catch {
|
|
2212
2207
|
// The directly serialized observation copy remains authoritative when
|
|
2213
2208
|
// no side-channel file was produced. A missing completion copy is never
|
|
2214
2209
|
// repaired by whichever partial lines happen to remain on disk.
|
|
2215
2210
|
}
|
|
2211
|
+
if (
|
|
2212
|
+
envelopeText !== undefined &&
|
|
2213
|
+
reportText !== undefined &&
|
|
2214
|
+
envelopeText !== reportText
|
|
2215
|
+
) {
|
|
2216
|
+
// A partial or contradictory side channel cannot certify completeness.
|
|
2217
|
+
// Keep both records so watch callers still learn every reported input.
|
|
2218
|
+
complete = false;
|
|
2219
|
+
}
|
|
2220
|
+
const text =
|
|
2221
|
+
envelopeText === undefined
|
|
2222
|
+
? (reportText ?? "")
|
|
2223
|
+
: reportText === undefined || reportText === envelopeText
|
|
2224
|
+
? envelopeText
|
|
2225
|
+
: `${envelopeText}\n${reportText}`;
|
|
2216
2226
|
for (const line of text.split(/\r?\n/)) {
|
|
2217
2227
|
if (line.trim() === "") continue;
|
|
2218
2228
|
let record: TtsxDescriptorResolutionRecord;
|
|
@@ -2516,11 +2526,17 @@ function ttscPackageRoot(): string {
|
|
|
2516
2526
|
}
|
|
2517
2527
|
|
|
2518
2528
|
/**
|
|
2519
|
-
* Create an evaluator directory
|
|
2520
|
-
*
|
|
2529
|
+
* Create an evaluator directory under the current selected record store when it
|
|
2530
|
+
* has an ordinary identities child. Canonical allocation fixes the physical
|
|
2531
|
+
* cleanup path; an absent or unproved store retains system TEMP.
|
|
2521
2532
|
*/
|
|
2522
|
-
function createEvaluationTempDir(
|
|
2523
|
-
|
|
2533
|
+
function createEvaluationTempDir(
|
|
2534
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
2535
|
+
): string {
|
|
2536
|
+
return createCanonicalTempDirectory(
|
|
2537
|
+
"ttsc-plugin-descriptor-",
|
|
2538
|
+
selectedRecordIdentityTempParent(identities?.root),
|
|
2539
|
+
);
|
|
2524
2540
|
}
|
|
2525
2541
|
|
|
2526
2542
|
/**
|
|
@@ -44,6 +44,9 @@ export namespace SourceBuildCacheLayout {
|
|
|
44
44
|
/** Directory name of ttsc's own Go object cache inside the cache root. */
|
|
45
45
|
export const GO_BUILD_CACHE_DIRNAME = "go-build";
|
|
46
46
|
|
|
47
|
+
/** Directory of publisher package bodies and local Go cache writes. */
|
|
48
|
+
export const PACKAGE_ARTIFACTS_DIRNAME = "package-artifacts";
|
|
49
|
+
|
|
47
50
|
/** File inside a plugin cache entry recording when it was last used. */
|
|
48
51
|
export const CACHE_LAST_USED_FILE = ".last-used";
|
|
49
52
|
|