@mnci/cli 4.6.2 → 4.7.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.
package/README.md CHANGED
@@ -81,6 +81,7 @@ consumers point at it.
81
81
  mnci new my-repo # create a monorepo (prompts scope + registry)
82
82
  mnci new my-repo --yes --registry npm --scope @my
83
83
  mnci new my-repo --yes --registry npm --scope @my --nx-cloud # opt in to Nx Cloud
84
+ mnci new --into . # ...or bootstrap into a clone that already exists
84
85
 
85
86
  cd my-repo
86
87
  mnci add react-app web # @nx/react (Vite + Jest)
@@ -613,6 +614,23 @@ the editor. It also makes `space-before-function-paren` enforceable for the
613
614
  first time: every Prettier-compatible formatter, oxfmt included, rewrites
614
615
  `function f (a)` back to `function f(a)`.
615
616
 
617
+ **`npm run lint` checks one thing `npm run format` does not.** `lint` is
618
+ `nx run-many -t lint`; `format` is a bare `eslint . --fix --cache`. The
619
+ `@nx/dependency-checks` rule needs the Nx project graph, and outside a target it
620
+ prints `No cached ProjectGraph is available. The rule will be skipped.` So a
621
+ dependency problem shows up in `lint` and never in `format`, your editor, or a
622
+ pre-commit hook.
623
+
624
+ That asymmetry is now a safety property rather than a hazard. The rule is
625
+ **fixable**, and `format` passes `--fix`; when the graph was warm — which it is
626
+ after any `nx` command in the same workspace — a `format` run could and did
627
+ rewrite `package.json`. `@mnci/eslint-config` turns off the two checks whose
628
+ fixers do that (`checkObsoleteDependencies`, `checkVersionMismatches`), so
629
+ neither path is destructive, and the skip means `format` cannot reach a manifest
630
+ at all. Warm the graph deliberately (`npx nx show projects`) if you want the
631
+ rule evaluated in `format` too; mnci does not, because it would make every
632
+ format run pay for a graph computation to enforce what `lint` already gates.
633
+
616
634
  **Upgrading an older workspace.** `mnci upgrade` deletes every config a previous
617
635
  version could have written for a second tool — `.prettierrc`, `.prettierrc.json`,
618
636
  `.prettierrc.mjs`, `.prettierignore`, `.oxfmtrc.json`, `oxlint.config.ts` — and
@@ -623,6 +641,47 @@ formatter from the **project's** dependencies, so a stale declaration is enough
623
641
  to reformat on save against an opinion nothing checks. `mnci doctor` reports a
624
642
  workspace that has not been upgraded yet.
625
643
 
644
+ ## `--into`: bootstrapping into a repository that already exists
645
+
646
+ `create-nx-workspace <name>` creates the directory itself and exits with
647
+ `DIRECTORY_EXISTS` when one is already there. That rules out the most common
648
+ way a repository actually starts: the host creates it, you clone it, and the
649
+ clone holds a `.git` directory, a README and a licence. Doing it by hand means
650
+ generating into a temp parent, copying everything except `.git` and
651
+ `node_modules` across, and reinstalling — four steps, each of which can quietly
652
+ lose a file.
653
+
654
+ `mnci new --into <dir>` is that, done once and tested:
655
+
656
+ ```sh
657
+ git clone git@github.com:me/my-repo.git
658
+ cd my-repo
659
+ mnci new --into .
660
+ ```
661
+
662
+ The workspace name defaults to the directory's name, because the directory is
663
+ already named and retyping it is a way to get the two out of step; pass a name
664
+ argument to override it.
665
+
666
+ What it does with the files that are already there is the whole of the risk, so
667
+ every case is decided in advance:
668
+
669
+ | Already in the directory | What happens |
670
+ | --- | --- |
671
+ | `.git` | Never touched. Keeping it is the point. |
672
+ | `README.md`, `LICENSE*` | **Kept.** The generator's README is boilerplate; yours is usually the only hand-written file in the repository. |
673
+ | `.gitignore` | **Merged.** Your lines stay, and the generated ones (`.nx/cache`, `dist`, `out-tsc`, …) are appended under a labelled heading. Lines already present are not repeated, so it is idempotent. |
674
+ | Anything else the new workspace also writes | **Refused**, naming every collision, before a single file is written. |
675
+ | Anything the new workspace does not write | Left alone. |
676
+
677
+ Two checks, not one. A directory holding `package.json`, `nx.json`,
678
+ `tsconfig.base.json`, `node_modules`, `apps/`, `libs/` or `packages/` is
679
+ rejected **before** anything is generated — it is a project already, and the
680
+ answer there is `mnci upgrade`, not `mnci new`. The full collision check needs
681
+ the generated tree, so it runs afterwards, but still before the first write:
682
+ a refusal leaves the target byte-identical to how it was found, and the staging
683
+ copy is discarded.
684
+
626
685
  ## Layout convention = release scoping
627
686
 
628
687
  | Directory | Contents | Released? |
package/dist/cli.js CHANGED
@@ -147,7 +147,7 @@ function runCapture(command, arguments_, cwd) {
147
147
  return { status: result.status ?? 1, stdout: result.stdout ?? "" };
148
148
  }
149
149
  async function runCaptureAsync(command, arguments_, cwd) {
150
- return await new Promise((resolve) => {
150
+ return await new Promise((resolve2) => {
151
151
  const child = (0, import_cross_spawn.default)(command, arguments_, {
152
152
  cwd,
153
153
  timeout: CAPTURE_TIMEOUT_MS,
@@ -159,10 +159,10 @@ async function runCaptureAsync(command, arguments_, cwd) {
159
159
  stdout += chunk;
160
160
  });
161
161
  child.on("error", () => {
162
- resolve({ status: 1, stdout: "" });
162
+ resolve2({ status: 1, stdout: "" });
163
163
  });
164
164
  child.on("close", (code) => {
165
- resolve({ status: code ?? 1, stdout });
165
+ resolve2({ status: code ?? 1, stdout });
166
166
  });
167
167
  });
168
168
  }
@@ -1558,7 +1558,58 @@ updates:
1558
1558
  }
1559
1559
  return config;
1560
1560
  }
1561
- var NX_SCAFFOLDING_TO_REMOVE = [".prettierrc", ".prettierrc.json", ".vscode"];
1561
+ var NX_SCAFFOLDING_TO_REMOVE = [
1562
+ ".prettierrc",
1563
+ ".prettierrc.json",
1564
+ ".vscode",
1565
+ // See LOCAL_REGISTRY_SCAFFOLDING: the config half of a publishing mechanism
1566
+ // this workspace does not use.
1567
+ ".verdaccio",
1568
+ // The AI-agent set, in full. See the remarks above: a partial delete leaves
1569
+ // every `nx` command printing an "outdated configuration" nag.
1570
+ ".agents",
1571
+ ".claude",
1572
+ ".codex",
1573
+ ".cursor",
1574
+ ".gemini",
1575
+ ".opencode",
1576
+ ".github/agents",
1577
+ ".github/prompts",
1578
+ ".github/skills",
1579
+ "AGENTS.md",
1580
+ "CLAUDE.md",
1581
+ "opencode.json"
1582
+ ];
1583
+ function withoutKey(record, key) {
1584
+ return Object.fromEntries(Object.entries(record).filter(([name]) => name !== key));
1585
+ }
1586
+ var LOCAL_REGISTRY_SCAFFOLDING = {
1587
+ /** The config directory, removed with the rest of {@link NX_SCAFFOLDING_TO_REMOVE}. */
1588
+ directory: ".verdaccio",
1589
+ /** The root devDependency the target runs. */
1590
+ devDependency: "verdaccio",
1591
+ /** The root Nx target wired to both of the above. */
1592
+ rootTarget: "local-registry"
1593
+ };
1594
+ function removeLocalRegistryScaffolding(workspaceRoot) {
1595
+ (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, LOCAL_REGISTRY_SCAFFOLDING.directory), {
1596
+ recursive: true,
1597
+ force: true
1598
+ });
1599
+ const manifestPath = (0, import_node_path2.join)(workspaceRoot, "package.json");
1600
+ if (!fileExists(manifestPath)) return;
1601
+ const manifest = readJson(manifestPath);
1602
+ if (manifest.devDependencies?.[LOCAL_REGISTRY_SCAFFOLDING.devDependency] !== void 0) {
1603
+ delete manifest.devDependencies[LOCAL_REGISTRY_SCAFFOLDING.devDependency];
1604
+ if (Object.keys(manifest.devDependencies).length === 0) delete manifest.devDependencies;
1605
+ }
1606
+ if (manifest.nx?.targets?.[LOCAL_REGISTRY_SCAFFOLDING.rootTarget] !== void 0) {
1607
+ delete manifest.nx.targets[LOCAL_REGISTRY_SCAFFOLDING.rootTarget];
1608
+ if (Object.keys(manifest.nx.targets).length === 0) delete manifest.nx.targets;
1609
+ if (Object.keys(manifest.nx).length === 0) delete manifest.nx;
1610
+ }
1611
+ writeFileEnsured(manifestPath, toJson(manifest));
1612
+ }
1562
1613
  function removeNxScaffolding(workspaceRoot) {
1563
1614
  for (const entry of NX_SCAFFOLDING_TO_REMOVE) {
1564
1615
  (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, entry), { recursive: true, force: true });
@@ -1586,6 +1637,38 @@ function ensureEslintCacheIgnored(workspaceRoot) {
1586
1637
  `
1587
1638
  );
1588
1639
  }
1640
+ var PYTHON_ARTEFACT_IGNORES = ["__pycache__/", "*.py[cod]"];
1641
+ function ensurePythonArtefactsIgnored(workspaceRoot) {
1642
+ const gitignorePath = (0, import_node_path2.join)(workspaceRoot, ".gitignore");
1643
+ if (!fileExists(gitignorePath)) {
1644
+ return;
1645
+ }
1646
+ const hasPython = (0, import_node_fs2.globSync)(
1647
+ ["python-packages/*/pyproject.toml", "apps/*/pyproject.toml", "libs/*/pyproject.toml"],
1648
+ { cwd: workspaceRoot }
1649
+ ).length > 0;
1650
+ if (!hasPython) {
1651
+ return;
1652
+ }
1653
+ const current = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
1654
+ const present = new Set(current.split("\n").map((line) => line.trim()));
1655
+ const missing = PYTHON_ARTEFACT_IGNORES.filter((line) => !present.has(line));
1656
+ if (missing.length === 0) {
1657
+ return;
1658
+ }
1659
+ const withoutTrailingBlankLines = current.replace(/\n+$/u, "");
1660
+ const separator = withoutTrailingBlankLines.length > 0 ? "\n\n" : "";
1661
+ const heading = [
1662
+ "# Added by MoNecromanCI: Python bytecode. The tool caches (.mypy_cache,",
1663
+ "# .pytest_cache, .ruff_cache) write their own .gitignore; CPython does not."
1664
+ ].join("\n");
1665
+ writeFileEnsured(
1666
+ gitignorePath,
1667
+ `${withoutTrailingBlankLines}${separator}${heading}
1668
+ ${missing.join("\n")}
1669
+ `
1670
+ );
1671
+ }
1589
1672
  function removeProjectEslintConfigs(workspaceRoot) {
1590
1673
  const matches = (0, import_node_fs2.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
1591
1674
  cwd: workspaceRoot
@@ -1621,12 +1704,15 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
1621
1704
  ...rootScripts()
1622
1705
  };
1623
1706
  const existingDevDeps = manifest.devDependencies;
1624
- const devDeps = withoutRetiredFormatterDependencies({
1625
- ...existingDevDeps,
1626
- ...TS_COMPILER_DEPENDENCIES,
1627
- // The preset pins `nx` itself; the ESLint plugins must match it exactly.
1628
- ...eslintToolchainDependencies(existingDevDeps?.nx ?? "latest")
1629
- });
1707
+ const devDeps = withoutKey(
1708
+ withoutRetiredFormatterDependencies({
1709
+ ...existingDevDeps,
1710
+ ...TS_COMPILER_DEPENDENCIES,
1711
+ // The preset pins `nx` itself; the ESLint plugins must match it exactly.
1712
+ ...eslintToolchainDependencies(existingDevDeps?.nx ?? "latest")
1713
+ }),
1714
+ LOCAL_REGISTRY_SCAFFOLDING.devDependency
1715
+ );
1630
1716
  const overrides = {
1631
1717
  ...manifest.overrides,
1632
1718
  ...ESLINT_PEER_OVERRIDES,
@@ -1638,11 +1724,15 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
1638
1724
  ...reactExpressPeerOverride(manifest)
1639
1725
  };
1640
1726
  const existingNx = manifest.nx;
1727
+ const existingTargets = withoutKey(
1728
+ existingNx?.targets ?? {},
1729
+ LOCAL_REGISTRY_SCAFFOLDING.rootTarget
1730
+ );
1641
1731
  const nx = {
1642
1732
  ...existingNx,
1643
1733
  includedScripts: existingNx?.includedScripts ?? [],
1644
1734
  targets: {
1645
- ...existingNx?.targets,
1735
+ ...existingTargets,
1646
1736
  lint: ROOT_LINT_TARGET
1647
1737
  }
1648
1738
  };
@@ -1670,6 +1760,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
1670
1760
  writeFileEnsured((0, import_node_path2.join)(workspaceRoot, ESLINT_MNCI_FILENAME), ESLINT_MNCI_CONFIG);
1671
1761
  writeEslintEntryPoint(workspaceRoot, onProgress);
1672
1762
  ensureEslintCacheIgnored(workspaceRoot);
1763
+ ensurePythonArtefactsIgnored(workspaceRoot);
1673
1764
  for (const retired of RETIRED_FORMATTER_FILES) {
1674
1765
  removeIfPresent((0, import_node_path2.join)(workspaceRoot, retired));
1675
1766
  }
@@ -2937,6 +3028,7 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
2937
3028
  repairDeclarationSpecifiers(projectRoot);
2938
3029
  writeProjectReadme(projectRoot, `${scope}/${name}`, stack.testRunner);
2939
3030
  removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
3031
+ removeLocalRegistryScaffolding(workspaceRoot);
2940
3032
  registerProjectCommands(workspaceRoot, name, { build: true });
2941
3033
  }
2942
3034
  );
@@ -3283,6 +3375,7 @@ async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
3283
3375
  repairDeclarationSpecifiers(projectRoot);
3284
3376
  writeProjectReadme(projectRoot, `${scope}/${name}`, stack.testRunner);
3285
3377
  removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
3378
+ removeLocalRegistryScaffolding(workspaceRoot);
3286
3379
  registerProjectCommands(workspaceRoot, name, { build: true });
3287
3380
  }
3288
3381
  );
@@ -4838,9 +4931,86 @@ function runDoctor(workspaceRoot) {
4838
4931
  process.exitCode = 1;
4839
4932
  }
4840
4933
 
4841
- // src/workspace-creation/create-workspace.use-case.ts
4934
+ // src/workspace-creation/adopt-directory.use-case.ts
4842
4935
  var import_node_fs13 = require("fs");
4843
4936
  var import_node_path20 = require("path");
4937
+ var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
4938
+ var EXISTING_WINS = /* @__PURE__ */ new Set(["README.md", "LICENSE", "LICENSE.md", "LICENSE.txt"]);
4939
+ var PREFLIGHT_BLOCKERS = [
4940
+ "package.json",
4941
+ "nx.json",
4942
+ "tsconfig.base.json",
4943
+ "node_modules",
4944
+ "apps",
4945
+ "libs",
4946
+ "packages"
4947
+ ];
4948
+ function assertAdoptableDirectory(target) {
4949
+ if (!(0, import_node_fs13.existsSync)(target)) {
4950
+ throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
4951
+ }
4952
+ if (!(0, import_node_fs13.statSync)(target).isDirectory()) {
4953
+ throw new Error(`--into '${target}' is not a directory.`);
4954
+ }
4955
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)));
4956
+ if (blockers.length > 0) {
4957
+ throw new Error(
4958
+ `--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.`
4959
+ );
4960
+ }
4961
+ }
4962
+ function mergeGitignore(generatedFile, targetFile) {
4963
+ const existing = (0, import_node_fs13.readFileSync)(targetFile, "utf8");
4964
+ const present = new Set(existing.split("\n").map((line) => line.trim()));
4965
+ const additions = (0, import_node_fs13.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
4966
+ const trimmed = line.trim();
4967
+ return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
4968
+ });
4969
+ if (additions.length === 0) return false;
4970
+ const separator = existing.endsWith("\n") ? "" : "\n";
4971
+ (0, import_node_fs13.writeFileSync)(
4972
+ targetFile,
4973
+ `${existing}${separator}
4974
+ # Added by mnci (Nx workspace)
4975
+ ${additions.join("\n")}
4976
+ `
4977
+ );
4978
+ return true;
4979
+ }
4980
+ function adoptGeneratedWorkspace(generatedRoot, target) {
4981
+ const entries = (0, import_node_fs13.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
4982
+ const collisions = entries.filter(
4983
+ (entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
4984
+ );
4985
+ if (collisions.length > 0) {
4986
+ throw new Error(
4987
+ `--into '${target}' already contains ${collisions.join(", ")}, which the new workspace also writes. Move those aside and run it again; nothing has been changed.`
4988
+ );
4989
+ }
4990
+ const result = { copied: [], kept: [], mergedGitignore: false };
4991
+ for (const entry of entries) {
4992
+ const from = (0, import_node_path20.join)(generatedRoot, entry);
4993
+ const to = (0, import_node_path20.join)(target, entry);
4994
+ if (entry === ".gitignore" && (0, import_node_fs13.existsSync)(to)) {
4995
+ result.mergedGitignore = mergeGitignore(from, to);
4996
+ result.kept.push(entry);
4997
+ continue;
4998
+ }
4999
+ if ((0, import_node_fs13.existsSync)(to)) {
5000
+ result.kept.push(entry);
5001
+ continue;
5002
+ }
5003
+ (0, import_node_fs13.cpSync)(from, to, { recursive: true });
5004
+ result.copied.push(entry);
5005
+ }
5006
+ (0, import_node_fs13.rmSync)(generatedRoot, { recursive: true, force: true });
5007
+ return result;
5008
+ }
5009
+
5010
+ // src/workspace-creation/create-workspace.use-case.ts
5011
+ var import_node_fs14 = require("fs");
5012
+ var import_node_os = require("os");
5013
+ var import_node_path21 = require("path");
4844
5014
  function nxCloudProviderValue(ci) {
4845
5015
  return ci === "azure" ? "azure" : "github";
4846
5016
  }
@@ -4876,7 +5046,9 @@ async function resolveRegistry(options) {
4876
5046
  return await promptRegistry();
4877
5047
  }
4878
5048
  async function runNew(name, options) {
4879
- const workspaceName = name ?? await promptText("Workspace name");
5049
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path21.resolve)(process.cwd(), options.into);
5050
+ if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
5051
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path21.basename)(adoptTarget));
4880
5052
  assertValidProjectName(workspaceName, "Workspace name");
4881
5053
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
4882
5054
  const registry = await resolveRegistry(options);
@@ -4888,6 +5060,7 @@ async function runNew(name, options) {
4888
5060
  const variableGroup = ci === "github" ? options.variableGroup ?? "Build" : options.variableGroup ?? (options.yes ? "Build" : await promptText("Azure DevOps variable group holding the npm PAT", "Build"));
4889
5061
  const stack = await resolveStack(options);
4890
5062
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
5063
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs14.mkdtempSync)((0, import_node_path21.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
4891
5064
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
4892
5065
  runNpx(
4893
5066
  [
@@ -4899,9 +5072,17 @@ async function runNew(name, options) {
4899
5072
  nxCloud ? `--nxCloud=${nxCloudProviderValue(ci)}` : "--nxCloud=skip",
4900
5073
  "--no-interactive"
4901
5074
  ],
4902
- process.cwd()
5075
+ stagingParent
4903
5076
  );
4904
- const workspaceRoot = (0, import_node_path20.join)(process.cwd(), workspaceName);
5077
+ let workspaceRoot = (0, import_node_path21.join)(stagingParent, workspaceName);
5078
+ if (adoptTarget !== void 0) {
5079
+ logger.step(`Adopting ${adoptTarget} (keeping its .git)`);
5080
+ const adoption = adoptGeneratedWorkspace(workspaceRoot, adoptTarget);
5081
+ for (const kept of adoption.kept) logger.detail(`kept the existing ${kept}`);
5082
+ if (adoption.mergedGitignore) logger.detail("merged the generated .gitignore into the existing one");
5083
+ (0, import_node_fs14.rmSync)(stagingParent, { recursive: true, force: true });
5084
+ workspaceRoot = adoptTarget;
5085
+ }
4905
5086
  logger.step(
4906
5087
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
4907
5088
  );
@@ -4910,8 +5091,8 @@ async function runNew(name, options) {
4910
5091
  { workspaceName, scope, registry, agent, variableGroup, ci, stack },
4911
5092
  logger.detail
4912
5093
  );
4913
- (0, import_node_fs13.rmSync)((0, import_node_path20.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
4914
- (0, import_node_fs13.rmSync)((0, import_node_path20.join)(workspaceRoot, "package-lock.json"), { force: true });
5094
+ (0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
5095
+ (0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "package-lock.json"), { force: true });
4915
5096
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
4916
5097
  const installStatus = runShell(
4917
5098
  "npm",
@@ -4925,7 +5106,7 @@ async function runNew(name, options) {
4925
5106
  logger.step("Formatting the workspace (eslint --fix, JavaScript Standard Style)");
4926
5107
  runFormatter(workspaceRoot);
4927
5108
  logger.success("Done. Next steps:");
4928
- logger.info(` cd ${workspaceName}`);
5109
+ if (adoptTarget === void 0) logger.info(` cd ${workspaceName}`);
4929
5110
  logger.info(" mnci add react-app web # or: react-lib, react-internal-lib, node-app,");
4930
5111
  logger.info(" # node-function-app, npm-lib, internal-lib,");
4931
5112
  logger.info(
@@ -4941,12 +5122,12 @@ async function runNew(name, options) {
4941
5122
  }
4942
5123
 
4943
5124
  // src/workspace-creation/interactive-wizard.use-case.ts
4944
- var import_node_path22 = require("path");
5125
+ var import_node_path23 = require("path");
4945
5126
  var import_prompts4 = require("@inquirer/prompts");
4946
5127
 
4947
5128
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
4948
- var import_node_fs14 = require("fs");
4949
- var import_node_path21 = require("path");
5129
+ var import_node_fs15 = require("fs");
5130
+ var import_node_path22 = require("path");
4950
5131
  function resolveRegistry2(options, persisted) {
4951
5132
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
4952
5133
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -4975,7 +5156,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
4975
5156
  return persisted.workspaceName;
4976
5157
  }
4977
5158
  try {
4978
- const existing = (0, import_node_fs14.readdirSync)(workspaceRoot).find(
5159
+ const existing = (0, import_node_fs15.readdirSync)(workspaceRoot).find(
4979
5160
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
4980
5161
  );
4981
5162
  if (existing) {
@@ -4983,7 +5164,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
4983
5164
  }
4984
5165
  } catch {
4985
5166
  }
4986
- return (0, import_node_path21.basename)(workspaceRoot);
5167
+ return (0, import_node_path22.basename)(workspaceRoot);
4987
5168
  }
4988
5169
  function resolveOverlayOptions(workspaceRoot, options, persisted) {
4989
5170
  const scope = options.scope ?? persisted.scope;
@@ -5021,7 +5202,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
5021
5202
  };
5022
5203
  }
5023
5204
  function runUpgrade(workspaceRoot, options) {
5024
- if (!fileExists((0, import_node_path21.join)(workspaceRoot, "nx.json"))) {
5205
+ if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
5025
5206
  throw new Error(
5026
5207
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
5027
5208
  );
@@ -5060,7 +5241,7 @@ function runUpgrade(workspaceRoot, options) {
5060
5241
 
5061
5242
  // src/workspace-creation/interactive-wizard.use-case.ts
5062
5243
  async function runInteractive() {
5063
- const inWorkspace = fileExists((0, import_node_path22.join)(process.cwd(), "nx.json"));
5244
+ const inWorkspace = fileExists((0, import_node_path23.join)(process.cwd(), "nx.json"));
5064
5245
  const choiceNew = { name: "Create a new monorepo", value: "new" };
5065
5246
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
5066
5247
  const choiceUpgrade = {
@@ -5081,8 +5262,8 @@ async function runInteractive() {
5081
5262
  }
5082
5263
 
5083
5264
  // src/cli-version/check-for-update.use-case.ts
5084
- var import_node_fs15 = require("fs");
5085
- var import_node_path23 = require("path");
5265
+ var import_node_fs16 = require("fs");
5266
+ var import_node_path24 = require("path");
5086
5267
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
5087
5268
  var PACKAGE_NAME = "@mnci/cli";
5088
5269
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -5138,8 +5319,8 @@ function releaseTriple(version) {
5138
5319
  }
5139
5320
  function readCliVersion(packageDirectory) {
5140
5321
  try {
5141
- const manifestPath = (0, import_node_path23.join)(packageDirectory, "..", "package.json");
5142
- const manifest = JSON.parse((0, import_node_fs15.readFileSync)(manifestPath, "utf8"));
5322
+ const manifestPath = (0, import_node_path24.join)(packageDirectory, "..", "package.json");
5323
+ const manifest = JSON.parse((0, import_node_fs16.readFileSync)(manifestPath, "utf8"));
5143
5324
  return manifest.version ?? "0.0.0";
5144
5325
  } catch {
5145
5326
  return "0.0.0";
@@ -5153,7 +5334,10 @@ function buildProgram(cliVersion) {
5153
5334
  program.command("new").argument("[name]", "workspace name").description("Create a new monorepo (Nx TS preset + release/pipeline overlay)").option("-y, --yes", "accept defaults for anything not passed as a flag").option("--scope <scope>", "npm scope for publishable packages (e.g. @demo)").option("--registry <kind>", "azure-artifacts | npm").option("--organization <name>", "Azure DevOps organization").option("--project <name>", "Azure DevOps project").option("--artifacts-feed <name>", "Azure Artifacts feed").option(
5154
5335
  "--agent <pool>",
5155
5336
  "CI build agent: a vmImage (e.g. ubuntu-latest) or self-hosted pool name"
5156
- ).option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--test-runner <runner>", "unit-test runner: jest | vitest").option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").action(async (name, options) => {
5337
+ ).option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--test-runner <runner>", "unit-test runner: jest | vitest").option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").option(
5338
+ "--into <dir>",
5339
+ "bootstrap into an existing directory (a fresh clone holding only .git); the directory name is the workspace name unless one is given"
5340
+ ).action(async (name, options) => {
5157
5341
  await runNew(name, options);
5158
5342
  });
5159
5343
  program.command("upgrade").description(