nx 22.7.0 → 22.7.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 (58) hide show
  1. package/dist/bin/nx.d.ts +1 -0
  2. package/dist/bin/nx.js +5 -2
  3. package/dist/src/ai/clone-ai-config-repo.js +20 -3
  4. package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +15 -23
  5. package/dist/src/analytics/analytics.js +10 -1
  6. package/dist/src/command-line/graph/graph.js +0 -1
  7. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +13 -1
  8. package/dist/src/command-line/init/implementation/dot-nx/nxw.js +2 -1
  9. package/dist/src/command-line/migrate/command-object.js +5 -0
  10. package/dist/src/command-line/migrate/migrate.d.ts +10 -2
  11. package/dist/src/command-line/migrate/migrate.js +157 -30
  12. package/dist/src/command-line/release/config/use-legacy-versioning.d.ts +2 -0
  13. package/dist/src/command-line/release/config/use-legacy-versioning.js +8 -0
  14. package/dist/src/command-line/release/utils/shared.js +22 -12
  15. package/dist/src/config/misc-interfaces.d.ts +6 -0
  16. package/dist/src/core/graph/main.js +1 -1
  17. package/dist/src/core/graph/styles.css +1 -1
  18. package/dist/src/daemon/client/client.js +1 -1
  19. package/dist/src/daemon/client/daemon-environment.js +2 -0
  20. package/dist/src/daemon/is-nx-version-mismatch.d.ts +0 -1
  21. package/dist/src/daemon/is-nx-version-mismatch.js +2 -18
  22. package/dist/src/daemon/server/latest-nx.js +2 -0
  23. package/dist/src/daemon/server/server.js +2 -1
  24. package/dist/src/daemon/server/start.d.ts +1 -1
  25. package/dist/src/daemon/server/start.js +2 -0
  26. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  27. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  28. package/dist/src/plugins/js/lock-file/npm-parser.js +37 -19
  29. package/dist/src/plugins/js/lock-file/pnpm-parser.js +51 -4
  30. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +12 -4
  31. package/dist/src/project-graph/plugins/isolation/plugin-worker.d.ts +1 -0
  32. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +2 -0
  33. package/dist/src/tasks-runner/life-cycles/task-history-life-cycle-old.js +13 -2
  34. package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -5
  35. package/dist/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +11 -2
  36. package/dist/src/tasks-runner/run-command.js +10 -4
  37. package/dist/src/tasks-runner/task-orchestrator.js +26 -5
  38. package/dist/src/tasks-runner/utils.d.ts +11 -0
  39. package/dist/src/tasks-runner/utils.js +37 -0
  40. package/dist/src/utils/ab-testing.js +12 -0
  41. package/dist/src/utils/compile-cache.d.ts +24 -0
  42. package/dist/src/utils/compile-cache.js +49 -0
  43. package/dist/src/utils/enable-compile-cache.d.ts +1 -0
  44. package/dist/src/utils/enable-compile-cache.js +7 -0
  45. package/dist/src/utils/has-nx-js-plugin.d.ts +9 -0
  46. package/dist/src/utils/has-nx-js-plugin.js +24 -0
  47. package/dist/src/utils/installed-nx-version.d.ts +8 -0
  48. package/dist/src/utils/installed-nx-version.js +67 -0
  49. package/dist/src/utils/logger.d.ts +12 -1
  50. package/dist/src/utils/logger.js +57 -36
  51. package/dist/src/utils/nx-key.d.ts +0 -1
  52. package/dist/src/utils/nx-key.js +20 -23
  53. package/dist/src/utils/output.d.ts +3 -2
  54. package/dist/src/utils/output.js +29 -28
  55. package/dist/src/utils/package-json.js +2 -13
  56. package/dist/src/utils/perf-logging.js +3 -1
  57. package/dist/src/utils/workspace-context.js +1 -1
  58. package/package.json +22 -15
@@ -79,14 +79,25 @@ class TaskHistoryLifeCycle {
79
79
  }
80
80
  printFlakyTasksMessage() {
81
81
  if (this.flakyTasks?.length > 0) {
82
+ const MAX_VISIBLE_FLAKY = 5;
83
+ const visibleFlaky = this.flakyTasks.length > MAX_VISIBLE_FLAKY + 1
84
+ ? this.flakyTasks.slice(0, MAX_VISIBLE_FLAKY)
85
+ : this.flakyTasks;
86
+ const hiddenCount = this.flakyTasks.length - visibleFlaky.length;
87
+ const flakyRows = visibleFlaky.map((hash) => {
88
+ const taskRun = this.taskRuns.get(hash);
89
+ return ` ${(0, serialize_target_1.serializeTarget)(taskRun.target.project, taskRun.target.target, taskRun.target.configuration)}`;
90
+ });
91
+ if (hiddenCount > 0) {
92
+ flakyRows.push(` ${hiddenCount} more...`);
93
+ }
82
94
  output_1.output.warn({
83
- title: `Nx detected ${this.flakyTasks.length === 1 ? 'a flaky task' : ' flaky tasks'}`,
95
+ title: `Nx detected ${this.flakyTasks.length === 1
96
+ ? 'a flaky task'
97
+ : `${this.flakyTasks.length} flaky tasks`}`,
84
98
  bodyLines: [
85
99
  ,
86
- ...this.flakyTasks.map((hash) => {
87
- const taskRun = this.taskRuns.get(hash);
88
- return ` ${(0, serialize_target_1.serializeTarget)(taskRun.target.project, taskRun.target.target, taskRun.target.configuration)}`;
89
- }),
100
+ ...flakyRows,
90
101
  ...((0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)())
91
102
  ? []
92
103
  : [
@@ -67,6 +67,12 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, taskGraph, args,
67
67
  displayStoppedTasks.add(taskId);
68
68
  inProgressTasks.delete(taskId);
69
69
  }
70
+ else if (taskStatus === 2 /* NativeTaskStatus.Skipped */) {
71
+ // Skipped tasks don't get an endTasks() call; clear them here so the run
72
+ // summary doesn't treat them as still-in-progress and report Cancelled.
73
+ tasksToTaskStatus[taskId] = 'skipped';
74
+ inProgressTasks.delete(taskId);
75
+ }
70
76
  };
71
77
  lifeCycle.endTasks = (taskResults) => {
72
78
  for (const { task, status, terminalOutput } of taskResults) {
@@ -132,10 +138,13 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, taskGraph, args,
132
138
  (0, task_history_life_cycle_1.getTasksHistoryLifeCycle)().printFlakyTasksMessage();
133
139
  };
134
140
  const printRunOneSummary = ({ failure, cancelled, }) => {
135
- // Prints task outputs in the order they were completed
136
- // above the summary, since run-one should print all task results.
141
+ // Print task outputs in completion order above the summary.
137
142
  for (const taskId of taskIdsInTheOrderTheyStart) {
138
143
  const taskStatus = tasksToTaskStatus[taskId];
144
+ // Skipped tasks never ran; don't print a misleading `> nx run` header.
145
+ if (taskStatus === 'skipped') {
146
+ continue;
147
+ }
139
148
  const terminalOutput = getTerminalOutput(taskId);
140
149
  output_1.output.logCommandOutput(taskId, taskStatus, terminalOutput);
141
150
  }
@@ -11,9 +11,9 @@ const tslib_1 = require("tslib");
11
11
  const enquirer_1 = require("enquirer");
12
12
  const node_path_1 = require("node:path");
13
13
  const node_util_1 = require("node:util");
14
- const ora = require('ora');
15
14
  const nx_json_1 = require("../config/nx-json");
16
15
  const client_1 = require("../daemon/client/client");
16
+ const spinner_1 = require("../utils/spinner");
17
17
  const create_task_hasher_1 = require("../hasher/create-task-hasher");
18
18
  const hash_task_1 = require("../hasher/hash-task");
19
19
  const native_1 = require("../native");
@@ -22,6 +22,7 @@ const project_graph_1 = require("../project-graph/project-graph");
22
22
  const handle_errors_1 = require("../utils/handle-errors");
23
23
  const is_ci_1 = require("../utils/is-ci");
24
24
  const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
25
+ const logger_1 = require("../utils/logger");
25
26
  const nx_key_1 = require("../utils/nx-key");
26
27
  const output_1 = require("../utils/output");
27
28
  const sync_generators_1 = require("../utils/sync-generators");
@@ -324,6 +325,10 @@ async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs
324
325
  return status;
325
326
  }
326
327
  async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
328
+ // Kick off the license lookup in the background so it overlaps with task
329
+ // execution. The log itself is deferred to the print site below so it
330
+ // never lands in the middle of task output.
331
+ const nxKeyPromise = (0, nx_key_1.getNxKeyInformation)().catch(() => null);
327
332
  const projectNames = projectsToRun.map((t) => t.name);
328
333
  const projectNameSet = new Set(projectNames);
329
334
  const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
@@ -348,7 +353,9 @@ async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }
348
353
  printSummary();
349
354
  }
350
355
  await printConfigureAiAgentsDisclaimer();
351
- await (0, nx_key_1.printNxKey)();
356
+ const nxKey = await nxKeyPromise;
357
+ if (nxKey)
358
+ logger_1.logger.log((0, nx_key_1.createNxKeyLicenseeInformation)(nxKey));
352
359
  return {
353
360
  taskResults,
354
361
  completed: didCommandComplete(tasks, taskResults),
@@ -486,8 +493,7 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, project
486
493
  const applyChanges = nxJson.sync?.applyChanges === true ||
487
494
  (await promptForApplyingSyncGeneratorChanges());
488
495
  if (applyChanges) {
489
- const spinner = ora('Syncing the workspace...');
490
- spinner.start();
496
+ const spinner = spinner_1.globalSpinner.start('Syncing the workspace...');
491
497
  // Flush sync generator changes to disk
492
498
  const flushResult = await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
493
499
  if ('generatorFailures' in flushResult) {
@@ -29,6 +29,14 @@ const task_env_1 = require("./task-env");
29
29
  const tasks_schedule_1 = require("./tasks-schedule");
30
30
  const utils_1 = require("./utils");
31
31
  const shared_running_task_1 = require("./running-tasks/shared-running-task");
32
+ /**
33
+ * Resolve a batch executor's per-task result to a TaskStatus. Prefers an
34
+ * explicit `status` from the executor; falls back to the `success` boolean
35
+ * for executors that pre-date the `status` field.
36
+ */
37
+ function resolveBatchTaskStatus(result) {
38
+ return result.status ?? (result.success ? 'success' : 'failure');
39
+ }
32
40
  class TaskOrchestrator {
33
41
  // endregion internal state
34
42
  constructor(hasher, initiatingProject, initiatingTasks, projectGraph, taskGraph, nxJson, options, bail, daemon, outputStyle, taskGraphForHashing = taskGraph) {
@@ -57,7 +65,12 @@ class TaskOrchestrator {
57
65
  // region internal state
58
66
  this.batchEnv = (0, task_env_1.getEnvVariablesForBatchProcess)(this.options.skipNxCache, this.options.captureStderr);
59
67
  this.reverseTaskDeps = (0, utils_1.calculateReverseDeps)(this.taskGraph);
60
- this.initializingTaskIds = new Set(this.initiatingTasks.map((t) => t.id));
68
+ // `nx:noop` initiating tasks exit instantly via the fast-path in
69
+ // `spawnProcess`. If we treat the noop itself as the keep-alive anchor for
70
+ // its continuous dependencies, `cleanUpUnneededContinuousTasks` kills those
71
+ // children the moment the noop finishes. Expand through noops so the
72
+ // underlying real tasks become the anchors.
73
+ this.initializingTaskIds = (0, utils_1.expandInitiatingTasksThroughNoop)(this.initiatingTasks, this.taskGraph, this.projectGraph);
61
74
  this.processedTasks = new Map();
62
75
  this.completedTasks = new Map();
63
76
  this.waitingForTasks = [];
@@ -493,11 +506,18 @@ class TaskOrchestrator {
493
506
  // Heavy operations (caching, scheduling, complete) happen at batch-end in postRunSteps
494
507
  batchProcess.onTaskResults((taskId, result) => {
495
508
  const task = this.taskGraph.tasks[taskId];
496
- const status = result.success ? 'success' : 'failure';
497
- this.options.lifeCycle.printTaskTerminalOutput(task, status, result.terminalOutput ?? '');
509
+ const status = resolveBatchTaskStatus(result);
510
+ // Append before print so printTaskTerminalOutput finds the PTY already
511
+ // populated and no-ops; reversing the order writes terminalOutput twice.
498
512
  if (result.terminalOutput) {
499
513
  this.options.lifeCycle.appendTaskOutput(taskId, result.terminalOutput, false);
500
514
  }
515
+ // Skipped tasks didn't run, so they have no terminal output and don't
516
+ // need a per-task PTY — calling printTaskTerminalOutput would otherwise
517
+ // allocate one just to write a cursor-hide escape.
518
+ if (status !== 'skipped') {
519
+ this.options.lifeCycle.printTaskTerminalOutput(task, status, result.terminalOutput ?? '');
520
+ }
501
521
  task.startTime = result.startTime;
502
522
  task.endTime = result.endTime;
503
523
  if (result.startTime && result.endTime) {
@@ -511,10 +531,11 @@ class TaskOrchestrator {
511
531
  const task = this.taskGraph.tasks[taskId];
512
532
  task.startTime = result.startTime;
513
533
  task.endTime = result.endTime;
534
+ const status = resolveBatchTaskStatus(result);
514
535
  return {
515
- code: result.success ? 0 : 1,
536
+ code: status === 'success' ? 0 : 1,
516
537
  task,
517
- status: (result.success ? 'success' : 'failure'),
538
+ status,
518
539
  terminalOutput: result.terminalOutput,
519
540
  };
520
541
  });
@@ -31,6 +31,17 @@ export declare function getOutputsForTargetAndConfiguration(target: Task['target
31
31
  export declare function interpolate(template: string, data: any): string;
32
32
  export declare function getTargetConfigurationForTask(task: Task, projectGraph: ProjectGraph): TargetConfiguration | undefined;
33
33
  export declare function getExecutorNameForTask(task: Task, projectGraph: ProjectGraph): string;
34
+ /**
35
+ * Expand a set of initiating task IDs by walking through any `nx:noop` tasks
36
+ * and replacing them with their direct dependencies + continuous dependencies.
37
+ * Non-noop tasks are kept as-is; cycles are safe.
38
+ *
39
+ * An `nx:noop` executor returns immediately, so if it is the only thing
40
+ * anchoring a continuous child, the child gets killed by
41
+ * `cleanUpUnneededContinuousTasks` the moment the noop completes. Treating the
42
+ * noop's dependencies as the real anchors preserves the intended orchestration.
43
+ */
44
+ export declare function expandInitiatingTasksThroughNoop(initiatingTasks: Task[], taskGraph: TaskGraph, projectGraph: ProjectGraph): Set<string>;
34
45
  export declare function getExecutorForTask(task: Task, projects: Record<string, ProjectConfiguration>): ExecutorConfig & {
35
46
  isNgCompat: boolean;
36
47
  isNxExecutor: boolean;
@@ -14,6 +14,7 @@ exports.getOutputsForTargetAndConfiguration = getOutputsForTargetAndConfiguratio
14
14
  exports.interpolate = interpolate;
15
15
  exports.getTargetConfigurationForTask = getTargetConfigurationForTask;
16
16
  exports.getExecutorNameForTask = getExecutorNameForTask;
17
+ exports.expandInitiatingTasksThroughNoop = expandInitiatingTasksThroughNoop;
17
18
  exports.getExecutorForTask = getExecutorForTask;
18
19
  exports.getCustomHasher = getCustomHasher;
19
20
  exports.removeTasksFromTaskGraph = removeTasksFromTaskGraph;
@@ -291,6 +292,42 @@ function getTargetConfigurationForTask(task, projectGraph) {
291
292
  function getExecutorNameForTask(task, projectGraph) {
292
293
  return getTargetConfigurationForTask(task, projectGraph)?.executor;
293
294
  }
295
+ /**
296
+ * Expand a set of initiating task IDs by walking through any `nx:noop` tasks
297
+ * and replacing them with their direct dependencies + continuous dependencies.
298
+ * Non-noop tasks are kept as-is; cycles are safe.
299
+ *
300
+ * An `nx:noop` executor returns immediately, so if it is the only thing
301
+ * anchoring a continuous child, the child gets killed by
302
+ * `cleanUpUnneededContinuousTasks` the moment the noop completes. Treating the
303
+ * noop's dependencies as the real anchors preserves the intended orchestration.
304
+ */
305
+ function expandInitiatingTasksThroughNoop(initiatingTasks, taskGraph, projectGraph) {
306
+ const expanded = new Set();
307
+ const visited = new Set();
308
+ const queue = initiatingTasks.map((t) => t.id);
309
+ while (queue.length > 0) {
310
+ const taskId = queue.shift();
311
+ if (visited.has(taskId))
312
+ continue;
313
+ visited.add(taskId);
314
+ const task = taskGraph.tasks[taskId];
315
+ if (!task)
316
+ continue;
317
+ if (getExecutorNameForTask(task, projectGraph) === 'nx:noop') {
318
+ for (const dep of taskGraph.dependencies[taskId] ?? []) {
319
+ queue.push(dep);
320
+ }
321
+ for (const dep of taskGraph.continuousDependencies[taskId] ?? []) {
322
+ queue.push(dep);
323
+ }
324
+ }
325
+ else {
326
+ expanded.add(taskId);
327
+ }
328
+ }
329
+ return expanded;
330
+ }
294
331
  function getExecutorForTask(task, projects) {
295
332
  const executor = projects[task.target.project]?.targets?.[task.target.target]?.executor;
296
333
  const [nodeModule, executorName] = (0, executor_utils_1.parseExecutor)(executor);
@@ -21,6 +21,18 @@ const messageOptions = {
21
21
  ],
22
22
  footer: '\nFree for small teams. Remote caching and task distribution. 2-minute setup: https://nx.dev/nx-cloud',
23
23
  },
24
+ {
25
+ code: 'cloud-self-healing-remote-cache',
26
+ message: `Would you like to enable AI-powered Self-Healing CI and Remote Caching?`,
27
+ initial: 0,
28
+ choices: [
29
+ { value: 'yes', name: 'Yes' },
30
+ { value: 'skip', name: 'Skip for now' },
31
+ { value: 'never', name: pc.dim("No, don't ask again") },
32
+ ],
33
+ footer: '\nLearn about it at https://nx.dev/nx-cloud',
34
+ hint: `\n(it's free and can be disabled any time)`,
35
+ },
24
36
  ],
25
37
  setupViewLogs: [
26
38
  {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Enables V8's on-disk bytecode cache for the current process.
3
+ *
4
+ * Calls `module.enableCompileCache()` with no arguments and lets Node pick
5
+ * the location, which means Node's standard env vars work transparently:
6
+ * - `NODE_COMPILE_CACHE=<dir>` — override the cache directory.
7
+ * - `NODE_DISABLE_COMPILE_CACHE=1` — disable entirely.
8
+ *
9
+ * The default location lives under the OS temp dir keyed by V8 version, so
10
+ * the cache is shared across workspaces and self-invalidates on Node
11
+ * upgrades — no nx-specific cleanup needed.
12
+ *
13
+ * Called at the entry point of every long-lived nx process (main CLI,
14
+ * daemon, plugin workers) via `enable-compile-cache.ts`, which side-effects
15
+ * this on import.
16
+ *
17
+ * Set `NX_COMPILE_CACHE=false` to opt out without disabling the cache for
18
+ * non-nx Node processes the way `NODE_DISABLE_COMPILE_CACHE` would.
19
+ *
20
+ * No-op on Node versions without the `module.enableCompileCache` API.
21
+ * Errors are swallowed — the compile cache is a pure performance
22
+ * optimization and must never break the CLI.
23
+ */
24
+ export declare function enableCompileCache(...override: [unknown?]): boolean;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enableCompileCache = enableCompileCache;
4
+ const tslib_1 = require("tslib");
5
+ const nodeModule = tslib_1.__importStar(require("node:module"));
6
+ /**
7
+ * Enables V8's on-disk bytecode cache for the current process.
8
+ *
9
+ * Calls `module.enableCompileCache()` with no arguments and lets Node pick
10
+ * the location, which means Node's standard env vars work transparently:
11
+ * - `NODE_COMPILE_CACHE=<dir>` — override the cache directory.
12
+ * - `NODE_DISABLE_COMPILE_CACHE=1` — disable entirely.
13
+ *
14
+ * The default location lives under the OS temp dir keyed by V8 version, so
15
+ * the cache is shared across workspaces and self-invalidates on Node
16
+ * upgrades — no nx-specific cleanup needed.
17
+ *
18
+ * Called at the entry point of every long-lived nx process (main CLI,
19
+ * daemon, plugin workers) via `enable-compile-cache.ts`, which side-effects
20
+ * this on import.
21
+ *
22
+ * Set `NX_COMPILE_CACHE=false` to opt out without disabling the cache for
23
+ * non-nx Node processes the way `NODE_DISABLE_COMPILE_CACHE` would.
24
+ *
25
+ * No-op on Node versions without the `module.enableCompileCache` API.
26
+ * Errors are swallowed — the compile cache is a pure performance
27
+ * optimization and must never break the CLI.
28
+ */
29
+ function enableCompileCache(
30
+ // Test seam: production callers omit this. `unknown` (rather than
31
+ // `EnableCompileCacheFn | undefined`) lets tests pass a non-function to
32
+ // simulate pre-22.8 Node where `module.enableCompileCache` is missing. We
33
+ // read `arguments.length` so callers can *explicitly* pass `undefined`.
34
+ ...override) {
35
+ if (process.env.NX_COMPILE_CACHE === 'false')
36
+ return false;
37
+ const impl = override.length === 0
38
+ ? nodeModule.enableCompileCache
39
+ : override[0];
40
+ if (typeof impl !== 'function')
41
+ return false;
42
+ try {
43
+ impl();
44
+ return true;
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // Side-effect-only module: import this as the *first* import in any nx
4
+ // process entry point so V8's compile cache is enabled before the rest of
5
+ // the import chain (which is what we actually want to cache) starts loading.
6
+ const compile_cache_1 = require("./compile-cache");
7
+ (0, compile_cache_1.enableCompileCache)();
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Checks if `@nx/js` is installed by attempting to resolve its `package.json`.
3
+ *
4
+ * Lives in its own module so unit tests can `jest.doMock` it without having to
5
+ * intercept Node's resolver at the global level. The previous in-`package-json`
6
+ * definition was unreachable to mocks because callers in the same module
7
+ * referenced it via the local lexical binding rather than `module.exports`.
8
+ */
9
+ export declare function hasNxJsPlugin(projectRoot: string, workspaceRoot: string): boolean;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasNxJsPlugin = hasNxJsPlugin;
4
+ const installation_directory_1 = require("./installation-directory");
5
+ /**
6
+ * Checks if `@nx/js` is installed by attempting to resolve its `package.json`.
7
+ *
8
+ * Lives in its own module so unit tests can `jest.doMock` it without having to
9
+ * intercept Node's resolver at the global level. The previous in-`package-json`
10
+ * definition was unreachable to mocks because callers in the same module
11
+ * referenced it via the local lexical binding rather than `module.exports`.
12
+ */
13
+ function hasNxJsPlugin(projectRoot, workspaceRoot) {
14
+ try {
15
+ // nx-ignore-next-line
16
+ require.resolve('@nx/js/package.json', {
17
+ paths: [projectRoot, ...(0, installation_directory_1.getNxRequirePaths)(workspaceRoot), __dirname],
18
+ });
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resolve the workspace's installed `nx` version, or `null` if no installed
3
+ * `nx` can be located. Routed through a cache-shielded, self-reference-free
4
+ * `require.resolve` so the answer always reflects the workspace's
5
+ * `node_modules`/PnP store rather than whichever `nx` package happens to be
6
+ * loaded in the current process. See nrwl/nx#35444.
7
+ */
8
+ export declare function getInstalledNxVersion(): string | null;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getInstalledNxVersion = getInstalledNxVersion;
4
+ const tslib_1 = require("tslib");
5
+ const node_module_1 = tslib_1.__importStar(require("node:module"));
6
+ const fileutils_1 = require("./fileutils");
7
+ const workspace_root_1 = require("./workspace-root");
8
+ const installation_directory_1 = require("./installation-directory");
9
+ /**
10
+ * Resolve the workspace's installed `nx` version, or `null` if no installed
11
+ * `nx` can be located. Routed through a cache-shielded, self-reference-free
12
+ * `require.resolve` so the answer always reflects the workspace's
13
+ * `node_modules`/PnP store rather than whichever `nx` package happens to be
14
+ * loaded in the current process. See nrwl/nx#35444.
15
+ */
16
+ function getInstalledNxVersion() {
17
+ const nxPackageJsonPath = resolvePackageJsonWithoutCachePollution('nx', (0, installation_directory_1.getNxRequirePaths)(workspace_root_1.workspaceRoot));
18
+ if (!nxPackageJsonPath) {
19
+ return null;
20
+ }
21
+ try {
22
+ return (0, fileutils_1.readJsonFile)(nxPackageJsonPath).version ?? null;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ /**
29
+ * Resolve `<packageName>/package.json` via Node's CJS resolver while
30
+ * neutralising both ways `require.resolve(req, { paths })` can lie about
31
+ * the `paths` argument:
32
+ *
33
+ * 1. Process-wide `Module._pathCache` — swapped out for the duration of
34
+ * the call, so any cache entries written are discarded and any
35
+ * previously-poisoned entries are not read. Without this, an
36
+ * in-process load of a second `nx` package (e.g. the temp `nx@latest`
37
+ * install used by the daemon's AI-agents and console-status checks)
38
+ * can poison the cache key this call uses and make us read the temp
39
+ * path instead of the workspace path.
40
+ *
41
+ * 2. Package self-reference — when a file inside package `nx` calls
42
+ * `require.resolve('nx/...')`, Node returns that calling package's
43
+ * own file regardless of `paths`. We avoid that by issuing the
44
+ * resolve from a `createRequire` rooted at a synthetic path that is
45
+ * outside any package, so the resolver has no "self" to reference
46
+ * and must honour `paths`.
47
+ *
48
+ * Node's single-threaded synchronous execution means `require.resolve` does
49
+ * not yield, so no other code in the process can observe the swapped cache.
50
+ */
51
+ function resolvePackageJsonWithoutCachePollution(packageName, requirePaths) {
52
+ // `_pathCache` is an internal Node API not exposed in @types/node.
53
+ const realCache = node_module_1.default._pathCache;
54
+ node_module_1.default._pathCache = Object.create(null);
55
+ try {
56
+ const detachedRequire = (0, node_module_1.createRequire)('/__nx_detached_resolver__/x.js');
57
+ return detachedRequire.resolve(`${packageName}/package.json`, {
58
+ paths: requirePaths,
59
+ });
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ finally {
65
+ node_module_1.default._pathCache = realCache;
66
+ }
67
+ }
@@ -1,7 +1,17 @@
1
1
  export declare const NX_PREFIX: string;
2
2
  export declare const NX_ERROR: string;
3
+ type LogDriver = Pick<Console, 'warn' | 'error' | 'info' | 'log' | 'debug'>;
4
+ export declare function createLogger(driver: LogDriver): {
5
+ warn: (...v: any[]) => void;
6
+ error: (s: any) => void;
7
+ info: (s: any) => void;
8
+ log: (...s: any[]) => void;
9
+ debug: (...s: any[]) => void;
10
+ fatal: (...s: any[]) => void;
11
+ verbose: (...s: any[]) => void;
12
+ };
3
13
  export declare const logger: {
4
- warn: (s: any) => void;
14
+ warn: (...v: any[]) => void;
5
15
  error: (s: any) => void;
6
16
  info: (s: any) => void;
7
17
  log: (...s: any[]) => void;
@@ -10,3 +20,4 @@ export declare const logger: {
10
20
  verbose: (...s: any[]) => void;
11
21
  };
12
22
  export declare function stripIndent(str: string): string;
23
+ export {};
@@ -1,47 +1,68 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logger = exports.NX_ERROR = exports.NX_PREFIX = void 0;
4
+ exports.createLogger = createLogger;
4
5
  exports.stripIndent = stripIndent;
5
6
  const tslib_1 = require("tslib");
6
7
  const pc = tslib_1.__importStar(require("picocolors"));
8
+ const is_on_daemon_1 = require("../daemon/is-on-daemon");
9
+ const logger_1 = require("../daemon/logger");
7
10
  exports.NX_PREFIX = pc.inverse(pc.bold(pc.cyan(' NX ')));
8
11
  exports.NX_ERROR = pc.inverse(pc.bold(pc.red(' ERROR ')));
9
- exports.logger = {
10
- warn: (s) => console.warn(pc.bold(pc.yellow(s))),
11
- error: (s) => {
12
- if (typeof s === 'string' && s.startsWith('NX ')) {
13
- console.error(`\n${exports.NX_ERROR} ${pc.bold(pc.red(s.slice(3)))}\n`);
14
- }
15
- else if (s instanceof Error && s.stack) {
16
- console.error(pc.bold(pc.red(s.stack)));
17
- }
18
- else {
19
- console.error(pc.bold(pc.red(s)));
20
- }
21
- },
22
- info: (s) => {
23
- if (typeof s === 'string' && s.startsWith('NX ')) {
24
- console.info(`\n${exports.NX_PREFIX} ${pc.bold(s.slice(3))}\n`);
25
- }
26
- else {
27
- console.info(s);
28
- }
29
- },
30
- log: (...s) => {
31
- console.log(...s);
32
- },
33
- debug: (...s) => {
34
- console.debug(...s);
35
- },
36
- fatal: (...s) => {
37
- console.error(...s);
38
- },
39
- verbose: (...s) => {
40
- if (process.env.NX_VERBOSE_LOGGING === 'true') {
41
- console.log(...s);
42
- }
43
- },
44
- };
12
+ function createLogger(driver) {
13
+ return {
14
+ warn: (...v) => driver.warn(...v.map((s) => pc.bold(pc.yellow(s)))),
15
+ error: (s) => {
16
+ if (typeof s === 'string' && s.startsWith('NX ')) {
17
+ driver.error(`\n${exports.NX_ERROR} ${pc.bold(pc.red(s.slice(3)))}\n`);
18
+ }
19
+ else if (s instanceof Error && s.stack) {
20
+ driver.error(pc.bold(pc.red(s.stack)));
21
+ }
22
+ else {
23
+ driver.error(pc.bold(pc.red(s)));
24
+ }
25
+ },
26
+ info: (s) => {
27
+ if (typeof s === 'string' && s.startsWith('NX ')) {
28
+ driver.info(`\n${exports.NX_PREFIX} ${pc.bold(s.slice(3))}\n`);
29
+ }
30
+ else {
31
+ driver.info(s);
32
+ }
33
+ },
34
+ log: (...s) => {
35
+ driver.log(...s);
36
+ },
37
+ debug: (...s) => {
38
+ driver.debug(...s);
39
+ },
40
+ fatal: (...s) => {
41
+ driver.error(...s);
42
+ },
43
+ verbose: (...s) => {
44
+ if (process.env.NX_VERBOSE_LOGGING === 'true') {
45
+ // verbose logs go to stderr to prevent things like `nx show projects | grep`
46
+ // breaking when you enable verbose logging. The only potential breakage from
47
+ // this would be if a tool counts any output on stderr as being an issue, but
48
+ // there are likely other places that would trigger those same issues.
49
+ driver.warn(...s);
50
+ }
51
+ },
52
+ };
53
+ }
54
+ exports.logger = createLogger((0, is_on_daemon_1.isOnDaemon)()
55
+ ? (() => {
56
+ const log = logger_1.serverLogger.log.bind(logger_1.serverLogger);
57
+ return {
58
+ warn: log,
59
+ error: log,
60
+ debug: log,
61
+ info: log,
62
+ log: log,
63
+ };
64
+ })()
65
+ : console);
45
66
  function stripIndent(str) {
46
67
  const match = str.match(/^[ \t]*(?=\S)/gm);
47
68
  if (!match) {
@@ -1,6 +1,5 @@
1
1
  import type { NxKey } from '@nx/key';
2
2
  export declare function createNxKeyLicenseeInformation(nxKey: NxKey): string;
3
- export declare function printNxKey(): Promise<void>;
4
3
  export declare function getNxKeyInformation(): Promise<NxKey | null>;
5
4
  export declare class NxKeyNotInstalledError extends Error {
6
5
  constructor(e: Error);