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.
Files changed (155) hide show
  1. package/cmd/platform/main.go +2 -2
  2. package/internal/sourceprocess/contain_windows.go +10 -13
  3. package/internal/sourceprocess/started_windows.go +41 -0
  4. package/internal/sourceprocess/windows_started_publication_distinguishes_pending_from_refusal_test.go +76 -0
  5. package/internal/watchhelper/run.go +30 -20
  6. package/internal/watchhelper/run_other.go +4 -4
  7. package/internal/watchhelper/run_windows.go +471 -0
  8. package/internal/watchhelper/watchhelper.go +8 -2
  9. package/internal/watchhelper/windows_notifications_preserve_mutations_without_access_noise_test.go +506 -0
  10. package/lib/compiler/internal/build/BuildExecution.d.ts +4 -2
  11. package/lib/compiler/internal/build/BuildExecution.js +40 -12
  12. package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
  13. package/lib/compiler/internal/startResidentTransform.js +5 -4
  14. package/lib/compiler/internal/startResidentTransform.js.map +1 -1
  15. package/lib/compiler/internal/transformProjectInMemory.js +9 -7
  16. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  17. package/lib/internal/javascriptRuntimeCapabilities.d.ts +13 -4
  18. package/lib/internal/javascriptRuntimeCapabilities.js +56 -6
  19. package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
  20. package/lib/internal/nativeBinary.d.ts +3 -3
  21. package/lib/internal/nativeBinary.js +3 -3
  22. package/lib/internal/pluginSource.d.ts +1 -0
  23. package/lib/internal/pluginSource.js +1 -0
  24. package/lib/internal/pluginSource.js.map +1 -1
  25. package/lib/internal/resolveNodeBinary.d.ts +6 -1
  26. package/lib/internal/resolveNodeBinary.js +6 -2
  27. package/lib/internal/resolveNodeBinary.js.map +1 -1
  28. package/lib/internal/runtimeExecutableIdentity.d.ts +22 -13
  29. package/lib/internal/runtimeExecutableIdentity.js +192 -102
  30. package/lib/internal/runtimeExecutableIdentity.js.map +1 -1
  31. package/lib/launcher/internal/runtime/installRuntimeHooks.js +58 -4
  32. package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
  33. package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.d.ts +5 -1
  34. package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js +7 -2
  35. package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js.map +1 -1
  36. package/lib/launcher/internal/ttscserver/runTtscserver.js +8 -1
  37. package/lib/launcher/internal/ttscserver/runTtscserver.js.map +1 -1
  38. package/lib/plugin/internal/CapabilityResolutionFormat.d.ts +21 -62
  39. package/lib/plugin/internal/CapabilityResolutionFormat.js +15 -106
  40. package/lib/plugin/internal/CapabilityResolutionFormat.js.map +1 -1
  41. package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.d.ts +6 -0
  42. package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +4 -4
  43. package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
  44. package/lib/plugin/internal/load/loadProjectPlugins.d.ts +24 -14
  45. package/lib/plugin/internal/load/loadProjectPlugins.js +141 -56
  46. package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
  47. package/lib/plugin/internal/readCapabilityResolution.d.ts +6 -0
  48. package/lib/plugin/internal/readCapabilityResolution.js +8 -5
  49. package/lib/plugin/internal/readCapabilityResolution.js.map +1 -1
  50. package/lib/plugin/internal/source/GoEnvironmentReading.d.ts +48 -0
  51. package/lib/plugin/internal/source/GoEnvironmentReading.js +156 -0
  52. package/lib/plugin/internal/source/GoEnvironmentReading.js.map +1 -0
  53. package/lib/plugin/internal/source/NativeSourcePackages.d.ts +51 -13
  54. package/lib/plugin/internal/source/NativeSourcePackages.js +182 -27
  55. package/lib/plugin/internal/source/NativeSourcePackages.js.map +1 -1
  56. package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +42 -3
  57. package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +68 -7
  58. package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
  59. package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.d.ts +5 -3
  60. package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.js +14 -8
  61. package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.js.map +1 -1
  62. package/lib/plugin/internal/source/PluginContentIdentities.d.ts +265 -0
  63. package/lib/plugin/internal/source/PluginContentIdentities.js +452 -0
  64. package/lib/plugin/internal/source/PluginContentIdentities.js.map +1 -0
  65. package/lib/plugin/internal/source/PluginLoadAnswers.d.ts +63 -0
  66. package/lib/plugin/internal/source/PluginLoadAnswers.js +128 -0
  67. package/lib/plugin/internal/source/PluginLoadAnswers.js.map +1 -0
  68. package/lib/plugin/internal/source/SourceBuildCacheLayout.d.ts +10 -0
  69. package/lib/plugin/internal/source/SourceBuildCacheLayout.js +12 -0
  70. package/lib/plugin/internal/source/SourceBuildCacheLayout.js.map +1 -1
  71. package/lib/plugin/internal/source/SourcePluginWorkspace.d.ts +53 -19
  72. package/lib/plugin/internal/source/SourcePluginWorkspace.js +111 -22
  73. package/lib/plugin/internal/source/SourcePluginWorkspace.js.map +1 -1
  74. package/lib/plugin/internal/source/buildSourcePlugin.d.ts +34 -18
  75. package/lib/plugin/internal/source/buildSourcePlugin.js +52 -24
  76. package/lib/plugin/internal/source/buildSourcePlugin.js.map +1 -1
  77. package/lib/plugin/internal/source/computeCacheKey.d.ts +25 -7
  78. package/lib/plugin/internal/source/computeCacheKey.js +85 -34
  79. package/lib/plugin/internal/source/computeCacheKey.js.map +1 -1
  80. package/lib/plugin/internal/source/hashPluginBuildEnvironment.d.ts +7 -3
  81. package/lib/plugin/internal/source/hashPluginBuildEnvironment.js +75 -102
  82. package/lib/plugin/internal/source/hashPluginBuildEnvironment.js.map +1 -1
  83. package/lib/plugin/internal/source/pluginBuildEnvironment.d.ts +8 -3
  84. package/lib/plugin/internal/source/pluginBuildEnvironment.js +8 -4
  85. package/lib/plugin/internal/source/pluginBuildEnvironment.js.map +1 -1
  86. package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js +12 -2
  87. package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js.map +1 -1
  88. package/lib/plugin/internal/source/pluginBuildVersions.d.ts +2 -2
  89. package/lib/plugin/internal/source/pluginBuildVersions.js +4 -17
  90. package/lib/plugin/internal/source/pluginBuildVersions.js.map +1 -1
  91. package/lib/plugin/internal/source/pluginModuleReplaceDirectories.d.ts +6 -5
  92. package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js +10 -17
  93. package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js.map +1 -1
  94. package/lib/plugin/internal/source/pluginSourceState.d.ts +6 -2
  95. package/lib/plugin/internal/source/pluginSourceState.js +20 -8
  96. package/lib/plugin/internal/source/pluginSourceState.js.map +1 -1
  97. package/lib/plugin/internal/source/pluginSourceStateHolds.d.ts +7 -2
  98. package/lib/plugin/internal/source/pluginSourceStateHolds.js +12 -7
  99. package/lib/plugin/internal/source/pluginSourceStateHolds.js.map +1 -1
  100. package/lib/plugin/internal/source/processPluginBuildEnvironment.d.ts +7 -2
  101. package/lib/plugin/internal/source/processPluginBuildEnvironment.js +8 -3
  102. package/lib/plugin/internal/source/processPluginBuildEnvironment.js.map +1 -1
  103. package/lib/plugin/internal/source/provenPluginSourceDigest.d.ts +28 -0
  104. package/lib/plugin/internal/source/provenPluginSourceDigest.js +41 -0
  105. package/lib/plugin/internal/source/provenPluginSourceDigest.js.map +1 -0
  106. package/lib/plugin/internal/source/pruneCacheFileRoot.d.ts +3 -2
  107. package/lib/plugin/internal/source/pruneCacheFileRoot.js +3 -2
  108. package/lib/plugin/internal/source/pruneCacheFileRoot.js.map +1 -1
  109. package/lib/plugin/internal/source/ttscPackageVersion.d.ts +26 -0
  110. package/lib/plugin/internal/source/ttscPackageVersion.js +47 -0
  111. package/lib/plugin/internal/source/ttscPackageVersion.js.map +1 -0
  112. package/lib/plugin/internal/writeCapabilityResolution.d.ts +6 -0
  113. package/lib/plugin/internal/writeCapabilityResolution.js +11 -7
  114. package/lib/plugin/internal/writeCapabilityResolution.js.map +1 -1
  115. package/lib/plugin/resolveCapabilityPlugins.js +67 -15
  116. package/lib/plugin/resolveCapabilityPlugins.js.map +1 -1
  117. package/package.json +8 -8
  118. package/src/compiler/internal/build/BuildExecution.ts +46 -13
  119. package/src/compiler/internal/startResidentTransform.ts +12 -3
  120. package/src/compiler/internal/transformProjectInMemory.ts +10 -2
  121. package/src/internal/javascriptRuntimeCapabilities.ts +71 -5
  122. package/src/internal/nativeBinary.ts +3 -3
  123. package/src/internal/pluginSource.ts +1 -0
  124. package/src/internal/resolveNodeBinary.ts +12 -1
  125. package/src/internal/runtimeExecutableIdentity.ts +227 -141
  126. package/src/launcher/internal/runtime/installRuntimeHooks.ts +68 -3
  127. package/src/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.ts +11 -2
  128. package/src/launcher/internal/ttscserver/runTtscserver.ts +18 -1
  129. package/src/plugin/internal/CapabilityResolutionFormat.ts +23 -107
  130. package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +14 -4
  131. package/src/plugin/internal/load/loadProjectPlugins.ts +421 -211
  132. package/src/plugin/internal/readCapabilityResolution.ts +17 -6
  133. package/src/plugin/internal/source/GoEnvironmentReading.ts +178 -0
  134. package/src/plugin/internal/source/NativeSourcePackages.ts +365 -48
  135. package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +83 -5
  136. package/src/plugin/internal/source/PluginBuildEnvironmentWitness.ts +18 -8
  137. package/src/plugin/internal/source/PluginContentIdentities.ts +563 -0
  138. package/src/plugin/internal/source/PluginLoadAnswers.ts +151 -0
  139. package/src/plugin/internal/source/SourceBuildCacheLayout.ts +14 -0
  140. package/src/plugin/internal/source/SourcePluginWorkspace.ts +148 -25
  141. package/src/plugin/internal/source/buildSourcePlugin.ts +104 -36
  142. package/src/plugin/internal/source/computeCacheKey.ts +129 -55
  143. package/src/plugin/internal/source/hashPluginBuildEnvironment.ts +152 -105
  144. package/src/plugin/internal/source/pluginBuildEnvironment.ts +9 -2
  145. package/src/plugin/internal/source/pluginBuildEnvironmentWorker.ts +18 -2
  146. package/src/plugin/internal/source/pluginBuildVersions.ts +5 -26
  147. package/src/plugin/internal/source/pluginModuleReplaceDirectories.ts +13 -25
  148. package/src/plugin/internal/source/pluginSourceState.ts +28 -12
  149. package/src/plugin/internal/source/pluginSourceStateHolds.ts +15 -8
  150. package/src/plugin/internal/source/processPluginBuildEnvironment.ts +8 -2
  151. package/src/plugin/internal/source/provenPluginSourceDigest.ts +45 -0
  152. package/src/plugin/internal/source/pruneCacheFileRoot.ts +3 -2
  153. package/src/plugin/internal/source/ttscPackageVersion.ts +45 -0
  154. package/src/plugin/internal/writeCapabilityResolution.ts +29 -8
  155. package/src/plugin/resolveCapabilityPlugins.ts +87 -13
@@ -21,12 +21,15 @@ const spawnSyncResilient_1 = require("../../../internal/spawnSyncResilient");
21
21
  const pluginDescriptorFailureReason_1 = require("../pluginDescriptorFailureReason");
22
22
  const pluginDescriptorProcessFailure_1 = require("../pluginDescriptorProcessFailure");
23
23
  const NativeSourcePackages_1 = require("../source/NativeSourcePackages");
24
- const resolvePluginGoModule_1 = require("../source/resolvePluginGoModule");
24
+ const PluginContentIdentities_1 = require("../source/PluginContentIdentities");
25
+ const SourcePluginWorkspace_1 = require("../source/SourcePluginWorkspace");
25
26
  const buildSourcePlugin_1 = require("../source/buildSourcePlugin");
26
27
  const isPathWithin_1 = require("../source/isPathWithin");
28
+ const pluginBuildEnvironment_1 = require("../source/pluginBuildEnvironment");
27
29
  const pluginBuildVersions_1 = require("../source/pluginBuildVersions");
28
30
  const pluginModuleReplaceDirectories_1 = require("../source/pluginModuleReplaceDirectories");
29
31
  const pluginSourceState_1 = require("../source/pluginSourceState");
32
+ const resolvePluginGoModule_1 = require("../source/resolvePluginGoModule");
30
33
  const COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE_1 = require("./COMMONJS_PLUGIN_DESCRIPTOR_SHIM_SOURCE");
31
34
  const PLUGIN_DESCRIPTOR_SHIM_SOURCE_1 = require("./PLUGIN_DESCRIPTOR_SHIM_SOURCE");
32
35
  const PluginDescriptorAdmission_1 = require("./PluginDescriptorAdmission");
@@ -58,19 +61,18 @@ const visitImportMappedCandidates_1 = require("./visitImportMappedCandidates");
58
61
  * under generic host manifests while preserving source-relative input layout.
59
62
  * Main proposals must agree in their full owning module; linked proposals must
60
63
  * agree inside every selected transform host. Errors or disagreement terminate
61
- * the load rather than changing the proposed kind.
62
- * Watch callers first receive structurally selected source/module/contributor
63
- * repair interests, before metadata can reject them. Valid records then narrow
64
- * those interests to the exact build directories; interests alone never admit
65
- * a plugin, certify a kind or supply reusable source-state proof.
66
- * Returns the ordered native plugins, parsed project config, recorded
67
- * JavaScript-host inputs and unresolved selection candidates, and the keyed
68
- * state of reported Go source directories supplied to the builds
69
- * (`pluginSources`): each plugin's module root and each contributor's source,
70
- * with its state (`pluginSourceState`), the sources as the build read them
71
- * together with the environment a build there is keyed on. Directories within
72
- * ttsc's installed package, including its overlays and the fallback
73
- * linked-plugin host, are keyed but omitted from this report under the
64
+ * the load rather than changing the proposed kind. Watch callers first receive
65
+ * structurally selected source/module/contributor repair interests, before
66
+ * metadata can reject them. Valid records then narrow those interests to the
67
+ * exact build directories; interests alone never admit a plugin, certify a kind
68
+ * or supply reusable source-state proof. Returns the ordered native plugins,
69
+ * parsed project config, recorded JavaScript-host inputs and unresolved
70
+ * selection candidates, and the keyed state of reported Go source directories
71
+ * supplied to the builds (`pluginSources`): each plugin's module root and each
72
+ * contributor's source, with its state (`pluginSourceState`), the sources as
73
+ * the build read them together with the environment a build there is keyed on.
74
+ * Directories within ttsc's installed package, including its overlays and the
75
+ * fallback linked-plugin host, are keyed but omitted from this report under the
74
76
  * installed-package/version ownership policy. That policy does not prove the
75
77
  * installation cannot be edited in place. Descriptor completeness relies on the
76
78
  * runtime recorder's status and the descriptor's explicit external-read
@@ -97,7 +99,7 @@ const visitImportMappedCandidates_1 = require("./visitImportMappedCandidates");
97
99
  * @evidence contracts/common.md#meaningful-documentation Native JSDoc explains result provenance, environment and path options; helper comments explain input races, conservative proof omission, fallback authority and cleanup. Member/tag spacing and separated concepts follow the documentation skill.
98
100
  * @evidence contracts/portability.md#os-neutral-implementation Native path/file-URL conversion, createRequire and hidden spawn with explicit argv/environment implement OS-neutral selection and process execution. Physical identities are preserved separately from lexical candidates; Bun-specific differences are capability decisions, not OS guesses.
99
101
  * @evidence contracts/performance.md#efficient-algorithms Input merging and conflicts use Sets/maps and sorted path populations, with path/key/value byte costs. Discovery can repeat config/manifest/candidate reads and full hashes; descriptor work includes runtime probes, full observation/JSON processing and possibly synchronous evaluation. Watch-only preliminary publication can temporarily digest/watch the full admitted module as well as its package before kind is known; callbacks delegate topology reconciliation. Load-local replacement readings serve preliminary and final publication. Package selection groups equivalent module contexts and batches entries through Go list without dependency compilation; per-load selected-tool manifest readers share overlay readings. Builds delegate source/environment hashing, copying, cold materialized ownership admission and Go execution; per-load digest maps share selected work. Composition can be quadratic in configured plugins/aliases, and native lookup/file/output bytes are not bounded by plugin count alone.
100
- * @evidence contracts/performance.md#reuse-equivalent-work Descriptor hits require the cache's context/environment/runtime/version identity and matching recorded projections, subject to producer declarations and sequential-observation limits. Per-load source/environment maps share directory-keyed digests and one selected transform host serves linked contributors; these identities do not certify every undeclared read or atomic filesystem stability.
102
+ * @evidence contracts/performance.md#reuse-equivalent-work Descriptor hits require the cache's context/environment/runtime/version identity and matching recorded projections, subject to producer declarations and sequential-observation limits. Per-load source/environment maps share directory-keyed digests between package selection and builds, and one selected transform host serves linked contributors. Across processes, the record store opened here proves unchanged sources, toolchain and runtime from separable metadata and answers equal package selections and runtime probes (#1721, #1722, #1723); a store whose root lies inside a plugin source is withdrawn before any source is proven. These identities do not certify every undeclared read or atomic filesystem stability.
101
103
  * @evidence contracts/performance.md#bound-retention-and-release-resources Finally restores injected environment locators, attempts evaluator directory removal and closes direct-evaluator diagnostic descriptors. Close/removal can fail; synchronous completion concerns the selected evaluator and does not certify arbitrary descendants are gone. Generation maps/results scale with observed data, and disk diagnostics/result/observation files have no independent byte ceiling here. Default disk pruning has its own interval/protection/failure policy; explicit roots remain caller-owned.
102
104
  */
103
105
  function loadProjectPlugins(options) {
@@ -143,8 +145,19 @@ function loadProjectPlugins(options) {
143
145
  };
144
146
  // Where isolated descriptor evaluations keep their answers across launches
145
147
  // (`PluginDescriptorEvaluationCache`).
148
+ // WARNING (#1721, #1722, #1723): a warm load must prove its unchanged inputs
149
+ // from this store, not re-read them. Every launch is a new process, so any
150
+ // module-level memo of this load's work dies with it; a 27 s warm typia
151
+ // launch whose native build took 0.28 s is what that looked like.
152
+ const identities = options.identities ??
153
+ PluginContentIdentities_1.PluginContentIdentities.open({
154
+ projectRoot: project.root,
155
+ cacheDir: options.cacheDir,
156
+ env: effectiveEnv,
157
+ });
146
158
  const descriptorCache = {
147
159
  cacheDir: options.cacheDir,
160
+ identities,
148
161
  version: (0, pluginBuildVersions_1.pluginBuildVersions)(project.root).ttsc,
149
162
  };
150
163
  const loadedEntries = withPluginLoaderEnv(() => entries.map((entry) => {
@@ -185,10 +198,11 @@ function loadProjectPlugins(options) {
185
198
  hostInputs: [...loaded.hostInputs, ...entryCandidates],
186
199
  request,
187
200
  };
188
- }));
201
+ }), identities);
189
202
  const plugins = (0, composePluginSources_1.composePluginSources)(entries, loadedEntries.map((entry) => entry.plugin));
190
203
  const { ttsc: ttscVersion, tsgo: tsgoVersion } = (0, pluginBuildVersions_1.pluginBuildVersions)(context.projectRoot);
191
- const candidates = plugins.map((plugin, index) => {
204
+ const candidates = plugins
205
+ .map((plugin, index) => {
192
206
  const stage = PluginDescriptorAdmission_1.PluginDescriptorAdmission.stage(plugin);
193
207
  (0, validatePluginSource_1.validatePluginSource)(plugin);
194
208
  const contributors = (0, validatePluginContributors_1.validatePluginContributors)(plugin);
@@ -196,10 +210,39 @@ function loadProjectPlugins(options) {
196
210
  const label = (0, pluginLabel_1.pluginLabel)(plugin, entries[index].config, index);
197
211
  (0, requirePluginSource_1.requirePluginSource)(source, label);
198
212
  return { plugin, index, stage, contributors, source, label };
199
- }).map((candidate) => ({
213
+ })
214
+ .map((candidate) => ({
200
215
  ...candidate,
201
216
  ...(0, resolvePluginGoModule_1.resolvePluginGoModule)(candidate.source, candidate.label),
202
217
  }));
218
+ // One reading of each source directory, shared by package selection and
219
+ // every build below and reported as the state the binaries were keyed on.
220
+ const sourceDigests = new Map();
221
+ // And one reading of the environment each build directory is keyed on, which
222
+ // a plugin module root's state reports as it is.
223
+ const environmentDigests = new Map();
224
+ // With the witness of each such reading, so a build of a directory package
225
+ // selection already read keys on that reading instead of probing Go again.
226
+ const environmentWitnesses = new Map();
227
+ const readings = {
228
+ sources: sourceDigests,
229
+ environments: environmentDigests,
230
+ witnesses: environmentWitnesses,
231
+ };
232
+ // Records describing sources must never land inside one, so the store is
233
+ // admitted for source proofs only once every source of the load is known.
234
+ const sourceIdentities = PluginContentIdentities_1.PluginContentIdentities.outside(identities, [
235
+ ...candidates.flatMap((candidate) => [
236
+ candidate.moduleRoot,
237
+ candidate.packageDir,
238
+ ...(candidate.contributors ?? []).map((input) => input.source),
239
+ ]),
240
+ ...SourcePluginWorkspace_1.SourcePluginWorkspace.findTtscOverlayDirs(),
241
+ ]);
242
+ // One fixed-effective-environment load owns manifest syntax sharing from the
243
+ // first watch query through metadata and builds. Do not allocate this after
244
+ // watch projection: that silently repeats selected-Go work (#1712).
245
+ const packageReaders = new Map();
203
246
  const watchReplacements = options.onWatchInputs === undefined
204
247
  ? undefined
205
248
  : new Map();
@@ -207,11 +250,13 @@ function loadProjectPlugins(options) {
207
250
  // The prospective context reads the admitted module layout and anchors its
208
251
  // tool there before kind exists. Keep both possible final-root baselines:
209
252
  // a linked package keeps packageDir, and an executable keeps moduleRoot.
210
- const interests = new Set(candidates.flatMap((candidate) => [
253
+ const interests = new Set(candidates
254
+ .flatMap((candidate) => [
211
255
  candidate.moduleRoot,
212
256
  candidate.packageDir,
213
257
  ...(candidate.contributors ?? []).map((input) => input.source),
214
- ]).filter(reportsPluginSource));
258
+ ])
259
+ .filter(reportsPluginSource));
215
260
  options.onWatchInputs([...interests].sort());
216
261
  const initialSize = interests.size;
217
262
  for (const candidate of candidates) {
@@ -219,20 +264,21 @@ function loadProjectPlugins(options) {
219
264
  // activate their irrelevant module graph just to discover watch inputs.
220
265
  if (candidate.stage === "transform" && candidate.entry !== ".")
221
266
  continue;
222
- for (const directory of pluginReplacementWatchDirectories(candidate.moduleRoot, effectiveEnv, watchReplacements))
267
+ for (const directory of pluginReplacementWatchDirectories(candidate.moduleRoot, effectiveEnv, watchReplacements, packageReaders))
223
268
  if (reportsPluginSource(directory))
224
269
  interests.add(directory);
225
270
  }
226
271
  if (interests.size !== initialSize)
227
272
  options.onWatchInputs([...interests].sort());
228
273
  }
229
- const packageReaders = new Map();
230
274
  const proposals = NativeSourcePackages_1.NativeSourcePackages.propose(candidates.map((candidate) => ({
231
- ...candidate, ownModule: candidate.stage !== "transform",
232
- })), effectiveEnv, packageReaders);
275
+ ...candidate,
276
+ ownModule: candidate.stage !== "transform",
277
+ })), effectiveEnv, packageReaders, sourceIdentities, readings);
233
278
  const records = candidates.map(({ plugin, index, stage, contributors, source, packageDir }) => {
234
279
  const { kind, moduleRoot } = (0, resolveNativeSource_1.resolveNativeSource)(source, plugin, entries[index].config, index, {
235
- env: effectiveEnv, observation: proposals[index].observation,
280
+ env: effectiveEnv,
281
+ observation: proposals[index].observation,
236
282
  });
237
283
  if (kind === "linked" && stage !== "transform") {
238
284
  throw new Error(`ttsc: plugin "${(0, pluginLabel_1.pluginLabel)(plugin, entries[index].config, index)}" source is a linked Go package, but only transform-stage plugins can be linked into a compiler host`);
@@ -262,10 +308,11 @@ function loadProjectPlugins(options) {
262
308
  stage,
263
309
  };
264
310
  });
265
- const executableCandidates = candidates.filter((candidate) => records[candidate.index].kind === "executable" && !proposals[candidate.index].ownModule);
311
+ const executableCandidates = candidates.filter((candidate) => records[candidate.index].kind === "executable" &&
312
+ !proposals[candidate.index].ownModule);
266
313
  // Admission can now narrow the provisional interests without restamping the
267
314
  // retained package/module baselines. Final host errors still keep these roots.
268
- options.onWatchInputs?.(pluginBuildDirectories(records, effectiveEnv, watchReplacements));
315
+ options.onWatchInputs?.(pluginBuildDirectories(records, effectiveEnv, watchReplacements, packageReaders));
269
316
  const linkedContributors = records
270
317
  .filter((record) => record.stage === "transform")
271
318
  .flatMap((record) => record.kind === "linked"
@@ -279,7 +326,12 @@ function loadProjectPlugins(options) {
279
326
  const admittedExecutables = new Set();
280
327
  if (linkedContributors.length !== 0) {
281
328
  const hosts = transformHosts.length === 0
282
- ? [{ source: node_path_1.default.join(ttscPackageRoot(), "cmd", "utility-host"), label: "linked-plugin-host" }]
329
+ ? [
330
+ {
331
+ source: node_path_1.default.join(ttscPackageRoot(), "cmd", "utility-host"),
332
+ label: "linked-plugin-host",
333
+ },
334
+ ]
283
335
  : transformHosts;
284
336
  const contexts = new Map();
285
337
  for (const host of hosts) {
@@ -298,12 +350,17 @@ function loadProjectPlugins(options) {
298
350
  entry: (0, resolvePluginGoModule_1.resolvePluginGoModule)(record.source, record.label).entry,
299
351
  }));
300
352
  const observations = NativeSourcePackages_1.NativeSourcePackages.inspect({
301
- source: host.source, pluginName: host.label, env: effectiveEnv,
353
+ source: host.source,
354
+ pluginName: host.label,
355
+ env: effectiveEnv,
302
356
  readers: packageReaders,
357
+ identities: sourceIdentities,
358
+ readings,
303
359
  packages: [
304
360
  ...hostEntries,
305
361
  ...linkedContributors.map((input) => ({
306
- ...input, entry: `./contrib/${input.name}`,
362
+ ...input,
363
+ entry: `./contrib/${input.name}`,
307
364
  })),
308
365
  ],
309
366
  });
@@ -320,22 +377,22 @@ function loadProjectPlugins(options) {
320
377
  // with linked contributors were admitted together above; other equivalent
321
378
  // entries share one standalone observation, with no repeated host copy.
322
379
  const standaloneCandidates = executableCandidates.filter((candidate) => !admittedExecutables.has(candidate.source));
323
- const executablePackages = NativeSourcePackages_1.NativeSourcePackages.ownPackages(standaloneCandidates, effectiveEnv, packageReaders);
380
+ const executablePackages = NativeSourcePackages_1.NativeSourcePackages.ownPackages(standaloneCandidates, effectiveEnv, packageReaders, sourceIdentities, readings);
324
381
  standaloneCandidates.forEach((candidate, index) => {
325
382
  NativeSourcePackages_1.NativeSourcePackages.kind(executablePackages[index], candidate.label, "executable");
326
383
  });
327
384
  const packageOwnership = (source, label, linked) => [
328
- { entry: (0, resolvePluginGoModule_1.resolvePluginGoModule)(source, label).entry, kind: "executable" },
329
- ...(linked ? linkedContributors.map((input) => ({
330
- entry: `./contrib/${input.name}`, kind: "linked",
331
- })) : []),
385
+ {
386
+ entry: (0, resolvePluginGoModule_1.resolvePluginGoModule)(source, label).entry,
387
+ kind: "executable",
388
+ },
389
+ ...(linked
390
+ ? linkedContributors.map((input) => ({
391
+ entry: `./contrib/${input.name}`,
392
+ kind: "linked",
393
+ }))
394
+ : []),
332
395
  ];
333
- // One reading of each source directory, shared by every build below and
334
- // reported as the state the binaries were keyed on.
335
- const sourceDigests = new Map();
336
- // And one reading of the environment each build directory is keyed on, which
337
- // a plugin module root's state reports as it is.
338
- const environmentDigests = new Map();
339
396
  const builtTransformHosts = new Map();
340
397
  for (const record of transformHosts) {
341
398
  builtTransformHosts.set(record, (0, buildSourcePlugin_1.buildSourcePlugin)({
@@ -343,10 +400,13 @@ function loadProjectPlugins(options) {
343
400
  cacheDir: options.cacheDir,
344
401
  contributors: mergeContributors(record.contributors, hostContributors),
345
402
  env: effectiveEnv,
403
+ goModReaders: packageReaders,
404
+ identities: sourceIdentities,
346
405
  pluginName: record.label,
347
406
  packageOwnership: packageOwnership(record.source, record.label, true),
348
407
  source: record.source,
349
408
  environmentDigests,
409
+ environmentWitnesses,
350
410
  sourceDigests,
351
411
  ttscVersion,
352
412
  tsgoVersion,
@@ -358,11 +418,14 @@ function loadProjectPlugins(options) {
358
418
  cacheDir: options.cacheDir,
359
419
  contributors: linkedContributors,
360
420
  env: effectiveEnv,
421
+ goModReaders: packageReaders,
422
+ identities: sourceIdentities,
361
423
  label: "linked plugin host",
362
424
  pluginName: "linked-plugin-host",
363
425
  source: node_path_1.default.join(ttscPackageRoot(), "cmd", "utility-host"),
364
426
  packageOwnership: packageOwnership(node_path_1.default.join(ttscPackageRoot(), "cmd", "utility-host"), "linked-plugin-host", true),
365
427
  environmentDigests,
428
+ environmentWitnesses,
366
429
  sourceDigests,
367
430
  ttscVersion,
368
431
  tsgoVersion,
@@ -381,10 +444,13 @@ function loadProjectPlugins(options) {
381
444
  cacheDir: options.cacheDir,
382
445
  contributors: record.contributors,
383
446
  env: effectiveEnv,
447
+ goModReaders: packageReaders,
448
+ identities: sourceIdentities,
384
449
  pluginName: record.label,
385
450
  packageOwnership: packageOwnership(record.source, record.label, false),
386
451
  source: record.source,
387
452
  environmentDigests,
453
+ environmentWitnesses,
388
454
  sourceDigests,
389
455
  ttscVersion,
390
456
  tsgoVersion,
@@ -420,6 +486,7 @@ function loadProjectPlugins(options) {
420
486
  ...collectHostInputSnapshot(project, context, records, projectHostInputs, revalidateHostInputHashes(projectHostInputHashes, projectHostInputs), revalidateHostInputRealpaths(projectHostInputRealpaths, projectHostInputs)),
421
487
  descriptorReadsDeclared: loadedEntries.every((entry) => entry.observationsComplete && (0, declaresHostInputReads_1.declaresHostInputReads)(entry.plugin)),
422
488
  discoveryInputsComplete: project.configInputsComplete === true,
489
+ ...(identities === undefined ? {} : { identities }),
423
490
  nativePlugins: orderNativePlugins(nativePlugins),
424
491
  ...(loadedEntries.some((entry) => !entry.observationsComplete)
425
492
  ? { observationsComplete: false }
@@ -434,9 +501,8 @@ function loadProjectPlugins(options) {
434
501
  (0, pluginSourceState_1.pluginSourceState)(directory, {
435
502
  env: effectiveEnv,
436
503
  sourceDigest,
437
- ...(environmentDigests.has(directory)
438
- ? { environment: environmentDigests.get(directory) }
439
- : {}),
504
+ environment: environmentDigests.get(directory) ??
505
+ (0, pluginBuildEnvironment_1.pluginBuildEnvironment)(directory, effectiveEnv, undefined, sourceIdentities),
440
506
  }),
441
507
  ])),
442
508
  project,
@@ -852,7 +918,7 @@ function loadPluginDescriptor(request, context, effectiveEnv, descriptorCache) {
852
918
  !error.retryWithTtsx) {
853
919
  throw error;
854
920
  }
855
- const loaded = loadDescriptorViaTtsx(request, context, effectiveEnv);
921
+ const loaded = loadDescriptorViaTtsx(request, context, effectiveEnv, descriptorCache.identities);
856
922
  if (loaded === undefined) {
857
923
  throw error;
858
924
  }
@@ -885,20 +951,22 @@ class CommonJsDescriptorLoadError extends Error {
885
951
  function loadCommonJsDescriptor(request, context, effectiveEnv, descriptorCache) {
886
952
  const runtime = pluginDescriptorRuntimeBinary(effectiveEnv);
887
953
  const ttsx = effectiveEnv.TTSC_TTSX_BINARY ?? process.env.TTSC_TTSX_BINARY;
888
- const runtimeCapabilities = (0, javascriptRuntimeCapabilities_1.javascriptRuntimeCapabilities)(runtime, effectiveEnv, context.projectRoot);
954
+ const runtimeCapabilities = (0, javascriptRuntimeCapabilities_1.javascriptRuntimeCapabilities)(runtime, effectiveEnv, context.projectRoot, descriptorCache.identities);
889
955
  const node = !runtimeCapabilities.bun &&
890
956
  runtimeCapabilities.registerHooks &&
891
957
  runtimeCapabilities.executable !== undefined
892
958
  ? runtimeCapabilities.executable
893
- : (0, resolveNodeBinary_1.resolveNodeBinary)(effectiveEnv, context.projectRoot);
959
+ : (0, resolveNodeBinary_1.resolveNodeBinary)(effectiveEnv, context.projectRoot, descriptorCache.identities);
894
960
  const cacheAuthority = {
895
961
  additionalRuntime: node,
896
962
  cacheDir: descriptorCache.cacheDir,
963
+ identities: descriptorCache.identities,
897
964
  context,
898
965
  // Everything the child receives besides the per-evaluation output paths.
899
966
  env: {
900
967
  ...effectiveEnv,
901
968
  ...(node === undefined ? {} : { TTSC_NODE_BINARY: node }),
969
+ ...descriptorRecordRoot(descriptorCache.identities),
902
970
  TTSC_TTSX_BINARY: ttsx,
903
971
  },
904
972
  projectRoot: context.projectRoot,
@@ -973,6 +1041,7 @@ function loadCommonJsDescriptor(request, context, effectiveEnv, descriptorCache)
973
1041
  // The direct evaluator may be Bun, but ttsx and native config
974
1042
  // loaders require a real Node runtime with synchronous hooks.
975
1043
  ...(node === undefined ? {} : { TTSC_NODE_BINARY: node }),
1044
+ ...descriptorRecordRoot(descriptorCache.identities),
976
1045
  TTSC_TTSX_BINARY: ttsx,
977
1046
  TTSC_PLUGIN_CONTEXT: JSON.stringify(context),
978
1047
  TTSC_PLUGIN_DESCRIPTOR_LOAD: "1",
@@ -1229,11 +1298,11 @@ const TS_SOURCE_PATTERN = /\.(?:[cm]?ts|tsx)$/i;
1229
1298
  * shim with plugins disabled across the whole graph. Returns `undefined` when
1230
1299
  * `ttsx` is unavailable, so the caller can rethrow the original load error.
1231
1300
  */
1232
- function loadDescriptorViaTtsx(request, context, effectiveEnv) {
1301
+ function loadDescriptorViaTtsx(request, context, effectiveEnv, identities) {
1233
1302
  // Binary discovery prefers the instance environment, then the ambient
1234
1303
  // process.env (where `withPluginLoaderEnv` injects ttsc's own node/ttsx paths
1235
1304
  // just before this runs), then the running interpreter.
1236
- const node = (0, resolveNodeBinary_1.resolveNodeBinary)(effectiveEnv, context.projectRoot);
1305
+ const node = (0, resolveNodeBinary_1.resolveNodeBinary)(effectiveEnv, context.projectRoot, identities);
1237
1306
  const ttsx = effectiveEnv.TTSC_TTSX_BINARY ?? process.env.TTSC_TTSX_BINARY;
1238
1307
  if (node === undefined || ttsx === undefined || ttsx.length === 0) {
1239
1308
  return undefined;
@@ -1264,6 +1333,7 @@ function loadDescriptorViaTtsx(request, context, effectiveEnv) {
1264
1333
  // may recurse into further descriptor loads) finds them even when the
1265
1334
  // instance-env snapshot predates `withPluginLoaderEnv`.
1266
1335
  TTSC_NODE_BINARY: node,
1336
+ ...descriptorRecordRoot(identities),
1267
1337
  TTSC_TTSX_BINARY: ttsx,
1268
1338
  TTSC_PLUGIN_CONTEXT: JSON.stringify({
1269
1339
  binary: context.binary,
@@ -1328,6 +1398,17 @@ ${reason}`);
1328
1398
  removeEvaluationTempDir(dir);
1329
1399
  }
1330
1400
  }
1401
+ /**
1402
+ * The private variable that hands a descriptor evaluator the plugin cache root
1403
+ * this load's record store selected, so the child proves the compiler it runs
1404
+ * from that root's records instead of streaming it (#1726) and never selects a
1405
+ * cache root of its own. Absent without a store.
1406
+ */
1407
+ function descriptorRecordRoot(identities) {
1408
+ return identities === undefined
1409
+ ? {}
1410
+ : { TTSC_PLUGIN_RECORD_ROOT: identities.root };
1411
+ }
1331
1412
  /**
1332
1413
  * Expand the ttsx runtime's selected module edges into the same exact and
1333
1414
  * missing resolution inputs used by the direct isolated evaluator.
@@ -1388,6 +1469,11 @@ function readTtsxDescriptorInputs(file, request, observation) {
1388
1469
  if (typeof record.signature !== "string" ||
1389
1470
  (signatures.has(resolved) &&
1390
1471
  signatures.get(resolved) !== record.signature)) {
1472
+ E2ETrace_1.E2ETrace.capabilityResolution("plugin-descriptor-input-signature-moved", {
1473
+ resolved,
1474
+ first: signatures.get(resolved),
1475
+ later: typeof record.signature === "string" ? record.signature : null,
1476
+ });
1391
1477
  hashes.delete(resolved);
1392
1478
  realpaths.delete(resolved);
1393
1479
  signatures.delete(resolved);
@@ -1452,10 +1538,10 @@ function readTtsxDescriptorInputs(file, request, observation) {
1452
1538
  function errorMessage(error) {
1453
1539
  return error instanceof Error ? error.message : String(error);
1454
1540
  }
1455
- function withPluginLoaderEnv(run) {
1541
+ function withPluginLoaderEnv(run, identities) {
1456
1542
  const previousNode = process.env.TTSC_NODE_BINARY;
1457
1543
  const previousTtsx = process.env.TTSC_TTSX_BINARY;
1458
- const node = (0, resolveNodeBinary_1.resolveNodeBinary)({}, process.cwd());
1544
+ const node = (0, resolveNodeBinary_1.resolveNodeBinary)({}, process.cwd(), identities);
1459
1545
  if (process.env.TTSC_NODE_BINARY === undefined && node !== undefined) {
1460
1546
  process.env.TTSC_NODE_BINARY = node;
1461
1547
  }
@@ -1530,12 +1616,12 @@ function resolvePluginSource(source, projectRoot) {
1530
1616
  * that it replaces a module with, which the build compiles in place
1531
1617
  * (`pluginModuleReplaceDirectories`).
1532
1618
  */
1533
- function pluginBuildDirectories(records, env, replacements) {
1619
+ function pluginBuildDirectories(records, env, replacements, readers) {
1534
1620
  const directories = new Set();
1535
1621
  for (const record of records) {
1536
1622
  directories.add(node_path_1.default.resolve(record.kind === "linked" ? record.packageDir : record.moduleRoot));
1537
1623
  if (record.kind === "executable") {
1538
- for (const directory of pluginReplacementWatchDirectories(record.moduleRoot, env, replacements))
1624
+ for (const directory of pluginReplacementWatchDirectories(record.moduleRoot, env, replacements, readers))
1539
1625
  directories.add(directory);
1540
1626
  }
1541
1627
  for (const contributor of record.contributors ?? [])
@@ -1548,14 +1634,13 @@ function pluginBuildDirectories(records, env, replacements) {
1548
1634
  * The load shares this best-effort watch projection, not package validity or a
1549
1635
  * cross-load manifest cache. Go metadata/build admission still owns errors.
1550
1636
  */
1551
- function pluginReplacementWatchDirectories(moduleRoot, env, observed) {
1637
+ function pluginReplacementWatchDirectories(moduleRoot, env, observed, readers) {
1552
1638
  const previous = observed?.get(moduleRoot);
1553
1639
  if (previous !== undefined)
1554
1640
  return previous;
1555
1641
  let directories;
1556
1642
  try {
1557
- directories = (0, pluginModuleReplaceDirectories_1.pluginModuleReplaceDirectories)(moduleRoot, env)
1558
- .map((replacement) => replacement.directory);
1643
+ directories = (0, pluginModuleReplaceDirectories_1.pluginModuleReplaceDirectories)(moduleRoot, env, undefined, undefined, readers).map((replacement) => replacement.directory);
1559
1644
  }
1560
1645
  catch {
1561
1646
  // An unreadable manifest/tool is not valid metadata. The already observed