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
@@ -1,10 +1,12 @@
1
1
  import fs from "node:fs";
2
+ import path from "node:path";
2
3
 
3
4
  import { CapabilityResolutionFormat } from "./CapabilityResolutionFormat";
4
5
  import type { ITtscCapabilityPluginSource } from "./ITtscCapabilityPluginSource";
5
6
  import type { ITtscCapabilityResolutionEntry } from "./ITtscCapabilityResolutionEntry";
6
7
  import { hashHostInputPaths } from "./load/hashHostInputPaths";
7
8
  import { realpathHostInputPaths } from "./load/realpathHostInputPaths";
9
+ import { PluginContentIdentities } from "./source/PluginContentIdentities";
8
10
  import { pluginSourceFilesSignature } from "./source/pluginSourceFilesSignature";
9
11
  import { pluginSourceStateHolds } from "./source/pluginSourceStateHolds";
10
12
  import { recordCacheFileUse } from "./source/recordCacheFileUse";
@@ -52,6 +54,12 @@ export function readCapabilityResolution(options: {
52
54
 
53
55
  /** Environment selecting the cache root; ambient process env when omitted. */
54
56
  env?: NodeJS.ProcessEnv;
57
+
58
+ /**
59
+ * Record store of the project's plugin cache, which proves the runtime and
60
+ * the plugin sources and SDK from metadata instead of their bytes (#1725).
61
+ */
62
+ identities?: PluginContentIdentities.Store;
55
63
  }): ITtscCapabilityResolutionEntry | null {
56
64
  const file = CapabilityResolutionFormat.resolutionFile(options);
57
65
  if (file === null) return null;
@@ -83,12 +91,14 @@ export function readCapabilityResolution(options: {
83
91
  // old one still exists.
84
92
  const sources = Object.entries(entry.pluginSources);
85
93
  const evidence = sources.some(([, source]) => source.signature !== undefined)
86
- ? CapabilityResolutionFormat.sourceEvidence(
87
- CapabilityResolutionFormat.clockReference(file),
94
+ ? PluginContentIdentities.sourceEvidence(
95
+ PluginContentIdentities.mintReference(path.dirname(file)),
88
96
  )
89
97
  : undefined;
98
+ const projectRoot = path.resolve(options.cwd);
90
99
  for (const [directory, source] of sources)
91
- if (!pluginSourceProven(directory, source, evidence)) return null;
100
+ if (!pluginSourceProven(directory, source, evidence, projectRoot))
101
+ return null;
92
102
  for (const plugin of entry.plugins)
93
103
  if (!fs.existsSync(plugin.binary)) return null;
94
104
  recordCacheFileUse(file);
@@ -108,8 +118,9 @@ function pluginSourceProven(
108
118
  directory: string,
109
119
  source: ITtscCapabilityPluginSource,
110
120
  evidence:
111
- | ReturnType<typeof CapabilityResolutionFormat.sourceEvidence>
121
+ | ReturnType<typeof PluginContentIdentities.sourceEvidence>
112
122
  | undefined,
123
+ projectRoot: string,
113
124
  ): boolean {
114
125
  try {
115
126
  const now =
@@ -123,8 +134,8 @@ function pluginSourceProven(
123
134
  now.separable &&
124
135
  now.signature === source.signature &&
125
136
  source.digest !== undefined
126
- ? { sourceDigest: source.digest }
127
- : {},
137
+ ? { projectRoot, sourceDigest: source.digest }
138
+ : { projectRoot },
128
139
  );
129
140
  } catch {
130
141
  return false;
@@ -0,0 +1,178 @@
1
+ import crypto from "node:crypto";
2
+
3
+ import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
4
+ import { GoSourceInputs } from "./GoSourceInputs";
5
+ import { PluginBuildEnvironmentWitness } from "./PluginBuildEnvironmentWitness";
6
+ import type { PluginContentIdentities } from "./PluginContentIdentities";
7
+ import { PluginLoadAnswers } from "./PluginLoadAnswers";
8
+ import { spawnGoTool } from "./spawnGoTool";
9
+
10
+ /**
11
+ * Acquire current Go values together with their environment-file evidence.
12
+ * Build digests and syntax readers share this owner; a file-location hint is
13
+ * never a retained positive environment verdict (#1516, #1712).
14
+ *
15
+ * @evidence contracts/common.md#principled-implementation The acquisition pairs actual Go output with native pre-read file evidence; callers retain their own completeness and reuse policy.
16
+ * @evidence contracts/common.md#clear-and-simple-design One namespace owns environment-file discovery and native acquisition for build and manifest clients.
17
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts No handwritten default GOENV path or process-permanent environment success replaces native Go.
18
+ * @evidence contracts/common.md#meaningful-documentation Prose distinguishes observation from a discovery hint and identifies both consumers.
19
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation The read member owns native observation and execution.
20
+ * @evidenceExclude contracts/performance.md#efficient-algorithms The read member owns acquisition and identity costs.
21
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work The read member owns hint sharing; no result cache is exposed.
22
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The read member describes the private hint map and delegated native lifetime.
23
+ */
24
+ export namespace GoEnvironmentReading {
25
+ /**
26
+ * The Go environment file each Go tool and environment was last seen to name,
27
+ * which lets a reading witness that file before `go env` reads it.
28
+ */
29
+ const goEnvironmentFiles = new Map<string, string | null>();
30
+
31
+ /**
32
+ * Answer family that carries the same location hint across processes, so a
33
+ * new process does not run `go env` once merely to learn it (#1722). A wrong
34
+ * or stale hint only costs the existing rediscovery run.
35
+ */
36
+ const ENVIRONMENT_FILE_HINT = "go-environment-file";
37
+
38
+ /**
39
+ * What chooses the file's location: `GOENV`, else `os.UserConfigDir()`
40
+ * (`%AppData%`, `$XDG_CONFIG_HOME`, `$HOME`, Plan 9's `$home`). The hint
41
+ * across processes is keyed by these alone, because a launch rarely repeats
42
+ * every unrelated variable, such as a per-run trace path, and a hint that
43
+ * misses costs the rediscovery run on every launch.
44
+ */
45
+ const LOCATION_VARIABLES = [
46
+ "GOENV",
47
+ "APPDATA",
48
+ "XDG_CONFIG_HOME",
49
+ "HOME",
50
+ "home",
51
+ ] as const;
52
+
53
+ /**
54
+ * Run `go env -json` for the requested keys and `GOENV`, the file `go env -w`
55
+ * writes, witnessing that file before the run reads it.
56
+ *
57
+ * The file decides the reading without being part of it, so only its metadata
58
+ * is kept, and it must be taken before the read: metadata taken after would
59
+ * describe an edit that landed between the two, and a reading of the old
60
+ * content would pass as proven. Which file `go env` reads is known only from
61
+ * its answer, so the file this Go tool and environment named last is
62
+ * witnessed first, and a reading that names another is taken again with that
63
+ * one witnessed. A file that keeps moving between runs leaves the reading
64
+ * unwitnessable, so a kept reading or a build keyed on it never holds.
65
+ *
66
+ * The location hint also comes from the record store when one is supplied, so
67
+ * a new process witnesses the right file on its first run instead of running
68
+ * `go env` once only to learn the name.
69
+ *
70
+ * @param identities Optional record store carrying the hint across processes.
71
+ * @returns The parsed object, or `undefined` when native acquisition or JSON
72
+ * object decoding failed.
73
+ * @evidence contracts/common.md#principled-implementation Actual Go supplies values and the environment-file path; pre-read metadata and bounded rediscovery preserve the earliest file witness instead of attaching a later state to an earlier read.
74
+ * @evidence contracts/common.md#clear-and-simple-design One acquisition serves build hashing and manifest syntax qualification; callers choose keys and own interpretation and cache admission.
75
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts A remembered file name is only a discovery hint. Every call executes Go, and unresolved movement marks its witness unproven rather than lending a historical positive verdict.
76
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain why file discovery can repeat and distinguish unavailable acquisition from current authority.
77
+ * @evidence contracts/portability.md#os-neutral-implementation Go reports its actual environment-file location; native path metadata and the existing Go process owner supply observation and execution semantics.
78
+ * @evidence contracts/performance.md#efficient-algorithms Hashing the complete tool/environment identity and up to three native Go queries process full name/value/output bytes. Requested keys contribute argument bytes; file discovery uses metadata rather than an SDK walk.
79
+ * @evidence contracts/performance.md#reuse-equivalent-work Only file-location discovery hints are shared: in process across equal selected-tool/environment identities, and through the record store across equal selected tools and location variables, since the reading verifies any hint against the file Go reports. Current Go values and file authority are reacquired for every call.
80
+ * @evidence contracts/performance.md#bound-retention-and-release-resources The module retains one file-location hint per historical tool/environment identity, without eviction, but no positive reading or native handle; persisted hints belong to the single-file collector. Command capture/retirement belongs to spawnGoTool and the caller owns the transferred witness.
81
+ */
82
+ export function read(
83
+ goBinary: string,
84
+ cwd: string,
85
+ env: NodeJS.ProcessEnv,
86
+ keys: readonly string[],
87
+ witness: PluginBuildEnvironmentWitness.Record | undefined,
88
+ identities?: PluginContentIdentities.Store,
89
+ ): Record<string, unknown> | undefined {
90
+ const memo = crypto.createHash("sha256").update(goBinary);
91
+ for (const [key, value] of Object.entries(env).sort(([left], [right]) =>
92
+ left < right ? -1 : left > right ? 1 : 0,
93
+ )) {
94
+ if (value !== undefined)
95
+ memo.update(`\0${key.length}:${key}${value.length}:${value}`);
96
+ }
97
+ const memoKey = memo.digest("hex");
98
+ let named = goEnvironmentFiles.get(memoKey);
99
+ if (named === undefined) {
100
+ const hinted = PluginLoadAnswers.read(
101
+ identities,
102
+ ENVIRONMENT_FILE_HINT,
103
+ hintKey(goBinary, env),
104
+ );
105
+ if (hinted === null || typeof hinted === "string") named = hinted;
106
+ }
107
+ const remembered = named;
108
+ for (let attempt = 0; attempt < 3; attempt += 1) {
109
+ if (named !== undefined && named !== null)
110
+ PluginBuildEnvironmentWitness.add(witness, named);
111
+ const result = spawnGoTool(goBinary, ["env", "-json", ...keys, "GOENV"], {
112
+ cwd,
113
+ encoding: "utf8",
114
+ env: GoSourceInputs.goBuildEnv(goBinary, undefined, env),
115
+ windowsHide: true,
116
+ });
117
+ if (result.error !== undefined || result.status !== 0) return undefined;
118
+ let parsed: Record<string, unknown>;
119
+ try {
120
+ const decoded: unknown = JSON.parse(result.stdout);
121
+ if (
122
+ decoded === null ||
123
+ typeof decoded !== "object" ||
124
+ Array.isArray(decoded)
125
+ )
126
+ return undefined;
127
+ parsed = decoded as Record<string, unknown>;
128
+ } catch {
129
+ return undefined;
130
+ }
131
+ const reported =
132
+ typeof parsed.GOENV === "string" &&
133
+ parsed.GOENV !== "" &&
134
+ parsed.GOENV !== "off"
135
+ ? parsed.GOENV
136
+ : null;
137
+ if (reported === named) {
138
+ goEnvironmentFiles.set(memoKey, named);
139
+ if (named !== remembered)
140
+ PluginLoadAnswers.write(
141
+ identities,
142
+ ENVIRONMENT_FILE_HINT,
143
+ hintKey(goBinary, env),
144
+ named,
145
+ );
146
+ return parsed;
147
+ }
148
+ if (named !== undefined && named !== null) witness?.delete(named);
149
+ named = reported;
150
+ goEnvironmentFiles.set(memoKey, named);
151
+ // No file to witness: the reading depends on none.
152
+ if (named === null || witness === undefined) {
153
+ if (named !== remembered)
154
+ PluginLoadAnswers.write(
155
+ identities,
156
+ ENVIRONMENT_FILE_HINT,
157
+ hintKey(goBinary, env),
158
+ named,
159
+ );
160
+ return parsed;
161
+ }
162
+ }
163
+ if (named !== undefined && named !== null)
164
+ PluginBuildEnvironmentWitness.refuse(witness, named);
165
+ return undefined;
166
+ }
167
+
168
+ // A wrong hint is safe: the reading compares it with the `GOENV` Go reports
169
+ // and runs again with the reported file witnessed.
170
+ function hintKey(goBinary: string, env: NodeJS.ProcessEnv): unknown {
171
+ return [
172
+ goBinary,
173
+ LOCATION_VARIABLES.map(
174
+ (name) => SidecarEnvironment.read(env, name) ?? null,
175
+ ),
176
+ ];
177
+ }
178
+ }