@mnci/cli 4.18.0 → 4.19.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
@@ -4999,7 +4999,8 @@ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4999
4999
  refreshLockFile(workspaceRoot, name);
5000
5000
  }
5001
5001
 
5002
- // src/dependency-management/sync-dependencies.use-case.ts
5002
+ // src/dependency-management/install-dependencies.use-case.ts
5003
+ var import_node_fs17 = require("fs");
5003
5004
  var import_node_path21 = require("path");
5004
5005
 
5005
5006
  // src/dependency-management/manifest.repository.ts
@@ -5330,6 +5331,27 @@ function collectInventory(workspaceRoot, ecosystems = ECOSYSTEMS) {
5330
5331
  }
5331
5332
  return inventory;
5332
5333
  }
5334
+ var PROJECT_GLOBS = {
5335
+ ...MANIFEST_GLOBS,
5336
+ go: ["apps/*/go.mod", "libs/*/go.mod", "packages/*/go.mod"]
5337
+ };
5338
+ function locateProjects(workspaceRoot) {
5339
+ const locations = [];
5340
+ for (const ecosystem of ECOSYSTEMS) {
5341
+ const relativePaths = (0, import_node_fs16.globSync)(PROJECT_GLOBS[ecosystem], { cwd: workspaceRoot });
5342
+ for (const relativePath of relativePaths) {
5343
+ const posix = toPosix(relativePath);
5344
+ const dir = posix.slice(0, posix.lastIndexOf("/"));
5345
+ locations.push({
5346
+ ecosystem,
5347
+ dir,
5348
+ name: dir.slice(dir.lastIndexOf("/") + 1),
5349
+ manifestPath: (0, import_node_path20.join)(workspaceRoot, relativePath)
5350
+ });
5351
+ }
5352
+ }
5353
+ return locations;
5354
+ }
5333
5355
  function rewriteSpec(site, spec) {
5334
5356
  if (!site.rewritable || spec === site.spec) {
5335
5357
  return false;
@@ -5379,6 +5401,41 @@ function replacePipSpec(content, name, spec) {
5379
5401
  (match, lead, matched) => `${lead}${matched}${spec}`
5380
5402
  );
5381
5403
  }
5404
+ function addPipDependency(content, entry) {
5405
+ const name = parseRequirement(entry)?.name;
5406
+ const already = name !== void 0 && pyprojectDependencies(content).some((existing) => parseRequirement(existing)?.name === name);
5407
+ if (already) {
5408
+ return content;
5409
+ }
5410
+ const newline = content.includes("\r\n") ? "\r\n" : "\n";
5411
+ const lines = content.split(/\r?\n/);
5412
+ const quoted = `"${entry}"`;
5413
+ let inProjectTable = false;
5414
+ for (let index = 0; index < lines.length; index++) {
5415
+ const trimmed = lines[index].trim();
5416
+ if (trimmed.startsWith("[")) {
5417
+ inProjectTable = trimmed === "[project]";
5418
+ continue;
5419
+ }
5420
+ if (!inProjectTable) {
5421
+ continue;
5422
+ }
5423
+ const opener = /^(\s*)dependencies\s*=\s*\[(.*)$/.exec(lines[index]);
5424
+ if (!opener) {
5425
+ continue;
5426
+ }
5427
+ const [, indent, rest] = opener;
5428
+ if (rest.includes("]")) {
5429
+ const inner = rest.slice(0, rest.lastIndexOf("]")).trim().replace(/,+\s*$/, "");
5430
+ const list = inner.length > 0 ? `${inner}, ${quoted}` : quoted;
5431
+ lines[index] = `${indent}dependencies = [${list}]`;
5432
+ } else {
5433
+ lines.splice(index + 1, 0, `${indent} ${quoted},`);
5434
+ }
5435
+ return lines.join(newline);
5436
+ }
5437
+ return content;
5438
+ }
5382
5439
  function replacePubSpec(content, name, spec) {
5383
5440
  return content.replaceAll(
5384
5441
  new RegExp(String.raw`^(\s+${escapeForRegex(name)}:[^\S\n]*)\S[^\n]*$`, "gm"),
@@ -5450,6 +5507,158 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
5450
5507
  return void 0;
5451
5508
  }
5452
5509
 
5510
+ // src/dependency-management/install-dependencies.use-case.ts
5511
+ var WHOLE_WORKSPACE_INSTALL = [
5512
+ ["npm", "npm", ["install"]],
5513
+ ["pip", "npm", ["run", "python:install"]],
5514
+ ["pub", "flutter", ["pub", "get"]],
5515
+ ["nuget", "npx", ["nx", "run-many", "-t", "restore"]],
5516
+ ["go", "go", ["work", "sync"]]
5517
+ ];
5518
+ function runInstall(workspaceRoot, packages, options = {}) {
5519
+ const targets = options.workspace ?? [];
5520
+ if (targets.length === 0) {
5521
+ if (packages.length > 0) {
5522
+ logger.error(
5523
+ "Adding a package needs a target project \u2014 'mnci install -w <project> <package>'. A bare 'mnci install' (no package) installs the whole workspace"
5524
+ );
5525
+ process.exitCode = 1;
5526
+ return;
5527
+ }
5528
+ installEverything(workspaceRoot);
5529
+ return;
5530
+ }
5531
+ const locations = locateProjects(workspaceRoot);
5532
+ for (const target of targets) {
5533
+ const location = resolveTarget(locations, target);
5534
+ if (location === void 0) {
5535
+ logger.error(
5536
+ `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`
5537
+ );
5538
+ process.exitCode = 1;
5539
+ continue;
5540
+ }
5541
+ installInto(workspaceRoot, location, packages, Boolean(options.saveDev));
5542
+ }
5543
+ }
5544
+ function resolveTarget(locations, target) {
5545
+ const byDir = locations.find((location) => location.dir === target);
5546
+ if (byDir !== void 0) {
5547
+ return byDir;
5548
+ }
5549
+ const byName = locations.filter((location) => location.name === target);
5550
+ if (byName.length > 1) {
5551
+ logger.error(
5552
+ `'${target}' matches ${byName.length} projects (${byName.map((match) => match.dir).join(", ")}) \u2014 name it by directory`
5553
+ );
5554
+ return void 0;
5555
+ }
5556
+ return byName[0];
5557
+ }
5558
+ function installInto(workspaceRoot, location, packages, saveDev) {
5559
+ const projectDir = (0, import_node_path21.join)(workspaceRoot, location.dir);
5560
+ switch (location.ecosystem) {
5561
+ case "npm": {
5562
+ const flags = saveDev ? ["--save-dev"] : [];
5563
+ shell(workspaceRoot, "npm", ["install", ...packages, ...flags, "-w", location.dir], location);
5564
+ return;
5565
+ }
5566
+ case "go": {
5567
+ shell(projectDir, "go", packages.length > 0 ? ["get", ...packages] : ["mod", "download"], location);
5568
+ if (packages.length > 0) {
5569
+ runShell("go", ["work", "sync"], workspaceRoot);
5570
+ }
5571
+ return;
5572
+ }
5573
+ case "nuget": {
5574
+ if (packages.length === 0) {
5575
+ shell(workspaceRoot, "dotnet", ["restore", location.manifestPath], location);
5576
+ return;
5577
+ }
5578
+ for (const specifier of packages) {
5579
+ const [name, version] = splitAtLast(specifier, "@");
5580
+ const versionFlag = version === void 0 ? [] : ["--version", version];
5581
+ shell(workspaceRoot, "dotnet", ["add", location.manifestPath, "package", name, ...versionFlag], location);
5582
+ }
5583
+ return;
5584
+ }
5585
+ case "pub": {
5586
+ const devFlag = saveDev ? ["--dev"] : [];
5587
+ shell(
5588
+ projectDir,
5589
+ "flutter",
5590
+ packages.length > 0 ? ["pub", "add", ...devFlag, ...packages] : ["pub", "get"],
5591
+ location
5592
+ );
5593
+ return;
5594
+ }
5595
+ case "pip": {
5596
+ if (saveDev) {
5597
+ logger.warn(
5598
+ "pip has no per-project dev-dependency section \u2014 adding to [project].dependencies (dev tools live in the root requirements-dev.txt)"
5599
+ );
5600
+ }
5601
+ for (const specifier of packages) {
5602
+ addPythonDependency(location.manifestPath, specifier);
5603
+ }
5604
+ installEverything(workspaceRoot, ["pip"]);
5605
+ return;
5606
+ }
5607
+ }
5608
+ }
5609
+ function addPythonDependency(manifestPath, specifier) {
5610
+ let content;
5611
+ try {
5612
+ content = (0, import_node_fs17.readFileSync)(manifestPath, "utf8");
5613
+ } catch {
5614
+ logger.warn(`Could not read ${manifestPath} \u2014 skipped ${specifier}`);
5615
+ return;
5616
+ }
5617
+ const updated = addPipDependency(content, specifier);
5618
+ if (updated === content) {
5619
+ logger.info(`${specifier} is already declared \u2014 left as is`);
5620
+ return;
5621
+ }
5622
+ writeFileEnsured(manifestPath, updated);
5623
+ logger.step(`Added ${specifier} to ${manifestPath}`);
5624
+ }
5625
+ function installEverything(workspaceRoot, only) {
5626
+ for (const [ecosystem, command, arguments_] of WHOLE_WORKSPACE_INSTALL) {
5627
+ if (only !== void 0 && !only.includes(ecosystem)) {
5628
+ continue;
5629
+ }
5630
+ if (!ecosystemPresent(workspaceRoot, ecosystem)) {
5631
+ continue;
5632
+ }
5633
+ logger.step(`Installing ${ecosystem} dependencies (${command} ${arguments_.join(" ")})`);
5634
+ if (runShell(command, [...arguments_], workspaceRoot) !== 0) {
5635
+ logger.warn(`${command} ${arguments_.join(" ")} failed \u2014 re-run it once the cause is fixed`);
5636
+ }
5637
+ }
5638
+ }
5639
+ function ecosystemPresent(workspaceRoot, ecosystem) {
5640
+ if (ecosystem === "go") {
5641
+ return fileExists((0, import_node_path21.join)(workspaceRoot, "go.work")) || fileExists((0, import_node_path21.join)(workspaceRoot, "go.mod"));
5642
+ }
5643
+ return hasEcosystem(workspaceRoot, ecosystem);
5644
+ }
5645
+ function shell(cwd, command, arguments_, location) {
5646
+ logger.step(`${location.dir}: ${command} ${arguments_.join(" ")}`);
5647
+ if (runShell(command, [...arguments_], cwd) !== 0) {
5648
+ logger.warn(`${command} ${arguments_.join(" ")} failed in ${location.dir}`);
5649
+ }
5650
+ }
5651
+ function splitAtLast(value, separator) {
5652
+ const at = value.lastIndexOf(separator);
5653
+ if (at <= 0) {
5654
+ return [value, void 0];
5655
+ }
5656
+ return [value.slice(0, at), value.slice(at + 1)];
5657
+ }
5658
+
5659
+ // src/dependency-management/sync-dependencies.use-case.ts
5660
+ var import_node_path22 = require("path");
5661
+
5453
5662
  // src/dependency-management/semver.algorithm.ts
5454
5663
  var UPDATE_KINDS = ["patch", "minor", "major", "non-semver"];
5455
5664
  var UPDATE_KIND_LABELS = {
@@ -5625,7 +5834,7 @@ function describe(finding) {
5625
5834
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
5626
5835
  }
5627
5836
  function runSync(workspaceRoot, options) {
5628
- if (!fileExists((0, import_node_path21.join)(workspaceRoot, "nx.json"))) {
5837
+ if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
5629
5838
  throw new Error(
5630
5839
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
5631
5840
  );
@@ -5675,7 +5884,7 @@ function runSync(workspaceRoot, options) {
5675
5884
  }
5676
5885
 
5677
5886
  // src/dependency-management/update-dependencies.use-case.ts
5678
- var import_node_path22 = require("path");
5887
+ var import_node_path23 = require("path");
5679
5888
  var import_prompts2 = require("@inquirer/prompts");
5680
5889
 
5681
5890
  // src/dependency-management/registry.client.ts
@@ -5958,7 +6167,7 @@ function reinstall(workspaceRoot, ecosystems) {
5958
6167
  function hasPythonInstallScript(workspaceRoot) {
5959
6168
  try {
5960
6169
  const manifest = readJson(
5961
- (0, import_node_path22.join)(workspaceRoot, "package.json")
6170
+ (0, import_node_path23.join)(workspaceRoot, "package.json")
5962
6171
  );
5963
6172
  return manifest.scripts?.["python:install"] !== void 0;
5964
6173
  } catch {
@@ -5974,7 +6183,7 @@ function applyGoUpdates(workspaceRoot, entries) {
5974
6183
  }
5975
6184
  }
5976
6185
  async function runUp(workspaceRoot, options) {
5977
- if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
6186
+ if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
5978
6187
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
5979
6188
  }
5980
6189
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -6050,7 +6259,7 @@ var PROJECT_KINDS = [
6050
6259
  ];
6051
6260
  async function runAdd(kind, name, options) {
6052
6261
  const workspaceRoot = process.cwd();
6053
- if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
6262
+ if (!fileExists((0, import_node_path24.join)(workspaceRoot, "nx.json"))) {
6054
6263
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
6055
6264
  }
6056
6265
  const stack = readWorkspaceStack(workspaceRoot);
@@ -6110,8 +6319,8 @@ async function runAdd(kind, name, options) {
6110
6319
  ],
6111
6320
  workspaceRoot
6112
6321
  );
6113
- markPrivate((0, import_node_path23.join)(workspaceRoot, "libs", resolvedName, "package.json"));
6114
- renameScaffoldPlaceholder((0, import_node_path23.join)(workspaceRoot, "libs", resolvedName), resolvedName);
6322
+ markPrivate((0, import_node_path24.join)(workspaceRoot, "libs", resolvedName, "package.json"));
6323
+ renameScaffoldPlaceholder((0, import_node_path24.join)(workspaceRoot, "libs", resolvedName), resolvedName);
6115
6324
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
6116
6325
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
6117
6326
  break;
@@ -6203,7 +6412,7 @@ async function runAdd(kind, name, options) {
6203
6412
  }
6204
6413
  function readWorkspaceStack(workspaceRoot) {
6205
6414
  const nxJson = readJson(
6206
- (0, import_node_path23.join)(workspaceRoot, "nx.json")
6415
+ (0, import_node_path24.join)(workspaceRoot, "nx.json")
6207
6416
  );
6208
6417
  const stack = nxJson.mnci?.stack;
6209
6418
  return {
@@ -6213,15 +6422,15 @@ function readWorkspaceStack(workspaceRoot) {
6213
6422
 
6214
6423
  // src/workspace-diagnostics/check-invariants.use-case.ts
6215
6424
  var import_node_child_process = require("child_process");
6216
- var import_node_fs17 = require("fs");
6217
- var import_node_path24 = require("path");
6425
+ var import_node_fs18 = require("fs");
6426
+ var import_node_path25 = require("path");
6218
6427
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
6219
6428
  function toPosix2(path) {
6220
6429
  return path.replaceAll("\\", "/");
6221
6430
  }
6222
6431
  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}", {
6432
+ const rootConfigs = (0, import_node_fs18.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
6433
+ const projectConfigs = (0, import_node_fs18.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
6225
6434
  cwd: workspaceRoot
6226
6435
  }).map((config) => toPosix2(config));
6227
6436
  return [
@@ -6241,10 +6450,10 @@ function checkEslintConfigs(workspaceRoot) {
6241
6450
  ];
6242
6451
  }
6243
6452
  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") : "";
6453
+ const rules = (0, import_node_path25.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
6454
+ if (!(0, import_node_fs18.existsSync)(rules)) return [];
6455
+ const entryPoint = (0, import_node_path25.join)(workspaceRoot, ESLINT_USER_FILENAME);
6456
+ const source = (0, import_node_fs18.existsSync)(entryPoint) ? (0, import_node_fs18.readFileSync)(entryPoint, "utf8") : "";
6248
6457
  return [
6249
6458
  {
6250
6459
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -6257,7 +6466,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
6257
6466
  function declaredDevDependencies(workspaceRoot) {
6258
6467
  try {
6259
6468
  const manifest = readJson(
6260
- (0, import_node_path24.join)(workspaceRoot, "package.json")
6469
+ (0, import_node_path25.join)(workspaceRoot, "package.json")
6261
6470
  );
6262
6471
  return manifest.devDependencies ?? {};
6263
6472
  } catch {
@@ -6265,7 +6474,7 @@ function declaredDevDependencies(workspaceRoot) {
6265
6474
  }
6266
6475
  }
6267
6476
  function checkNoRetiredFormatter(workspaceRoot) {
6268
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path24.join)(workspaceRoot, file)));
6477
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path25.join)(workspaceRoot, file)));
6269
6478
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
6270
6479
  const stale = [...files, ...declared];
6271
6480
  if (stale.length === 0) {
@@ -6291,7 +6500,7 @@ function checkEslintPlugin(nxJson) {
6291
6500
  };
6292
6501
  }
6293
6502
  function checkResolvedEslint(workspaceRoot) {
6294
- const manifestPath = (0, import_node_path24.join)(workspaceRoot, "node_modules/eslint/package.json");
6503
+ const manifestPath = (0, import_node_path25.join)(workspaceRoot, "node_modules/eslint/package.json");
6295
6504
  if (!fileExists(manifestPath)) {
6296
6505
  return void 0;
6297
6506
  }
@@ -6309,11 +6518,11 @@ function checkResolvedEslint(workspaceRoot) {
6309
6518
  }
6310
6519
  }
6311
6520
  function checkNpmrc(workspaceRoot, registry, scope) {
6312
- const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
6521
+ const npmrcPath = (0, import_node_path25.join)(workspaceRoot, ".npmrc");
6313
6522
  if (!registry || !fileExists(npmrcPath)) {
6314
6523
  return void 0;
6315
6524
  }
6316
- const npmrc = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8");
6525
+ const npmrc = (0, import_node_fs18.readFileSync)(npmrcPath, "utf8");
6317
6526
  if (registry.kind === "npm") {
6318
6527
  return {
6319
6528
  check: ".npmrc authenticates the public registry",
@@ -6330,11 +6539,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
6330
6539
  };
6331
6540
  }
6332
6541
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
6333
- const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
6542
+ const npmrcPath = (0, import_node_path25.join)(workspaceRoot, ".npmrc");
6334
6543
  if (!fileExists(npmrcPath)) {
6335
6544
  return void 0;
6336
6545
  }
6337
- const npmrc = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8");
6546
+ const npmrc = (0, import_node_fs18.readFileSync)(npmrcPath, "utf8");
6338
6547
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
6339
6548
  const referenced = [
6340
6549
  ...new Set(
@@ -6358,13 +6567,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
6358
6567
  };
6359
6568
  }
6360
6569
  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");
6570
+ const npmrcPath = (0, import_node_path25.join)(workspaceRoot, ".npmrc");
6571
+ const pipelinePath = (0, import_node_path25.join)(workspaceRoot, "azure-pipelines.yml");
6363
6572
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
6364
6573
  return void 0;
6365
6574
  }
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");
6575
+ 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));
6576
+ const runsTask = (0, import_node_fs18.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
6368
6577
  if (!holdsCredentials && !runsTask) {
6369
6578
  return {
6370
6579
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -6409,13 +6618,13 @@ function npmjsCredentialShape(credentials, environment) {
6409
6618
  }
6410
6619
  function checkVersionActions(workspaceRoot) {
6411
6620
  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 })
6621
+ ...(0, import_node_fs18.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
6622
+ ...(0, import_node_fs18.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
6623
+ ...(0, import_node_fs18.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
6415
6624
  ].map((manifest) => toPosix2(manifest));
6416
6625
  return candidates.flatMap((manifest) => {
6417
6626
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
6418
- const projectJsonPath = (0, import_node_path24.join)(workspaceRoot, projectRoot, "project.json");
6627
+ const projectJsonPath = (0, import_node_path25.join)(workspaceRoot, projectRoot, "project.json");
6419
6628
  let hasOverride = false;
6420
6629
  try {
6421
6630
  const projectJson = readJson(projectJsonPath);
@@ -6444,7 +6653,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
6444
6653
  ]) {
6445
6654
  try {
6446
6655
  const targets = extract(
6447
- readJson((0, import_node_path24.join)(workspaceRoot, projectRoot, file))
6656
+ readJson((0, import_node_path25.join)(workspaceRoot, projectRoot, file))
6448
6657
  );
6449
6658
  if (targets && typeof targets === "object") {
6450
6659
  sources.push({
@@ -6460,8 +6669,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
6460
6669
  function checkTargetFilesExist(workspaceRoot) {
6461
6670
  const projectRoots = new Set(
6462
6671
  [
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 })
6672
+ ...(0, import_node_fs18.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
6673
+ ...(0, import_node_fs18.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
6465
6674
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
6466
6675
  );
6467
6676
  return [...projectRoots].flatMap(
@@ -6476,7 +6685,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
6476
6685
  return TARGET_FILE_OPTIONS.flatMap((option) => {
6477
6686
  const value = target?.options?.[option];
6478
6687
  const checkable = typeof value === "string" && !value.includes("{");
6479
- if (!checkable || fileExists((0, import_node_path24.join)(workspaceRoot, value))) {
6688
+ if (!checkable || fileExists((0, import_node_path25.join)(workspaceRoot, value))) {
6480
6689
  return [];
6481
6690
  }
6482
6691
  return [
@@ -6513,15 +6722,15 @@ function checkGoPluginRegistered(workspaceRoot) {
6513
6722
  };
6514
6723
  }
6515
6724
  function checkGoWorkInSync(workspaceRoot) {
6516
- const goWorkPath = (0, import_node_path24.join)(workspaceRoot, "go.work");
6725
+ const goWorkPath = (0, import_node_path25.join)(workspaceRoot, "go.work");
6517
6726
  if (!fileExists(goWorkPath)) {
6518
6727
  return void 0;
6519
6728
  }
6520
- const contents = (0, import_node_fs17.existsSync)(goWorkPath) ? (0, import_node_fs17.readFileSync)(goWorkPath, "utf8") : "";
6729
+ const contents = (0, import_node_fs18.existsSync)(goWorkPath) ? (0, import_node_fs18.readFileSync)(goWorkPath, "utf8") : "";
6521
6730
  const blockEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+\(([^)]*)\)/g), (match) => match[1].split("\n")).flat();
6522
6731
  const singleEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+(\.\S+)/g), (match) => match[1]);
6523
6732
  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")));
6733
+ const stale = uses.filter((entry) => !(0, import_node_fs18.existsSync)((0, import_node_path25.join)(workspaceRoot, entry, "go.mod")));
6525
6734
  return {
6526
6735
  check: "every go.work `use` entry points to a module that still exists",
6527
6736
  ok: stale.length === 0,
@@ -6537,9 +6746,9 @@ function checkNativeApps(workspaceRoot) {
6537
6746
  { file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
6538
6747
  { file: "azure-pipelines.yml", marker: "- job: native" }
6539
6748
  ];
6540
- const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path24.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6749
+ const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path25.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6541
6750
  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),
6751
+ ok: (0, import_node_fs18.readFileSync)((0, import_node_path25.join)(workspaceRoot, file), "utf8").includes(marker),
6543
6752
  detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
6544
6753
  remedy: "run `mnci upgrade`"
6545
6754
  }));
@@ -6552,7 +6761,7 @@ function checkNativeApps(workspaceRoot) {
6552
6761
  return findings;
6553
6762
  }
6554
6763
  function checkNoRootRuntimeDependencies(workspaceRoot) {
6555
- const manifestPath = (0, import_node_path24.join)(workspaceRoot, "package.json");
6764
+ const manifestPath = (0, import_node_path25.join)(workspaceRoot, "package.json");
6556
6765
  if (!fileExists(manifestPath)) {
6557
6766
  return void 0;
6558
6767
  }
@@ -6572,14 +6781,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
6572
6781
  };
6573
6782
  }
6574
6783
  function checkRollupSourceMaps(workspaceRoot) {
6575
- const configs = (0, import_node_fs17.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6784
+ const configs = (0, import_node_fs18.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6576
6785
  cwd: workspaceRoot
6577
6786
  }).map((config) => toPosix2(config));
6578
6787
  return configs.flatMap((relativePath) => {
6579
- const configPath = (0, import_node_path24.join)(workspaceRoot, relativePath);
6788
+ const configPath = (0, import_node_path25.join)(workspaceRoot, relativePath);
6580
6789
  let config;
6581
6790
  try {
6582
- config = (0, import_node_fs17.readFileSync)(configPath, "utf8");
6791
+ config = (0, import_node_fs18.readFileSync)(configPath, "utf8");
6583
6792
  } catch {
6584
6793
  return [];
6585
6794
  }
@@ -6594,11 +6803,11 @@ function checkRollupSourceMaps(workspaceRoot) {
6594
6803
  });
6595
6804
  }
6596
6805
  function checkDeclarationSpecifiers(workspaceRoot) {
6597
- const configs = (0, import_node_fs17.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6806
+ const configs = (0, import_node_fs18.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6598
6807
  cwd: workspaceRoot
6599
6808
  }).map((config) => toPosix2(config));
6600
6809
  return configs.flatMap((relativePath) => {
6601
- const configPath = (0, import_node_path24.join)(workspaceRoot, relativePath);
6810
+ const configPath = (0, import_node_path25.join)(workspaceRoot, relativePath);
6602
6811
  if (!fileExists(configPath)) {
6603
6812
  return [];
6604
6813
  }
@@ -6632,7 +6841,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
6632
6841
  });
6633
6842
  }
6634
6843
  function collectFindings(workspaceRoot) {
6635
- const nxJsonPath = (0, import_node_path24.join)(workspaceRoot, "nx.json");
6844
+ const nxJsonPath = (0, import_node_path25.join)(workspaceRoot, "nx.json");
6636
6845
  if (!fileExists(nxJsonPath)) {
6637
6846
  throw new Error(
6638
6847
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -6680,8 +6889,8 @@ function runDoctor(workspaceRoot) {
6680
6889
  }
6681
6890
 
6682
6891
  // src/workspace-creation/adopt-directory.use-case.ts
6683
- var import_node_fs18 = require("fs");
6684
- var import_node_path25 = require("path");
6892
+ var import_node_fs19 = require("fs");
6893
+ var import_node_path26 = require("path");
6685
6894
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
6686
6895
  var AGENT_AND_CI_ENTRIES = [
6687
6896
  "AGENTS.md",
@@ -6712,13 +6921,13 @@ var PREFLIGHT_BLOCKERS = [
6712
6921
  "packages"
6713
6922
  ];
6714
6923
  function assertAdoptableDirectory(target) {
6715
- if (!(0, import_node_fs18.existsSync)(target)) {
6924
+ if (!(0, import_node_fs19.existsSync)(target)) {
6716
6925
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
6717
6926
  }
6718
- if (!(0, import_node_fs18.statSync)(target).isDirectory()) {
6927
+ if (!(0, import_node_fs19.statSync)(target).isDirectory()) {
6719
6928
  throw new Error(`--into '${target}' is not a directory.`);
6720
6929
  }
6721
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs18.existsSync)((0, import_node_path25.join)(target, entry)));
6930
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs19.existsSync)((0, import_node_path26.join)(target, entry)));
6722
6931
  if (blockers.length > 0) {
6723
6932
  throw new Error(
6724
6933
  `--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 +6935,15 @@ function assertAdoptableDirectory(target) {
6726
6935
  }
6727
6936
  }
6728
6937
  function mergeGitignore(generatedFile, targetFile) {
6729
- const existing = (0, import_node_fs18.readFileSync)(targetFile, "utf8");
6938
+ const existing = (0, import_node_fs19.readFileSync)(targetFile, "utf8");
6730
6939
  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) => {
6940
+ const additions = (0, import_node_fs19.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
6732
6941
  const trimmed = line.trim();
6733
6942
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
6734
6943
  });
6735
6944
  if (additions.length === 0) return false;
6736
6945
  const separator = existing.endsWith("\n") ? "" : "\n";
6737
- (0, import_node_fs18.writeFileSync)(
6946
+ (0, import_node_fs19.writeFileSync)(
6738
6947
  targetFile,
6739
6948
  `${existing}${separator}
6740
6949
  # Added by mnci (Nx workspace)
@@ -6744,9 +6953,9 @@ ${additions.join("\n")}
6744
6953
  return true;
6745
6954
  }
6746
6955
  function adoptGeneratedWorkspace(generatedRoot, target) {
6747
- const entries = (0, import_node_fs18.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6956
+ const entries = (0, import_node_fs19.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6748
6957
  const collisions = entries.filter(
6749
- (entry) => (0, import_node_fs18.existsSync)((0, import_node_path25.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6958
+ (entry) => (0, import_node_fs19.existsSync)((0, import_node_path26.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6750
6959
  );
6751
6960
  if (collisions.length > 0) {
6752
6961
  throw new Error(
@@ -6755,28 +6964,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
6755
6964
  }
6756
6965
  const result = { copied: [], kept: [], mergedGitignore: false };
6757
6966
  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)) {
6967
+ const from = (0, import_node_path26.join)(generatedRoot, entry);
6968
+ const to = (0, import_node_path26.join)(target, entry);
6969
+ if (entry === ".gitignore" && (0, import_node_fs19.existsSync)(to)) {
6761
6970
  result.mergedGitignore = mergeGitignore(from, to);
6762
6971
  result.kept.push(entry);
6763
6972
  continue;
6764
6973
  }
6765
- if ((0, import_node_fs18.existsSync)(to)) {
6974
+ if ((0, import_node_fs19.existsSync)(to)) {
6766
6975
  result.kept.push(entry);
6767
6976
  continue;
6768
6977
  }
6769
- (0, import_node_fs18.cpSync)(from, to, { recursive: true });
6978
+ (0, import_node_fs19.cpSync)(from, to, { recursive: true });
6770
6979
  result.copied.push(entry);
6771
6980
  }
6772
- (0, import_node_fs18.rmSync)(generatedRoot, { recursive: true, force: true });
6981
+ (0, import_node_fs19.rmSync)(generatedRoot, { recursive: true, force: true });
6773
6982
  return result;
6774
6983
  }
6775
6984
 
6776
6985
  // src/workspace-creation/create-workspace.use-case.ts
6777
- var import_node_fs19 = require("fs");
6986
+ var import_node_fs20 = require("fs");
6778
6987
  var import_node_os = require("os");
6779
- var import_node_path26 = require("path");
6988
+ var import_node_path27 = require("path");
6780
6989
  function nxCloudProviderValue(ci) {
6781
6990
  return ci === "azure" ? "azure" : "github";
6782
6991
  }
@@ -6819,9 +7028,9 @@ async function resolveRegistry(options) {
6819
7028
  return await promptRegistry();
6820
7029
  }
6821
7030
  async function runNew(name, options) {
6822
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path26.resolve)(process.cwd(), options.into);
7031
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path27.resolve)(process.cwd(), options.into);
6823
7032
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
6824
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path26.basename)(adoptTarget));
7033
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path27.basename)(adoptTarget));
6825
7034
  assertValidProjectName(workspaceName, "Workspace name");
6826
7035
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
6827
7036
  const registry = await resolveRegistry(options);
@@ -6834,8 +7043,8 @@ async function runNew(name, options) {
6834
7043
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
6835
7044
  const stack = await resolveStack(options);
6836
7045
  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);
7046
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs20.mkdtempSync)((0, import_node_path27.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
7047
+ let workspaceRoot = (0, import_node_path27.join)(stagingParent, workspaceName);
6839
7048
  try {
6840
7049
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
6841
7050
  runNpx(
@@ -6858,7 +7067,7 @@ async function runNew(name, options) {
6858
7067
  workspaceRoot = adoptTarget;
6859
7068
  }
6860
7069
  } finally {
6861
- if (adoptTarget !== void 0) (0, import_node_fs19.rmSync)(stagingParent, { recursive: true, force: true });
7070
+ if (adoptTarget !== void 0) (0, import_node_fs20.rmSync)(stagingParent, { recursive: true, force: true });
6862
7071
  }
6863
7072
  logger.step(
6864
7073
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -6868,8 +7077,8 @@ async function runNew(name, options) {
6868
7077
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
6869
7078
  logger.detail
6870
7079
  );
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 });
7080
+ (0, import_node_fs20.rmSync)((0, import_node_path27.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
7081
+ (0, import_node_fs20.rmSync)((0, import_node_path27.join)(workspaceRoot, "package-lock.json"), { force: true });
6873
7082
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
6874
7083
  const installStatus = runShell(
6875
7084
  "npm",
@@ -6907,12 +7116,12 @@ function projectKindHintLines(kinds = PROJECT_KINDS) {
6907
7116
  }
6908
7117
 
6909
7118
  // src/workspace-creation/interactive-wizard.use-case.ts
6910
- var import_node_path28 = require("path");
7119
+ var import_node_path29 = require("path");
6911
7120
  var import_prompts4 = require("@inquirer/prompts");
6912
7121
 
6913
7122
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
6914
- var import_node_fs20 = require("fs");
6915
- var import_node_path27 = require("path");
7123
+ var import_node_fs21 = require("fs");
7124
+ var import_node_path28 = require("path");
6916
7125
  function resolveRegistry2(options, persisted) {
6917
7126
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
6918
7127
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -6941,7 +7150,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6941
7150
  return persisted.workspaceName;
6942
7151
  }
6943
7152
  try {
6944
- const existing = (0, import_node_fs20.readdirSync)(workspaceRoot).find(
7153
+ const existing = (0, import_node_fs21.readdirSync)(workspaceRoot).find(
6945
7154
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
6946
7155
  );
6947
7156
  if (existing) {
@@ -6949,11 +7158,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6949
7158
  }
6950
7159
  } catch {
6951
7160
  }
6952
- return (0, import_node_path27.basename)(workspaceRoot);
7161
+ return (0, import_node_path28.basename)(workspaceRoot);
6953
7162
  }
6954
7163
  function detectNpmAuth(workspaceRoot) {
6955
7164
  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;
7165
+ return (0, import_node_fs21.readFileSync)((0, import_node_path28.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6957
7166
  } catch {
6958
7167
  return void 0;
6959
7168
  }
@@ -7000,7 +7209,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
7000
7209
  };
7001
7210
  }
7002
7211
  function runUpgrade(workspaceRoot, options) {
7003
- if (!fileExists((0, import_node_path27.join)(workspaceRoot, "nx.json"))) {
7212
+ if (!fileExists((0, import_node_path28.join)(workspaceRoot, "nx.json"))) {
7004
7213
  throw new Error(
7005
7214
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
7006
7215
  );
@@ -7065,7 +7274,7 @@ function runUpgrade(workspaceRoot, options) {
7065
7274
 
7066
7275
  // src/workspace-creation/interactive-wizard.use-case.ts
7067
7276
  async function runInteractive() {
7068
- const inWorkspace = fileExists((0, import_node_path28.join)(process.cwd(), "nx.json"));
7277
+ const inWorkspace = fileExists((0, import_node_path29.join)(process.cwd(), "nx.json"));
7069
7278
  const choiceNew = { name: "Create a new monorepo", value: "new" };
7070
7279
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
7071
7280
  const choiceUpgrade = {
@@ -7086,8 +7295,8 @@ async function runInteractive() {
7086
7295
  }
7087
7296
 
7088
7297
  // src/cli-version/check-for-update.use-case.ts
7089
- var import_node_fs21 = require("fs");
7090
- var import_node_path29 = require("path");
7298
+ var import_node_fs22 = require("fs");
7299
+ var import_node_path30 = require("path");
7091
7300
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
7092
7301
  var PACKAGE_NAME = "@mnci/cli";
7093
7302
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -7143,8 +7352,8 @@ function releaseTriple(version) {
7143
7352
  }
7144
7353
  function readCliVersion(packageDirectory) {
7145
7354
  try {
7146
- const manifestPath = (0, import_node_path29.join)(packageDirectory, "..", "package.json");
7147
- const manifest = JSON.parse((0, import_node_fs21.readFileSync)(manifestPath, "utf8"));
7355
+ const manifestPath = (0, import_node_path30.join)(packageDirectory, "..", "package.json");
7356
+ const manifest = JSON.parse((0, import_node_fs22.readFileSync)(manifestPath, "utf8"));
7148
7357
  return manifest.version ?? "0.0.0";
7149
7358
  } catch {
7150
7359
  return "0.0.0";
@@ -7198,6 +7407,11 @@ function buildProgram(cliVersion) {
7198
7407
  ).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
7408
  await runUp(process.cwd(), options);
7200
7409
  });
7410
+ program.command("install").alias("i").argument("[packages...]", "packages to add (a bare name or a pinned spec); omit to install only").description(
7411
+ "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>'"
7412
+ ).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) => {
7413
+ runInstall(process.cwd(), packages, options);
7414
+ });
7201
7415
  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
7416
  "--framework <framework>",
7203
7417
  "node-app only: express | fastify | koa | nest | none (default: none)"