ttsc 0.26.2 → 0.28.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.
Files changed (170) hide show
  1. package/README.md +9 -0
  2. package/cmd/graphbench/main.go +26 -16
  3. package/cmd/graphdump/main.go +37 -12
  4. package/cmd/graphdump/run_declares_the_capability_its_output_carries_test.go +137 -0
  5. package/cmd/graphdump/run_reports_an_unknown_flag_without_exiting_the_process_test.go +56 -0
  6. package/cmd/graphdump/run_reports_an_unloadable_project_without_printing_a_dump_test.go +46 -0
  7. package/cmd/ttsc/api_transform.go +28 -3
  8. package/cmd/ttscgraph/auxiliary_identity_state_tracks_retargets_not_source_contents_test.go +85 -0
  9. package/cmd/ttscgraph/disk_realpath_other.go +16 -0
  10. package/cmd/ttscgraph/disk_realpath_windows.go +56 -0
  11. package/cmd/ttscgraph/dump.go +43 -11
  12. package/cmd/ttscgraph/run_dump_claims_artifacts_only_when_it_asked_test.go +135 -0
  13. package/cmd/ttscgraph/run_dump_declares_the_capability_its_output_carries_test.go +96 -0
  14. package/cmd/ttscgraph/serve.go +357 -60
  15. package/cmd/ttscgraph/serve_adopts_a_republished_artifact_set_test.go +348 -0
  16. package/cmd/ttscgraph/serve_projects_an_artifact_no_source_owns_test.go +90 -0
  17. package/cmd/ttscgraph/serve_shards.go +31 -9
  18. package/driver/config_discovery.go +121 -0
  19. package/driver/emit_plugin.go +77 -11
  20. package/driver/graph.go +64 -11
  21. package/driver/input_observation.go +273 -0
  22. package/driver/input_observation_test.go +149 -0
  23. package/driver/plugins.go +506 -15
  24. package/driver/program.go +54 -1
  25. package/driver/resolution_candidates.go +13 -5
  26. package/driver/rewrite.go +45 -2
  27. package/driver/transform_dependencies.go +283 -0
  28. package/driver/transform_dependencies_declares_every_file_without_a_contributor_test.go +28 -0
  29. package/driver/transform_dependencies_drops_a_self_reported_dependency_test.go +21 -0
  30. package/driver/transform_dependencies_keys_a_reported_path_like_the_envelope_test.go +46 -0
  31. package/driver/transform_dependencies_requires_every_contributor_to_declare_test.go +38 -0
  32. package/driver/transform_dependencies_stays_silent_for_an_undeclared_contributor_test.go +23 -0
  33. package/driver/transform_dependencies_withdraws_completeness_after_an_unusable_dependency_test.go +37 -0
  34. package/internal/graph/artifacts.go +230 -0
  35. package/internal/graph/artifacts_index_what_a_plugin_published_test.go +154 -0
  36. package/internal/graph/artifacts_survive_a_partial_rebuild_test.go +89 -0
  37. package/internal/graph/build.go +35 -0
  38. package/internal/graph/build_releases_the_scratch_it_no_longer_reads_test.go +118 -0
  39. package/internal/graph/doc_refs_are_the_use_the_checker_already_counts_test.go +93 -0
  40. package/internal/graph/doc_refs_resolve_documentation_links_test.go +335 -0
  41. package/internal/graph/doc_tags.go +416 -0
  42. package/internal/graph/doc_tags_are_claimed_before_they_are_read_test.go +131 -0
  43. package/internal/graph/doc_tags_capture_every_unrecognized_tag_test.go +165 -0
  44. package/internal/graph/doc_tags_read_only_what_the_parser_attached_test.go +97 -0
  45. package/internal/graph/doc_tags_stop_at_the_external_boundary_test.go +59 -0
  46. package/internal/graph/doc_tags_survive_line_endings_and_repeated_blocks_test.go +146 -0
  47. package/internal/graph/dump.go +60 -13
  48. package/internal/graph/dump_checkout_paths_are_stable_test.go +2 -2
  49. package/internal/graph/dump_paths.go +2 -2
  50. package/internal/graph/dump_paths_are_portable_and_injective_test.go +1 -1
  51. package/internal/graph/edge_kinds_names_every_declared_kind_test.go +49 -0
  52. package/internal/graph/edges.go +1 -0
  53. package/internal/graph/graph.go +79 -4
  54. package/internal/graph/provenance.go +29 -2
  55. package/lib/TtscCompiler.d.ts +12 -11
  56. package/lib/TtscCompiler.js +44 -29
  57. package/lib/TtscCompiler.js.map +1 -1
  58. package/lib/compiler/internal/captureProcessOutput.js +2 -2
  59. package/lib/compiler/internal/captureProcessOutput.js.map +1 -1
  60. package/lib/compiler/internal/compileProjectInMemory.js +4 -3
  61. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  62. package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +9 -0
  63. package/lib/compiler/internal/project/createNativeProjectContextArgs.js +16 -4
  64. package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -1
  65. package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -0
  66. package/lib/compiler/internal/resolveEmittedJavaScript.js +3 -0
  67. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  68. package/lib/compiler/internal/runBuild.d.ts +1 -1
  69. package/lib/compiler/internal/runBuild.js +80 -34
  70. package/lib/compiler/internal/runBuild.js.map +1 -1
  71. package/lib/compiler/internal/runSingleFileEmit.js +2 -2
  72. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  73. package/lib/compiler/internal/sharedHostHelpers.d.ts +28 -0
  74. package/lib/compiler/internal/sharedHostHelpers.js +39 -0
  75. package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
  76. package/lib/compiler/internal/startResidentTransform.js +12 -4
  77. package/lib/compiler/internal/startResidentTransform.js.map +1 -1
  78. package/lib/compiler/internal/transformProjectInMemory.d.ts +3 -0
  79. package/lib/compiler/internal/transformProjectInMemory.js +239 -35
  80. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  81. package/lib/flags/schema.js +12 -5
  82. package/lib/flags/schema.js.map +1 -1
  83. package/lib/index.d.ts +1 -0
  84. package/lib/index.js +1 -0
  85. package/lib/index.js.map +1 -1
  86. package/lib/internal/createCanonicalTempDirectory.d.ts +17 -0
  87. package/lib/internal/createCanonicalTempDirectory.js +42 -0
  88. package/lib/internal/createCanonicalTempDirectory.js.map +1 -0
  89. package/lib/internal/projectInputPathIdentity.d.ts +3 -0
  90. package/lib/internal/projectInputPathIdentity.js +11 -5
  91. package/lib/internal/projectInputPathIdentity.js.map +1 -1
  92. package/lib/internal/resolveNodeBinary.d.ts +14 -0
  93. package/lib/internal/resolveNodeBinary.js +150 -0
  94. package/lib/internal/resolveNodeBinary.js.map +1 -0
  95. package/lib/internal/resolveSafeCacheCleanupTargets.d.ts +15 -0
  96. package/lib/internal/resolveSafeCacheCleanupTargets.js +61 -0
  97. package/lib/internal/resolveSafeCacheCleanupTargets.js.map +1 -0
  98. package/lib/launcher/internal/prepareExecution.d.ts +3 -0
  99. package/lib/launcher/internal/prepareExecution.js +42 -14
  100. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  101. package/lib/launcher/internal/runTtsc.js +25 -13
  102. package/lib/launcher/internal/runTtsc.js.map +1 -1
  103. package/lib/launcher/internal/runTtscserver.js +18 -3
  104. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  105. package/lib/launcher/internal/runTtsx.js +2 -0
  106. package/lib/launcher/internal/runTtsx.js.map +1 -1
  107. package/lib/launcher/internal/runtimeHooks.d.ts +47 -3
  108. package/lib/launcher/internal/runtimeHooks.js +746 -64
  109. package/lib/launcher/internal/runtimeHooks.js.map +1 -1
  110. package/lib/plugin/internal/buildSourcePlugin.d.ts +62 -8
  111. package/lib/plugin/internal/buildSourcePlugin.js +754 -72
  112. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  113. package/lib/plugin/internal/capabilityResolutionCache.d.ts +76 -0
  114. package/lib/plugin/internal/capabilityResolutionCache.js +224 -0
  115. package/lib/plugin/internal/capabilityResolutionCache.js.map +1 -0
  116. package/lib/plugin/internal/loadProjectPlugins.d.ts +17 -5
  117. package/lib/plugin/internal/loadProjectPlugins.js +1339 -77
  118. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  119. package/lib/plugin/resolveCapabilityPlugins.d.ts +55 -0
  120. package/lib/plugin/resolveCapabilityPlugins.js +118 -0
  121. package/lib/plugin/resolveCapabilityPlugins.js.map +1 -0
  122. package/lib/register.d.ts +1 -0
  123. package/lib/register.js +46 -0
  124. package/lib/register.js.map +1 -0
  125. package/lib/structures/ITtscCompilerContext.d.ts +6 -3
  126. package/lib/structures/ITtscCompilerTransformation.d.ts +38 -0
  127. package/lib/structures/ITtscPlugin.d.ts +33 -0
  128. package/package.json +16 -9
  129. package/shim/ast/parent.go +16 -3
  130. package/shim/checker/enums_gen.go +11 -0
  131. package/shim/checker/go.mod +9 -0
  132. package/shim/checker/go.sum +22 -0
  133. package/shim/checker/shim.go +78 -0
  134. package/shim/compiler/emithook.go +10 -0
  135. package/shim/compiler/incremental.go +45 -8
  136. package/src/TtscCompiler.ts +55 -33
  137. package/src/compiler/internal/captureProcessOutput.ts +3 -2
  138. package/src/compiler/internal/compileProjectInMemory.ts +4 -3
  139. package/src/compiler/internal/project/createNativeProjectContextArgs.ts +19 -4
  140. package/src/compiler/internal/resolveEmittedJavaScript.ts +6 -0
  141. package/src/compiler/internal/runBuild.ts +102 -39
  142. package/src/compiler/internal/runSingleFileEmit.ts +2 -2
  143. package/src/compiler/internal/sharedHostHelpers.ts +44 -0
  144. package/src/compiler/internal/startResidentTransform.ts +12 -3
  145. package/src/compiler/internal/transformProjectInMemory.ts +410 -39
  146. package/src/flags/schema.ts +12 -5
  147. package/src/index.ts +1 -0
  148. package/src/internal/createCanonicalTempDirectory.ts +53 -0
  149. package/src/internal/projectInputPathIdentity.ts +17 -4
  150. package/src/internal/resolveNodeBinary.ts +173 -0
  151. package/src/internal/resolveSafeCacheCleanupTargets.ts +85 -0
  152. package/src/launcher/internal/prepareExecution.ts +50 -14
  153. package/src/launcher/internal/runTtsc.ts +24 -13
  154. package/src/launcher/internal/runTtscserver.ts +18 -3
  155. package/src/launcher/internal/runTtsx.ts +2 -0
  156. package/src/launcher/internal/runtimeHooks.ts +934 -68
  157. package/src/plugin/internal/buildSourcePlugin.ts +984 -79
  158. package/src/plugin/internal/capabilityResolutionCache.ts +305 -0
  159. package/src/plugin/internal/loadProjectPlugins.ts +1718 -104
  160. package/src/plugin/resolveCapabilityPlugins.ts +171 -0
  161. package/src/register.ts +47 -0
  162. package/src/structures/ITtscCompilerContext.ts +6 -3
  163. package/src/structures/ITtscCompilerTransformation.ts +46 -0
  164. package/src/structures/ITtscPlugin.ts +36 -0
  165. package/tools/shim_audit/baseline.json +0 -2
  166. package/utility/host.go +18 -3
  167. package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +0 -5
  168. package/lib/internal/assertSafeExplicitCacheDirectory.js +0 -26
  169. package/lib/internal/assertSafeExplicitCacheDirectory.js.map +0 -1
  170. package/src/internal/assertSafeExplicitCacheDirectory.ts +0 -29
@@ -6,6 +6,7 @@ import {
6
6
  type ProjectInputPathIdentityContext,
7
7
  createProjectInputPathIdentityContext,
8
8
  } from "../../internal/projectInputPathIdentity";
9
+ import { resolveNodeBinary } from "../../internal/resolveNodeBinary";
9
10
  import {
10
11
  hasProjectPluginEntries,
11
12
  loadProjectPlugins,
@@ -26,7 +27,10 @@ import {
26
27
  import { resolveBinary } from "./resolveBinary";
27
28
  import { resolveTsgo } from "./resolveTsgo";
28
29
  import {
30
+ TSGO_ARGS_ENV,
29
31
  assertSharedHostCompatibility,
32
+ clearInheritedTsgoArgs,
33
+ inheritedSidecarEnv,
30
34
  linkedTransformPlugins,
31
35
  resolvePluginConfigDir,
32
36
  selectSharedHostPlugin,
@@ -101,13 +105,18 @@ type BuildTiming = {
101
105
  * `TTSC_NODE_BINARY` so child processes can re-invoke the same Node.js binary
102
106
  * without searching `PATH`.
103
107
  */
104
- function mergeEnv(extra?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
105
- const base = {
108
+ function mergeEnv(
109
+ extra?: NodeJS.ProcessEnv,
110
+ cwd: string = process.cwd(),
111
+ ): NodeJS.ProcessEnv {
112
+ const env: NodeJS.ProcessEnv = {
106
113
  ...process.env,
107
- TTSC_NODE_BINARY: process.env.TTSC_NODE_BINARY ?? process.execPath,
114
+ ...extra,
108
115
  };
109
- if (!extra) return base;
110
- return { ...base, ...extra };
116
+ const node = resolveNodeBinary(env, cwd);
117
+ if (node === undefined) delete env.TTSC_NODE_BINARY;
118
+ else env.TTSC_NODE_BINARY = node;
119
+ return env;
111
120
  }
112
121
 
113
122
  function createBuildTiming(options: TtscCommonOptions): BuildTiming {
@@ -198,17 +207,29 @@ function nativePluginEnv(
198
207
  extra: NodeJS.ProcessEnv | undefined,
199
208
  execution: ReturnType<typeof resolveExecutionContext>,
200
209
  plugin?: ITtscLoadedNativePlugin,
210
+ tsgoArgs?: string,
201
211
  ): NodeJS.ProcessEnv {
202
- const env = mergeEnv({
203
- ...(execution.pluginConfigDir === undefined
204
- ? {}
205
- : { TTSC_PLUGIN_CONFIG_DIR: execution.pluginConfigDir }),
206
- TTSC_TSGO_BINARY: process.env.TTSC_TSGO_BINARY ?? execution.tsgo.binary,
207
- TTSC_TTSX_BINARY:
208
- process.env.TTSC_TTSX_BINARY ??
209
- path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
210
- ...extra,
211
- });
212
+ const env = mergeEnv(
213
+ {
214
+ ...(execution.pluginConfigDir === undefined
215
+ ? {}
216
+ : { TTSC_PLUGIN_CONFIG_DIR: execution.pluginConfigDir }),
217
+ TTSC_TSGO_BINARY: process.env.TTSC_TSGO_BINARY ?? execution.tsgo.binary,
218
+ TTSC_TTSX_BINARY:
219
+ process.env.TTSC_TTSX_BINARY ??
220
+ path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
221
+ ...extra,
222
+ },
223
+ execution.projectRoot,
224
+ );
225
+ // Forwarded tsgo argv is per-invocation state this host owns, exactly like
226
+ // the config anchor below: publish this run's payload, or drop whatever an
227
+ // ancestor ttsc process left behind when this lane forwards nothing.
228
+ if (tsgoArgs !== undefined) {
229
+ env[TSGO_ARGS_ENV] = tsgoArgs;
230
+ } else {
231
+ clearInheritedTsgoArgs(env, extra);
232
+ }
212
233
  // The anchor is per-invocation state owned by this host: when this run
213
234
  // declared none (and the caller's env does not name one), drop any value
214
235
  // inherited from an ancestor ttsc process so a nested build never
@@ -391,8 +412,11 @@ export class ResidentCheckWatchSession {
391
412
  stderr: "",
392
413
  stdout: "",
393
414
  };
394
- const checks = planResidentCheckEntries(execution.nativePlugins, (plugin) =>
395
- createNativeCheckArgs(execution, options, plugin),
415
+ const tsgoArgs = createNativeTsgoArgs(options);
416
+ const checks = planResidentCheckEntries(
417
+ execution.nativePlugins,
418
+ (plugin) => createNativeCheckArgs(execution, options, plugin),
419
+ tsgoArgs,
396
420
  );
397
421
  const request = residentCheckRequest(change, execution.projectRoot);
398
422
  // Buffer the cycle for every resident plugin before running any of them.
@@ -411,6 +435,7 @@ export class ResidentCheckWatchSession {
411
435
  "ttsc.check",
412
436
  timing,
413
437
  `ttsc check plugin ${plugin.name} time`,
438
+ tsgoArgs,
414
439
  );
415
440
  } else {
416
441
  const startedAt = process.hrtime.bigint();
@@ -420,7 +445,7 @@ export class ResidentCheckWatchSession {
420
445
  args: ["check-serve", ...args.slice(1)],
421
446
  binary: plugin.binary,
422
447
  cwd: execution.projectRoot,
423
- env: nativePluginEnv(options.env, execution, plugin),
448
+ env: nativePluginEnv(options.env, execution, plugin, tsgoArgs),
424
449
  });
425
450
  this.processes.set(key, resident);
426
451
  }
@@ -506,8 +531,9 @@ function residentCheckExecutionIsCompatible(
506
531
  function residentCheckProcessKey(
507
532
  plugin: ITtscLoadedNativePlugin,
508
533
  args: readonly string[],
534
+ tsgoArgs?: string,
509
535
  ): string {
510
- return `${plugin.binary}\0${plugin.name}\0${JSON.stringify(args)}`;
536
+ return `${plugin.binary}\0${plugin.name}\0${JSON.stringify(args)}\0${tsgoArgs ?? ""}`;
511
537
  }
512
538
 
513
539
  export type ResidentCheckEntryPlan = {
@@ -524,6 +550,11 @@ export type ResidentCheckEntryPlan = {
524
550
  export function planResidentCheckEntries(
525
551
  plugins: readonly ITtscLoadedNativePlugin[],
526
552
  createArgs: (plugin: ITtscLoadedNativePlugin) => string[],
553
+ // Part of the process identity even though it never appears in argv: the
554
+ // forwarded tsgo payload rides the environment, and a resident process holds
555
+ // the compiler options it was started with. Two cycles that forward different
556
+ // flags must not share one warm Program.
557
+ tsgoArgs?: string,
527
558
  ): ResidentCheckEntryPlan[] {
528
559
  return plugins
529
560
  .filter((candidate) => candidate.stage === "check")
@@ -534,7 +565,7 @@ export function planResidentCheckEntries(
534
565
  entryIndex,
535
566
  key:
536
567
  plugin.capabilities?.residentCheck === true
537
- ? residentCheckProcessKey(plugin, args)
568
+ ? residentCheckProcessKey(plugin, args, tsgoArgs)
538
569
  : undefined,
539
570
  plugin,
540
571
  };
@@ -830,7 +861,7 @@ function runProjectFreeTerminalFlag(
830
861
  const tsgo = resolveTsgo({ ...options, cwd });
831
862
  const res = spawnNative(tsgo.binary, [...(options.passthrough ?? [])], {
832
863
  cwd,
833
- env: mergeEnv(options.env),
864
+ env: mergeEnv(options.env, cwd),
834
865
  encoding: "utf8",
835
866
  });
836
867
  if (res.error) {
@@ -1126,6 +1157,7 @@ function buildWithNativeCompilerPlugins(
1126
1157
  "ttsc.build",
1127
1158
  timing,
1128
1159
  transformHostTimingLabel(plugins),
1160
+ createNativeBuildTsgoArgs(execution, options),
1129
1161
  );
1130
1162
  }
1131
1163
 
@@ -1150,7 +1182,7 @@ function runTsgo(
1150
1182
  ],
1151
1183
  {
1152
1184
  cwd: execution.projectRoot,
1153
- env: mergeEnv(options.env),
1185
+ env: mergeEnv(options.env, execution.projectRoot),
1154
1186
  encoding: "utf8",
1155
1187
  },
1156
1188
  );
@@ -1184,7 +1216,7 @@ function runTsgoBuild(
1184
1216
  ): TtscBuildResult {
1185
1217
  const res = spawnNative(execution.tsgo.binary, args, {
1186
1218
  cwd: execution.projectRoot,
1187
- env: mergeEnv(options.env),
1219
+ env: mergeEnv(options.env, execution.projectRoot),
1188
1220
  encoding: "utf8",
1189
1221
  });
1190
1222
  if (res.error) {
@@ -1401,15 +1433,23 @@ function createNativeBuildArgs(
1401
1433
  args.push("--quiet");
1402
1434
  }
1403
1435
  }
1404
- // The sidecar builds its Program in-process, so the pinned `rootDir` has to
1405
- // travel the same channel every other tsgo option takes to it — the host flag
1406
- // set does not declare `--rootDir`, and `filterHostArgs` would strip it.
1407
- args.push(
1408
- ...createNativeTsgoArgs(options, pinnedRootDirArgs(execution, options)),
1409
- );
1410
1436
  return args;
1411
1437
  }
1412
1438
 
1439
+ /**
1440
+ * The forwarded-tsgo payload for a native `build`/`check` emit invocation.
1441
+ *
1442
+ * The sidecar builds its Program in-process, so the pinned `rootDir` has to
1443
+ * travel the same channel every other tsgo option takes to it — the host flag
1444
+ * set does not declare `--rootDir`, and `filterHostArgs` would strip it.
1445
+ */
1446
+ function createNativeBuildTsgoArgs(
1447
+ execution: ReturnType<typeof resolveExecutionContext>,
1448
+ options: RunBuildOptions,
1449
+ ): string | undefined {
1450
+ return createNativeTsgoArgs(options, pinnedRootDirArgs(execution, options));
1451
+ }
1452
+
1413
1453
  /** Build the argument list for a native plugin check/fix/format invocation. */
1414
1454
  function createNativeCheckArgs(
1415
1455
  execution: ReturnType<typeof resolveExecutionContext>,
@@ -1440,7 +1480,6 @@ function createNativeCheckArgs(
1440
1480
  }
1441
1481
  args.push(...createNativeCheckThreadingArgs(options, plugin));
1442
1482
  args.push(...createNativeCheckDiagnosticsArgs(options, plugin));
1443
- args.push(...createNativeTsgoArgs(options));
1444
1483
  return args;
1445
1484
  }
1446
1485
 
@@ -1550,15 +1589,37 @@ function transformHostTimingLabel(
1550
1589
 
1551
1590
  /**
1552
1591
  * Forward the tsgo flags ttsc did not recognize to a native sidecar as one
1553
- * JSON-encoded `--tsgo-args` flag. The sidecar replays them through tsgo's own
1554
- * option parser onto `CompilerOptions`, so a flag like `ttsc --strict` reaches
1555
- * a plugin build the same way it reaches the plain tsgo lane. Encoded as a
1556
- * single token so the sidecars' unknown-flag filters keep it intact.
1592
+ * JSON-encoded payload. The sidecar replays them through tsgo's own option
1593
+ * parser onto `CompilerOptions`, so a flag like `ttsc --strict` reaches a
1594
+ * plugin build the same way it reaches the plain tsgo lane.
1595
+ *
1596
+ * The payload travels in the `TTSC_TSGO_ARGS` environment variable, not on the
1597
+ * sidecar's command line. #113 shipped it as a `--tsgo-args` flag, which is an
1598
+ * addition to a plugin protocol third-party hosts had already frozen: a Go
1599
+ * `flag.FlagSet` created with `flag.ContinueOnError` treats an undeclared flag
1600
+ * as fatal, so every pre-#113 sidecar answered `flag provided but not defined:
1601
+ * -tsgo-args` and exited 2. That took down `ttsc --strict`, `ttsc
1602
+ * --declaration`, `ttsx --strict` and — because {@link isolatedTsgoOutputArgs}
1603
+ * makes this payload non-empty on its own — plain `ttsc <file.ts>`, on every
1604
+ * project carrying a typia/nestia-era transform host (issue #1188).
1605
+ *
1606
+ * The environment is the channel ttsc already uses for host-owned payloads that
1607
+ * must not collide with a third-party flag set (`TTSC_LINKED_PLUGINS_JSON`,
1608
+ * `TTSC_PLUGIN_CONFIG_DIR`). It reaches those hosts without any change on their
1609
+ * side, because `buildSourcePlugin.ts::sourceBuildWorkspaceReplacements` builds
1610
+ * every source plugin against the installed ttsc's own driver, and
1611
+ * `driver.LoadProgram` reads the variable whenever the caller supplied no
1612
+ * explicit argv. It is strictly better than the capability gate `ad3443a` used
1613
+ * for `--singleThreaded` / `--checkers`: that one drops the flag for hosts that
1614
+ * cannot take it, which is acceptable for a threading knob and not for
1615
+ * `--strict`.
1616
+ *
1617
+ * Returns the JSON payload, or `undefined` when this lane forwards nothing.
1557
1618
  */
1558
1619
  function createNativeTsgoArgs(
1559
1620
  options: TtscCommonOptions,
1560
1621
  leading: readonly string[] = [],
1561
- ): string[] {
1622
+ ): string | undefined {
1562
1623
  const passthrough = [
1563
1624
  // Ahead of the user's own flags, so the same precedence holds here as on
1564
1625
  // the direct tsgo lane: whatever the user forwarded wins.
@@ -1567,9 +1628,9 @@ function createNativeTsgoArgs(
1567
1628
  ...isolatedTsgoOutputArgs(options),
1568
1629
  ];
1569
1630
  if (passthrough.length === 0) {
1570
- return [];
1631
+ return undefined;
1571
1632
  }
1572
- return ["--tsgo-args=" + JSON.stringify(passthrough)];
1633
+ return JSON.stringify(passthrough);
1573
1634
  }
1574
1635
 
1575
1636
  function isolatedTsgoOutputArgs(options: TtscCommonOptions): string[] {
@@ -1678,6 +1739,7 @@ function runNativeCheckPlugins(
1678
1739
  "ttsc.check",
1679
1740
  timing,
1680
1741
  `ttsc check plugin ${plugin.name} time`,
1742
+ createNativeTsgoArgs(options),
1681
1743
  );
1682
1744
  out = appendBuildOutput(out, result);
1683
1745
  if (result.status !== 0) {
@@ -1949,11 +2011,12 @@ function runNativePluginCommand(
1949
2011
  label: string,
1950
2012
  timing: BuildTiming,
1951
2013
  timingLabel: string,
2014
+ tsgoArgs?: string,
1952
2015
  ): TtscBuildResult {
1953
2016
  const startedAt = process.hrtime.bigint();
1954
2017
  const res = spawnNative(plugin.binary, args, {
1955
2018
  cwd: execution.projectRoot,
1956
- env: nativePluginEnv(options.env, execution, plugin),
2019
+ env: nativePluginEnv(options.env, execution, plugin, tsgoArgs),
1957
2020
  encoding: "utf8",
1958
2021
  });
1959
2022
  recordTiming(timing, timingLabel, startedAt);
@@ -2047,7 +2110,7 @@ function resolveExecutionContext(
2047
2110
  cacheDir: options.cacheDir ?? options.env?.TTSC_CACHE_DIR,
2048
2111
  cwd,
2049
2112
  entries: options.plugins,
2050
- env: { ...process.env, ...options.env },
2113
+ env: inheritedSidecarEnv(options.env),
2051
2114
  onWatchInputs: options.onWatchInputs,
2052
2115
  pluginConfigDir: options.pluginConfigDir,
2053
2116
  projectRoot,
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
- import os from "node:os";
3
2
  import path from "node:path";
4
3
 
4
+ import { createCanonicalTempDirectory } from "../../internal/createCanonicalTempDirectory";
5
5
  import type { TtscSingleFileEmitOptions } from "../../structures/internal/TtscSingleFileEmitOptions";
6
6
  import { readProjectConfig } from "./project/readProjectConfig";
7
7
  import { resolveEmittedJavaScript } from "./resolveEmittedJavaScript";
@@ -32,7 +32,7 @@ export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
32
32
  });
33
33
  const tsconfig = project.path;
34
34
  const projectRoot = project.root;
35
- const outDir = fs.mkdtempSync(path.join(os.tmpdir(), "ttsc-single-file-"));
35
+ const outDir = createCanonicalTempDirectory("ttsc-single-file-");
36
36
  try {
37
37
  const result = runBuild({
38
38
  ...options,
@@ -2,6 +2,50 @@ import path from "node:path";
2
2
 
3
3
  import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
4
4
 
5
+ /**
6
+ * Environment channel carrying the JSON-encoded tsgo argv ttsc forwards to a
7
+ * native sidecar. Mirrors `driver.TsgoArgsEnv` on the Go side; see
8
+ * `runBuild.ts::createNativeTsgoArgs` for why the payload is not a CLI flag.
9
+ */
10
+ export const TSGO_ARGS_ENV = "TTSC_TSGO_ARGS";
11
+
12
+ /**
13
+ * Drop a forwarded-tsgo payload this invocation did not publish itself.
14
+ *
15
+ * Every sidecar env starts from `process.env`, so a ttsc that is itself running
16
+ * inside a plugin sidecar — `@ttsc/lint` evaluating a config file through
17
+ * `ttsx`, for instance — would otherwise hand the outer run's `--strict` to its
18
+ * own sidecars, and `driver.LoadProgram` would apply it. The forwarded argv is
19
+ * per-invocation state the spawning host owns, the same rule
20
+ * `TTSC_PLUGIN_CONFIG_DIR` already follows. A caller that named the variable
21
+ * explicitly keeps it.
22
+ */
23
+ export function clearInheritedTsgoArgs(
24
+ env: NodeJS.ProcessEnv,
25
+ callerEnv: NodeJS.ProcessEnv | undefined,
26
+ ): void {
27
+ if (callerEnv?.[TSGO_ARGS_ENV] === undefined) {
28
+ delete env[TSGO_ARGS_ENV];
29
+ }
30
+ }
31
+
32
+ /**
33
+ * The `{ ...process.env, ...callerEnv }` a child process inherits, minus a
34
+ * forwarded-tsgo payload this lane never published.
35
+ *
36
+ * Use it at every spawn whose child can reach `driver.LoadProgram` — the
37
+ * `api-compile` / `api-transform` hosts, and the plugin loader, whose `ttsx`
38
+ * descriptor evaluation compiles a project of its own. One rule at every site
39
+ * beats four sites each reasoning about whether the variable could be present.
40
+ */
41
+ export function inheritedSidecarEnv(
42
+ callerEnv: NodeJS.ProcessEnv | undefined,
43
+ ): NodeJS.ProcessEnv {
44
+ const env: NodeJS.ProcessEnv = { ...process.env, ...callerEnv };
45
+ clearInheritedTsgoArgs(env, callerEnv);
46
+ return env;
47
+ }
48
+
5
49
  /**
6
50
  * Resolve the caller-declared plugin config anchor to an absolute path, or
7
51
  * `undefined` when the caller did not declare one.
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
 
3
+ import { resolveNodeBinary } from "../../internal/resolveNodeBinary";
3
4
  import { loadProjectPlugins } from "../../plugin/internal/loadProjectPlugins";
4
5
  import type { ITtscCompilerContext } from "../../structures/ITtscCompilerContext";
5
6
  import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
@@ -9,6 +10,8 @@ import { resolveBinary } from "./resolveBinary";
9
10
  import { resolveTsgo } from "./resolveTsgo";
10
11
  import {
11
12
  assertSharedHostCompatibility,
13
+ clearInheritedTsgoArgs,
14
+ inheritedSidecarEnv,
12
15
  linkedTransformPlugins,
13
16
  resolvePluginConfigDir,
14
17
  selectSharedHostPlugin,
@@ -52,7 +55,7 @@ export function startResidentTransform(
52
55
  cacheDir: context.cacheDir ?? context.env?.TTSC_CACHE_DIR,
53
56
  cwd,
54
57
  entries: context.plugins,
55
- env: { ...process.env, ...context.env },
58
+ env: inheritedSidecarEnv(context.env),
56
59
  pluginConfigDir: context.pluginConfigDir,
57
60
  projectRoot: context.projectRoot,
58
61
  tsconfig: project.path,
@@ -79,7 +82,7 @@ export function startResidentTransform(
79
82
  ],
80
83
  binary: host.binary,
81
84
  cwd: project.root,
82
- env: residentEnv(context, tsgoBinary, loaded.nativePlugins),
85
+ env: residentEnv(context, project.root, tsgoBinary, loaded.nativePlugins),
83
86
  });
84
87
  return { process: resident, projectRoot: project.root };
85
88
  }
@@ -95,13 +98,13 @@ export function startResidentTransform(
95
98
  */
96
99
  function residentEnv(
97
100
  context: ITtscCompilerContext,
101
+ projectRoot: string,
98
102
  tsgoBinary: string,
99
103
  nativePlugins: readonly ITtscLoadedNativePlugin[],
100
104
  ): NodeJS.ProcessEnv {
101
105
  const pluginConfigDir = resolvePluginConfigDir(context);
102
106
  const env: NodeJS.ProcessEnv = {
103
107
  ...process.env,
104
- TTSC_NODE_BINARY: process.env.TTSC_NODE_BINARY ?? process.execPath,
105
108
  ...(pluginConfigDir === undefined
106
109
  ? {}
107
110
  : { TTSC_PLUGIN_CONFIG_DIR: pluginConfigDir }),
@@ -111,6 +114,9 @@ function residentEnv(
111
114
  path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
112
115
  ...context.env,
113
116
  };
117
+ const node = resolveNodeBinary(env, projectRoot);
118
+ if (node === undefined) delete env.TTSC_NODE_BINARY;
119
+ else env.TTSC_NODE_BINARY = node;
114
120
  // The anchor is per-invocation state owned by this host: when this run
115
121
  // declared none (and the caller's env does not name one), drop any value
116
122
  // inherited from an ancestor ttsc process so a nested build never
@@ -121,6 +127,9 @@ function residentEnv(
121
127
  ) {
122
128
  delete env.TTSC_PLUGIN_CONFIG_DIR;
123
129
  }
130
+ // This lane forwards no tsgo argv of its own, so anything inherited belongs
131
+ // to an outer ttsc run and must not reach the resident sidecar.
132
+ clearInheritedTsgoArgs(env, context.env);
124
133
  const linked = linkedTransformPlugins(nativePlugins);
125
134
  if (linked.length !== 0) {
126
135
  env.TTSC_LINKED_PLUGINS_JSON = serializeNativePlugins(linked);