ttsc 0.34.3 → 0.36.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/driver/compilation_snapshot.go +267 -0
- package/driver/compilation_snapshot_keeps_inputs_across_stages_test.go +130 -0
- package/driver/compilation_snapshot_preserves_checked_emission_test.go +100 -0
- package/driver/graph.go +9 -3
- package/driver/program.go +45 -14
- package/lib/compiler/internal/CompilationSnapshot.d.ts +33 -0
- package/lib/compiler/internal/CompilationSnapshot.js +90 -0
- package/lib/compiler/internal/CompilationSnapshot.js.map +1 -0
- package/lib/compiler/internal/build/BuildExecution.d.ts +33 -4
- package/lib/compiler/internal/build/BuildExecution.js +81 -8
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/build/RunBuildOptions.d.ts +2 -0
- package/lib/compiler/internal/build/RuntimeBuildCache.d.ts +47 -0
- package/lib/compiler/internal/build/RuntimeBuildCache.js +235 -0
- package/lib/compiler/internal/build/RuntimeBuildCache.js.map +1 -0
- package/lib/compiler/internal/build/RuntimeBuildInputs.d.ts +44 -0
- package/lib/compiler/internal/build/RuntimeBuildInputs.js +282 -0
- package/lib/compiler/internal/build/RuntimeBuildInputs.js.map +1 -0
- package/lib/compiler/internal/build/RuntimeInputProof.d.ts +50 -0
- package/lib/compiler/internal/build/RuntimeInputProof.js +315 -0
- package/lib/compiler/internal/build/RuntimeInputProof.js.map +1 -0
- package/lib/compiler/internal/build/TsgoArguments.d.ts +5 -4
- package/lib/compiler/internal/build/TsgoArguments.js +11 -5
- package/lib/compiler/internal/build/TsgoArguments.js.map +1 -1
- package/lib/compiler/internal/build/appendBuildOutput.js +4 -0
- package/lib/compiler/internal/build/appendBuildOutput.js.map +1 -1
- package/lib/compiler/internal/build/runBuild.d.ts +3 -3
- package/lib/compiler/internal/build/runBuild.js +17 -4
- package/lib/compiler/internal/build/runBuild.js.map +1 -1
- package/lib/compiler/internal/build/runExternalEmitProvenance.d.ts +12 -13
- package/lib/compiler/internal/build/runExternalEmitProvenance.js +24 -18
- package/lib/compiler/internal/build/runExternalEmitProvenance.js.map +1 -1
- package/lib/compiler/internal/parseNativeTransformOutput.js +4 -0
- package/lib/compiler/internal/parseNativeTransformOutput.js.map +1 -1
- package/lib/compiler/internal/runNativeCheckWithObservations.d.ts +18 -14
- package/lib/compiler/internal/runNativeCheckWithObservations.js +42 -18
- package/lib/compiler/internal/runNativeCheckWithObservations.js.map +1 -1
- package/lib/compiler/internal/sharedHost/inheritedSidecarEnv.d.ts +2 -1
- package/lib/compiler/internal/sharedHost/inheritedSidecarEnv.js +4 -1
- package/lib/compiler/internal/sharedHost/inheritedSidecarEnv.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.d.ts +3 -3
- package/lib/compiler/internal/transformProjectInMemory.js +29 -5
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/FLAG_SCHEMA.js +7 -0
- package/lib/flags/FLAG_SCHEMA.js.map +1 -1
- package/lib/launcher/internal/parseTtsxCLI.d.ts +1 -0
- package/lib/launcher/internal/parseTtsxCLI.js +1 -0
- package/lib/launcher/internal/parseTtsxCLI.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.d.ts +2 -0
- package/lib/launcher/internal/prepareExecution.js +6 -0
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +5 -0
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +7 -0
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.js +1 -0
- 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 +3 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js.map +1 -1
- package/lib/structures/ITtscCompilerTransformation.d.ts +5 -0
- package/lib/structures/ITtscPluginCapabilities.d.ts +13 -2
- package/package.json +8 -8
- package/src/compiler/internal/CompilationSnapshot.ts +97 -0
- package/src/compiler/internal/build/BuildExecution.ts +128 -20
- package/src/compiler/internal/build/RunBuildOptions.ts +3 -0
- package/src/compiler/internal/build/RuntimeBuildCache.ts +252 -0
- package/src/compiler/internal/build/RuntimeBuildInputs.ts +349 -0
- package/src/compiler/internal/build/RuntimeInputProof.ts +346 -0
- package/src/compiler/internal/build/TsgoArguments.ts +11 -5
- package/src/compiler/internal/build/appendBuildOutput.ts +4 -0
- package/src/compiler/internal/build/runBuild.ts +20 -5
- package/src/compiler/internal/build/runExternalEmitProvenance.ts +25 -23
- package/src/compiler/internal/parseNativeTransformOutput.ts +5 -0
- package/src/compiler/internal/runNativeCheckWithObservations.ts +41 -18
- package/src/compiler/internal/sharedHost/inheritedSidecarEnv.ts +8 -1
- package/src/compiler/internal/transformProjectInMemory.ts +46 -5
- package/src/flags/FLAG_SCHEMA.ts +7 -0
- package/src/launcher/internal/parseTtsxCLI.ts +1 -0
- package/src/launcher/internal/prepareExecution.ts +13 -0
- package/src/launcher/internal/runTtsx.ts +5 -0
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +11 -0
- package/src/plugin/internal/load/loadProjectPlugins.ts +1 -0
- package/src/plugin/internal/source/SourceBuildCacheLayout.ts +4 -0
- package/src/structures/ITtscCompilerTransformation.ts +6 -0
- package/src/structures/ITtscPluginCapabilities.ts +14 -2
- package/utility/host.go +22 -1
|
@@ -7,36 +7,40 @@ import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult"
|
|
|
7
7
|
import { parseReferenceGraph } from "./parseNativeTransformOutput";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Execute a check with
|
|
11
|
-
* selected host, original diagnostics, streams and status.
|
|
10
|
+
* Execute a check or opted-in build with same-generation input observations,
|
|
11
|
+
* preserving the selected host, original diagnostics, streams and status.
|
|
12
12
|
*
|
|
13
|
-
* The selected native verb must be check
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* The selected native verb must be check, or build with the separate
|
|
14
|
+
* emitObservations capability, before negotiating its generation channel. A
|
|
15
|
+
* check-stage descriptor can also serve effectful fix/format verbs; those
|
|
16
|
+
* retain their original result and never acquire an invented check graph. An
|
|
17
|
+
* opted-in host writes a private sidecar even when its check fails. Hosts
|
|
17
18
|
* without that transport run their original command under their existing
|
|
18
19
|
* descriptor and declared-input contract; omission does not assert complete
|
|
19
20
|
* driver observations. No check is rerun to infer what the earlier generation
|
|
20
21
|
* read. Missing metadata after an interrupted failed opted-in check likewise
|
|
21
|
-
* withholds reuse
|
|
22
|
-
* error
|
|
22
|
+
* withholds reuse. Missing or malformed successful check metadata is a protocol
|
|
23
|
+
* error. Build metadata is optional cache evidence: unavailable setup, records
|
|
24
|
+
* or cleanup retain the original build result with incomplete observations, so
|
|
25
|
+
* loss of caching cannot turn a fresh successful emit into failure.
|
|
23
26
|
*
|
|
24
27
|
* The callback receives only additional transport arguments. This operation
|
|
25
28
|
* owns their accepted canonical private directory and attempts file and empty
|
|
26
29
|
* directory removal without recursive deletion. Setup observes ownership before
|
|
27
30
|
* entering the cleanup boundary, so a setup observation failure can leave the
|
|
28
31
|
* allocation unclaimed. Cleanup failures retain the original thrown failure or
|
|
29
|
-
* completed result as their cause. Before reading and removing the
|
|
30
|
-
* the parent must still have its captured native identity; a replaced
|
|
31
|
-
* is left untouched and
|
|
32
|
-
* an atomic descriptor or ABA
|
|
32
|
+
* completed check result as their cause. Before reading and removing the
|
|
33
|
+
* artifact, the parent must still have its captured native identity; a replaced
|
|
34
|
+
* directory is left untouched and withholds build reuse or reports check
|
|
35
|
+
* failure. These observations do not provide an atomic descriptor or ABA
|
|
36
|
+
* guarantee.
|
|
33
37
|
*
|
|
34
|
-
* @evidence contracts/common.md#principled-implementation
|
|
38
|
+
* @evidence contracts/common.md#principled-implementation Actual check and build verbs negotiate independent declared observation capabilities; fix/format verbs retain their own result. Build witness IO/protocol failures preserve the one original build with incomplete observations, while checks retain their strict metadata contract. Legacy hosts keep their original command without fabricated completeness.
|
|
35
39
|
* @evidence contracts/common.md#clear-and-simple-design The actual verb and descriptor opt-in jointly select one adapter for strict wire decoding and private artifact lifetime; its callback retains command and diagnostic normalization ownership.
|
|
36
40
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Neither a later project-input query nor a separate transform can reconstruct check observations; unknown hosts receive no guessed flag and malformed metadata cannot become a complete empty observation.
|
|
37
41
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs distinguish failed-check metadata, unavailable transport, protocol errors and cleanup ownership, with body and tags separated according to the documentation skill.
|
|
38
42
|
* @evidence contracts/portability.md#os-neutral-implementation Node native absolute paths locate the canonical private artifact, and an additional argv element conveys it without shell quoting or platform-specific filename guesses.
|
|
39
|
-
* @evidence contracts/performance.md#efficient-algorithms One original check callback runs; this adapter adds canonical temp acquisition/native ownership observations, complete sidecar read/JSON decoding and indexed input membership/witness validation. Work and temporary storage follow wire/path bytes and declared inputs plus delegated
|
|
43
|
+
* @evidence contracts/performance.md#efficient-algorithms One original check or build callback runs; this adapter adds canonical temp acquisition/native ownership observations, complete sidecar read/JSON decoding and indexed input membership/witness validation. Work and temporary storage follow wire/path bytes and declared inputs plus delegated producer runtime; it does not add a second compiler generation or source-content rehash, and supplies no callback timeout or metadata-byte ceiling.
|
|
40
44
|
*
|
|
41
45
|
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This adapter supplies the generation's proof to its cache owner rather than retaining or sharing a completed check itself.
|
|
42
46
|
*
|
|
@@ -48,17 +52,32 @@ export function runNativeCheckWithObservations(
|
|
|
48
52
|
/** Actual argv verb; legacy direct callers already represent a check. */
|
|
49
53
|
command: string = "check",
|
|
50
54
|
): TtscBuildResult {
|
|
51
|
-
|
|
55
|
+
const emitting =
|
|
56
|
+
command === "build" && plugin.capabilities?.emitObservations === true;
|
|
57
|
+
if (
|
|
58
|
+
!emitting &&
|
|
59
|
+
(command !== "check" || plugin.capabilities?.checkObservations !== true)
|
|
60
|
+
)
|
|
52
61
|
return run([]);
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
let directory: string;
|
|
64
|
+
let ownership: fs.Stats;
|
|
65
|
+
try {
|
|
66
|
+
directory = createCanonicalTempDirectory("ttsc-check-observations-");
|
|
67
|
+
ownership = fs.lstatSync(directory);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (emitting) return { ...run([]), observationsComplete: false };
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
56
72
|
const file = path.join(directory, "observations.json");
|
|
57
73
|
let completed: TtscBuildResult | undefined;
|
|
58
74
|
let failed = false;
|
|
59
75
|
let failure: unknown;
|
|
60
76
|
try {
|
|
61
|
-
completed = run([
|
|
77
|
+
completed = run([
|
|
78
|
+
(emitting ? "--emit-observations-json=" : "--check-observations-json=") +
|
|
79
|
+
file,
|
|
80
|
+
]);
|
|
62
81
|
if (completed.processCompletedNormally !== true)
|
|
63
82
|
return { ...completed, observationsComplete: false };
|
|
64
83
|
let text: string;
|
|
@@ -68,6 +87,7 @@ export function runNativeCheckWithObservations(
|
|
|
68
87
|
throw new Error("check observation artifact is not an ordinary file");
|
|
69
88
|
text = fs.readFileSync(file, "utf8");
|
|
70
89
|
} catch (error) {
|
|
90
|
+
if (emitting) return { ...completed, observationsComplete: false };
|
|
71
91
|
if (
|
|
72
92
|
completed.status !== 0 &&
|
|
73
93
|
(error as NodeJS.ErrnoException).code === "ENOENT"
|
|
@@ -80,6 +100,7 @@ export function runNativeCheckWithObservations(
|
|
|
80
100
|
try {
|
|
81
101
|
return { ...completed, ...parseObservations(JSON.parse(text)) };
|
|
82
102
|
} catch (error) {
|
|
103
|
+
if (emitting) return { ...completed, observationsComplete: false };
|
|
83
104
|
throw new Error("ttsc: invalid check observation metadata", {
|
|
84
105
|
cause: new AggregateError([completed, error]),
|
|
85
106
|
});
|
|
@@ -108,6 +129,8 @@ export function runNativeCheckWithObservations(
|
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
131
|
if (errors.length !== 0) {
|
|
132
|
+
if (emitting && completed !== undefined && !failed)
|
|
133
|
+
return { ...completed, observationsComplete: false };
|
|
111
134
|
const primary = failed ? failure : completed;
|
|
112
135
|
throw new AggregateError(
|
|
113
136
|
[primary, ...errors],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CompilationSnapshot } from "../CompilationSnapshot";
|
|
1
2
|
import { SidecarEnvironment } from "./SidecarEnvironment";
|
|
2
3
|
import { clearInheritedSemanticConfigPath } from "./clearInheritedSemanticConfigPath";
|
|
3
4
|
import { clearInheritedTsgoArgs } from "./clearInheritedTsgoArgs";
|
|
@@ -6,7 +7,8 @@ import { publishLinkedTransformPlugins } from "./publishLinkedTransformPlugins";
|
|
|
6
7
|
/**
|
|
7
8
|
* Merge inherited and caller environments with native variable-name identity,
|
|
8
9
|
* then clear per-invocation payloads this lane never published: forwarded tsgo
|
|
9
|
-
* arguments, semantic config ownership and the
|
|
10
|
+
* arguments, compilation snapshot, semantic config ownership and the
|
|
11
|
+
* linked-plugin manifest.
|
|
10
12
|
*
|
|
11
13
|
* Use it at every spawn whose child can reach `driver.LoadProgram` — the
|
|
12
14
|
* `api-compile` / `api-transform` hosts, and the plugin loader, whose `ttsx`
|
|
@@ -40,6 +42,11 @@ export function inheritedSidecarEnv(
|
|
|
40
42
|
);
|
|
41
43
|
clearInheritedTsgoArgs(env, callerEnv);
|
|
42
44
|
clearInheritedSemanticConfigPath(env, callerEnv);
|
|
45
|
+
SidecarEnvironment.write(
|
|
46
|
+
env,
|
|
47
|
+
CompilationSnapshot.ENV,
|
|
48
|
+
SidecarEnvironment.read(callerEnv, CompilationSnapshot.ENV),
|
|
49
|
+
);
|
|
43
50
|
publishLinkedTransformPlugins(env, callerEnv, []);
|
|
44
51
|
return env;
|
|
45
52
|
}
|
|
@@ -11,6 +11,7 @@ import type { ITtscCompilerTransformation } from "../../structures/ITtscCompiler
|
|
|
11
11
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
12
12
|
import type { ITtscParsedProjectConfig } from "../../structures/internal/ITtscParsedProjectConfig";
|
|
13
13
|
import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult";
|
|
14
|
+
import { CompilationSnapshot } from "./CompilationSnapshot";
|
|
14
15
|
import { appendBuildOutput, mergeCheckGraphs } from "./build/appendBuildOutput";
|
|
15
16
|
import { normalizeBuildOutput } from "./build/normalizeBuildOutput";
|
|
16
17
|
import { buildNativeCompiler } from "./buildNativeCompiler";
|
|
@@ -60,10 +61,10 @@ import { spawnNative } from "./spawnNative";
|
|
|
60
61
|
* @evidence contracts/common.md#clear-and-simple-design One router composes built-in and plugin-backed transforms; envelope parsers, environment construction, proof merging and negative-only observation limits have separate shared helpers.
|
|
61
62
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Missing input proof cannot be repaired by a postcompile baseline; conventional deferred config reads accept only the actual native consumer's proof, while malformed required TypeScript output is a protocol error.
|
|
62
63
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs describe transform lanes and stage ordering; separated result members distinguish output, advisory graph/dependency data, evaluation witnesses and unstable source markers under documentation guidance.
|
|
63
|
-
* @evidence contracts/performance.md#efficient-algorithms Stage filtering, declared-input Sets and proof maps scale with plugin/input counts; merged paths are sorted with path-text comparison costs. Each stage can rehash/re-realpath declared inputs, serialize plugin/config records and parse complete output; discovery, native capability probes, source builds and child execution remain delegated costs of this call. No byte/work ceiling or measured dominant-cost ranking is asserted.
|
|
64
|
-
* @evidence contracts/performance.md#reuse-equivalent-work Source-plugin artifacts are shared by their owning loader; this transform intentionally produces a current generation and gives downstream consumers the graph, source states and host witnesses required to qualify reuse.
|
|
64
|
+
* @evidence contracts/performance.md#efficient-algorithms Stage filtering, declared-input Sets and proof maps scale with plugin/input counts; merged paths are sorted with path-text comparison costs. Each stage can rehash/re-realpath declared inputs, serialize plugin/config records and parse complete output; discovery, native capability probes, source builds and child execution remain delegated costs of this call. The invocation snapshot adds full captured-population parsing and dirty document encoding/writes per native stage. No byte/work ceiling or measured dominant-cost ranking is asserted.
|
|
65
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Descriptor/source discovery precedes snapshot allocation so invocation-private paths do not vary its environment cache identity. Source-plugin artifacts are shared by their owning loader; this transform intentionally produces a current generation and gives downstream consumers the graph, source states and host witnesses required to qualify reuse.
|
|
65
66
|
*
|
|
66
|
-
* @evidence contracts/performance.md#bound-retention-and-release-resources This router retains discovery records, per-stage proof maps and accumulated diagnostics/output until synchronous stage completion, then transfers the returned envelope.
|
|
67
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources This router retains discovery records, per-stage proof maps and accumulated diagnostics/output until synchronous stage completion, then transfers the returned envelope. The invocation coordinator attempts identity-checked snapshot removal and propagates or aggregates removal failure. Other native capture/observation owners attempt their own cleanup; suppressed cleanup failures and descendant release remain unconfirmed where those owners do not join them. Artifact-cache retention belongs to the builder, and no stage timeout or input/output byte ceiling is supplied here.
|
|
67
68
|
*
|
|
68
69
|
* @evidence contracts/portability.md#os-neutral-implementation Native paths remain filesystem coordinates, child argv are arrays, and environment helpers preserve Windows key equivalence and explicit Node/tsgo/config anchors without shell parsing or native method patching.
|
|
69
70
|
*/
|
|
@@ -123,6 +124,16 @@ export function transformProjectInMemory(options: ITtscCompilerContext): {
|
|
|
123
124
|
projectRoot: options.projectRoot,
|
|
124
125
|
tsconfig: options.tsconfig,
|
|
125
126
|
});
|
|
127
|
+
return CompilationSnapshot.run(options.env, (env) =>
|
|
128
|
+
transformWithSnapshot({ ...options, env }, loaded),
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Run native checks and transformation after descriptor/source discovery. */
|
|
133
|
+
function transformWithSnapshot(
|
|
134
|
+
options: ITtscCompilerContext,
|
|
135
|
+
loaded: ReturnType<typeof loadProjectPlugins>,
|
|
136
|
+
): ReturnType<typeof transformProjectInMemory> {
|
|
126
137
|
if (loaded.nativePlugins.length !== 0) {
|
|
127
138
|
// Every step below runs binaries built from these sources, so the output
|
|
128
139
|
// is a function of their state, which the envelope carries for a consumer
|
|
@@ -393,7 +404,11 @@ function transformProjectWithPlugins(
|
|
|
393
404
|
);
|
|
394
405
|
return {
|
|
395
406
|
...envelopeSideChannels(transformed),
|
|
396
|
-
graph:
|
|
407
|
+
graph: mergeTransformGraphs(
|
|
408
|
+
checked.graph,
|
|
409
|
+
transformed.graph,
|
|
410
|
+
checks.length,
|
|
411
|
+
),
|
|
397
412
|
...observationLimitations(
|
|
398
413
|
[loaded, checked, transformed],
|
|
399
414
|
hostInputHashes,
|
|
@@ -476,7 +491,7 @@ function transformProjectWithPlugins(
|
|
|
476
491
|
);
|
|
477
492
|
return {
|
|
478
493
|
...envelopeSideChannels(output),
|
|
479
|
-
graph:
|
|
494
|
+
graph: mergeTransformGraphs(checked.graph, output.graph, checks.length),
|
|
480
495
|
...observationLimitations(
|
|
481
496
|
[loaded, checked, output],
|
|
482
497
|
hostInputHashes,
|
|
@@ -708,6 +723,7 @@ function runNativeChecks(
|
|
|
708
723
|
stdout: "",
|
|
709
724
|
stderr: "",
|
|
710
725
|
};
|
|
726
|
+
let snapshotsComplete = true;
|
|
711
727
|
for (const plugin of checks) {
|
|
712
728
|
const checked = runNativeCheckWithObservations(plugin, (extraArgs) => {
|
|
713
729
|
const res = spawnNative(
|
|
@@ -748,7 +764,12 @@ function runNativeChecks(
|
|
|
748
764
|
project.root,
|
|
749
765
|
);
|
|
750
766
|
});
|
|
767
|
+
snapshotsComplete &&= checked.graph?.compilationSnapshot !== undefined;
|
|
751
768
|
result = appendBuildOutput(result, checked);
|
|
769
|
+
if (!snapshotsComplete && result.graph?.compilationSnapshot !== undefined) {
|
|
770
|
+
const { compilationSnapshot: _snapshot, ...unqualified } = result.graph;
|
|
771
|
+
result.graph = unqualified;
|
|
772
|
+
}
|
|
752
773
|
if (result.status !== 0) {
|
|
753
774
|
return result;
|
|
754
775
|
}
|
|
@@ -877,3 +898,23 @@ function nativePluginEnv(
|
|
|
877
898
|
);
|
|
878
899
|
return env;
|
|
879
900
|
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* A legacy check with no graph cannot certify the transform's shared input
|
|
904
|
+
* view.
|
|
905
|
+
*/
|
|
906
|
+
function mergeTransformGraphs(
|
|
907
|
+
checked: TtscBuildResult["graph"],
|
|
908
|
+
transformed: TtscBuildResult["graph"],
|
|
909
|
+
checks: number,
|
|
910
|
+
): TtscBuildResult["graph"] {
|
|
911
|
+
const graph = mergeCheckGraphs(checked, transformed);
|
|
912
|
+
if (
|
|
913
|
+
graph === undefined ||
|
|
914
|
+
checks === 0 ||
|
|
915
|
+
checked?.compilationSnapshot !== undefined
|
|
916
|
+
)
|
|
917
|
+
return graph;
|
|
918
|
+
const { compilationSnapshot: _snapshot, ...unqualified } = graph;
|
|
919
|
+
return unqualified;
|
|
920
|
+
}
|
package/src/flags/FLAG_SCHEMA.ts
CHANGED
|
@@ -352,6 +352,13 @@ export const FLAG_SCHEMA: readonly FlagSpec[] = [
|
|
|
352
352
|
// -------------------------------------------------------------------------
|
|
353
353
|
// ttsx-specific options.
|
|
354
354
|
// -------------------------------------------------------------------------
|
|
355
|
+
{
|
|
356
|
+
name: "--no-cache",
|
|
357
|
+
kind: "boolean",
|
|
358
|
+
subcommands: ["ttsx"],
|
|
359
|
+
consumedBy: ["launcher"],
|
|
360
|
+
description: "Disable persistent runtime project emit reuse.",
|
|
361
|
+
},
|
|
355
362
|
{
|
|
356
363
|
name: "--require",
|
|
357
364
|
aliases: ["-r"],
|
|
@@ -120,6 +120,7 @@ export function parseTtsxCLI(argv: readonly string[]) {
|
|
|
120
120
|
checkers: getNumber(result, "--checkers"),
|
|
121
121
|
cwd: getString(result, "--cwd"),
|
|
122
122
|
entry,
|
|
123
|
+
noCache: getBoolean(result, "--no-cache") === true,
|
|
123
124
|
noPlugins: getBoolean(result, "--no-plugins") === true,
|
|
124
125
|
passthrough: postEntryArgs,
|
|
125
126
|
preload,
|
|
@@ -65,6 +65,9 @@ export function prepareExecution(
|
|
|
65
65
|
|
|
66
66
|
/** Internal cache key for more than one checked entry in this process. */
|
|
67
67
|
runtimeCacheKey?: string;
|
|
68
|
+
|
|
69
|
+
/** False bypasses persistent project emits while keeping normal execution. */
|
|
70
|
+
runtimeCache?: boolean;
|
|
68
71
|
} = {},
|
|
69
72
|
): {
|
|
70
73
|
/** Claimed runtime generation whose cleanup ownership transfers to the caller. */
|
|
@@ -383,6 +386,15 @@ function createProjectContext(
|
|
|
383
386
|
runtimeCacheKey,
|
|
384
387
|
processDir,
|
|
385
388
|
pluginCacheDir: explicitCacheDir === undefined ? undefined : cacheDir,
|
|
389
|
+
runtimeBuildCacheDir:
|
|
390
|
+
options.runtimeCache === false ||
|
|
391
|
+
env.TTSX_DISABLE_CACHE === "1" ||
|
|
392
|
+
env.TTSC_PLUGIN_DESCRIPTOR_LOAD === "1"
|
|
393
|
+
? undefined
|
|
394
|
+
: path.join(
|
|
395
|
+
cacheRoot,
|
|
396
|
+
SourceBuildCacheLayout.RUNTIME_BUILD_CACHE_DIRNAME,
|
|
397
|
+
),
|
|
386
398
|
orphanCacheDir: path.join(
|
|
387
399
|
cacheRoot,
|
|
388
400
|
SourceBuildCacheLayout.ORPHAN_CACHE_DIRNAME,
|
|
@@ -527,6 +539,7 @@ function buildProject(
|
|
|
527
539
|
emit: true,
|
|
528
540
|
env: options.env,
|
|
529
541
|
cacheDir: context.pluginCacheDir,
|
|
542
|
+
runtimeCacheDir: context.runtimeBuildCacheDir,
|
|
530
543
|
outDir: context.emitDir,
|
|
531
544
|
// Every output this build writes stays in ttsx's private directory: a
|
|
532
545
|
// declared `declarationDir`, `tsBuildInfoFile`, or `outFile`, and any
|
|
@@ -110,6 +110,7 @@ async function run(
|
|
|
110
110
|
cacheDir: resolveCacheDir(cwd, parsed.cacheDir),
|
|
111
111
|
checkers: parsed.checkers,
|
|
112
112
|
cwd,
|
|
113
|
+
env: parsed.noCache ? { TTSX_DISABLE_CACHE: "1" } : undefined,
|
|
113
114
|
passthrough: parsed.tsgoFlags,
|
|
114
115
|
// `--no-plugins` builds the entry's owning project with plugin
|
|
115
116
|
// discovery and loading disabled. ttsc's own config loaders use it
|
|
@@ -121,6 +122,7 @@ async function run(
|
|
|
121
122
|
// tsconfig deliberately does not satisfy.
|
|
122
123
|
plugins: parsed.noPlugins ? false : undefined,
|
|
123
124
|
project: parsed.project,
|
|
125
|
+
runtimeCache: !parsed.noCache,
|
|
124
126
|
singleThreaded: parsed.singleThreaded,
|
|
125
127
|
});
|
|
126
128
|
await settleSignals();
|
|
@@ -159,6 +161,7 @@ function printHelp(): void {
|
|
|
159
161
|
" -P, --project <file> Use an explicit tsconfig.json",
|
|
160
162
|
" --cwd <dir> Resolve entry/project relative to this directory",
|
|
161
163
|
" --cache-dir <dir> Override the runner and source-plugin cache root",
|
|
164
|
+
" --no-cache Disable persistent runtime project emit reuse",
|
|
162
165
|
" --binary <path> Use an explicit tsgo binary",
|
|
163
166
|
" --no-plugins Build the project without ttsc plugins",
|
|
164
167
|
" -r, --require <module> Preload a module before the entrypoint",
|
|
@@ -244,6 +247,7 @@ async function runJavaScriptEntry(
|
|
|
244
247
|
];
|
|
245
248
|
const env: NodeJS.ProcessEnv = {
|
|
246
249
|
...process.env,
|
|
250
|
+
...(parsed.noCache ? { TTSX_DISABLE_CACHE: "1" } : {}),
|
|
247
251
|
// ttsc's own helpers run with what the user passed (#1740).
|
|
248
252
|
...TtsxNodeOptions.give(
|
|
249
253
|
process.env,
|
|
@@ -329,6 +333,7 @@ async function runPreparedEntry(
|
|
|
329
333
|
];
|
|
330
334
|
const runtimeEnv: NodeJS.ProcessEnv = {
|
|
331
335
|
...process.env,
|
|
336
|
+
...(parsed.noCache ? { TTSX_DISABLE_CACHE: "1" } : {}),
|
|
332
337
|
// ttsc's own helpers run with what the user passed (#1740).
|
|
333
338
|
...TtsxNodeOptions.give(
|
|
334
339
|
process.env,
|
|
@@ -22,7 +22,9 @@ import { createCanonicalTempDirectory } from "../../../internal/createCanonicalT
|
|
|
22
22
|
import { runtimeExecutableIdentity } from "../../../internal/runtimeExecutableIdentity";
|
|
23
23
|
import { moduleResolutionBaseSelects } from "../../../plugin/internal/load/moduleResolutionBaseSelects";
|
|
24
24
|
import { PluginContentIdentities } from "../../../plugin/internal/source/PluginContentIdentities";
|
|
25
|
+
import { SourceBuildCacheLayout } from "../../../plugin/internal/source/SourceBuildCacheLayout";
|
|
25
26
|
import { recordCacheFileUse } from "../../../plugin/internal/source/recordCacheFileUse";
|
|
27
|
+
import { resolveSourceBuildCachePaths } from "../../../plugin/internal/source/resolveSourceBuildCachePaths";
|
|
26
28
|
import { buildSingleRootProject } from "../buildSingleRootProject";
|
|
27
29
|
import { inlineServedSourceMap } from "../inlineServedSourceMap";
|
|
28
30
|
import { runtimeCompilerArgs } from "../runtimeCompilerArgs";
|
|
@@ -2192,6 +2194,15 @@ function buildDependency(
|
|
|
2192
2194
|
fs.mkdirSync(emitDir, { recursive: true });
|
|
2193
2195
|
const result = runBuild({
|
|
2194
2196
|
cwd: project.root,
|
|
2197
|
+
runtimeCacheDir:
|
|
2198
|
+
process.env.TTSX_DISABLE_CACHE === "1" ||
|
|
2199
|
+
process.env.TTSC_PLUGIN_DESCRIPTOR_LOAD === "1"
|
|
2200
|
+
? undefined
|
|
2201
|
+
: path.join(
|
|
2202
|
+
runtimeRecordStore()?.root ??
|
|
2203
|
+
resolveSourceBuildCachePaths(project.root).root,
|
|
2204
|
+
SourceBuildCacheLayout.RUNTIME_BUILD_CACHE_DIRNAME,
|
|
2205
|
+
),
|
|
2195
2206
|
forceEmitProvenance: true,
|
|
2196
2207
|
// Emit-only means diagnostics never withhold the emit, so a dependency's
|
|
2197
2208
|
// own `noEmitOnError` is switched off: honoured, it would turn any
|
|
@@ -80,6 +80,9 @@ export namespace SourceBuildCacheLayout {
|
|
|
80
80
|
/** Directory of the lowered orphan sources inside the cache root. */
|
|
81
81
|
export const ORPHAN_CACHE_DIRNAME = "ttsx-orphan";
|
|
82
82
|
|
|
83
|
+
/** Checksummed completed runtime project emits, independent of run lifetime. */
|
|
84
|
+
export const RUNTIME_BUILD_CACHE_DIRNAME = "runtime-builds";
|
|
85
|
+
|
|
83
86
|
/**
|
|
84
87
|
* The parts of the cache root whose entries are single files, each collected
|
|
85
88
|
* by `pruneCacheFileRoot` and removed by `ttsc clean`.
|
|
@@ -90,6 +93,7 @@ export namespace SourceBuildCacheLayout {
|
|
|
90
93
|
IDENTITY_CACHE_DIRNAME,
|
|
91
94
|
ANSWER_CACHE_DIRNAME,
|
|
92
95
|
ORPHAN_CACHE_DIRNAME,
|
|
96
|
+
RUNTIME_BUILD_CACHE_DIRNAME,
|
|
93
97
|
];
|
|
94
98
|
|
|
95
99
|
/**
|
|
@@ -51,6 +51,12 @@ export namespace ITtscCompilerTransformation {
|
|
|
51
51
|
* @evidence contracts/portability.md#os-neutral-implementation Graph keys use the producer's cwd-relative slash spelling with absolute slash paths for outside-root or cross-volume inputs; this protocol spelling is distinct from reported native realpaths carried by inputRealpaths and observations, which can retain lexical fallback on native VFS errors. The reported compiler case policy governs compiler membership comparisons rather than an OS-name assumption; absent policy or proof does not establish native filesystem capabilities.
|
|
52
52
|
*/
|
|
53
53
|
export interface IReferenceGraph {
|
|
54
|
+
/**
|
|
55
|
+
* Shared native read-once input view; current delivery authority, never
|
|
56
|
+
* disk freshness.
|
|
57
|
+
*/
|
|
58
|
+
compilationSnapshot?: string;
|
|
59
|
+
|
|
54
60
|
/**
|
|
55
61
|
* Effective native possible-root suffixes and output-directory exclusions.
|
|
56
62
|
* A report that differs from a host's provisional policy requires a new
|
|
@@ -83,13 +83,25 @@ export interface ITtscPluginCapabilities {
|
|
|
83
83
|
* from an output filename or configuration prediction.
|
|
84
84
|
*
|
|
85
85
|
* When omitted, ttsc does not pass the option to a strict third-party host. A
|
|
86
|
-
* runtime operation
|
|
87
|
-
*
|
|
86
|
+
* runtime operation then uses the existing externally observed provenance
|
|
87
|
+
* adapter, whose incomplete proof remains visible to the runtime consumer.
|
|
88
88
|
*
|
|
89
89
|
* @default false
|
|
90
90
|
*/
|
|
91
91
|
emitProvenance?: true;
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Whether build accepts `--emit-observations-json=<absolute private path>`
|
|
95
|
+
* and publishes its generation's compiler and native input observations.
|
|
96
|
+
* Missing support keeps runtime emits fresh rather than assuming reusable
|
|
97
|
+
* input completeness. This protocol is independent of output ownership. Hosts
|
|
98
|
+
* publish the same observation envelope as checkObservations, including
|
|
99
|
+
* failures, before releasing their Program.
|
|
100
|
+
*
|
|
101
|
+
* @default false
|
|
102
|
+
*/
|
|
103
|
+
emitObservations?: true;
|
|
104
|
+
|
|
93
105
|
/**
|
|
94
106
|
* Whether the sidecar accepts ttsc's `--project-context-json` identity
|
|
95
107
|
* protocol. The payload keeps lexical selection paths, physical Program
|
package/utility/host.go
CHANGED
|
@@ -40,6 +40,9 @@ type hostOptions struct {
|
|
|
40
40
|
// checkObservationsJSON is the caller-owned absolute check input result path.
|
|
41
41
|
checkObservationsJSON string
|
|
42
42
|
|
|
43
|
+
// emitObservationsJSON is the caller-owned absolute build input result path.
|
|
44
|
+
emitObservationsJSON string
|
|
45
|
+
|
|
43
46
|
// observationsIncomplete points to the resident host's committed generation
|
|
44
47
|
// state. It is nil for non-resident calls and updated only after success.
|
|
45
48
|
observationsIncomplete *bool
|
|
@@ -201,6 +204,10 @@ func RunBuild(args []string) int {
|
|
|
201
204
|
// diagnostics. Analysis-only success writes an empty map. The original build
|
|
202
205
|
// status remains authoritative; absent or invalid metadata supplies no ownership
|
|
203
206
|
// proof. Callers own the artifact's removal.
|
|
207
|
+
// A separately negotiated absolute emit-observations path receives this same
|
|
208
|
+
// Program's compiler and native input witnesses before its checker lease closes,
|
|
209
|
+
// including failing loaded builds. Unavailable optional observations withhold
|
|
210
|
+
// reuse without changing the build status. They supply no authority by themselves.
|
|
204
211
|
// Program.Close returns its checker lease; it does not remove emitted files or
|
|
205
212
|
// private metadata. Summary and diagnostic stream writes are best-effort here,
|
|
206
213
|
// so a zero status does not certify delivery to the supplied io.Writer values.
|
|
@@ -211,7 +218,7 @@ func RunBuild(args []string) int {
|
|
|
211
218
|
// @evidence contracts/common.md#meaningful-documentation Native paragraphs identify stream ownership, failure statuses, private metadata admission and caller artifact removal following the documentation skill.
|
|
212
219
|
// @evidence contracts/portability.md#os-neutral-implementation Driver loading and DefaultWriteFile own native paths and filesystem APIs; output streams are not replaced globally.
|
|
213
220
|
// @evidence contracts/performance.md#efficient-algorithms Admission and loading include argument/plugin-manifest parsing, native project and diagnostic work. Emission dispatches linked AST transforms through the driver, which owns native generation and one authored-coordinate correction. The final writer indexes compiler carrier/map paths and shifts generated map coordinates only when it inserts missing preamble text, including JSON/base64/VLQ and output-byte work. Optional provenance adds output-path candidate collection, successful-write bookkeeping, source-proof checks, owner sorting and JSON/file publication; costs depend on source/graph, output and metadata bytes rather than only the number of emit calls.
|
|
214
|
-
// @evidence contracts/performance.md#reuse-equivalent-work The same loaded compiler generation validates and
|
|
221
|
+
// @evidence contracts/performance.md#reuse-equivalent-work The same loaded compiler generation validates, emits and optionally publishes its input witnesses; linked program hooks remain latched rather than independently reexecuted for output files. Completed-generation reuse belongs to the caller.
|
|
215
222
|
// @evidence contracts/performance.md#bound-retention-and-release-resources Successful loading transfers one Program checker lease to a deferred Close on analysis-only, normal and failure returns. The final writer retains output-path decisions and maps awaiting their carrier without a byte cap, releases pending map entries as their carrier arrives, and reports unfinished pairs at emit completion. Facade graphs, provenance maps, writer closures and serialization buffers lose local ownership when the invocation ends; Close does not destroy all program memory, supplied-stream state or emitted disk artifacts. Callers own stream lifetime and metadata/output removal, with no invocation-enforced byte cap.
|
|
216
223
|
func RunBuildWithIO(args []string, stdout, stderr io.Writer) int {
|
|
217
224
|
opts, ok := parseHostOptions("build", args, stdout, stderr)
|
|
@@ -224,6 +231,13 @@ func RunBuildWithIO(args []string, stdout, stderr io.Writer) int {
|
|
|
224
231
|
return 2
|
|
225
232
|
}
|
|
226
233
|
defer prog.Close()
|
|
234
|
+
defer func() {
|
|
235
|
+
if opts.emitObservationsJSON != "" {
|
|
236
|
+
if err := driver.WriteCheckObservationsJSON(opts.emitObservationsJSON, prog); err != nil {
|
|
237
|
+
fmt.Fprintf(opts.stderr, "ttsc utility: emit observations write failed: %v\n", err)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}()
|
|
227
241
|
driver.WritePrettyDiagnostics(opts.stderr, diags, opts.cwd)
|
|
228
242
|
if opts.noEmit {
|
|
229
243
|
if len(diags) != 0 {
|
|
@@ -446,8 +460,10 @@ func parseHostOptions(command string, args []string, stdout, stderr io.Writer) (
|
|
|
446
460
|
tsgoArgsRaw := fs.String("tsgo-args", "", "JSON array of forwarded tsgo CLI flags")
|
|
447
461
|
provenanceJSON := ""
|
|
448
462
|
checkObservationsJSON := ""
|
|
463
|
+
emitObservationsJSON := ""
|
|
449
464
|
if command == "build" {
|
|
450
465
|
fs.StringVar(&provenanceJSON, "emit-provenance-json", "", "private absolute emit provenance result path")
|
|
466
|
+
fs.StringVar(&emitObservationsJSON, "emit-observations-json", "", "private absolute build input result path")
|
|
451
467
|
}
|
|
452
468
|
if command == "check" {
|
|
453
469
|
fs.StringVar(&checkObservationsJSON, "check-observations-json", "", "private absolute check input result path")
|
|
@@ -463,6 +479,10 @@ func parseHostOptions(command string, args []string, stdout, stderr io.Writer) (
|
|
|
463
479
|
fmt.Fprintln(stderr, "ttsc utility: check observations path must be absolute")
|
|
464
480
|
return hostOptions{}, false
|
|
465
481
|
}
|
|
482
|
+
if emitObservationsJSON != "" && !filepath.IsAbs(emitObservationsJSON) {
|
|
483
|
+
fmt.Fprintln(stderr, "ttsc utility: emit observations path must be absolute")
|
|
484
|
+
return hostOptions{}, false
|
|
485
|
+
}
|
|
466
486
|
var tsgoArgs []string
|
|
467
487
|
if *tsgoArgsRaw != "" {
|
|
468
488
|
if err := json.Unmarshal([]byte(*tsgoArgsRaw), &tsgoArgs); err != nil {
|
|
@@ -507,6 +527,7 @@ func parseHostOptions(command string, args []string, stdout, stderr io.Writer) (
|
|
|
507
527
|
stderr: stderr,
|
|
508
528
|
provenanceJSON: provenanceJSON,
|
|
509
529
|
checkObservationsJSON: checkObservationsJSON,
|
|
530
|
+
emitObservationsJSON: emitObservationsJSON,
|
|
510
531
|
}, true
|
|
511
532
|
}
|
|
512
533
|
|