nx 23.1.0 → 23.1.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 (223) hide show
  1. package/dist/bin/nx.js +2 -1
  2. package/dist/release/changelog-renderer/index.js +4 -5
  3. package/dist/release/index.d.ts +1 -1
  4. package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
  5. package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
  6. package/dist/src/analytics/analytics.d.ts +6 -0
  7. package/dist/src/analytics/analytics.js +16 -8
  8. package/dist/src/analytics/index.d.ts +1 -1
  9. package/dist/src/analytics/index.js +2 -1
  10. package/dist/src/command-line/add/add.js +13 -1
  11. package/dist/src/command-line/affected/affected.js +1 -0
  12. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  13. package/dist/src/command-line/graph/graph.d.ts +1 -0
  14. package/dist/src/command-line/graph/graph.js +15 -6
  15. package/dist/src/command-line/import/import.js +2 -3
  16. package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
  17. package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
  18. package/dist/src/command-line/init/command-object.js +10 -2
  19. package/dist/src/command-line/init/configure-plugins.js +3 -2
  20. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
  21. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
  22. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
  23. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
  24. package/dist/src/command-line/init/implementation/angular/index.js +4 -2
  25. package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
  26. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
  27. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
  28. package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
  29. package/dist/src/command-line/init/implementation/utils.js +22 -3
  30. package/dist/src/command-line/init/init-v2.js +4 -5
  31. package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
  32. package/dist/src/command-line/migrate/execute-migration.js +389 -0
  33. package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
  34. package/dist/src/command-line/migrate/migrate.d.ts +5 -45
  35. package/dist/src/command-line/migrate/migrate.js +122 -402
  36. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
  37. package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
  38. package/dist/src/command-line/release/changelog.js +5 -0
  39. package/dist/src/command-line/release/index.d.ts +1 -1
  40. package/dist/src/command-line/release/utils/git.js +7 -3
  41. package/dist/src/command-line/release/utils/release-graph.d.ts +19 -2
  42. package/dist/src/command-line/release/utils/release-graph.js +71 -19
  43. package/dist/src/command-line/release/utils/remote-release-clients/github.js +7 -1
  44. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
  45. package/dist/src/command-line/release/utils/shared.d.ts +2 -2
  46. package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
  47. package/dist/src/command-line/release/version/release-group-processor.js +80 -6
  48. package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
  49. package/dist/src/command-line/release/version/version-actions.js +9 -1
  50. package/dist/src/command-line/release/version.js +9 -5
  51. package/dist/src/command-line/reset/reset.js +6 -1
  52. package/dist/src/command-line/run/run-one.js +1 -0
  53. package/dist/src/command-line/run-many/run-many.js +1 -0
  54. package/dist/src/command-line/show/show-target/info.js +11 -2
  55. package/dist/src/command-line/show/show-target/inputs.js +50 -153
  56. package/dist/src/command-line/show/show-target/outputs.js +48 -173
  57. package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
  58. package/dist/src/command-line/show/show-target/utils.js +83 -3
  59. package/dist/src/command-line/watch/watch.js +13 -0
  60. package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  61. package/dist/src/commands-runner/create-command-graph.js +5 -0
  62. package/dist/src/config/nx-json.d.ts +5 -3
  63. package/dist/src/core/graph/main.js +1 -1
  64. package/dist/src/core/graph/styles.js +1 -1
  65. package/dist/src/daemon/client/client.d.ts +52 -3
  66. package/dist/src/daemon/client/client.js +177 -55
  67. package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
  68. package/dist/src/daemon/client/daemon-environment.js +110 -2
  69. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  70. package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
  71. package/dist/src/daemon/message-types/daemon-message.js +25 -0
  72. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
  73. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
  74. package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
  75. package/dist/src/daemon/server/latest-nx.js +5 -2
  76. package/dist/src/daemon/server/server.js +31 -4
  77. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  78. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  79. package/dist/src/daemon/socket-utils.d.ts +1 -0
  80. package/dist/src/daemon/socket-utils.js +24 -3
  81. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  82. package/dist/src/daemon/tmp-dir.js +437 -15
  83. package/dist/src/devkit-internals.d.ts +96 -3
  84. package/dist/src/devkit-internals.js +200 -4
  85. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  86. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  87. package/dist/src/generators/tree.d.ts +4 -2
  88. package/dist/src/generators/utils/nx-json.js +13 -3
  89. package/dist/src/hasher/check-task-files.d.ts +86 -0
  90. package/dist/src/hasher/check-task-files.js +378 -0
  91. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  92. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  93. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  94. package/dist/src/native/index.d.ts +31 -2
  95. package/dist/src/native/index.js +71 -28
  96. package/dist/src/native/native-bindings.js +3 -0
  97. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  98. package/dist/src/native/native-file-cache-location.js +86 -12
  99. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  100. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  101. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  102. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  103. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  104. package/dist/src/plugins/js/lock-file/npm-parser.js +71 -27
  105. package/dist/src/plugins/js/lock-file/pnpm-parser.js +110 -17
  106. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +15 -9
  107. package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
  108. package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
  109. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
  110. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +14 -4
  111. package/dist/src/plugins/js/utils/register.d.ts +18 -0
  112. package/dist/src/plugins/js/utils/register.js +81 -0
  113. package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
  114. package/dist/src/plugins/js/utils/typescript.js +15 -0
  115. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  116. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  117. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  118. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  119. package/dist/src/project-graph/build-project-graph.js +7 -1
  120. package/dist/src/project-graph/error-types.d.ts +12 -1
  121. package/dist/src/project-graph/error-types.js +68 -3
  122. package/dist/src/project-graph/file-utils.js +6 -1
  123. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  124. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +22 -1
  125. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  126. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  127. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  128. package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
  129. package/dist/src/project-graph/plugins/transpiler.js +4 -0
  130. package/dist/src/project-graph/project-graph.js +23 -0
  131. package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +10 -12
  132. package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +93 -63
  133. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
  134. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +16 -15
  135. package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
  136. package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
  137. package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
  138. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
  139. package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
  140. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +149 -6
  141. package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
  142. package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
  143. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
  144. package/dist/src/project-graph/utils/project-configuration-utils.js +79 -101
  145. package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
  146. package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
  147. package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
  148. package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
  149. package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
  150. package/dist/src/tasks-runner/run-command.js +4 -2
  151. package/dist/src/tasks-runner/task-env.d.ts +9 -0
  152. package/dist/src/tasks-runner/task-env.js +31 -4
  153. package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
  154. package/dist/src/tasks-runner/task-orchestrator.js +23 -10
  155. package/dist/src/tasks-runner/utils.js +2 -6
  156. package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
  157. package/dist/src/utils/acknowledge-build-scripts.js +102 -0
  158. package/dist/src/utils/analytics-prompt.d.ts +0 -6
  159. package/dist/src/utils/analytics-prompt.js +0 -51
  160. package/dist/src/utils/assert-workspace-validity.js +7 -2
  161. package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
  162. package/dist/src/utils/catalog/manager-utils.js +22 -5
  163. package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
  164. package/dist/src/utils/catalog/pnpm-manager.js +3 -15
  165. package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
  166. package/dist/src/utils/catalog/yarn-manager.js +3 -15
  167. package/dist/src/utils/command-line-utils.js +30 -20
  168. package/dist/src/utils/fileutils.d.ts +5 -0
  169. package/dist/src/utils/fileutils.js +7 -2
  170. package/dist/src/utils/git-revision.d.ts +12 -0
  171. package/dist/src/utils/git-revision.js +25 -0
  172. package/dist/src/utils/git-utils.d.ts +16 -3
  173. package/dist/src/utils/git-utils.js +146 -52
  174. package/dist/src/utils/git-worktrees.d.ts +30 -0
  175. package/dist/src/utils/git-worktrees.js +212 -0
  176. package/dist/src/utils/ignore.d.ts +128 -1
  177. package/dist/src/utils/ignore.js +182 -12
  178. package/dist/src/utils/long-running-target.d.ts +10 -0
  179. package/dist/src/utils/long-running-target.js +19 -0
  180. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  181. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  182. package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
  183. package/dist/src/utils/min-release-age/packument.js +1 -1
  184. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  185. package/dist/src/utils/nx-tmp-dir.js +40 -0
  186. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  187. package/dist/src/utils/owned-private-dir.js +323 -0
  188. package/dist/src/utils/package-json.js +11 -7
  189. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  190. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  191. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  192. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  193. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  194. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  195. package/dist/src/utils/package-manager.d.ts +23 -2
  196. package/dist/src/utils/package-manager.js +264 -43
  197. package/dist/src/utils/provenance.js +18 -16
  198. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  199. package/dist/src/utils/registry-config/bun.js +257 -0
  200. package/dist/src/utils/registry-config/index.d.ts +13 -0
  201. package/dist/src/utils/registry-config/index.js +102 -0
  202. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  203. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  204. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  205. package/dist/src/utils/registry-config/utils.js +496 -0
  206. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  207. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  208. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  209. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  210. package/dist/src/utils/safe-spawn.d.ts +24 -0
  211. package/dist/src/utils/safe-spawn.js +104 -0
  212. package/dist/src/utils/shell-quoting.d.ts +15 -0
  213. package/dist/src/utils/shell-quoting.js +35 -0
  214. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  215. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  216. package/dist/src/utils/workspace-id.d.ts +20 -0
  217. package/dist/src/utils/workspace-id.js +54 -0
  218. package/migrations.json +13 -1
  219. package/package.json +22 -17
  220. package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
  221. package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
  222. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  223. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -8,6 +8,7 @@ const semver_1 = require("semver");
8
8
  const find_project_for_path_1 = require("../../../../project-graph/utils/find-project-for-path");
9
9
  const fileutils_1 = require("../../../../utils/fileutils");
10
10
  const get_package_name_from_import_path_1 = require("../../../../utils/get-package-name-from-import-path");
11
+ const path_1 = require("../../../../utils/path");
11
12
  const workspace_root_1 = require("../../../../utils/workspace-root");
12
13
  const packages_1 = require("../../utils/packages");
13
14
  const resolve_relative_to_dir_1 = require("../../utils/resolve-relative-to-dir");
@@ -161,11 +162,19 @@ class TargetProjectLocator {
161
162
  return externalNodeName;
162
163
  }
163
164
  const version = (0, semver_1.clean)(externalPackageJson.version);
164
- let matchingExternalNode = this.npmProjects[`npm:${externalPackageJson.name}@${version}`];
165
- if (!matchingExternalNode) {
166
- // check if it's a package alias, where the resolved package key is used as the version
165
+ const isAliasImport = packageName !== externalPackageJson.name;
166
+ let matchingExternalNode = null;
167
+ if (isAliasImport) {
168
+ // Prefer the alias node when both the alias import and the resolved package
169
+ // exist in the graph, otherwise generated package.json files lose the alias key.
167
170
  const aliasNpmProjectKey = `npm:${packageName}@npm:${externalPackageJson.name}@${version}`;
168
- matchingExternalNode = this.npmProjects[aliasNpmProjectKey];
171
+ matchingExternalNode =
172
+ this.npmProjects[aliasNpmProjectKey] ??
173
+ this.npmProjects[`npm:${packageName}`];
174
+ }
175
+ if (!matchingExternalNode) {
176
+ matchingExternalNode =
177
+ this.npmProjects[`npm:${externalPackageJson.name}@${version}`];
169
178
  }
170
179
  if (!matchingExternalNode) {
171
180
  // Fallback to package name as key. This can happen if the version in project graph is not the same as in the resolved package.json.
@@ -338,6 +347,7 @@ class TargetProjectLocator {
338
347
  }));
339
348
  }
340
349
  findProjectOfResolvedModule(resolvedModule) {
350
+ resolvedModule = (0, path_1.normalizePath)(resolvedModule);
341
351
  if (resolvedModule.startsWith('node_modules/') ||
342
352
  resolvedModule.includes('/node_modules/')) {
343
353
  return undefined;
@@ -96,6 +96,24 @@ export declare function ensureNodeNextEsmResolverRegistered(): void;
96
96
  * unaffected when both files exist. Idempotent on repeat calls.
97
97
  */
98
98
  export declare function ensureCjsResolverPatched(): void;
99
+ /**
100
+ * Make Node's module resolver honor the given export conditions for the rest of
101
+ * the process, via `module.registerHooks()`. Used when a local plugin is loaded
102
+ * from source in-process (no child process to pass `--conditions` to at spawn):
103
+ * the hook appends the conditions to every resolution so the plugin's transitive
104
+ * workspace imports resolve to source the same way the plugin entry did.
105
+ *
106
+ * No-op when:
107
+ * - `conditions` is empty (nothing to inject);
108
+ * - every target condition is already active at startup (a spawned plugin
109
+ * worker or daemon was launched with the full `--conditions` set, so Node's
110
+ * resolver already honors them and the per-resolve hook would be redundant);
111
+ * - `module.registerHooks` is unavailable (Node < 22.15 / < 23.5). Those
112
+ * runtimes keep the `NODE_OPTIONS=--conditions` escape hatch.
113
+ *
114
+ * Idempotent and best-effort.
115
+ */
116
+ export declare function ensureResolveConditionsInjected(conditions: string[]): void;
99
117
  /**
100
118
  * Whether Nx will defer to Node's native TypeScript stripping for the next
101
119
  * `.ts` load. Mirrors the gate used by `loadTsFile`/`registerTsProject` so
@@ -5,6 +5,7 @@ exports.forceRegisterEsmLoader = forceRegisterEsmLoader;
5
5
  exports.nodeNextEsmResolveHook = nodeNextEsmResolveHook;
6
6
  exports.ensureNodeNextEsmResolverRegistered = ensureNodeNextEsmResolverRegistered;
7
7
  exports.ensureCjsResolverPatched = ensureCjsResolverPatched;
8
+ exports.ensureResolveConditionsInjected = ensureResolveConditionsInjected;
8
9
  exports.isNativeStripPreferred = isNativeStripPreferred;
9
10
  exports.registerTsProject = registerTsProject;
10
11
  exports.getSwcTranspiler = getSwcTranspiler;
@@ -388,6 +389,86 @@ const isInvokedByTsx = (() => {
388
389
  return (requireArgs.some((a) => isTsxPath(a)) ||
389
390
  importArgs.some((a) => isTsxPath(a)));
390
391
  })();
392
+ let resolveConditionsInjected = false;
393
+ /**
394
+ * Make Node's module resolver honor the given export conditions for the rest of
395
+ * the process, via `module.registerHooks()`. Used when a local plugin is loaded
396
+ * from source in-process (no child process to pass `--conditions` to at spawn):
397
+ * the hook appends the conditions to every resolution so the plugin's transitive
398
+ * workspace imports resolve to source the same way the plugin entry did.
399
+ *
400
+ * No-op when:
401
+ * - `conditions` is empty (nothing to inject);
402
+ * - every target condition is already active at startup (a spawned plugin
403
+ * worker or daemon was launched with the full `--conditions` set, so Node's
404
+ * resolver already honors them and the per-resolve hook would be redundant);
405
+ * - `module.registerHooks` is unavailable (Node < 22.15 / < 23.5). Those
406
+ * runtimes keep the `NODE_OPTIONS=--conditions` escape hatch.
407
+ *
408
+ * Idempotent and best-effort.
409
+ */
410
+ function ensureResolveConditionsInjected(conditions) {
411
+ if (resolveConditionsInjected)
412
+ return;
413
+ resolveConditionsInjected = true;
414
+ if (!conditions.length)
415
+ return;
416
+ // Skip only when Node already honors every target condition (e.g. a worker or
417
+ // daemon spawned with the full `--conditions` set); a partial overlap still
418
+ // needs the hook to add the missing ones.
419
+ const activeConditions = getConditionsActiveAtStartup();
420
+ if (conditions.every((condition) => activeConditions.has(condition)))
421
+ return;
422
+ const module = require('node:module');
423
+ const registerHooks = module.registerHooks;
424
+ if (typeof registerHooks !== 'function')
425
+ return;
426
+ try {
427
+ registerHooks.call(module, {
428
+ resolve(specifier, context, nextResolve) {
429
+ const merged = context.conditions
430
+ ? [...context.conditions, ...conditions]
431
+ : conditions;
432
+ return nextResolve(specifier, { ...context, conditions: merged });
433
+ },
434
+ });
435
+ }
436
+ catch {
437
+ // Best-effort: leave Node's native resolution in place rather than failing.
438
+ }
439
+ }
440
+ /**
441
+ * Export conditions this process was started with, parsed from `--conditions`
442
+ * (or its `-C` alias) in `process.execArgv` and `NODE_OPTIONS`. Node's resolver
443
+ * already honors these, so the injected hook only needs to cover target
444
+ * conditions not present here.
445
+ */
446
+ function getConditionsActiveAtStartup() {
447
+ const active = new Set();
448
+ const collect = (tokens) => {
449
+ for (let i = 0; i < tokens.length; i++) {
450
+ const token = tokens[i];
451
+ if (token === '--conditions' || token === '-C') {
452
+ const value = tokens[i + 1];
453
+ if (value) {
454
+ active.add(value);
455
+ i++;
456
+ }
457
+ }
458
+ else if (token.startsWith('--conditions=')) {
459
+ active.add(token.slice('--conditions='.length));
460
+ }
461
+ else if (token.startsWith('-C=')) {
462
+ active.add(token.slice('-C='.length));
463
+ }
464
+ }
465
+ };
466
+ collect(process.execArgv ?? []);
467
+ const nodeOptions = process.env.NODE_OPTIONS;
468
+ if (nodeOptions)
469
+ collect(nodeOptions.split(/\s+/).filter(Boolean));
470
+ return active;
471
+ }
391
472
  /**
392
473
  * Whether the current Node.js runtime exposes native TypeScript type
393
474
  * stripping. This is the authoritative gate - it correctly handles every
@@ -20,4 +20,13 @@ export declare function getRootTsConfigCustomConditions(root?: string): string[]
20
20
  * `migrate-development-custom-condition` (21.5).
21
21
  */
22
22
  export declare function getRootTsConfigResolveExportsConditions(root?: string): string[];
23
+ /**
24
+ * Node `--conditions <name>` CLI args for spawning a plugin worker or the daemon
25
+ * with the plugin-resolution conditions active at startup. Mirrors the set Nx
26
+ * uses to resolve the plugin entry (`getRootTsConfigResolveExportsConditions`)
27
+ * so the entry and the plugin's transitive workspace imports resolve the same
28
+ * way; Node's own resolver otherwise ignores TypeScript `customConditions` and a
29
+ * source-loaded plugin's imports land on their unbuilt `dist`.
30
+ */
31
+ export declare function getPluginResolveConditionNodeArgs(root?: string): string[];
23
32
  export declare function findNodes(node: Node, kind: SyntaxKind | SyntaxKind[], max?: number): Node[];
@@ -8,6 +8,7 @@ exports.getRootTsConfigFileName = getRootTsConfigFileName;
8
8
  exports.getRootTsConfigPath = getRootTsConfigPath;
9
9
  exports.getRootTsConfigCustomConditions = getRootTsConfigCustomConditions;
10
10
  exports.getRootTsConfigResolveExportsConditions = getRootTsConfigResolveExportsConditions;
11
+ exports.getPluginResolveConditionNodeArgs = getPluginResolveConditionNodeArgs;
11
12
  exports.findNodes = findNodes;
12
13
  const workspace_root_1 = require("../../../utils/workspace-root");
13
14
  const fs_1 = require("fs");
@@ -113,6 +114,20 @@ function getRootTsConfigResolveExportsConditions(root = workspace_root_1.workspa
113
114
  ? conditions
114
115
  : [...conditions, 'development'];
115
116
  }
117
+ /**
118
+ * Node `--conditions <name>` CLI args for spawning a plugin worker or the daemon
119
+ * with the plugin-resolution conditions active at startup. Mirrors the set Nx
120
+ * uses to resolve the plugin entry (`getRootTsConfigResolveExportsConditions`)
121
+ * so the entry and the plugin's transitive workspace imports resolve the same
122
+ * way; Node's own resolver otherwise ignores TypeScript `customConditions` and a
123
+ * source-loaded plugin's imports land on their unbuilt `dist`.
124
+ */
125
+ function getPluginResolveConditionNodeArgs(root = workspace_root_1.workspaceRoot) {
126
+ return getRootTsConfigResolveExportsConditions(root).flatMap((c) => [
127
+ '--conditions',
128
+ c,
129
+ ]);
130
+ }
116
131
  function findNodes(node, kind, max = Infinity) {
117
132
  if (!node || max == 0) {
118
133
  return [];
@@ -7,5 +7,5 @@ export interface AffectedProjectGraphContext {
7
7
  touchedProjects: string[];
8
8
  }
9
9
  export interface TouchedProjectLocator<T extends Change = Change> {
10
- (fileChanges: FileChange<T>[], projectGraphNodes?: Record<string, ProjectGraphProjectNode>, nxJson?: NxJsonConfiguration<any>, packageJson?: any, projectGraph?: ProjectGraph): string[] | Promise<string[]>;
10
+ (fileChanges: FileChange<T>[], projectGraphNodes?: Record<string, ProjectGraphProjectNode>, nxJson?: NxJsonConfiguration<any>, packageJson?: any, projectGraph?: ProjectGraph, projectDeletionAffectsAllProjects?: boolean): string[] | Promise<string[]>;
11
11
  }
@@ -1,4 +1,4 @@
1
1
  import { FileChange } from '../file-utils';
2
2
  import { NxJsonConfiguration } from '../../config/nx-json';
3
3
  import { ProjectGraph } from '../../config/project-graph';
4
- export declare function filterAffected(graph: ProjectGraph, touchedFiles: FileChange[], nxJson?: NxJsonConfiguration, packageJson?: any): Promise<ProjectGraph>;
4
+ export declare function filterAffected(graph: ProjectGraph, touchedFiles: FileChange[], nxJson?: NxJsonConfiguration, packageJson?: any, projectDeletionAffectsAllProjects?: boolean): Promise<ProjectGraph>;
@@ -7,7 +7,7 @@ const touched_projects_1 = require("../../plugins/js/project-graph/affected/touc
7
7
  const operators_1 = require("../operators");
8
8
  const configuration_1 = require("../../config/configuration");
9
9
  const project_glob_changes_1 = require("./locators/project-glob-changes");
10
- async function filterAffected(graph, touchedFiles, nxJson = (0, configuration_1.readNxJson)(), packageJson = (0, file_utils_1.readPackageJson)()) {
10
+ async function filterAffected(graph, touchedFiles, nxJson = (0, configuration_1.readNxJson)(), packageJson = (0, file_utils_1.readPackageJson)(), projectDeletionAffectsAllProjects = true) {
11
11
  // Additional affected logic should be in this array.
12
12
  const touchedProjectLocators = [
13
13
  workspace_projects_1.getTouchedProjects,
@@ -18,7 +18,7 @@ async function filterAffected(graph, touchedFiles, nxJson = (0, configuration_1.
18
18
  const touchedProjects = [];
19
19
  for (const locator of touchedProjectLocators) {
20
20
  performance.mark(locator.name + ':start');
21
- const projects = await locator(touchedFiles, graph.nodes, nxJson, packageJson, graph);
21
+ const projects = await locator(touchedFiles, graph.nodes, nxJson, packageJson, graph, projectDeletionAffectsAllProjects);
22
22
  performance.mark(locator.name + ':end');
23
23
  performance.measure(locator.name, locator.name + ':start', locator.name + ':end');
24
24
  touchedProjects.push(...projects);
@@ -9,7 +9,7 @@ const fs_1 = require("fs");
9
9
  const retrieve_workspace_files_1 = require("../../utils/retrieve-workspace-files");
10
10
  const globs_1 = require("../../../utils/globs");
11
11
  const get_plugins_1 = require("../../plugins/get-plugins");
12
- const getTouchedProjectsFromProjectGlobChanges = async (touchedFiles, projectGraphNodes) => {
12
+ const getTouchedProjectsFromProjectGlobChanges = async (touchedFiles, projectGraphNodes, _nxJson, _packageJson, _projectGraph, projectDeletionAffectsAllProjects = true) => {
13
13
  const globPattern = await (async () => {
14
14
  // TODO: We need a quicker way to get patterns that should not
15
15
  // require starting up plugin workers
@@ -33,7 +33,10 @@ const getTouchedProjectsFromProjectGlobChanges = async (touchedFiles, projectGra
33
33
  // If the file no longer exists on disk, then it was deleted
34
34
  if (!(0, fs_1.existsSync)((0, path_1.join)(workspace_root_1.workspaceRoot, touchedFile.file))) {
35
35
  // If any project has been deleted, we must assume all projects were affected
36
- return Object.keys(projectGraphNodes);
36
+ if (projectDeletionAffectsAllProjects) {
37
+ return Object.keys(projectGraphNodes);
38
+ }
39
+ continue;
37
40
  }
38
41
  // Modified project config files are under a project's root, and implicitly
39
42
  // mark it as affected. Thus, we don't need to handle it here.
@@ -7,6 +7,7 @@ exports.applyProjectMetadata = applyProjectMetadata;
7
7
  const fs_1 = require("fs");
8
8
  const path_1 = require("path");
9
9
  const perf_hooks_1 = require("perf_hooks");
10
+ const analytics_1 = require("../analytics");
10
11
  const configuration_1 = require("../config/configuration");
11
12
  const file_hasher_1 = require("../hasher/file-hasher");
12
13
  const typescript_1 = require("../plugins/js/utils/typescript");
@@ -222,7 +223,12 @@ async function updateProjectGraphWithPlugins(context, initProjectGraph, plugins,
222
223
  perf_hooks_1.performance.measure(`${plugin.name}:createDependencies`, {
223
224
  start: `${plugin.name}:createDependencies - start`,
224
225
  end: `${plugin.name}:createDependencies - end`,
225
- detail: { track: true },
226
+ detail: {
227
+ track: true,
228
+ ...(analytics_1.customDimensions && {
229
+ [analytics_1.customDimensions.sampleRate]: analytics_1.PERF_SPAN_SAMPLE_RATE,
230
+ }),
231
+ },
226
232
  });
227
233
  }));
228
234
  perf_hooks_1.performance.mark('createDependencies:end');
@@ -3,6 +3,7 @@ import { ProjectConfiguration } from '../config/workspace-json-project-json';
3
3
  import { CreateNodesFunction } from './plugins/public-api';
4
4
  import { ConfigurationResult } from './utils/project-configuration-utils';
5
5
  import type { ConfigurationSourceMaps } from './utils/project-configuration/source-maps';
6
+ import type { WorktreeConflictAdvice } from '../utils/git-worktrees';
6
7
  export type ProjectGraphErrorTypes = AggregateCreateNodesError | MergeNodesError | CreateMetadataError | ProjectsWithNoNameError | MultipleProjectsWithSameNameError | ProcessDependenciesError | WorkspaceValidityError;
7
8
  export declare class StaleProjectGraphCacheError extends Error {
8
9
  constructor();
@@ -29,7 +30,17 @@ export declare class ProjectGraphError extends Error {
29
30
  export declare class MultipleProjectsWithSameNameError extends Error {
30
31
  conflicts: Map<string, string[]>;
31
32
  projects: Record<string, ProjectConfiguration>;
32
- constructor(conflicts: Map<string, string[]>, projects: Record<string, ProjectConfiguration>);
33
+ /**
34
+ * Set when some of the duplicates come from git worktrees nested in the
35
+ * workspace, which is a different fix than renaming them.
36
+ */
37
+ worktreeAdvice?: WorktreeConflictAdvice;
38
+ constructor(conflicts: Map<string, string[]>, projects: Record<string, ProjectConfiguration>,
39
+ /**
40
+ * Set when some of the duplicates come from git worktrees nested in the
41
+ * workspace, which is a different fix than renaming them.
42
+ */
43
+ worktreeAdvice?: WorktreeConflictAdvice);
33
44
  }
34
45
  export declare class ProjectWithExistingNameError extends Error {
35
46
  projectName: string;
@@ -92,19 +92,44 @@ class ProjectGraphError extends Error {
92
92
  exports.ProjectGraphError = ProjectGraphError;
93
93
  _ProjectGraphError_partialProjectGraph = new WeakMap(), _ProjectGraphError_partialSourceMaps = new WeakMap();
94
94
  class MultipleProjectsWithSameNameError extends Error {
95
- constructor(conflicts, projects) {
95
+ constructor(conflicts, projects,
96
+ /**
97
+ * Set when some of the duplicates come from git worktrees nested in the
98
+ * workspace, which is a different fix than renaming them.
99
+ */
100
+ worktreeAdvice) {
96
101
  super([
97
102
  `The following projects are defined in multiple locations:`,
98
103
  ...Array.from(conflicts.entries()).map(([project, roots]) => [`- ${project}: `, ...roots.map((r) => ` - ${r}`)].join('\n')),
99
104
  '',
100
- "To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.",
105
+ ...(worktreeAdvice?.ignoreTargets.length
106
+ ? [
107
+ 'Some of these are inside git worktrees nested in this workspace. A worktree is a full checkout, so every project in it collides with the one it was checked out from.',
108
+ '',
109
+ // Which `.gitignore` matters: a leading slash anchors to the
110
+ // directory holding the file, and these paths are relative to
111
+ // the workspace, which is not always the repository root.
112
+ 'To fix those, add the following to the .gitignore in the workspace root:',
113
+ ...worktreeAdvice.ignoreTargets.map((target) => ` ${target}`),
114
+ // Ignoring the worktrees settles only the duplicates they
115
+ // explain; anything left is an ordinary name collision and still
116
+ // needs the ordinary answer.
117
+ ...(worktreeAdvice.explainsAllConflicts
118
+ ? []
119
+ : ['', `The rest are not from worktrees. ${RENAME_ADVICE}`]),
120
+ ]
121
+ : [
122
+ `To fix this, ${RENAME_ADVICE[0].toLowerCase()}${RENAME_ADVICE.slice(1)}`,
123
+ ]),
101
124
  ].join('\n'));
102
125
  this.conflicts = conflicts;
103
126
  this.projects = projects;
127
+ this.worktreeAdvice = worktreeAdvice;
104
128
  this.name = this.constructor.name;
105
129
  }
106
130
  }
107
131
  exports.MultipleProjectsWithSameNameError = MultipleProjectsWithSameNameError;
132
+ const RENAME_ADVICE = "Set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.";
108
133
  class ProjectWithExistingNameError extends Error {
109
134
  constructor(projectName, projectRoot) {
110
135
  super(`The project "${projectName}" is defined in multiple locations.`);
@@ -242,9 +267,48 @@ class AggregateCreateNodesError extends Error {
242
267
  errorTuple.length === 2)) {
243
268
  throw new Error('AggregateCreateNodesError must be constructed with an array of tuples where the first element is a filename or undefined and the second element is the underlying error.');
244
269
  }
270
+ // Plugins pass through whatever value they caught, which is not
271
+ // guaranteed to be an Error. Coerce so formatting can rely on
272
+ // message and stack being present.
273
+ for (const errorTuple of errors) {
274
+ errorTuple[1] = coerceToError(errorTuple[1]);
275
+ }
245
276
  }
246
277
  }
247
278
  exports.AggregateCreateNodesError = AggregateCreateNodesError;
279
+ function coerceToError(value) {
280
+ if (value instanceof Error) {
281
+ return value;
282
+ }
283
+ let message;
284
+ let stack;
285
+ if (typeof value === 'object' && value !== null) {
286
+ const candidate = value;
287
+ if (typeof candidate.message === 'string') {
288
+ message = candidate.message;
289
+ if (typeof candidate.stack === 'string') {
290
+ stack = candidate.stack;
291
+ }
292
+ }
293
+ else {
294
+ try {
295
+ message = JSON.stringify(value);
296
+ }
297
+ catch {
298
+ // Circular structures cannot be stringified.
299
+ message = String(value);
300
+ }
301
+ }
302
+ }
303
+ else {
304
+ message = String(value);
305
+ }
306
+ const error = new Error(message);
307
+ // A synthesized stack would point at this coercion site rather than
308
+ // the original failure, so prefer the original stack or just the message.
309
+ error.stack = stack ?? message;
310
+ return error;
311
+ }
248
312
  function formatAggregateCreateNodesError(error, pluginName) {
249
313
  const errorCount = error.errors.length > 1 ? `${error.errors.length} errors` : 'An error';
250
314
  const pluginLocation = error.pluginIndex
@@ -270,7 +334,8 @@ function formatAggregateCreateNodesError(error, pluginName) {
270
334
  }
271
335
  for (const e of errors) {
272
336
  const messageLines = e.message.split('\n');
273
- const stackLines = e.stack.split('\n');
337
+ // Errors deserialized from a plugin worker may arrive without a stack.
338
+ const stackLines = (e.stack ?? e.message).split('\n');
274
339
  if (file) {
275
340
  errorBodyLines.push(...messageLines.map((line) => ` ${line}`));
276
341
  errorStackLines.push(...stackLines.map((line) => ` ${line}`));
@@ -12,6 +12,7 @@ const fs_1 = require("fs");
12
12
  const os_1 = require("os");
13
13
  const path_1 = require("path");
14
14
  const fileutils_1 = require("../utils/fileutils");
15
+ const git_revision_1 = require("../utils/git-revision");
15
16
  const ignore_1 = require("../utils/ignore");
16
17
  const json_diff_1 = require("../utils/json-diff");
17
18
  const workspace_root_1 = require("../utils/workspace-root");
@@ -116,11 +117,14 @@ function readLockFileAtRevision(file, lockFileName, revision, readFileAtRevision
116
117
  }
117
118
  exports.TEN_MEGABYTES = 1024 * 10000;
118
119
  function defaultReadFileAtRevision(file, revision) {
120
+ if (revision) {
121
+ (0, git_revision_1.assertValidGitRevision)(revision);
122
+ }
119
123
  try {
120
124
  const filePathInGitRepository = getFilePathInGitRepository(file);
121
125
  return !revision
122
126
  ? (0, fs_1.readFileSync)(file, 'utf-8')
123
- : (0, child_process_1.execSync)(`git show ${revision}:${filePathInGitRepository}`, {
127
+ : (0, child_process_1.execFileSync)('git', ['show', `${revision}:${filePathInGitRepository}`], {
124
128
  maxBuffer: exports.TEN_MEGABYTES,
125
129
  stdio: ['pipe', 'pipe', 'ignore'],
126
130
  windowsHide: true,
@@ -140,6 +144,7 @@ function defaultReadBunLockFileAtRevision(file, revision) {
140
144
  windowsHide: true,
141
145
  }).trim();
142
146
  }
147
+ (0, git_revision_1.assertValidGitRevision)(revision);
143
148
  const filePathInGitRepository = getFilePathInGitRepository(file);
144
149
  const tempDirectory = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'nx-bun-lock-'));
145
150
  const tempLockfilePath = (0, path_1.join)(tempDirectory, 'bun.lockb');
@@ -60,3 +60,4 @@ export declare class IsolatedPlugin implements LoadedNxPlugin {
60
60
  shutdown(): void;
61
61
  private registerProcessMetrics;
62
62
  }
63
+ export declare function getPluginWorkerSocketId(): string;
@@ -1,16 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IsolatedPlugin = void 0;
4
+ exports.getPluginWorkerSocketId = getPluginWorkerSocketId;
4
5
  const child_process_1 = require("child_process");
6
+ const crypto_1 = require("crypto");
5
7
  const net_1 = require("net");
6
8
  const path = require("path");
7
9
  const logger_1 = require("../../../daemon/logger");
8
10
  const socket_utils_1 = require("../../../daemon/socket-utils");
9
11
  const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
12
+ const typescript_1 = require("../../../plugins/js/utils/typescript");
10
13
  const installation_directory_1 = require("../../../utils/installation-directory");
11
14
  const logger_2 = require("../../../utils/logger");
12
15
  const progress_topics_1 = require("../../../utils/progress-topics");
13
16
  const wait_for_socket_connection_1 = require("../../../utils/wait-for-socket-connection");
17
+ const workspace_root_1 = require("../../../utils/workspace-root");
14
18
  const resolve_plugin_1 = require("../resolve-plugin");
15
19
  const messaging_1 = require("./messaging");
16
20
  const plugin_lifecycle_manager_1 = require("./plugin-lifecycle-manager");
@@ -335,6 +339,10 @@ class IsolatedPlugin {
335
339
  exports.IsolatedPlugin = IsolatedPlugin;
336
340
  // --- Worker Spawning Utilities ---
337
341
  global.nxPluginWorkerCount ??= 0;
342
+ function getPluginWorkerSocketId() {
343
+ const counter = global.nxPluginWorkerCount++;
344
+ return `${process.pid}-${counter.toString(36)}-${(0, crypto_1.randomBytes)(4).toString('hex')}`;
345
+ }
338
346
  async function startPluginWorker(name) {
339
347
  performance.mark(`start-plugin-worker:${name}`);
340
348
  const isWorkerTypescript = path.extname(__filename) === '.ts';
@@ -351,12 +359,25 @@ async function startPluginWorker(name) {
351
359
  }
352
360
  : {}),
353
361
  };
354
- const ipcPath = (0, socket_utils_1.getPluginOsSocketPath)([process.pid, global.nxPluginWorkerCount++, performance.now()].join('-'));
362
+ // Keep the host pid readable for diagnostics, the counter collision-free
363
+ // within this process, and entropy for a reused pid across process runs. The
364
+ // suffix is a base36 counter plus four random bytes: eleven characters after
365
+ // the pid until the counter passes 36, and fixed-length where the
366
+ // `performance.now()` stamp it replaced varied with process uptime. That
367
+ // keeps the socket path inside the 95-character budget `assertValidSocketPath`
368
+ // enforces.
369
+ const ipcPath = (0, socket_utils_1.getPluginOsSocketPath)(getPluginWorkerSocketId());
355
370
  const worker = (0, child_process_1.spawn)(process.execPath, [
371
+ // Spawn the worker with the same resolve conditions Nx uses for plugin
372
+ // entries so the plugin's transitive workspace imports resolve to source.
373
+ ...(0, typescript_1.getPluginResolveConditionNodeArgs)(),
356
374
  ...(isWorkerTypescript ? ['--require', 'ts-node/register'] : []),
357
375
  workerPath,
358
376
  ipcPath,
359
377
  name,
378
+ // The host's root. The worker validates against this rather than re-resolving,
379
+ // so the two agree by construction.
380
+ workspace_root_1.workspaceRoot,
360
381
  ], {
361
382
  stdio: ['ignore', 'pipe', 'pipe'],
362
383
  env,
@@ -107,10 +107,23 @@ type PluginMessageDefs = DefineMessages<{
107
107
  };
108
108
  };
109
109
  }>;
110
+ /**
111
+ * The sender's workspace root. Only the *worker* asserts on it, for host→worker
112
+ * messages; results and notifications carry the field but the host does not
113
+ * check it. The daemon channel is checked in the same one direction — the
114
+ * server validates inbound client messages and the client does not validate
115
+ * responses — so the two are alike rather than one being weaker.
116
+ * Optional and stamped centrally in `sendMessageOverSocket`, so the many
117
+ * message constructors need not set it; undefined is treated as not foreign,
118
+ * which is why this detects a shared socket directory rather than an attacker.
119
+ */
120
+ export type WorkspaceStampedMessage = {
121
+ workspaceRoot?: string;
122
+ };
110
123
  /** Union of all plugin worker message types */
111
- export type PluginWorkerMessage = AllMessages<PluginMessageDefs>;
124
+ export type PluginWorkerMessage = AllMessages<PluginMessageDefs> & WorkspaceStampedMessage;
112
125
  /** Union of all plugin worker result types */
113
- export type PluginWorkerResult = AllResults<PluginMessageDefs>;
126
+ export type PluginWorkerResult = AllResults<PluginMessageDefs> & WorkspaceStampedMessage;
114
127
  /** Result type for the load message */
115
128
  export type PluginWorkerLoadResult = ResultOf<PluginMessageDefs, 'load'>;
116
129
  /**
@@ -122,7 +135,7 @@ export type PluginWorkerEmitLogNotification = {
122
135
  type: 'emitLog';
123
136
  level: 'log' | 'warn' | 'error';
124
137
  message: string;
125
- };
138
+ } & WorkspaceStampedMessage;
126
139
  export type PluginWorkerNotification = PluginWorkerEmitLogNotification;
127
140
  export declare function isPluginWorkerNotification(message: Serializable): message is PluginWorkerNotification;
128
141
  export declare function isPluginWorkerMessage(message: Serializable): message is PluginWorkerMessage;
@@ -7,6 +7,7 @@ exports.consumeMessage = consumeMessage;
7
7
  exports.sendMessageOverSocket = sendMessageOverSocket;
8
8
  const socket_utils_1 = require("../../../daemon/socket-utils");
9
9
  const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
10
+ const workspace_root_1 = require("../../../utils/workspace-root");
10
11
  const NOTIFICATION_TYPES = [
11
12
  'emitLog',
12
13
  ];
@@ -81,6 +82,8 @@ async function consumeMessage(socket, raw, handlers) {
81
82
  * Sends a message over the socket with proper formatting.
82
83
  */
83
84
  function sendMessageOverSocket(socket, message) {
85
+ // Stamped here rather than in each constructor, mirroring the daemon.
86
+ message.workspaceRoot = workspace_root_1.workspaceRoot;
84
87
  socket.write((0, socket_utils_1.serialize)(message));
85
88
  socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
86
89
  }