@mnci/cli 4.44.0 → 4.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8485,6 +8485,369 @@ function runDoctor(workspaceRoot, options = {}) {
8485
8485
  process.exitCode = 1;
8486
8486
  }
8487
8487
 
8488
+ // src/repository-adoption/adopt-overlay.use-case.ts
8489
+ var import_node_fs32 = require("fs");
8490
+ var import_node_path37 = require("path");
8491
+
8492
+ // src/workspace-upgrade/upgrade-workspace.use-case.ts
8493
+ var import_node_fs31 = require("fs");
8494
+ var import_node_path36 = require("path");
8495
+ function resolveRegistry(options, persisted) {
8496
+ if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
8497
+ const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
8498
+ const organization = options.organization ?? persistedAzure?.organization;
8499
+ const project = options.project ?? persistedAzure?.project;
8500
+ const artifactsFeed = options.artifactsFeed ?? persistedAzure?.artifactsFeed;
8501
+ if (!organization || !project || !artifactsFeed) {
8502
+ throw new Error(
8503
+ "Azure Artifacts registry needs --organization, --project and --artifacts-feed (none found in nx.json's persisted config either)."
8504
+ );
8505
+ }
8506
+ return { kind: "azure-artifacts", organization, project, artifactsFeed };
8507
+ }
8508
+ if (options.registry === "npm") {
8509
+ return { kind: "npm" };
8510
+ }
8511
+ if (persisted) {
8512
+ return persisted;
8513
+ }
8514
+ throw new Error(
8515
+ "No registry found in nx.json's persisted config. Pass --registry npm or --registry azure-artifacts (with --organization/--project/--artifacts-feed)."
8516
+ );
8517
+ }
8518
+ function resolveWorkspaceName(workspaceRoot, persisted) {
8519
+ if (persisted.workspaceName) {
8520
+ return persisted.workspaceName;
8521
+ }
8522
+ try {
8523
+ const existing = (0, import_node_fs31.readdirSync)(workspaceRoot).find(
8524
+ (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
8525
+ );
8526
+ if (existing) {
8527
+ return existing.replace(/\.code-workspace$/, "");
8528
+ }
8529
+ } catch {
8530
+ }
8531
+ return (0, import_node_path36.basename)(workspaceRoot);
8532
+ }
8533
+ function detectNpmAuth(workspaceRoot) {
8534
+ try {
8535
+ return (0, import_node_fs31.readFileSync)((0, import_node_path36.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
8536
+ } catch {
8537
+ return void 0;
8538
+ }
8539
+ }
8540
+ function resolveOverlayOptions(workspaceRoot, options, persisted) {
8541
+ const scope = options.scope ?? persisted.scope;
8542
+ if (!scope) {
8543
+ throw new Error("No npm scope found in nx.json's persisted config. Pass --scope explicitly.");
8544
+ }
8545
+ const registry = resolveRegistry(options, persisted.registry);
8546
+ const ci = options.ci ?? persisted.ci;
8547
+ if (!ci) {
8548
+ throw new Error(
8549
+ "No CI provider found in nx.json's persisted config. Pass --ci azure|github|both explicitly."
8550
+ );
8551
+ }
8552
+ const agent = options.agent ?? persisted.agent;
8553
+ if (!agent) {
8554
+ throw new Error(
8555
+ "No CI build agent found in nx.json's persisted config. Pass --agent explicitly."
8556
+ );
8557
+ }
8558
+ const variableGroup = options.variableGroup ?? persisted.variableGroup ?? "Build";
8559
+ const detected = ci === "azure" && persisted.npmAuth === void 0 && options.npmAuth === void 0 ? detectNpmAuth(workspaceRoot) : void 0;
8560
+ if (detected) {
8561
+ logger.detail("keeping build-identity npm auth: azure-pipelines.yml already runs npmAuthenticate@0");
8562
+ }
8563
+ const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci, persisted.npmAuth ?? detected);
8564
+ const testRunner = options.testRunner ?? persisted.stack?.testRunner;
8565
+ if (!testRunner) {
8566
+ throw new Error(
8567
+ "No testRunner found in nx.json's persisted config. Pass --test-runner explicitly."
8568
+ );
8569
+ }
8570
+ return {
8571
+ workspaceName: resolveWorkspaceName(workspaceRoot, persisted),
8572
+ scope,
8573
+ registry,
8574
+ agent,
8575
+ variableGroup,
8576
+ ci,
8577
+ stack: { testRunner },
8578
+ ...npmAuth && { npmAuth }
8579
+ };
8580
+ }
8581
+ function runUpgrade(workspaceRoot, options) {
8582
+ if (!fileExists((0, import_node_path36.join)(workspaceRoot, "nx.json"))) {
8583
+ throw new Error(
8584
+ `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
8585
+ );
8586
+ }
8587
+ const persisted = readMnciConfig(workspaceRoot);
8588
+ const resolved = resolveOverlayOptions(workspaceRoot, options, persisted);
8589
+ logger.step("Re-applying the MoNecromanCI overlay");
8590
+ applyOverlay(workspaceRoot, resolved, logger.detail);
8591
+ const repaired = repairRollupSourceMaps(workspaceRoot);
8592
+ if (repaired.length > 0) {
8593
+ logger.step("Enabling source maps in rollup configs (breakpoints in .ts files)");
8594
+ for (const path of repaired) {
8595
+ logger.detail(`updated ${path}`);
8596
+ }
8597
+ }
8598
+ const repairedManifests = repairPublishableManifests(workspaceRoot);
8599
+ if (repairedManifests.length > 0) {
8600
+ logger.step("Repointing `types` at the real declaration file");
8601
+ for (const path of repairedManifests) {
8602
+ logger.detail(`updated ${path}`);
8603
+ }
8604
+ }
8605
+ const lockfile = pruneStaleLocalRegistry(workspaceRoot);
8606
+ if (lockfile.stale) {
8607
+ logger.step("Dropping the unused local registry (verdaccio) from package-lock.json");
8608
+ if (lockfile.status !== 0) {
8609
+ logger.warn("npm could not re-resolve the lockfile; run `npm install --package-lock-only` once you are online.");
8610
+ }
8611
+ }
8612
+ const goApps = addGoPlatformTargets(workspaceRoot);
8613
+ if (goApps.length > 0) {
8614
+ logger.step("Adding the six-platform build to Go apps (build-all, package-all)");
8615
+ for (const path of goApps) {
8616
+ logger.detail(`updated ${path}`);
8617
+ }
8618
+ }
8619
+ const pinnedExtensions = pinVscodeExtensionProjectNames(workspaceRoot);
8620
+ if (pinnedExtensions.length > 0) {
8621
+ logger.step("Pinning the Nx project name of VS Code extensions (nx.name)");
8622
+ for (const path of pinnedExtensions) {
8623
+ logger.detail(`updated ${path}`);
8624
+ }
8625
+ }
8626
+ if (refreshVscodeExtensionScript(workspaceRoot)) {
8627
+ logger.step("Updating the VS Code extension packaging script");
8628
+ logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
8629
+ }
8630
+ if (refreshGoReleaseScript(workspaceRoot)) {
8631
+ logger.step("Updating the releasable Go app script");
8632
+ logger.detail(`updated ${GO_RELEASE_SCRIPT_PATH}`);
8633
+ }
8634
+ if (hasGoProject(workspaceRoot) && registerNxGoPlugin(workspaceRoot)) {
8635
+ logger.step("Registering the Go plugin in nx.json, so Nx can see which Go project imports which");
8636
+ logger.detail("updated nx.json");
8637
+ }
8638
+ const addedDtsPlugins = addMissingDeclarationSpecifierPlugins(workspaceRoot);
8639
+ if (addedDtsPlugins.length > 0) {
8640
+ logger.step("Adding the declaration-specifier plugin to rollup configs that lacked it");
8641
+ for (const path of addedDtsPlugins) {
8642
+ logger.detail(`updated ${path}`);
8643
+ }
8644
+ }
8645
+ const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
8646
+ if (upgradedDtsPlugins.length > 0) {
8647
+ logger.step("Upgrading declaration specifiers to resolve under nodenext");
8648
+ for (const path of upgradedDtsPlugins) {
8649
+ logger.detail(`updated ${path}`);
8650
+ }
8651
+ }
8652
+ logger.step(
8653
+ "Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
8654
+ );
8655
+ runFormatter(workspaceRoot);
8656
+ const nxJson = readJson((0, import_node_path36.join)(workspaceRoot, "nx.json"));
8657
+ const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
8658
+ for (const entry of stranded) {
8659
+ logger.warn(`${entry.project} has release tags only under ${entry.oldTag}: nx release would restart it from its disk version. Run \`git tag ${entry.newTag} ${entry.oldTag}^{commit}\` before the next release (\`mnci doctor\` lists them all).`);
8660
+ }
8661
+ logger.success("Done. Review the changes with `git diff` before committing.");
8662
+ logger.info("Run `npm install` and commit package-lock.json too: the overlay may have added or moved a dependency, and CI installs with `npm ci`, which refuses a stale lockfile.");
8663
+ }
8664
+
8665
+ // src/repository-adoption/clean-working-tree.validator.ts
8666
+ function requireCleanWorkingTree(repositoryRoot, capture = runCapture) {
8667
+ if (capture("git", ["rev-parse", "--is-inside-work-tree"], repositoryRoot).status !== 0) {
8668
+ throw new Error("This directory is not a git repository. Every adoption step is one diff to review, so it needs git.");
8669
+ }
8670
+ if (capture("git", ["status", "--porcelain"], repositoryRoot).stdout.trim() !== "") {
8671
+ throw new Error("The working tree has uncommitted changes. Commit or stash them, so this step is one diff you can review or discard.");
8672
+ }
8673
+ }
8674
+
8675
+ // src/repository-adoption/adopt-overlay.use-case.ts
8676
+ function detectCiProvider(repositoryRoot) {
8677
+ const azure = (0, import_node_fs32.existsSync)((0, import_node_path37.join)(repositoryRoot, "azure-pipelines.yml"));
8678
+ const workflows = (0, import_node_path37.join)(repositoryRoot, ".github", "workflows");
8679
+ const github = (0, import_node_fs32.existsSync)(workflows) && (0, import_node_fs32.readdirSync)(workflows).some((file) => /\.ya?ml$/.test(file));
8680
+ if (azure && github) {
8681
+ return "both";
8682
+ }
8683
+ if (azure) {
8684
+ return "azure";
8685
+ }
8686
+ return github ? "github" : void 0;
8687
+ }
8688
+ function detectTestRunner(repositoryRoot) {
8689
+ const manifestPath = (0, import_node_path37.join)(repositoryRoot, "package.json");
8690
+ if (!fileExists(manifestPath)) {
8691
+ return void 0;
8692
+ }
8693
+ const manifest = readJson(manifestPath);
8694
+ const declared = new Set(Object.keys({ ...manifest.dependencies, ...manifest.devDependencies }));
8695
+ if (declared.has("vitest")) {
8696
+ return "vitest";
8697
+ }
8698
+ return declared.has("jest") ? "jest" : void 0;
8699
+ }
8700
+ function adoptOverlay(repositoryRoot, options, dependencies = {}) {
8701
+ requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
8702
+ if (!fileExists((0, import_node_path37.join)(repositoryRoot, "nx.json"))) {
8703
+ throw new Error("There is no nx.json, so Nx is not set up here. Set it up first (`npx nx@latest init`); adopt does not install Nx yet.");
8704
+ }
8705
+ const persisted = readMnciConfig(repositoryRoot);
8706
+ const filled = {
8707
+ ...options,
8708
+ ci: options.ci ?? (persisted.ci === void 0 ? detectCiProvider(repositoryRoot) : void 0),
8709
+ testRunner: options.testRunner ?? (persisted.stack?.testRunner === void 0 ? detectTestRunner(repositoryRoot) : void 0)
8710
+ };
8711
+ (dependencies.upgrade ?? runUpgrade)(repositoryRoot, filled);
8712
+ }
8713
+
8714
+ // src/repository-adoption/adopt-toolchain.use-case.ts
8715
+ var import_node_path39 = require("path");
8716
+
8717
+ // src/repository-adoption/align-nx-family.algorithm.ts
8718
+ var VERSION = /^[\^~]?(\d+)\.(\d+)\.(\d+)$/;
8719
+ function isNxFamily(name) {
8720
+ return name === "nx" || name.startsWith("@nx/");
8721
+ }
8722
+ function compare(left, right) {
8723
+ const a = left.split(".").map(Number);
8724
+ const b = right.split(".").map(Number);
8725
+ return a[0] - b[0] || a[1] - b[1] || a[2] - b[2] || 0;
8726
+ }
8727
+ function chooseNxVersion(declared, published, requested) {
8728
+ const current = Object.entries(declared).filter(([name]) => isNxFamily(name)).map(([, range]) => VERSION.exec(range)).filter((match) => match !== null).map((match) => `${match[1]}.${match[2]}.${match[3]}`);
8729
+ if (current.length === 0) {
8730
+ return void 0;
8731
+ }
8732
+ if (requested !== void 0) {
8733
+ return requested;
8734
+ }
8735
+ const newest = current.toSorted((a, b) => compare(a, b)).at(-1);
8736
+ const major = newest.split(".", 1)[0];
8737
+ const candidates = published.filter((version) => /^\d+\.\d+\.\d+$/.test(version) && version.split(".", 1)[0] === major);
8738
+ return candidates.toSorted((a, b) => compare(a, b)).at(-1);
8739
+ }
8740
+ function alignNxFamily(dependencies, version) {
8741
+ const changed = [];
8742
+ const aligned = Object.fromEntries(Object.entries(dependencies).map(([name, range]) => {
8743
+ if (range !== version && isNxFamily(name)) {
8744
+ changed.push(name);
8745
+ return [name, version];
8746
+ }
8747
+ return [name, range];
8748
+ }));
8749
+ return { dependencies: aligned, changed };
8750
+ }
8751
+
8752
+ // src/repository-adoption/retire-tooling.use-case.ts
8753
+ var import_node_fs33 = require("fs");
8754
+ var import_node_path38 = require("path");
8755
+ var RETIRED_COMMAND = /\b(?:prettier|oxfmt|oxlint)\b/;
8756
+ function retireTooling(repositoryRoot) {
8757
+ const removed = [];
8758
+ for (const file of RETIRED_FORMATTER_FILES) {
8759
+ if (!fileExists((0, import_node_path38.join)(repositoryRoot, file))) {
8760
+ continue;
8761
+ }
8762
+ (0, import_node_fs33.rmSync)((0, import_node_path38.join)(repositoryRoot, file), { force: true });
8763
+ removed.push(file);
8764
+ }
8765
+ const hadRegistry = fileExists((0, import_node_path38.join)(repositoryRoot, ".verdaccio"));
8766
+ removeLocalRegistryScaffolding(repositoryRoot);
8767
+ if (hadRegistry) {
8768
+ removed.push(".verdaccio, its dependency and the local-registry target");
8769
+ }
8770
+ const manifestPath = (0, import_node_path38.join)(repositoryRoot, "package.json");
8771
+ if (!fileExists(manifestPath)) {
8772
+ return removed;
8773
+ }
8774
+ const manifest = readJson(manifestPath);
8775
+ for (const key of ["dependencies", "devDependencies"]) {
8776
+ const before = manifest[key];
8777
+ if (before === void 0) {
8778
+ continue;
8779
+ }
8780
+ const after = withoutRetiredFormatterDependencies(before);
8781
+ const kept = new Set(Object.keys(after));
8782
+ const dropped = Object.keys(before).filter((name) => !kept.has(name));
8783
+ removed.push(...dropped.map((name) => `${key}: ${name}`));
8784
+ manifest[key] = after;
8785
+ }
8786
+ const scripts = Object.entries(manifest.scripts ?? {});
8787
+ for (const [name, command] of scripts) {
8788
+ if (!RETIRED_COMMAND.test(command)) {
8789
+ continue;
8790
+ }
8791
+ Reflect.deleteProperty(manifest.scripts, name);
8792
+ removed.push(`script: ${name} (${command})`);
8793
+ }
8794
+ writeFileEnsured(manifestPath, toJson(manifest));
8795
+ return removed;
8796
+ }
8797
+
8798
+ // src/repository-adoption/adopt-toolchain.use-case.ts
8799
+ var MAX_AUDIT_FIX_PASSES = 4;
8800
+ function publishedNxVersions(repositoryRoot, capture) {
8801
+ const answer = capture("npm", ["view", "nx", "versions", "--json"], repositoryRoot);
8802
+ try {
8803
+ const parsed = JSON.parse(answer.stdout);
8804
+ return Array.isArray(parsed) ? parsed.filter((version) => typeof version === "string") : [];
8805
+ } catch {
8806
+ return [];
8807
+ }
8808
+ }
8809
+ function adoptToolchain(repositoryRoot, options = {}, dependencies = {}) {
8810
+ const run = dependencies.run ?? runShell;
8811
+ const capture = dependencies.capture ?? runCapture;
8812
+ const audit = dependencies.audit ?? ((root) => runAudit(root));
8813
+ const log = dependencies.log ?? ((message) => {
8814
+ console.log(message);
8815
+ });
8816
+ requireCleanWorkingTree(repositoryRoot, capture);
8817
+ const manifestPath = (0, import_node_path39.join)(repositoryRoot, "package.json");
8818
+ if (!fileExists(manifestPath)) {
8819
+ throw new Error("No package.json at the repository root.");
8820
+ }
8821
+ log("Removing retired tooling");
8822
+ const removed = retireTooling(repositoryRoot);
8823
+ const manifest = readJson(manifestPath);
8824
+ const version = chooseNxVersion({ ...manifest.dependencies, ...manifest.devDependencies }, publishedNxVersions(repositoryRoot, capture), options.nxVersion);
8825
+ const names = [];
8826
+ if (version !== void 0) {
8827
+ for (const key of ["dependencies", "devDependencies"]) {
8828
+ if (manifest[key] === void 0) {
8829
+ continue;
8830
+ }
8831
+ const result = alignNxFamily(manifest[key], version);
8832
+ manifest[key] = result.dependencies;
8833
+ names.push(...result.changed);
8834
+ }
8835
+ writeFileEnsured(manifestPath, toJson(manifest));
8836
+ }
8837
+ log("Installing, so the lockfile follows the manifest");
8838
+ run("npm", ["install", "--ignore-scripts", "--no-audit", "--no-fund"], repositoryRoot);
8839
+ pruneStaleLocalRegistry(repositoryRoot);
8840
+ let auditFixes = 0;
8841
+ let passes = audit(repositoryRoot) === 0;
8842
+ while (!passes && auditFixes < MAX_AUDIT_FIX_PASSES) {
8843
+ auditFixes += 1;
8844
+ log(`npm audit fix, pass ${auditFixes}`);
8845
+ run("npm", ["audit", "fix", "--no-fund"], repositoryRoot);
8846
+ passes = audit(repositoryRoot) === 0;
8847
+ }
8848
+ return { removed, aligned: { names, version }, auditFixes, auditPasses: passes };
8849
+ }
8850
+
8488
8851
  // src/repository-adoption/create-baseline-tags.use-case.ts
8489
8852
  function createBaselineTags(repositoryRoot, stranded) {
8490
8853
  const result = { created: [], existing: [], failed: [] };
@@ -8501,8 +8864,8 @@ function createBaselineTags(repositoryRoot, stranded) {
8501
8864
  }
8502
8865
 
8503
8866
  // src/repository-adoption/inspect-repository.use-case.ts
8504
- var import_node_fs31 = require("fs");
8505
- var import_node_path36 = require("path");
8867
+ var import_node_fs34 = require("fs");
8868
+ var import_node_path40 = require("path");
8506
8869
  var LOCKFILES = [
8507
8870
  ["package-lock.json", "npm"],
8508
8871
  ["pnpm-lock.yaml", "pnpm"],
@@ -8523,25 +8886,25 @@ function inspectRepository(repositoryRoot) {
8523
8886
  const isGitRepo = inside.status === 0 && inside.stdout.trim() === "true";
8524
8887
  const dirty = isGitRepo && runCapture("git", ["status", "--porcelain"], repositoryRoot).stdout.trim() !== "";
8525
8888
  const tags = isGitRepo ? runCapture("git", ["tag", "--list"], repositoryRoot).stdout.split(/\r?\n/).filter(Boolean) : [];
8526
- const manifestPath = (0, import_node_path36.join)(repositoryRoot, "package.json");
8889
+ const manifestPath = (0, import_node_path40.join)(repositoryRoot, "package.json");
8527
8890
  const manifest = fileExists(manifestPath) ? readJson(manifestPath) : {};
8528
- const nxJsonPath = (0, import_node_path36.join)(repositoryRoot, "nx.json");
8891
+ const nxJsonPath = (0, import_node_path40.join)(repositoryRoot, "nx.json");
8529
8892
  const nxJson = fileExists(nxJsonPath) ? readJson(nxJsonPath) : {};
8530
8893
  const ci = [];
8531
8894
  const pipelines = [];
8532
- if ((0, import_node_fs31.existsSync)((0, import_node_path36.join)(repositoryRoot, "azure-pipelines.yml"))) {
8895
+ if ((0, import_node_fs34.existsSync)((0, import_node_path40.join)(repositoryRoot, "azure-pipelines.yml"))) {
8533
8896
  ci.push("azure");
8534
- pipelines.push((0, import_node_path36.join)(repositoryRoot, "azure-pipelines.yml"));
8897
+ pipelines.push((0, import_node_path40.join)(repositoryRoot, "azure-pipelines.yml"));
8535
8898
  }
8536
- const workflows = (0, import_node_path36.join)(repositoryRoot, ".github", "workflows");
8537
- if ((0, import_node_fs31.existsSync)(workflows)) {
8538
- const files = (0, import_node_fs31.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
8899
+ const workflows = (0, import_node_path40.join)(repositoryRoot, ".github", "workflows");
8900
+ if ((0, import_node_fs34.existsSync)(workflows)) {
8901
+ const files = (0, import_node_fs34.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
8539
8902
  if (files.length > 0) {
8540
8903
  ci.push("github");
8541
- pipelines.push(...files.map((file) => (0, import_node_path36.join)(workflows, file)));
8904
+ pipelines.push(...files.map((file) => (0, import_node_path40.join)(workflows, file)));
8542
8905
  }
8543
8906
  }
8544
- const rootFiles = (0, import_node_fs31.readdirSync)(repositoryRoot);
8907
+ const rootFiles = (0, import_node_fs34.readdirSync)(repositoryRoot);
8545
8908
  return {
8546
8909
  isGitRepo,
8547
8910
  dirty,
@@ -8552,7 +8915,7 @@ function inspectRepository(repositoryRoot) {
8552
8915
  tagCount: tags.length,
8553
8916
  strandedTags: isGitRepo ? locateStrandedReleaseTags(repositoryRoot, nxJson.release?.releaseTag?.pattern) : [],
8554
8917
  ci,
8555
- pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs31.readFileSync)(file, "utf8"))),
8918
+ pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs34.readFileSync)(file, "utf8"))),
8556
8919
  retiredTooling: [.../* @__PURE__ */ new Set([...rootFiles.filter((file) => RETIRED_FILE_PATTERN.test(file) || file === ".verdaccio"), ...retiredNamesIn(manifest)])],
8557
8920
  personalFiles: PERSONAL_FILES.filter((file) => rootFiles.includes(file))
8558
8921
  };
@@ -8582,7 +8945,7 @@ function judgeAdoption(facts) {
8582
8945
  warning("nx.json already carries an mnci block, so this is an mnci workspace", "use `mnci upgrade`; adopt is for repositories mnci has not touched");
8583
8946
  }
8584
8947
  if (facts.nxVersion === void 0) {
8585
- warning("Nx is not installed", "the toolchain step installs the Nx family at the version mnci supports (#380)");
8948
+ warning("Nx is not installed", "set Nx up first (`npx nx@latest init`); adopt does not install it yet, and the toolchain and overlay steps need an nx.json");
8586
8949
  }
8587
8950
  if (facts.strandedTags.length > 0) {
8588
8951
  warning(
@@ -8609,6 +8972,14 @@ function reportAdoption(repositoryRoot) {
8609
8972
  }
8610
8973
  function runAdopt(repositoryRoot, options = {}) {
8611
8974
  const report = reportAdoption(repositoryRoot);
8975
+ if (options.overlay === true) {
8976
+ runOverlay(repositoryRoot, options);
8977
+ return;
8978
+ }
8979
+ if (options.toolchain === true) {
8980
+ runToolchain(repositoryRoot, options);
8981
+ return;
8982
+ }
8612
8983
  if (options.tags === true) {
8613
8984
  runBaselineTags(repositoryRoot, report);
8614
8985
  return;
@@ -8666,6 +9037,40 @@ function runBaselineTags(repositoryRoot, report) {
8666
9037
  logger.info("A tag made under the new name at a LOWER version (for example @scope/x@0.0.5) stays; the baseline outranks it, and removing it from the remote is your call.");
8667
9038
  }
8668
9039
  }
9040
+ function runToolchain(repositoryRoot, options) {
9041
+ try {
9042
+ const result = adoptToolchain(repositoryRoot, { nxVersion: options.nx }, { log: (message) => {
9043
+ logger.step(message);
9044
+ } });
9045
+ for (const line of result.removed) {
9046
+ logger.info(`removed ${line}`);
9047
+ }
9048
+ if (result.aligned.version === void 0) {
9049
+ logger.info("Nx is not declared at the root, so there is no family to align.");
9050
+ } else {
9051
+ logger.info(`Nx family at ${result.aligned.version}${result.aligned.names.length > 0 ? ` (moved: ${result.aligned.names.join(", ")})` : " (already aligned)"}`);
9052
+ }
9053
+ if (result.auditPasses) {
9054
+ logger.success(`The audit gate passes${result.auditFixes > 0 ? ` after ${result.auditFixes} npm audit fix pass(es)` : ""}. Review with \`git diff\` and commit package.json and package-lock.json.`);
9055
+ } else {
9056
+ logger.error("The audit gate still fails after npm audit fix. Run `mnci ci audit` to see what is left; a targeted overrides entry is the usual answer.");
9057
+ process.exitCode = 1;
9058
+ }
9059
+ } catch (error) {
9060
+ logger.error(error instanceof Error ? error.message : String(error));
9061
+ process.exitCode = 1;
9062
+ }
9063
+ }
9064
+ function runOverlay(repositoryRoot, options) {
9065
+ try {
9066
+ adoptOverlay(repositoryRoot, options);
9067
+ logger.info("Steps of your old pipeline that mnci does not recognise are in its slots (# mnci:slot); anything it could not carry over was listed above.");
9068
+ logger.info("Run `mnci doctor` to confirm the verify phase is active, then review with `git diff`.");
9069
+ } catch (error) {
9070
+ logger.error(error instanceof Error ? error.message : String(error));
9071
+ process.exitCode = 1;
9072
+ }
9073
+ }
8669
9074
 
8670
9075
  // src/command-catalog/command-groups.config.ts
8671
9076
  var COMMAND_GROUPS = {
@@ -8738,11 +9143,11 @@ function runCommands(program, options) {
8738
9143
  }
8739
9144
 
8740
9145
  // src/workspace-info/list-projects.use-case.ts
8741
- var import_node_path37 = require("path");
9146
+ var import_node_path41 = require("path");
8742
9147
  var TYPE_TAG_PREFIX = "type:";
8743
9148
  function listProjects(workspaceRoot) {
8744
9149
  return locateProjects(workspaceRoot).map((location) => {
8745
- const projectJsonPath = (0, import_node_path37.join)(workspaceRoot, location.dir, "project.json");
9150
+ const projectJsonPath = (0, import_node_path41.join)(workspaceRoot, location.dir, "project.json");
8746
9151
  const project = fileExists(projectJsonPath) ? readJson(projectJsonPath) : {};
8747
9152
  const typeTag = (project.tags ?? []).find((tag) => tag.startsWith(TYPE_TAG_PREFIX));
8748
9153
  return {
@@ -8755,7 +9160,7 @@ function listProjects(workspaceRoot) {
8755
9160
  }).toSorted((a, b) => a.dir.localeCompare(b.dir));
8756
9161
  }
8757
9162
  function runProjects(workspaceRoot, options) {
8758
- if (!fileExists((0, import_node_path37.join)(workspaceRoot, "nx.json"))) {
9163
+ if (!fileExists((0, import_node_path41.join)(workspaceRoot, "nx.json"))) {
8759
9164
  throw new Error("No nx.json found here. Run `projects` from the workspace root.");
8760
9165
  }
8761
9166
  const projects = listProjects(workspaceRoot);
@@ -8769,11 +9174,11 @@ function runProjects(workspaceRoot, options) {
8769
9174
  }
8770
9175
 
8771
9176
  // src/workspace-info/read-workspace-info.use-case.ts
8772
- var import_node_path39 = require("path");
9177
+ var import_node_path43 = require("path");
8773
9178
 
8774
9179
  // src/cli-version/check-for-update.use-case.ts
8775
- var import_node_fs32 = require("fs");
8776
- var import_node_path38 = require("path");
9180
+ var import_node_fs35 = require("fs");
9181
+ var import_node_path42 = require("path");
8777
9182
  var import_cross_spawn3 = __toESM(require("cross-spawn"));
8778
9183
  var PACKAGE_NAME2 = "@mnci/cli";
8779
9184
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -8832,8 +9237,8 @@ function releaseTriple(version) {
8832
9237
  }
8833
9238
  function readCliVersion(packageDirectory) {
8834
9239
  try {
8835
- const manifestPath = (0, import_node_path38.join)(packageDirectory, "..", "package.json");
8836
- const manifest = JSON.parse((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
9240
+ const manifestPath = (0, import_node_path42.join)(packageDirectory, "..", "package.json");
9241
+ const manifest = JSON.parse((0, import_node_fs35.readFileSync)(manifestPath, "utf8"));
8837
9242
  return manifest.version ?? "0.0.0";
8838
9243
  } catch {
8839
9244
  return "0.0.0";
@@ -8843,7 +9248,7 @@ function readCliVersion(packageDirectory) {
8843
9248
  // src/workspace-info/read-workspace-info.use-case.ts
8844
9249
  function readWorkspaceInfo(workspaceRoot, cliVersion) {
8845
9250
  const latest = fetchLatestVersion() ?? null;
8846
- const isWorkspace = fileExists((0, import_node_path39.join)(workspaceRoot, "nx.json"));
9251
+ const isWorkspace = fileExists((0, import_node_path43.join)(workspaceRoot, "nx.json"));
8847
9252
  return {
8848
9253
  cli: {
8849
9254
  version: cliVersion,
@@ -8864,8 +9269,8 @@ function runInfo(workspaceRoot, cliVersion, options) {
8864
9269
  }
8865
9270
 
8866
9271
  // src/workspace-creation/adopt-directory.use-case.ts
8867
- var import_node_fs33 = require("fs");
8868
- var import_node_path40 = require("path");
9272
+ var import_node_fs36 = require("fs");
9273
+ var import_node_path44 = require("path");
8869
9274
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
8870
9275
  var AGENT_AND_CI_ENTRIES = [
8871
9276
  "AGENTS.md",
@@ -8896,13 +9301,13 @@ var PREFLIGHT_BLOCKERS = [
8896
9301
  "packages"
8897
9302
  ];
8898
9303
  function assertAdoptableDirectory(target) {
8899
- if (!(0, import_node_fs33.existsSync)(target)) {
9304
+ if (!(0, import_node_fs36.existsSync)(target)) {
8900
9305
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
8901
9306
  }
8902
- if (!(0, import_node_fs33.statSync)(target).isDirectory()) {
9307
+ if (!(0, import_node_fs36.statSync)(target).isDirectory()) {
8903
9308
  throw new Error(`--into '${target}' is not a directory.`);
8904
9309
  }
8905
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs33.existsSync)((0, import_node_path40.join)(target, entry)));
9310
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs36.existsSync)((0, import_node_path44.join)(target, entry)));
8906
9311
  if (blockers.length > 0) {
8907
9312
  throw new Error(
8908
9313
  `--into '${target}' already holds ${blockers.join(", ")}, so it is a project already. Use \`mnci upgrade\` to re-apply the overlay to an existing workspace, or point --into at an empty checkout.`
@@ -8910,15 +9315,15 @@ function assertAdoptableDirectory(target) {
8910
9315
  }
8911
9316
  }
8912
9317
  function mergeGitignore(generatedFile, targetFile) {
8913
- const existing = (0, import_node_fs33.readFileSync)(targetFile, "utf8");
9318
+ const existing = (0, import_node_fs36.readFileSync)(targetFile, "utf8");
8914
9319
  const present = new Set(existing.split("\n").map((line) => line.trim()));
8915
- const additions = (0, import_node_fs33.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
9320
+ const additions = (0, import_node_fs36.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
8916
9321
  const trimmed = line.trim();
8917
9322
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
8918
9323
  });
8919
9324
  if (additions.length === 0) return false;
8920
9325
  const separator = existing.endsWith("\n") ? "" : "\n";
8921
- (0, import_node_fs33.writeFileSync)(
9326
+ (0, import_node_fs36.writeFileSync)(
8922
9327
  targetFile,
8923
9328
  `${existing}${separator}
8924
9329
  # Added by mnci (Nx workspace)
@@ -8928,9 +9333,9 @@ ${additions.join("\n")}
8928
9333
  return true;
8929
9334
  }
8930
9335
  function adoptGeneratedWorkspace(generatedRoot, target) {
8931
- const entries = (0, import_node_fs33.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
9336
+ const entries = (0, import_node_fs36.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
8932
9337
  const collisions = entries.filter(
8933
- (entry) => (0, import_node_fs33.existsSync)((0, import_node_path40.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
9338
+ (entry) => (0, import_node_fs36.existsSync)((0, import_node_path44.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
8934
9339
  );
8935
9340
  if (collisions.length > 0) {
8936
9341
  throw new Error(
@@ -8939,28 +9344,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
8939
9344
  }
8940
9345
  const result = { copied: [], kept: [], mergedGitignore: false };
8941
9346
  for (const entry of entries) {
8942
- const from = (0, import_node_path40.join)(generatedRoot, entry);
8943
- const to = (0, import_node_path40.join)(target, entry);
8944
- if (entry === ".gitignore" && (0, import_node_fs33.existsSync)(to)) {
9347
+ const from = (0, import_node_path44.join)(generatedRoot, entry);
9348
+ const to = (0, import_node_path44.join)(target, entry);
9349
+ if (entry === ".gitignore" && (0, import_node_fs36.existsSync)(to)) {
8945
9350
  result.mergedGitignore = mergeGitignore(from, to);
8946
9351
  result.kept.push(entry);
8947
9352
  continue;
8948
9353
  }
8949
- if ((0, import_node_fs33.existsSync)(to)) {
9354
+ if ((0, import_node_fs36.existsSync)(to)) {
8950
9355
  result.kept.push(entry);
8951
9356
  continue;
8952
9357
  }
8953
- (0, import_node_fs33.cpSync)(from, to, { recursive: true });
9358
+ (0, import_node_fs36.cpSync)(from, to, { recursive: true });
8954
9359
  result.copied.push(entry);
8955
9360
  }
8956
- (0, import_node_fs33.rmSync)(generatedRoot, { recursive: true, force: true });
9361
+ (0, import_node_fs36.rmSync)(generatedRoot, { recursive: true, force: true });
8957
9362
  return result;
8958
9363
  }
8959
9364
 
8960
9365
  // src/workspace-creation/create-workspace.use-case.ts
8961
- var import_node_fs34 = require("fs");
9366
+ var import_node_fs37 = require("fs");
8962
9367
  var import_node_os2 = require("os");
8963
- var import_node_path41 = require("path");
9368
+ var import_node_path45 = require("path");
8964
9369
  function nxCloudProviderValue(ci) {
8965
9370
  return ci === "azure" ? "azure" : "github";
8966
9371
  }
@@ -8985,7 +9390,7 @@ async function resolveCi(options) {
8985
9390
  return await promptCi();
8986
9391
  }
8987
9392
  var REGISTRY_KINDS = /* @__PURE__ */ new Set(["azure-artifacts", "npm"]);
8988
- async function resolveRegistry(options) {
9393
+ async function resolveRegistry2(options) {
8989
9394
  if (options.registry !== void 0 && !REGISTRY_KINDS.has(options.registry)) {
8990
9395
  throw new Error(`Invalid --registry '${options.registry}'. Valid values: azure-artifacts, npm.`);
8991
9396
  }
@@ -9003,12 +9408,12 @@ async function resolveRegistry(options) {
9003
9408
  return await promptRegistry();
9004
9409
  }
9005
9410
  async function runNew(name, options) {
9006
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path41.resolve)(process.cwd(), options.into);
9411
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path45.resolve)(process.cwd(), options.into);
9007
9412
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
9008
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path41.basename)(adoptTarget));
9413
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path45.basename)(adoptTarget));
9009
9414
  assertValidProjectName(workspaceName, "Workspace name");
9010
9415
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
9011
- const registry = await resolveRegistry(options);
9416
+ const registry = await resolveRegistry2(options);
9012
9417
  const ci = await resolveCi(options);
9013
9418
  const agent = options.agent ?? (options.yes ? "ubuntu-latest" : await promptText(
9014
9419
  "CI build agent/runner (vmImage, GitHub Actions runner label, or self-hosted pool name)",
@@ -9018,8 +9423,8 @@ async function runNew(name, options) {
9018
9423
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
9019
9424
  const stack = await resolveStack(options);
9020
9425
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
9021
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs34.mkdtempSync)((0, import_node_path41.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
9022
- let workspaceRoot = (0, import_node_path41.join)(stagingParent, workspaceName);
9426
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs37.mkdtempSync)((0, import_node_path45.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
9427
+ let workspaceRoot = (0, import_node_path45.join)(stagingParent, workspaceName);
9023
9428
  try {
9024
9429
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
9025
9430
  runNpx(
@@ -9042,7 +9447,7 @@ async function runNew(name, options) {
9042
9447
  workspaceRoot = adoptTarget;
9043
9448
  }
9044
9449
  } finally {
9045
- if (adoptTarget !== void 0) (0, import_node_fs34.rmSync)(stagingParent, { recursive: true, force: true });
9450
+ if (adoptTarget !== void 0) (0, import_node_fs37.rmSync)(stagingParent, { recursive: true, force: true });
9046
9451
  }
9047
9452
  logger.step(
9048
9453
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -9052,8 +9457,8 @@ async function runNew(name, options) {
9052
9457
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
9053
9458
  logger.detail
9054
9459
  );
9055
- (0, import_node_fs34.rmSync)((0, import_node_path41.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
9056
- (0, import_node_fs34.rmSync)((0, import_node_path41.join)(workspaceRoot, "package-lock.json"), { force: true });
9460
+ (0, import_node_fs37.rmSync)((0, import_node_path45.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
9461
+ (0, import_node_fs37.rmSync)((0, import_node_path45.join)(workspaceRoot, "package-lock.json"), { force: true });
9057
9462
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
9058
9463
  const installStatus = runShell(
9059
9464
  "npm",
@@ -9091,185 +9496,10 @@ function projectKindHintLines(kinds = PROJECT_KINDS) {
9091
9496
  }
9092
9497
 
9093
9498
  // src/workspace-creation/interactive-wizard.use-case.ts
9094
- var import_node_path43 = require("path");
9499
+ var import_node_path46 = require("path");
9095
9500
  var import_prompts4 = require("@inquirer/prompts");
9096
-
9097
- // src/workspace-upgrade/upgrade-workspace.use-case.ts
9098
- var import_node_fs35 = require("fs");
9099
- var import_node_path42 = require("path");
9100
- function resolveRegistry2(options, persisted) {
9101
- if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
9102
- const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
9103
- const organization = options.organization ?? persistedAzure?.organization;
9104
- const project = options.project ?? persistedAzure?.project;
9105
- const artifactsFeed = options.artifactsFeed ?? persistedAzure?.artifactsFeed;
9106
- if (!organization || !project || !artifactsFeed) {
9107
- throw new Error(
9108
- "Azure Artifacts registry needs --organization, --project and --artifacts-feed (none found in nx.json's persisted config either)."
9109
- );
9110
- }
9111
- return { kind: "azure-artifacts", organization, project, artifactsFeed };
9112
- }
9113
- if (options.registry === "npm") {
9114
- return { kind: "npm" };
9115
- }
9116
- if (persisted) {
9117
- return persisted;
9118
- }
9119
- throw new Error(
9120
- "No registry found in nx.json's persisted config. Pass --registry npm or --registry azure-artifacts (with --organization/--project/--artifacts-feed)."
9121
- );
9122
- }
9123
- function resolveWorkspaceName(workspaceRoot, persisted) {
9124
- if (persisted.workspaceName) {
9125
- return persisted.workspaceName;
9126
- }
9127
- try {
9128
- const existing = (0, import_node_fs35.readdirSync)(workspaceRoot).find(
9129
- (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
9130
- );
9131
- if (existing) {
9132
- return existing.replace(/\.code-workspace$/, "");
9133
- }
9134
- } catch {
9135
- }
9136
- return (0, import_node_path42.basename)(workspaceRoot);
9137
- }
9138
- function detectNpmAuth(workspaceRoot) {
9139
- try {
9140
- return (0, import_node_fs35.readFileSync)((0, import_node_path42.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
9141
- } catch {
9142
- return void 0;
9143
- }
9144
- }
9145
- function resolveOverlayOptions(workspaceRoot, options, persisted) {
9146
- const scope = options.scope ?? persisted.scope;
9147
- if (!scope) {
9148
- throw new Error("No npm scope found in nx.json's persisted config. Pass --scope explicitly.");
9149
- }
9150
- const registry = resolveRegistry2(options, persisted.registry);
9151
- const ci = options.ci ?? persisted.ci;
9152
- if (!ci) {
9153
- throw new Error(
9154
- "No CI provider found in nx.json's persisted config. Pass --ci azure|github|both explicitly."
9155
- );
9156
- }
9157
- const agent = options.agent ?? persisted.agent;
9158
- if (!agent) {
9159
- throw new Error(
9160
- "No CI build agent found in nx.json's persisted config. Pass --agent explicitly."
9161
- );
9162
- }
9163
- const variableGroup = options.variableGroup ?? persisted.variableGroup ?? "Build";
9164
- const detected = ci === "azure" && persisted.npmAuth === void 0 && options.npmAuth === void 0 ? detectNpmAuth(workspaceRoot) : void 0;
9165
- if (detected) {
9166
- logger.detail("keeping build-identity npm auth: azure-pipelines.yml already runs npmAuthenticate@0");
9167
- }
9168
- const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci, persisted.npmAuth ?? detected);
9169
- const testRunner = options.testRunner ?? persisted.stack?.testRunner;
9170
- if (!testRunner) {
9171
- throw new Error(
9172
- "No testRunner found in nx.json's persisted config. Pass --test-runner explicitly."
9173
- );
9174
- }
9175
- return {
9176
- workspaceName: resolveWorkspaceName(workspaceRoot, persisted),
9177
- scope,
9178
- registry,
9179
- agent,
9180
- variableGroup,
9181
- ci,
9182
- stack: { testRunner },
9183
- ...npmAuth && { npmAuth }
9184
- };
9185
- }
9186
- function runUpgrade(workspaceRoot, options) {
9187
- if (!fileExists((0, import_node_path42.join)(workspaceRoot, "nx.json"))) {
9188
- throw new Error(
9189
- `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
9190
- );
9191
- }
9192
- const persisted = readMnciConfig(workspaceRoot);
9193
- const resolved = resolveOverlayOptions(workspaceRoot, options, persisted);
9194
- logger.step("Re-applying the MoNecromanCI overlay");
9195
- applyOverlay(workspaceRoot, resolved, logger.detail);
9196
- const repaired = repairRollupSourceMaps(workspaceRoot);
9197
- if (repaired.length > 0) {
9198
- logger.step("Enabling source maps in rollup configs (breakpoints in .ts files)");
9199
- for (const path of repaired) {
9200
- logger.detail(`updated ${path}`);
9201
- }
9202
- }
9203
- const repairedManifests = repairPublishableManifests(workspaceRoot);
9204
- if (repairedManifests.length > 0) {
9205
- logger.step("Repointing `types` at the real declaration file");
9206
- for (const path of repairedManifests) {
9207
- logger.detail(`updated ${path}`);
9208
- }
9209
- }
9210
- const lockfile = pruneStaleLocalRegistry(workspaceRoot);
9211
- if (lockfile.stale) {
9212
- logger.step("Dropping the unused local registry (verdaccio) from package-lock.json");
9213
- if (lockfile.status !== 0) {
9214
- logger.warn("npm could not re-resolve the lockfile; run `npm install --package-lock-only` once you are online.");
9215
- }
9216
- }
9217
- const goApps = addGoPlatformTargets(workspaceRoot);
9218
- if (goApps.length > 0) {
9219
- logger.step("Adding the six-platform build to Go apps (build-all, package-all)");
9220
- for (const path of goApps) {
9221
- logger.detail(`updated ${path}`);
9222
- }
9223
- }
9224
- const pinnedExtensions = pinVscodeExtensionProjectNames(workspaceRoot);
9225
- if (pinnedExtensions.length > 0) {
9226
- logger.step("Pinning the Nx project name of VS Code extensions (nx.name)");
9227
- for (const path of pinnedExtensions) {
9228
- logger.detail(`updated ${path}`);
9229
- }
9230
- }
9231
- if (refreshVscodeExtensionScript(workspaceRoot)) {
9232
- logger.step("Updating the VS Code extension packaging script");
9233
- logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
9234
- }
9235
- if (refreshGoReleaseScript(workspaceRoot)) {
9236
- logger.step("Updating the releasable Go app script");
9237
- logger.detail(`updated ${GO_RELEASE_SCRIPT_PATH}`);
9238
- }
9239
- if (hasGoProject(workspaceRoot) && registerNxGoPlugin(workspaceRoot)) {
9240
- logger.step("Registering the Go plugin in nx.json, so Nx can see which Go project imports which");
9241
- logger.detail("updated nx.json");
9242
- }
9243
- const addedDtsPlugins = addMissingDeclarationSpecifierPlugins(workspaceRoot);
9244
- if (addedDtsPlugins.length > 0) {
9245
- logger.step("Adding the declaration-specifier plugin to rollup configs that lacked it");
9246
- for (const path of addedDtsPlugins) {
9247
- logger.detail(`updated ${path}`);
9248
- }
9249
- }
9250
- const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
9251
- if (upgradedDtsPlugins.length > 0) {
9252
- logger.step("Upgrading declaration specifiers to resolve under nodenext");
9253
- for (const path of upgradedDtsPlugins) {
9254
- logger.detail(`updated ${path}`);
9255
- }
9256
- }
9257
- logger.step(
9258
- "Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
9259
- );
9260
- runFormatter(workspaceRoot);
9261
- const nxJson = readJson((0, import_node_path42.join)(workspaceRoot, "nx.json"));
9262
- const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
9263
- for (const entry of stranded) {
9264
- logger.warn(`${entry.project} has release tags only under ${entry.oldTag}: nx release would restart it from its disk version. Run \`git tag ${entry.newTag} ${entry.oldTag}^{commit}\` before the next release (\`mnci doctor\` lists them all).`);
9265
- }
9266
- logger.success("Done. Review the changes with `git diff` before committing.");
9267
- logger.info("Run `npm install` and commit package-lock.json too: the overlay may have added or moved a dependency, and CI installs with `npm ci`, which refuses a stale lockfile.");
9268
- }
9269
-
9270
- // src/workspace-creation/interactive-wizard.use-case.ts
9271
9501
  async function runInteractive() {
9272
- const inWorkspace = fileExists((0, import_node_path43.join)(process.cwd(), "nx.json"));
9502
+ const inWorkspace = fileExists((0, import_node_path46.join)(process.cwd(), "nx.json"));
9273
9503
  const choiceNew = { name: "Create a new monorepo", value: "new" };
9274
9504
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
9275
9505
  const choiceUpgrade = {
@@ -9321,7 +9551,7 @@ function buildProgram(cliVersion) {
9321
9551
  ).option("--json", "print the findings as one JSON document, each with its remedy").action((options) => {
9322
9552
  runDoctor(process.cwd(), options);
9323
9553
  });
9324
- program.command("adopt").description("Read an existing repository and report what bringing it under mnci would involve: blockers, warnings and the step that clears each. Read-only unless a step flag is given; exits non-zero when something blocks").option("--json", "print the report as one JSON document").option("--tags", "create, locally, the baseline tag each project whose release tags are stranded under an old name needs; nothing is pushed").action((options) => {
9554
+ program.command("adopt").description("Read an existing repository and report what bringing it under mnci would involve: blockers, warnings and the step that clears each. Read-only unless a step flag is given; exits non-zero when something blocks").option("--json", "print the report as one JSON document").option("--tags", "create, locally, the baseline tag each project whose release tags are stranded under an old name needs; nothing is pushed").option("--toolchain", "retire old formatter and registry tooling, align the Nx family to one version and run npm audit fix until the audit gate passes; needs a clean git tree and leaves the changes uncommitted").option("--nx <version>", "the Nx version --toolchain aligns to (default: the newest published in the major already in use)").option("--overlay", "apply the mnci overlay (release config, pipeline, npmrc, commitlint, scripts) with the flags mnci upgrade takes; the pipeline keeps the steps mnci does not recognise in its slots; needs a clean git tree and an nx.json").option("--scope <scope>", "npm scope for publishable packages (--overlay)").option("--registry <kind>", "azure-artifacts | npm (--overlay)").option("--organization <name>", "Azure DevOps organization (--overlay)").option("--project <name>", "Azure DevOps project (--overlay)").option("--artifacts-feed <name>", "Azure Artifacts feed (--overlay)").option("--agent <pool>", "CI build agent (--overlay)").option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT (--overlay)").option("--npm-auth <mode>", "pat (default) | build-identity (--overlay, --ci azure only)").option("--ci <provider>", "azure | github | both (--overlay; default: what the repository already has)").option("--test-runner <runner>", "jest | vitest (--overlay; default: what the repository already declares)").action((options) => {
9325
9555
  runAdopt(process.cwd(), options);
9326
9556
  });
9327
9557
  program.command("ci").addArgument(new import_commander.Argument("<phase>", "which phase of the pipeline to run").choices(CI_PHASES)).description(