@mnci/cli 4.18.0 → 4.20.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
@@ -2342,7 +2342,7 @@ function runCiPhase(phase, workspaceRoot, dependencies = {}) {
2342
2342
  }
2343
2343
 
2344
2344
  // src/project-scaffolding/add-project.use-case.ts
2345
- var import_node_path23 = require("path");
2345
+ var import_node_path24 = require("path");
2346
2346
  var import_prompts3 = require("@inquirer/prompts");
2347
2347
 
2348
2348
  // src/project-name/project-name.validator.ts
@@ -2492,27 +2492,35 @@ function projectTask(name, kind) {
2492
2492
  return kind === "start" ? { ...base, isBackground: true } : { ...base, group: kind };
2493
2493
  }
2494
2494
  function renameScaffoldPlaceholder(projectRoot, name) {
2495
- const placeholder = (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.ts`);
2495
+ const sourceDir = (0, import_node_path4.join)(projectRoot, "src");
2496
+ const placeholder = (0, import_node_path4.join)(sourceDir, "lib", `${name}.ts`);
2496
2497
  if (!(0, import_node_fs4.existsSync)(placeholder)) {
2497
2498
  return;
2498
2499
  }
2499
- (0, import_node_fs4.renameSync)(placeholder, (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.use-case.ts`));
2500
- const spec = (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.spec.ts`);
2500
+ const sliceDir = (0, import_node_path4.join)(sourceDir, name);
2501
+ (0, import_node_fs4.mkdirSync)(sliceDir, { recursive: true });
2502
+ (0, import_node_fs4.renameSync)(placeholder, (0, import_node_path4.join)(sliceDir, `${name}.use-case.ts`));
2503
+ const spec = (0, import_node_path4.join)(sourceDir, "lib", `${name}.spec.ts`);
2501
2504
  if ((0, import_node_fs4.existsSync)(spec)) {
2502
- const renamed = (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.use-case.spec.ts`);
2505
+ const renamed = (0, import_node_path4.join)(sliceDir, `${name}.use-case.spec.ts`);
2503
2506
  (0, import_node_fs4.renameSync)(spec, renamed);
2504
2507
  writeFileEnsured(
2505
2508
  renamed,
2509
+ // The spec still sits beside the implementation, so only its role suffix changes.
2506
2510
  repointSpecifier((0, import_node_fs4.readFileSync)(renamed, "utf8"), `./${name}`, `./${name}.use-case`)
2507
2511
  );
2508
2512
  }
2509
- const barrel = (0, import_node_path4.join)(projectRoot, "src", "index.ts");
2513
+ const barrel = (0, import_node_path4.join)(sourceDir, "index.ts");
2514
+ const esm = (0, import_node_fs4.existsSync)(barrel) && (0, import_node_fs4.readFileSync)(barrel, "utf8").includes(`./lib/${name}.js'`);
2515
+ writeFileEnsured((0, import_node_path4.join)(sliceDir, "index.ts"), `export * from './${name}.use-case${esm ? ".js" : ""}'
2516
+ `);
2510
2517
  if ((0, import_node_fs4.existsSync)(barrel)) {
2511
2518
  writeFileEnsured(
2512
2519
  barrel,
2513
- repointSpecifier((0, import_node_fs4.readFileSync)(barrel, "utf8"), `./lib/${name}`, `./lib/${name}.use-case`)
2520
+ (0, import_node_fs4.readFileSync)(barrel, "utf8").replaceAll(`./lib/${name}.js'`, () => `./${name}/index.js'`).replaceAll(`./lib/${name}'`, () => `./${name}'`)
2514
2521
  );
2515
2522
  }
2523
+ (0, import_node_fs4.rmSync)((0, import_node_path4.join)(sourceDir, "lib"), { recursive: true, force: true });
2516
2524
  }
2517
2525
  function repointSpecifier(source, from, to) {
2518
2526
  return source.replaceAll(`${from}'`, () => `${to}'`).replaceAll(`${from}.js'`, () => `${to}.js'`);
@@ -4999,7 +5007,8 @@ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4999
5007
  refreshLockFile(workspaceRoot, name);
5000
5008
  }
5001
5009
 
5002
- // src/dependency-management/sync-dependencies.use-case.ts
5010
+ // src/dependency-management/install-dependencies.use-case.ts
5011
+ var import_node_fs17 = require("fs");
5003
5012
  var import_node_path21 = require("path");
5004
5013
 
5005
5014
  // src/dependency-management/manifest.repository.ts
@@ -5330,6 +5339,27 @@ function collectInventory(workspaceRoot, ecosystems = ECOSYSTEMS) {
5330
5339
  }
5331
5340
  return inventory;
5332
5341
  }
5342
+ var PROJECT_GLOBS = {
5343
+ ...MANIFEST_GLOBS,
5344
+ go: ["apps/*/go.mod", "libs/*/go.mod", "packages/*/go.mod"]
5345
+ };
5346
+ function locateProjects(workspaceRoot) {
5347
+ const locations = [];
5348
+ for (const ecosystem of ECOSYSTEMS) {
5349
+ const relativePaths = (0, import_node_fs16.globSync)(PROJECT_GLOBS[ecosystem], { cwd: workspaceRoot });
5350
+ for (const relativePath of relativePaths) {
5351
+ const posix = toPosix(relativePath);
5352
+ const dir = posix.slice(0, posix.lastIndexOf("/"));
5353
+ locations.push({
5354
+ ecosystem,
5355
+ dir,
5356
+ name: dir.slice(dir.lastIndexOf("/") + 1),
5357
+ manifestPath: (0, import_node_path20.join)(workspaceRoot, relativePath)
5358
+ });
5359
+ }
5360
+ }
5361
+ return locations;
5362
+ }
5333
5363
  function rewriteSpec(site, spec) {
5334
5364
  if (!site.rewritable || spec === site.spec) {
5335
5365
  return false;
@@ -5379,6 +5409,41 @@ function replacePipSpec(content, name, spec) {
5379
5409
  (match, lead, matched) => `${lead}${matched}${spec}`
5380
5410
  );
5381
5411
  }
5412
+ function addPipDependency(content, entry) {
5413
+ const name = parseRequirement(entry)?.name;
5414
+ const already = name !== void 0 && pyprojectDependencies(content).some((existing) => parseRequirement(existing)?.name === name);
5415
+ if (already) {
5416
+ return content;
5417
+ }
5418
+ const newline = content.includes("\r\n") ? "\r\n" : "\n";
5419
+ const lines = content.split(/\r?\n/);
5420
+ const quoted = `"${entry}"`;
5421
+ let inProjectTable = false;
5422
+ for (let index = 0; index < lines.length; index++) {
5423
+ const trimmed = lines[index].trim();
5424
+ if (trimmed.startsWith("[")) {
5425
+ inProjectTable = trimmed === "[project]";
5426
+ continue;
5427
+ }
5428
+ if (!inProjectTable) {
5429
+ continue;
5430
+ }
5431
+ const opener = /^(\s*)dependencies\s*=\s*\[(.*)$/.exec(lines[index]);
5432
+ if (!opener) {
5433
+ continue;
5434
+ }
5435
+ const [, indent, rest] = opener;
5436
+ if (rest.includes("]")) {
5437
+ const inner = rest.slice(0, rest.lastIndexOf("]")).trim().replace(/,+\s*$/, "");
5438
+ const list = inner.length > 0 ? `${inner}, ${quoted}` : quoted;
5439
+ lines[index] = `${indent}dependencies = [${list}]`;
5440
+ } else {
5441
+ lines.splice(index + 1, 0, `${indent} ${quoted},`);
5442
+ }
5443
+ return lines.join(newline);
5444
+ }
5445
+ return content;
5446
+ }
5382
5447
  function replacePubSpec(content, name, spec) {
5383
5448
  return content.replaceAll(
5384
5449
  new RegExp(String.raw`^(\s+${escapeForRegex(name)}:[^\S\n]*)\S[^\n]*$`, "gm"),
@@ -5450,6 +5515,158 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
5450
5515
  return void 0;
5451
5516
  }
5452
5517
 
5518
+ // src/dependency-management/install-dependencies.use-case.ts
5519
+ var WHOLE_WORKSPACE_INSTALL = [
5520
+ ["npm", "npm", ["install"]],
5521
+ ["pip", "npm", ["run", "python:install"]],
5522
+ ["pub", "flutter", ["pub", "get"]],
5523
+ ["nuget", "npx", ["nx", "run-many", "-t", "restore"]],
5524
+ ["go", "go", ["work", "sync"]]
5525
+ ];
5526
+ function runInstall(workspaceRoot, packages, options = {}) {
5527
+ const targets = options.workspace ?? [];
5528
+ if (targets.length === 0) {
5529
+ if (packages.length > 0) {
5530
+ logger.error(
5531
+ "Adding a package needs a target project \u2014 'mnci install -w <project> <package>'. A bare 'mnci install' (no package) installs the whole workspace"
5532
+ );
5533
+ process.exitCode = 1;
5534
+ return;
5535
+ }
5536
+ installEverything(workspaceRoot);
5537
+ return;
5538
+ }
5539
+ const locations = locateProjects(workspaceRoot);
5540
+ for (const target of targets) {
5541
+ const location = resolveTarget(locations, target);
5542
+ if (location === void 0) {
5543
+ logger.error(
5544
+ `No project '${target}' \u2014 looked for a manifest under apps/, libs/, packages/ (and python-packages/). Name it by directory (apps/${target}) or by its basename`
5545
+ );
5546
+ process.exitCode = 1;
5547
+ continue;
5548
+ }
5549
+ installInto(workspaceRoot, location, packages, Boolean(options.saveDev));
5550
+ }
5551
+ }
5552
+ function resolveTarget(locations, target) {
5553
+ const byDir = locations.find((location) => location.dir === target);
5554
+ if (byDir !== void 0) {
5555
+ return byDir;
5556
+ }
5557
+ const byName = locations.filter((location) => location.name === target);
5558
+ if (byName.length > 1) {
5559
+ logger.error(
5560
+ `'${target}' matches ${byName.length} projects (${byName.map((match) => match.dir).join(", ")}) \u2014 name it by directory`
5561
+ );
5562
+ return void 0;
5563
+ }
5564
+ return byName[0];
5565
+ }
5566
+ function installInto(workspaceRoot, location, packages, saveDev) {
5567
+ const projectDir = (0, import_node_path21.join)(workspaceRoot, location.dir);
5568
+ switch (location.ecosystem) {
5569
+ case "npm": {
5570
+ const flags = saveDev ? ["--save-dev"] : [];
5571
+ shell(workspaceRoot, "npm", ["install", ...packages, ...flags, "-w", location.dir], location);
5572
+ return;
5573
+ }
5574
+ case "go": {
5575
+ shell(projectDir, "go", packages.length > 0 ? ["get", ...packages] : ["mod", "download"], location);
5576
+ if (packages.length > 0) {
5577
+ runShell("go", ["work", "sync"], workspaceRoot);
5578
+ }
5579
+ return;
5580
+ }
5581
+ case "nuget": {
5582
+ if (packages.length === 0) {
5583
+ shell(workspaceRoot, "dotnet", ["restore", location.manifestPath], location);
5584
+ return;
5585
+ }
5586
+ for (const specifier of packages) {
5587
+ const [name, version] = splitAtLast(specifier, "@");
5588
+ const versionFlag = version === void 0 ? [] : ["--version", version];
5589
+ shell(workspaceRoot, "dotnet", ["add", location.manifestPath, "package", name, ...versionFlag], location);
5590
+ }
5591
+ return;
5592
+ }
5593
+ case "pub": {
5594
+ const devFlag = saveDev ? ["--dev"] : [];
5595
+ shell(
5596
+ projectDir,
5597
+ "flutter",
5598
+ packages.length > 0 ? ["pub", "add", ...devFlag, ...packages] : ["pub", "get"],
5599
+ location
5600
+ );
5601
+ return;
5602
+ }
5603
+ case "pip": {
5604
+ if (saveDev) {
5605
+ logger.warn(
5606
+ "pip has no per-project dev-dependency section \u2014 adding to [project].dependencies (dev tools live in the root requirements-dev.txt)"
5607
+ );
5608
+ }
5609
+ for (const specifier of packages) {
5610
+ addPythonDependency(location.manifestPath, specifier);
5611
+ }
5612
+ installEverything(workspaceRoot, ["pip"]);
5613
+ return;
5614
+ }
5615
+ }
5616
+ }
5617
+ function addPythonDependency(manifestPath, specifier) {
5618
+ let content;
5619
+ try {
5620
+ content = (0, import_node_fs17.readFileSync)(manifestPath, "utf8");
5621
+ } catch {
5622
+ logger.warn(`Could not read ${manifestPath} \u2014 skipped ${specifier}`);
5623
+ return;
5624
+ }
5625
+ const updated = addPipDependency(content, specifier);
5626
+ if (updated === content) {
5627
+ logger.info(`${specifier} is already declared \u2014 left as is`);
5628
+ return;
5629
+ }
5630
+ writeFileEnsured(manifestPath, updated);
5631
+ logger.step(`Added ${specifier} to ${manifestPath}`);
5632
+ }
5633
+ function installEverything(workspaceRoot, only) {
5634
+ for (const [ecosystem, command, arguments_] of WHOLE_WORKSPACE_INSTALL) {
5635
+ if (only !== void 0 && !only.includes(ecosystem)) {
5636
+ continue;
5637
+ }
5638
+ if (!ecosystemPresent(workspaceRoot, ecosystem)) {
5639
+ continue;
5640
+ }
5641
+ logger.step(`Installing ${ecosystem} dependencies (${command} ${arguments_.join(" ")})`);
5642
+ if (runShell(command, [...arguments_], workspaceRoot) !== 0) {
5643
+ logger.warn(`${command} ${arguments_.join(" ")} failed \u2014 re-run it once the cause is fixed`);
5644
+ }
5645
+ }
5646
+ }
5647
+ function ecosystemPresent(workspaceRoot, ecosystem) {
5648
+ if (ecosystem === "go") {
5649
+ return fileExists((0, import_node_path21.join)(workspaceRoot, "go.work")) || fileExists((0, import_node_path21.join)(workspaceRoot, "go.mod"));
5650
+ }
5651
+ return hasEcosystem(workspaceRoot, ecosystem);
5652
+ }
5653
+ function shell(cwd, command, arguments_, location) {
5654
+ logger.step(`${location.dir}: ${command} ${arguments_.join(" ")}`);
5655
+ if (runShell(command, [...arguments_], cwd) !== 0) {
5656
+ logger.warn(`${command} ${arguments_.join(" ")} failed in ${location.dir}`);
5657
+ }
5658
+ }
5659
+ function splitAtLast(value, separator) {
5660
+ const at = value.lastIndexOf(separator);
5661
+ if (at <= 0) {
5662
+ return [value, void 0];
5663
+ }
5664
+ return [value.slice(0, at), value.slice(at + 1)];
5665
+ }
5666
+
5667
+ // src/dependency-management/sync-dependencies.use-case.ts
5668
+ var import_node_path22 = require("path");
5669
+
5453
5670
  // src/dependency-management/semver.algorithm.ts
5454
5671
  var UPDATE_KINDS = ["patch", "minor", "major", "non-semver"];
5455
5672
  var UPDATE_KIND_LABELS = {
@@ -5625,7 +5842,7 @@ function describe(finding) {
5625
5842
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
5626
5843
  }
5627
5844
  function runSync(workspaceRoot, options) {
5628
- if (!fileExists((0, import_node_path21.join)(workspaceRoot, "nx.json"))) {
5845
+ if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
5629
5846
  throw new Error(
5630
5847
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
5631
5848
  );
@@ -5675,7 +5892,7 @@ function runSync(workspaceRoot, options) {
5675
5892
  }
5676
5893
 
5677
5894
  // src/dependency-management/update-dependencies.use-case.ts
5678
- var import_node_path22 = require("path");
5895
+ var import_node_path23 = require("path");
5679
5896
  var import_prompts2 = require("@inquirer/prompts");
5680
5897
 
5681
5898
  // src/dependency-management/registry.client.ts
@@ -5958,7 +6175,7 @@ function reinstall(workspaceRoot, ecosystems) {
5958
6175
  function hasPythonInstallScript(workspaceRoot) {
5959
6176
  try {
5960
6177
  const manifest = readJson(
5961
- (0, import_node_path22.join)(workspaceRoot, "package.json")
6178
+ (0, import_node_path23.join)(workspaceRoot, "package.json")
5962
6179
  );
5963
6180
  return manifest.scripts?.["python:install"] !== void 0;
5964
6181
  } catch {
@@ -5974,7 +6191,7 @@ function applyGoUpdates(workspaceRoot, entries) {
5974
6191
  }
5975
6192
  }
5976
6193
  async function runUp(workspaceRoot, options) {
5977
- if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
6194
+ if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
5978
6195
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
5979
6196
  }
5980
6197
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -6050,7 +6267,7 @@ var PROJECT_KINDS = [
6050
6267
  ];
6051
6268
  async function runAdd(kind, name, options) {
6052
6269
  const workspaceRoot = process.cwd();
6053
- if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
6270
+ if (!fileExists((0, import_node_path24.join)(workspaceRoot, "nx.json"))) {
6054
6271
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
6055
6272
  }
6056
6273
  const stack = readWorkspaceStack(workspaceRoot);
@@ -6110,8 +6327,8 @@ async function runAdd(kind, name, options) {
6110
6327
  ],
6111
6328
  workspaceRoot
6112
6329
  );
6113
- markPrivate((0, import_node_path23.join)(workspaceRoot, "libs", resolvedName, "package.json"));
6114
- renameScaffoldPlaceholder((0, import_node_path23.join)(workspaceRoot, "libs", resolvedName), resolvedName);
6330
+ markPrivate((0, import_node_path24.join)(workspaceRoot, "libs", resolvedName, "package.json"));
6331
+ renameScaffoldPlaceholder((0, import_node_path24.join)(workspaceRoot, "libs", resolvedName), resolvedName);
6115
6332
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
6116
6333
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
6117
6334
  break;
@@ -6203,7 +6420,7 @@ async function runAdd(kind, name, options) {
6203
6420
  }
6204
6421
  function readWorkspaceStack(workspaceRoot) {
6205
6422
  const nxJson = readJson(
6206
- (0, import_node_path23.join)(workspaceRoot, "nx.json")
6423
+ (0, import_node_path24.join)(workspaceRoot, "nx.json")
6207
6424
  );
6208
6425
  const stack = nxJson.mnci?.stack;
6209
6426
  return {
@@ -6213,15 +6430,15 @@ function readWorkspaceStack(workspaceRoot) {
6213
6430
 
6214
6431
  // src/workspace-diagnostics/check-invariants.use-case.ts
6215
6432
  var import_node_child_process = require("child_process");
6216
- var import_node_fs17 = require("fs");
6217
- var import_node_path24 = require("path");
6433
+ var import_node_fs18 = require("fs");
6434
+ var import_node_path25 = require("path");
6218
6435
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
6219
6436
  function toPosix2(path) {
6220
6437
  return path.replaceAll("\\", "/");
6221
6438
  }
6222
6439
  function checkEslintConfigs(workspaceRoot) {
6223
- const rootConfigs = (0, import_node_fs17.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
6224
- const projectConfigs = (0, import_node_fs17.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
6440
+ const rootConfigs = (0, import_node_fs18.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
6441
+ const projectConfigs = (0, import_node_fs18.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
6225
6442
  cwd: workspaceRoot
6226
6443
  }).map((config) => toPosix2(config));
6227
6444
  return [
@@ -6241,10 +6458,10 @@ function checkEslintConfigs(workspaceRoot) {
6241
6458
  ];
6242
6459
  }
6243
6460
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
6244
- const rules = (0, import_node_path24.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
6245
- if (!(0, import_node_fs17.existsSync)(rules)) return [];
6246
- const entryPoint = (0, import_node_path24.join)(workspaceRoot, ESLINT_USER_FILENAME);
6247
- const source = (0, import_node_fs17.existsSync)(entryPoint) ? (0, import_node_fs17.readFileSync)(entryPoint, "utf8") : "";
6461
+ const rules = (0, import_node_path25.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
6462
+ if (!(0, import_node_fs18.existsSync)(rules)) return [];
6463
+ const entryPoint = (0, import_node_path25.join)(workspaceRoot, ESLINT_USER_FILENAME);
6464
+ const source = (0, import_node_fs18.existsSync)(entryPoint) ? (0, import_node_fs18.readFileSync)(entryPoint, "utf8") : "";
6248
6465
  return [
6249
6466
  {
6250
6467
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -6257,7 +6474,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
6257
6474
  function declaredDevDependencies(workspaceRoot) {
6258
6475
  try {
6259
6476
  const manifest = readJson(
6260
- (0, import_node_path24.join)(workspaceRoot, "package.json")
6477
+ (0, import_node_path25.join)(workspaceRoot, "package.json")
6261
6478
  );
6262
6479
  return manifest.devDependencies ?? {};
6263
6480
  } catch {
@@ -6265,7 +6482,7 @@ function declaredDevDependencies(workspaceRoot) {
6265
6482
  }
6266
6483
  }
6267
6484
  function checkNoRetiredFormatter(workspaceRoot) {
6268
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path24.join)(workspaceRoot, file)));
6485
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path25.join)(workspaceRoot, file)));
6269
6486
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
6270
6487
  const stale = [...files, ...declared];
6271
6488
  if (stale.length === 0) {
@@ -6291,7 +6508,7 @@ function checkEslintPlugin(nxJson) {
6291
6508
  };
6292
6509
  }
6293
6510
  function checkResolvedEslint(workspaceRoot) {
6294
- const manifestPath = (0, import_node_path24.join)(workspaceRoot, "node_modules/eslint/package.json");
6511
+ const manifestPath = (0, import_node_path25.join)(workspaceRoot, "node_modules/eslint/package.json");
6295
6512
  if (!fileExists(manifestPath)) {
6296
6513
  return void 0;
6297
6514
  }
@@ -6309,11 +6526,11 @@ function checkResolvedEslint(workspaceRoot) {
6309
6526
  }
6310
6527
  }
6311
6528
  function checkNpmrc(workspaceRoot, registry, scope) {
6312
- const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
6529
+ const npmrcPath = (0, import_node_path25.join)(workspaceRoot, ".npmrc");
6313
6530
  if (!registry || !fileExists(npmrcPath)) {
6314
6531
  return void 0;
6315
6532
  }
6316
- const npmrc = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8");
6533
+ const npmrc = (0, import_node_fs18.readFileSync)(npmrcPath, "utf8");
6317
6534
  if (registry.kind === "npm") {
6318
6535
  return {
6319
6536
  check: ".npmrc authenticates the public registry",
@@ -6330,11 +6547,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
6330
6547
  };
6331
6548
  }
6332
6549
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
6333
- const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
6550
+ const npmrcPath = (0, import_node_path25.join)(workspaceRoot, ".npmrc");
6334
6551
  if (!fileExists(npmrcPath)) {
6335
6552
  return void 0;
6336
6553
  }
6337
- const npmrc = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8");
6554
+ const npmrc = (0, import_node_fs18.readFileSync)(npmrcPath, "utf8");
6338
6555
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
6339
6556
  const referenced = [
6340
6557
  ...new Set(
@@ -6358,13 +6575,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
6358
6575
  };
6359
6576
  }
6360
6577
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
6361
- const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
6362
- const pipelinePath = (0, import_node_path24.join)(workspaceRoot, "azure-pipelines.yml");
6578
+ const npmrcPath = (0, import_node_path25.join)(workspaceRoot, ".npmrc");
6579
+ const pipelinePath = (0, import_node_path25.join)(workspaceRoot, "azure-pipelines.yml");
6363
6580
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
6364
6581
  return void 0;
6365
6582
  }
6366
- const holdsCredentials = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
6367
- const runsTask = (0, import_node_fs17.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
6583
+ const holdsCredentials = (0, import_node_fs18.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
6584
+ const runsTask = (0, import_node_fs18.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
6368
6585
  if (!holdsCredentials && !runsTask) {
6369
6586
  return {
6370
6587
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -6409,13 +6626,13 @@ function npmjsCredentialShape(credentials, environment) {
6409
6626
  }
6410
6627
  function checkVersionActions(workspaceRoot) {
6411
6628
  const candidates = [
6412
- ...(0, import_node_fs17.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
6413
- ...(0, import_node_fs17.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
6414
- ...(0, import_node_fs17.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
6629
+ ...(0, import_node_fs18.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
6630
+ ...(0, import_node_fs18.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
6631
+ ...(0, import_node_fs18.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
6415
6632
  ].map((manifest) => toPosix2(manifest));
6416
6633
  return candidates.flatMap((manifest) => {
6417
6634
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
6418
- const projectJsonPath = (0, import_node_path24.join)(workspaceRoot, projectRoot, "project.json");
6635
+ const projectJsonPath = (0, import_node_path25.join)(workspaceRoot, projectRoot, "project.json");
6419
6636
  let hasOverride = false;
6420
6637
  try {
6421
6638
  const projectJson = readJson(projectJsonPath);
@@ -6444,7 +6661,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
6444
6661
  ]) {
6445
6662
  try {
6446
6663
  const targets = extract(
6447
- readJson((0, import_node_path24.join)(workspaceRoot, projectRoot, file))
6664
+ readJson((0, import_node_path25.join)(workspaceRoot, projectRoot, file))
6448
6665
  );
6449
6666
  if (targets && typeof targets === "object") {
6450
6667
  sources.push({
@@ -6460,8 +6677,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
6460
6677
  function checkTargetFilesExist(workspaceRoot) {
6461
6678
  const projectRoots = new Set(
6462
6679
  [
6463
- ...(0, import_node_fs17.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
6464
- ...(0, import_node_fs17.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
6680
+ ...(0, import_node_fs18.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
6681
+ ...(0, import_node_fs18.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
6465
6682
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
6466
6683
  );
6467
6684
  return [...projectRoots].flatMap(
@@ -6476,7 +6693,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
6476
6693
  return TARGET_FILE_OPTIONS.flatMap((option) => {
6477
6694
  const value = target?.options?.[option];
6478
6695
  const checkable = typeof value === "string" && !value.includes("{");
6479
- if (!checkable || fileExists((0, import_node_path24.join)(workspaceRoot, value))) {
6696
+ if (!checkable || fileExists((0, import_node_path25.join)(workspaceRoot, value))) {
6480
6697
  return [];
6481
6698
  }
6482
6699
  return [
@@ -6513,15 +6730,15 @@ function checkGoPluginRegistered(workspaceRoot) {
6513
6730
  };
6514
6731
  }
6515
6732
  function checkGoWorkInSync(workspaceRoot) {
6516
- const goWorkPath = (0, import_node_path24.join)(workspaceRoot, "go.work");
6733
+ const goWorkPath = (0, import_node_path25.join)(workspaceRoot, "go.work");
6517
6734
  if (!fileExists(goWorkPath)) {
6518
6735
  return void 0;
6519
6736
  }
6520
- const contents = (0, import_node_fs17.existsSync)(goWorkPath) ? (0, import_node_fs17.readFileSync)(goWorkPath, "utf8") : "";
6737
+ const contents = (0, import_node_fs18.existsSync)(goWorkPath) ? (0, import_node_fs18.readFileSync)(goWorkPath, "utf8") : "";
6521
6738
  const blockEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+\(([^)]*)\)/g), (match) => match[1].split("\n")).flat();
6522
6739
  const singleEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+(\.\S+)/g), (match) => match[1]);
6523
6740
  const uses = [...blockEntries, ...singleEntries].map((entry) => entry.trim()).filter(Boolean);
6524
- const stale = uses.filter((entry) => !(0, import_node_fs17.existsSync)((0, import_node_path24.join)(workspaceRoot, entry, "go.mod")));
6741
+ const stale = uses.filter((entry) => !(0, import_node_fs18.existsSync)((0, import_node_path25.join)(workspaceRoot, entry, "go.mod")));
6525
6742
  return {
6526
6743
  check: "every go.work `use` entry points to a module that still exists",
6527
6744
  ok: stale.length === 0,
@@ -6537,9 +6754,9 @@ function checkNativeApps(workspaceRoot) {
6537
6754
  { file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
6538
6755
  { file: "azure-pipelines.yml", marker: "- job: native" }
6539
6756
  ];
6540
- const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path24.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6757
+ const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path25.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6541
6758
  check: `${file} builds the native apps on every OS`,
6542
- ok: (0, import_node_fs17.readFileSync)((0, import_node_path24.join)(workspaceRoot, file), "utf8").includes(marker),
6759
+ ok: (0, import_node_fs18.readFileSync)((0, import_node_path25.join)(workspaceRoot, file), "utf8").includes(marker),
6543
6760
  detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
6544
6761
  remedy: "run `mnci upgrade`"
6545
6762
  }));
@@ -6552,7 +6769,7 @@ function checkNativeApps(workspaceRoot) {
6552
6769
  return findings;
6553
6770
  }
6554
6771
  function checkNoRootRuntimeDependencies(workspaceRoot) {
6555
- const manifestPath = (0, import_node_path24.join)(workspaceRoot, "package.json");
6772
+ const manifestPath = (0, import_node_path25.join)(workspaceRoot, "package.json");
6556
6773
  if (!fileExists(manifestPath)) {
6557
6774
  return void 0;
6558
6775
  }
@@ -6572,14 +6789,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
6572
6789
  };
6573
6790
  }
6574
6791
  function checkRollupSourceMaps(workspaceRoot) {
6575
- const configs = (0, import_node_fs17.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6792
+ const configs = (0, import_node_fs18.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6576
6793
  cwd: workspaceRoot
6577
6794
  }).map((config) => toPosix2(config));
6578
6795
  return configs.flatMap((relativePath) => {
6579
- const configPath = (0, import_node_path24.join)(workspaceRoot, relativePath);
6796
+ const configPath = (0, import_node_path25.join)(workspaceRoot, relativePath);
6580
6797
  let config;
6581
6798
  try {
6582
- config = (0, import_node_fs17.readFileSync)(configPath, "utf8");
6799
+ config = (0, import_node_fs18.readFileSync)(configPath, "utf8");
6583
6800
  } catch {
6584
6801
  return [];
6585
6802
  }
@@ -6594,11 +6811,11 @@ function checkRollupSourceMaps(workspaceRoot) {
6594
6811
  });
6595
6812
  }
6596
6813
  function checkDeclarationSpecifiers(workspaceRoot) {
6597
- const configs = (0, import_node_fs17.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6814
+ const configs = (0, import_node_fs18.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6598
6815
  cwd: workspaceRoot
6599
6816
  }).map((config) => toPosix2(config));
6600
6817
  return configs.flatMap((relativePath) => {
6601
- const configPath = (0, import_node_path24.join)(workspaceRoot, relativePath);
6818
+ const configPath = (0, import_node_path25.join)(workspaceRoot, relativePath);
6602
6819
  if (!fileExists(configPath)) {
6603
6820
  return [];
6604
6821
  }
@@ -6632,7 +6849,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
6632
6849
  });
6633
6850
  }
6634
6851
  function collectFindings(workspaceRoot) {
6635
- const nxJsonPath = (0, import_node_path24.join)(workspaceRoot, "nx.json");
6852
+ const nxJsonPath = (0, import_node_path25.join)(workspaceRoot, "nx.json");
6636
6853
  if (!fileExists(nxJsonPath)) {
6637
6854
  throw new Error(
6638
6855
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -6680,8 +6897,8 @@ function runDoctor(workspaceRoot) {
6680
6897
  }
6681
6898
 
6682
6899
  // src/workspace-creation/adopt-directory.use-case.ts
6683
- var import_node_fs18 = require("fs");
6684
- var import_node_path25 = require("path");
6900
+ var import_node_fs19 = require("fs");
6901
+ var import_node_path26 = require("path");
6685
6902
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
6686
6903
  var AGENT_AND_CI_ENTRIES = [
6687
6904
  "AGENTS.md",
@@ -6712,13 +6929,13 @@ var PREFLIGHT_BLOCKERS = [
6712
6929
  "packages"
6713
6930
  ];
6714
6931
  function assertAdoptableDirectory(target) {
6715
- if (!(0, import_node_fs18.existsSync)(target)) {
6932
+ if (!(0, import_node_fs19.existsSync)(target)) {
6716
6933
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
6717
6934
  }
6718
- if (!(0, import_node_fs18.statSync)(target).isDirectory()) {
6935
+ if (!(0, import_node_fs19.statSync)(target).isDirectory()) {
6719
6936
  throw new Error(`--into '${target}' is not a directory.`);
6720
6937
  }
6721
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs18.existsSync)((0, import_node_path25.join)(target, entry)));
6938
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs19.existsSync)((0, import_node_path26.join)(target, entry)));
6722
6939
  if (blockers.length > 0) {
6723
6940
  throw new Error(
6724
6941
  `--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.`
@@ -6726,15 +6943,15 @@ function assertAdoptableDirectory(target) {
6726
6943
  }
6727
6944
  }
6728
6945
  function mergeGitignore(generatedFile, targetFile) {
6729
- const existing = (0, import_node_fs18.readFileSync)(targetFile, "utf8");
6946
+ const existing = (0, import_node_fs19.readFileSync)(targetFile, "utf8");
6730
6947
  const present = new Set(existing.split("\n").map((line) => line.trim()));
6731
- const additions = (0, import_node_fs18.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
6948
+ const additions = (0, import_node_fs19.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
6732
6949
  const trimmed = line.trim();
6733
6950
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
6734
6951
  });
6735
6952
  if (additions.length === 0) return false;
6736
6953
  const separator = existing.endsWith("\n") ? "" : "\n";
6737
- (0, import_node_fs18.writeFileSync)(
6954
+ (0, import_node_fs19.writeFileSync)(
6738
6955
  targetFile,
6739
6956
  `${existing}${separator}
6740
6957
  # Added by mnci (Nx workspace)
@@ -6744,9 +6961,9 @@ ${additions.join("\n")}
6744
6961
  return true;
6745
6962
  }
6746
6963
  function adoptGeneratedWorkspace(generatedRoot, target) {
6747
- const entries = (0, import_node_fs18.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6964
+ const entries = (0, import_node_fs19.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6748
6965
  const collisions = entries.filter(
6749
- (entry) => (0, import_node_fs18.existsSync)((0, import_node_path25.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6966
+ (entry) => (0, import_node_fs19.existsSync)((0, import_node_path26.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6750
6967
  );
6751
6968
  if (collisions.length > 0) {
6752
6969
  throw new Error(
@@ -6755,28 +6972,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
6755
6972
  }
6756
6973
  const result = { copied: [], kept: [], mergedGitignore: false };
6757
6974
  for (const entry of entries) {
6758
- const from = (0, import_node_path25.join)(generatedRoot, entry);
6759
- const to = (0, import_node_path25.join)(target, entry);
6760
- if (entry === ".gitignore" && (0, import_node_fs18.existsSync)(to)) {
6975
+ const from = (0, import_node_path26.join)(generatedRoot, entry);
6976
+ const to = (0, import_node_path26.join)(target, entry);
6977
+ if (entry === ".gitignore" && (0, import_node_fs19.existsSync)(to)) {
6761
6978
  result.mergedGitignore = mergeGitignore(from, to);
6762
6979
  result.kept.push(entry);
6763
6980
  continue;
6764
6981
  }
6765
- if ((0, import_node_fs18.existsSync)(to)) {
6982
+ if ((0, import_node_fs19.existsSync)(to)) {
6766
6983
  result.kept.push(entry);
6767
6984
  continue;
6768
6985
  }
6769
- (0, import_node_fs18.cpSync)(from, to, { recursive: true });
6986
+ (0, import_node_fs19.cpSync)(from, to, { recursive: true });
6770
6987
  result.copied.push(entry);
6771
6988
  }
6772
- (0, import_node_fs18.rmSync)(generatedRoot, { recursive: true, force: true });
6989
+ (0, import_node_fs19.rmSync)(generatedRoot, { recursive: true, force: true });
6773
6990
  return result;
6774
6991
  }
6775
6992
 
6776
6993
  // src/workspace-creation/create-workspace.use-case.ts
6777
- var import_node_fs19 = require("fs");
6994
+ var import_node_fs20 = require("fs");
6778
6995
  var import_node_os = require("os");
6779
- var import_node_path26 = require("path");
6996
+ var import_node_path27 = require("path");
6780
6997
  function nxCloudProviderValue(ci) {
6781
6998
  return ci === "azure" ? "azure" : "github";
6782
6999
  }
@@ -6819,9 +7036,9 @@ async function resolveRegistry(options) {
6819
7036
  return await promptRegistry();
6820
7037
  }
6821
7038
  async function runNew(name, options) {
6822
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path26.resolve)(process.cwd(), options.into);
7039
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path27.resolve)(process.cwd(), options.into);
6823
7040
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
6824
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path26.basename)(adoptTarget));
7041
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path27.basename)(adoptTarget));
6825
7042
  assertValidProjectName(workspaceName, "Workspace name");
6826
7043
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
6827
7044
  const registry = await resolveRegistry(options);
@@ -6834,8 +7051,8 @@ async function runNew(name, options) {
6834
7051
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
6835
7052
  const stack = await resolveStack(options);
6836
7053
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
6837
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs19.mkdtempSync)((0, import_node_path26.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
6838
- let workspaceRoot = (0, import_node_path26.join)(stagingParent, workspaceName);
7054
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs20.mkdtempSync)((0, import_node_path27.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
7055
+ let workspaceRoot = (0, import_node_path27.join)(stagingParent, workspaceName);
6839
7056
  try {
6840
7057
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
6841
7058
  runNpx(
@@ -6858,7 +7075,7 @@ async function runNew(name, options) {
6858
7075
  workspaceRoot = adoptTarget;
6859
7076
  }
6860
7077
  } finally {
6861
- if (adoptTarget !== void 0) (0, import_node_fs19.rmSync)(stagingParent, { recursive: true, force: true });
7078
+ if (adoptTarget !== void 0) (0, import_node_fs20.rmSync)(stagingParent, { recursive: true, force: true });
6862
7079
  }
6863
7080
  logger.step(
6864
7081
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -6868,8 +7085,8 @@ async function runNew(name, options) {
6868
7085
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
6869
7086
  logger.detail
6870
7087
  );
6871
- (0, import_node_fs19.rmSync)((0, import_node_path26.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
6872
- (0, import_node_fs19.rmSync)((0, import_node_path26.join)(workspaceRoot, "package-lock.json"), { force: true });
7088
+ (0, import_node_fs20.rmSync)((0, import_node_path27.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
7089
+ (0, import_node_fs20.rmSync)((0, import_node_path27.join)(workspaceRoot, "package-lock.json"), { force: true });
6873
7090
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
6874
7091
  const installStatus = runShell(
6875
7092
  "npm",
@@ -6907,12 +7124,12 @@ function projectKindHintLines(kinds = PROJECT_KINDS) {
6907
7124
  }
6908
7125
 
6909
7126
  // src/workspace-creation/interactive-wizard.use-case.ts
6910
- var import_node_path28 = require("path");
7127
+ var import_node_path29 = require("path");
6911
7128
  var import_prompts4 = require("@inquirer/prompts");
6912
7129
 
6913
7130
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
6914
- var import_node_fs20 = require("fs");
6915
- var import_node_path27 = require("path");
7131
+ var import_node_fs21 = require("fs");
7132
+ var import_node_path28 = require("path");
6916
7133
  function resolveRegistry2(options, persisted) {
6917
7134
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
6918
7135
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -6941,7 +7158,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6941
7158
  return persisted.workspaceName;
6942
7159
  }
6943
7160
  try {
6944
- const existing = (0, import_node_fs20.readdirSync)(workspaceRoot).find(
7161
+ const existing = (0, import_node_fs21.readdirSync)(workspaceRoot).find(
6945
7162
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
6946
7163
  );
6947
7164
  if (existing) {
@@ -6949,11 +7166,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6949
7166
  }
6950
7167
  } catch {
6951
7168
  }
6952
- return (0, import_node_path27.basename)(workspaceRoot);
7169
+ return (0, import_node_path28.basename)(workspaceRoot);
6953
7170
  }
6954
7171
  function detectNpmAuth(workspaceRoot) {
6955
7172
  try {
6956
- return (0, import_node_fs20.readFileSync)((0, import_node_path27.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
7173
+ return (0, import_node_fs21.readFileSync)((0, import_node_path28.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6957
7174
  } catch {
6958
7175
  return void 0;
6959
7176
  }
@@ -7000,7 +7217,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
7000
7217
  };
7001
7218
  }
7002
7219
  function runUpgrade(workspaceRoot, options) {
7003
- if (!fileExists((0, import_node_path27.join)(workspaceRoot, "nx.json"))) {
7220
+ if (!fileExists((0, import_node_path28.join)(workspaceRoot, "nx.json"))) {
7004
7221
  throw new Error(
7005
7222
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
7006
7223
  );
@@ -7065,7 +7282,7 @@ function runUpgrade(workspaceRoot, options) {
7065
7282
 
7066
7283
  // src/workspace-creation/interactive-wizard.use-case.ts
7067
7284
  async function runInteractive() {
7068
- const inWorkspace = fileExists((0, import_node_path28.join)(process.cwd(), "nx.json"));
7285
+ const inWorkspace = fileExists((0, import_node_path29.join)(process.cwd(), "nx.json"));
7069
7286
  const choiceNew = { name: "Create a new monorepo", value: "new" };
7070
7287
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
7071
7288
  const choiceUpgrade = {
@@ -7086,8 +7303,8 @@ async function runInteractive() {
7086
7303
  }
7087
7304
 
7088
7305
  // src/cli-version/check-for-update.use-case.ts
7089
- var import_node_fs21 = require("fs");
7090
- var import_node_path29 = require("path");
7306
+ var import_node_fs22 = require("fs");
7307
+ var import_node_path30 = require("path");
7091
7308
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
7092
7309
  var PACKAGE_NAME = "@mnci/cli";
7093
7310
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -7143,8 +7360,8 @@ function releaseTriple(version) {
7143
7360
  }
7144
7361
  function readCliVersion(packageDirectory) {
7145
7362
  try {
7146
- const manifestPath = (0, import_node_path29.join)(packageDirectory, "..", "package.json");
7147
- const manifest = JSON.parse((0, import_node_fs21.readFileSync)(manifestPath, "utf8"));
7363
+ const manifestPath = (0, import_node_path30.join)(packageDirectory, "..", "package.json");
7364
+ const manifest = JSON.parse((0, import_node_fs22.readFileSync)(manifestPath, "utf8"));
7148
7365
  return manifest.version ?? "0.0.0";
7149
7366
  } catch {
7150
7367
  return "0.0.0";
@@ -7198,6 +7415,11 @@ function buildProgram(cliVersion) {
7198
7415
  ).option("--check", "report only; never prompt and never write (the default when piped)").option("-y, --yes", "select every available update without prompting").option("--ecosystem <name>", "restrict to one ecosystem: npm | pip | pub | go").option("--no-install", "update the manifests but skip the reinstall step").action(async (options) => {
7199
7416
  await runUp(process.cwd(), options);
7200
7417
  });
7418
+ program.command("install").alias("i").argument("[packages...]", "packages to add (a bare name or a pinned spec); omit to install only").description(
7419
+ "Add a dependency to a specific project using its own toolchain (npm/pip/pub/nuget/go), or \u2014 with no package \u2014 install everything. Each project owns its dependencies, so a package needs a target: 'mnci i -w <project> <package>'"
7420
+ ).option("-w, --workspace <project...>", "target project, by directory (apps/foo) or basename (foo); repeatable").option("-D, --save-dev", "add as a development dependency, where the ecosystem distinguishes one").action((packages, options) => {
7421
+ runInstall(process.cwd(), packages, options);
7422
+ });
7201
7423
  program.command("add").addArgument(new import_commander.Argument("[kind]", "project kind").choices(PROJECT_KINDS)).argument("[name]", "project name").description("Add a project by delegating to the matching Nx plugin generator").option("--scope <scope>", "npm scope for a publishable lib (defaults to @<workspace name>)").option(
7202
7424
  "--framework <framework>",
7203
7425
  "node-app only: express | fastify | koa | nest | none (default: none)"