nx 23.3.0 → 24.0.0-beta.1

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 (114) hide show
  1. package/README.md +3 -6
  2. package/dist/nx-cloud-internals.d.ts +1 -0
  3. package/dist/nx-cloud-internals.js +7 -1
  4. package/dist/src/adapter/ngcli-adapter.js +1 -0
  5. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +0 -12
  6. package/dist/src/command-line/graph/graph.js +3 -5
  7. package/dist/src/command-line/init/command-object.js +0 -12
  8. package/dist/src/command-line/init/init-v2.js +0 -2
  9. package/dist/src/command-line/migrate/agentic/close-agent-session.d.ts +1 -1
  10. package/dist/src/command-line/migrate/agentic/close-agent-session.js +4 -3
  11. package/dist/src/command-line/migrate/agentic/master/spawn-master.js +76 -15
  12. package/dist/src/command-line/migrate/execute-migration.d.ts +2 -2
  13. package/dist/src/command-line/migrate/execute-migration.js +18 -10
  14. package/dist/src/command-line/migrate/migrate-commits.d.ts +4 -1
  15. package/dist/src/command-line/migrate/migrate-commits.js +10 -3
  16. package/dist/src/command-line/migrate/migrate.js +43 -6
  17. package/dist/src/command-line/migrate/run/agent-output.d.ts +1 -0
  18. package/dist/src/command-line/migrate/run/agent-output.js +5 -0
  19. package/dist/src/command-line/migrate/run/broker.d.ts +14 -5
  20. package/dist/src/command-line/migrate/run/broker.js +68 -20
  21. package/dist/src/command-line/migrate/run/index.d.ts +4 -3
  22. package/dist/src/command-line/migrate/run/index.js +8 -1
  23. package/dist/src/command-line/migrate/run/orchestrator.js +72 -13
  24. package/dist/src/command-line/migrate/run/runbook.js +19 -0
  25. package/dist/src/command-line/migrate/run/state-machine.js +4 -1
  26. package/dist/src/command-line/migrate/run/util.d.ts +3 -0
  27. package/dist/src/command-line/migrate/run/util.js +7 -1
  28. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +17 -12
  29. package/dist/src/command-line/release/utils/remote-release-clients/github.js +5 -6
  30. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +5 -6
  31. package/dist/src/command-line/run/executor-utils.js +1 -0
  32. package/dist/src/command-line/run/run-one.d.ts +20 -1
  33. package/dist/src/command-line/run/run-one.js +153 -5
  34. package/dist/src/command-line/show/show-target/info.js +1 -1
  35. package/dist/src/command-line/show/show-target/utils.js +1 -0
  36. package/dist/src/command-line/watch/command-object.js +3 -22
  37. package/dist/src/command-line/watch/watch.d.ts +0 -7
  38. package/dist/src/command-line/watch/watch.js +1 -1
  39. package/dist/src/config/misc-interfaces.d.ts +12 -0
  40. package/dist/src/config/task-graph.d.ts +1 -1
  41. package/dist/src/config/workspace-json-project-json.d.ts +65 -0
  42. package/dist/src/core/graph/main.js +1 -1
  43. package/dist/src/daemon/client/client.d.ts +9 -0
  44. package/dist/src/daemon/client/client.js +89 -37
  45. package/dist/src/daemon/server/shutdown-utils.js +0 -3
  46. package/dist/src/daemon/socket-utils.d.ts +9 -4
  47. package/dist/src/daemon/socket-utils.js +12 -49
  48. package/dist/src/daemon/tmp-dir.d.ts +19 -14
  49. package/dist/src/daemon/tmp-dir.js +142 -354
  50. package/dist/src/devkit-exports.d.ts +1 -1
  51. package/dist/src/devkit-internals.d.ts +1 -1
  52. package/dist/src/devkit-internals.js +1 -0
  53. package/dist/src/hasher/check-task-files.js +4 -4
  54. package/dist/src/hasher/file-hasher.js +9 -7
  55. package/dist/src/hasher/hash-task.js +4 -0
  56. package/dist/src/hasher/native-task-hasher-impl.js +3 -1
  57. package/dist/src/migrations/update-24-0-0/find-custom-hashers.d.ts +3 -0
  58. package/dist/src/migrations/update-24-0-0/find-custom-hashers.js +100 -0
  59. package/dist/src/migrations/update-24-0-0/find-custom-hashers.md +63 -0
  60. package/dist/src/migrations/update-24-0-0/move-custom-hashers-to-inputs.md +145 -0
  61. package/dist/src/native/index.d.ts +180 -12
  62. package/dist/src/native/native-bindings.js +8 -0
  63. package/dist/src/native/nx.wasi-browser.js +1 -0
  64. package/dist/src/native/nx.wasi.cjs +1 -0
  65. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  66. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  67. package/dist/src/nx-cloud/update-manager.d.ts +7 -0
  68. package/dist/src/nx-cloud/update-manager.js +237 -50
  69. package/dist/src/project-graph/affected/affected-tasks.js +1 -0
  70. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +7 -0
  71. package/dist/src/tasks-runner/create-task-graph.d.ts +8 -7
  72. package/dist/src/tasks-runner/create-task-graph.js +47 -26
  73. package/dist/src/tasks-runner/init-tasks-runner.js +13 -0
  74. package/dist/src/tasks-runner/life-cycle.d.ts +4 -1
  75. package/dist/src/tasks-runner/life-cycle.js +7 -0
  76. package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +5 -2
  77. package/dist/src/tasks-runner/life-cycles/performance-analysis.js +13 -7
  78. package/dist/src/tasks-runner/life-cycles/performance-life-cycle.d.ts +4 -3
  79. package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +9 -2
  80. package/dist/src/tasks-runner/readiness/probes.d.ts +9 -0
  81. package/dist/src/tasks-runner/readiness/probes.js +62 -0
  82. package/dist/src/tasks-runner/readiness/ready-when.d.ts +38 -0
  83. package/dist/src/tasks-runner/readiness/ready-when.js +190 -0
  84. package/dist/src/tasks-runner/run-command.js +5 -4
  85. package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -4
  86. package/dist/src/tasks-runner/task-env.d.ts +10 -0
  87. package/dist/src/tasks-runner/task-env.js +26 -5
  88. package/dist/src/tasks-runner/task-graph-utils.d.ts +9 -6
  89. package/dist/src/tasks-runner/task-graph-utils.js +17 -12
  90. package/dist/src/tasks-runner/task-orchestrator.d.ts +37 -8
  91. package/dist/src/tasks-runner/task-orchestrator.js +460 -76
  92. package/dist/src/tasks-runner/tasks-schedule.d.ts +18 -1
  93. package/dist/src/tasks-runner/tasks-schedule.js +64 -6
  94. package/dist/src/tasks-runner/utils.d.ts +20 -5
  95. package/dist/src/tasks-runner/utils.js +70 -35
  96. package/dist/src/ultracache/overrides.js +4 -0
  97. package/dist/src/utils/child-process.js +1 -0
  98. package/dist/src/utils/git-utils.d.ts +6 -1
  99. package/dist/src/utils/git-utils.js +26 -5
  100. package/dist/src/utils/owned-private-dir.d.ts +1 -17
  101. package/dist/src/utils/owned-private-dir.js +10 -62
  102. package/dist/src/utils/perf-hooks.d.ts +1 -0
  103. package/dist/src/utils/plugins/core-plugins.js +1 -1
  104. package/dist/src/utils/spawn-without-terminal.d.ts +27 -0
  105. package/dist/src/utils/spawn-without-terminal.js +110 -0
  106. package/dist/src/utils/string-similarity.d.ts +38 -0
  107. package/dist/src/utils/string-similarity.js +108 -0
  108. package/migrations.json +7 -0
  109. package/package.json +11 -20
  110. package/readme-template.md +3 -3
  111. package/schemas/nx-schema.json +70 -0
  112. package/schemas/project-schema.json +67 -0
  113. package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +0 -18
  114. package/dist/src/tasks-runner/legacy-depends-on-warning.js +0 -109
@@ -8,7 +8,7 @@
8
8
  // every file the parent could consult is writable from the sandbox, so the
9
9
  // parent's own invocation decides what it installs and commits.
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.MigrateCommitBroker = exports.TreeBusyError = exports.BrokerUnavailableError = exports.BrokerStaleRequestError = exports.BROKER_ENV_VAR = void 0;
11
+ exports.MigrateCommitBroker = exports.COMMIT_INSTALLS_FIRST = exports.TreeBusyError = exports.BrokerUnavailableError = exports.BrokerStaleRequestError = exports.BROKER_ENV_VAR = void 0;
12
12
  exports.acquireTreeOperation = acquireTreeOperation;
13
13
  exports.releaseTreeOperation = releaseTreeOperation;
14
14
  exports.liveTreeOperation = liveTreeOperation;
@@ -19,16 +19,21 @@ exports.commitStepTree = commitStepTree;
19
19
  exports.installStepTree = installStepTree;
20
20
  exports.resetStepTree = resetStepTree;
21
21
  exports.giveUpStepTree = giveUpStepTree;
22
+ exports.commitsStep = commitsStep;
23
+ exports.sessionOperationWayOut = sessionOperationWayOut;
24
+ exports.formatElapsed = formatElapsed;
22
25
  const crypto_1 = require("crypto");
23
26
  const fs_1 = require("fs");
24
27
  const path_1 = require("path");
25
28
  const native_1 = require("../../../native");
26
29
  const fileutils_1 = require("../../../utils/fileutils");
27
30
  const json_1 = require("../../../utils/json");
31
+ const pretty_time_1 = require("../../../tasks-runner/life-cycles/pretty-time");
28
32
  const handoff_1 = require("../agentic/handoff");
29
33
  const deferred_output_1 = require("../deferred-output");
30
34
  const execute_migration_1 = require("../execute-migration");
31
35
  const migrate_commits_1 = require("../migrate-commits");
36
+ const agent_output_1 = require("./agent-output");
32
37
  const atomic_write_1 = require("./atomic-write");
33
38
  const give_up_1 = require("./give-up");
34
39
  const run_state_1 = require("./run-state");
@@ -40,6 +45,9 @@ const util_1 = require("./util");
40
45
  exports.BROKER_ENV_VAR = 'NX_MIGRATE_BROKER';
41
46
  const BROKER_DIR_NAME = 'broker';
42
47
  const CHILD_POLL_INTERVAL_MS = 250;
48
+ // The runbook's "Long-running commands" section states both intervals.
49
+ const FIRST_WAITING_LINE_MS = 15_000;
50
+ const WAITING_LINE_INTERVAL_MS = 60_000;
43
51
  /** The request no longer matches the step: another attempt owns it. */
44
52
  class BrokerStaleRequestError extends Error {
45
53
  }
@@ -74,7 +82,7 @@ function acquireTreeOperation(dir, request, owner = (0, crypto_1.randomBytes)(4)
74
82
  if (held)
75
83
  throw new TreeBusyError(treeBusyMessage(held));
76
84
  marks =
77
- (request.kind === 'commit' || request.kind === 'give-up') &&
85
+ commitsStep(request.kind) &&
78
86
  fresh.steps.find((s) => s.id === request.stepId)?.commitStarted !== true;
79
87
  return {
80
88
  ...(marks ? (0, state_machine_1.markCommitStarted)(fresh, request.stepId) : fresh),
@@ -113,22 +121,22 @@ function liveTreeOperation(state, owner) {
113
121
  return undefined;
114
122
  return held;
115
123
  }
116
- function treeBusyMessage(held) {
117
- return `The working tree is held by process ${held.pid} for ${treeOperationLabel(held)}; run the reconcile again once it finishes.`;
124
+ function treeBusyMessage(held, stepName) {
125
+ return `The working tree is held by process ${held.pid} for ${treeOperationLabel(held, stepName)}; run the reconcile again once it finishes.`;
118
126
  }
119
- function treeOperationLabel(held) {
127
+ function treeOperationLabel(held, stepName = `step '${held.stepId}'`) {
120
128
  switch (held.kind) {
121
129
  case 'checkpoint':
122
130
  return 'the checkpoint commit';
123
131
  case 'commit':
124
132
  case 'give-up':
125
- return `the commit of step '${held.stepId}'`;
133
+ return `the commit of ${stepName}`;
126
134
  case 'reset':
127
- return `the reset of step '${held.stepId}'`;
135
+ return `the reset of ${stepName}`;
128
136
  case 'install':
129
137
  case 'fold-install':
130
138
  case 'action-install':
131
- return `the install of step '${held.stepId}'`;
139
+ return `the install of ${stepName}`;
132
140
  default: {
133
141
  const exhaustive = held.kind;
134
142
  throw new Error(`Unhandled tree operation '${exhaustive}'.`);
@@ -204,7 +212,7 @@ async function commitStepTree(dir, step, absorbedStepIds, commitInProcess, scope
204
212
  lease.markedStepId = undefined;
205
213
  return { result, absorbedStepIds, recorded: false };
206
214
  }
207
- const answer = await ask(dir, nonce, request);
215
+ const answer = await ask(dir, nonce, request, (0, state_machine_1.stepLabel)(step));
208
216
  if (answer.kind !== 'commit') {
209
217
  throw new Error(`Unexpected '${answer.kind}' answer to a commit request.`);
210
218
  }
@@ -229,7 +237,7 @@ async function installStepTree(dir, step, seam, installInProcess, scope) {
229
237
  scope.lease = acquireTreeOperation(dir, request);
230
238
  return installInProcess();
231
239
  }
232
- const answer = await ask(dir, nonce, request);
240
+ const answer = await ask(dir, nonce, request, (0, state_machine_1.stepLabel)(step));
233
241
  if (answer.kind !== 'installed') {
234
242
  throw new Error(`Unexpected '${answer.kind}' answer to an install request.`);
235
243
  }
@@ -251,7 +259,7 @@ async function resetStepTree(dir, step, resetInProcess, scope) {
251
259
  scope.lease = acquireTreeOperation(dir, request);
252
260
  return resetInProcess();
253
261
  }
254
- const answer = await ask(dir, nonce, request);
262
+ const answer = await ask(dir, nonce, request, (0, state_machine_1.stepLabel)(step));
255
263
  if (answer.kind !== 'reset') {
256
264
  throw new Error(`Unexpected '${answer.kind}' answer to a reset request.`);
257
265
  }
@@ -280,13 +288,13 @@ async function giveUpStepTree(root, dir, step, skipInstall, reconcileCommand, sc
280
288
  reconcileCommand,
281
289
  });
282
290
  }
283
- const answer = await ask(dir, nonce, request);
291
+ const answer = await ask(dir, nonce, request, (0, state_machine_1.stepLabel)(step));
284
292
  if (answer.kind !== 'give-up') {
285
293
  throw new Error(`Unexpected '${answer.kind}' answer to a give-up request.`);
286
294
  }
287
295
  return answer.outcome;
288
296
  }
289
- async function ask(dir, nonce, request) {
297
+ async function ask(dir, nonce, request, stepName) {
290
298
  const id = `${nonce}-${request.stepId}-${request.attempt}-${request.kind}${request.invocation ? `-${request.invocation}` : ''}${request.commitAs !== undefined ? `-${request.commitAs}` : ''}`;
291
299
  const path = resultPath(dir, id);
292
300
  // A repeat reads the first answer, whatever became of the session since.
@@ -313,6 +321,8 @@ async function ask(dir, nonce, request) {
313
321
  catch (e) {
314
322
  throw notAccepting(e);
315
323
  }
324
+ const askedAt = Date.now();
325
+ let nextWaitingLineAt = askedAt + FIRST_WAITING_LINE_MS;
316
326
  for (;;) {
317
327
  if ((0, fs_1.existsSync)(path)) {
318
328
  return settle((0, fileutils_1.readJsonFile)(path));
@@ -323,9 +333,49 @@ async function ask(dir, nonce, request) {
323
333
  continue;
324
334
  throw new BrokerUnavailableError(`The nx migrate session that started this step ended before its request was answered. The install or the commit may still have landed; check the working tree and git log.`);
325
335
  }
336
+ if (Date.now() >= nextWaitingLineAt) {
337
+ nextWaitingLineAt = Date.now() + WAITING_LINE_INTERVAL_MS;
338
+ (0, agent_output_1.logLineToAgent)(waitingLine(request, stepName, Date.now() - askedAt));
339
+ }
326
340
  await new Promise((resolve) => setTimeout(resolve, CHILD_POLL_INTERVAL_MS));
327
341
  }
328
342
  }
343
+ function waitingLine(request, stepName, waitedMs) {
344
+ return [
345
+ `[nx] Waiting for the nx process that started this session to finish ${treeOperationLabel(request, stepName)} (${formatElapsed(waitedMs)} so far).`,
346
+ ...(commitsStep(request.kind)
347
+ ? [
348
+ exports.COMMIT_INSTALLS_FIRST,
349
+ 'A signing popup or a security key can also hold a commit until the user answers it.',
350
+ ]
351
+ : []),
352
+ `If it seems stuck, the user can ${sessionOperationWayOut('it')}.`,
353
+ ].join(' ');
354
+ }
355
+ exports.COMMIT_INSTALLS_FIRST = 'A commit first installs any dependency changes.';
356
+ function commitsStep(kind) {
357
+ switch (kind) {
358
+ case 'commit':
359
+ case 'give-up':
360
+ return true;
361
+ case 'checkpoint':
362
+ case 'install':
363
+ case 'fold-install':
364
+ case 'action-install':
365
+ case 'reset':
366
+ return false;
367
+ default: {
368
+ const exhaustive = kind;
369
+ throw new Error(`Unhandled tree operation '${exhaustive}'.`);
370
+ }
371
+ }
372
+ }
373
+ function sessionOperationWayOut(operation) {
374
+ return `quit this session, then press Ctrl+C in the terminal to end ${operation}, and resume the run afterwards`;
375
+ }
376
+ function formatElapsed(ms) {
377
+ return (0, pretty_time_1.prettyTime)(Math.max(0, Math.round(ms)) * 1e6, 's');
378
+ }
329
379
  function notAccepting(e) {
330
380
  return new BrokerUnavailableError(`The nx migrate session that started this step is not accepting its request (${e instanceof Error ? e.message : String(e)}).`);
331
381
  }
@@ -387,7 +437,7 @@ class MigrateCommitBroker {
387
437
  this.lock = native_1.IS_WASM ? null : new native_1.FileLock(lockPath(dir, this.nonce));
388
438
  this.lock?.lock();
389
439
  }
390
- /** The request whose operation this process is running right now. */
440
+ /** The request whose operation this process is running right now, and since when. */
391
441
  get requestInFlight() {
392
442
  return this.inFlight;
393
443
  }
@@ -423,8 +473,6 @@ class MigrateCommitBroker {
423
473
  this.handled.add(id);
424
474
  let result;
425
475
  try {
426
- if (lease)
427
- this.inFlight = request;
428
476
  result = lease ? await this.answer(request, lease) : { kind: 'stale' };
429
477
  // Recorded by the process that ran the commit, before the answer: the
430
478
  // step reading it can die with the commit already in history. A failed
@@ -466,13 +514,13 @@ class MigrateCommitBroker {
466
514
  const step = state.steps.find((s) => s.id === request.stepId);
467
515
  if (!Object.hasOwn(SEAM_STATUSES, request.kind) ||
468
516
  !isAtSeam(step, request) ||
469
- ((request.kind === 'commit' ||
470
- request.kind === 'reset' ||
471
- request.kind === 'give-up') &&
517
+ ((commitsStep(request.kind) || request.kind === 'reset') &&
472
518
  !this.policy.createCommits) ||
473
519
  (request.commitAs !== undefined && request.commitAs !== 'adopt')) {
474
520
  return { kind: 'stale' };
475
521
  }
522
+ const stepName = (0, state_machine_1.stepLabel)(step);
523
+ this.inFlight = { request, startedAt: Date.now(), stepName };
476
524
  if (request.kind === 'give-up') {
477
525
  const output = new deferred_output_1.DeferredOutputCollector();
478
526
  const outcome = await (0, give_up_1.giveUpWithCommit)({
@@ -540,7 +588,7 @@ class MigrateCommitBroker {
540
588
  };
541
589
  }
542
590
  }
543
- /** Releases the lock; call after the last `service` settled. */
591
+ /** Releases the lock; call after the last `service` settled, or once giving up on it. */
544
592
  close() {
545
593
  this.lock?.unlock();
546
594
  // A reservation this session still holds would only expire with its pid.
@@ -1,12 +1,13 @@
1
- export { CURRENT_RUN_STATE_FORMAT_VERSION, NewerRunStateFormatError, migrateRunsDir, runDir, runHandoffsDir, readRunState, writeRunState, findActiveRun, createRun, } from './run-state';
1
+ export { CURRENT_RUN_STATE_FORMAT_VERSION, NewerRunStateFormatError, migrateRunsDir, runDir, runHandoffsDir, readRunState, writeRunState, findActiveRun, createRun, TERMINAL_STEP_STATUSES, } from './run-state';
2
2
  export type { MigrateRunStatus, MigrateRunRound, MigrateStepStatus, PromptOutcomeStatus, MigrateStepAwaitingKind, MigrateStepOutcome, MigrateStepPromptOutcome, MigrateStep, MigrateCommitKind, MigrateCommitLedgerEntry, MigrateIssueDisposition, MigrateRunIssue, MigrateRunAnalytics, MigrateRunNoProgress, MigrateRunPolicy, MigrateRunState, } from './run-state';
3
- export { applyStepEvent, completionSummaryLines, hasPendingCommitDebt, latestRound, runTallies, tallySteps, } from './state-machine';
3
+ export { applyStepEvent, completionSummaryLines, hasPendingCommitDebt, latestRound, runTallies, stepLabel, tallySteps, } from './state-machine';
4
4
  export { hasUnresolvedIssues } from './issues';
5
5
  export type { StepAction, StepEvent, ApplyStepEventResult, } from './state-machine';
6
6
  export { createRunId } from './run-id';
7
+ export { pmInstallCommand } from './util';
7
8
  export { runSingleMigrationWorker } from './worker';
8
9
  export type { RunSingleMigrationWorkerInput } from './worker';
9
10
  export { activeRunToReplace, completionWarnings, holdRunToContinue, releaseRunToHandOff, runOrchestratorInit, runOrchestratorReconcile, runOrchestratorResume, } from './orchestrator';
10
11
  export type { OrchestratorInitResult, RunOrchestratorInitInput, RunOrchestratorReconcileInput, } from './orchestrator';
11
12
  export { renderContinueCommand, renderExistingRunCommands, renderExistingRunReport, } from './existing-run-report';
12
- export { BROKER_ENV_VAR, MigrateCommitBroker, treeOperationLabel, } from './broker';
13
+ export { BROKER_ENV_VAR, COMMIT_INSTALLS_FIRST, formatElapsed, MigrateCommitBroker, commitsStep, treeOperationLabel, } from './broker';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.treeOperationLabel = exports.MigrateCommitBroker = exports.BROKER_ENV_VAR = exports.renderExistingRunReport = exports.renderExistingRunCommands = exports.renderContinueCommand = exports.runOrchestratorResume = exports.runOrchestratorReconcile = exports.runOrchestratorInit = exports.releaseRunToHandOff = exports.holdRunToContinue = exports.completionWarnings = exports.activeRunToReplace = exports.runSingleMigrationWorker = exports.createRunId = exports.hasUnresolvedIssues = exports.tallySteps = exports.runTallies = exports.latestRound = exports.hasPendingCommitDebt = exports.completionSummaryLines = exports.applyStepEvent = exports.createRun = exports.findActiveRun = exports.writeRunState = exports.readRunState = exports.runHandoffsDir = exports.runDir = exports.migrateRunsDir = exports.NewerRunStateFormatError = exports.CURRENT_RUN_STATE_FORMAT_VERSION = void 0;
3
+ exports.treeOperationLabel = exports.commitsStep = exports.MigrateCommitBroker = exports.formatElapsed = exports.COMMIT_INSTALLS_FIRST = exports.BROKER_ENV_VAR = exports.renderExistingRunReport = exports.renderExistingRunCommands = exports.renderContinueCommand = exports.runOrchestratorResume = exports.runOrchestratorReconcile = exports.runOrchestratorInit = exports.releaseRunToHandOff = exports.holdRunToContinue = exports.completionWarnings = exports.activeRunToReplace = exports.runSingleMigrationWorker = exports.pmInstallCommand = exports.createRunId = exports.hasUnresolvedIssues = exports.tallySteps = exports.stepLabel = exports.runTallies = exports.latestRound = exports.hasPendingCommitDebt = exports.completionSummaryLines = exports.applyStepEvent = exports.TERMINAL_STEP_STATUSES = exports.createRun = exports.findActiveRun = exports.writeRunState = exports.readRunState = exports.runHandoffsDir = exports.runDir = exports.migrateRunsDir = exports.NewerRunStateFormatError = exports.CURRENT_RUN_STATE_FORMAT_VERSION = void 0;
4
4
  var run_state_1 = require("./run-state");
5
5
  Object.defineProperty(exports, "CURRENT_RUN_STATE_FORMAT_VERSION", { enumerable: true, get: function () { return run_state_1.CURRENT_RUN_STATE_FORMAT_VERSION; } });
6
6
  Object.defineProperty(exports, "NewerRunStateFormatError", { enumerable: true, get: function () { return run_state_1.NewerRunStateFormatError; } });
@@ -11,17 +11,21 @@ Object.defineProperty(exports, "readRunState", { enumerable: true, get: function
11
11
  Object.defineProperty(exports, "writeRunState", { enumerable: true, get: function () { return run_state_1.writeRunState; } });
12
12
  Object.defineProperty(exports, "findActiveRun", { enumerable: true, get: function () { return run_state_1.findActiveRun; } });
13
13
  Object.defineProperty(exports, "createRun", { enumerable: true, get: function () { return run_state_1.createRun; } });
14
+ Object.defineProperty(exports, "TERMINAL_STEP_STATUSES", { enumerable: true, get: function () { return run_state_1.TERMINAL_STEP_STATUSES; } });
14
15
  var state_machine_1 = require("./state-machine");
15
16
  Object.defineProperty(exports, "applyStepEvent", { enumerable: true, get: function () { return state_machine_1.applyStepEvent; } });
16
17
  Object.defineProperty(exports, "completionSummaryLines", { enumerable: true, get: function () { return state_machine_1.completionSummaryLines; } });
17
18
  Object.defineProperty(exports, "hasPendingCommitDebt", { enumerable: true, get: function () { return state_machine_1.hasPendingCommitDebt; } });
18
19
  Object.defineProperty(exports, "latestRound", { enumerable: true, get: function () { return state_machine_1.latestRound; } });
19
20
  Object.defineProperty(exports, "runTallies", { enumerable: true, get: function () { return state_machine_1.runTallies; } });
21
+ Object.defineProperty(exports, "stepLabel", { enumerable: true, get: function () { return state_machine_1.stepLabel; } });
20
22
  Object.defineProperty(exports, "tallySteps", { enumerable: true, get: function () { return state_machine_1.tallySteps; } });
21
23
  var issues_1 = require("./issues");
22
24
  Object.defineProperty(exports, "hasUnresolvedIssues", { enumerable: true, get: function () { return issues_1.hasUnresolvedIssues; } });
23
25
  var run_id_1 = require("./run-id");
24
26
  Object.defineProperty(exports, "createRunId", { enumerable: true, get: function () { return run_id_1.createRunId; } });
27
+ var util_1 = require("./util");
28
+ Object.defineProperty(exports, "pmInstallCommand", { enumerable: true, get: function () { return util_1.pmInstallCommand; } });
25
29
  var worker_1 = require("./worker");
26
30
  Object.defineProperty(exports, "runSingleMigrationWorker", { enumerable: true, get: function () { return worker_1.runSingleMigrationWorker; } });
27
31
  var orchestrator_1 = require("./orchestrator");
@@ -38,5 +42,8 @@ Object.defineProperty(exports, "renderExistingRunCommands", { enumerable: true,
38
42
  Object.defineProperty(exports, "renderExistingRunReport", { enumerable: true, get: function () { return existing_run_report_1.renderExistingRunReport; } });
39
43
  var broker_1 = require("./broker");
40
44
  Object.defineProperty(exports, "BROKER_ENV_VAR", { enumerable: true, get: function () { return broker_1.BROKER_ENV_VAR; } });
45
+ Object.defineProperty(exports, "COMMIT_INSTALLS_FIRST", { enumerable: true, get: function () { return broker_1.COMMIT_INSTALLS_FIRST; } });
46
+ Object.defineProperty(exports, "formatElapsed", { enumerable: true, get: function () { return broker_1.formatElapsed; } });
41
47
  Object.defineProperty(exports, "MigrateCommitBroker", { enumerable: true, get: function () { return broker_1.MigrateCommitBroker; } });
48
+ Object.defineProperty(exports, "commitsStep", { enumerable: true, get: function () { return broker_1.commitsStep; } });
42
49
  Object.defineProperty(exports, "treeOperationLabel", { enumerable: true, get: function () { return broker_1.treeOperationLabel; } });
@@ -776,6 +776,8 @@ async function runOrchestratorReconcile(input) {
776
776
  return;
777
777
  }
778
778
  (0, give_up_1.warnAboutGiveUp)(target, outcome);
779
+ if (target.installFailed === true)
780
+ warnInstallLeftToUser(root, target);
779
781
  // Settled already; the dispense refuses a tree still held.
780
782
  scope.lease?.release();
781
783
  scope.lease = undefined;
@@ -786,8 +788,9 @@ async function runOrchestratorReconcile(input) {
786
788
  // sections stay synchronous); the transition and any unrecorded entry then
787
789
  // land in one write. Adopt and skip keep the tree, so the install they owe
788
790
  // runs here: the next dispense would take the changed deps as its baseline.
789
- // Giving up keeps it the same way when the run does not commit. Retries
790
- // owe nothing: the rearmed attempt reconciles itself.
791
+ // Giving up keeps it the same way when the run does not commit. An install
792
+ // that already failed is left to the step's mark instead. Retries owe
793
+ // nothing: the rearmed attempt reconciles itself.
791
794
  const { entry, installFailed, recorded } = await stepActionSideEffects(root, dir, state, target, stepAction, result.resetTree, scope);
792
795
  // A rearm starts a fresh attempt; drop the stale handoff before the rearm
793
796
  // is persisted so a crash in between can't refold the old outcome into the
@@ -863,6 +866,11 @@ async function runOrchestratorReconcile(input) {
863
866
  if (unresolvedArchiveError !== undefined) {
864
867
  (0, give_up_1.warnUnresolvedNotArchived)((0, state_machine_1.stepLabel)(target), unresolvedArchiveError);
865
868
  }
869
+ // A retry's rearm drops the mark: its next attempt installs.
870
+ if (target.installFailed === true &&
871
+ written.steps.find((s) => s.id === target.id)?.installFailed === true) {
872
+ warnInstallLeftToUser(root, target);
873
+ }
866
874
  state = written;
867
875
  }
868
876
  finally {
@@ -1131,6 +1139,14 @@ async function installFailedForStep(root, dir, state, step, seam, scope) {
1131
1139
  return true;
1132
1140
  }
1133
1141
  }
1142
+ function warnInstallLeftToUser(root, step) {
1143
+ (0, agent_output_1.warnToAgent)({
1144
+ title: `The dependency changes made by ${(0, state_machine_1.stepLabel)(step)} are not installed.`,
1145
+ bodyLines: [
1146
+ `Run \`${(0, util_1.pmInstallCommand)(root)}\` once the cause of the failed install is fixed. The run's final report repeats this unless a later install covers them.`,
1147
+ ],
1148
+ });
1149
+ }
1134
1150
  // A failed handoff fails the prompt; a success handoff completes it, unless it
1135
1151
  // marks the prompt not applicable via `extras.outcome === 'skipped'`.
1136
1152
  function handoffToPromptOutcome(handoff) {
@@ -1316,11 +1332,13 @@ function unresolvedResetsTree(state, step, cleanRetry) {
1316
1332
  async function stepActionSideEffects(root, dir, state, step, action, resetTree, scope) {
1317
1333
  switch (action) {
1318
1334
  case 'adopt':
1319
- // A died worker's unrecorded commit request is reused. A failed step, or
1320
- // a recorded commit, needs an adopt request of its own, or the old answer
1321
- // would be replayed.
1335
+ // A died worker's commit request is reused while nothing records its
1336
+ // outcome, since the session may still answer it. Otherwise the adopt
1337
+ // asks under its own request, or the old answer would be replayed.
1322
1338
  return state.createCommits
1323
1339
  ? commitForStep(root, dir, state, step, scope, step.status === 'failed' ||
1340
+ step.commitLedgerIndex !== undefined ||
1341
+ step.installFailed === true ||
1324
1342
  (0, state_machine_1.coveringLandedEntries)(state, step.id).length > 0
1325
1343
  ? 'adopt'
1326
1344
  : undefined)
@@ -1631,6 +1649,7 @@ function emitRetryFailed(root, runId, state, step, noProgress) {
1631
1649
  ` current HEAD: ${head ?? '(unknown)'}`,
1632
1650
  ` working tree: ${tree === null ? '(unknown)' : tree ? `\n${tree}` : '(clean)'}`,
1633
1651
  ``,
1652
+ ...unfinishedOperationLines(root, state, step),
1634
1653
  retryBudgetLine(step, committed),
1635
1654
  ``,
1636
1655
  `Decide how to proceed and re-run reconcile with one of:`,
@@ -1641,11 +1660,15 @@ function emitRetryFailed(root, runId, state, step, noProgress) {
1641
1660
  if (cleanRetry && !capReached) {
1642
1661
  lines.push(` retry-clean: reset the tree to ${step.gitRefBefore ?? 'the pre-migration ref'} (discarding its uncommitted tracked changes and the untracked files git does not ignore, ${types_1.MIGRATE_RUNS_RELATIVE_DIR} kept) and retry from that clean state by running: ${reconcileCommand(root, runId, 'retry-clean')}`);
1643
1662
  }
1663
+ // A failed commit is already named above the choices.
1664
+ const adoptWhen = recordedCommitFailed(state, step)
1665
+ ? ''
1666
+ : committed
1667
+ ? `a commit of this ${(0, state_machine_1.stepNoun)(step)}'s changes was started and never recorded; `
1668
+ : `the ${(0, state_machine_1.stepNoun)(step)} was ${step.kind === 'migration' ? 'applied' : 'done'} by hand; `;
1644
1669
  lines.push(landed
1645
1670
  ? ` adopt: keep the landed commit${landed.sha ? ` ${landed.sha}` : ''} and the current working-tree state as the ${(0, state_machine_1.stepNoun)(step)}'s result, then run: ${reconcileCommand(root, runId, 'adopt')}`
1646
- : ` adopt: ${committed
1647
- ? `a commit of this ${(0, state_machine_1.stepNoun)(step)}'s changes was started and never recorded`
1648
- : `the ${(0, state_machine_1.stepNoun)(step)} was ${step.kind === 'migration' ? 'applied' : 'done'} by hand`}; keep the current working-tree state as its result, then run: ${reconcileCommand(root, runId, 'adopt')}`);
1671
+ : ` adopt: ${adoptWhen}keep the current working-tree state as its result, then run: ${reconcileCommand(root, runId, 'adopt')}`);
1649
1672
  // Refused by the state machine: the migration is, or may be, committed.
1650
1673
  if (!committed) {
1651
1674
  lines.push(` skip: ${reconcileCommand(root, runId, 'skip')}`, unresolvedOptionLine(root, runId, state, step, unresolvedResetsTree(state, step, cleanRetry)));
@@ -1677,6 +1700,26 @@ function retryBudgetLine(step, committed) {
1677
1700
  ? `adopt only once you have inspected the tree and finished the ${(0, state_machine_1.stepNoun)(step)}; otherwise stop and report`
1678
1701
  : 'give the step up with unresolved and continue'}.`;
1679
1702
  }
1703
+ // A recorded failed commit with the mark standing withdraws skip and
1704
+ // unresolved, so every choice left commits.
1705
+ function unfinishedOperationLines(root, state, step) {
1706
+ const lines = [];
1707
+ if (step.installFailed === true) {
1708
+ lines.push(`Its dependency install did not complete. A retry runs it again, so fix the cause first if it can be fixed. Any other choice settles the step without installing and leaves the install to you; the run's final report asks for \`${(0, util_1.pmInstallCommand)(root)}\`.`, ``);
1709
+ }
1710
+ if (recordedCommitFailed(state, step)) {
1711
+ lines.push(`Its commit did not complete. Every choice below commits again.`, ``);
1712
+ }
1713
+ return lines;
1714
+ }
1715
+ function recordedCommitFailed(state, step) {
1716
+ // Not commitReceipt, which throws on an index the ledger lacks: a dispense
1717
+ // has to render whatever run.json holds.
1718
+ const receipt = step.commitLedgerIndex === undefined
1719
+ ? undefined
1720
+ : state.commits[step.commitLedgerIndex];
1721
+ return step.commitStarted === true && receipt?.kind === 'failed';
1722
+ }
1680
1723
  // Opens a capped dispense and is the reason a retry past the cap is refused.
1681
1724
  function rearmCapLine(step, committed) {
1682
1725
  return `This ${(0, state_machine_1.stepNoun)(step)} has already been retried ${step.attempt - 1} times without completing, and no further retry is accepted. ${committed
@@ -1776,6 +1819,7 @@ function emitDied(root, runId, state, step, noProgress) {
1776
1819
  ` current HEAD: ${head ?? '(unknown)'}`,
1777
1820
  ` working tree: ${tree === null ? '(unknown)' : tree ? `\n${tree}` : '(clean)'}`,
1778
1821
  ``,
1822
+ ...unfinishedOperationLines(root, state, step),
1779
1823
  retryBudgetLine(step, committed),
1780
1824
  ``,
1781
1825
  ];
@@ -1810,9 +1854,19 @@ function emitDied(root, runId, state, step, noProgress) {
1810
1854
  }, noProgress);
1811
1855
  }
1812
1856
  function emitHeld(root, runId, state, step, held, noProgress) {
1857
+ const heldStep = state.steps.find((s) => s.id === held.stepId);
1858
+ const heldStepName = heldStep && (0, state_machine_1.stepLabel)(heldStep);
1813
1859
  emit(root, runId, state, step, 'held', {
1814
1860
  next: reconcileCommand(root, runId),
1815
- instructionLines: [(0, broker_1.treeBusyMessage)(held)],
1861
+ instructionLines: [
1862
+ (0, broker_1.treeBusyMessage)(held, heldStepName),
1863
+ // Quitting this session frees the terminal only for its own parent.
1864
+ ...(held.owner === process.env[broker_1.BROKER_ENV_VAR]
1865
+ ? [
1866
+ `If it seems stuck, the user can ${(0, broker_1.sessionOperationWayOut)((0, broker_1.treeOperationLabel)(held, heldStepName))}.`,
1867
+ ]
1868
+ : []),
1869
+ ],
1816
1870
  }, noProgress);
1817
1871
  }
1818
1872
  function emitStillRunning(root, runId, state, step, held, noProgress) {
@@ -1830,7 +1884,7 @@ function emitStillRunning(root, runId, state, step, held, noProgress) {
1830
1884
  if (ageMs >= HANG_THRESHOLD_MS) {
1831
1885
  const hung = `It has been running for ${Math.floor(ageMs / 60000)} minutes and may be hung.`;
1832
1886
  lines.push(parentOperation
1833
- ? `${hung} Report this to the user: they can quit this session, then press Ctrl+C in the terminal to end ${parentOperation}, and resume the run afterwards.`
1887
+ ? `${hung} Report this to the user: they can ${(0, broker_1.sessionOperationWayOut)(parentOperation)}.`
1834
1888
  : `${hung} Verify pid ${step.pid}; either keep waiting, or kill it so the next reconcile can classify it as died.`);
1835
1889
  }
1836
1890
  emit(root, runId, state, step, 'still-running', {
@@ -2074,14 +2128,19 @@ function completionWarnings(root, runId, state) {
2074
2128
  // fact absorbed; suppress the warning only on a verified-clean tree. A dirty
2075
2129
  // tree can still be unrelated edits, so the warning only claims the changes
2076
2130
  // "may remain".
2077
- const commitDebt = (0, state_machine_1.hasPendingCommitDebt)(state) && (0, git_utils_1.getWorkingTreeStatus)(root) !== 'clean';
2131
+ const debtStepIds = (0, state_machine_1.uncoveredFailedStepIds)(state);
2132
+ const uncommitted = debtStepIds.length > 0 && (0, git_utils_1.getWorkingTreeStatus)(root) !== 'clean'
2133
+ ? state.steps.filter((s) => debtStepIds.includes(s.id))
2134
+ : [];
2078
2135
  const uninstalled = state.steps.filter((s) => s.installFailed);
2079
2136
  const issueLines = (0, issues_1.renderUnresolvedIssueLines)(state, runId);
2080
2137
  return [
2081
- ...(commitDebt
2138
+ ...(uncommitted.length > 0
2082
2139
  ? [
2083
2140
  [
2084
- 'Some migration changes could not be committed and may remain in the working tree; review and commit them manually.',
2141
+ `The changes made by ${uncommitted
2142
+ .map(state_machine_1.stepLabel)
2143
+ .join(', ')} could not be committed and may remain in the working tree; review and commit them manually.`,
2085
2144
  ],
2086
2145
  ]
2087
2146
  : []),
@@ -76,6 +76,25 @@ function renderRunbook(ctx) {
76
76
  `already active. Show its report to the user and let them choose between`,
77
77
  `the two commands it lists; do not choose for them.`,
78
78
  ``,
79
+ `## Long-running commands`,
80
+ ``,
81
+ `A worker or \`next\` command can wait for minutes on a dependency install`,
82
+ `or a commit. When Nx started this session, the nx process that started it`,
83
+ `runs them, and the waiting command prints an \`[nx]\` line after 15`,
84
+ `seconds and then once a minute: what nx is running and for how long.`,
85
+ ``,
86
+ `- If your shell tool can run a command in the background, start worker and`,
87
+ ` \`next\` commands that way and check their output about once a minute.`,
88
+ ` Each time, tell the user in one sentence what the latest \`[nx]\` line`,
89
+ ` says.`,
90
+ `- Claude Code: start each worker and \`next\` command with`,
91
+ ` \`run_in_background\`, then start a Monitor on its output that passes`,
92
+ ` \`[nx]\` lines through. A \`next\` command can wait as long as a worker.`,
93
+ `- Stopping a worker or \`next\` command does not stop the install or the`,
94
+ ` commit it waits on. If one seems stuck, tell the user they can quit this`,
95
+ ` session, then press Ctrl+C in the terminal to end it, and resume the run`,
96
+ ` afterwards.`,
97
+ ``,
79
98
  `## Agent work`,
80
99
  ``,
81
100
  `Some steps hand work back to you:`,
@@ -231,7 +231,10 @@ function applyStepAction(state, index, step, action) {
231
231
  };
232
232
  }
233
233
  function workerDiedSummary(step) {
234
- return `the worker process${step.pid === undefined ? '' : ` (pid ${step.pid})`} died before recording an outcome`;
234
+ const worker = `the worker process${step.pid === undefined ? '' : ` (pid ${step.pid})`}`;
235
+ return step.installFailed === true
236
+ ? `its dependency install did not complete, and ${worker} died`
237
+ : `${worker} died before recording an outcome`;
235
238
  }
236
239
  // Re-arms for a retry that resets the tree first. The reset target predates
237
240
  // the generator unless a commit of this step's own already carries it, so the
@@ -28,6 +28,9 @@ export declare function depsHash(root: string): string | null;
28
28
  * dispense-time probe failed has no baseline, which says the dependencies it
29
29
  * started from are unknown rather than unchanged, and skipping there would
30
30
  * strand the change with nothing left to detect it.
31
+ *
32
+ * A failed or died step whose install already failed settles without it, so
33
+ * the settle cannot hang on that install again. A retry's rearm drops the mark.
31
34
  */
32
35
  export declare function installDepsChangedSinceDispense(root: string, dir: string, step: MigrateStep, skipInstall: boolean, rerunCommand?: string, sink?: MigrateOutputSink): Promise<void>;
33
36
  /**
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // Internal to run/: deliberately not re-exported from ./index.
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.nowIso = nowIso;
5
4
  exports.depsHash = depsHash;
@@ -51,8 +50,15 @@ function depsHash(root) {
51
50
  * dispense-time probe failed has no baseline, which says the dependencies it
52
51
  * started from are unknown rather than unchanged, and skipping there would
53
52
  * strand the change with nothing left to detect it.
53
+ *
54
+ * A failed or died step whose install already failed settles without it, so
55
+ * the settle cannot hang on that install again. A retry's rearm drops the mark.
54
56
  */
55
57
  async function installDepsChangedSinceDispense(root, dir, step, skipInstall, rerunCommand, sink) {
58
+ if (step.installFailed === true &&
59
+ (step.status === 'failed' || step.status === 'died')) {
60
+ return;
61
+ }
56
62
  const current = depsHash(root);
57
63
  if (current !== null && current === step.depsHashAtDispense)
58
64
  return;
@@ -155,23 +155,28 @@ async function runConnectToNxCloud(options, command) {
155
155
  installationSource: command ?? installationSource,
156
156
  });
157
157
  const connectCloudUrl = await (0, url_shorten_1.createNxCloudOnboardingURL)('nx-connect', token, undefined, options?.generateToken === true);
158
+ const manualConnectNote = {
159
+ title: `Your Nx Cloud workspace is ready.`,
160
+ bodyLines: [
161
+ `To claim it, connect it to your Nx Cloud account:`,
162
+ `- Go to the following URL to connect your workspace to Nx Cloud:`,
163
+ '',
164
+ `${connectCloudUrl}`,
165
+ ],
166
+ };
158
167
  try {
159
168
  const cloudConnectSpinner = ora(`Opening Nx Cloud ${connectCloudUrl} in your browser to connect your workspace.`).start();
160
169
  await sleep(2000);
161
- const { default: open } = await new Function('return import("open")')();
162
- await open(connectCloudUrl);
163
- cloudConnectSpinner.succeed();
170
+ if ((0, native_1.openUrl)(connectCloudUrl)) {
171
+ cloudConnectSpinner.succeed();
172
+ }
173
+ else {
174
+ cloudConnectSpinner.fail();
175
+ output_1.output.note(manualConnectNote);
176
+ }
164
177
  }
165
178
  catch (e) {
166
- output_1.output.note({
167
- title: `Your Nx Cloud workspace is ready.`,
168
- bodyLines: [
169
- `To claim it, connect it to your Nx Cloud account:`,
170
- `- Go to the following URL to connect your workspace to Nx Cloud:`,
171
- '',
172
- `${connectCloudUrl}`,
173
- ],
174
- });
179
+ output_1.output.note(manualConnectNote);
175
180
  }
176
181
  return true;
177
182
  }
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const pc = tslib_1.__importStar(require("picocolors"));
6
6
  const prompt_helpers_1 = require("../../../../utils/prompt-helpers");
7
7
  const node_child_process_1 = require("node:child_process");
8
+ const native_1 = require("../../../../native");
8
9
  const node_fs_1 = require("node:fs");
9
10
  const node_os_1 = require("node:os");
10
11
  const output_1 = require("../../../../utils/output");
@@ -238,18 +239,16 @@ class GithubRemoteReleaseClient extends remote_release_client_1.RemoteReleaseCli
238
239
  if (!shouldContinueInGitHub) {
239
240
  return;
240
241
  }
241
- const { default: open } = await new Function('return import("open")')();
242
- await open(result.url)
243
- .then(() => {
242
+ if ((0, native_1.openUrl)(result.url)) {
244
243
  console.info(`\nFollow up in the browser to manually create the release:\n\n` +
245
244
  pc.underline(pc.cyan(result.url)) +
246
245
  `\n`);
247
- })
248
- .catch(() => {
246
+ }
247
+ else {
249
248
  console.info(`Open this link to manually create a release: \n` +
250
249
  pc.underline(pc.cyan(result.url)) +
251
250
  '\n');
252
- });
251
+ }
253
252
  }
254
253
  async promptForContinueInGitHub() {
255
254
  try {
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const pc = tslib_1.__importStar(require("picocolors"));
6
6
  const prompt_helpers_1 = require("../../../../utils/prompt-helpers");
7
7
  const node_child_process_1 = require("node:child_process");
8
+ const native_1 = require("../../../../native");
8
9
  const output_1 = require("../../../../utils/output");
9
10
  const extract_repo_slug_1 = require("./extract-repo-slug");
10
11
  const remote_release_client_1 = require("./remote-release-client");
@@ -157,18 +158,16 @@ class GitLabRemoteReleaseClient extends remote_release_client_1.RemoteReleaseCli
157
158
  if (!shouldContinueInGitLab) {
158
159
  return;
159
160
  }
160
- const { default: open } = await new Function('return import("open")')();
161
- await open(result.url)
162
- .then(() => {
161
+ if ((0, native_1.openUrl)(result.url)) {
163
162
  console.info(`\nFollow up in the browser to manually create the release:\n\n` +
164
163
  pc.underline(pc.cyan(result.url)) +
165
164
  `\n`);
166
- })
167
- .catch(() => {
165
+ }
166
+ else {
168
167
  console.info(`Open this link to manually create a release: \n` +
169
168
  pc.underline(pc.cyan(result.url)) +
170
169
  '\n');
171
- });
170
+ }
172
171
  }
173
172
  async promptForContinueInGitLab() {
174
173
  try {