@mnci/cli 4.47.0 → 4.49.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
@@ -3187,7 +3187,7 @@ function runPhase(phase, workspaceRoot, dependencies) {
3187
3187
  }
3188
3188
 
3189
3189
  // src/project-scaffolding/add-project.use-case.ts
3190
- var import_node_path33 = require("path");
3190
+ var import_node_path34 = require("path");
3191
3191
  var import_prompts3 = require("@inquirer/prompts");
3192
3192
 
3193
3193
  // src/project-name/project-name.validator.ts
@@ -3521,7 +3521,7 @@ function registerProjectCommands(workspaceRoot, name, commands) {
3521
3521
  removeStaleGitkeeps(workspaceRoot);
3522
3522
  ensurePythonArtefactsIgnored(workspaceRoot);
3523
3523
  const scripts = {
3524
- [`${name}:qa`]: `nx run ${name}:lint && nx run ${name}:test`
3524
+ [`${name}:qa`]: commands.qa ?? `nx run ${name}:lint && nx run ${name}:test`
3525
3525
  };
3526
3526
  if (commands.build) {
3527
3527
  scripts[`${name}:build`] = `nx run ${name}:build`;
@@ -4797,9 +4797,70 @@ function addGoInternalLib(workspaceRoot, name) {
4797
4797
  }
4798
4798
  }
4799
4799
 
4800
- // src/project-scaffolding/node.use-case.ts
4800
+ // src/project-scaffolding/esm-conversion.use-case.ts
4801
+ var import_node_fs19 = require("fs");
4801
4802
  var import_node_path18 = require("path");
4802
4803
 
4804
+ // src/project-scaffolding/esm-specifiers.algorithm.ts
4805
+ var RELATIVE_SPECIFIER = /((?:\bfrom|\bimport)\s*)(['"])(\.{1,2}\/[^'"\n]*|\.{1,2})\2/g;
4806
+ var HAS_EXTENSION = /\.(?:[cm]?js|json|node)$/;
4807
+ function withJsSpecifiers(source, directories = []) {
4808
+ return source.replaceAll(RELATIVE_SPECIFIER, (_match, lead, quote, specifier) => {
4809
+ if (HAS_EXTENSION.test(specifier)) {
4810
+ return `${lead}${quote}${specifier}${quote}`;
4811
+ }
4812
+ const extended = directories.includes(specifier) ? `${specifier}/index.js` : `${specifier}.js`;
4813
+ return `${lead}${quote}${extended}${quote}`;
4814
+ });
4815
+ }
4816
+
4817
+ // src/project-scaffolding/esm-conversion.use-case.ts
4818
+ var SAMPLE_DIRECTORIES = ["./hello"];
4819
+ var JEST_ANCHOR = " moduleFileExtensions:";
4820
+ var JEST_MAPPER = String.raw` moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1' },`;
4821
+ function typescriptFiles(directory) {
4822
+ const entries = (0, import_node_fs19.readdirSync)(directory, { withFileTypes: true });
4823
+ return entries.flatMap((entry) => {
4824
+ const path = (0, import_node_path18.join)(directory, entry.name);
4825
+ if (entry.isDirectory()) {
4826
+ return typescriptFiles(path);
4827
+ }
4828
+ return entry.name.endsWith(".ts") ? [path] : [];
4829
+ });
4830
+ }
4831
+ function convertAppToEsm(appRoot) {
4832
+ const manifestPath = (0, import_node_path18.join)(appRoot, "package.json");
4833
+ const manifest = readJson(manifestPath);
4834
+ const build = manifest.nx?.targets?.build;
4835
+ if (build?.options === void 0) {
4836
+ throw new Error(`${manifestPath} has no nx build target to switch to ESM; the generator's output changed.`);
4837
+ }
4838
+ build.options.format = ["esm"];
4839
+ writeFileEnsured(manifestPath, toJson({ ...manifest, type: "module" }));
4840
+ const sources = typescriptFiles((0, import_node_path18.join)(appRoot, "src"));
4841
+ for (const file of sources) {
4842
+ const source = (0, import_node_fs19.readFileSync)(file, "utf8");
4843
+ const converted = withJsSpecifiers(source, SAMPLE_DIRECTORIES);
4844
+ if (converted !== source) {
4845
+ writeFileEnsured(file, converted);
4846
+ }
4847
+ }
4848
+ const jestPath = (0, import_node_path18.join)(appRoot, "jest.config.cts");
4849
+ if (fileExists(jestPath)) {
4850
+ const jest = (0, import_node_fs19.readFileSync)(jestPath, "utf8");
4851
+ if (!jest.includes("moduleNameMapper")) {
4852
+ if (!jest.includes(JEST_ANCHOR)) {
4853
+ throw new Error(`${jestPath} has no moduleFileExtensions line to put the .js mapper above; the generator's output changed.`);
4854
+ }
4855
+ writeFileEnsured(jestPath, jest.replace(JEST_ANCHOR, () => `${JEST_MAPPER}
4856
+ ${JEST_ANCHOR}`));
4857
+ }
4858
+ }
4859
+ }
4860
+
4861
+ // src/project-scaffolding/node.use-case.ts
4862
+ var import_node_path19 = require("path");
4863
+
4803
4864
  // src/project-scaffolding/node-app-example.algorithm.ts
4804
4865
  var GREET_USE_CASE = `import type { Greeting } from './greeting.contract'
4805
4866
 
@@ -4921,12 +4982,12 @@ function runNodeApp(workspaceRoot, name, stack, framework) {
4921
4982
  ],
4922
4983
  workspaceRoot
4923
4984
  );
4924
- const appRoot = (0, import_node_path18.join)(workspaceRoot, "apps", name);
4985
+ const appRoot = (0, import_node_path19.join)(workspaceRoot, "apps", name);
4925
4986
  separateDeclarationOutput(appRoot);
4926
4987
  repairAssetMapping(appRoot, name);
4927
4988
  }
4928
4989
  function separateDeclarationOutput(appRoot) {
4929
- const tsconfigPath = (0, import_node_path18.join)(appRoot, "tsconfig.app.json");
4990
+ const tsconfigPath = (0, import_node_path19.join)(appRoot, "tsconfig.app.json");
4930
4991
  if (!fileExists(tsconfigPath)) {
4931
4992
  return;
4932
4993
  }
@@ -4948,7 +5009,7 @@ function separateDeclarationOutput(appRoot) {
4948
5009
  );
4949
5010
  }
4950
5011
  function repairAssetMapping(appRoot, name) {
4951
- const manifestPath = (0, import_node_path18.join)(appRoot, "package.json");
5012
+ const manifestPath = (0, import_node_path19.join)(appRoot, "package.json");
4952
5013
  if (!fileExists(manifestPath)) {
4953
5014
  return;
4954
5015
  }
@@ -4972,16 +5033,19 @@ function nodeAppPackageTarget(name) {
4972
5033
  options: { command }
4973
5034
  };
4974
5035
  }
4975
- function addNodeApp(workspaceRoot, name, stack, framework = "none") {
5036
+ function addNodeApp(workspaceRoot, name, stack, framework = "none", esm = false) {
4976
5037
  runNodeApp(workspaceRoot, name, stack, framework);
4977
5038
  const example = nodeAppExampleFiles(framework);
4978
5039
  if (example !== null) {
4979
5040
  for (const [relative, contents] of Object.entries(example)) {
4980
- writeFileEnsured((0, import_node_path18.join)(workspaceRoot, "apps", name, "src", relative), contents);
5041
+ writeFileEnsured((0, import_node_path19.join)(workspaceRoot, "apps", name, "src", relative), contents);
4981
5042
  }
4982
5043
  }
5044
+ if (esm) {
5045
+ convertAppToEsm((0, import_node_path19.join)(workspaceRoot, "apps", name));
5046
+ }
4983
5047
  ensureAdmZip(workspaceRoot);
4984
- addNxTargets((0, import_node_path18.join)(workspaceRoot, "apps", name, "package.json"), {
5048
+ addNxTargets((0, import_node_path19.join)(workspaceRoot, "apps", name, "package.json"), {
4985
5049
  package: nodeAppPackageTarget(name)
4986
5050
  });
4987
5051
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
@@ -5050,10 +5114,10 @@ describe('greet', () => {
5050
5114
  })
5051
5115
  `;
5052
5116
  function repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot) {
5053
- const manifestPath = (0, import_node_path18.join)(nodeFunctionAppRoot, "package.json");
5117
+ const manifestPath = (0, import_node_path19.join)(nodeFunctionAppRoot, "package.json");
5054
5118
  const manifest = readJson(manifestPath);
5055
5119
  const azureFunctionsVersion = readJson(
5056
- (0, import_node_path18.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
5120
+ (0, import_node_path19.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
5057
5121
  ).version;
5058
5122
  const dependencies = manifest.dependencies ?? {};
5059
5123
  writeFileEnsured(
@@ -5093,23 +5157,26 @@ function nodeFunctionAppStartTarget(name) {
5093
5157
  options: { command: "func start", cwd: `apps/${name}` }
5094
5158
  };
5095
5159
  }
5096
- function addNodeFunctionApp(workspaceRoot, name, stack, empty = false) {
5160
+ function addNodeFunctionApp(workspaceRoot, name, stack, empty = false, esm = false) {
5097
5161
  runNodeApp(workspaceRoot, name, stack, "none");
5098
5162
  ensureAzureFunctionsPackage(workspaceRoot);
5099
- const nodeFunctionAppRoot = (0, import_node_path18.join)(workspaceRoot, "apps", name);
5100
- writeFileEnsured((0, import_node_path18.join)(nodeFunctionAppRoot, "src/main.ts"), empty ? NODE_FUNCTION_APP_MAIN_EMPTY : NODE_FUNCTION_APP_MAIN);
5163
+ const nodeFunctionAppRoot = (0, import_node_path19.join)(workspaceRoot, "apps", name);
5164
+ writeFileEnsured((0, import_node_path19.join)(nodeFunctionAppRoot, "src/main.ts"), empty ? NODE_FUNCTION_APP_MAIN_EMPTY : NODE_FUNCTION_APP_MAIN);
5101
5165
  if (!empty) {
5102
- const slice = (0, import_node_path18.join)(nodeFunctionAppRoot, "src/hello");
5103
- writeFileEnsured((0, import_node_path18.join)(slice, "hello.handler.ts"), NODE_FUNCTION_APP_HELLO);
5104
- writeFileEnsured((0, import_node_path18.join)(slice, "greet.use-case.ts"), NODE_FUNCTION_APP_GREET_USE_CASE);
5105
- writeFileEnsured((0, import_node_path18.join)(slice, "greet.use-case.spec.ts"), NODE_FUNCTION_APP_GREET_SPEC);
5106
- writeFileEnsured((0, import_node_path18.join)(slice, "greeting.contract.ts"), NODE_FUNCTION_APP_GREETING_CONTRACT);
5107
- writeFileEnsured((0, import_node_path18.join)(slice, "index.ts"), NODE_FUNCTION_APP_HELLO_BARREL);
5108
- }
5109
- writeFileEnsured((0, import_node_path18.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
5166
+ const slice = (0, import_node_path19.join)(nodeFunctionAppRoot, "src/hello");
5167
+ writeFileEnsured((0, import_node_path19.join)(slice, "hello.handler.ts"), NODE_FUNCTION_APP_HELLO);
5168
+ writeFileEnsured((0, import_node_path19.join)(slice, "greet.use-case.ts"), NODE_FUNCTION_APP_GREET_USE_CASE);
5169
+ writeFileEnsured((0, import_node_path19.join)(slice, "greet.use-case.spec.ts"), NODE_FUNCTION_APP_GREET_SPEC);
5170
+ writeFileEnsured((0, import_node_path19.join)(slice, "greeting.contract.ts"), NODE_FUNCTION_APP_GREETING_CONTRACT);
5171
+ writeFileEnsured((0, import_node_path19.join)(slice, "index.ts"), NODE_FUNCTION_APP_HELLO_BARREL);
5172
+ }
5173
+ writeFileEnsured((0, import_node_path19.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
5110
5174
  repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot);
5175
+ if (esm) {
5176
+ convertAppToEsm(nodeFunctionAppRoot);
5177
+ }
5111
5178
  ensureAdmZip(workspaceRoot);
5112
- addNxTargets((0, import_node_path18.join)(nodeFunctionAppRoot, "package.json"), {
5179
+ addNxTargets((0, import_node_path19.join)(nodeFunctionAppRoot, "package.json"), {
5113
5180
  package: nodeFunctionAppPackageTarget(name),
5114
5181
  prune: nodeFunctionAppPruneTarget(name),
5115
5182
  start: nodeFunctionAppStartTarget(name),
@@ -5121,24 +5188,24 @@ function addNodeFunctionApp(workspaceRoot, name, stack, empty = false) {
5121
5188
  }
5122
5189
 
5123
5190
  // src/project-scaffolding/npm-lib.use-case.ts
5124
- var import_node_path24 = require("path");
5191
+ var import_node_path25 = require("path");
5125
5192
 
5126
5193
  // src/lockfile-pruning/prune-stale-local-registry.use-case.ts
5127
- var import_node_fs20 = require("fs");
5128
- var import_node_path20 = require("path");
5194
+ var import_node_fs21 = require("fs");
5195
+ var import_node_path21 = require("path");
5129
5196
 
5130
5197
  // src/lockfile-pruning/stale-local-registry.validator.ts
5131
- var import_node_fs19 = require("fs");
5132
- var import_node_path19 = require("path");
5198
+ var import_node_fs20 = require("fs");
5199
+ var import_node_path20 = require("path");
5133
5200
  var LOCAL_REGISTRY_PACKAGE = "verdaccio";
5134
5201
  var LOCAL_REGISTRY_LOCK_KEY = `node_modules/${LOCAL_REGISTRY_PACKAGE}`;
5135
5202
  var DEPENDENCY_FIELDS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
5136
5203
  function readJsonFile(path) {
5137
- if (!(0, import_node_fs19.existsSync)(path)) {
5204
+ if (!(0, import_node_fs20.existsSync)(path)) {
5138
5205
  return void 0;
5139
5206
  }
5140
5207
  try {
5141
- return JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
5208
+ return JSON.parse((0, import_node_fs20.readFileSync)(path, "utf8"));
5142
5209
  } catch {
5143
5210
  return void 0;
5144
5211
  }
@@ -5150,13 +5217,13 @@ function declaresLocalRegistry(manifest) {
5150
5217
  });
5151
5218
  }
5152
5219
  function hasStaleLocalRegistry(workspaceRoot) {
5153
- const lock = readJsonFile((0, import_node_path19.join)(workspaceRoot, "package-lock.json"));
5220
+ const lock = readJsonFile((0, import_node_path20.join)(workspaceRoot, "package-lock.json"));
5154
5221
  const entries = lock?.packages ?? {};
5155
5222
  if (!Object.hasOwn(entries, LOCAL_REGISTRY_LOCK_KEY)) {
5156
5223
  return false;
5157
5224
  }
5158
5225
  const members = Object.keys(entries).filter((key) => key !== "" && !key.startsWith("node_modules/") && !key.includes("/node_modules/"));
5159
- const manifests = ["", ...members].map((directory) => readJsonFile((0, import_node_path19.join)(workspaceRoot, directory, "package.json")));
5226
+ const manifests = ["", ...members].map((directory) => readJsonFile((0, import_node_path20.join)(workspaceRoot, directory, "package.json")));
5160
5227
  return manifests.every((manifest) => !declaresLocalRegistry(manifest));
5161
5228
  }
5162
5229
 
@@ -5165,21 +5232,21 @@ function pruneStaleLocalRegistry(workspaceRoot, resolve2 = runShell) {
5165
5232
  if (!hasStaleLocalRegistry(workspaceRoot)) {
5166
5233
  return { stale: false, status: 0 };
5167
5234
  }
5168
- const lockPath = (0, import_node_path20.join)(workspaceRoot, "package-lock.json");
5169
- const lock = JSON.parse((0, import_node_fs20.readFileSync)(lockPath, "utf8"));
5235
+ const lockPath = (0, import_node_path21.join)(workspaceRoot, "package-lock.json");
5236
+ const lock = JSON.parse((0, import_node_fs21.readFileSync)(lockPath, "utf8"));
5170
5237
  Reflect.deleteProperty(lock.packages, LOCAL_REGISTRY_LOCK_KEY);
5171
5238
  const root = lock.packages[""];
5172
5239
  if (root?.devDependencies !== void 0) {
5173
5240
  Reflect.deleteProperty(root.devDependencies, LOCAL_REGISTRY_PACKAGE);
5174
5241
  }
5175
- (0, import_node_fs20.writeFileSync)(lockPath, `${JSON.stringify(lock, void 0, 2)}
5242
+ (0, import_node_fs21.writeFileSync)(lockPath, `${JSON.stringify(lock, void 0, 2)}
5176
5243
  `);
5177
5244
  return { stale: true, status: resolve2("npm", ["install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--no-fund"], workspaceRoot) };
5178
5245
  }
5179
5246
 
5180
5247
  // src/rollup-library/repair-publishable-manifest.use-case.ts
5181
- var import_node_fs21 = require("fs");
5182
- var import_node_path21 = require("path");
5248
+ var import_node_fs22 = require("fs");
5249
+ var import_node_path22 = require("path");
5183
5250
  var WRONG_TYPES_PATH = "./dist/index.esm.d.ts";
5184
5251
  var ACTUAL_TYPES_PATH = "./dist/src/index.d.ts";
5185
5252
  var DECLARATION_MAP_EXCLUSION = "!**/*.d.ts.map";
@@ -5202,14 +5269,14 @@ function repairPublishableManifest(manifestPath) {
5202
5269
  }
5203
5270
  function repairPublishableManifests(workspaceRoot) {
5204
5271
  const changed = [];
5205
- const manifests = (0, import_node_fs21.globSync)(["packages/*/package.json", "libs/*/package.json"], {
5272
+ const manifests = (0, import_node_fs22.globSync)(["packages/*/package.json", "libs/*/package.json"], {
5206
5273
  cwd: workspaceRoot
5207
5274
  });
5208
5275
  for (const relativePath of manifests) {
5209
- const manifestPath = (0, import_node_path21.join)(workspaceRoot, relativePath);
5210
- const before = (0, import_node_fs21.readFileSync)(manifestPath, "utf8");
5276
+ const manifestPath = (0, import_node_path22.join)(workspaceRoot, relativePath);
5277
+ const before = (0, import_node_fs22.readFileSync)(manifestPath, "utf8");
5211
5278
  repairPublishableManifest(manifestPath);
5212
- const after = (0, import_node_fs21.readFileSync)(manifestPath, "utf8");
5279
+ const after = (0, import_node_fs22.readFileSync)(manifestPath, "utf8");
5213
5280
  if (after !== before) {
5214
5281
  changed.push(relativePath.replaceAll("\\", "/"));
5215
5282
  }
@@ -5218,8 +5285,8 @@ function repairPublishableManifests(workspaceRoot) {
5218
5285
  }
5219
5286
 
5220
5287
  // src/rollup-library/repair-rollup-config.use-case.ts
5221
- var import_node_fs22 = require("fs");
5222
- var import_node_path22 = require("path");
5288
+ var import_node_fs23 = require("fs");
5289
+ var import_node_path23 = require("path");
5223
5290
 
5224
5291
  // src/rollup-library/rollup-config.algorithm.ts
5225
5292
  var ROLLUP_CONFIG_PLACEHOLDER = [
@@ -5437,12 +5504,12 @@ ${DECLARATION_SPECIFIER_PLUGIN},`);
5437
5504
  // src/rollup-library/repair-rollup-config.use-case.ts
5438
5505
  function repairRollupSourceMaps(workspaceRoot) {
5439
5506
  const changed = [];
5440
- const configs = (0, import_node_fs22.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5507
+ const configs = (0, import_node_fs23.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5441
5508
  cwd: workspaceRoot
5442
5509
  });
5443
5510
  for (const relativePath of configs) {
5444
- const configPath = (0, import_node_path22.join)(workspaceRoot, relativePath);
5445
- const before = (0, import_node_fs22.readFileSync)(configPath, "utf8");
5511
+ const configPath = (0, import_node_path23.join)(workspaceRoot, relativePath);
5512
+ const before = (0, import_node_fs23.readFileSync)(configPath, "utf8");
5446
5513
  const after = withRollupSourceMaps(before);
5447
5514
  if (after !== before) {
5448
5515
  writeFileEnsured(configPath, after);
@@ -5453,12 +5520,12 @@ function repairRollupSourceMaps(workspaceRoot) {
5453
5520
  }
5454
5521
  function upgradeDeclarationSpecifierPlugins(workspaceRoot) {
5455
5522
  const changed = [];
5456
- const configs = (0, import_node_fs22.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5523
+ const configs = (0, import_node_fs23.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5457
5524
  cwd: workspaceRoot
5458
5525
  });
5459
5526
  for (const relativePath of configs) {
5460
- const configPath = (0, import_node_path22.join)(workspaceRoot, relativePath);
5461
- const before = (0, import_node_fs22.readFileSync)(configPath, "utf8");
5527
+ const configPath = (0, import_node_path23.join)(workspaceRoot, relativePath);
5528
+ const before = (0, import_node_fs23.readFileSync)(configPath, "utf8");
5462
5529
  const after = withUpgradedDeclarationSpecifierPlugin(before);
5463
5530
  if (after !== before) {
5464
5531
  writeFileEnsured(configPath, after);
@@ -5468,11 +5535,11 @@ function upgradeDeclarationSpecifierPlugins(workspaceRoot) {
5468
5535
  return changed;
5469
5536
  }
5470
5537
  function repairDeclarationSpecifiers(projectRoot) {
5471
- const configPath = (0, import_node_path22.join)(projectRoot, "rollup.config.cjs");
5538
+ const configPath = (0, import_node_path23.join)(projectRoot, "rollup.config.cjs");
5472
5539
  if (!fileExists(configPath)) {
5473
5540
  return;
5474
5541
  }
5475
- const config = (0, import_node_fs22.readFileSync)(configPath, "utf8");
5542
+ const config = (0, import_node_fs23.readFileSync)(configPath, "utf8");
5476
5543
  if (!config.includes(ROLLUP_CONFIG_PLACEHOLDER)) {
5477
5544
  const repaired = withRollupSourceMaps(withDeclarationSpecifierPlugin(config));
5478
5545
  if (repaired !== config) {
@@ -5487,12 +5554,12 @@ function repairDeclarationSpecifiers(projectRoot) {
5487
5554
  }
5488
5555
  function addMissingDeclarationSpecifierPlugins(workspaceRoot) {
5489
5556
  const changed = [];
5490
- const configs = (0, import_node_fs22.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5557
+ const configs = (0, import_node_fs23.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5491
5558
  cwd: workspaceRoot
5492
5559
  });
5493
5560
  for (const relativePath of configs) {
5494
- const configPath = (0, import_node_path22.join)(workspaceRoot, relativePath);
5495
- const before = (0, import_node_fs22.readFileSync)(configPath, "utf8");
5561
+ const configPath = (0, import_node_path23.join)(workspaceRoot, relativePath);
5562
+ const before = (0, import_node_fs23.readFileSync)(configPath, "utf8");
5496
5563
  const after = withDeclarationSpecifierPlugin(before);
5497
5564
  if (after !== before) {
5498
5565
  writeFileEnsured(configPath, after);
@@ -5503,10 +5570,10 @@ function addMissingDeclarationSpecifierPlugins(workspaceRoot) {
5503
5570
  }
5504
5571
 
5505
5572
  // src/rollup-library/rollup-config.repository.ts
5506
- var import_node_fs23 = require("fs");
5507
- var import_node_path23 = require("path");
5573
+ var import_node_fs24 = require("fs");
5574
+ var import_node_path24 = require("path");
5508
5575
  function resolveRequireTarget(fromDir, specifier) {
5509
- const base = (0, import_node_path23.join)(fromDir, specifier);
5576
+ const base = (0, import_node_path24.join)(fromDir, specifier);
5510
5577
  return [base, `${base}.cjs`, `${base}.js`].find((candidate) => fileExists(candidate));
5511
5578
  }
5512
5579
  function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()) {
@@ -5516,7 +5583,7 @@ function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()
5516
5583
  visited.add(configPath);
5517
5584
  let text;
5518
5585
  try {
5519
- text = (0, import_node_fs23.readFileSync)(configPath, "utf8");
5586
+ text = (0, import_node_fs24.readFileSync)(configPath, "utf8");
5520
5587
  } catch {
5521
5588
  return "";
5522
5589
  }
@@ -5524,15 +5591,15 @@ function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()
5524
5591
  text.matchAll(/require\((['"])(\.[^'"]*)\1\)/g),
5525
5592
  (match) => match[2]
5526
5593
  );
5527
- const requiredText = specifiers.map((specifier) => resolveRequireTarget((0, import_node_path23.dirname)(configPath), specifier)).filter((target) => target !== void 0).map((target) => resolveRollupConfigText(target, visited));
5594
+ const requiredText = specifiers.map((specifier) => resolveRequireTarget((0, import_node_path24.dirname)(configPath), specifier)).filter((target) => target !== void 0).map((target) => resolveRollupConfigText(target, visited));
5528
5595
  return [text, ...requiredText].join("\n");
5529
5596
  }
5530
5597
 
5531
5598
  // src/project-scaffolding/npm-lib.use-case.ts
5532
5599
  async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
5533
5600
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
5534
- const projectRoot = (0, import_node_path24.join)(workspaceRoot, "packages", name);
5535
- const manifestPath = (0, import_node_path24.join)(projectRoot, "package.json");
5601
+ const projectRoot = (0, import_node_path25.join)(workspaceRoot, "packages", name);
5602
+ const manifestPath = (0, import_node_path25.join)(projectRoot, "package.json");
5536
5603
  runGeneratorAndRepair(
5537
5604
  workspaceRoot,
5538
5605
  [
@@ -5565,8 +5632,8 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
5565
5632
  }
5566
5633
 
5567
5634
  // src/project-scaffolding/python.use-case.ts
5568
- var import_node_fs24 = require("fs");
5569
- var import_node_path25 = require("path");
5635
+ var import_node_fs25 = require("fs");
5636
+ var import_node_path26 = require("path");
5570
5637
  function ensurePython(workspaceRoot) {
5571
5638
  const hasPython = runShell("python3", ["--version"], workspaceRoot) === 0 || runShell("python", ["--version"], workspaceRoot) === 0;
5572
5639
  if (!hasPython) {
@@ -5589,7 +5656,7 @@ function ensurePythonPipPlugin(workspaceRoot) {
5589
5656
  registerPythonGraphPlugin(workspaceRoot);
5590
5657
  }
5591
5658
  function registerPythonGraphPlugin(workspaceRoot) {
5592
- const nxJsonPath = (0, import_node_path25.join)(workspaceRoot, "nx.json");
5659
+ const nxJsonPath = (0, import_node_path26.join)(workspaceRoot, "nx.json");
5593
5660
  if (!fileExists(nxJsonPath)) {
5594
5661
  return;
5595
5662
  }
@@ -5612,7 +5679,7 @@ pytest
5612
5679
  pip-audit
5613
5680
  `;
5614
5681
  function ensureRequirementsDev(workspaceRoot) {
5615
- const requirementsDevPath = (0, import_node_path25.join)(workspaceRoot, "requirements-dev.txt");
5682
+ const requirementsDevPath = (0, import_node_path26.join)(workspaceRoot, "requirements-dev.txt");
5616
5683
  if (!fileExists(requirementsDevPath)) {
5617
5684
  writeFileEnsured(requirementsDevPath, PYTHON_REQUIREMENTS_DEV);
5618
5685
  }
@@ -5672,8 +5739,8 @@ function addPythonApp(workspaceRoot, name) {
5672
5739
  ["g", "@mnci/nx-python-pip:application", name, `--directory=apps/${name}`, "--no-interactive"],
5673
5740
  workspaceRoot
5674
5741
  );
5675
- writeFileEnsured((0, import_node_path25.join)(workspaceRoot, "apps", name, "main.py"), pythonAppMain(name));
5676
- addProjectJsonTargets((0, import_node_path25.join)(workspaceRoot, "apps", name, "project.json"), {
5742
+ writeFileEnsured((0, import_node_path26.join)(workspaceRoot, "apps", name, "main.py"), pythonAppMain(name));
5743
+ addProjectJsonTargets((0, import_node_path26.join)(workspaceRoot, "apps", name, "project.json"), {
5677
5744
  package: pythonAppPackageTarget(name),
5678
5745
  start: pythonAppStartTarget(name)
5679
5746
  });
@@ -5695,7 +5762,7 @@ function addPythonFunctionApp(workspaceRoot, name) {
5695
5762
  workspaceRoot
5696
5763
  );
5697
5764
  const moduleDirectory = pythonModuleDirectory(name);
5698
- addProjectJsonTargets((0, import_node_path25.join)(workspaceRoot, "apps", name, "project.json"), {
5765
+ addProjectJsonTargets((0, import_node_path26.join)(workspaceRoot, "apps", name, "project.json"), {
5699
5766
  package: pythonFunctionAppPackageTarget(name, moduleDirectory),
5700
5767
  start: pythonFunctionAppStartTarget(name)
5701
5768
  });
@@ -5736,7 +5803,7 @@ function addPythonInternalLib(workspaceRoot, name) {
5736
5803
  var PYTHON_PROJECT_DIRS = ["apps", "python-packages", "libs"];
5737
5804
  function findPythonProjectDirectory(workspaceRoot, name) {
5738
5805
  return PYTHON_PROJECT_DIRS.find(
5739
- (directory) => fileExists((0, import_node_path25.join)(workspaceRoot, directory, name, "pyproject.toml"))
5806
+ (directory) => fileExists((0, import_node_path26.join)(workspaceRoot, directory, name, "pyproject.toml"))
5740
5807
  );
5741
5808
  }
5742
5809
  function parseVendorEntries(pyprojectToml) {
@@ -5775,7 +5842,7 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
5775
5842
  `No Python project named '${consumer}' with a pyproject.toml found (checked apps/, python-packages/, libs/). A Python function app has no pyproject.toml \u2014 there is nothing to vendor into.`
5776
5843
  );
5777
5844
  }
5778
- if (!fileExists((0, import_node_path25.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
5845
+ if (!fileExists((0, import_node_path26.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
5779
5846
  throw new Error(
5780
5847
  `No internal Python library named '${lib}' found at libs/${lib}/pyproject.toml. Only an internal library (added via 'mnci add python-internal-lib') can be vendored.`
5781
5848
  );
@@ -5783,8 +5850,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
5783
5850
  if (consumerDirectory === "libs" && consumer === lib) {
5784
5851
  throw new Error(`'${consumer}' cannot vendor itself.`);
5785
5852
  }
5786
- const pyprojectPath = (0, import_node_path25.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
5787
- const pyprojectToml = (0, import_node_fs24.readFileSync)(pyprojectPath, "utf8");
5853
+ const pyprojectPath = (0, import_node_path26.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
5854
+ const pyprojectToml = (0, import_node_fs25.readFileSync)(pyprojectPath, "utf8");
5788
5855
  if (parseVendorEntries(pyprojectToml).includes(lib)) {
5789
5856
  logger.info(`'${consumer}' already vendors '${lib}' \u2014 nothing to do.`);
5790
5857
  return;
@@ -5796,8 +5863,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
5796
5863
  }
5797
5864
 
5798
5865
  // src/project-scaffolding/react-app.use-case.ts
5799
- var import_node_fs25 = require("fs");
5800
- var import_node_path26 = require("path");
5866
+ var import_node_fs26 = require("fs");
5867
+ var import_node_path27 = require("path");
5801
5868
 
5802
5869
  // src/project-scaffolding/react-app-example.algorithm.ts
5803
5870
  function reactAppExampleFiles(name) {
@@ -5876,6 +5943,15 @@ describe('App', () => {
5876
5943
  `
5877
5944
  };
5878
5945
  }
5946
+ function reactAppE2eSpec(name) {
5947
+ return `import { expect, test } from '@playwright/test'
5948
+
5949
+ test('shows the greeting', async ({ page }) => {
5950
+ await page.goto('/')
5951
+ await expect(page.getByText('Hello, ${name}!')).toBeVisible()
5952
+ })
5953
+ `;
5954
+ }
5879
5955
 
5880
5956
  // src/project-scaffolding/react-app.use-case.ts
5881
5957
  var REACT_ENVIRONMENTS = ["dev", "uat", "prod"];
@@ -5914,12 +5990,12 @@ function reactAppTargets(name) {
5914
5990
  return targets;
5915
5991
  }
5916
5992
  function allowEnvFiles(workspaceRoot) {
5917
- const gitignorePath = (0, import_node_path26.join)(workspaceRoot, ".gitignore");
5993
+ const gitignorePath = (0, import_node_path27.join)(workspaceRoot, ".gitignore");
5918
5994
  if (!fileExists(gitignorePath)) {
5919
5995
  return;
5920
5996
  }
5921
5997
  const marker = "# MoNecromanCI: keep the committed per-environment Vite config (public VITE_ values)";
5922
- const current = (0, import_node_fs25.readFileSync)(gitignorePath, "utf8");
5998
+ const current = (0, import_node_fs26.readFileSync)(gitignorePath, "utf8");
5923
5999
  if (current.includes(marker)) {
5924
6000
  return;
5925
6001
  }
@@ -5929,7 +6005,7 @@ ${marker}
5929
6005
  ${allow}
5930
6006
  `);
5931
6007
  }
5932
- function addReactApp(workspaceRoot, name, stack) {
6008
+ function addReactApp(workspaceRoot, name, stack, e2e = false) {
5933
6009
  ensurePlugin(workspaceRoot, "@nx/react");
5934
6010
  runNx(
5935
6011
  [
@@ -5940,36 +6016,50 @@ function addReactApp(workspaceRoot, name, stack) {
5940
6016
  `--unitTestRunner=${stack.testRunner}`,
5941
6017
  "--linter=none",
5942
6018
  "--style=css",
5943
- "--e2eTestRunner=none",
6019
+ `--e2eTestRunner=${e2e ? "playwright" : "none"}`,
5944
6020
  "--no-interactive"
5945
6021
  ],
5946
6022
  workspaceRoot
5947
6023
  );
5948
6024
  ensureAdmZip(workspaceRoot);
5949
- const reactAppRoot = (0, import_node_path26.join)(workspaceRoot, "apps", name);
6025
+ const reactAppRoot = (0, import_node_path27.join)(workspaceRoot, "apps", name);
5950
6026
  for (const environment of REACT_ENVIRONMENTS) {
5951
- writeFileEnsured((0, import_node_path26.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
6027
+ writeFileEnsured((0, import_node_path27.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
5952
6028
  }
5953
6029
  allowEnvFiles(workspaceRoot);
5954
- addNxTargets((0, import_node_path26.join)(reactAppRoot, "package.json"), reactAppTargets(name));
6030
+ addNxTargets((0, import_node_path27.join)(reactAppRoot, "package.json"), reactAppTargets(name));
5955
6031
  reshapeReactAppScaffold(reactAppRoot);
5956
- (0, import_node_fs25.rmSync)((0, import_node_path26.join)(reactAppRoot, "src/app/nx-welcome.component.tsx"), { force: true });
6032
+ (0, import_node_fs26.rmSync)((0, import_node_path27.join)(reactAppRoot, "src/app/nx-welcome.component.tsx"), { force: true });
5957
6033
  const example = reactAppExampleFiles(name);
5958
6034
  for (const [relative, contents] of Object.entries(example)) {
5959
- writeFileEnsured((0, import_node_path26.join)(reactAppRoot, "src", relative), contents);
6035
+ writeFileEnsured((0, import_node_path27.join)(reactAppRoot, "src", relative), contents);
5960
6036
  }
5961
6037
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
5962
6038
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:serve` });
6039
+ if (e2e) {
6040
+ pairE2eProject(workspaceRoot, name);
6041
+ }
6042
+ }
6043
+ function pairE2eProject(workspaceRoot, name) {
6044
+ const e2eName = `${name}-e2e`;
6045
+ const e2eRoot = (0, import_node_path27.join)(workspaceRoot, "apps", e2eName);
6046
+ (0, import_node_fs26.rmSync)((0, import_node_path27.join)(e2eRoot, "src/example.spec.ts"), { force: true });
6047
+ writeFileEnsured((0, import_node_path27.join)(e2eRoot, "src/greeting.e2e.spec.ts"), reactAppE2eSpec(name));
6048
+ removeGeneratedEslintConfig(workspaceRoot, `apps/${e2eName}`);
6049
+ registerProjectCommands(workspaceRoot, e2eName, {
6050
+ build: false,
6051
+ qa: `nx run ${e2eName}:lint && nx run ${e2eName}:typecheck`
6052
+ });
5963
6053
  }
5964
6054
 
5965
6055
  // src/project-scaffolding/react-lib.use-case.ts
5966
- var import_node_path27 = require("path");
6056
+ var import_node_path28 = require("path");
5967
6057
  var REACT_LIB_BUNDLER = "rollup";
5968
6058
  async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
5969
6059
  ensurePlugin(workspaceRoot, "@nx/react");
5970
6060
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
5971
- const projectRoot = (0, import_node_path27.join)(workspaceRoot, "packages", name);
5972
- const publishableManifest = (0, import_node_path27.join)(projectRoot, "package.json");
6061
+ const projectRoot = (0, import_node_path28.join)(workspaceRoot, "packages", name);
6062
+ const publishableManifest = (0, import_node_path28.join)(projectRoot, "package.json");
5973
6063
  runGeneratorAndRepair(
5974
6064
  workspaceRoot,
5975
6065
  [
@@ -6013,8 +6103,8 @@ function dropNxProjectName(manifestPath) {
6013
6103
  }
6014
6104
  function addReactInternalLib(workspaceRoot, name, stack, empty = false) {
6015
6105
  ensurePlugin(workspaceRoot, "@nx/react");
6016
- const projectRoot = (0, import_node_path27.join)(workspaceRoot, "libs", name);
6017
- const privateManifest = (0, import_node_path27.join)(projectRoot, "package.json");
6106
+ const projectRoot = (0, import_node_path28.join)(workspaceRoot, "libs", name);
6107
+ const privateManifest = (0, import_node_path28.join)(projectRoot, "package.json");
6018
6108
  runGeneratorAndRepair(
6019
6109
  workspaceRoot,
6020
6110
  [
@@ -6041,8 +6131,8 @@ function addReactInternalLib(workspaceRoot, name, stack, empty = false) {
6041
6131
  }
6042
6132
 
6043
6133
  // src/project-scaffolding/vscode-extension.use-case.ts
6044
- var import_node_fs26 = require("fs");
6045
- var import_node_path28 = require("path");
6134
+ var import_node_fs27 = require("fs");
6135
+ var import_node_path29 = require("path");
6046
6136
  var VSCODE_EXTENSION_SCRIPT_PATH = "tools/vscode-extension.cjs";
6047
6137
  var VSCODE_ENGINE_FLOOR = "1.96.0";
6048
6138
  var VSCODE_SIDECAR_TARGETS = {
@@ -6227,8 +6317,8 @@ export const window = {
6227
6317
  var VSCODE_STUB_PATH = "test/vscode.stub.ts";
6228
6318
  function mapVscodeToStub(projectRoot, testRunner) {
6229
6319
  const [file, anchor, mapping] = testRunner === "jest" ? ["jest.config.cts", "testEnvironment: 'node',", `moduleNameMapper: { '^vscode$': '<rootDir>/${VSCODE_STUB_PATH}' },`] : ["vitest.config.mts", "environment: 'node',", `alias: { vscode: \`\${import.meta.dirname}/${VSCODE_STUB_PATH}\` },`];
6230
- const path = (0, import_node_path28.join)(projectRoot, file);
6231
- const content = fileExists(path) ? (0, import_node_fs26.readFileSync)(path, "utf8") : "";
6320
+ const path = (0, import_node_path29.join)(projectRoot, file);
6321
+ const content = fileExists(path) ? (0, import_node_fs27.readFileSync)(path, "utf8") : "";
6232
6322
  const line = content.split("\n").find((candidate) => candidate.trim() === anchor);
6233
6323
  if (line === void 0) {
6234
6324
  throw new Error(`${file} has no "${anchor}" line to map the vscode module after; map 'vscode' to ${VSCODE_STUB_PATH} by hand.`);
@@ -6248,11 +6338,11 @@ function ensureVscodeToolchain(workspaceRoot) {
6248
6338
  }
6249
6339
  }
6250
6340
  function defaultPublisher(workspaceRoot) {
6251
- const { name } = readJson((0, import_node_path28.join)(workspaceRoot, "package.json"));
6341
+ const { name } = readJson((0, import_node_path29.join)(workspaceRoot, "package.json"));
6252
6342
  return (name ?? "publisher").replace(/^@/, "").split("/", 1)[0];
6253
6343
  }
6254
6344
  function reshapeManifest(projectRoot, name, publisher) {
6255
- const manifestPath = (0, import_node_path28.join)(projectRoot, "package.json");
6345
+ const manifestPath = (0, import_node_path29.join)(projectRoot, "package.json");
6256
6346
  const manifest = readJson(manifestPath);
6257
6347
  const { nx = {}, ...rest } = manifest;
6258
6348
  const targets = { ...nx.targets };
@@ -6316,11 +6406,11 @@ function vscodeExtensionPublishTarget(name, sidecar) {
6316
6406
  };
6317
6407
  }
6318
6408
  function addDebugLaunch(workspaceRoot, name) {
6319
- const file = (0, import_node_fs26.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
6409
+ const file = (0, import_node_fs27.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
6320
6410
  if (file === void 0) {
6321
6411
  return;
6322
6412
  }
6323
- const path = (0, import_node_path28.join)(workspaceRoot, file);
6413
+ const path = (0, import_node_path29.join)(workspaceRoot, file);
6324
6414
  const workspace = readCodeWorkspace(path) ?? {};
6325
6415
  const folder = `\${workspaceFolder:${workspace.folders?.[0]?.name ?? file.replace(/\.code-workspace$/, "")}}`;
6326
6416
  const taskLabel = `${name}: build (development)`;
@@ -6353,39 +6443,39 @@ function addDebugLaunch(workspaceRoot, name) {
6353
6443
  );
6354
6444
  }
6355
6445
  function refreshVscodeExtensionScript(workspaceRoot) {
6356
- const apps = (0, import_node_path28.join)(workspaceRoot, "apps");
6446
+ const apps = (0, import_node_path29.join)(workspaceRoot, "apps");
6357
6447
  let entries;
6358
6448
  try {
6359
- entries = (0, import_node_fs26.readdirSync)(apps);
6449
+ entries = (0, import_node_fs27.readdirSync)(apps);
6360
6450
  } catch {
6361
6451
  return false;
6362
6452
  }
6363
6453
  const hasExtension = entries.some((entry) => {
6364
- const manifestPath = (0, import_node_path28.join)(apps, entry, "package.json");
6454
+ const manifestPath = (0, import_node_path29.join)(apps, entry, "package.json");
6365
6455
  if (!fileExists(manifestPath)) {
6366
6456
  return false;
6367
6457
  }
6368
6458
  const tags = readJson(manifestPath).nx?.tags ?? [];
6369
6459
  return tags.includes(VSCODE_EXTENSION_TAG);
6370
6460
  });
6371
- const path = (0, import_node_path28.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
6372
- if (!hasExtension || fileExists(path) && (0, import_node_fs26.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
6461
+ const path = (0, import_node_path29.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
6462
+ if (!hasExtension || fileExists(path) && (0, import_node_fs27.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
6373
6463
  return false;
6374
6464
  }
6375
6465
  writeFileEnsured(path, VSCODE_EXTENSION_SCRIPT);
6376
6466
  return true;
6377
6467
  }
6378
6468
  function pinVscodeExtensionProjectNames(workspaceRoot) {
6379
- const apps = (0, import_node_path28.join)(workspaceRoot, "apps");
6469
+ const apps = (0, import_node_path29.join)(workspaceRoot, "apps");
6380
6470
  let entries;
6381
6471
  try {
6382
- entries = (0, import_node_fs26.readdirSync)(apps);
6472
+ entries = (0, import_node_fs27.readdirSync)(apps);
6383
6473
  } catch {
6384
6474
  return [];
6385
6475
  }
6386
6476
  const updated = [];
6387
6477
  for (const entry of entries) {
6388
- const manifestPath = (0, import_node_path28.join)(apps, entry, "package.json");
6478
+ const manifestPath = (0, import_node_path29.join)(apps, entry, "package.json");
6389
6479
  if (!fileExists(manifestPath)) {
6390
6480
  continue;
6391
6481
  }
@@ -6405,22 +6495,22 @@ function refreshLockFile(workspaceRoot, name) {
6405
6495
  }
6406
6496
  function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
6407
6497
  const { sidecar } = options;
6408
- if (sidecar !== void 0 && !fileExists((0, import_node_path28.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
6498
+ if (sidecar !== void 0 && !fileExists((0, import_node_path29.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
6409
6499
  throw new Error(`--sidecar ${sidecar}: no Go app at apps/${sidecar}. Add it first with \`mnci add go-app ${sidecar}\`.`);
6410
6500
  }
6411
6501
  runNodeApp(workspaceRoot, name, stack, "none");
6412
6502
  ensureVscodeToolchain(workspaceRoot);
6413
- const projectRoot = (0, import_node_path28.join)(workspaceRoot, "apps", name);
6503
+ const projectRoot = (0, import_node_path29.join)(workspaceRoot, "apps", name);
6414
6504
  reshapeManifest(projectRoot, name, options.publisher ?? defaultPublisher(workspaceRoot));
6415
- addVscodeTypes((0, import_node_path28.join)(projectRoot, "tsconfig.app.json"));
6416
- addVscodeTypes((0, import_node_path28.join)(projectRoot, "tsconfig.spec.json"));
6417
- writeFileEnsured((0, import_node_path28.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
6418
- writeFileEnsured((0, import_node_path28.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
6419
- writeFileEnsured((0, import_node_path28.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
6505
+ addVscodeTypes((0, import_node_path29.join)(projectRoot, "tsconfig.app.json"));
6506
+ addVscodeTypes((0, import_node_path29.join)(projectRoot, "tsconfig.spec.json"));
6507
+ writeFileEnsured((0, import_node_path29.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
6508
+ writeFileEnsured((0, import_node_path29.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
6509
+ writeFileEnsured((0, import_node_path29.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
6420
6510
  mapVscodeToStub(projectRoot, stack.testRunner);
6421
- writeFileEnsured((0, import_node_path28.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
6422
- writeFileEnsured((0, import_node_path28.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
6423
- addNxTargets((0, import_node_path28.join)(projectRoot, "package.json"), {
6511
+ writeFileEnsured((0, import_node_path29.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
6512
+ writeFileEnsured((0, import_node_path29.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
6513
+ addNxTargets((0, import_node_path29.join)(projectRoot, "package.json"), {
6424
6514
  "package": vscodeExtensionPackageTarget(name, sidecar),
6425
6515
  "nx-release-publish": vscodeExtensionPublishTarget(name, sidecar)
6426
6516
  });
@@ -6431,12 +6521,12 @@ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
6431
6521
  }
6432
6522
 
6433
6523
  // src/dependency-management/install-dependencies.use-case.ts
6434
- var import_node_fs28 = require("fs");
6435
- var import_node_path30 = require("path");
6524
+ var import_node_fs29 = require("fs");
6525
+ var import_node_path31 = require("path");
6436
6526
 
6437
6527
  // src/dependency-management/manifest.repository.ts
6438
- var import_node_fs27 = require("fs");
6439
- var import_node_path29 = require("path");
6528
+ var import_node_fs28 = require("fs");
6529
+ var import_node_path30 = require("path");
6440
6530
  var ECOSYSTEMS = ["npm", "pip", "pub", "nuget", "go"];
6441
6531
  var ROOT_LABEL = "(root)";
6442
6532
  var MANIFEST_GLOBS = {
@@ -6469,23 +6559,23 @@ function projectOf(manifestRelativePath) {
6469
6559
  }
6470
6560
  function hasEcosystem(workspaceRoot, ecosystem) {
6471
6561
  if (ecosystem === "go") {
6472
- return fileExists((0, import_node_path29.join)(workspaceRoot, "go.mod"));
6562
+ return fileExists((0, import_node_path30.join)(workspaceRoot, "go.mod"));
6473
6563
  }
6474
6564
  if (ecosystem === "nuget") {
6475
- return (0, import_node_fs27.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
6565
+ return (0, import_node_fs28.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
6476
6566
  }
6477
6567
  const rootMarker = {
6478
6568
  npm: "package.json",
6479
6569
  pip: "requirements-dev.txt",
6480
6570
  pub: "pubspec.yaml"
6481
6571
  };
6482
- return fileExists((0, import_node_path29.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs27.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
6572
+ return fileExists((0, import_node_path30.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs28.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
6483
6573
  }
6484
6574
  function collectNpm(workspaceRoot) {
6485
6575
  const sites = [];
6486
- const relativePaths = ["package.json", ...(0, import_node_fs27.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
6576
+ const relativePaths = ["package.json", ...(0, import_node_fs28.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
6487
6577
  for (const relativePath of relativePaths) {
6488
- const manifestPath = (0, import_node_path29.join)(workspaceRoot, relativePath);
6578
+ const manifestPath = (0, import_node_path30.join)(workspaceRoot, relativePath);
6489
6579
  try {
6490
6580
  const manifest = readJson(manifestPath);
6491
6581
  sites.push(...npmManifestSites(manifest, relativePath, manifestPath));
@@ -6546,17 +6636,17 @@ function collectPip(workspaceRoot) {
6546
6636
  name: parsed.name,
6547
6637
  ecosystem: "pip",
6548
6638
  project: projectOf(relativePath),
6549
- manifestPath: (0, import_node_path29.join)(workspaceRoot, relativePath),
6639
+ manifestPath: (0, import_node_path30.join)(workspaceRoot, relativePath),
6550
6640
  section,
6551
6641
  spec: parsed.spec,
6552
6642
  rewritable: parsed.rewritable && parsed.spec !== ""
6553
6643
  });
6554
6644
  };
6555
- const pyprojectPaths = (0, import_node_fs27.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
6645
+ const pyprojectPaths = (0, import_node_fs28.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
6556
6646
  for (const relativePath of pyprojectPaths) {
6557
6647
  let content;
6558
6648
  try {
6559
- content = (0, import_node_fs27.readFileSync)((0, import_node_path29.join)(workspaceRoot, relativePath), "utf8");
6649
+ content = (0, import_node_fs28.readFileSync)((0, import_node_path30.join)(workspaceRoot, relativePath), "utf8");
6560
6650
  } catch {
6561
6651
  continue;
6562
6652
  }
@@ -6567,14 +6657,14 @@ function collectPip(workspaceRoot) {
6567
6657
  }
6568
6658
  const requirementsPaths = [
6569
6659
  "requirements-dev.txt",
6570
- ...(0, import_node_fs27.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
6660
+ ...(0, import_node_fs28.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
6571
6661
  ];
6572
6662
  for (const relativePath of requirementsPaths) {
6573
- if (!fileExists((0, import_node_path29.join)(workspaceRoot, relativePath))) {
6663
+ if (!fileExists((0, import_node_path30.join)(workspaceRoot, relativePath))) {
6574
6664
  continue;
6575
6665
  }
6576
6666
  const section = relativePath === "requirements-dev.txt" ? "devDep" : "dep";
6577
- const lines = (0, import_node_fs27.readFileSync)((0, import_node_path29.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
6667
+ const lines = (0, import_node_fs28.readFileSync)((0, import_node_path30.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
6578
6668
  for (const line of lines) {
6579
6669
  push(relativePath, section, line);
6580
6670
  }
@@ -6612,11 +6702,11 @@ function pyprojectDependencies(content) {
6612
6702
  }
6613
6703
  function collectPub(workspaceRoot) {
6614
6704
  const sites = [];
6615
- const pubspecPaths = (0, import_node_fs27.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
6705
+ const pubspecPaths = (0, import_node_fs28.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
6616
6706
  for (const relativePath of pubspecPaths) {
6617
6707
  let content;
6618
6708
  try {
6619
- content = (0, import_node_fs27.readFileSync)((0, import_node_path29.join)(workspaceRoot, relativePath), "utf8");
6709
+ content = (0, import_node_fs28.readFileSync)((0, import_node_path30.join)(workspaceRoot, relativePath), "utf8");
6620
6710
  } catch {
6621
6711
  continue;
6622
6712
  }
@@ -6626,7 +6716,7 @@ function collectPub(workspaceRoot) {
6626
6716
  name: entry.name,
6627
6717
  ecosystem: "pub",
6628
6718
  project: projectOf(relativePath),
6629
- manifestPath: (0, import_node_path29.join)(workspaceRoot, relativePath),
6719
+ manifestPath: (0, import_node_path30.join)(workspaceRoot, relativePath),
6630
6720
  section: block === "dependencies" ? "dep" : "devDep",
6631
6721
  spec: entry.spec,
6632
6722
  rewritable: entry.spec !== ""
@@ -6676,11 +6766,11 @@ function stripQuotes(value) {
6676
6766
  }
6677
6767
  function collectNuget(workspaceRoot) {
6678
6768
  const sites = [];
6679
- const csprojPaths = (0, import_node_fs27.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
6769
+ const csprojPaths = (0, import_node_fs28.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
6680
6770
  for (const relativePath of csprojPaths) {
6681
6771
  let content;
6682
6772
  try {
6683
- content = (0, import_node_fs27.readFileSync)((0, import_node_path29.join)(workspaceRoot, relativePath), "utf8");
6773
+ content = (0, import_node_fs28.readFileSync)((0, import_node_path30.join)(workspaceRoot, relativePath), "utf8");
6684
6774
  } catch {
6685
6775
  continue;
6686
6776
  }
@@ -6689,7 +6779,7 @@ function collectNuget(workspaceRoot) {
6689
6779
  name: entry.name,
6690
6780
  ecosystem: "nuget",
6691
6781
  project: projectOf(relativePath),
6692
- manifestPath: (0, import_node_path29.join)(workspaceRoot, relativePath),
6782
+ manifestPath: (0, import_node_path30.join)(workspaceRoot, relativePath),
6693
6783
  section: "dep",
6694
6784
  spec: entry.spec,
6695
6785
  // A plain SemVer string is rewritable; an MSBuild property reference
@@ -6714,13 +6804,13 @@ function csprojPackageReferences(content) {
6714
6804
  return entries;
6715
6805
  }
6716
6806
  function collectGo(workspaceRoot) {
6717
- const manifestPath = (0, import_node_path29.join)(workspaceRoot, "go.mod");
6807
+ const manifestPath = (0, import_node_path30.join)(workspaceRoot, "go.mod");
6718
6808
  if (!fileExists(manifestPath)) {
6719
6809
  return [];
6720
6810
  }
6721
6811
  let content;
6722
6812
  try {
6723
- content = (0, import_node_fs27.readFileSync)(manifestPath, "utf8");
6813
+ content = (0, import_node_fs28.readFileSync)(manifestPath, "utf8");
6724
6814
  } catch {
6725
6815
  return [];
6726
6816
  }
@@ -6769,7 +6859,7 @@ var PROJECT_GLOBS = {
6769
6859
  function locateProjects(workspaceRoot) {
6770
6860
  const locations = [];
6771
6861
  for (const ecosystem of ECOSYSTEMS) {
6772
- const relativePaths = (0, import_node_fs27.globSync)(PROJECT_GLOBS[ecosystem], { cwd: workspaceRoot });
6862
+ const relativePaths = (0, import_node_fs28.globSync)(PROJECT_GLOBS[ecosystem], { cwd: workspaceRoot });
6773
6863
  for (const relativePath of relativePaths) {
6774
6864
  const posix = toPosix(relativePath);
6775
6865
  const dir = posix.slice(0, posix.lastIndexOf("/"));
@@ -6777,7 +6867,7 @@ function locateProjects(workspaceRoot) {
6777
6867
  ecosystem,
6778
6868
  dir,
6779
6869
  name: dir.slice(dir.lastIndexOf("/") + 1),
6780
- manifestPath: (0, import_node_path29.join)(workspaceRoot, relativePath)
6870
+ manifestPath: (0, import_node_path30.join)(workspaceRoot, relativePath)
6781
6871
  });
6782
6872
  }
6783
6873
  }
@@ -6798,7 +6888,7 @@ function rewriteSpec(site, spec) {
6798
6888
  writeFileEnsured(site.manifestPath, toJson(manifest));
6799
6889
  return true;
6800
6890
  }
6801
- const before = (0, import_node_fs27.readFileSync)(site.manifestPath, "utf8");
6891
+ const before = (0, import_node_fs28.readFileSync)(site.manifestPath, "utf8");
6802
6892
  const after = (() => {
6803
6893
  switch (site.ecosystem) {
6804
6894
  case "pip": {
@@ -6889,13 +6979,13 @@ function escapeForRegex(value) {
6889
6979
  function isWorkspaceProject(workspaceRoot, name) {
6890
6980
  const short = name.includes("/") ? name.split("/").at(-1) : name;
6891
6981
  return ["apps", "libs", "packages"].some(
6892
- (directory) => fileExists((0, import_node_path29.join)(workspaceRoot, directory, short ?? name, "package.json"))
6982
+ (directory) => fileExists((0, import_node_path30.join)(workspaceRoot, directory, short ?? name, "package.json"))
6893
6983
  );
6894
6984
  }
6895
6985
  function isAliasedInstall(workspaceRoot, name) {
6896
6986
  try {
6897
6987
  const installed = readJson(
6898
- (0, import_node_path29.join)(workspaceRoot, "node_modules", name, "package.json")
6988
+ (0, import_node_path30.join)(workspaceRoot, "node_modules", name, "package.json")
6899
6989
  );
6900
6990
  return installed.name !== void 0 && installed.name !== name;
6901
6991
  } catch {
@@ -6906,14 +6996,14 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
6906
6996
  if (ecosystem === "npm") {
6907
6997
  try {
6908
6998
  return readJson(
6909
- (0, import_node_path29.join)(workspaceRoot, "node_modules", name, "package.json")
6999
+ (0, import_node_path30.join)(workspaceRoot, "node_modules", name, "package.json")
6910
7000
  ).version;
6911
7001
  } catch {
6912
7002
  return void 0;
6913
7003
  }
6914
7004
  }
6915
7005
  if (ecosystem === "pub") {
6916
- const lockPath = (0, import_node_path29.join)(workspaceRoot, "pubspec.lock");
7006
+ const lockPath = (0, import_node_path30.join)(workspaceRoot, "pubspec.lock");
6917
7007
  if (!fileExists(lockPath)) {
6918
7008
  return void 0;
6919
7009
  }
@@ -6921,7 +7011,7 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
6921
7011
  const match = new RegExp(
6922
7012
  String.raw`^\s{2}${escapeForRegex(name)}:[^]*?^\s+version:\s*["']?([^"'\s]+)`,
6923
7013
  "m"
6924
- ).exec((0, import_node_fs27.readFileSync)(lockPath, "utf8"));
7014
+ ).exec((0, import_node_fs28.readFileSync)(lockPath, "utf8"));
6925
7015
  return match?.[1];
6926
7016
  } catch {
6927
7017
  return void 0;
@@ -6987,7 +7077,7 @@ function resolveTarget(locations, target) {
6987
7077
  return byName[0];
6988
7078
  }
6989
7079
  function installInto(workspaceRoot, location, packages, saveDev) {
6990
- const projectDir = (0, import_node_path30.join)(workspaceRoot, location.dir);
7080
+ const projectDir = (0, import_node_path31.join)(workspaceRoot, location.dir);
6991
7081
  switch (location.ecosystem) {
6992
7082
  case "npm": {
6993
7083
  const flags = saveDev ? ["--save-dev"] : [];
@@ -7040,7 +7130,7 @@ function installInto(workspaceRoot, location, packages, saveDev) {
7040
7130
  function addPythonDependency(manifestPath, specifier) {
7041
7131
  let content;
7042
7132
  try {
7043
- content = (0, import_node_fs28.readFileSync)(manifestPath, "utf8");
7133
+ content = (0, import_node_fs29.readFileSync)(manifestPath, "utf8");
7044
7134
  } catch {
7045
7135
  logger.warn(`Could not read ${manifestPath} \u2014 skipped ${specifier}`);
7046
7136
  return;
@@ -7069,7 +7159,7 @@ function installEverything(workspaceRoot, only) {
7069
7159
  }
7070
7160
  function ecosystemPresent(workspaceRoot, ecosystem) {
7071
7161
  if (ecosystem === "go") {
7072
- return fileExists((0, import_node_path30.join)(workspaceRoot, "go.work")) || fileExists((0, import_node_path30.join)(workspaceRoot, "go.mod"));
7162
+ return fileExists((0, import_node_path31.join)(workspaceRoot, "go.work")) || fileExists((0, import_node_path31.join)(workspaceRoot, "go.mod"));
7073
7163
  }
7074
7164
  return hasEcosystem(workspaceRoot, ecosystem);
7075
7165
  }
@@ -7088,7 +7178,7 @@ function splitAtLast(value, separator) {
7088
7178
  }
7089
7179
 
7090
7180
  // src/dependency-management/sync-dependencies.use-case.ts
7091
- var import_node_path31 = require("path");
7181
+ var import_node_path32 = require("path");
7092
7182
 
7093
7183
  // src/dependency-management/semver.algorithm.ts
7094
7184
  var UPDATE_KINDS = ["patch", "minor", "major", "non-semver"];
@@ -7265,7 +7355,7 @@ function describe(finding) {
7265
7355
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
7266
7356
  }
7267
7357
  function runSync(workspaceRoot, options) {
7268
- if (!fileExists((0, import_node_path31.join)(workspaceRoot, "nx.json"))) {
7358
+ if (!fileExists((0, import_node_path32.join)(workspaceRoot, "nx.json"))) {
7269
7359
  throw new Error(
7270
7360
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
7271
7361
  );
@@ -7315,7 +7405,7 @@ function runSync(workspaceRoot, options) {
7315
7405
  }
7316
7406
 
7317
7407
  // src/dependency-management/update-dependencies.use-case.ts
7318
- var import_node_path32 = require("path");
7408
+ var import_node_path33 = require("path");
7319
7409
  var import_prompts2 = require("@inquirer/prompts");
7320
7410
 
7321
7411
  // src/dependency-management/registry.client.ts
@@ -7598,7 +7688,7 @@ function reinstall(workspaceRoot, ecosystems) {
7598
7688
  function hasPythonInstallScript(workspaceRoot) {
7599
7689
  try {
7600
7690
  const manifest = readJson(
7601
- (0, import_node_path32.join)(workspaceRoot, "package.json")
7691
+ (0, import_node_path33.join)(workspaceRoot, "package.json")
7602
7692
  );
7603
7693
  return manifest.scripts?.["python:install"] !== void 0;
7604
7694
  } catch {
@@ -7614,7 +7704,7 @@ function applyGoUpdates(workspaceRoot, entries) {
7614
7704
  }
7615
7705
  }
7616
7706
  async function runUp(workspaceRoot, options) {
7617
- if (!fileExists((0, import_node_path32.join)(workspaceRoot, "nx.json"))) {
7707
+ if (!fileExists((0, import_node_path33.join)(workspaceRoot, "nx.json"))) {
7618
7708
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
7619
7709
  }
7620
7710
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -7691,7 +7781,7 @@ var PROJECT_KINDS = [
7691
7781
  var EMPTY_KINDS = /* @__PURE__ */ new Set(["npm-lib", "internal-lib", "react-lib", "react-internal-lib", "node-function-app"]);
7692
7782
  async function runAdd(kind, name, options) {
7693
7783
  const workspaceRoot = process.cwd();
7694
- if (!fileExists((0, import_node_path33.join)(workspaceRoot, "nx.json"))) {
7784
+ if (!fileExists((0, import_node_path34.join)(workspaceRoot, "nx.json"))) {
7695
7785
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
7696
7786
  }
7697
7787
  const stack = readWorkspaceStack(workspaceRoot);
@@ -7712,13 +7802,24 @@ async function runAdd(kind, name, options) {
7712
7802
  if (options.empty === true && !EMPTY_KINDS.has(resolvedKind)) {
7713
7803
  throw new Error(`--empty applies to ${[...EMPTY_KINDS].join(", ")}, not ${resolvedKind}.`);
7714
7804
  }
7805
+ if (options.esm === true) {
7806
+ if (resolvedKind !== "node-app" && resolvedKind !== "node-function-app") {
7807
+ throw new Error(`--esm applies to node-app and node-function-app, not ${resolvedKind}.`);
7808
+ }
7809
+ if (options.framework === "fastify" || options.framework === "nest") {
7810
+ throw new Error(`--esm is not supported with --framework ${options.framework}: its layout (autoloaded routes, decorators) is mandated by the framework. Use express, koa or none.`);
7811
+ }
7812
+ }
7813
+ if (resolvedKind !== "react-app" && options.e2e === true) {
7814
+ throw new Error(`--e2e applies to react-app, not ${resolvedKind}.`);
7815
+ }
7715
7816
  const resolvedName = name ?? await promptText("Project name");
7716
7817
  assertValidProjectName(resolvedName, "Project name");
7717
7818
  const rootDependenciesBefore = rootRuntimeDependencies(workspaceRoot);
7718
7819
  ensureNxPeerOverrides(workspaceRoot);
7719
7820
  switch (resolvedKind) {
7720
7821
  case "react-app": {
7721
- addReactApp(workspaceRoot, resolvedName, stack);
7822
+ addReactApp(workspaceRoot, resolvedName, stack, options.e2e === true);
7722
7823
  break;
7723
7824
  }
7724
7825
  case "react-lib": {
@@ -7730,11 +7831,11 @@ async function runAdd(kind, name, options) {
7730
7831
  break;
7731
7832
  }
7732
7833
  case "node-app": {
7733
- addNodeApp(workspaceRoot, resolvedName, stack, options.framework);
7834
+ addNodeApp(workspaceRoot, resolvedName, stack, options.framework, options.esm === true);
7734
7835
  break;
7735
7836
  }
7736
7837
  case "node-function-app": {
7737
- addNodeFunctionApp(workspaceRoot, resolvedName, stack, options.empty === true);
7838
+ addNodeFunctionApp(workspaceRoot, resolvedName, stack, options.empty === true, options.esm === true);
7738
7839
  break;
7739
7840
  }
7740
7841
  case "npm-lib": {
@@ -7754,8 +7855,8 @@ async function runAdd(kind, name, options) {
7754
7855
  ],
7755
7856
  workspaceRoot
7756
7857
  );
7757
- markPrivate((0, import_node_path33.join)(workspaceRoot, "libs", resolvedName, "package.json"));
7758
- renameScaffoldPlaceholder((0, import_node_path33.join)(workspaceRoot, "libs", resolvedName), resolvedName, options.empty === true);
7858
+ markPrivate((0, import_node_path34.join)(workspaceRoot, "libs", resolvedName, "package.json"));
7859
+ renameScaffoldPlaceholder((0, import_node_path34.join)(workspaceRoot, "libs", resolvedName), resolvedName, options.empty === true);
7759
7860
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
7760
7861
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
7761
7862
  break;
@@ -7847,7 +7948,7 @@ async function runAdd(kind, name, options) {
7847
7948
  }
7848
7949
  function readWorkspaceStack(workspaceRoot) {
7849
7950
  const nxJson = readJson(
7850
- (0, import_node_path33.join)(workspaceRoot, "nx.json")
7951
+ (0, import_node_path34.join)(workspaceRoot, "nx.json")
7851
7952
  );
7852
7953
  const stack = nxJson.mnci?.stack;
7853
7954
  return {
@@ -7857,11 +7958,11 @@ function readWorkspaceStack(workspaceRoot) {
7857
7958
 
7858
7959
  // src/project-scaffolding/project-kind-catalog.config.ts
7859
7960
  var PROJECT_KIND_CATALOG = [
7860
- { kind: "react-app", language: "typescript", label: "React app", description: "A Vite React app, built per environment", flags: [], requiredFlags: [] },
7961
+ { kind: "react-app", language: "typescript", label: "React app", description: "A Vite React app, built per environment", flags: ["e2e"], requiredFlags: [] },
7861
7962
  { kind: "react-lib", language: "typescript", label: "React library", description: "A publishable React component library", flags: ["scope", "empty"], requiredFlags: [] },
7862
7963
  { kind: "react-internal-lib", language: "typescript", label: "React internal library", description: "A private React library for apps in this workspace", flags: ["empty"], requiredFlags: [] },
7863
- { kind: "node-app", language: "typescript", label: "Node app", description: "A Node service, with Express, Fastify, Koa or Nest if you choose one", flags: ["framework"], requiredFlags: [] },
7864
- { kind: "node-function-app", language: "typescript", label: "Node function app", description: "An Azure Functions (v4) app in TypeScript", flags: ["empty"], requiredFlags: [] },
7964
+ { kind: "node-app", language: "typescript", label: "Node app", description: "A Node service, with Express, Fastify, Koa or Nest if you choose one", flags: ["framework", "esm"], requiredFlags: [] },
7965
+ { kind: "node-function-app", language: "typescript", label: "Node function app", description: "An Azure Functions (v4) app in TypeScript", flags: ["empty", "esm"], requiredFlags: [] },
7865
7966
  { kind: "npm-lib", language: "typescript", label: "npm library", description: "A library published to npm, bundled with Rollup", flags: ["scope", "empty"], requiredFlags: [] },
7866
7967
  { kind: "internal-lib", language: "typescript", label: "Internal library", description: "A private TypeScript library for apps in this workspace", flags: ["empty"], requiredFlags: [] },
7867
7968
  { kind: "vscode-extension", language: "typescript", label: "VS Code extension", description: "A bundled Marketplace extension, optionally shipping a Go sidecar", flags: ["publisher", "sidecar"], requiredFlags: [] },
@@ -7896,12 +7997,12 @@ function runKinds(options) {
7896
7997
 
7897
7998
  // src/workspace-diagnostics/check-invariants.use-case.ts
7898
7999
  var import_node_child_process = require("child_process");
7899
- var import_node_fs30 = require("fs");
7900
- var import_node_path35 = require("path");
8000
+ var import_node_fs31 = require("fs");
8001
+ var import_node_path36 = require("path");
7901
8002
 
7902
8003
  // src/workspace-diagnostics/locate-stranded-release-tags.use-case.ts
7903
- var import_node_fs29 = require("fs");
7904
- var import_node_path34 = require("path");
8004
+ var import_node_fs30 = require("fs");
8005
+ var import_node_path35 = require("path");
7905
8006
 
7906
8007
  // src/workspace-diagnostics/stranded-release-tags.algorithm.ts
7907
8008
  function compareVersions2(left, right) {
@@ -7938,7 +8039,7 @@ function locateStrandedReleaseTags(workspaceRoot, tagPattern) {
7938
8039
  if (listed.status !== 0) {
7939
8040
  return [];
7940
8041
  }
7941
- const projects = (0, import_node_fs29.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot }).map((path) => readJson((0, import_node_path34.join)(workspaceRoot, path))).filter((manifest) => manifest.private !== true && manifest.name !== void 0).map((manifest) => manifest.name);
8042
+ const projects = (0, import_node_fs30.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot }).map((path) => readJson((0, import_node_path35.join)(workspaceRoot, path))).filter((manifest) => manifest.private !== true && manifest.name !== void 0).map((manifest) => manifest.name);
7942
8043
  return findStrandedReleaseTags(projects, listed.stdout.split(/\r?\n/).filter(Boolean));
7943
8044
  }
7944
8045
 
@@ -7948,8 +8049,8 @@ function toPosix2(path) {
7948
8049
  return path.replaceAll("\\", "/");
7949
8050
  }
7950
8051
  function checkEslintConfigs(workspaceRoot) {
7951
- const rootConfigs = (0, import_node_fs30.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
7952
- const projectConfigs = (0, import_node_fs30.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
8052
+ const rootConfigs = (0, import_node_fs31.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
8053
+ const projectConfigs = (0, import_node_fs31.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
7953
8054
  cwd: workspaceRoot
7954
8055
  }).map((config) => toPosix2(config));
7955
8056
  return [
@@ -7969,10 +8070,10 @@ function checkEslintConfigs(workspaceRoot) {
7969
8070
  ];
7970
8071
  }
7971
8072
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
7972
- const rules = (0, import_node_path35.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
7973
- if (!(0, import_node_fs30.existsSync)(rules)) return [];
7974
- const entryPoint = (0, import_node_path35.join)(workspaceRoot, ESLINT_USER_FILENAME);
7975
- const source = (0, import_node_fs30.existsSync)(entryPoint) ? (0, import_node_fs30.readFileSync)(entryPoint, "utf8") : "";
8073
+ const rules = (0, import_node_path36.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
8074
+ if (!(0, import_node_fs31.existsSync)(rules)) return [];
8075
+ const entryPoint = (0, import_node_path36.join)(workspaceRoot, ESLINT_USER_FILENAME);
8076
+ const source = (0, import_node_fs31.existsSync)(entryPoint) ? (0, import_node_fs31.readFileSync)(entryPoint, "utf8") : "";
7976
8077
  return [
7977
8078
  {
7978
8079
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -7985,7 +8086,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
7985
8086
  function declaredDevDependencies(workspaceRoot) {
7986
8087
  try {
7987
8088
  const manifest = readJson(
7988
- (0, import_node_path35.join)(workspaceRoot, "package.json")
8089
+ (0, import_node_path36.join)(workspaceRoot, "package.json")
7989
8090
  );
7990
8091
  return manifest.devDependencies ?? {};
7991
8092
  } catch {
@@ -7993,7 +8094,7 @@ function declaredDevDependencies(workspaceRoot) {
7993
8094
  }
7994
8095
  }
7995
8096
  function checkNoRetiredFormatter(workspaceRoot) {
7996
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path35.join)(workspaceRoot, file)));
8097
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path36.join)(workspaceRoot, file)));
7997
8098
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
7998
8099
  const stale = [...files, ...declared];
7999
8100
  if (stale.length === 0) {
@@ -8019,7 +8120,7 @@ function checkEslintPlugin(nxJson) {
8019
8120
  };
8020
8121
  }
8021
8122
  function checkResolvedEslint(workspaceRoot) {
8022
- const manifestPath = (0, import_node_path35.join)(workspaceRoot, "node_modules/eslint/package.json");
8123
+ const manifestPath = (0, import_node_path36.join)(workspaceRoot, "node_modules/eslint/package.json");
8023
8124
  if (!fileExists(manifestPath)) {
8024
8125
  return void 0;
8025
8126
  }
@@ -8037,11 +8138,11 @@ function checkResolvedEslint(workspaceRoot) {
8037
8138
  }
8038
8139
  }
8039
8140
  function checkNpmrc(workspaceRoot, registry, scope) {
8040
- const npmrcPath = (0, import_node_path35.join)(workspaceRoot, ".npmrc");
8141
+ const npmrcPath = (0, import_node_path36.join)(workspaceRoot, ".npmrc");
8041
8142
  if (!registry || !fileExists(npmrcPath)) {
8042
8143
  return void 0;
8043
8144
  }
8044
- const npmrc = (0, import_node_fs30.readFileSync)(npmrcPath, "utf8");
8145
+ const npmrc = (0, import_node_fs31.readFileSync)(npmrcPath, "utf8");
8045
8146
  if (registry.kind === "npm") {
8046
8147
  return {
8047
8148
  check: ".npmrc authenticates the public registry",
@@ -8058,11 +8159,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
8058
8159
  };
8059
8160
  }
8060
8161
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
8061
- const npmrcPath = (0, import_node_path35.join)(workspaceRoot, ".npmrc");
8162
+ const npmrcPath = (0, import_node_path36.join)(workspaceRoot, ".npmrc");
8062
8163
  if (!fileExists(npmrcPath)) {
8063
8164
  return void 0;
8064
8165
  }
8065
- const npmrc = (0, import_node_fs30.readFileSync)(npmrcPath, "utf8");
8166
+ const npmrc = (0, import_node_fs31.readFileSync)(npmrcPath, "utf8");
8066
8167
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
8067
8168
  const referenced = [
8068
8169
  ...new Set(
@@ -8086,13 +8187,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
8086
8187
  };
8087
8188
  }
8088
8189
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
8089
- const npmrcPath = (0, import_node_path35.join)(workspaceRoot, ".npmrc");
8090
- const pipelinePath = (0, import_node_path35.join)(workspaceRoot, "azure-pipelines.yml");
8190
+ const npmrcPath = (0, import_node_path36.join)(workspaceRoot, ".npmrc");
8191
+ const pipelinePath = (0, import_node_path36.join)(workspaceRoot, "azure-pipelines.yml");
8091
8192
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
8092
8193
  return void 0;
8093
8194
  }
8094
- const holdsCredentials = (0, import_node_fs30.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
8095
- const runsTask = (0, import_node_fs30.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
8195
+ const holdsCredentials = (0, import_node_fs31.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
8196
+ const runsTask = (0, import_node_fs31.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
8096
8197
  if (!holdsCredentials && !runsTask) {
8097
8198
  return {
8098
8199
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -8137,13 +8238,13 @@ function npmjsCredentialShape(credentials, environment) {
8137
8238
  }
8138
8239
  function checkVersionActions(workspaceRoot) {
8139
8240
  const candidates = [
8140
- ...(0, import_node_fs30.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
8141
- ...(0, import_node_fs30.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
8142
- ...(0, import_node_fs30.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
8241
+ ...(0, import_node_fs31.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
8242
+ ...(0, import_node_fs31.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
8243
+ ...(0, import_node_fs31.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
8143
8244
  ].map((manifest) => toPosix2(manifest));
8144
8245
  return candidates.flatMap((manifest) => {
8145
8246
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
8146
- const projectJsonPath = (0, import_node_path35.join)(workspaceRoot, projectRoot, "project.json");
8247
+ const projectJsonPath = (0, import_node_path36.join)(workspaceRoot, projectRoot, "project.json");
8147
8248
  let hasOverride = false;
8148
8249
  try {
8149
8250
  const projectJson = readJson(projectJsonPath);
@@ -8172,7 +8273,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
8172
8273
  ]) {
8173
8274
  try {
8174
8275
  const targets = extract(
8175
- readJson((0, import_node_path35.join)(workspaceRoot, projectRoot, file))
8276
+ readJson((0, import_node_path36.join)(workspaceRoot, projectRoot, file))
8176
8277
  );
8177
8278
  if (targets && typeof targets === "object") {
8178
8279
  sources.push({
@@ -8188,8 +8289,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
8188
8289
  function checkTargetFilesExist(workspaceRoot) {
8189
8290
  const projectRoots = new Set(
8190
8291
  [
8191
- ...(0, import_node_fs30.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
8192
- ...(0, import_node_fs30.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
8292
+ ...(0, import_node_fs31.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
8293
+ ...(0, import_node_fs31.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
8193
8294
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
8194
8295
  );
8195
8296
  return [...projectRoots].flatMap(
@@ -8204,7 +8305,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
8204
8305
  return TARGET_FILE_OPTIONS.flatMap((option) => {
8205
8306
  const value = target?.options?.[option];
8206
8307
  const checkable = typeof value === "string" && !value.includes("{");
8207
- if (!checkable || fileExists((0, import_node_path35.join)(workspaceRoot, value))) {
8308
+ if (!checkable || fileExists((0, import_node_path36.join)(workspaceRoot, value))) {
8208
8309
  return [];
8209
8310
  }
8210
8311
  return [
@@ -8243,15 +8344,15 @@ function checkGoPluginRegistered(workspaceRoot) {
8243
8344
  };
8244
8345
  }
8245
8346
  function checkGoWorkInSync(workspaceRoot) {
8246
- const goWorkPath = (0, import_node_path35.join)(workspaceRoot, "go.work");
8347
+ const goWorkPath = (0, import_node_path36.join)(workspaceRoot, "go.work");
8247
8348
  if (!fileExists(goWorkPath)) {
8248
8349
  return void 0;
8249
8350
  }
8250
- const contents = (0, import_node_fs30.existsSync)(goWorkPath) ? (0, import_node_fs30.readFileSync)(goWorkPath, "utf8") : "";
8351
+ const contents = (0, import_node_fs31.existsSync)(goWorkPath) ? (0, import_node_fs31.readFileSync)(goWorkPath, "utf8") : "";
8251
8352
  const blockEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+\(([^)]*)\)/g), (match) => match[1].split("\n")).flat();
8252
8353
  const singleEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+(\.\S+)/g), (match) => match[1]);
8253
8354
  const uses = [...blockEntries, ...singleEntries].map((entry) => entry.trim()).filter(Boolean);
8254
- const stale = uses.filter((entry) => !(0, import_node_fs30.existsSync)((0, import_node_path35.join)(workspaceRoot, entry, "go.mod")));
8355
+ const stale = uses.filter((entry) => !(0, import_node_fs31.existsSync)((0, import_node_path36.join)(workspaceRoot, entry, "go.mod")));
8255
8356
  return {
8256
8357
  check: "every go.work `use` entry points to a module that still exists",
8257
8358
  ok: stale.length === 0,
@@ -8267,9 +8368,9 @@ function checkNativeApps(workspaceRoot) {
8267
8368
  { file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
8268
8369
  { file: "azure-pipelines.yml", marker: "- job: native" }
8269
8370
  ];
8270
- const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path35.join)(workspaceRoot, file))).map(({ file, marker }) => ({
8371
+ const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path36.join)(workspaceRoot, file))).map(({ file, marker }) => ({
8271
8372
  check: `${file} builds the native apps on every OS`,
8272
- ok: (0, import_node_fs30.readFileSync)((0, import_node_path35.join)(workspaceRoot, file), "utf8").includes(marker),
8373
+ ok: (0, import_node_fs31.readFileSync)((0, import_node_path36.join)(workspaceRoot, file), "utf8").includes(marker),
8273
8374
  detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
8274
8375
  remedy: "run `mnci upgrade`"
8275
8376
  }));
@@ -8282,7 +8383,7 @@ function checkNativeApps(workspaceRoot) {
8282
8383
  return findings;
8283
8384
  }
8284
8385
  function checkNoRootRuntimeDependencies(workspaceRoot) {
8285
- const manifestPath = (0, import_node_path35.join)(workspaceRoot, "package.json");
8386
+ const manifestPath = (0, import_node_path36.join)(workspaceRoot, "package.json");
8286
8387
  if (!fileExists(manifestPath)) {
8287
8388
  return void 0;
8288
8389
  }
@@ -8302,14 +8403,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
8302
8403
  };
8303
8404
  }
8304
8405
  function checkRollupSourceMaps(workspaceRoot) {
8305
- const configs = (0, import_node_fs30.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8406
+ const configs = (0, import_node_fs31.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8306
8407
  cwd: workspaceRoot
8307
8408
  }).map((config) => toPosix2(config));
8308
8409
  return configs.flatMap((relativePath) => {
8309
- const configPath = (0, import_node_path35.join)(workspaceRoot, relativePath);
8410
+ const configPath = (0, import_node_path36.join)(workspaceRoot, relativePath);
8310
8411
  let config;
8311
8412
  try {
8312
- config = (0, import_node_fs30.readFileSync)(configPath, "utf8");
8413
+ config = (0, import_node_fs31.readFileSync)(configPath, "utf8");
8313
8414
  } catch {
8314
8415
  return [];
8315
8416
  }
@@ -8324,11 +8425,11 @@ function checkRollupSourceMaps(workspaceRoot) {
8324
8425
  });
8325
8426
  }
8326
8427
  function checkDeclarationSpecifiers(workspaceRoot) {
8327
- const configs = (0, import_node_fs30.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8428
+ const configs = (0, import_node_fs31.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8328
8429
  cwd: workspaceRoot
8329
8430
  }).map((config) => toPosix2(config));
8330
8431
  return configs.flatMap((relativePath) => {
8331
- const configPath = (0, import_node_path35.join)(workspaceRoot, relativePath);
8432
+ const configPath = (0, import_node_path36.join)(workspaceRoot, relativePath);
8332
8433
  if (!fileExists(configPath)) {
8333
8434
  return [];
8334
8435
  }
@@ -8343,7 +8444,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
8343
8444
  // `plugins` array (what @nx/react:library writes). For any other shape it would no-op, and
8344
8445
  // naming a command that silently does nothing is the failure mode the source-map check
8345
8446
  // above goes out of its way to avoid, so the remedy depends on the shape.
8346
- remedy: canAddDeclarationSpecifierPlugin((0, import_node_fs30.readFileSync)(configPath, "utf8")) ? "run `mnci upgrade`, which adds the plugin to the plugins array of withNx's second argument" : "add the plugin to withNx's second argument by hand (copy it from a freshly `mnci add npm-lib`'d project) \u2014 mnci does not recognise the shape of this config, so `mnci upgrade` cannot add it"
8447
+ remedy: canAddDeclarationSpecifierPlugin((0, import_node_fs31.readFileSync)(configPath, "utf8")) ? "run `mnci upgrade`, which adds the plugin to the plugins array of withNx's second argument" : "add the plugin to withNx's second argument by hand (copy it from a freshly `mnci add npm-lib`'d project) \u2014 mnci does not recognise the shape of this config, so `mnci upgrade` cannot add it"
8347
8448
  }
8348
8449
  ];
8349
8450
  }
@@ -8359,8 +8460,8 @@ function checkDeclarationSpecifiers(workspaceRoot) {
8359
8460
  }
8360
8461
  function checkPipelinePhases(workspaceRoot) {
8361
8462
  const files = ["azure-pipelines.yml", ".github/workflows/ci.yml"];
8362
- return files.filter((file) => fileExists((0, import_node_path35.join)(workspaceRoot, file))).flatMap((file) => {
8363
- const { verifyActive, switchedOff } = inspectPipeline((0, import_node_fs30.readFileSync)((0, import_node_path35.join)(workspaceRoot, file), "utf8"));
8463
+ return files.filter((file) => fileExists((0, import_node_path36.join)(workspaceRoot, file))).flatMap((file) => {
8464
+ const { verifyActive, switchedOff } = inspectPipeline((0, import_node_fs31.readFileSync)((0, import_node_path36.join)(workspaceRoot, file), "utf8"));
8364
8465
  const verify = {
8365
8466
  check: `${file} runs the enforced verify phase`,
8366
8467
  ok: verifyActive,
@@ -8401,7 +8502,7 @@ function checkDependencyRangesNotPreserved(nxJson) {
8401
8502
  };
8402
8503
  }
8403
8504
  function checkLockfileHasNoLocalRegistry(workspaceRoot) {
8404
- if (!fileExists((0, import_node_path35.join)(workspaceRoot, "package-lock.json"))) {
8505
+ if (!fileExists((0, import_node_path36.join)(workspaceRoot, "package-lock.json"))) {
8405
8506
  return void 0;
8406
8507
  }
8407
8508
  return {
@@ -8421,7 +8522,7 @@ function checkReleaseTagsResolve(workspaceRoot, nxJson) {
8421
8522
  };
8422
8523
  }
8423
8524
  function collectFindings(workspaceRoot) {
8424
- const nxJsonPath = (0, import_node_path35.join)(workspaceRoot, "nx.json");
8525
+ const nxJsonPath = (0, import_node_path36.join)(workspaceRoot, "nx.json");
8425
8526
  if (!fileExists(nxJsonPath)) {
8426
8527
  throw new Error(
8427
8528
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -8486,8 +8587,8 @@ function runDoctor(workspaceRoot, options = {}) {
8486
8587
  }
8487
8588
 
8488
8589
  // src/repository-adoption/adopt-dependencies.use-case.ts
8489
- var import_node_fs31 = require("fs");
8490
- var import_node_path36 = require("path");
8590
+ var import_node_fs32 = require("fs");
8591
+ var import_node_path37 = require("path");
8491
8592
 
8492
8593
  // src/repository-adoption/clean-working-tree.validator.ts
8493
8594
  function requireCleanWorkingTree(repositoryRoot, capture = runCapture) {
@@ -8558,7 +8659,7 @@ var SOURCE_FILE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
8558
8659
  var TEST_FILE = /\.(?:spec|test)\.[^.]+$|[\\/](?:__tests__|tests?|e2e)[\\/]/;
8559
8660
  var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage", "out", ".git", ".nx", "tmp"]);
8560
8661
  function sourceFiles(directory, relative = "") {
8561
- const entries = (0, import_node_fs31.readdirSync)((0, import_node_path36.join)(directory, relative), { withFileTypes: true });
8662
+ const entries = (0, import_node_fs32.readdirSync)((0, import_node_path37.join)(directory, relative), { withFileTypes: true });
8562
8663
  const found = [];
8563
8664
  for (const entry of entries) {
8564
8665
  const path = relative === "" ? entry.name : `${relative}/${entry.name}`;
@@ -8574,7 +8675,7 @@ function sourceFiles(directory, relative = "") {
8574
8675
  }
8575
8676
  function wantedImportsOf(path, wanted) {
8576
8677
  try {
8577
- const imported = [...extractImportedPackages((0, import_node_fs31.readFileSync)(path, "utf8"))];
8678
+ const imported = [...extractImportedPackages((0, import_node_fs32.readFileSync)(path, "utf8"))];
8578
8679
  return imported.filter((name) => wanted.has(name));
8579
8680
  } catch {
8580
8681
  return [];
@@ -8585,7 +8686,7 @@ function importsOfProject(projectDirectory, wanted) {
8585
8686
  const tested = /* @__PURE__ */ new Set();
8586
8687
  const files = sourceFiles(projectDirectory);
8587
8688
  for (const file of files) {
8588
- const names = wantedImportsOf((0, import_node_path36.join)(projectDirectory, file), wanted);
8689
+ const names = wantedImportsOf((0, import_node_path37.join)(projectDirectory, file), wanted);
8589
8690
  const target = TEST_FILE.test(file) ? tested : shipped;
8590
8691
  for (const name of names) {
8591
8692
  target.add(name);
@@ -8597,7 +8698,7 @@ function importsOfProject(projectDirectory, wanted) {
8597
8698
  function findUsage(repositoryRoot, projectDirectories, wanted) {
8598
8699
  const usage = {};
8599
8700
  for (const dir of projectDirectories) {
8600
- const { shipped, testsOnly } = importsOfProject((0, import_node_path36.join)(repositoryRoot, dir), wanted);
8701
+ const { shipped, testsOnly } = importsOfProject((0, import_node_path37.join)(repositoryRoot, dir), wanted);
8601
8702
  for (const name of shipped) {
8602
8703
  usage[name] ??= { runtime: [], testsOnly: [] };
8603
8704
  usage[name].runtime.push(dir);
@@ -8612,7 +8713,7 @@ function findUsage(repositoryRoot, projectDirectories, wanted) {
8612
8713
  function adoptDependencies(repositoryRoot, dependencies = {}) {
8613
8714
  const run = dependencies.run ?? runShell;
8614
8715
  requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
8615
- const rootPath = (0, import_node_path36.join)(repositoryRoot, "package.json");
8716
+ const rootPath = (0, import_node_path37.join)(repositoryRoot, "package.json");
8616
8717
  if (!fileExists(rootPath)) {
8617
8718
  throw new Error("No package.json at the repository root.");
8618
8719
  }
@@ -8647,8 +8748,8 @@ function adoptDependencies(repositoryRoot, dependencies = {}) {
8647
8748
  }
8648
8749
 
8649
8750
  // src/repository-adoption/adopt-kinds.use-case.ts
8650
- var import_node_fs32 = require("fs");
8651
- var import_node_path37 = require("path");
8751
+ var import_node_fs33 = require("fs");
8752
+ var import_node_path38 = require("path");
8652
8753
 
8653
8754
  // src/repository-adoption/infer-project-kind.algorithm.ts
8654
8755
  var SERVER_FRAMEWORKS = ["express", "koa", "fastify", "@nestjs/core"];
@@ -8749,32 +8850,32 @@ function inferProjectKind(evidence) {
8749
8850
  // src/repository-adoption/adopt-kinds.use-case.ts
8750
8851
  var TYPE_TAG = "type:";
8751
8852
  function readEvidence(repositoryRoot, location) {
8752
- const directory = (0, import_node_path37.join)(repositoryRoot, location.dir);
8753
- const files = (0, import_node_fs32.readdirSync)(directory);
8853
+ const directory = (0, import_node_path38.join)(repositoryRoot, location.dir);
8854
+ const files = (0, import_node_fs33.readdirSync)(directory);
8754
8855
  const manifest = location.ecosystem === "npm" ? readJson(location.manifestPath) : {};
8755
- const text = location.ecosystem === "npm" ? "" : (0, import_node_fs32.readFileSync)(location.manifestPath, "utf8");
8856
+ const text = location.ecosystem === "npm" ? "" : (0, import_node_fs33.readFileSync)(location.manifestPath, "utf8");
8756
8857
  let hasProgram = false;
8757
8858
  if (location.ecosystem === "go") {
8758
- hasProgram = files.filter((file) => file.endsWith(".go")).some((file) => /^package main\b/m.test((0, import_node_fs32.readFileSync)((0, import_node_path37.join)(directory, file), "utf8")));
8859
+ hasProgram = files.filter((file) => file.endsWith(".go")).some((file) => /^package main\b/m.test((0, import_node_fs33.readFileSync)((0, import_node_path38.join)(directory, file), "utf8")));
8759
8860
  } else if (location.ecosystem === "pub") {
8760
- hasProgram = (0, import_node_fs32.existsSync)((0, import_node_path37.join)(directory, "lib", "main.dart"));
8861
+ hasProgram = (0, import_node_fs33.existsSync)((0, import_node_path38.join)(directory, "lib", "main.dart"));
8761
8862
  }
8762
8863
  return { ecosystem: location.ecosystem, manifest, text, files, hasProgram };
8763
8864
  }
8764
8865
  function existingKind(directory) {
8765
8866
  const sources = [];
8766
- if (fileExists((0, import_node_path37.join)(directory, "project.json"))) {
8767
- sources.push(readJson((0, import_node_path37.join)(directory, "project.json")).tags ?? []);
8867
+ if (fileExists((0, import_node_path38.join)(directory, "project.json"))) {
8868
+ sources.push(readJson((0, import_node_path38.join)(directory, "project.json")).tags ?? []);
8768
8869
  }
8769
- if (fileExists((0, import_node_path37.join)(directory, "package.json"))) {
8770
- sources.push(readJson((0, import_node_path37.join)(directory, "package.json")).nx?.tags ?? []);
8870
+ if (fileExists((0, import_node_path38.join)(directory, "package.json"))) {
8871
+ sources.push(readJson((0, import_node_path38.join)(directory, "package.json")).nx?.tags ?? []);
8771
8872
  }
8772
8873
  return sources.flat().find((tag) => tag.startsWith(TYPE_TAG))?.slice(TYPE_TAG.length);
8773
8874
  }
8774
8875
  function writeKindTag(directory, name, kind) {
8775
8876
  const tag = `${TYPE_TAG}${kind}`;
8776
- const projectJson = (0, import_node_path37.join)(directory, "project.json");
8777
- const packageJson = (0, import_node_path37.join)(directory, "package.json");
8877
+ const projectJson = (0, import_node_path38.join)(directory, "project.json");
8878
+ const packageJson = (0, import_node_path38.join)(directory, "package.json");
8778
8879
  if (fileExists(projectJson)) {
8779
8880
  const project = readJson(projectJson);
8780
8881
  writeFileEnsured(projectJson, toJson({ ...project, tags: [...project.tags ?? [], tag] }));
@@ -8798,7 +8899,7 @@ function adoptKinds(repositoryRoot, overrides = {}, dependencies = {}) {
8798
8899
  }
8799
8900
  }
8800
8901
  return locations.map((location) => {
8801
- const directory = (0, import_node_path37.join)(repositoryRoot, location.dir);
8902
+ const directory = (0, import_node_path38.join)(repositoryRoot, location.dir);
8802
8903
  const present = existingKind(directory);
8803
8904
  if (present !== void 0) {
8804
8905
  return { dir: location.dir, outcome: "already", kind: present, reason: PROJECT_KINDS.includes(present) ? "it already has a type tag" : "it already has a type tag of its own, which is not an mnci kind name; left as it is" };
@@ -8814,12 +8915,12 @@ function adoptKinds(repositoryRoot, overrides = {}, dependencies = {}) {
8814
8915
  }
8815
8916
 
8816
8917
  // src/repository-adoption/adopt-overlay.use-case.ts
8817
- var import_node_fs34 = require("fs");
8818
- var import_node_path39 = require("path");
8918
+ var import_node_fs35 = require("fs");
8919
+ var import_node_path40 = require("path");
8819
8920
 
8820
8921
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
8821
- var import_node_fs33 = require("fs");
8822
- var import_node_path38 = require("path");
8922
+ var import_node_fs34 = require("fs");
8923
+ var import_node_path39 = require("path");
8823
8924
  function resolveRegistry(options, persisted) {
8824
8925
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
8825
8926
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -8848,7 +8949,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
8848
8949
  return persisted.workspaceName;
8849
8950
  }
8850
8951
  try {
8851
- const existing = (0, import_node_fs33.readdirSync)(workspaceRoot).find(
8952
+ const existing = (0, import_node_fs34.readdirSync)(workspaceRoot).find(
8852
8953
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
8853
8954
  );
8854
8955
  if (existing) {
@@ -8856,11 +8957,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
8856
8957
  }
8857
8958
  } catch {
8858
8959
  }
8859
- return (0, import_node_path38.basename)(workspaceRoot);
8960
+ return (0, import_node_path39.basename)(workspaceRoot);
8860
8961
  }
8861
8962
  function detectNpmAuth(workspaceRoot) {
8862
8963
  try {
8863
- return (0, import_node_fs33.readFileSync)((0, import_node_path38.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
8964
+ return (0, import_node_fs34.readFileSync)((0, import_node_path39.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
8864
8965
  } catch {
8865
8966
  return void 0;
8866
8967
  }
@@ -8907,7 +9008,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
8907
9008
  };
8908
9009
  }
8909
9010
  function runUpgrade(workspaceRoot, options) {
8910
- if (!fileExists((0, import_node_path38.join)(workspaceRoot, "nx.json"))) {
9011
+ if (!fileExists((0, import_node_path39.join)(workspaceRoot, "nx.json"))) {
8911
9012
  throw new Error(
8912
9013
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
8913
9014
  );
@@ -8981,7 +9082,7 @@ function runUpgrade(workspaceRoot, options) {
8981
9082
  "Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
8982
9083
  );
8983
9084
  runFormatter(workspaceRoot);
8984
- const nxJson = readJson((0, import_node_path38.join)(workspaceRoot, "nx.json"));
9085
+ const nxJson = readJson((0, import_node_path39.join)(workspaceRoot, "nx.json"));
8985
9086
  const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
8986
9087
  for (const entry of stranded) {
8987
9088
  logger.warn(`${entry.project} has release tags only under ${entry.oldTag}: nx release would restart it from its disk version. Run \`mnci adopt --tags\` before the next release to create ${entry.newTag} locally (\`mnci doctor\` lists them all).`);
@@ -8992,9 +9093,9 @@ function runUpgrade(workspaceRoot, options) {
8992
9093
 
8993
9094
  // src/repository-adoption/adopt-overlay.use-case.ts
8994
9095
  function detectCiProvider(repositoryRoot) {
8995
- const azure = (0, import_node_fs34.existsSync)((0, import_node_path39.join)(repositoryRoot, "azure-pipelines.yml"));
8996
- const workflows = (0, import_node_path39.join)(repositoryRoot, ".github", "workflows");
8997
- const github = (0, import_node_fs34.existsSync)(workflows) && (0, import_node_fs34.readdirSync)(workflows).some((file) => /\.ya?ml$/.test(file));
9096
+ const azure = (0, import_node_fs35.existsSync)((0, import_node_path40.join)(repositoryRoot, "azure-pipelines.yml"));
9097
+ const workflows = (0, import_node_path40.join)(repositoryRoot, ".github", "workflows");
9098
+ const github = (0, import_node_fs35.existsSync)(workflows) && (0, import_node_fs35.readdirSync)(workflows).some((file) => /\.ya?ml$/.test(file));
8998
9099
  if (azure && github) {
8999
9100
  return "both";
9000
9101
  }
@@ -9004,7 +9105,7 @@ function detectCiProvider(repositoryRoot) {
9004
9105
  return github ? "github" : void 0;
9005
9106
  }
9006
9107
  function detectTestRunner(repositoryRoot) {
9007
- const manifestPath = (0, import_node_path39.join)(repositoryRoot, "package.json");
9108
+ const manifestPath = (0, import_node_path40.join)(repositoryRoot, "package.json");
9008
9109
  if (!fileExists(manifestPath)) {
9009
9110
  return void 0;
9010
9111
  }
@@ -9017,7 +9118,7 @@ function detectTestRunner(repositoryRoot) {
9017
9118
  }
9018
9119
  function adoptOverlay(repositoryRoot, options, dependencies = {}) {
9019
9120
  requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
9020
- if (!fileExists((0, import_node_path39.join)(repositoryRoot, "nx.json"))) {
9121
+ if (!fileExists((0, import_node_path40.join)(repositoryRoot, "nx.json"))) {
9021
9122
  throw new Error("There is no nx.json, so Nx is not set up here. Set it up first (`npx nx@latest init`); adopt does not install Nx yet.");
9022
9123
  }
9023
9124
  const persisted = readMnciConfig(repositoryRoot);
@@ -9030,7 +9131,7 @@ function adoptOverlay(repositoryRoot, options, dependencies = {}) {
9030
9131
  }
9031
9132
 
9032
9133
  // src/repository-adoption/adopt-toolchain.use-case.ts
9033
- var import_node_path41 = require("path");
9134
+ var import_node_path42 = require("path");
9034
9135
 
9035
9136
  // src/repository-adoption/align-nx-family.algorithm.ts
9036
9137
  var VERSION = /^[\^~]?(\d+)\.(\d+)\.(\d+)$/;
@@ -9068,24 +9169,24 @@ function alignNxFamily(dependencies, version) {
9068
9169
  }
9069
9170
 
9070
9171
  // src/repository-adoption/retire-tooling.use-case.ts
9071
- var import_node_fs35 = require("fs");
9072
- var import_node_path40 = require("path");
9172
+ var import_node_fs36 = require("fs");
9173
+ var import_node_path41 = require("path");
9073
9174
  var RETIRED_COMMAND = /\b(?:prettier|oxfmt|oxlint)\b/;
9074
9175
  function retireTooling(repositoryRoot) {
9075
9176
  const removed = [];
9076
9177
  for (const file of RETIRED_FORMATTER_FILES) {
9077
- if (!fileExists((0, import_node_path40.join)(repositoryRoot, file))) {
9178
+ if (!fileExists((0, import_node_path41.join)(repositoryRoot, file))) {
9078
9179
  continue;
9079
9180
  }
9080
- (0, import_node_fs35.rmSync)((0, import_node_path40.join)(repositoryRoot, file), { force: true });
9181
+ (0, import_node_fs36.rmSync)((0, import_node_path41.join)(repositoryRoot, file), { force: true });
9081
9182
  removed.push(file);
9082
9183
  }
9083
- const hadRegistry = fileExists((0, import_node_path40.join)(repositoryRoot, ".verdaccio"));
9184
+ const hadRegistry = fileExists((0, import_node_path41.join)(repositoryRoot, ".verdaccio"));
9084
9185
  removeLocalRegistryScaffolding(repositoryRoot);
9085
9186
  if (hadRegistry) {
9086
9187
  removed.push(".verdaccio, its dependency and the local-registry target");
9087
9188
  }
9088
- const manifestPath = (0, import_node_path40.join)(repositoryRoot, "package.json");
9189
+ const manifestPath = (0, import_node_path41.join)(repositoryRoot, "package.json");
9089
9190
  if (!fileExists(manifestPath)) {
9090
9191
  return removed;
9091
9192
  }
@@ -9132,7 +9233,7 @@ function adoptToolchain(repositoryRoot, options = {}, dependencies = {}) {
9132
9233
  console.log(message);
9133
9234
  });
9134
9235
  requireCleanWorkingTree(repositoryRoot, capture);
9135
- const manifestPath = (0, import_node_path41.join)(repositoryRoot, "package.json");
9236
+ const manifestPath = (0, import_node_path42.join)(repositoryRoot, "package.json");
9136
9237
  if (!fileExists(manifestPath)) {
9137
9238
  throw new Error("No package.json at the repository root.");
9138
9239
  }
@@ -9182,8 +9283,8 @@ function createBaselineTags(repositoryRoot, stranded) {
9182
9283
  }
9183
9284
 
9184
9285
  // src/repository-adoption/inspect-repository.use-case.ts
9185
- var import_node_fs36 = require("fs");
9186
- var import_node_path42 = require("path");
9286
+ var import_node_fs37 = require("fs");
9287
+ var import_node_path43 = require("path");
9187
9288
  var LOCKFILES = [
9188
9289
  ["package-lock.json", "npm"],
9189
9290
  ["pnpm-lock.yaml", "pnpm"],
@@ -9204,25 +9305,25 @@ function inspectRepository(repositoryRoot) {
9204
9305
  const isGitRepo = inside.status === 0 && inside.stdout.trim() === "true";
9205
9306
  const dirty = isGitRepo && runCapture("git", ["status", "--porcelain"], repositoryRoot).stdout.trim() !== "";
9206
9307
  const tags = isGitRepo ? runCapture("git", ["tag", "--list"], repositoryRoot).stdout.split(/\r?\n/).filter(Boolean) : [];
9207
- const manifestPath = (0, import_node_path42.join)(repositoryRoot, "package.json");
9308
+ const manifestPath = (0, import_node_path43.join)(repositoryRoot, "package.json");
9208
9309
  const manifest = fileExists(manifestPath) ? readJson(manifestPath) : {};
9209
- const nxJsonPath = (0, import_node_path42.join)(repositoryRoot, "nx.json");
9310
+ const nxJsonPath = (0, import_node_path43.join)(repositoryRoot, "nx.json");
9210
9311
  const nxJson = fileExists(nxJsonPath) ? readJson(nxJsonPath) : {};
9211
9312
  const ci = [];
9212
9313
  const pipelines = [];
9213
- if ((0, import_node_fs36.existsSync)((0, import_node_path42.join)(repositoryRoot, "azure-pipelines.yml"))) {
9314
+ if ((0, import_node_fs37.existsSync)((0, import_node_path43.join)(repositoryRoot, "azure-pipelines.yml"))) {
9214
9315
  ci.push("azure");
9215
- pipelines.push((0, import_node_path42.join)(repositoryRoot, "azure-pipelines.yml"));
9316
+ pipelines.push((0, import_node_path43.join)(repositoryRoot, "azure-pipelines.yml"));
9216
9317
  }
9217
- const workflows = (0, import_node_path42.join)(repositoryRoot, ".github", "workflows");
9218
- if ((0, import_node_fs36.existsSync)(workflows)) {
9219
- const files = (0, import_node_fs36.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
9318
+ const workflows = (0, import_node_path43.join)(repositoryRoot, ".github", "workflows");
9319
+ if ((0, import_node_fs37.existsSync)(workflows)) {
9320
+ const files = (0, import_node_fs37.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
9220
9321
  if (files.length > 0) {
9221
9322
  ci.push("github");
9222
- pipelines.push(...files.map((file) => (0, import_node_path42.join)(workflows, file)));
9323
+ pipelines.push(...files.map((file) => (0, import_node_path43.join)(workflows, file)));
9223
9324
  }
9224
9325
  }
9225
- const rootFiles = (0, import_node_fs36.readdirSync)(repositoryRoot);
9326
+ const rootFiles = (0, import_node_fs37.readdirSync)(repositoryRoot);
9226
9327
  return {
9227
9328
  isGitRepo,
9228
9329
  dirty,
@@ -9233,7 +9334,7 @@ function inspectRepository(repositoryRoot) {
9233
9334
  tagCount: tags.length,
9234
9335
  strandedTags: isGitRepo ? locateStrandedReleaseTags(repositoryRoot, nxJson.release?.releaseTag?.pattern) : [],
9235
9336
  ci,
9236
- pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs36.readFileSync)(file, "utf8"))),
9337
+ pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs37.readFileSync)(file, "utf8"))),
9237
9338
  retiredTooling: [.../* @__PURE__ */ new Set([...rootFiles.filter((file) => RETIRED_FILE_PATTERN.test(file) || file === ".verdaccio"), ...retiredNamesIn(manifest)])],
9238
9339
  personalFiles: PERSONAL_FILES.filter((file) => rootFiles.includes(file))
9239
9340
  };
@@ -9530,13 +9631,13 @@ function runCommands(program, options) {
9530
9631
  }
9531
9632
 
9532
9633
  // src/workspace-info/list-projects.use-case.ts
9533
- var import_node_path43 = require("path");
9634
+ var import_node_path44 = require("path");
9534
9635
  var TYPE_TAG_PREFIX = "type:";
9535
9636
  function listProjects(workspaceRoot) {
9536
9637
  return locateProjects(workspaceRoot).map((location) => {
9537
- const projectJsonPath = (0, import_node_path43.join)(workspaceRoot, location.dir, "project.json");
9638
+ const projectJsonPath = (0, import_node_path44.join)(workspaceRoot, location.dir, "project.json");
9538
9639
  const project = fileExists(projectJsonPath) ? readJson(projectJsonPath) : {};
9539
- const manifestPath = (0, import_node_path43.join)(workspaceRoot, location.dir, "package.json");
9640
+ const manifestPath = (0, import_node_path44.join)(workspaceRoot, location.dir, "package.json");
9540
9641
  const manifestTags = fileExists(manifestPath) ? readJson(manifestPath).nx?.tags ?? [] : [];
9541
9642
  const typeTag = [...project.tags ?? [], ...manifestTags].find((tag) => tag.startsWith(TYPE_TAG_PREFIX));
9542
9643
  return {
@@ -9549,7 +9650,7 @@ function listProjects(workspaceRoot) {
9549
9650
  }).toSorted((a, b) => a.dir.localeCompare(b.dir));
9550
9651
  }
9551
9652
  function runProjects(workspaceRoot, options) {
9552
- if (!fileExists((0, import_node_path43.join)(workspaceRoot, "nx.json"))) {
9653
+ if (!fileExists((0, import_node_path44.join)(workspaceRoot, "nx.json"))) {
9553
9654
  throw new Error("No nx.json found here. Run `projects` from the workspace root.");
9554
9655
  }
9555
9656
  const projects = listProjects(workspaceRoot);
@@ -9563,11 +9664,11 @@ function runProjects(workspaceRoot, options) {
9563
9664
  }
9564
9665
 
9565
9666
  // src/workspace-info/read-workspace-info.use-case.ts
9566
- var import_node_path45 = require("path");
9667
+ var import_node_path46 = require("path");
9567
9668
 
9568
9669
  // src/cli-version/check-for-update.use-case.ts
9569
- var import_node_fs37 = require("fs");
9570
- var import_node_path44 = require("path");
9670
+ var import_node_fs38 = require("fs");
9671
+ var import_node_path45 = require("path");
9571
9672
  var import_cross_spawn3 = __toESM(require("cross-spawn"));
9572
9673
  var PACKAGE_NAME2 = "@mnci/cli";
9573
9674
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -9626,8 +9727,8 @@ function releaseTriple(version) {
9626
9727
  }
9627
9728
  function readCliVersion(packageDirectory) {
9628
9729
  try {
9629
- const manifestPath = (0, import_node_path44.join)(packageDirectory, "..", "package.json");
9630
- const manifest = JSON.parse((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
9730
+ const manifestPath = (0, import_node_path45.join)(packageDirectory, "..", "package.json");
9731
+ const manifest = JSON.parse((0, import_node_fs38.readFileSync)(manifestPath, "utf8"));
9631
9732
  return manifest.version ?? "0.0.0";
9632
9733
  } catch {
9633
9734
  return "0.0.0";
@@ -9637,7 +9738,7 @@ function readCliVersion(packageDirectory) {
9637
9738
  // src/workspace-info/read-workspace-info.use-case.ts
9638
9739
  function readWorkspaceInfo(workspaceRoot, cliVersion) {
9639
9740
  const latest = fetchLatestVersion() ?? null;
9640
- const isWorkspace = fileExists((0, import_node_path45.join)(workspaceRoot, "nx.json"));
9741
+ const isWorkspace = fileExists((0, import_node_path46.join)(workspaceRoot, "nx.json"));
9641
9742
  return {
9642
9743
  cli: {
9643
9744
  version: cliVersion,
@@ -9657,9 +9758,203 @@ function runInfo(workspaceRoot, cliVersion, options) {
9657
9758
  logger.info(info.workspace ? `workspace: ${info.workspace.root}` : "not inside a workspace");
9658
9759
  }
9659
9760
 
9761
+ // src/interactive-wizard/interactive-wizard.use-case.ts
9762
+ var import_node_path47 = require("path");
9763
+
9764
+ // src/interactive-wizard/adopt-steps.config.ts
9765
+ var ADOPT_GLOBAL_OPTIONS = ["json"];
9766
+ var ADOPT_STEPS = [
9767
+ { id: "report", label: "Report", summary: "read the repository and say what adopting it involves (changes nothing)", options: [] },
9768
+ { id: "tags", label: "Baseline release tags", summary: "create the tag each renamed project needs so a release continues from its last version", switch: "tags", options: [] },
9769
+ { id: "toolchain", label: "Toolchain", summary: "retire old tooling, align Nx to one version, make the audit pass", switch: "toolchain", options: ["nx"] },
9770
+ { id: "kinds", label: "Project kinds", summary: "record each project's kind as a type tag", switch: "kinds", options: ["kind"] },
9771
+ { id: "dependencies", label: "Dependencies", summary: "move root runtime dependencies into the projects that import them", switch: "dependencies", options: [] },
9772
+ {
9773
+ id: "overlay",
9774
+ label: "Overlay and pipeline",
9775
+ summary: "apply the release config, .npmrc, commitlint and the CI pipeline",
9776
+ switch: "overlay",
9777
+ options: ["scope", "registry", "organization", "project", "artifacts-feed", "agent", "variable-group", "npm-auth", "ci", "test-runner"]
9778
+ }
9779
+ ];
9780
+
9781
+ // src/interactive-wizard/applicable-options.policy.ts
9782
+ function optionsOfAdd(command, kind) {
9783
+ const claimed = new Set(PROJECT_KIND_CATALOG.flatMap((entry) => entry.flags));
9784
+ const own = new Set(PROJECT_KIND_CATALOG.find((entry) => entry.kind === kind)?.flags);
9785
+ return command.options.filter((option) => !claimed.has(option.name) || own.has(option.name));
9786
+ }
9787
+ function applicableOptions(command, context = {}) {
9788
+ if (command.name === "add") {
9789
+ return optionsOfAdd(command, context.kind);
9790
+ }
9791
+ if (command.name === "adopt") {
9792
+ const step = context.adoptStep;
9793
+ const wanted = /* @__PURE__ */ new Set([...step?.options ?? [], ...ADOPT_GLOBAL_OPTIONS]);
9794
+ return command.options.filter((option) => wanted.has(option.name));
9795
+ }
9796
+ return [...command.options];
9797
+ }
9798
+
9799
+ // src/interactive-wizard/ask-command.use-case.ts
9800
+ var NOT_ASKED = /* @__PURE__ */ new Set(["help", "version"]);
9801
+ var SKIP = "";
9802
+ async function askArgument(argument, prompter) {
9803
+ const message = `${argument.name}${argument.required ? "" : " (optional)"}: ${argument.description}`;
9804
+ if (argument.choices !== void 0) {
9805
+ const choices = argument.choices.map((choice) => ({ name: choice, value: choice }));
9806
+ const value = await prompter.select(message, argument.required ? choices : [{ name: "(skip)", value: SKIP }, ...choices]);
9807
+ return value === SKIP ? [] : [value];
9808
+ }
9809
+ const typed = await prompter.input(message, argument.required);
9810
+ const answer = typed.trim();
9811
+ if (answer === "") {
9812
+ return [];
9813
+ }
9814
+ return argument.variadic ? answer.split(/\s+/) : [answer];
9815
+ }
9816
+ async function askOptionValue(option, prompter) {
9817
+ if (option.takesValue === "none") {
9818
+ return true;
9819
+ }
9820
+ const message = `${option.flags}: ${option.description}`;
9821
+ if (option.choices !== void 0) {
9822
+ return await prompter.select(message, option.choices.map((choice) => ({ name: choice, value: choice })));
9823
+ }
9824
+ if (option.repeatable) {
9825
+ const values = [];
9826
+ let typed2 = await prompter.input(`${message} (an empty answer ends the list)`, false);
9827
+ while (typed2.trim() !== "") {
9828
+ values.push(typed2.trim());
9829
+ typed2 = await prompter.input(`${option.flags} (another, or empty to finish)`, false);
9830
+ }
9831
+ return values;
9832
+ }
9833
+ const typed = await prompter.input(message, option.takesValue === "required");
9834
+ const answer = typed.trim();
9835
+ return answer === "" ? true : answer;
9836
+ }
9837
+ async function askAdoptStep(prompter) {
9838
+ const id = await prompter.select("Which adoption step?", ADOPT_STEPS.map((step) => ({ name: step.label, value: step.id, description: step.summary })));
9839
+ return ADOPT_STEPS.find((step) => step.id === id);
9840
+ }
9841
+ async function askCommand(command, prompter) {
9842
+ const answers = { arguments: [], options: {} };
9843
+ for (const argument of command.arguments) {
9844
+ answers.arguments.push(...await askArgument(argument, prompter));
9845
+ }
9846
+ let adoptStep;
9847
+ if (command.name === "adopt") {
9848
+ adoptStep = await askAdoptStep(prompter);
9849
+ if (adoptStep.switch !== void 0) {
9850
+ answers.options[adoptStep.switch] = true;
9851
+ }
9852
+ }
9853
+ const offered = applicableOptions(command, { kind: command.name === "add" ? answers.arguments[0] : void 0, adoptStep }).filter((option) => !NOT_ASKED.has(option.name) && answers.options[option.name] === void 0);
9854
+ if (offered.length === 0) {
9855
+ return answers;
9856
+ }
9857
+ const chosen = await prompter.checkbox("Options (space to select, enter to continue)", offered.map((option) => ({ name: option.flags, value: option.name, description: option.description })));
9858
+ for (const name of chosen) {
9859
+ const option = offered.find((candidate) => candidate.name === name);
9860
+ const value = await askOptionValue(option, prompter);
9861
+ if (!(Array.isArray(value) && value.length === 0)) {
9862
+ answers.options[name] = value;
9863
+ }
9864
+ }
9865
+ return answers;
9866
+ }
9867
+
9868
+ // src/interactive-wizard/build-argv.algorithm.ts
9869
+ function longFlag(option) {
9870
+ return `--${option.name}`;
9871
+ }
9872
+ function buildArgv(command, answers) {
9873
+ const argv = [command.name, ...answers.arguments];
9874
+ for (const [name, answer] of Object.entries(answers.options)) {
9875
+ const option = command.options.find((candidate) => candidate.name === name);
9876
+ if (option === void 0) {
9877
+ throw new Error(`mnci ${command.name} has no option --${name}`);
9878
+ }
9879
+ if (answer === false) {
9880
+ continue;
9881
+ }
9882
+ if (typeof answer === "boolean") {
9883
+ argv.push(longFlag(option));
9884
+ } else {
9885
+ const values = Array.isArray(answer) ? answer : [answer];
9886
+ for (const value of values) {
9887
+ argv.push(longFlag(option), value);
9888
+ }
9889
+ }
9890
+ }
9891
+ return argv;
9892
+ }
9893
+ function formatCommandLine(argv) {
9894
+ return ["mnci", ...argv.map((argument) => /\s/.test(argument) ? JSON.stringify(argument) : argument)].join(" ");
9895
+ }
9896
+
9897
+ // src/interactive-wizard/inquirer-prompter.client.ts
9898
+ var import_prompts4 = require("@inquirer/prompts");
9899
+ function toRows(choices) {
9900
+ const rows = [];
9901
+ let current;
9902
+ for (const choice of choices) {
9903
+ if (choice.group !== void 0 && choice.group !== current) {
9904
+ current = choice.group;
9905
+ rows.push(new import_prompts4.Separator(`-- ${choice.group} --`));
9906
+ }
9907
+ rows.push({ name: choice.name, value: choice.value, description: choice.description });
9908
+ }
9909
+ return rows;
9910
+ }
9911
+ function createInquirerPrompter() {
9912
+ return {
9913
+ select: async (message, choices) => await (0, import_prompts4.select)({ message, choices: toRows(choices), pageSize: 18 }),
9914
+ checkbox: async (message, choices) => await (0, import_prompts4.checkbox)({ message, choices: toRows(choices), pageSize: 18 }),
9915
+ input: async (message, required) => await (0, import_prompts4.input)({ message, validate: (value) => !required || value.trim().length > 0 || "A value is required" }),
9916
+ confirm: async (message, fallback) => await (0, import_prompts4.confirm)({ message, default: fallback })
9917
+ };
9918
+ }
9919
+
9920
+ // src/interactive-wizard/interactive-wizard.use-case.ts
9921
+ var GROUP_LABELS = {
9922
+ workspace: "Workspace",
9923
+ projects: "Projects",
9924
+ dependencies: "Dependencies",
9925
+ pipeline: "Pipeline",
9926
+ inspect: "Inspect"
9927
+ };
9928
+ var WIZARD_GROUP_OVERRIDES = { adopt: "workspace" };
9929
+ var ORDER_IN_WORKSPACE = ["projects", "dependencies", "workspace", "pipeline", "inspect"];
9930
+ var ORDER_OUTSIDE = ["workspace", "projects", "dependencies", "pipeline", "inspect"];
9931
+ var SUMMARY_LENGTH = 110;
9932
+ function summarise(description) {
9933
+ const first = description.split(/\.\s| — /, 1)[0];
9934
+ return first.length > SUMMARY_LENGTH ? `${first.slice(0, SUMMARY_LENGTH - 1)}\u2026` : first;
9935
+ }
9936
+ function wizardMenu(commands, inWorkspace) {
9937
+ const groupOf = (command) => WIZARD_GROUP_OVERRIDES[command.name] ?? command.group;
9938
+ const order = inWorkspace ? ORDER_IN_WORKSPACE : ORDER_OUTSIDE;
9939
+ return order.flatMap((group) => commands.filter((command) => groupOf(command) === group).map((command) => ({ name: `${command.name.padEnd(9)} ${summarise(command.description)}`, value: command.name, group: GROUP_LABELS[group] })));
9940
+ }
9941
+ async function runInteractive(program, prompter = createInquirerPrompter(), workingDirectory = process.cwd()) {
9942
+ const commands = describeCommands(program);
9943
+ const inWorkspace = fileExists((0, import_node_path47.join)(workingDirectory, "nx.json"));
9944
+ const name = await prompter.select("What would you like to do?", wizardMenu(commands, inWorkspace));
9945
+ const command = commands.find((candidate) => candidate.name === name);
9946
+ const argv = buildArgv(command, await askCommand(command, prompter));
9947
+ logger.info(`Running: ${formatCommandLine(argv)}`);
9948
+ if (await prompter.confirm("Run it?", true)) {
9949
+ await program.parseAsync(argv, { from: "user" });
9950
+ } else {
9951
+ logger.info("Nothing was run.");
9952
+ }
9953
+ }
9954
+
9660
9955
  // src/workspace-creation/adopt-directory.use-case.ts
9661
- var import_node_fs38 = require("fs");
9662
- var import_node_path46 = require("path");
9956
+ var import_node_fs39 = require("fs");
9957
+ var import_node_path48 = require("path");
9663
9958
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
9664
9959
  var AGENT_AND_CI_ENTRIES = [
9665
9960
  "AGENTS.md",
@@ -9690,13 +9985,13 @@ var PREFLIGHT_BLOCKERS = [
9690
9985
  "packages"
9691
9986
  ];
9692
9987
  function assertAdoptableDirectory(target) {
9693
- if (!(0, import_node_fs38.existsSync)(target)) {
9988
+ if (!(0, import_node_fs39.existsSync)(target)) {
9694
9989
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
9695
9990
  }
9696
- if (!(0, import_node_fs38.statSync)(target).isDirectory()) {
9991
+ if (!(0, import_node_fs39.statSync)(target).isDirectory()) {
9697
9992
  throw new Error(`--into '${target}' is not a directory.`);
9698
9993
  }
9699
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs38.existsSync)((0, import_node_path46.join)(target, entry)));
9994
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs39.existsSync)((0, import_node_path48.join)(target, entry)));
9700
9995
  if (blockers.length > 0) {
9701
9996
  throw new Error(
9702
9997
  `--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.`
@@ -9704,15 +9999,15 @@ function assertAdoptableDirectory(target) {
9704
9999
  }
9705
10000
  }
9706
10001
  function mergeGitignore(generatedFile, targetFile) {
9707
- const existing = (0, import_node_fs38.readFileSync)(targetFile, "utf8");
10002
+ const existing = (0, import_node_fs39.readFileSync)(targetFile, "utf8");
9708
10003
  const present = new Set(existing.split("\n").map((line) => line.trim()));
9709
- const additions = (0, import_node_fs38.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
10004
+ const additions = (0, import_node_fs39.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
9710
10005
  const trimmed = line.trim();
9711
10006
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
9712
10007
  });
9713
10008
  if (additions.length === 0) return false;
9714
10009
  const separator = existing.endsWith("\n") ? "" : "\n";
9715
- (0, import_node_fs38.writeFileSync)(
10010
+ (0, import_node_fs39.writeFileSync)(
9716
10011
  targetFile,
9717
10012
  `${existing}${separator}
9718
10013
  # Added by mnci (Nx workspace)
@@ -9722,9 +10017,9 @@ ${additions.join("\n")}
9722
10017
  return true;
9723
10018
  }
9724
10019
  function adoptGeneratedWorkspace(generatedRoot, target) {
9725
- const entries = (0, import_node_fs38.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
10020
+ const entries = (0, import_node_fs39.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
9726
10021
  const collisions = entries.filter(
9727
- (entry) => (0, import_node_fs38.existsSync)((0, import_node_path46.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
10022
+ (entry) => (0, import_node_fs39.existsSync)((0, import_node_path48.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
9728
10023
  );
9729
10024
  if (collisions.length > 0) {
9730
10025
  throw new Error(
@@ -9733,28 +10028,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
9733
10028
  }
9734
10029
  const result = { copied: [], kept: [], mergedGitignore: false };
9735
10030
  for (const entry of entries) {
9736
- const from = (0, import_node_path46.join)(generatedRoot, entry);
9737
- const to = (0, import_node_path46.join)(target, entry);
9738
- if (entry === ".gitignore" && (0, import_node_fs38.existsSync)(to)) {
10031
+ const from = (0, import_node_path48.join)(generatedRoot, entry);
10032
+ const to = (0, import_node_path48.join)(target, entry);
10033
+ if (entry === ".gitignore" && (0, import_node_fs39.existsSync)(to)) {
9739
10034
  result.mergedGitignore = mergeGitignore(from, to);
9740
10035
  result.kept.push(entry);
9741
10036
  continue;
9742
10037
  }
9743
- if ((0, import_node_fs38.existsSync)(to)) {
10038
+ if ((0, import_node_fs39.existsSync)(to)) {
9744
10039
  result.kept.push(entry);
9745
10040
  continue;
9746
10041
  }
9747
- (0, import_node_fs38.cpSync)(from, to, { recursive: true });
10042
+ (0, import_node_fs39.cpSync)(from, to, { recursive: true });
9748
10043
  result.copied.push(entry);
9749
10044
  }
9750
- (0, import_node_fs38.rmSync)(generatedRoot, { recursive: true, force: true });
10045
+ (0, import_node_fs39.rmSync)(generatedRoot, { recursive: true, force: true });
9751
10046
  return result;
9752
10047
  }
9753
10048
 
9754
10049
  // src/workspace-creation/create-workspace.use-case.ts
9755
- var import_node_fs39 = require("fs");
10050
+ var import_node_fs40 = require("fs");
9756
10051
  var import_node_os2 = require("os");
9757
- var import_node_path47 = require("path");
10052
+ var import_node_path49 = require("path");
9758
10053
  function nxCloudProviderValue(ci) {
9759
10054
  return ci === "azure" ? "azure" : "github";
9760
10055
  }
@@ -9797,9 +10092,9 @@ async function resolveRegistry2(options) {
9797
10092
  return await promptRegistry();
9798
10093
  }
9799
10094
  async function runNew(name, options) {
9800
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path47.resolve)(process.cwd(), options.into);
10095
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path49.resolve)(process.cwd(), options.into);
9801
10096
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
9802
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path47.basename)(adoptTarget));
10097
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path49.basename)(adoptTarget));
9803
10098
  assertValidProjectName(workspaceName, "Workspace name");
9804
10099
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
9805
10100
  const registry = await resolveRegistry2(options);
@@ -9812,8 +10107,8 @@ async function runNew(name, options) {
9812
10107
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
9813
10108
  const stack = await resolveStack(options);
9814
10109
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
9815
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs39.mkdtempSync)((0, import_node_path47.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
9816
- let workspaceRoot = (0, import_node_path47.join)(stagingParent, workspaceName);
10110
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs40.mkdtempSync)((0, import_node_path49.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
10111
+ let workspaceRoot = (0, import_node_path49.join)(stagingParent, workspaceName);
9817
10112
  try {
9818
10113
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
9819
10114
  runNpx(
@@ -9836,7 +10131,7 @@ async function runNew(name, options) {
9836
10131
  workspaceRoot = adoptTarget;
9837
10132
  }
9838
10133
  } finally {
9839
- if (adoptTarget !== void 0) (0, import_node_fs39.rmSync)(stagingParent, { recursive: true, force: true });
10134
+ if (adoptTarget !== void 0) (0, import_node_fs40.rmSync)(stagingParent, { recursive: true, force: true });
9840
10135
  }
9841
10136
  logger.step(
9842
10137
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -9846,8 +10141,8 @@ async function runNew(name, options) {
9846
10141
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
9847
10142
  logger.detail
9848
10143
  );
9849
- (0, import_node_fs39.rmSync)((0, import_node_path47.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
9850
- (0, import_node_fs39.rmSync)((0, import_node_path47.join)(workspaceRoot, "package-lock.json"), { force: true });
10144
+ (0, import_node_fs40.rmSync)((0, import_node_path49.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
10145
+ (0, import_node_fs40.rmSync)((0, import_node_path49.join)(workspaceRoot, "package-lock.json"), { force: true });
9851
10146
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
9852
10147
  const installStatus = runShell(
9853
10148
  "npm",
@@ -9884,30 +10179,6 @@ function projectKindHintLines(kinds = PROJECT_KINDS) {
9884
10179
  return lines;
9885
10180
  }
9886
10181
 
9887
- // src/workspace-creation/interactive-wizard.use-case.ts
9888
- var import_node_path48 = require("path");
9889
- var import_prompts4 = require("@inquirer/prompts");
9890
- async function runInteractive() {
9891
- const inWorkspace = fileExists((0, import_node_path48.join)(process.cwd(), "nx.json"));
9892
- const choiceNew = { name: "Create a new monorepo", value: "new" };
9893
- const choiceAdd = { name: "Add a project to this workspace", value: "add" };
9894
- const choiceUpgrade = {
9895
- name: "Upgrade this workspace (re-apply the latest overlay)",
9896
- value: "upgrade"
9897
- };
9898
- const action = await (0, import_prompts4.select)({
9899
- message: "What would you like to do?",
9900
- choices: inWorkspace ? [choiceAdd, choiceUpgrade, choiceNew] : [choiceNew, choiceAdd, choiceUpgrade]
9901
- });
9902
- if (action === "new") {
9903
- await runNew(void 0, {});
9904
- } else if (action === "upgrade") {
9905
- runUpgrade(process.cwd(), {});
9906
- } else {
9907
- await runAdd(void 0, void 0, {});
9908
- }
9909
- }
9910
-
9911
10182
  // src/main.ts
9912
10183
  function buildProgram(cliVersion) {
9913
10184
  const program = new import_commander.Command();
@@ -9973,6 +10244,12 @@ function buildProgram(cliVersion) {
9973
10244
  ).option(
9974
10245
  "--empty",
9975
10246
  "npm-lib, internal-lib, react-lib, react-internal-lib, node-function-app: scaffold the slice skeleton only, with no sample code or spec"
10247
+ ).option(
10248
+ "--e2e",
10249
+ "react-app only: also scaffold a Playwright end-to-end project, <name>-e2e, that runs the app and checks its greeting; its e2e target needs a browser (npx playwright install) and is not part of CI verify"
10250
+ ).option(
10251
+ "--esm",
10252
+ 'node-app, node-function-app: ES module output ("type": "module", explicit .js import specifiers, Jest mapped to match); not with fastify or nest'
9976
10253
  ).option(
9977
10254
  "--lib <name>",
9978
10255
  "python-vendor only: the internal Python library (libs/<name>) to vendor into <name>"
@@ -10009,7 +10286,7 @@ function buildProgram(cliVersion) {
10009
10286
  runInfo(process.cwd(), cliVersion, options);
10010
10287
  });
10011
10288
  program.action(async () => {
10012
- await runInteractive();
10289
+ await runInteractive(program);
10013
10290
  });
10014
10291
  return program;
10015
10292
  }