nx 23.1.1 → 23.1.3
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.
- package/dist/release/changelog-renderer/index.js +4 -5
- package/dist/release/index.d.ts +1 -1
- package/dist/src/command-line/add/add.js +5 -0
- package/dist/src/command-line/affected/affected.js +1 -0
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
- package/dist/src/command-line/import/import.js +1 -2
- package/dist/src/command-line/init/init-v2.js +4 -5
- package/dist/src/command-line/migrate/migrate.d.ts +4 -0
- package/dist/src/command-line/migrate/migrate.js +89 -26
- package/dist/src/command-line/release/changelog.js +5 -0
- package/dist/src/command-line/release/index.d.ts +1 -1
- package/dist/src/command-line/release/utils/git.js +1 -1
- package/dist/src/command-line/release/utils/release-graph.d.ts +17 -0
- package/dist/src/command-line/release/utils/release-graph.js +71 -19
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +6 -0
- package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
- package/dist/src/command-line/release/version/release-group-processor.js +80 -6
- package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
- package/dist/src/command-line/release/version/version-actions.js +9 -1
- package/dist/src/command-line/release/version.js +9 -5
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/command-line/run/run-one.js +1 -0
- package/dist/src/command-line/run-many/run-many.js +1 -0
- package/dist/src/command-line/watch/watch.js +13 -0
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +52 -1
- package/dist/src/daemon/client/client.js +160 -36
- package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
- package/dist/src/daemon/client/daemon-environment.js +110 -2
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +33 -0
- package/dist/src/daemon/message-types/daemon-message.js +48 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
- package/dist/src/daemon/server/latest-nx.js +5 -2
- package/dist/src/daemon/server/server.js +24 -0
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +94 -4
- package/dist/src/devkit-internals.js +194 -5
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
- package/dist/src/generators/tree.d.ts +4 -2
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
- package/dist/src/native/index.d.ts +10 -0
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-bindings.js +1 -0
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
- package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
- package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +60 -0
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +14 -8
- package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +2 -0
- package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
- package/dist/src/project-graph/error-types.d.ts +12 -1
- package/dist/src/project-graph/error-types.js +27 -2
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/project-graph.js +20 -0
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +5 -1
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +133 -3
- package/dist/src/tasks-runner/task-env.js +5 -2
- package/dist/src/tasks-runner/utils.js +2 -6
- package/dist/src/utils/assert-workspace-validity.js +7 -2
- package/dist/src/utils/fileutils.d.ts +5 -0
- package/dist/src/utils/fileutils.js +7 -2
- package/dist/src/utils/git-worktrees.d.ts +30 -0
- package/dist/src/utils/git-worktrees.js +212 -0
- package/dist/src/utils/ignore.d.ts +128 -1
- package/dist/src/utils/ignore.js +182 -12
- package/dist/src/utils/long-running-target.d.ts +10 -0
- package/dist/src/utils/long-running-target.js +19 -0
- package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
- package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
- package/dist/src/utils/min-release-age/packument.js +1 -1
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
- package/dist/src/utils/package-manager-config/bunfig.js +49 -0
- package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
- package/dist/src/utils/package-manager-config/npmrc.js +124 -0
- package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
- package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
- package/dist/src/utils/package-manager.d.ts +21 -2
- package/dist/src/utils/package-manager.js +244 -47
- package/dist/src/utils/provenance.js +6 -14
- package/dist/src/utils/registry-config/bun.d.ts +2 -0
- package/dist/src/utils/registry-config/bun.js +257 -0
- package/dist/src/utils/registry-config/index.d.ts +13 -0
- package/dist/src/utils/registry-config/index.js +102 -0
- package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
- package/dist/src/utils/registry-config/pnpm.js +1551 -0
- package/dist/src/utils/registry-config/utils.d.ts +195 -0
- package/dist/src/utils/registry-config/utils.js +496 -0
- package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-berry.js +612 -0
- package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- package/migrations.json +6 -0
- package/package.json +12 -12
- package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
- package/dist/src/utils/min-release-age/npmrc.js +0 -45
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk_nx_graph_client=self.webpackChunk_nx_graph_client||[]).push([[869],{
|
|
1
|
+
"use strict";(self.webpackChunk_nx_graph_client=self.webpackChunk_nx_graph_client||[]).push([[869],{946(){}},e=>{var n;n=946,e(e.s=n)}]);
|
|
@@ -8,11 +8,23 @@ import { ConfigurationSourceMaps } from '../../project-graph/utils/project-confi
|
|
|
8
8
|
import type { FlushSyncGeneratorChangesResult, SyncGeneratorRunResult } from '../../utils/sync-generators';
|
|
9
9
|
import { type ConfigureAiAgentsStatusResponse } from '../message-types/configure-ai-agents';
|
|
10
10
|
import { type NxConsoleStatusResponse, type SetNxConsolePreferenceAndInstallResponse } from '../message-types/nx-console';
|
|
11
|
+
/** A refused connect: the errno, and the path it was made against. */
|
|
12
|
+
type ConnectRefusal = {
|
|
13
|
+
error: NodeJS.ErrnoException;
|
|
14
|
+
socketPath: string;
|
|
15
|
+
};
|
|
11
16
|
export type UnregisterCallback = () => void;
|
|
12
17
|
export type ChangedFile = {
|
|
13
18
|
path: string;
|
|
14
19
|
type: 'create' | 'update' | 'delete';
|
|
15
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* The daemon's workspace watcher died. Nothing it serves will see file changes
|
|
23
|
+
* again, so a watching client has to restart rather than keep waiting.
|
|
24
|
+
*/
|
|
25
|
+
export declare class WatcherFailedError extends Error {
|
|
26
|
+
constructor(message: string);
|
|
27
|
+
}
|
|
16
28
|
export declare class DaemonClient {
|
|
17
29
|
private readonly nxJson;
|
|
18
30
|
constructor();
|
|
@@ -93,6 +105,12 @@ export declare class DaemonClient {
|
|
|
93
105
|
resetConfigureAiAgentsStatus(): Promise<{
|
|
94
106
|
success: boolean;
|
|
95
107
|
}>;
|
|
108
|
+
/**
|
|
109
|
+
* The pre-start probe, returning why it failed rather than leaving it on the
|
|
110
|
+
* instance: `_daemonStatus` does not serialize `isServerAvailable`'s five
|
|
111
|
+
* public callers against `startDaemonIfNecessary`.
|
|
112
|
+
*/
|
|
113
|
+
private probeServer;
|
|
96
114
|
isServerAvailable(): Promise<boolean>;
|
|
97
115
|
private startDaemonIfNecessary;
|
|
98
116
|
private sendToDaemonViaQueue;
|
|
@@ -108,8 +126,41 @@ export declare class DaemonClient {
|
|
|
108
126
|
private sendMessageToDaemon;
|
|
109
127
|
private registerDaemonProcessWithMetricsService;
|
|
110
128
|
private handleMessage;
|
|
111
|
-
|
|
129
|
+
/**
|
|
130
|
+
* @param probeRefusal what the caller's pre-start probe saw. The only evidence
|
|
131
|
+
* when a daemon refuses us and then exits — the poll cannot reproduce it
|
|
132
|
+
* once the process json is gone. `nx daemon --start` passes nothing.
|
|
133
|
+
*/
|
|
134
|
+
startInBackground(probeRefusal?: ConnectRefusal): Promise<ChildProcess['pid']>;
|
|
112
135
|
stop(): Promise<void>;
|
|
113
136
|
}
|
|
114
137
|
export declare const daemonClient: DaemonClient;
|
|
115
138
|
export declare function isDaemonEnabled(): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* EACCES and EPERM are the two errnos that mean the OS refused us rather than
|
|
141
|
+
* that nothing was listening. They need opposite remedies — a socket owned by
|
|
142
|
+
* someone else versus a sandbox refusing the connect syscall — but they share
|
|
143
|
+
* the property that retrying cannot change the answer.
|
|
144
|
+
*/
|
|
145
|
+
export declare function isPermissionErrno(error: NodeJS.ErrnoException): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* The operating system refused the connection. Most often the socket belongs to
|
|
148
|
+
* another user, which is the guarantee the owner-only socket directory buys —
|
|
149
|
+
* but a sandbox that denies unix-socket connects produces the same errno, so the
|
|
150
|
+
* message does not assert which. Either way it is an environment condition
|
|
151
|
+
* rather than a defect in Nx, and it deliberately does not
|
|
152
|
+
* carry `internalDaemonError`: that tag tells the user to file an issue and
|
|
153
|
+
* disables the daemon until `nx reset`, which would outlast the stale socket
|
|
154
|
+
* that caused it.
|
|
155
|
+
*
|
|
156
|
+
* It also skips the daemon log that `daemonProcessException` appends. The log
|
|
157
|
+
* belongs to *our* daemon; the process holding this socket is someone else's, so
|
|
158
|
+
* quoting it would describe an unrelated run.
|
|
159
|
+
*/
|
|
160
|
+
export declare function daemonPermissionException(socketPath: string, cause: string): Error;
|
|
161
|
+
/**
|
|
162
|
+
* Exported for testing: the `internalDaemonError` tag decides whether a daemon
|
|
163
|
+
* failure degrades to a daemonless graph build or aborts the command.
|
|
164
|
+
*/
|
|
165
|
+
export declare function daemonProcessException(message: string): Error;
|
|
166
|
+
export {};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.daemonClient = exports.DaemonClient = void 0;
|
|
3
|
+
exports.daemonClient = exports.DaemonClient = exports.WatcherFailedError = void 0;
|
|
4
4
|
exports.isDaemonEnabled = isDaemonEnabled;
|
|
5
|
+
exports.isPermissionErrno = isPermissionErrno;
|
|
6
|
+
exports.daemonPermissionException = daemonPermissionException;
|
|
7
|
+
exports.daemonProcessException = daemonProcessException;
|
|
5
8
|
const child_process_1 = require("child_process");
|
|
6
9
|
const net_1 = require("net");
|
|
7
10
|
const node_fs_1 = require("node:fs");
|
|
@@ -52,6 +55,18 @@ const WAIT_FOR_SERVER_CONFIG = {
|
|
|
52
55
|
delayMs: 10,
|
|
53
56
|
maxAttempts: 6000, // 6000 * 10ms = 60 seconds
|
|
54
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* The daemon's workspace watcher died. Nothing it serves will see file changes
|
|
60
|
+
* again, so a watching client has to restart rather than keep waiting.
|
|
61
|
+
*/
|
|
62
|
+
class WatcherFailedError extends Error {
|
|
63
|
+
constructor(message) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = 'WatcherFailedError';
|
|
66
|
+
Object.setPrototypeOf(this, WatcherFailedError.prototype);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.WatcherFailedError = WatcherFailedError;
|
|
55
70
|
class DaemonClient {
|
|
56
71
|
constructor() {
|
|
57
72
|
// Tracks the spinner owned by the in-flight request so streamed
|
|
@@ -177,12 +192,21 @@ class DaemonClient {
|
|
|
177
192
|
return await this.sendToDaemonViaQueue({ type: 'REQUEST_FILE_DATA' });
|
|
178
193
|
}
|
|
179
194
|
hashTasks(runnerOptions, tasks, taskGraph, perTaskEnvs, cwd, collectInputs) {
|
|
195
|
+
// Task results get written back onto these task objects as the run
|
|
196
|
+
// progresses — hash/hashDetails/timestamps by hashing and the
|
|
197
|
+
// orchestrator, terminalOutput by the Nx Cloud life cycle (untyped) —
|
|
198
|
+
// so a later message would otherwise re-ship every earlier result.
|
|
199
|
+
const trimmedTasks = {};
|
|
200
|
+
for (const [id, t] of Object.entries(taskGraph.tasks)) {
|
|
201
|
+
const { hash, hashDetails, startTime, endTime, terminalOutput, ...strippedTask } = t;
|
|
202
|
+
trimmedTasks[id] = strippedTask;
|
|
203
|
+
}
|
|
180
204
|
return this.sendToDaemonViaQueue({
|
|
181
205
|
type: 'HASH_TASKS',
|
|
182
206
|
runnerOptions,
|
|
183
207
|
perTaskEnvs,
|
|
184
|
-
tasks,
|
|
185
|
-
taskGraph,
|
|
208
|
+
tasks: tasks.map((t) => trimmedTasks[t.id]),
|
|
209
|
+
taskGraph: { ...taskGraph, tasks: trimmedTasks },
|
|
186
210
|
cwd,
|
|
187
211
|
collectInputs,
|
|
188
212
|
});
|
|
@@ -218,6 +242,13 @@ class DaemonClient {
|
|
|
218
242
|
this.fileWatcherMessenger = new daemon_socket_messenger_1.DaemonSocketMessenger((0, net_1.connect)(socketPath)).listen((message) => {
|
|
219
243
|
try {
|
|
220
244
|
const parsedMessage = (0, consume_messages_from_socket_1.parseMessage)(message);
|
|
245
|
+
if (parsedMessage?.watcherError) {
|
|
246
|
+
const error = new WatcherFailedError(parsedMessage.watcherError);
|
|
247
|
+
for (const cb of this.fileWatcherCallbacks.values()) {
|
|
248
|
+
cb(error, null);
|
|
249
|
+
}
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
221
252
|
// Notify all callbacks
|
|
222
253
|
for (const cb of this.fileWatcherCallbacks.values()) {
|
|
223
254
|
cb(null, parsedMessage);
|
|
@@ -276,9 +307,9 @@ class DaemonClient {
|
|
|
276
307
|
// Wait for daemon server to be available before trying to reconnect
|
|
277
308
|
let serverAvailable;
|
|
278
309
|
try {
|
|
279
|
-
serverAvailable = await this.waitForServerToBeAvailable({
|
|
310
|
+
({ available: serverAvailable } = await this.waitForServerToBeAvailable({
|
|
280
311
|
ignoreVersionMismatch: false,
|
|
281
|
-
});
|
|
312
|
+
}));
|
|
282
313
|
}
|
|
283
314
|
catch (err) {
|
|
284
315
|
// Version mismatch - pass error to callbacks so they can handle it
|
|
@@ -428,9 +459,9 @@ class DaemonClient {
|
|
|
428
459
|
// Wait for daemon server to be available before trying to reconnect
|
|
429
460
|
let serverAvailable;
|
|
430
461
|
try {
|
|
431
|
-
serverAvailable = await this.waitForServerToBeAvailable({
|
|
462
|
+
({ available: serverAvailable } = await this.waitForServerToBeAvailable({
|
|
432
463
|
ignoreVersionMismatch: false,
|
|
433
|
-
});
|
|
464
|
+
}));
|
|
434
465
|
}
|
|
435
466
|
catch (err) {
|
|
436
467
|
// Version mismatch - pass error to callbacks so they can handle it
|
|
@@ -665,30 +696,40 @@ class DaemonClient {
|
|
|
665
696
|
};
|
|
666
697
|
return this.sendToDaemonViaQueue(message);
|
|
667
698
|
}
|
|
668
|
-
|
|
699
|
+
/**
|
|
700
|
+
* The pre-start probe, returning why it failed rather than leaving it on the
|
|
701
|
+
* instance: `_daemonStatus` does not serialize `isServerAvailable`'s five
|
|
702
|
+
* public callers against `startDaemonIfNecessary`.
|
|
703
|
+
*/
|
|
704
|
+
async probeServer() {
|
|
669
705
|
return new Promise((resolve, reject) => {
|
|
670
706
|
try {
|
|
671
707
|
const socketPath = this.getSocketPath();
|
|
672
708
|
if (!socketPath) {
|
|
673
|
-
resolve(false);
|
|
709
|
+
resolve({ available: false });
|
|
674
710
|
return;
|
|
675
711
|
}
|
|
676
712
|
const socket = (0, net_1.connect)(socketPath, () => {
|
|
677
713
|
socket.destroy();
|
|
678
|
-
resolve(true);
|
|
714
|
+
resolve({ available: true });
|
|
679
715
|
});
|
|
680
|
-
socket.once('error', () => {
|
|
681
|
-
|
|
716
|
+
socket.once('error', (err) => {
|
|
717
|
+
// The only place the errno for "the socket is there but refuses us"
|
|
718
|
+
// is produced, and the only thing separating it from "no daemon yet".
|
|
719
|
+
resolve({ available: false, refusal: { error: err, socketPath } });
|
|
682
720
|
});
|
|
683
721
|
}
|
|
684
722
|
catch (err) {
|
|
685
723
|
if (err instanceof daemon_socket_messenger_1.VersionMismatchError) {
|
|
686
724
|
reject(err); // Let version mismatch bubble up
|
|
687
725
|
}
|
|
688
|
-
resolve(false);
|
|
726
|
+
resolve({ available: false });
|
|
689
727
|
}
|
|
690
728
|
});
|
|
691
729
|
}
|
|
730
|
+
async isServerAvailable() {
|
|
731
|
+
return (await this.probeServer()).available;
|
|
732
|
+
}
|
|
692
733
|
async startDaemonIfNecessary() {
|
|
693
734
|
if (this._daemonStatus == DaemonStatus.CONNECTED) {
|
|
694
735
|
return;
|
|
@@ -697,21 +738,22 @@ class DaemonClient {
|
|
|
697
738
|
if (this._daemonStatus == DaemonStatus.DISCONNECTED) {
|
|
698
739
|
this._daemonStatus = DaemonStatus.CONNECTING;
|
|
699
740
|
let daemonPid = null;
|
|
700
|
-
let
|
|
741
|
+
let probe;
|
|
701
742
|
try {
|
|
702
|
-
|
|
743
|
+
probe = await this.probeServer();
|
|
703
744
|
}
|
|
704
745
|
catch (err) {
|
|
705
746
|
// Version mismatch - treat as server not available, start new one
|
|
706
747
|
if (err instanceof daemon_socket_messenger_1.VersionMismatchError) {
|
|
707
|
-
|
|
748
|
+
probe = { available: false };
|
|
708
749
|
}
|
|
709
750
|
else {
|
|
710
751
|
throw err;
|
|
711
752
|
}
|
|
712
753
|
}
|
|
713
|
-
if (!
|
|
714
|
-
|
|
754
|
+
if (!probe.available) {
|
|
755
|
+
// Carried as a value so no other caller's probe can substitute for it.
|
|
756
|
+
daemonPid = await this.startInBackground(probe.refusal);
|
|
715
757
|
}
|
|
716
758
|
this.setUpConnection();
|
|
717
759
|
this._daemonStatus = DaemonStatus.CONNECTED;
|
|
@@ -762,6 +804,11 @@ class DaemonClient {
|
|
|
762
804
|
if (err.message.startsWith('connect ENOENT')) {
|
|
763
805
|
error = daemonProcessException('The Daemon Server is not running');
|
|
764
806
|
}
|
|
807
|
+
else if (isPermissionErrno(err)) {
|
|
808
|
+
// The 0700 dir and 0600 socket mean the OS refuses this rather than the
|
|
809
|
+
// connect silently succeeding.
|
|
810
|
+
error = daemonPermissionException(socketPath, err.message);
|
|
811
|
+
}
|
|
765
812
|
else if (err.message.startsWith('connect ECONNREFUSED')) {
|
|
766
813
|
error = daemonProcessException(`A server instance had not been fully shut down. Please try running the command again.`);
|
|
767
814
|
}
|
|
@@ -782,9 +829,9 @@ class DaemonClient {
|
|
|
782
829
|
this._daemonStatus = DaemonStatus.CONNECTING;
|
|
783
830
|
let serverAvailable;
|
|
784
831
|
try {
|
|
785
|
-
serverAvailable = await this.waitForServerToBeAvailable({
|
|
832
|
+
({ available: serverAvailable } = await this.waitForServerToBeAvailable({
|
|
786
833
|
ignoreVersionMismatch: false,
|
|
787
|
-
});
|
|
834
|
+
}));
|
|
788
835
|
}
|
|
789
836
|
catch (err) {
|
|
790
837
|
if (err instanceof daemon_socket_messenger_1.VersionMismatchError) {
|
|
@@ -830,6 +877,11 @@ class DaemonClient {
|
|
|
830
877
|
*/
|
|
831
878
|
async waitForServerToBeAvailable(options) {
|
|
832
879
|
logger_1.clientLogger.log(`[Client] Waiting for server (max: ${WAIT_FOR_SERVER_CONFIG.maxAttempts} attempts, ${WAIT_FOR_SERVER_CONFIG.delayMs}ms interval)`);
|
|
880
|
+
// Poll-scoped, not instance state: reconnect paths have their own flags, so
|
|
881
|
+
// several attempts can be in flight and a shared slot would let one report
|
|
882
|
+
// another's socket.
|
|
883
|
+
let stoppedOnRefusal = false;
|
|
884
|
+
let refusal;
|
|
833
885
|
const socket = await (0, wait_for_socket_connection_1.waitForSocketConnection)(() => {
|
|
834
886
|
try {
|
|
835
887
|
return this.getSocketPath();
|
|
@@ -846,14 +898,29 @@ class DaemonClient {
|
|
|
846
898
|
}, {
|
|
847
899
|
maxAttempts: WAIT_FOR_SERVER_CONFIG.maxAttempts,
|
|
848
900
|
delayMs: WAIT_FOR_SERVER_CONFIG.delayMs,
|
|
901
|
+
onConnectError: (error, socketPath) => {
|
|
902
|
+
refusal = { error, socketPath };
|
|
903
|
+
// A refusal is not expected to become an acceptance, so polling the
|
|
904
|
+
// full 60s budget only delays the same answer. Not absolute:
|
|
905
|
+
// `server.ts` binds before it chmods to 0600, so under a umask that
|
|
906
|
+
// strips owner write a same-user connect can lose a microsecond race
|
|
907
|
+
// and see EACCES. That costs a specific error rather than a retry — a
|
|
908
|
+
// better trade than a 60s hang.
|
|
909
|
+
return (stoppedOnRefusal = isPermissionErrno(error));
|
|
910
|
+
},
|
|
849
911
|
});
|
|
850
912
|
if (socket) {
|
|
851
913
|
socket.destroy();
|
|
852
914
|
logger_1.clientLogger.log(`[Client] Server available`);
|
|
853
|
-
return true;
|
|
915
|
+
return { available: true };
|
|
854
916
|
}
|
|
855
|
-
|
|
856
|
-
|
|
917
|
+
// Keyed on the early exit taken, not on whether an errno was recorded:
|
|
918
|
+
// every failed connect records one, including an ordinary cold start's
|
|
919
|
+
// ENOENT.
|
|
920
|
+
logger_1.clientLogger.log(stoppedOnRefusal
|
|
921
|
+
? `[Client] Server refused the connection (${refusal?.error.code}), stopped polling`
|
|
922
|
+
: `[Client] Server not available after ${WAIT_FOR_SERVER_CONFIG.maxAttempts} attempts`);
|
|
923
|
+
return { available: false, refusal };
|
|
857
924
|
}
|
|
858
925
|
async sendMessageToDaemon(message, force) {
|
|
859
926
|
// the first message sent to the daemon includes an env prop
|
|
@@ -935,7 +1002,12 @@ class DaemonClient {
|
|
|
935
1002
|
].join('\n')));
|
|
936
1003
|
}
|
|
937
1004
|
}
|
|
938
|
-
|
|
1005
|
+
/**
|
|
1006
|
+
* @param probeRefusal what the caller's pre-start probe saw. The only evidence
|
|
1007
|
+
* when a daemon refuses us and then exits — the poll cannot reproduce it
|
|
1008
|
+
* once the process json is gone. `nx daemon --start` passes nothing.
|
|
1009
|
+
*/
|
|
1010
|
+
async startInBackground(probeRefusal) {
|
|
939
1011
|
if (global.NX_PLUGIN_WORKER) {
|
|
940
1012
|
throw new Error('Fatal Error: Something unexpected has occurred. Plugin Workers should not start a new daemon process. Please report this issue.');
|
|
941
1013
|
}
|
|
@@ -961,7 +1033,7 @@ class DaemonClient {
|
|
|
961
1033
|
detached: true,
|
|
962
1034
|
windowsHide: true,
|
|
963
1035
|
shell: false,
|
|
964
|
-
env: (0, daemon_environment_1.
|
|
1036
|
+
env: (0, daemon_environment_1.getDaemonSpawnEnv)(),
|
|
965
1037
|
});
|
|
966
1038
|
// The child now owns dup'd copies of the descriptors, so release ours.
|
|
967
1039
|
(0, node_fs_1.closeSync)(outFd);
|
|
@@ -973,14 +1045,25 @@ class DaemonClient {
|
|
|
973
1045
|
/**
|
|
974
1046
|
* Ensure the server is actually available to connect to via IPC before resolving
|
|
975
1047
|
*/
|
|
976
|
-
const
|
|
977
|
-
|
|
978
|
-
});
|
|
979
|
-
if (serverAvailable) {
|
|
1048
|
+
const { available, refusal: polled } = await this.waitForServerToBeAvailable({ ignoreVersionMismatch: true });
|
|
1049
|
+
if (available) {
|
|
980
1050
|
logger_1.clientLogger.log(`[Client] Daemon server started, pid=${backgroundProcess.pid}`);
|
|
981
1051
|
return backgroundProcess.pid;
|
|
982
1052
|
}
|
|
983
1053
|
else {
|
|
1054
|
+
// A permission refusal from either source wins, then the poll's errno,
|
|
1055
|
+
// then the probe's. Recency alone would report a daemon's ENOENT over the
|
|
1056
|
+
// EACCES the probe saw a moment earlier, losing the diagnosis.
|
|
1057
|
+
const refusal = [polled, probeRefusal].find((r) => r && isPermissionErrno(r.error)) ??
|
|
1058
|
+
polled ??
|
|
1059
|
+
probeRefusal;
|
|
1060
|
+
if (refusal && isPermissionErrno(refusal.error)) {
|
|
1061
|
+
// Reported here rather than as a generic startup failure, so it degrades
|
|
1062
|
+
// without disabling the daemon until `nx reset`. Both operands come from
|
|
1063
|
+
// the refusal: resolving a path here instead would throw once a daemon
|
|
1064
|
+
// that failed to bind has unlinked its process json.
|
|
1065
|
+
throw daemonPermissionException(refusal.socketPath, refusal.error.message);
|
|
1066
|
+
}
|
|
984
1067
|
throw daemonProcessException('Failed to start or connect to the Nx Daemon process.');
|
|
985
1068
|
}
|
|
986
1069
|
}
|
|
@@ -1023,24 +1106,65 @@ function isDocker() {
|
|
|
1023
1106
|
function nxJsonIsNotPresent() {
|
|
1024
1107
|
return !(0, nx_json_1.hasNxJson)(workspace_root_1.workspaceRoot);
|
|
1025
1108
|
}
|
|
1109
|
+
/**
|
|
1110
|
+
* EACCES and EPERM are the two errnos that mean the OS refused us rather than
|
|
1111
|
+
* that nothing was listening. They need opposite remedies — a socket owned by
|
|
1112
|
+
* someone else versus a sandbox refusing the connect syscall — but they share
|
|
1113
|
+
* the property that retrying cannot change the answer.
|
|
1114
|
+
*/
|
|
1115
|
+
function isPermissionErrno(error) {
|
|
1116
|
+
return error?.code === 'EACCES' || error?.code === 'EPERM';
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* The operating system refused the connection. Most often the socket belongs to
|
|
1120
|
+
* another user, which is the guarantee the owner-only socket directory buys —
|
|
1121
|
+
* but a sandbox that denies unix-socket connects produces the same errno, so the
|
|
1122
|
+
* message does not assert which. Either way it is an environment condition
|
|
1123
|
+
* rather than a defect in Nx, and it deliberately does not
|
|
1124
|
+
* carry `internalDaemonError`: that tag tells the user to file an issue and
|
|
1125
|
+
* disables the daemon until `nx reset`, which would outlast the stale socket
|
|
1126
|
+
* that caused it.
|
|
1127
|
+
*
|
|
1128
|
+
* It also skips the daemon log that `daemonProcessException` appends. The log
|
|
1129
|
+
* belongs to *our* daemon; the process holding this socket is someone else's, so
|
|
1130
|
+
* quoting it would describe an unrelated run.
|
|
1131
|
+
*/
|
|
1132
|
+
function daemonPermissionException(socketPath, cause) {
|
|
1133
|
+
const error = new Error([
|
|
1134
|
+
`The operating system refused the connection to the Nx Daemon socket (${cause}).`,
|
|
1135
|
+
'',
|
|
1136
|
+
`Socket: ${socketPath}`,
|
|
1137
|
+
'',
|
|
1138
|
+
'Most often the socket belongs to a different user: a daemon left behind by running Nx under `sudo`, a different uid inside a container, or a working copy shared between accounts. If the socket is your own, a sandbox is refusing the connection instead.',
|
|
1139
|
+
'If it belongs to another user, delete the socket above or set NX_SOCKET_DIR to a directory only your user can reach. If you are in a sandbox, allow unix sockets under the Nx socket root — in Claude Code a scoped `allowUnixSockets` only permits connecting, so starting a daemon there needs `allowAllUnixSockets: true`. See https://nx.dev/docs/kb/nx-sandbox-unix-sockets',
|
|
1140
|
+
].join('\n'));
|
|
1141
|
+
error.daemonPermissionError = true;
|
|
1142
|
+
return error;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Exported for testing: the `internalDaemonError` tag decides whether a daemon
|
|
1146
|
+
* failure degrades to a daemonless graph build or aborts the command.
|
|
1147
|
+
*/
|
|
1026
1148
|
function daemonProcessException(message) {
|
|
1149
|
+
// The log is an enrichment, not the classifier: it is absent on a first run,
|
|
1150
|
+
// which is exactly when the daemon is most likely to fail to start.
|
|
1151
|
+
let body = message;
|
|
1027
1152
|
try {
|
|
1028
1153
|
let log = (0, node_fs_1.readFileSync)(tmp_dir_1.DAEMON_OUTPUT_LOG_FILE).toString().split('\n');
|
|
1029
1154
|
if (log.length > 20) {
|
|
1030
1155
|
log = log.slice(log.length - 20);
|
|
1031
1156
|
}
|
|
1032
|
-
|
|
1157
|
+
body = [
|
|
1033
1158
|
message,
|
|
1034
1159
|
'',
|
|
1035
1160
|
'Messages from the log:',
|
|
1036
1161
|
...log,
|
|
1037
1162
|
'\n',
|
|
1038
1163
|
`More information: ${tmp_dir_1.DAEMON_OUTPUT_LOG_FILE}`,
|
|
1039
|
-
].join('\n')
|
|
1040
|
-
error.internalDaemonError = true;
|
|
1041
|
-
return error;
|
|
1042
|
-
}
|
|
1043
|
-
catch (e) {
|
|
1044
|
-
return new Error(message);
|
|
1164
|
+
].join('\n');
|
|
1045
1165
|
}
|
|
1166
|
+
catch { }
|
|
1167
|
+
const error = new Error(body);
|
|
1168
|
+
error.internalDaemonError = true;
|
|
1169
|
+
return error;
|
|
1046
1170
|
}
|
|
@@ -2,6 +2,23 @@ export declare function getDaemonEnv(): NodeJS.ProcessEnv & {
|
|
|
2
2
|
NX_PROJECT_GLOB_CACHE: string;
|
|
3
3
|
NX_CACHE_PROJECTS_CONFIG: string;
|
|
4
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* Env for spawning the daemon process. On top of the reflected env, it must
|
|
7
|
+
* keep excluded vars the daemon needs to start correctly:
|
|
8
|
+
* - ELECTRON_RUN_AS_NODE (matched by the ELECTRON_ prefix exclusion): when
|
|
9
|
+
* the spawning client runs inside an Electron host, process.execPath is
|
|
10
|
+
* the Electron binary and only this var makes it run the daemon's Node
|
|
11
|
+
* entry point.
|
|
12
|
+
* - NX_WORKSPACE_ROOT_PATH: the daemon resolves its workspace root at
|
|
13
|
+
* startup by walking up from cwd looking for workspace markers; without
|
|
14
|
+
* the pin, a root without markers under an ancestor that has them
|
|
15
|
+
* resolves to the ancestor and the daemon publishes its socket under the
|
|
16
|
+
* wrong workspace.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getDaemonSpawnEnv(): NodeJS.ProcessEnv & {
|
|
19
|
+
NX_PROJECT_GLOB_CACHE: string;
|
|
20
|
+
NX_CACHE_PROJECTS_CONFIG: string;
|
|
21
|
+
};
|
|
5
22
|
/**
|
|
6
23
|
* Without the deletion step, a var set by one client (e.g.
|
|
7
24
|
* `NX_PREFER_NODE_STRIP_TYPES=true` or `JAVA_TOOL_OPTIONS=...` for a single
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getDaemonEnv = getDaemonEnv;
|
|
4
|
+
exports.getDaemonSpawnEnv = getDaemonSpawnEnv;
|
|
4
5
|
exports.applyDaemonEnvFromClient = applyDaemonEnvFromClient;
|
|
5
6
|
const DAEMON_ENV_REQUIRED_SETTINGS = {
|
|
6
7
|
NX_PROJECT_GLOB_CACHE: 'false',
|
|
@@ -37,6 +38,12 @@ const DAEMON_ENV_VARS_EXCLUSIONS = new Set([
|
|
|
37
38
|
'NX_BATCH_MODE',
|
|
38
39
|
'NX_CI_EXECUTION_ID',
|
|
39
40
|
'NX_DAEMON_PROCESS',
|
|
41
|
+
'NX_CLI_SET',
|
|
42
|
+
// Set by Nx Console on the extension host; always equals the daemon's own
|
|
43
|
+
// workspace root (foreign-workspace messages are rejected), and the daemon
|
|
44
|
+
// resolves its root at startup before any client env is applied. The spawn
|
|
45
|
+
// env keeps it so that startup resolution honors the pinned root.
|
|
46
|
+
'NX_WORKSPACE_ROOT_PATH',
|
|
40
47
|
// Nx UI/logging vars (don't affect graph structure)
|
|
41
48
|
'NX_TUI',
|
|
42
49
|
'NX_TUI_AUTO_EXIT',
|
|
@@ -46,6 +53,7 @@ const DAEMON_ENV_VARS_EXCLUSIONS = new Set([
|
|
|
46
53
|
'NX_NATIVE_LOGGING',
|
|
47
54
|
'NX_PROFILE',
|
|
48
55
|
'NX_DAEMON_VERBOSE_LOGGING',
|
|
56
|
+
'NX_ORIGINAL_FORCE_COLOR',
|
|
49
57
|
// AI agent detection vars (the daemon itself is not an AI agent)
|
|
50
58
|
'CLAUDECODE',
|
|
51
59
|
'CLAUDE_CODE',
|
|
@@ -54,9 +62,12 @@ const DAEMON_ENV_VARS_EXCLUSIONS = new Set([
|
|
|
54
62
|
'COMPOSER_NO_INTERACTION',
|
|
55
63
|
'OPENCODE',
|
|
56
64
|
'GEMINI_CLI',
|
|
65
|
+
'CODEX_THREAD_ID',
|
|
66
|
+
'AI_AGENT',
|
|
57
67
|
// Shell mechanics
|
|
58
68
|
'_',
|
|
59
69
|
'SHLVL',
|
|
70
|
+
'PWD',
|
|
60
71
|
'OLDPWD',
|
|
61
72
|
'SHELL_SESSION_ID',
|
|
62
73
|
'TERM_SESSION_ID',
|
|
@@ -66,6 +77,56 @@ const DAEMON_ENV_VARS_EXCLUSIONS = new Set([
|
|
|
66
77
|
'COLUMNS',
|
|
67
78
|
'LINES',
|
|
68
79
|
'TMPDIR',
|
|
80
|
+
'PROMPT',
|
|
81
|
+
// Package-manager per-invocation vars not covered by the npm_/pnpm_ prefixes
|
|
82
|
+
'INIT_CWD',
|
|
83
|
+
'COLOR',
|
|
84
|
+
// Per-shell-session state; these tools' other vars are stable or can be
|
|
85
|
+
// meaningful (e.g. fnm's FNM_DIR), so no prefix exclusion
|
|
86
|
+
'FNM_MULTISHELL_PATH',
|
|
87
|
+
'POSH_SESSION_ID',
|
|
88
|
+
'MISE_SHELL',
|
|
89
|
+
// Editor preference; graph computation is non-interactive
|
|
90
|
+
'EDITOR',
|
|
91
|
+
'VISUAL',
|
|
92
|
+
// Output presentation
|
|
93
|
+
'PAGER',
|
|
94
|
+
'FORCE_COLOR',
|
|
95
|
+
'NO_COLOR',
|
|
96
|
+
'NODE_DISABLE_COLORS',
|
|
97
|
+
'FORCE_HYPERLINK',
|
|
98
|
+
// Terminal identification/presentation; differs per terminal app, so it
|
|
99
|
+
// churns whenever clients from different terminals share the daemon
|
|
100
|
+
'TERM',
|
|
101
|
+
'TERM_PROGRAM',
|
|
102
|
+
'TERM_PROGRAM_VERSION',
|
|
103
|
+
'COLORTERM',
|
|
104
|
+
'COLORFGBG',
|
|
105
|
+
'VTE_VERSION',
|
|
106
|
+
'GNOME_TERMINAL_SCREEN',
|
|
107
|
+
'GNOME_TERMINAL_SERVICE',
|
|
108
|
+
'WT_SESSION',
|
|
109
|
+
'WT_PROFILE_ID',
|
|
110
|
+
'TERMINAL_EMULATOR',
|
|
111
|
+
'TERMINUS_SUBLIME',
|
|
112
|
+
'ConEmuTask',
|
|
113
|
+
'ZELLIJ_PANE_ID',
|
|
114
|
+
'LC_TERMINAL',
|
|
115
|
+
'LC_TERMINAL_VERSION',
|
|
116
|
+
// Injected by VS Code and its extensions into integrated terminals. Single
|
|
117
|
+
// entries rather than GIT_/CHROME_/COPILOT_ prefixes: GIT_DIR, CHROME_BIN,
|
|
118
|
+
// COPILOT_HOME and COPILOT_GITHUB_TOKEN are functional inputs.
|
|
119
|
+
'GIT_ASKPASS',
|
|
120
|
+
'GIT_EDITOR',
|
|
121
|
+
'GIT_PAGER',
|
|
122
|
+
'GIT_MERGE_AUTOEDIT',
|
|
123
|
+
'APPLICATION_INSIGHTS_NO_STATSBEAT',
|
|
124
|
+
// Override for the @microsoft/mxc-sdk sandbox binaries; the SDK falls back
|
|
125
|
+
// to its bundled binaries when unset
|
|
126
|
+
'MXC_BIN_DIR',
|
|
127
|
+
'CHROME_CRASHPAD_PIPE_NAME',
|
|
128
|
+
'COPILOT_OTEL_FILE_EXPORTER_PATH',
|
|
129
|
+
'COPILOT_DEBUG_NONCE',
|
|
69
130
|
// Session / auth
|
|
70
131
|
'SSH_AUTH_SOCK',
|
|
71
132
|
'SSH_AGENT_PID',
|
|
@@ -103,16 +164,37 @@ const DAEMON_ENV_PREFIX_EXCLUSIONS = [
|
|
|
103
164
|
// Editors / IDEs
|
|
104
165
|
'VSCODE_',
|
|
105
166
|
'JETBRAINS_',
|
|
167
|
+
'ELECTRON_',
|
|
168
|
+
// AI agent harnesses (per-session ids; the bare CLAUDECODE/CLAUDE_CODE
|
|
169
|
+
// detection vars are excluded above)
|
|
170
|
+
'CLAUDE_CODE_',
|
|
171
|
+
// Shell prompts / integrations (per-command and per-session state)
|
|
172
|
+
'ATUIN_',
|
|
173
|
+
'STARSHIP_',
|
|
174
|
+
'MCFLY_',
|
|
175
|
+
'DIRENV_',
|
|
176
|
+
'__MISE_',
|
|
106
177
|
// Terminal emulators
|
|
107
178
|
'ITERM_',
|
|
108
179
|
'KITTY_',
|
|
109
180
|
'WEZTERM_',
|
|
110
181
|
'ALACRITTY_',
|
|
111
182
|
'KONSOLE_',
|
|
183
|
+
'GHOSTTY_',
|
|
112
184
|
'TMUX',
|
|
113
185
|
// Benchmarking / profiling tools
|
|
114
186
|
'HYPERFINE_', // hyperfine sets HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET for each iteration
|
|
115
187
|
];
|
|
188
|
+
/**
|
|
189
|
+
* Env var name patterns that should never be sent to the daemon. For vars
|
|
190
|
+
* whose NAME embeds a process id, so neither an exact entry nor a safe
|
|
191
|
+
* prefix can match them.
|
|
192
|
+
*/
|
|
193
|
+
const DAEMON_ENV_PATTERN_EXCLUSIONS = [
|
|
194
|
+
// Set by Windows 11 explorer.exe as EFC_<pid> (observed as EFC_<pid>_<hash>
|
|
195
|
+
// in Electron-spawned shells); regenerated on every login
|
|
196
|
+
/^EFC_\d+(_\d+)?$/,
|
|
197
|
+
];
|
|
116
198
|
/**
|
|
117
199
|
* Vars that match an excluded prefix but should still reach the daemon. The
|
|
118
200
|
* Nx Cloud auth/access tokens are excluded by the `NX_CLOUD_` prefix, but
|
|
@@ -125,11 +207,14 @@ const DAEMON_ENV_PREFIX_EXCLUSION_OVERRIDES = new Set([
|
|
|
125
207
|
'NX_CLOUD_AUTH_TOKEN',
|
|
126
208
|
]);
|
|
127
209
|
function isExcludedEnvVar(key) {
|
|
210
|
+
if (DAEMON_ENV_VARS_EXCLUSIONS.has(key) ||
|
|
211
|
+
DAEMON_ENV_PATTERN_EXCLUSIONS.some((pattern) => pattern.test(key))) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
128
214
|
if (DAEMON_ENV_PREFIX_EXCLUSION_OVERRIDES.has(key)) {
|
|
129
215
|
return false;
|
|
130
216
|
}
|
|
131
|
-
return (
|
|
132
|
-
DAEMON_ENV_PREFIX_EXCLUSIONS.some((prefix) => key.startsWith(prefix)));
|
|
217
|
+
return DAEMON_ENV_PREFIX_EXCLUSIONS.some((prefix) => key.startsWith(prefix));
|
|
133
218
|
}
|
|
134
219
|
function getDaemonEnv() {
|
|
135
220
|
const env = { ...DAEMON_ENV_OVERRIDABLE_SETTINGS };
|
|
@@ -140,6 +225,29 @@ function getDaemonEnv() {
|
|
|
140
225
|
}
|
|
141
226
|
return Object.assign(env, DAEMON_ENV_REQUIRED_SETTINGS);
|
|
142
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Env for spawning the daemon process. On top of the reflected env, it must
|
|
230
|
+
* keep excluded vars the daemon needs to start correctly:
|
|
231
|
+
* - ELECTRON_RUN_AS_NODE (matched by the ELECTRON_ prefix exclusion): when
|
|
232
|
+
* the spawning client runs inside an Electron host, process.execPath is
|
|
233
|
+
* the Electron binary and only this var makes it run the daemon's Node
|
|
234
|
+
* entry point.
|
|
235
|
+
* - NX_WORKSPACE_ROOT_PATH: the daemon resolves its workspace root at
|
|
236
|
+
* startup by walking up from cwd looking for workspace markers; without
|
|
237
|
+
* the pin, a root without markers under an ancestor that has them
|
|
238
|
+
* resolves to the ancestor and the daemon publishes its socket under the
|
|
239
|
+
* wrong workspace.
|
|
240
|
+
*/
|
|
241
|
+
function getDaemonSpawnEnv() {
|
|
242
|
+
const env = getDaemonEnv();
|
|
243
|
+
if (process.env.ELECTRON_RUN_AS_NODE !== undefined) {
|
|
244
|
+
env.ELECTRON_RUN_AS_NODE = process.env.ELECTRON_RUN_AS_NODE;
|
|
245
|
+
}
|
|
246
|
+
if (process.env.NX_WORKSPACE_ROOT_PATH !== undefined) {
|
|
247
|
+
env.NX_WORKSPACE_ROOT_PATH = process.env.NX_WORKSPACE_ROOT_PATH;
|
|
248
|
+
}
|
|
249
|
+
return env;
|
|
250
|
+
}
|
|
143
251
|
/**
|
|
144
252
|
* Without the deletion step, a var set by one client (e.g.
|
|
145
253
|
* `NX_PREFER_NODE_STRIP_TYPES=true` or `JAVA_TOOL_OPTIONS=...` for a single
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DaemonSocketMessenger = exports.VersionMismatchError = void 0;
|
|
4
4
|
const perf_hooks_1 = require("perf_hooks");
|
|
5
5
|
const consume_messages_from_socket_1 = require("../../utils/consume-messages-from-socket");
|
|
6
|
+
const workspace_root_1 = require("../../utils/workspace-root");
|
|
6
7
|
const logger_1 = require("../logger");
|
|
7
8
|
const socket_utils_1 = require("../socket-utils");
|
|
8
9
|
class VersionMismatchError extends Error {
|
|
@@ -21,6 +22,9 @@ class DaemonSocketMessenger {
|
|
|
21
22
|
if (!this.socket) {
|
|
22
23
|
throw new Error('Socket not initialized.');
|
|
23
24
|
}
|
|
25
|
+
// Stamp every message with the sending workspace's root so the daemon can
|
|
26
|
+
// reject messages from a different workspace (e.g. a shared NX_SOCKET_DIR).
|
|
27
|
+
messageToDaemon.workspaceRoot = workspace_root_1.workspaceRoot;
|
|
24
28
|
logger_1.clientLogger.log('[Messenger] Sending message type:', messageToDaemon.type);
|
|
25
29
|
perf_hooks_1.performance.mark('daemon-message-serialization-start-' + messageToDaemon.type);
|
|
26
30
|
const serialized = (0, socket_utils_1.serialize)(messageToDaemon, force);
|