@mnci/cli 4.52.0 → 4.54.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
@@ -136,8 +136,8 @@ async function promptStack() {
136
136
  }
137
137
 
138
138
  // src/nx-workspace/nx.client.ts
139
- function runShell(command, arguments_, cwd) {
140
- const result = import_cross_spawn.default.sync(command, arguments_, { stdio: "inherit", cwd });
139
+ function runShell(command, arguments_, cwd, environment) {
140
+ const result = import_cross_spawn.default.sync(command, arguments_, { stdio: "inherit", cwd, env: environment === void 0 ? void 0 : { ...process.env, ...environment } });
141
141
  return result.status ?? 1;
142
142
  }
143
143
  var CAPTURE_TIMEOUT_MS = 6e4;
@@ -199,10 +199,10 @@ function runNpx(arguments_, cwd) {
199
199
  }
200
200
  }
201
201
  function runFormatter(cwd, target = ".") {
202
- const status = runShell("npx", ["eslint", target, "--fix"], cwd);
202
+ const status = runShell("npx", ["eslint", target, "--fix"], cwd, { NODE_OPTIONS: "--max-old-space-size=8192" });
203
203
  if (status !== 0) {
204
204
  logger.warn(
205
- `eslint could not format '${target}' (exit code ${status}). The project was generated; run 'npm run format' to normalise it.`
205
+ `eslint could not format '${target}' (exit code ${status}), so formatting was SKIPPED and the tree is not normalised. The project was generated; run 'npm run format' to finish it.`
206
206
  );
207
207
  }
208
208
  }
@@ -2236,6 +2236,13 @@ updates:
2236
2236
  directory: "/"
2237
2237
  schedule:
2238
2238
  interval: weekly
2239
+ # The Nx packages are pinned to one exact version and must move together: a PR for one alone fails resolution
2240
+ # (ERESOLVE between @nx/eslint and @nx/jest) or leaves a second copy of nx in the lockfile (#295).
2241
+ groups:
2242
+ nx:
2243
+ patterns:
2244
+ - "nx"
2245
+ - "@nx/*"
2239
2246
 
2240
2247
  - package-ecosystem: github-actions
2241
2248
  directory: "/"
@@ -3187,7 +3194,7 @@ function runPhase(phase, workspaceRoot, dependencies) {
3187
3194
  }
3188
3195
 
3189
3196
  // src/project-scaffolding/add-project.use-case.ts
3190
- var import_node_path35 = require("path");
3197
+ var import_node_path37 = require("path");
3191
3198
  var import_prompts3 = require("@inquirer/prompts");
3192
3199
 
3193
3200
  // src/project-name/project-name.validator.ts
@@ -4090,12 +4097,19 @@ function goModulePrefix(workspaceRoot) {
4090
4097
  const result = runCapture("git", ["remote", "get-url", "origin"], workspaceRoot);
4091
4098
  return result.status === 0 ? modulePrefixFromRemoteUrl(result.stdout) : void 0;
4092
4099
  }
4100
+ function rootModulePath(workspaceRoot) {
4101
+ try {
4102
+ return /^module\s+(\S+)/m.exec((0, import_node_fs15.readFileSync)((0, import_node_path14.join)(workspaceRoot, "go.mod"), "utf8"))?.[1];
4103
+ } catch {
4104
+ return void 0;
4105
+ }
4106
+ }
4093
4107
  function registerNxGoPlugin(workspaceRoot) {
4094
4108
  const nxJsonPath = (0, import_node_path14.join)(workspaceRoot, "nx.json");
4095
4109
  if (!fileExists(nxJsonPath)) {
4096
4110
  return false;
4097
4111
  }
4098
- const modulePrefix = goModulePrefix(workspaceRoot);
4112
+ const modulePrefix = rootModulePath(workspaceRoot) === void 0 ? goModulePrefix(workspaceRoot) : void 0;
4099
4113
  const entry = modulePrefix === void 0 ? NX_GO_PLUGIN : { plugin: NX_GO_PLUGIN, options: { modulePrefix } };
4100
4114
  const nxJson = readJson(nxJsonPath);
4101
4115
  const plugins = [...nxJson.plugins ?? []];
@@ -4805,11 +4819,11 @@ function addGoInternalLib(workspaceRoot, name) {
4805
4819
  }
4806
4820
  }
4807
4821
 
4808
- // src/project-scaffolding/esm-conversion.use-case.ts
4822
+ // src/esm-conversion/esm-conversion.use-case.ts
4809
4823
  var import_node_fs19 = require("fs");
4810
4824
  var import_node_path18 = require("path");
4811
4825
 
4812
- // src/project-scaffolding/esm-specifiers.algorithm.ts
4826
+ // src/esm-conversion/esm-specifiers.algorithm.ts
4813
4827
  var RELATIVE_SPECIFIER = /((?:\bfrom|\bimport)\s*)(['"])(\.{1,2}\/[^'"\n]*|\.{1,2})\2/g;
4814
4828
  var HAS_EXTENSION = /\.(?:[cm]?js|json|node)$/;
4815
4829
  function withJsSpecifiers(source, directories = []) {
@@ -4822,7 +4836,7 @@ function withJsSpecifiers(source, directories = []) {
4822
4836
  });
4823
4837
  }
4824
4838
 
4825
- // src/project-scaffolding/esm-conversion.use-case.ts
4839
+ // src/esm-conversion/esm-conversion.use-case.ts
4826
4840
  var SAMPLE_DIRECTORIES = ["./hello"];
4827
4841
  var JEST_ANCHOR = " moduleFileExtensions:";
4828
4842
  var JEST_MAPPER = String.raw` moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1' },`;
@@ -6090,9 +6104,75 @@ function refreshContainerScript(workspaceRoot) {
6090
6104
  }
6091
6105
 
6092
6106
  // src/project-scaffolding/react-app.use-case.ts
6107
+ var import_node_fs28 = require("fs");
6108
+ var import_node_path30 = require("path");
6109
+
6110
+ // src/react-app-output/find-react-apps-sharing-output.use-case.ts
6093
6111
  var import_node_fs27 = require("fs");
6094
6112
  var import_node_path28 = require("path");
6095
6113
 
6114
+ // src/react-app-output/react-app-output.policy.ts
6115
+ var VITE_DEFAULT_OUT_DIR = "dist";
6116
+ var VITE_OUT_DIR = /\boutDir:\s*['"]([^'"]+)['"]/;
6117
+ function normalise(folder) {
6118
+ return folder.replace(/^\.\//, "").replace(/\/+$/, "");
6119
+ }
6120
+ function viteOutputFolder(viteConfig) {
6121
+ return normalise(VITE_OUT_DIR.exec(viteConfig)?.[1] ?? VITE_DEFAULT_OUT_DIR);
6122
+ }
6123
+ function sharesOutputFolder(typescriptOutDir, viteConfig) {
6124
+ return typescriptOutDir !== void 0 && normalise(typescriptOutDir) === viteOutputFolder(viteConfig);
6125
+ }
6126
+
6127
+ // src/react-app-output/find-react-apps-sharing-output.use-case.ts
6128
+ var VITE_CONFIGS = ["vite.config.mts", "vite.config.ts", "vite.config.mjs", "vite.config.js"];
6129
+ function appSharesOutputFolder(appRoot) {
6130
+ const config = VITE_CONFIGS.find((name) => fileExists((0, import_node_path28.join)(appRoot, name)));
6131
+ const tsconfigPath = (0, import_node_path28.join)(appRoot, "tsconfig.app.json");
6132
+ if (config === void 0 || !fileExists(tsconfigPath)) {
6133
+ return false;
6134
+ }
6135
+ try {
6136
+ const outDir = readJson(tsconfigPath).compilerOptions?.outDir;
6137
+ return sharesOutputFolder(outDir, (0, import_node_fs27.readFileSync)((0, import_node_path28.join)(appRoot, config), "utf8"));
6138
+ } catch {
6139
+ return false;
6140
+ }
6141
+ }
6142
+ function findReactAppsSharingOutput(workspaceRoot) {
6143
+ let entries;
6144
+ try {
6145
+ entries = (0, import_node_fs27.readdirSync)((0, import_node_path28.join)(workspaceRoot, "apps"));
6146
+ } catch {
6147
+ return [];
6148
+ }
6149
+ return entries.filter((entry) => appSharesOutputFolder((0, import_node_path28.join)(workspaceRoot, "apps", entry))).map((entry) => `apps/${entry}`).toSorted((a, b) => a.localeCompare(b));
6150
+ }
6151
+
6152
+ // src/react-app-output/separate-react-app-output.use-case.ts
6153
+ var import_node_path29 = require("path");
6154
+ function separateReactAppOutput(appRoot) {
6155
+ if (!appSharesOutputFolder(appRoot)) {
6156
+ return false;
6157
+ }
6158
+ const tsconfigPath = (0, import_node_path29.join)(appRoot, "tsconfig.app.json");
6159
+ const tsconfig = readJson(tsconfigPath);
6160
+ writeFileEnsured(tsconfigPath, toJson({
6161
+ ...tsconfig,
6162
+ compilerOptions: { ...tsconfig.compilerOptions, outDir: "out-tsc/app", tsBuildInfoFile: "out-tsc/app/tsconfig.app.tsbuildinfo" }
6163
+ }));
6164
+ return true;
6165
+ }
6166
+ function separateReactAppsOutput(workspaceRoot) {
6167
+ const repaired = [];
6168
+ for (const dir of findReactAppsSharingOutput(workspaceRoot)) {
6169
+ if (separateReactAppOutput((0, import_node_path29.join)(workspaceRoot, dir))) {
6170
+ repaired.push(dir);
6171
+ }
6172
+ }
6173
+ return repaired;
6174
+ }
6175
+
6096
6176
  // src/project-scaffolding/react-app-example.algorithm.ts
6097
6177
  function reactAppExampleFiles(name) {
6098
6178
  return {
@@ -6217,12 +6297,12 @@ function reactAppTargets(name) {
6217
6297
  return targets;
6218
6298
  }
6219
6299
  function allowEnvFiles(workspaceRoot) {
6220
- const gitignorePath = (0, import_node_path28.join)(workspaceRoot, ".gitignore");
6300
+ const gitignorePath = (0, import_node_path30.join)(workspaceRoot, ".gitignore");
6221
6301
  if (!fileExists(gitignorePath)) {
6222
6302
  return;
6223
6303
  }
6224
6304
  const marker = "# MoNecromanCI: keep the committed per-environment Vite config (public VITE_ values)";
6225
- const current = (0, import_node_fs27.readFileSync)(gitignorePath, "utf8");
6305
+ const current = (0, import_node_fs28.readFileSync)(gitignorePath, "utf8");
6226
6306
  if (current.includes(marker)) {
6227
6307
  return;
6228
6308
  }
@@ -6249,17 +6329,18 @@ function addReactApp(workspaceRoot, name, stack, e2e = false) {
6249
6329
  workspaceRoot
6250
6330
  );
6251
6331
  ensureAdmZip(workspaceRoot);
6252
- const reactAppRoot = (0, import_node_path28.join)(workspaceRoot, "apps", name);
6332
+ const reactAppRoot = (0, import_node_path30.join)(workspaceRoot, "apps", name);
6253
6333
  for (const environment of REACT_ENVIRONMENTS) {
6254
- writeFileEnsured((0, import_node_path28.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
6334
+ writeFileEnsured((0, import_node_path30.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
6255
6335
  }
6256
6336
  allowEnvFiles(workspaceRoot);
6257
- addNxTargets((0, import_node_path28.join)(reactAppRoot, "package.json"), reactAppTargets(name));
6337
+ addNxTargets((0, import_node_path30.join)(reactAppRoot, "package.json"), reactAppTargets(name));
6258
6338
  reshapeReactAppScaffold(reactAppRoot);
6259
- (0, import_node_fs27.rmSync)((0, import_node_path28.join)(reactAppRoot, "src/app/nx-welcome.component.tsx"), { force: true });
6339
+ separateReactAppOutput(reactAppRoot);
6340
+ (0, import_node_fs28.rmSync)((0, import_node_path30.join)(reactAppRoot, "src/app/nx-welcome.component.tsx"), { force: true });
6260
6341
  const example = reactAppExampleFiles(name);
6261
6342
  for (const [relative, contents] of Object.entries(example)) {
6262
- writeFileEnsured((0, import_node_path28.join)(reactAppRoot, "src", relative), contents);
6343
+ writeFileEnsured((0, import_node_path30.join)(reactAppRoot, "src", relative), contents);
6263
6344
  }
6264
6345
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
6265
6346
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:serve` });
@@ -6269,9 +6350,9 @@ function addReactApp(workspaceRoot, name, stack, e2e = false) {
6269
6350
  }
6270
6351
  function pairE2eProject(workspaceRoot, name) {
6271
6352
  const e2eName = `${name}-e2e`;
6272
- const e2eRoot = (0, import_node_path28.join)(workspaceRoot, "apps", e2eName);
6273
- (0, import_node_fs27.rmSync)((0, import_node_path28.join)(e2eRoot, "src/example.spec.ts"), { force: true });
6274
- writeFileEnsured((0, import_node_path28.join)(e2eRoot, "src/greeting.e2e.spec.ts"), reactAppE2eSpec(name));
6353
+ const e2eRoot = (0, import_node_path30.join)(workspaceRoot, "apps", e2eName);
6354
+ (0, import_node_fs28.rmSync)((0, import_node_path30.join)(e2eRoot, "src/example.spec.ts"), { force: true });
6355
+ writeFileEnsured((0, import_node_path30.join)(e2eRoot, "src/greeting.e2e.spec.ts"), reactAppE2eSpec(name));
6275
6356
  removeGeneratedEslintConfig(workspaceRoot, `apps/${e2eName}`);
6276
6357
  registerProjectCommands(workspaceRoot, e2eName, {
6277
6358
  build: false,
@@ -6280,13 +6361,13 @@ function pairE2eProject(workspaceRoot, name) {
6280
6361
  }
6281
6362
 
6282
6363
  // src/project-scaffolding/react-lib.use-case.ts
6283
- var import_node_path29 = require("path");
6364
+ var import_node_path31 = require("path");
6284
6365
  var REACT_LIB_BUNDLER = "rollup";
6285
6366
  async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
6286
6367
  ensurePlugin(workspaceRoot, "@nx/react");
6287
6368
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
6288
- const projectRoot = (0, import_node_path29.join)(workspaceRoot, "packages", name);
6289
- const publishableManifest = (0, import_node_path29.join)(projectRoot, "package.json");
6369
+ const projectRoot = (0, import_node_path31.join)(workspaceRoot, "packages", name);
6370
+ const publishableManifest = (0, import_node_path31.join)(projectRoot, "package.json");
6290
6371
  runGeneratorAndRepair(
6291
6372
  workspaceRoot,
6292
6373
  [
@@ -6330,8 +6411,8 @@ function dropNxProjectName(manifestPath) {
6330
6411
  }
6331
6412
  function addReactInternalLib(workspaceRoot, name, stack, empty = false) {
6332
6413
  ensurePlugin(workspaceRoot, "@nx/react");
6333
- const projectRoot = (0, import_node_path29.join)(workspaceRoot, "libs", name);
6334
- const privateManifest = (0, import_node_path29.join)(projectRoot, "package.json");
6414
+ const projectRoot = (0, import_node_path31.join)(workspaceRoot, "libs", name);
6415
+ const privateManifest = (0, import_node_path31.join)(projectRoot, "package.json");
6335
6416
  runGeneratorAndRepair(
6336
6417
  workspaceRoot,
6337
6418
  [
@@ -6358,8 +6439,8 @@ function addReactInternalLib(workspaceRoot, name, stack, empty = false) {
6358
6439
  }
6359
6440
 
6360
6441
  // src/project-scaffolding/vscode-extension.use-case.ts
6361
- var import_node_fs28 = require("fs");
6362
- var import_node_path30 = require("path");
6442
+ var import_node_fs29 = require("fs");
6443
+ var import_node_path32 = require("path");
6363
6444
  var VSCODE_EXTENSION_SCRIPT_PATH = "tools/vscode-extension.cjs";
6364
6445
  var VSCODE_ENGINE_FLOOR = "1.96.0";
6365
6446
  var VSCODE_SIDECAR_TARGETS = {
@@ -6544,8 +6625,8 @@ export const window = {
6544
6625
  var VSCODE_STUB_PATH = "test/vscode.stub.ts";
6545
6626
  function mapVscodeToStub(projectRoot, testRunner) {
6546
6627
  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}\` },`];
6547
- const path = (0, import_node_path30.join)(projectRoot, file);
6548
- const content = fileExists(path) ? (0, import_node_fs28.readFileSync)(path, "utf8") : "";
6628
+ const path = (0, import_node_path32.join)(projectRoot, file);
6629
+ const content = fileExists(path) ? (0, import_node_fs29.readFileSync)(path, "utf8") : "";
6549
6630
  const line = content.split("\n").find((candidate) => candidate.trim() === anchor);
6550
6631
  if (line === void 0) {
6551
6632
  throw new Error(`${file} has no "${anchor}" line to map the vscode module after; map 'vscode' to ${VSCODE_STUB_PATH} by hand.`);
@@ -6565,11 +6646,11 @@ function ensureVscodeToolchain(workspaceRoot) {
6565
6646
  }
6566
6647
  }
6567
6648
  function defaultPublisher(workspaceRoot) {
6568
- const { name } = readJson((0, import_node_path30.join)(workspaceRoot, "package.json"));
6649
+ const { name } = readJson((0, import_node_path32.join)(workspaceRoot, "package.json"));
6569
6650
  return (name ?? "publisher").replace(/^@/, "").split("/", 1)[0];
6570
6651
  }
6571
6652
  function reshapeManifest(projectRoot, name, publisher) {
6572
- const manifestPath = (0, import_node_path30.join)(projectRoot, "package.json");
6653
+ const manifestPath = (0, import_node_path32.join)(projectRoot, "package.json");
6573
6654
  const manifest = readJson(manifestPath);
6574
6655
  const { nx = {}, ...rest } = manifest;
6575
6656
  const targets = { ...nx.targets };
@@ -6633,11 +6714,11 @@ function vscodeExtensionPublishTarget(name, sidecar) {
6633
6714
  };
6634
6715
  }
6635
6716
  function addDebugLaunch(workspaceRoot, name) {
6636
- const file = (0, import_node_fs28.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
6717
+ const file = (0, import_node_fs29.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
6637
6718
  if (file === void 0) {
6638
6719
  return;
6639
6720
  }
6640
- const path = (0, import_node_path30.join)(workspaceRoot, file);
6721
+ const path = (0, import_node_path32.join)(workspaceRoot, file);
6641
6722
  const workspace = readCodeWorkspace(path) ?? {};
6642
6723
  const folder = `\${workspaceFolder:${workspace.folders?.[0]?.name ?? file.replace(/\.code-workspace$/, "")}}`;
6643
6724
  const taskLabel = `${name}: build (development)`;
@@ -6670,39 +6751,39 @@ function addDebugLaunch(workspaceRoot, name) {
6670
6751
  );
6671
6752
  }
6672
6753
  function refreshVscodeExtensionScript(workspaceRoot) {
6673
- const apps = (0, import_node_path30.join)(workspaceRoot, "apps");
6754
+ const apps = (0, import_node_path32.join)(workspaceRoot, "apps");
6674
6755
  let entries;
6675
6756
  try {
6676
- entries = (0, import_node_fs28.readdirSync)(apps);
6757
+ entries = (0, import_node_fs29.readdirSync)(apps);
6677
6758
  } catch {
6678
6759
  return false;
6679
6760
  }
6680
6761
  const hasExtension = entries.some((entry) => {
6681
- const manifestPath = (0, import_node_path30.join)(apps, entry, "package.json");
6762
+ const manifestPath = (0, import_node_path32.join)(apps, entry, "package.json");
6682
6763
  if (!fileExists(manifestPath)) {
6683
6764
  return false;
6684
6765
  }
6685
6766
  const tags = readJson(manifestPath).nx?.tags ?? [];
6686
6767
  return tags.includes(VSCODE_EXTENSION_TAG);
6687
6768
  });
6688
- const path = (0, import_node_path30.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
6689
- if (!hasExtension || fileExists(path) && (0, import_node_fs28.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
6769
+ const path = (0, import_node_path32.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
6770
+ if (!hasExtension || fileExists(path) && (0, import_node_fs29.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
6690
6771
  return false;
6691
6772
  }
6692
6773
  writeFileEnsured(path, VSCODE_EXTENSION_SCRIPT);
6693
6774
  return true;
6694
6775
  }
6695
6776
  function pinVscodeExtensionProjectNames(workspaceRoot) {
6696
- const apps = (0, import_node_path30.join)(workspaceRoot, "apps");
6777
+ const apps = (0, import_node_path32.join)(workspaceRoot, "apps");
6697
6778
  let entries;
6698
6779
  try {
6699
- entries = (0, import_node_fs28.readdirSync)(apps);
6780
+ entries = (0, import_node_fs29.readdirSync)(apps);
6700
6781
  } catch {
6701
6782
  return [];
6702
6783
  }
6703
6784
  const updated = [];
6704
6785
  for (const entry of entries) {
6705
- const manifestPath = (0, import_node_path30.join)(apps, entry, "package.json");
6786
+ const manifestPath = (0, import_node_path32.join)(apps, entry, "package.json");
6706
6787
  if (!fileExists(manifestPath)) {
6707
6788
  continue;
6708
6789
  }
@@ -6722,22 +6803,22 @@ function refreshLockFile(workspaceRoot, name) {
6722
6803
  }
6723
6804
  function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
6724
6805
  const { sidecar } = options;
6725
- if (sidecar !== void 0 && !fileExists((0, import_node_path30.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
6806
+ if (sidecar !== void 0 && !fileExists((0, import_node_path32.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
6726
6807
  throw new Error(`--sidecar ${sidecar}: no Go app at apps/${sidecar}. Add it first with \`mnci add go-app ${sidecar}\`.`);
6727
6808
  }
6728
6809
  runNodeApp(workspaceRoot, name, stack, "none");
6729
6810
  ensureVscodeToolchain(workspaceRoot);
6730
- const projectRoot = (0, import_node_path30.join)(workspaceRoot, "apps", name);
6811
+ const projectRoot = (0, import_node_path32.join)(workspaceRoot, "apps", name);
6731
6812
  reshapeManifest(projectRoot, name, options.publisher ?? defaultPublisher(workspaceRoot));
6732
- addVscodeTypes((0, import_node_path30.join)(projectRoot, "tsconfig.app.json"));
6733
- addVscodeTypes((0, import_node_path30.join)(projectRoot, "tsconfig.spec.json"));
6734
- writeFileEnsured((0, import_node_path30.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
6735
- writeFileEnsured((0, import_node_path30.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
6736
- writeFileEnsured((0, import_node_path30.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
6813
+ addVscodeTypes((0, import_node_path32.join)(projectRoot, "tsconfig.app.json"));
6814
+ addVscodeTypes((0, import_node_path32.join)(projectRoot, "tsconfig.spec.json"));
6815
+ writeFileEnsured((0, import_node_path32.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
6816
+ writeFileEnsured((0, import_node_path32.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
6817
+ writeFileEnsured((0, import_node_path32.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
6737
6818
  mapVscodeToStub(projectRoot, stack.testRunner);
6738
- writeFileEnsured((0, import_node_path30.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
6739
- writeFileEnsured((0, import_node_path30.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
6740
- addNxTargets((0, import_node_path30.join)(projectRoot, "package.json"), {
6819
+ writeFileEnsured((0, import_node_path32.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
6820
+ writeFileEnsured((0, import_node_path32.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
6821
+ addNxTargets((0, import_node_path32.join)(projectRoot, "package.json"), {
6741
6822
  "package": vscodeExtensionPackageTarget(name, sidecar),
6742
6823
  "nx-release-publish": vscodeExtensionPublishTarget(name, sidecar)
6743
6824
  });
@@ -6748,12 +6829,12 @@ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
6748
6829
  }
6749
6830
 
6750
6831
  // src/dependency-management/install-dependencies.use-case.ts
6751
- var import_node_fs30 = require("fs");
6752
- var import_node_path32 = require("path");
6832
+ var import_node_fs31 = require("fs");
6833
+ var import_node_path34 = require("path");
6753
6834
 
6754
6835
  // src/dependency-management/manifest.repository.ts
6755
- var import_node_fs29 = require("fs");
6756
- var import_node_path31 = require("path");
6836
+ var import_node_fs30 = require("fs");
6837
+ var import_node_path33 = require("path");
6757
6838
  var ECOSYSTEMS = ["npm", "pip", "pub", "nuget", "go"];
6758
6839
  var ROOT_LABEL = "(root)";
6759
6840
  var MANIFEST_GLOBS = {
@@ -6786,23 +6867,23 @@ function projectOf(manifestRelativePath) {
6786
6867
  }
6787
6868
  function hasEcosystem(workspaceRoot, ecosystem) {
6788
6869
  if (ecosystem === "go") {
6789
- return fileExists((0, import_node_path31.join)(workspaceRoot, "go.mod"));
6870
+ return fileExists((0, import_node_path33.join)(workspaceRoot, "go.mod"));
6790
6871
  }
6791
6872
  if (ecosystem === "nuget") {
6792
- return (0, import_node_fs29.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
6873
+ return (0, import_node_fs30.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
6793
6874
  }
6794
6875
  const rootMarker = {
6795
6876
  npm: "package.json",
6796
6877
  pip: "requirements-dev.txt",
6797
6878
  pub: "pubspec.yaml"
6798
6879
  };
6799
- return fileExists((0, import_node_path31.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs29.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
6880
+ return fileExists((0, import_node_path33.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs30.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
6800
6881
  }
6801
6882
  function collectNpm(workspaceRoot) {
6802
6883
  const sites = [];
6803
- const relativePaths = ["package.json", ...(0, import_node_fs29.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
6884
+ const relativePaths = ["package.json", ...(0, import_node_fs30.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
6804
6885
  for (const relativePath of relativePaths) {
6805
- const manifestPath = (0, import_node_path31.join)(workspaceRoot, relativePath);
6886
+ const manifestPath = (0, import_node_path33.join)(workspaceRoot, relativePath);
6806
6887
  try {
6807
6888
  const manifest = readJson(manifestPath);
6808
6889
  sites.push(...npmManifestSites(manifest, relativePath, manifestPath));
@@ -6863,17 +6944,17 @@ function collectPip(workspaceRoot) {
6863
6944
  name: parsed.name,
6864
6945
  ecosystem: "pip",
6865
6946
  project: projectOf(relativePath),
6866
- manifestPath: (0, import_node_path31.join)(workspaceRoot, relativePath),
6947
+ manifestPath: (0, import_node_path33.join)(workspaceRoot, relativePath),
6867
6948
  section,
6868
6949
  spec: parsed.spec,
6869
6950
  rewritable: parsed.rewritable && parsed.spec !== ""
6870
6951
  });
6871
6952
  };
6872
- const pyprojectPaths = (0, import_node_fs29.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
6953
+ const pyprojectPaths = (0, import_node_fs30.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
6873
6954
  for (const relativePath of pyprojectPaths) {
6874
6955
  let content;
6875
6956
  try {
6876
- content = (0, import_node_fs29.readFileSync)((0, import_node_path31.join)(workspaceRoot, relativePath), "utf8");
6957
+ content = (0, import_node_fs30.readFileSync)((0, import_node_path33.join)(workspaceRoot, relativePath), "utf8");
6877
6958
  } catch {
6878
6959
  continue;
6879
6960
  }
@@ -6884,14 +6965,14 @@ function collectPip(workspaceRoot) {
6884
6965
  }
6885
6966
  const requirementsPaths = [
6886
6967
  "requirements-dev.txt",
6887
- ...(0, import_node_fs29.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
6968
+ ...(0, import_node_fs30.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
6888
6969
  ];
6889
6970
  for (const relativePath of requirementsPaths) {
6890
- if (!fileExists((0, import_node_path31.join)(workspaceRoot, relativePath))) {
6971
+ if (!fileExists((0, import_node_path33.join)(workspaceRoot, relativePath))) {
6891
6972
  continue;
6892
6973
  }
6893
6974
  const section = relativePath === "requirements-dev.txt" ? "devDep" : "dep";
6894
- const lines = (0, import_node_fs29.readFileSync)((0, import_node_path31.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
6975
+ const lines = (0, import_node_fs30.readFileSync)((0, import_node_path33.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
6895
6976
  for (const line of lines) {
6896
6977
  push(relativePath, section, line);
6897
6978
  }
@@ -6929,11 +7010,11 @@ function pyprojectDependencies(content) {
6929
7010
  }
6930
7011
  function collectPub(workspaceRoot) {
6931
7012
  const sites = [];
6932
- const pubspecPaths = (0, import_node_fs29.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
7013
+ const pubspecPaths = (0, import_node_fs30.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
6933
7014
  for (const relativePath of pubspecPaths) {
6934
7015
  let content;
6935
7016
  try {
6936
- content = (0, import_node_fs29.readFileSync)((0, import_node_path31.join)(workspaceRoot, relativePath), "utf8");
7017
+ content = (0, import_node_fs30.readFileSync)((0, import_node_path33.join)(workspaceRoot, relativePath), "utf8");
6937
7018
  } catch {
6938
7019
  continue;
6939
7020
  }
@@ -6943,7 +7024,7 @@ function collectPub(workspaceRoot) {
6943
7024
  name: entry.name,
6944
7025
  ecosystem: "pub",
6945
7026
  project: projectOf(relativePath),
6946
- manifestPath: (0, import_node_path31.join)(workspaceRoot, relativePath),
7027
+ manifestPath: (0, import_node_path33.join)(workspaceRoot, relativePath),
6947
7028
  section: block === "dependencies" ? "dep" : "devDep",
6948
7029
  spec: entry.spec,
6949
7030
  rewritable: entry.spec !== ""
@@ -6993,11 +7074,11 @@ function stripQuotes(value) {
6993
7074
  }
6994
7075
  function collectNuget(workspaceRoot) {
6995
7076
  const sites = [];
6996
- const csprojPaths = (0, import_node_fs29.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
7077
+ const csprojPaths = (0, import_node_fs30.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
6997
7078
  for (const relativePath of csprojPaths) {
6998
7079
  let content;
6999
7080
  try {
7000
- content = (0, import_node_fs29.readFileSync)((0, import_node_path31.join)(workspaceRoot, relativePath), "utf8");
7081
+ content = (0, import_node_fs30.readFileSync)((0, import_node_path33.join)(workspaceRoot, relativePath), "utf8");
7001
7082
  } catch {
7002
7083
  continue;
7003
7084
  }
@@ -7006,7 +7087,7 @@ function collectNuget(workspaceRoot) {
7006
7087
  name: entry.name,
7007
7088
  ecosystem: "nuget",
7008
7089
  project: projectOf(relativePath),
7009
- manifestPath: (0, import_node_path31.join)(workspaceRoot, relativePath),
7090
+ manifestPath: (0, import_node_path33.join)(workspaceRoot, relativePath),
7010
7091
  section: "dep",
7011
7092
  spec: entry.spec,
7012
7093
  // A plain SemVer string is rewritable; an MSBuild property reference
@@ -7031,13 +7112,13 @@ function csprojPackageReferences(content) {
7031
7112
  return entries;
7032
7113
  }
7033
7114
  function collectGo(workspaceRoot) {
7034
- const manifestPath = (0, import_node_path31.join)(workspaceRoot, "go.mod");
7115
+ const manifestPath = (0, import_node_path33.join)(workspaceRoot, "go.mod");
7035
7116
  if (!fileExists(manifestPath)) {
7036
7117
  return [];
7037
7118
  }
7038
7119
  let content;
7039
7120
  try {
7040
- content = (0, import_node_fs29.readFileSync)(manifestPath, "utf8");
7121
+ content = (0, import_node_fs30.readFileSync)(manifestPath, "utf8");
7041
7122
  } catch {
7042
7123
  return [];
7043
7124
  }
@@ -7086,7 +7167,7 @@ var PROJECT_GLOBS = {
7086
7167
  function locateProjects(workspaceRoot) {
7087
7168
  const locations = [];
7088
7169
  for (const ecosystem of ECOSYSTEMS) {
7089
- const relativePaths = (0, import_node_fs29.globSync)(PROJECT_GLOBS[ecosystem], { cwd: workspaceRoot });
7170
+ const relativePaths = (0, import_node_fs30.globSync)(PROJECT_GLOBS[ecosystem], { cwd: workspaceRoot });
7090
7171
  for (const relativePath of relativePaths) {
7091
7172
  const posix = toPosix(relativePath);
7092
7173
  const dir = posix.slice(0, posix.lastIndexOf("/"));
@@ -7094,7 +7175,7 @@ function locateProjects(workspaceRoot) {
7094
7175
  ecosystem,
7095
7176
  dir,
7096
7177
  name: dir.slice(dir.lastIndexOf("/") + 1),
7097
- manifestPath: (0, import_node_path31.join)(workspaceRoot, relativePath)
7178
+ manifestPath: (0, import_node_path33.join)(workspaceRoot, relativePath)
7098
7179
  });
7099
7180
  }
7100
7181
  }
@@ -7115,7 +7196,7 @@ function rewriteSpec(site, spec) {
7115
7196
  writeFileEnsured(site.manifestPath, toJson(manifest));
7116
7197
  return true;
7117
7198
  }
7118
- const before = (0, import_node_fs29.readFileSync)(site.manifestPath, "utf8");
7199
+ const before = (0, import_node_fs30.readFileSync)(site.manifestPath, "utf8");
7119
7200
  const after = (() => {
7120
7201
  switch (site.ecosystem) {
7121
7202
  case "pip": {
@@ -7206,13 +7287,13 @@ function escapeForRegex(value) {
7206
7287
  function isWorkspaceProject(workspaceRoot, name) {
7207
7288
  const short = name.includes("/") ? name.split("/").at(-1) : name;
7208
7289
  return ["apps", "libs", "packages"].some(
7209
- (directory) => fileExists((0, import_node_path31.join)(workspaceRoot, directory, short ?? name, "package.json"))
7290
+ (directory) => fileExists((0, import_node_path33.join)(workspaceRoot, directory, short ?? name, "package.json"))
7210
7291
  );
7211
7292
  }
7212
7293
  function isAliasedInstall(workspaceRoot, name) {
7213
7294
  try {
7214
7295
  const installed = readJson(
7215
- (0, import_node_path31.join)(workspaceRoot, "node_modules", name, "package.json")
7296
+ (0, import_node_path33.join)(workspaceRoot, "node_modules", name, "package.json")
7216
7297
  );
7217
7298
  return installed.name !== void 0 && installed.name !== name;
7218
7299
  } catch {
@@ -7223,14 +7304,14 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
7223
7304
  if (ecosystem === "npm") {
7224
7305
  try {
7225
7306
  return readJson(
7226
- (0, import_node_path31.join)(workspaceRoot, "node_modules", name, "package.json")
7307
+ (0, import_node_path33.join)(workspaceRoot, "node_modules", name, "package.json")
7227
7308
  ).version;
7228
7309
  } catch {
7229
7310
  return void 0;
7230
7311
  }
7231
7312
  }
7232
7313
  if (ecosystem === "pub") {
7233
- const lockPath = (0, import_node_path31.join)(workspaceRoot, "pubspec.lock");
7314
+ const lockPath = (0, import_node_path33.join)(workspaceRoot, "pubspec.lock");
7234
7315
  if (!fileExists(lockPath)) {
7235
7316
  return void 0;
7236
7317
  }
@@ -7238,7 +7319,7 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
7238
7319
  const match = new RegExp(
7239
7320
  String.raw`^\s{2}${escapeForRegex(name)}:[^]*?^\s+version:\s*["']?([^"'\s]+)`,
7240
7321
  "m"
7241
- ).exec((0, import_node_fs29.readFileSync)(lockPath, "utf8"));
7322
+ ).exec((0, import_node_fs30.readFileSync)(lockPath, "utf8"));
7242
7323
  return match?.[1];
7243
7324
  } catch {
7244
7325
  return void 0;
@@ -7304,7 +7385,7 @@ function resolveTarget(locations, target) {
7304
7385
  return byName[0];
7305
7386
  }
7306
7387
  function installInto(workspaceRoot, location, packages, saveDev) {
7307
- const projectDir = (0, import_node_path32.join)(workspaceRoot, location.dir);
7388
+ const projectDir = (0, import_node_path34.join)(workspaceRoot, location.dir);
7308
7389
  switch (location.ecosystem) {
7309
7390
  case "npm": {
7310
7391
  const flags = saveDev ? ["--save-dev"] : [];
@@ -7357,7 +7438,7 @@ function installInto(workspaceRoot, location, packages, saveDev) {
7357
7438
  function addPythonDependency(manifestPath, specifier) {
7358
7439
  let content;
7359
7440
  try {
7360
- content = (0, import_node_fs30.readFileSync)(manifestPath, "utf8");
7441
+ content = (0, import_node_fs31.readFileSync)(manifestPath, "utf8");
7361
7442
  } catch {
7362
7443
  logger.warn(`Could not read ${manifestPath} \u2014 skipped ${specifier}`);
7363
7444
  return;
@@ -7386,7 +7467,7 @@ function installEverything(workspaceRoot, only) {
7386
7467
  }
7387
7468
  function ecosystemPresent(workspaceRoot, ecosystem) {
7388
7469
  if (ecosystem === "go") {
7389
- return fileExists((0, import_node_path32.join)(workspaceRoot, "go.work")) || fileExists((0, import_node_path32.join)(workspaceRoot, "go.mod"));
7470
+ return fileExists((0, import_node_path34.join)(workspaceRoot, "go.work")) || fileExists((0, import_node_path34.join)(workspaceRoot, "go.mod"));
7390
7471
  }
7391
7472
  return hasEcosystem(workspaceRoot, ecosystem);
7392
7473
  }
@@ -7405,7 +7486,7 @@ function splitAtLast(value, separator) {
7405
7486
  }
7406
7487
 
7407
7488
  // src/dependency-management/sync-dependencies.use-case.ts
7408
- var import_node_path33 = require("path");
7489
+ var import_node_path35 = require("path");
7409
7490
 
7410
7491
  // src/dependency-management/semver.algorithm.ts
7411
7492
  var UPDATE_KINDS = ["patch", "minor", "major", "non-semver"];
@@ -7582,7 +7663,7 @@ function describe(finding) {
7582
7663
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
7583
7664
  }
7584
7665
  function runSync(workspaceRoot, options) {
7585
- if (!fileExists((0, import_node_path33.join)(workspaceRoot, "nx.json"))) {
7666
+ if (!fileExists((0, import_node_path35.join)(workspaceRoot, "nx.json"))) {
7586
7667
  throw new Error(
7587
7668
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
7588
7669
  );
@@ -7632,7 +7713,7 @@ function runSync(workspaceRoot, options) {
7632
7713
  }
7633
7714
 
7634
7715
  // src/dependency-management/update-dependencies.use-case.ts
7635
- var import_node_path34 = require("path");
7716
+ var import_node_path36 = require("path");
7636
7717
  var import_prompts2 = require("@inquirer/prompts");
7637
7718
 
7638
7719
  // src/dependency-management/registry.client.ts
@@ -7915,7 +7996,7 @@ function reinstall(workspaceRoot, ecosystems) {
7915
7996
  function hasPythonInstallScript(workspaceRoot) {
7916
7997
  try {
7917
7998
  const manifest = readJson(
7918
- (0, import_node_path34.join)(workspaceRoot, "package.json")
7999
+ (0, import_node_path36.join)(workspaceRoot, "package.json")
7919
8000
  );
7920
8001
  return manifest.scripts?.["python:install"] !== void 0;
7921
8002
  } catch {
@@ -7931,7 +8012,7 @@ function applyGoUpdates(workspaceRoot, entries) {
7931
8012
  }
7932
8013
  }
7933
8014
  async function runUp(workspaceRoot, options) {
7934
- if (!fileExists((0, import_node_path34.join)(workspaceRoot, "nx.json"))) {
8015
+ if (!fileExists((0, import_node_path36.join)(workspaceRoot, "nx.json"))) {
7935
8016
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
7936
8017
  }
7937
8018
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -8009,7 +8090,7 @@ var PROJECT_KINDS = [
8009
8090
  var EMPTY_KINDS = /* @__PURE__ */ new Set(["npm-lib", "internal-lib", "react-lib", "react-internal-lib", "node-function-app"]);
8010
8091
  async function runAdd(kind, name, options) {
8011
8092
  const workspaceRoot = process.cwd();
8012
- if (!fileExists((0, import_node_path35.join)(workspaceRoot, "nx.json"))) {
8093
+ if (!fileExists((0, import_node_path37.join)(workspaceRoot, "nx.json"))) {
8013
8094
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
8014
8095
  }
8015
8096
  const stack = readWorkspaceStack(workspaceRoot);
@@ -8094,8 +8175,8 @@ async function runAdd(kind, name, options) {
8094
8175
  ],
8095
8176
  workspaceRoot
8096
8177
  );
8097
- markPrivate((0, import_node_path35.join)(workspaceRoot, "libs", resolvedName, "package.json"));
8098
- renameScaffoldPlaceholder((0, import_node_path35.join)(workspaceRoot, "libs", resolvedName), resolvedName, options.empty === true);
8178
+ markPrivate((0, import_node_path37.join)(workspaceRoot, "libs", resolvedName, "package.json"));
8179
+ renameScaffoldPlaceholder((0, import_node_path37.join)(workspaceRoot, "libs", resolvedName), resolvedName, options.empty === true);
8099
8180
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
8100
8181
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
8101
8182
  break;
@@ -8191,7 +8272,7 @@ async function runAdd(kind, name, options) {
8191
8272
  }
8192
8273
  function readWorkspaceStack(workspaceRoot) {
8193
8274
  const nxJson = readJson(
8194
- (0, import_node_path35.join)(workspaceRoot, "nx.json")
8275
+ (0, import_node_path37.join)(workspaceRoot, "nx.json")
8195
8276
  );
8196
8277
  const stack = nxJson.mnci?.stack;
8197
8278
  return {
@@ -8280,11 +8361,11 @@ function spawnProject(workspaceRoot, project, target, onLine) {
8280
8361
  }
8281
8362
 
8282
8363
  // src/dev-servers/startable-projects.use-case.ts
8283
- var import_node_path36 = require("path");
8364
+ var import_node_path38 = require("path");
8284
8365
  var START_SUFFIX = ":start";
8285
8366
  var NX_RUN = /\bnx run [^\s:]+:(\S+)/;
8286
8367
  function listStartableProjects(workspaceRoot) {
8287
- const manifestPath = (0, import_node_path36.join)(workspaceRoot, "package.json");
8368
+ const manifestPath = (0, import_node_path38.join)(workspaceRoot, "package.json");
8288
8369
  if (!fileExists(manifestPath)) {
8289
8370
  return [];
8290
8371
  }
@@ -8357,14 +8438,43 @@ async function runDev(workspaceRoot, named, options = {}, dependencies = {}) {
8357
8438
 
8358
8439
  // src/workspace-diagnostics/check-invariants.use-case.ts
8359
8440
  var import_node_child_process2 = require("child_process");
8360
- var import_node_fs32 = require("fs");
8361
- var import_node_path38 = require("path");
8441
+ var import_node_fs33 = require("fs");
8442
+ var import_node_path40 = require("path");
8362
8443
 
8363
- // src/workspace-diagnostics/locate-stranded-release-tags.use-case.ts
8364
- var import_node_fs31 = require("fs");
8365
- var import_node_path37 = require("path");
8444
+ // src/workspace-diagnostics/check-react-app-output.use-case.ts
8445
+ function checkReactAppOutput(workspaceRoot) {
8446
+ const apps = findReactAppsSharingOutput(workspaceRoot);
8447
+ if (apps.length === 0) {
8448
+ return void 0;
8449
+ }
8450
+ return {
8451
+ check: "React apps' tsc output is not the folder Vite builds into",
8452
+ ok: false,
8453
+ detail: `${apps.join(", ")}: tsconfig.app.json writes to the same folder as the Vite bundle, which Vite empties on each build, so build and typecheck running together fail intermittently with TS6305`,
8454
+ remedy: "run `mnci upgrade`, which moves tsc output to out-tsc/app"
8455
+ };
8456
+ }
8457
+
8458
+ // src/release-tag-lineage/create-baseline-tags.use-case.ts
8459
+ function createBaselineTags(repositoryRoot, stranded) {
8460
+ const result = { created: [], existing: [], failed: [] };
8461
+ for (const entry of stranded) {
8462
+ const present = runCapture("git", ["rev-parse", "--verify", "--quiet", `refs/tags/${entry.newTag}`], repositoryRoot);
8463
+ if (present.status === 0) {
8464
+ result.existing.push(entry.newTag);
8465
+ continue;
8466
+ }
8467
+ const made = runCapture("git", ["tag", entry.newTag, `${entry.oldTag}^{commit}`], repositoryRoot);
8468
+ (made.status === 0 ? result.created : result.failed).push(entry.newTag);
8469
+ }
8470
+ return result;
8471
+ }
8366
8472
 
8367
- // src/workspace-diagnostics/stranded-release-tags.algorithm.ts
8473
+ // src/release-tag-lineage/locate-stranded-release-tags.use-case.ts
8474
+ var import_node_fs32 = require("fs");
8475
+ var import_node_path39 = require("path");
8476
+
8477
+ // src/release-tag-lineage/stranded-release-tags.algorithm.ts
8368
8478
  function compareVersions2(left, right) {
8369
8479
  const a = left.split(".").map(Number);
8370
8480
  const b = right.split(".").map(Number);
@@ -8389,7 +8499,7 @@ function findStrandedReleaseTags(projects, tags) {
8389
8499
  return stranded;
8390
8500
  }
8391
8501
 
8392
- // src/workspace-diagnostics/locate-stranded-release-tags.use-case.ts
8502
+ // src/release-tag-lineage/locate-stranded-release-tags.use-case.ts
8393
8503
  var MNCI_TAG_PATTERN = "{projectName}@{version}";
8394
8504
  function locateStrandedReleaseTags(workspaceRoot, tagPattern) {
8395
8505
  if (tagPattern !== void 0 && tagPattern !== MNCI_TAG_PATTERN) {
@@ -8399,18 +8509,29 @@ function locateStrandedReleaseTags(workspaceRoot, tagPattern) {
8399
8509
  if (listed.status !== 0) {
8400
8510
  return [];
8401
8511
  }
8402
- const projects = (0, import_node_fs31.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot }).map((path) => readJson((0, import_node_path37.join)(workspaceRoot, path))).filter((manifest) => manifest.private !== true && manifest.name !== void 0).map((manifest) => manifest.name);
8512
+ const projects = (0, import_node_fs32.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot }).map((path) => readJson((0, import_node_path39.join)(workspaceRoot, path))).filter((manifest) => manifest.private !== true && manifest.name !== void 0).map((manifest) => manifest.name);
8403
8513
  return findStrandedReleaseTags(projects, listed.stdout.split(/\r?\n/).filter(Boolean));
8404
8514
  }
8405
8515
 
8516
+ // src/workspace-diagnostics/check-release-tags-resolve.use-case.ts
8517
+ function checkReleaseTagsResolve(workspaceRoot, nxJson) {
8518
+ const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
8519
+ return {
8520
+ check: "release tags resolve under each project's current name",
8521
+ ok: stranded.length === 0,
8522
+ detail: `${stranded.map((entry) => `${entry.project} has only ${entry.oldTag}`).join("; ")} - nx release finds no tag under the new name and would release from the disk version, a downgrade`,
8523
+ remedy: `run \`mnci adopt --tags\` to create the baseline tag for each (${stranded.map((entry) => entry.newTag).join(", ")}) on the commit of its old tag, then push the tags`
8524
+ };
8525
+ }
8526
+
8406
8527
  // src/workspace-diagnostics/check-invariants.use-case.ts
8407
8528
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
8408
8529
  function toPosix2(path) {
8409
8530
  return path.replaceAll("\\", "/");
8410
8531
  }
8411
8532
  function checkEslintConfigs(workspaceRoot) {
8412
- const rootConfigs = (0, import_node_fs32.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
8413
- const projectConfigs = (0, import_node_fs32.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
8533
+ const rootConfigs = (0, import_node_fs33.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
8534
+ const projectConfigs = (0, import_node_fs33.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
8414
8535
  cwd: workspaceRoot
8415
8536
  }).map((config) => toPosix2(config));
8416
8537
  return [
@@ -8430,10 +8551,10 @@ function checkEslintConfigs(workspaceRoot) {
8430
8551
  ];
8431
8552
  }
8432
8553
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
8433
- const rules = (0, import_node_path38.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
8434
- if (!(0, import_node_fs32.existsSync)(rules)) return [];
8435
- const entryPoint = (0, import_node_path38.join)(workspaceRoot, ESLINT_USER_FILENAME);
8436
- const source = (0, import_node_fs32.existsSync)(entryPoint) ? (0, import_node_fs32.readFileSync)(entryPoint, "utf8") : "";
8554
+ const rules = (0, import_node_path40.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
8555
+ if (!(0, import_node_fs33.existsSync)(rules)) return [];
8556
+ const entryPoint = (0, import_node_path40.join)(workspaceRoot, ESLINT_USER_FILENAME);
8557
+ const source = (0, import_node_fs33.existsSync)(entryPoint) ? (0, import_node_fs33.readFileSync)(entryPoint, "utf8") : "";
8437
8558
  return [
8438
8559
  {
8439
8560
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -8446,7 +8567,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
8446
8567
  function declaredDevDependencies(workspaceRoot) {
8447
8568
  try {
8448
8569
  const manifest = readJson(
8449
- (0, import_node_path38.join)(workspaceRoot, "package.json")
8570
+ (0, import_node_path40.join)(workspaceRoot, "package.json")
8450
8571
  );
8451
8572
  return manifest.devDependencies ?? {};
8452
8573
  } catch {
@@ -8454,7 +8575,7 @@ function declaredDevDependencies(workspaceRoot) {
8454
8575
  }
8455
8576
  }
8456
8577
  function checkNoRetiredFormatter(workspaceRoot) {
8457
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path38.join)(workspaceRoot, file)));
8578
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path40.join)(workspaceRoot, file)));
8458
8579
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
8459
8580
  const stale = [...files, ...declared];
8460
8581
  if (stale.length === 0) {
@@ -8480,7 +8601,7 @@ function checkEslintPlugin(nxJson) {
8480
8601
  };
8481
8602
  }
8482
8603
  function checkResolvedEslint(workspaceRoot) {
8483
- const manifestPath = (0, import_node_path38.join)(workspaceRoot, "node_modules/eslint/package.json");
8604
+ const manifestPath = (0, import_node_path40.join)(workspaceRoot, "node_modules/eslint/package.json");
8484
8605
  if (!fileExists(manifestPath)) {
8485
8606
  return void 0;
8486
8607
  }
@@ -8498,11 +8619,11 @@ function checkResolvedEslint(workspaceRoot) {
8498
8619
  }
8499
8620
  }
8500
8621
  function checkNpmrc(workspaceRoot, registry, scope) {
8501
- const npmrcPath = (0, import_node_path38.join)(workspaceRoot, ".npmrc");
8622
+ const npmrcPath = (0, import_node_path40.join)(workspaceRoot, ".npmrc");
8502
8623
  if (!registry || !fileExists(npmrcPath)) {
8503
8624
  return void 0;
8504
8625
  }
8505
- const npmrc = (0, import_node_fs32.readFileSync)(npmrcPath, "utf8");
8626
+ const npmrc = (0, import_node_fs33.readFileSync)(npmrcPath, "utf8");
8506
8627
  if (registry.kind === "npm") {
8507
8628
  return {
8508
8629
  check: ".npmrc authenticates the public registry",
@@ -8519,11 +8640,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
8519
8640
  };
8520
8641
  }
8521
8642
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
8522
- const npmrcPath = (0, import_node_path38.join)(workspaceRoot, ".npmrc");
8643
+ const npmrcPath = (0, import_node_path40.join)(workspaceRoot, ".npmrc");
8523
8644
  if (!fileExists(npmrcPath)) {
8524
8645
  return void 0;
8525
8646
  }
8526
- const npmrc = (0, import_node_fs32.readFileSync)(npmrcPath, "utf8");
8647
+ const npmrc = (0, import_node_fs33.readFileSync)(npmrcPath, "utf8");
8527
8648
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
8528
8649
  const referenced = [
8529
8650
  ...new Set(
@@ -8547,13 +8668,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
8547
8668
  };
8548
8669
  }
8549
8670
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
8550
- const npmrcPath = (0, import_node_path38.join)(workspaceRoot, ".npmrc");
8551
- const pipelinePath = (0, import_node_path38.join)(workspaceRoot, "azure-pipelines.yml");
8671
+ const npmrcPath = (0, import_node_path40.join)(workspaceRoot, ".npmrc");
8672
+ const pipelinePath = (0, import_node_path40.join)(workspaceRoot, "azure-pipelines.yml");
8552
8673
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
8553
8674
  return void 0;
8554
8675
  }
8555
- const holdsCredentials = (0, import_node_fs32.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
8556
- const runsTask = (0, import_node_fs32.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
8676
+ const holdsCredentials = (0, import_node_fs33.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
8677
+ const runsTask = (0, import_node_fs33.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
8557
8678
  if (!holdsCredentials && !runsTask) {
8558
8679
  return {
8559
8680
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -8593,18 +8714,18 @@ function npmjsCredentialShape(credentials, environment) {
8593
8714
  check: "the credential bound for npmjs.org looks like an npm token",
8594
8715
  ok: false,
8595
8716
  detail: `\${${variable}} is set (${value.length} characters) but does not start with '${NPM_TOKEN_PREFIX}' and is not a legacy UUID token, so it is probably a credential for somewhere else \u2014 '${variable}' is a generic name that other tooling also sets, and inside this workspace it is sent to the PUBLIC registry. A write then fails as a 404 on the PUT, which reads like a missing package`,
8596
- remedy: `\`npm whoami\` to confirm \u2014 it is the only thing that separates a wrong token from an expired one. Then unset \`${variable}\` for local work, or set it to a real npm token`
8717
+ remedy: `find where \`${variable}\` is set (shell profile, CI secret, another tool) and whether it is meant for npm. If it is not, unset \`${variable}\` for local work. If it is meant to be an npm token, check it with \`npm whoami\` run OUTSIDE this workspace (the project .npmrc would send it to the public registry from in here), or set it to a real npm token`
8597
8718
  };
8598
8719
  }
8599
8720
  function checkVersionActions(workspaceRoot) {
8600
8721
  const candidates = [
8601
- ...(0, import_node_fs32.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
8602
- ...(0, import_node_fs32.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
8603
- ...(0, import_node_fs32.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
8722
+ ...(0, import_node_fs33.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
8723
+ ...(0, import_node_fs33.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
8724
+ ...(0, import_node_fs33.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
8604
8725
  ].map((manifest) => toPosix2(manifest));
8605
8726
  return candidates.flatMap((manifest) => {
8606
8727
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
8607
- const projectJsonPath = (0, import_node_path38.join)(workspaceRoot, projectRoot, "project.json");
8728
+ const projectJsonPath = (0, import_node_path40.join)(workspaceRoot, projectRoot, "project.json");
8608
8729
  let hasOverride = false;
8609
8730
  try {
8610
8731
  const projectJson = readJson(projectJsonPath);
@@ -8633,7 +8754,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
8633
8754
  ]) {
8634
8755
  try {
8635
8756
  const targets = extract(
8636
- readJson((0, import_node_path38.join)(workspaceRoot, projectRoot, file))
8757
+ readJson((0, import_node_path40.join)(workspaceRoot, projectRoot, file))
8637
8758
  );
8638
8759
  if (targets && typeof targets === "object") {
8639
8760
  sources.push({
@@ -8649,8 +8770,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
8649
8770
  function checkTargetFilesExist(workspaceRoot) {
8650
8771
  const projectRoots = new Set(
8651
8772
  [
8652
- ...(0, import_node_fs32.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
8653
- ...(0, import_node_fs32.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
8773
+ ...(0, import_node_fs33.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
8774
+ ...(0, import_node_fs33.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
8654
8775
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
8655
8776
  );
8656
8777
  return [...projectRoots].flatMap(
@@ -8665,7 +8786,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
8665
8786
  return TARGET_FILE_OPTIONS.flatMap((option) => {
8666
8787
  const value = target?.options?.[option];
8667
8788
  const checkable = typeof value === "string" && !value.includes("{");
8668
- if (!checkable || fileExists((0, import_node_path38.join)(workspaceRoot, value))) {
8789
+ if (!checkable || fileExists((0, import_node_path40.join)(workspaceRoot, value))) {
8669
8790
  return [];
8670
8791
  }
8671
8792
  return [
@@ -8704,15 +8825,15 @@ function checkGoPluginRegistered(workspaceRoot) {
8704
8825
  };
8705
8826
  }
8706
8827
  function checkGoWorkInSync(workspaceRoot) {
8707
- const goWorkPath = (0, import_node_path38.join)(workspaceRoot, "go.work");
8828
+ const goWorkPath = (0, import_node_path40.join)(workspaceRoot, "go.work");
8708
8829
  if (!fileExists(goWorkPath)) {
8709
8830
  return void 0;
8710
8831
  }
8711
- const contents = (0, import_node_fs32.existsSync)(goWorkPath) ? (0, import_node_fs32.readFileSync)(goWorkPath, "utf8") : "";
8832
+ const contents = (0, import_node_fs33.existsSync)(goWorkPath) ? (0, import_node_fs33.readFileSync)(goWorkPath, "utf8") : "";
8712
8833
  const blockEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+\(([^)]*)\)/g), (match) => match[1].split("\n")).flat();
8713
8834
  const singleEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+(\.\S+)/g), (match) => match[1]);
8714
8835
  const uses = [...blockEntries, ...singleEntries].map((entry) => entry.trim()).filter(Boolean);
8715
- const stale = uses.filter((entry) => !(0, import_node_fs32.existsSync)((0, import_node_path38.join)(workspaceRoot, entry, "go.mod")));
8836
+ const stale = uses.filter((entry) => !(0, import_node_fs33.existsSync)((0, import_node_path40.join)(workspaceRoot, entry, "go.mod")));
8716
8837
  return {
8717
8838
  check: "every go.work `use` entry points to a module that still exists",
8718
8839
  ok: stale.length === 0,
@@ -8728,9 +8849,9 @@ function checkNativeApps(workspaceRoot) {
8728
8849
  { file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
8729
8850
  { file: "azure-pipelines.yml", marker: "- job: native" }
8730
8851
  ];
8731
- const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path38.join)(workspaceRoot, file))).map(({ file, marker }) => ({
8852
+ const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path40.join)(workspaceRoot, file))).map(({ file, marker }) => ({
8732
8853
  check: `${file} builds the native apps on every OS`,
8733
- ok: (0, import_node_fs32.readFileSync)((0, import_node_path38.join)(workspaceRoot, file), "utf8").includes(marker),
8854
+ ok: (0, import_node_fs33.readFileSync)((0, import_node_path40.join)(workspaceRoot, file), "utf8").includes(marker),
8734
8855
  detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
8735
8856
  remedy: "run `mnci upgrade`"
8736
8857
  }));
@@ -8743,7 +8864,7 @@ function checkNativeApps(workspaceRoot) {
8743
8864
  return findings;
8744
8865
  }
8745
8866
  function checkNoRootRuntimeDependencies(workspaceRoot) {
8746
- const manifestPath = (0, import_node_path38.join)(workspaceRoot, "package.json");
8867
+ const manifestPath = (0, import_node_path40.join)(workspaceRoot, "package.json");
8747
8868
  if (!fileExists(manifestPath)) {
8748
8869
  return void 0;
8749
8870
  }
@@ -8763,14 +8884,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
8763
8884
  };
8764
8885
  }
8765
8886
  function checkRollupSourceMaps(workspaceRoot) {
8766
- const configs = (0, import_node_fs32.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8887
+ const configs = (0, import_node_fs33.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8767
8888
  cwd: workspaceRoot
8768
8889
  }).map((config) => toPosix2(config));
8769
8890
  return configs.flatMap((relativePath) => {
8770
- const configPath = (0, import_node_path38.join)(workspaceRoot, relativePath);
8891
+ const configPath = (0, import_node_path40.join)(workspaceRoot, relativePath);
8771
8892
  let config;
8772
8893
  try {
8773
- config = (0, import_node_fs32.readFileSync)(configPath, "utf8");
8894
+ config = (0, import_node_fs33.readFileSync)(configPath, "utf8");
8774
8895
  } catch {
8775
8896
  return [];
8776
8897
  }
@@ -8785,11 +8906,11 @@ function checkRollupSourceMaps(workspaceRoot) {
8785
8906
  });
8786
8907
  }
8787
8908
  function checkDeclarationSpecifiers(workspaceRoot) {
8788
- const configs = (0, import_node_fs32.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8909
+ const configs = (0, import_node_fs33.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
8789
8910
  cwd: workspaceRoot
8790
8911
  }).map((config) => toPosix2(config));
8791
8912
  return configs.flatMap((relativePath) => {
8792
- const configPath = (0, import_node_path38.join)(workspaceRoot, relativePath);
8913
+ const configPath = (0, import_node_path40.join)(workspaceRoot, relativePath);
8793
8914
  if (!fileExists(configPath)) {
8794
8915
  return [];
8795
8916
  }
@@ -8804,7 +8925,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
8804
8925
  // `plugins` array (what @nx/react:library writes). For any other shape it would no-op, and
8805
8926
  // naming a command that silently does nothing is the failure mode the source-map check
8806
8927
  // above goes out of its way to avoid, so the remedy depends on the shape.
8807
- remedy: canAddDeclarationSpecifierPlugin((0, import_node_fs32.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"
8928
+ remedy: canAddDeclarationSpecifierPlugin((0, import_node_fs33.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"
8808
8929
  }
8809
8930
  ];
8810
8931
  }
@@ -8820,8 +8941,8 @@ function checkDeclarationSpecifiers(workspaceRoot) {
8820
8941
  }
8821
8942
  function checkPipelinePhases(workspaceRoot) {
8822
8943
  const files = ["azure-pipelines.yml", ".github/workflows/ci.yml"];
8823
- return files.filter((file) => fileExists((0, import_node_path38.join)(workspaceRoot, file))).flatMap((file) => {
8824
- const { verifyActive, switchedOff } = inspectPipeline((0, import_node_fs32.readFileSync)((0, import_node_path38.join)(workspaceRoot, file), "utf8"));
8944
+ return files.filter((file) => fileExists((0, import_node_path40.join)(workspaceRoot, file))).flatMap((file) => {
8945
+ const { verifyActive, switchedOff } = inspectPipeline((0, import_node_fs33.readFileSync)((0, import_node_path40.join)(workspaceRoot, file), "utf8"));
8825
8946
  const verify = {
8826
8947
  check: `${file} runs the enforced verify phase`,
8827
8948
  ok: verifyActive,
@@ -8862,7 +8983,7 @@ function checkDependencyRangesNotPreserved(nxJson) {
8862
8983
  };
8863
8984
  }
8864
8985
  function checkLockfileHasNoLocalRegistry(workspaceRoot) {
8865
- if (!fileExists((0, import_node_path38.join)(workspaceRoot, "package-lock.json"))) {
8986
+ if (!fileExists((0, import_node_path40.join)(workspaceRoot, "package-lock.json"))) {
8866
8987
  return void 0;
8867
8988
  }
8868
8989
  return {
@@ -8872,17 +8993,8 @@ function checkLockfileHasNoLocalRegistry(workspaceRoot) {
8872
8993
  remedy: "run `mnci upgrade`, which removes it, then commit package-lock.json"
8873
8994
  };
8874
8995
  }
8875
- function checkReleaseTagsResolve(workspaceRoot, nxJson) {
8876
- const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
8877
- return {
8878
- check: "release tags resolve under each project's current name",
8879
- ok: stranded.length === 0,
8880
- detail: `${stranded.map((entry) => `${entry.project} has only ${entry.oldTag}`).join("; ")} - nx release finds no tag under the new name and would release from the disk version, a downgrade`,
8881
- remedy: `run \`mnci adopt --tags\` to create the baseline tag for each (${stranded.map((entry) => entry.newTag).join(", ")}) on the commit of its old tag, then push the tags`
8882
- };
8883
- }
8884
8996
  function collectFindings(workspaceRoot) {
8885
- const nxJsonPath = (0, import_node_path38.join)(workspaceRoot, "nx.json");
8997
+ const nxJsonPath = (0, import_node_path40.join)(workspaceRoot, "nx.json");
8886
8998
  if (!fileExists(nxJsonPath)) {
8887
8999
  throw new Error(
8888
9000
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -8910,7 +9022,8 @@ function collectFindings(workspaceRoot) {
8910
9022
  ...checkNativeBuildConfig(workspaceRoot),
8911
9023
  checkDependencyRangesNotPreserved(nxJson),
8912
9024
  checkLockfileHasNoLocalRegistry(workspaceRoot),
8913
- checkReleaseTagsResolve(workspaceRoot, nxJson)
9025
+ checkReleaseTagsResolve(workspaceRoot, nxJson),
9026
+ checkReactAppOutput(workspaceRoot)
8914
9027
  ].filter((finding) => finding !== void 0);
8915
9028
  }
8916
9029
  function runDoctor(workspaceRoot, options = {}) {
@@ -8946,11 +9059,11 @@ function runDoctor(workspaceRoot, options = {}) {
8946
9059
  process.exitCode = 1;
8947
9060
  }
8948
9061
 
8949
- // src/repository-adoption/adopt-dependencies.use-case.ts
8950
- var import_node_fs33 = require("fs");
8951
- var import_node_path39 = require("path");
9062
+ // src/dependency-adoption/adopt-dependencies.use-case.ts
9063
+ var import_node_fs34 = require("fs");
9064
+ var import_node_path41 = require("path");
8952
9065
 
8953
- // src/repository-adoption/clean-working-tree.validator.ts
9066
+ // src/clean-working-tree/clean-working-tree.validator.ts
8954
9067
  function requireCleanWorkingTree(repositoryRoot, capture = runCapture) {
8955
9068
  if (capture("git", ["rev-parse", "--is-inside-work-tree"], repositoryRoot).status !== 0) {
8956
9069
  throw new Error("This directory is not a git repository. Every adoption step is one diff to review, so it needs git.");
@@ -8960,7 +9073,7 @@ function requireCleanWorkingTree(repositoryRoot, capture = runCapture) {
8960
9073
  }
8961
9074
  }
8962
9075
 
8963
- // src/repository-adoption/extract-imports.algorithm.ts
9076
+ // src/dependency-adoption/extract-imports.algorithm.ts
8964
9077
  var import_node_module = require("module");
8965
9078
  var SPECIFIER2 = /(?:\bfrom\s*|\bimport\s*(?:\(\s*)?|\brequire\s*\(\s*)(['"`])([^'"`\n]+)\1/g;
8966
9079
  var BUILTINS = new Set(import_node_module.builtinModules);
@@ -8986,7 +9099,7 @@ function extractImportedPackages(source) {
8986
9099
  return found;
8987
9100
  }
8988
9101
 
8989
- // src/repository-adoption/plan-dependency-moves.algorithm.ts
9102
+ // src/dependency-adoption/plan-dependency-moves.algorithm.ts
8990
9103
  function planDependencyMoves(rootDependencies, usage, declared) {
8991
9104
  const plan = { moves: [], removed: [], keptAtRoot: [], conflicts: [] };
8992
9105
  for (const [name, range] of Object.entries(rootDependencies)) {
@@ -9014,12 +9127,12 @@ function planDependencyMoves(rootDependencies, usage, declared) {
9014
9127
  return plan;
9015
9128
  }
9016
9129
 
9017
- // src/repository-adoption/adopt-dependencies.use-case.ts
9130
+ // src/dependency-adoption/adopt-dependencies.use-case.ts
9018
9131
  var SOURCE_FILE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
9019
9132
  var TEST_FILE = /\.(?:spec|test)\.[^.]+$|[\\/](?:__tests__|tests?|e2e)[\\/]/;
9020
9133
  var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage", "out", ".git", ".nx", "tmp"]);
9021
9134
  function sourceFiles(directory, relative = "") {
9022
- const entries = (0, import_node_fs33.readdirSync)((0, import_node_path39.join)(directory, relative), { withFileTypes: true });
9135
+ const entries = (0, import_node_fs34.readdirSync)((0, import_node_path41.join)(directory, relative), { withFileTypes: true });
9023
9136
  const found = [];
9024
9137
  for (const entry of entries) {
9025
9138
  const path = relative === "" ? entry.name : `${relative}/${entry.name}`;
@@ -9035,7 +9148,7 @@ function sourceFiles(directory, relative = "") {
9035
9148
  }
9036
9149
  function wantedImportsOf(path, wanted) {
9037
9150
  try {
9038
- const imported = [...extractImportedPackages((0, import_node_fs33.readFileSync)(path, "utf8"))];
9151
+ const imported = [...extractImportedPackages((0, import_node_fs34.readFileSync)(path, "utf8"))];
9039
9152
  return imported.filter((name) => wanted.has(name));
9040
9153
  } catch {
9041
9154
  return [];
@@ -9046,7 +9159,7 @@ function importsOfProject(projectDirectory, wanted) {
9046
9159
  const tested = /* @__PURE__ */ new Set();
9047
9160
  const files = sourceFiles(projectDirectory);
9048
9161
  for (const file of files) {
9049
- const names = wantedImportsOf((0, import_node_path39.join)(projectDirectory, file), wanted);
9162
+ const names = wantedImportsOf((0, import_node_path41.join)(projectDirectory, file), wanted);
9050
9163
  const target = TEST_FILE.test(file) ? tested : shipped;
9051
9164
  for (const name of names) {
9052
9165
  target.add(name);
@@ -9058,7 +9171,7 @@ function importsOfProject(projectDirectory, wanted) {
9058
9171
  function findUsage(repositoryRoot, projectDirectories, wanted) {
9059
9172
  const usage = {};
9060
9173
  for (const dir of projectDirectories) {
9061
- const { shipped, testsOnly } = importsOfProject((0, import_node_path39.join)(repositoryRoot, dir), wanted);
9174
+ const { shipped, testsOnly } = importsOfProject((0, import_node_path41.join)(repositoryRoot, dir), wanted);
9062
9175
  for (const name of shipped) {
9063
9176
  usage[name] ??= { runtime: [], testsOnly: [] };
9064
9177
  usage[name].runtime.push(dir);
@@ -9073,7 +9186,7 @@ function findUsage(repositoryRoot, projectDirectories, wanted) {
9073
9186
  function adoptDependencies(repositoryRoot, dependencies = {}) {
9074
9187
  const run = dependencies.run ?? runShell;
9075
9188
  requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
9076
- const rootPath = (0, import_node_path39.join)(repositoryRoot, "package.json");
9189
+ const rootPath = (0, import_node_path41.join)(repositoryRoot, "package.json");
9077
9190
  if (!fileExists(rootPath)) {
9078
9191
  throw new Error("No package.json at the repository root.");
9079
9192
  }
@@ -9107,11 +9220,11 @@ function adoptDependencies(repositoryRoot, dependencies = {}) {
9107
9220
  return { plan, installed };
9108
9221
  }
9109
9222
 
9110
- // src/repository-adoption/adopt-kinds.use-case.ts
9111
- var import_node_fs34 = require("fs");
9112
- var import_node_path40 = require("path");
9223
+ // src/kind-adoption/adopt-kinds.use-case.ts
9224
+ var import_node_fs35 = require("fs");
9225
+ var import_node_path42 = require("path");
9113
9226
 
9114
- // src/repository-adoption/infer-project-kind.algorithm.ts
9227
+ // src/kind-adoption/infer-project-kind.algorithm.ts
9115
9228
  var SERVER_FRAMEWORKS = ["express", "koa", "fastify", "@nestjs/core"];
9116
9229
  function declares(manifest, name) {
9117
9230
  return ["dependencies", "devDependencies", "peerDependencies"].some((key) => {
@@ -9207,35 +9320,35 @@ function inferProjectKind(evidence) {
9207
9320
  }
9208
9321
  }
9209
9322
 
9210
- // src/repository-adoption/adopt-kinds.use-case.ts
9323
+ // src/kind-adoption/adopt-kinds.use-case.ts
9211
9324
  var TYPE_TAG = "type:";
9212
9325
  function readEvidence(repositoryRoot, location) {
9213
- const directory = (0, import_node_path40.join)(repositoryRoot, location.dir);
9214
- const files = (0, import_node_fs34.readdirSync)(directory);
9326
+ const directory = (0, import_node_path42.join)(repositoryRoot, location.dir);
9327
+ const files = (0, import_node_fs35.readdirSync)(directory);
9215
9328
  const manifest = location.ecosystem === "npm" ? readJson(location.manifestPath) : {};
9216
- const text = location.ecosystem === "npm" ? "" : (0, import_node_fs34.readFileSync)(location.manifestPath, "utf8");
9329
+ const text = location.ecosystem === "npm" ? "" : (0, import_node_fs35.readFileSync)(location.manifestPath, "utf8");
9217
9330
  let hasProgram = false;
9218
9331
  if (location.ecosystem === "go") {
9219
- hasProgram = files.filter((file) => file.endsWith(".go")).some((file) => /^package main\b/m.test((0, import_node_fs34.readFileSync)((0, import_node_path40.join)(directory, file), "utf8")));
9332
+ hasProgram = files.filter((file) => file.endsWith(".go")).some((file) => /^package main\b/m.test((0, import_node_fs35.readFileSync)((0, import_node_path42.join)(directory, file), "utf8")));
9220
9333
  } else if (location.ecosystem === "pub") {
9221
- hasProgram = (0, import_node_fs34.existsSync)((0, import_node_path40.join)(directory, "lib", "main.dart"));
9334
+ hasProgram = (0, import_node_fs35.existsSync)((0, import_node_path42.join)(directory, "lib", "main.dart"));
9222
9335
  }
9223
9336
  return { ecosystem: location.ecosystem, manifest, text, files, hasProgram };
9224
9337
  }
9225
9338
  function existingKind(directory) {
9226
9339
  const sources = [];
9227
- if (fileExists((0, import_node_path40.join)(directory, "project.json"))) {
9228
- sources.push(readJson((0, import_node_path40.join)(directory, "project.json")).tags ?? []);
9340
+ if (fileExists((0, import_node_path42.join)(directory, "project.json"))) {
9341
+ sources.push(readJson((0, import_node_path42.join)(directory, "project.json")).tags ?? []);
9229
9342
  }
9230
- if (fileExists((0, import_node_path40.join)(directory, "package.json"))) {
9231
- sources.push(readJson((0, import_node_path40.join)(directory, "package.json")).nx?.tags ?? []);
9343
+ if (fileExists((0, import_node_path42.join)(directory, "package.json"))) {
9344
+ sources.push(readJson((0, import_node_path42.join)(directory, "package.json")).nx?.tags ?? []);
9232
9345
  }
9233
9346
  return sources.flat().find((tag) => tag.startsWith(TYPE_TAG))?.slice(TYPE_TAG.length);
9234
9347
  }
9235
9348
  function writeKindTag(directory, name, kind) {
9236
9349
  const tag = `${TYPE_TAG}${kind}`;
9237
- const projectJson = (0, import_node_path40.join)(directory, "project.json");
9238
- const packageJson = (0, import_node_path40.join)(directory, "package.json");
9350
+ const projectJson = (0, import_node_path42.join)(directory, "project.json");
9351
+ const packageJson = (0, import_node_path42.join)(directory, "package.json");
9239
9352
  if (fileExists(projectJson)) {
9240
9353
  const project = readJson(projectJson);
9241
9354
  writeFileEnsured(projectJson, toJson({ ...project, tags: [...project.tags ?? [], tag] }));
@@ -9259,7 +9372,7 @@ function adoptKinds(repositoryRoot, overrides = {}, dependencies = {}) {
9259
9372
  }
9260
9373
  }
9261
9374
  return locations.map((location) => {
9262
- const directory = (0, import_node_path40.join)(repositoryRoot, location.dir);
9375
+ const directory = (0, import_node_path42.join)(repositoryRoot, location.dir);
9263
9376
  const present = existingKind(directory);
9264
9377
  if (present !== void 0) {
9265
9378
  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" };
@@ -9275,12 +9388,12 @@ function adoptKinds(repositoryRoot, overrides = {}, dependencies = {}) {
9275
9388
  }
9276
9389
 
9277
9390
  // src/repository-adoption/adopt-overlay.use-case.ts
9278
- var import_node_fs36 = require("fs");
9279
- var import_node_path42 = require("path");
9391
+ var import_node_fs37 = require("fs");
9392
+ var import_node_path44 = require("path");
9280
9393
 
9281
9394
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
9282
- var import_node_fs35 = require("fs");
9283
- var import_node_path41 = require("path");
9395
+ var import_node_fs36 = require("fs");
9396
+ var import_node_path43 = require("path");
9284
9397
  function resolveRegistry(options, persisted) {
9285
9398
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
9286
9399
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -9309,7 +9422,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
9309
9422
  return persisted.workspaceName;
9310
9423
  }
9311
9424
  try {
9312
- const existing = (0, import_node_fs35.readdirSync)(workspaceRoot).find(
9425
+ const existing = (0, import_node_fs36.readdirSync)(workspaceRoot).find(
9313
9426
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
9314
9427
  );
9315
9428
  if (existing) {
@@ -9317,11 +9430,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
9317
9430
  }
9318
9431
  } catch {
9319
9432
  }
9320
- return (0, import_node_path41.basename)(workspaceRoot);
9433
+ return (0, import_node_path43.basename)(workspaceRoot);
9321
9434
  }
9322
9435
  function detectNpmAuth(workspaceRoot) {
9323
9436
  try {
9324
- return (0, import_node_fs35.readFileSync)((0, import_node_path41.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
9437
+ return (0, import_node_fs36.readFileSync)((0, import_node_path43.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
9325
9438
  } catch {
9326
9439
  return void 0;
9327
9440
  }
@@ -9368,7 +9481,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
9368
9481
  };
9369
9482
  }
9370
9483
  function runUpgrade(workspaceRoot, options) {
9371
- if (!fileExists((0, import_node_path41.join)(workspaceRoot, "nx.json"))) {
9484
+ if (!fileExists((0, import_node_path43.join)(workspaceRoot, "nx.json"))) {
9372
9485
  throw new Error(
9373
9486
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
9374
9487
  );
@@ -9416,6 +9529,13 @@ function runUpgrade(workspaceRoot, options) {
9416
9529
  logger.step("Updating the VS Code extension packaging script");
9417
9530
  logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
9418
9531
  }
9532
+ const separatedApps = separateReactAppsOutput(workspaceRoot);
9533
+ if (separatedApps.length > 0) {
9534
+ logger.step("Moving tsc output out of the folder Vite builds into (build and typecheck raced, TS6305)");
9535
+ for (const dir of separatedApps) {
9536
+ logger.detail(`updated ${dir}/tsconfig.app.json`);
9537
+ }
9538
+ }
9419
9539
  if (refreshContainerScript(workspaceRoot)) {
9420
9540
  logger.step("Updating the container image script");
9421
9541
  logger.detail("updated tools/container-image.cjs");
@@ -9446,7 +9566,7 @@ function runUpgrade(workspaceRoot, options) {
9446
9566
  "Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
9447
9567
  );
9448
9568
  runFormatter(workspaceRoot);
9449
- const nxJson = readJson((0, import_node_path41.join)(workspaceRoot, "nx.json"));
9569
+ const nxJson = readJson((0, import_node_path43.join)(workspaceRoot, "nx.json"));
9450
9570
  const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
9451
9571
  for (const entry of stranded) {
9452
9572
  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).`);
@@ -9457,9 +9577,9 @@ function runUpgrade(workspaceRoot, options) {
9457
9577
 
9458
9578
  // src/repository-adoption/adopt-overlay.use-case.ts
9459
9579
  function detectCiProvider(repositoryRoot) {
9460
- const azure = (0, import_node_fs36.existsSync)((0, import_node_path42.join)(repositoryRoot, "azure-pipelines.yml"));
9461
- const workflows = (0, import_node_path42.join)(repositoryRoot, ".github", "workflows");
9462
- const github = (0, import_node_fs36.existsSync)(workflows) && (0, import_node_fs36.readdirSync)(workflows).some((file) => /\.ya?ml$/.test(file));
9580
+ const azure = (0, import_node_fs37.existsSync)((0, import_node_path44.join)(repositoryRoot, "azure-pipelines.yml"));
9581
+ const workflows = (0, import_node_path44.join)(repositoryRoot, ".github", "workflows");
9582
+ const github = (0, import_node_fs37.existsSync)(workflows) && (0, import_node_fs37.readdirSync)(workflows).some((file) => /\.ya?ml$/.test(file));
9463
9583
  if (azure && github) {
9464
9584
  return "both";
9465
9585
  }
@@ -9469,7 +9589,7 @@ function detectCiProvider(repositoryRoot) {
9469
9589
  return github ? "github" : void 0;
9470
9590
  }
9471
9591
  function detectTestRunner(repositoryRoot) {
9472
- const manifestPath = (0, import_node_path42.join)(repositoryRoot, "package.json");
9592
+ const manifestPath = (0, import_node_path44.join)(repositoryRoot, "package.json");
9473
9593
  if (!fileExists(manifestPath)) {
9474
9594
  return void 0;
9475
9595
  }
@@ -9482,8 +9602,8 @@ function detectTestRunner(repositoryRoot) {
9482
9602
  }
9483
9603
  function adoptOverlay(repositoryRoot, options, dependencies = {}) {
9484
9604
  requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
9485
- if (!fileExists((0, import_node_path42.join)(repositoryRoot, "nx.json"))) {
9486
- 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.");
9605
+ if (!fileExists((0, import_node_path44.join)(repositoryRoot, "nx.json"))) {
9606
+ throw new Error("There is no nx.json, so Nx is not set up here. Run `mnci adopt --toolchain` first: it sets Nx up (nx init, then nx add), and the overlay needs that.");
9487
9607
  }
9488
9608
  const persisted = readMnciConfig(repositoryRoot);
9489
9609
  const filled = {
@@ -9494,10 +9614,10 @@ function adoptOverlay(repositoryRoot, options, dependencies = {}) {
9494
9614
  (dependencies.upgrade ?? runUpgrade)(repositoryRoot, filled);
9495
9615
  }
9496
9616
 
9497
- // src/repository-adoption/adopt-toolchain.use-case.ts
9498
- var import_node_path44 = require("path");
9617
+ // src/toolchain-adoption/adopt-toolchain.use-case.ts
9618
+ var import_node_path47 = require("path");
9499
9619
 
9500
- // src/repository-adoption/align-nx-family.algorithm.ts
9620
+ // src/toolchain-adoption/align-nx-family.algorithm.ts
9501
9621
  var VERSION = /^[\^~]?(\d+)\.(\d+)\.(\d+)$/;
9502
9622
  function isNxFamily(name) {
9503
9623
  return name === "nx" || name.startsWith("@nx/");
@@ -9532,25 +9652,56 @@ function alignNxFamily(dependencies, version) {
9532
9652
  return { dependencies: aligned, changed };
9533
9653
  }
9534
9654
 
9535
- // src/repository-adoption/retire-tooling.use-case.ts
9536
- var import_node_fs37 = require("fs");
9537
- var import_node_path43 = require("path");
9655
+ // src/toolchain-adoption/bootstrap-nx.use-case.ts
9656
+ var import_node_path45 = require("path");
9657
+ var BASE_PLUGIN = "@nx/js";
9658
+ var TOOL_PLUGINS = [
9659
+ ["eslint", "@nx/eslint"],
9660
+ ["jest", "@nx/jest"],
9661
+ ["vitest", "@nx/vite"]
9662
+ ];
9663
+ function pluginsFor(repositoryRoot) {
9664
+ const manifestPath = (0, import_node_path45.join)(repositoryRoot, "package.json");
9665
+ const manifest = fileExists(manifestPath) ? readJson(manifestPath) : {};
9666
+ const declared = Object.keys({ ...manifest.dependencies, ...manifest.devDependencies });
9667
+ return [BASE_PLUGIN, ...TOOL_PLUGINS.filter(([tool]) => declared.includes(tool)).map(([, plugin]) => plugin)];
9668
+ }
9669
+ function bootstrapNx(repositoryRoot, nxVersion, dependencies) {
9670
+ if (fileExists((0, import_node_path45.join)(repositoryRoot, "nx.json"))) {
9671
+ return { bootstrapped: false, plugins: [] };
9672
+ }
9673
+ const initialised = dependencies.run("npx", ["--yes", `nx@${nxVersion ?? "latest"}`, "init", "--interactive=false", "--nxCloud=skip", "--plugins=skip"], repositoryRoot);
9674
+ if (initialised !== 0) {
9675
+ throw new Error("`nx init` failed, so Nx could not be set up here. Read its output above; nothing else was changed after it.");
9676
+ }
9677
+ const plugins = pluginsFor(repositoryRoot);
9678
+ for (const plugin of plugins) {
9679
+ if (dependencies.run("npx", ["nx", "add", plugin], repositoryRoot) !== 0) {
9680
+ throw new Error(`\`nx add ${plugin}\` failed. Nx itself is set up (nx.json exists); add the plugin by hand once its error is dealt with.`);
9681
+ }
9682
+ }
9683
+ return { bootstrapped: true, plugins };
9684
+ }
9685
+
9686
+ // src/toolchain-adoption/retire-tooling.use-case.ts
9687
+ var import_node_fs38 = require("fs");
9688
+ var import_node_path46 = require("path");
9538
9689
  var RETIRED_COMMAND = /\b(?:prettier|oxfmt|oxlint)\b/;
9539
9690
  function retireTooling(repositoryRoot) {
9540
9691
  const removed = [];
9541
9692
  for (const file of RETIRED_FORMATTER_FILES) {
9542
- if (!fileExists((0, import_node_path43.join)(repositoryRoot, file))) {
9693
+ if (!fileExists((0, import_node_path46.join)(repositoryRoot, file))) {
9543
9694
  continue;
9544
9695
  }
9545
- (0, import_node_fs37.rmSync)((0, import_node_path43.join)(repositoryRoot, file), { force: true });
9696
+ (0, import_node_fs38.rmSync)((0, import_node_path46.join)(repositoryRoot, file), { force: true });
9546
9697
  removed.push(file);
9547
9698
  }
9548
- const hadRegistry = fileExists((0, import_node_path43.join)(repositoryRoot, ".verdaccio"));
9699
+ const hadRegistry = fileExists((0, import_node_path46.join)(repositoryRoot, ".verdaccio"));
9549
9700
  removeLocalRegistryScaffolding(repositoryRoot);
9550
9701
  if (hadRegistry) {
9551
9702
  removed.push(".verdaccio, its dependency and the local-registry target");
9552
9703
  }
9553
- const manifestPath = (0, import_node_path43.join)(repositoryRoot, "package.json");
9704
+ const manifestPath = (0, import_node_path46.join)(repositoryRoot, "package.json");
9554
9705
  if (!fileExists(manifestPath)) {
9555
9706
  return removed;
9556
9707
  }
@@ -9578,7 +9729,7 @@ function retireTooling(repositoryRoot) {
9578
9729
  return removed;
9579
9730
  }
9580
9731
 
9581
- // src/repository-adoption/adopt-toolchain.use-case.ts
9732
+ // src/toolchain-adoption/adopt-toolchain.use-case.ts
9582
9733
  var MAX_AUDIT_FIX_PASSES = 4;
9583
9734
  function publishedNxVersions(repositoryRoot, capture) {
9584
9735
  const answer = capture("npm", ["view", "nx", "versions", "--json"], repositoryRoot);
@@ -9597,10 +9748,14 @@ function adoptToolchain(repositoryRoot, options = {}, dependencies = {}) {
9597
9748
  console.log(message);
9598
9749
  });
9599
9750
  requireCleanWorkingTree(repositoryRoot, capture);
9600
- const manifestPath = (0, import_node_path44.join)(repositoryRoot, "package.json");
9751
+ const manifestPath = (0, import_node_path47.join)(repositoryRoot, "package.json");
9601
9752
  if (!fileExists(manifestPath)) {
9602
9753
  throw new Error("No package.json at the repository root.");
9603
9754
  }
9755
+ const bootstrap = bootstrapNx(repositoryRoot, options.nxVersion, { run });
9756
+ if (bootstrap.bootstrapped) {
9757
+ log(`Set Nx up (nx init, then nx add ${bootstrap.plugins.join(" ")})`);
9758
+ }
9604
9759
  log("Removing retired tooling");
9605
9760
  const removed = retireTooling(repositoryRoot);
9606
9761
  const manifest = readJson(manifestPath);
@@ -9628,27 +9783,12 @@ function adoptToolchain(repositoryRoot, options = {}, dependencies = {}) {
9628
9783
  run("npm", ["audit", "fix", "--no-fund"], repositoryRoot);
9629
9784
  passes = audit(repositoryRoot) === 0;
9630
9785
  }
9631
- return { removed, aligned: { names, version }, auditFixes, auditPasses: passes };
9632
- }
9633
-
9634
- // src/repository-adoption/create-baseline-tags.use-case.ts
9635
- function createBaselineTags(repositoryRoot, stranded) {
9636
- const result = { created: [], existing: [], failed: [] };
9637
- for (const entry of stranded) {
9638
- const present = runCapture("git", ["rev-parse", "--verify", "--quiet", `refs/tags/${entry.newTag}`], repositoryRoot);
9639
- if (present.status === 0) {
9640
- result.existing.push(entry.newTag);
9641
- continue;
9642
- }
9643
- const made = runCapture("git", ["tag", entry.newTag, `${entry.oldTag}^{commit}`], repositoryRoot);
9644
- (made.status === 0 ? result.created : result.failed).push(entry.newTag);
9645
- }
9646
- return result;
9786
+ return { bootstrapped: bootstrap.plugins, removed, aligned: { names, version }, auditFixes, auditPasses: passes };
9647
9787
  }
9648
9788
 
9649
- // src/repository-adoption/inspect-repository.use-case.ts
9650
- var import_node_fs38 = require("fs");
9651
- var import_node_path45 = require("path");
9789
+ // src/adoption-report/inspect-repository.use-case.ts
9790
+ var import_node_fs39 = require("fs");
9791
+ var import_node_path48 = require("path");
9652
9792
  var LOCKFILES = [
9653
9793
  ["package-lock.json", "npm"],
9654
9794
  ["pnpm-lock.yaml", "pnpm"],
@@ -9669,25 +9809,25 @@ function inspectRepository(repositoryRoot) {
9669
9809
  const isGitRepo = inside.status === 0 && inside.stdout.trim() === "true";
9670
9810
  const dirty = isGitRepo && runCapture("git", ["status", "--porcelain"], repositoryRoot).stdout.trim() !== "";
9671
9811
  const tags = isGitRepo ? runCapture("git", ["tag", "--list"], repositoryRoot).stdout.split(/\r?\n/).filter(Boolean) : [];
9672
- const manifestPath = (0, import_node_path45.join)(repositoryRoot, "package.json");
9812
+ const manifestPath = (0, import_node_path48.join)(repositoryRoot, "package.json");
9673
9813
  const manifest = fileExists(manifestPath) ? readJson(manifestPath) : {};
9674
- const nxJsonPath = (0, import_node_path45.join)(repositoryRoot, "nx.json");
9814
+ const nxJsonPath = (0, import_node_path48.join)(repositoryRoot, "nx.json");
9675
9815
  const nxJson = fileExists(nxJsonPath) ? readJson(nxJsonPath) : {};
9676
9816
  const ci = [];
9677
9817
  const pipelines = [];
9678
- if ((0, import_node_fs38.existsSync)((0, import_node_path45.join)(repositoryRoot, "azure-pipelines.yml"))) {
9818
+ if ((0, import_node_fs39.existsSync)((0, import_node_path48.join)(repositoryRoot, "azure-pipelines.yml"))) {
9679
9819
  ci.push("azure");
9680
- pipelines.push((0, import_node_path45.join)(repositoryRoot, "azure-pipelines.yml"));
9820
+ pipelines.push((0, import_node_path48.join)(repositoryRoot, "azure-pipelines.yml"));
9681
9821
  }
9682
- const workflows = (0, import_node_path45.join)(repositoryRoot, ".github", "workflows");
9683
- if ((0, import_node_fs38.existsSync)(workflows)) {
9684
- const files = (0, import_node_fs38.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
9822
+ const workflows = (0, import_node_path48.join)(repositoryRoot, ".github", "workflows");
9823
+ if ((0, import_node_fs39.existsSync)(workflows)) {
9824
+ const files = (0, import_node_fs39.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
9685
9825
  if (files.length > 0) {
9686
9826
  ci.push("github");
9687
- pipelines.push(...files.map((file) => (0, import_node_path45.join)(workflows, file)));
9827
+ pipelines.push(...files.map((file) => (0, import_node_path48.join)(workflows, file)));
9688
9828
  }
9689
9829
  }
9690
- const rootFiles = (0, import_node_fs38.readdirSync)(repositoryRoot);
9830
+ const rootFiles = (0, import_node_fs39.readdirSync)(repositoryRoot);
9691
9831
  return {
9692
9832
  isGitRepo,
9693
9833
  dirty,
@@ -9698,13 +9838,13 @@ function inspectRepository(repositoryRoot) {
9698
9838
  tagCount: tags.length,
9699
9839
  strandedTags: isGitRepo ? locateStrandedReleaseTags(repositoryRoot, nxJson.release?.releaseTag?.pattern) : [],
9700
9840
  ci,
9701
- pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs38.readFileSync)(file, "utf8"))),
9841
+ pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs39.readFileSync)(file, "utf8"))),
9702
9842
  retiredTooling: [.../* @__PURE__ */ new Set([...rootFiles.filter((file) => RETIRED_FILE_PATTERN.test(file) || file === ".verdaccio"), ...retiredNamesIn(manifest)])],
9703
9843
  personalFiles: PERSONAL_FILES.filter((file) => rootFiles.includes(file))
9704
9844
  };
9705
9845
  }
9706
9846
 
9707
- // src/repository-adoption/judge-adoption.policy.ts
9847
+ // src/adoption-report/judge-adoption.policy.ts
9708
9848
  function judgeAdoption(facts) {
9709
9849
  const findings = [];
9710
9850
  const blocker = (detail, step) => {
@@ -9728,7 +9868,7 @@ function judgeAdoption(facts) {
9728
9868
  warning("nx.json already carries an mnci block, so this is an mnci workspace", "use `mnci upgrade`; adopt is for repositories mnci has not touched");
9729
9869
  }
9730
9870
  if (facts.nxVersion === void 0) {
9731
- warning("Nx is not installed", "set Nx up first (`npx nx@latest init`); adopt does not install it yet, and the toolchain and overlay steps need an nx.json");
9871
+ warning("Nx is not installed", "run `mnci adopt --toolchain`, which sets Nx up through nx init and nx add before it does anything else; the overlay step needs the nx.json that makes");
9732
9872
  }
9733
9873
  if (facts.strandedTags.length > 0) {
9734
9874
  warning(
@@ -9749,10 +9889,12 @@ function judgeAdoption(facts) {
9749
9889
  return { ready: ordered.every((finding) => finding.severity !== "blocker"), facts, findings: ordered };
9750
9890
  }
9751
9891
 
9752
- // src/repository-adoption/run-adopt.use-case.ts
9892
+ // src/adoption-report/report-adoption.use-case.ts
9753
9893
  function reportAdoption(repositoryRoot) {
9754
9894
  return judgeAdoption(inspectRepository(repositoryRoot));
9755
9895
  }
9896
+
9897
+ // src/repository-adoption/run-adopt.use-case.ts
9756
9898
  function runAdopt(repositoryRoot, options = {}) {
9757
9899
  const report = reportAdoption(repositoryRoot);
9758
9900
  if (options.dependencies === true) {
@@ -9833,6 +9975,9 @@ function runToolchain(repositoryRoot, options) {
9833
9975
  const result = adoptToolchain(repositoryRoot, { nxVersion: options.nx }, { log: (message) => {
9834
9976
  logger.step(message);
9835
9977
  } });
9978
+ if (result.bootstrapped.length > 0) {
9979
+ logger.info(`Nx was not set up here, so it is now: ${result.bootstrapped.join(", ")} (nx.json and the plugins; review it with \`git diff\`).`);
9980
+ }
9836
9981
  for (const line of result.removed) {
9837
9982
  logger.info(`removed ${line}`);
9838
9983
  }
@@ -9996,13 +10141,13 @@ function runCommands(program, options) {
9996
10141
  }
9997
10142
 
9998
10143
  // src/workspace-info/list-projects.use-case.ts
9999
- var import_node_path46 = require("path");
10144
+ var import_node_path49 = require("path");
10000
10145
  var TYPE_TAG_PREFIX = "type:";
10001
10146
  function listProjects(workspaceRoot) {
10002
10147
  return locateProjects(workspaceRoot).map((location) => {
10003
- const projectJsonPath = (0, import_node_path46.join)(workspaceRoot, location.dir, "project.json");
10148
+ const projectJsonPath = (0, import_node_path49.join)(workspaceRoot, location.dir, "project.json");
10004
10149
  const project = fileExists(projectJsonPath) ? readJson(projectJsonPath) : {};
10005
- const manifestPath = (0, import_node_path46.join)(workspaceRoot, location.dir, "package.json");
10150
+ const manifestPath = (0, import_node_path49.join)(workspaceRoot, location.dir, "package.json");
10006
10151
  const manifestTags = fileExists(manifestPath) ? readJson(manifestPath).nx?.tags ?? [] : [];
10007
10152
  const typeTag = [...project.tags ?? [], ...manifestTags].find((tag) => tag.startsWith(TYPE_TAG_PREFIX));
10008
10153
  return {
@@ -10015,7 +10160,7 @@ function listProjects(workspaceRoot) {
10015
10160
  }).toSorted((a, b) => a.dir.localeCompare(b.dir));
10016
10161
  }
10017
10162
  function runProjects(workspaceRoot, options) {
10018
- if (!fileExists((0, import_node_path46.join)(workspaceRoot, "nx.json"))) {
10163
+ if (!fileExists((0, import_node_path49.join)(workspaceRoot, "nx.json"))) {
10019
10164
  throw new Error("No nx.json found here. Run `projects` from the workspace root.");
10020
10165
  }
10021
10166
  const projects = listProjects(workspaceRoot);
@@ -10029,11 +10174,11 @@ function runProjects(workspaceRoot, options) {
10029
10174
  }
10030
10175
 
10031
10176
  // src/workspace-info/read-workspace-info.use-case.ts
10032
- var import_node_path48 = require("path");
10177
+ var import_node_path51 = require("path");
10033
10178
 
10034
10179
  // src/cli-version/check-for-update.use-case.ts
10035
- var import_node_fs39 = require("fs");
10036
- var import_node_path47 = require("path");
10180
+ var import_node_fs40 = require("fs");
10181
+ var import_node_path50 = require("path");
10037
10182
  var import_cross_spawn4 = __toESM(require("cross-spawn"));
10038
10183
  var PACKAGE_NAME2 = "@mnci/cli";
10039
10184
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -10092,8 +10237,8 @@ function releaseTriple(version) {
10092
10237
  }
10093
10238
  function readCliVersion(packageDirectory) {
10094
10239
  try {
10095
- const manifestPath = (0, import_node_path47.join)(packageDirectory, "..", "package.json");
10096
- const manifest = JSON.parse((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
10240
+ const manifestPath = (0, import_node_path50.join)(packageDirectory, "..", "package.json");
10241
+ const manifest = JSON.parse((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
10097
10242
  return manifest.version ?? "0.0.0";
10098
10243
  } catch {
10099
10244
  return "0.0.0";
@@ -10103,7 +10248,7 @@ function readCliVersion(packageDirectory) {
10103
10248
  // src/workspace-info/read-workspace-info.use-case.ts
10104
10249
  function readWorkspaceInfo(workspaceRoot, cliVersion) {
10105
10250
  const latest = fetchLatestVersion() ?? null;
10106
- const isWorkspace = fileExists((0, import_node_path48.join)(workspaceRoot, "nx.json"));
10251
+ const isWorkspace = fileExists((0, import_node_path51.join)(workspaceRoot, "nx.json"));
10107
10252
  return {
10108
10253
  cli: {
10109
10254
  version: cliVersion,
@@ -10124,7 +10269,7 @@ function runInfo(workspaceRoot, cliVersion, options) {
10124
10269
  }
10125
10270
 
10126
10271
  // src/interactive-wizard/interactive-wizard.use-case.ts
10127
- var import_node_path49 = require("path");
10272
+ var import_node_path52 = require("path");
10128
10273
 
10129
10274
  // src/interactive-wizard/adopt-steps.config.ts
10130
10275
  var ADOPT_GLOBAL_OPTIONS = ["json"];
@@ -10305,7 +10450,7 @@ function wizardMenu(commands, inWorkspace) {
10305
10450
  }
10306
10451
  async function runInteractive(program, prompter = createInquirerPrompter(), workingDirectory = process.cwd()) {
10307
10452
  const commands = describeCommands(program);
10308
- const inWorkspace = fileExists((0, import_node_path49.join)(workingDirectory, "nx.json"));
10453
+ const inWorkspace = fileExists((0, import_node_path52.join)(workingDirectory, "nx.json"));
10309
10454
  const name = await prompter.select("What would you like to do?", wizardMenu(commands, inWorkspace));
10310
10455
  const command = commands.find((candidate) => candidate.name === name);
10311
10456
  const argv = buildArgv(command, await askCommand(command, prompter));
@@ -10332,8 +10477,8 @@ var PRESETS = [
10332
10477
  var PRESET_IDS = PRESETS.map((preset) => preset.id);
10333
10478
 
10334
10479
  // src/workspace-presets/wire-web-api.use-case.ts
10335
- var import_node_fs40 = require("fs");
10336
- var import_node_path50 = require("path");
10480
+ var import_node_fs41 = require("fs");
10481
+ var import_node_path53 = require("path");
10337
10482
 
10338
10483
  // src/workspace-presets/web-api-wiring.algorithm.ts
10339
10484
  function apiHandler(shared) {
@@ -10505,18 +10650,18 @@ function declareDependency(manifestPath, name) {
10505
10650
  }
10506
10651
  function removeFiles(slice, files) {
10507
10652
  for (const file of files) {
10508
- (0, import_node_fs40.rmSync)((0, import_node_path50.join)(slice, file), { force: true });
10653
+ (0, import_node_fs41.rmSync)((0, import_node_path53.join)(slice, file), { force: true });
10509
10654
  }
10510
10655
  }
10511
10656
  function replaceOnce(path, anchor, replacement) {
10512
- const text = (0, import_node_fs40.readFileSync)(path, "utf8");
10657
+ const text = (0, import_node_fs41.readFileSync)(path, "utf8");
10513
10658
  if (!text.includes(anchor)) {
10514
10659
  throw new Error(`${path} has no ${anchor}; the generator's output changed, so the preset cannot wire it.`);
10515
10660
  }
10516
10661
  writeFileEnsured(path, text.replace(anchor, () => replacement));
10517
10662
  }
10518
10663
  function proxyApi(viteConfigPath) {
10519
- const text = (0, import_node_fs40.readFileSync)(viteConfigPath, "utf8");
10664
+ const text = (0, import_node_fs41.readFileSync)(viteConfigPath, "utf8");
10520
10665
  const proxied = withApiProxy(text, API_ORIGIN);
10521
10666
  if (proxied === text && !text.includes("proxy:")) {
10522
10667
  throw new Error(`${viteConfigPath} has no server block to add the /api proxy to; the generator's output changed, so the preset cannot wire it.`);
@@ -10524,30 +10669,30 @@ function proxyApi(viteConfigPath) {
10524
10669
  writeFileEnsured(viteConfigPath, proxied);
10525
10670
  }
10526
10671
  function wireWebApi(workspaceRoot, projects) {
10527
- const sharedManifest = (0, import_node_path50.join)(workspaceRoot, "libs", projects.shared, "package.json");
10672
+ const sharedManifest = (0, import_node_path53.join)(workspaceRoot, "libs", projects.shared, "package.json");
10528
10673
  if (!fileExists(sharedManifest)) {
10529
10674
  throw new Error(`The shared library was not added at libs/${projects.shared}, so there is nothing to wire the API and the frontend to.`);
10530
10675
  }
10531
10676
  const shared = readJson(sharedManifest).name;
10532
- const api = (0, import_node_path50.join)(workspaceRoot, "apps", projects.api);
10533
- declareDependency((0, import_node_path50.join)(api, "package.json"), shared);
10534
- const hello = (0, import_node_path50.join)(api, "src", "hello");
10535
- writeFileEnsured((0, import_node_path50.join)(hello, "hello.handler.ts"), apiHandler(shared));
10536
- writeFileEnsured((0, import_node_path50.join)(hello, "hello.handler.spec.ts"), apiHandlerSpec(shared));
10537
- writeFileEnsured((0, import_node_path50.join)(hello, "index.ts"), apiBarrel());
10677
+ const api = (0, import_node_path53.join)(workspaceRoot, "apps", projects.api);
10678
+ declareDependency((0, import_node_path53.join)(api, "package.json"), shared);
10679
+ const hello = (0, import_node_path53.join)(api, "src", "hello");
10680
+ writeFileEnsured((0, import_node_path53.join)(hello, "hello.handler.ts"), apiHandler(shared));
10681
+ writeFileEnsured((0, import_node_path53.join)(hello, "hello.handler.spec.ts"), apiHandlerSpec(shared));
10682
+ writeFileEnsured((0, import_node_path53.join)(hello, "index.ts"), apiBarrel());
10538
10683
  removeFiles(hello, ["greet.use-case.ts", "greet.use-case.spec.ts", "greeting.contract.ts"]);
10539
- replaceOnce((0, import_node_path50.join)(api, "src", "main.ts"), "app.get('/', helloHandler)", "app.get('/api/greeting', helloHandler)");
10540
- const web = (0, import_node_path50.join)(workspaceRoot, "apps", projects.web);
10541
- declareDependency((0, import_node_path50.join)(web, "package.json"), shared);
10542
- const greeting = (0, import_node_path50.join)(web, "src", "greeting");
10543
- writeFileEnsured((0, import_node_path50.join)(greeting, "greeting.client.ts"), webGreetingClient(shared));
10544
- writeFileEnsured((0, import_node_path50.join)(greeting, "greeting.client.spec.ts"), webGreetingClientSpec());
10545
- writeFileEnsured((0, import_node_path50.join)(greeting, "greeting.component.tsx"), webGreetingComponent(shared));
10546
- writeFileEnsured((0, import_node_path50.join)(greeting, "greeting.component.spec.tsx"), webGreetingSpec());
10547
- writeFileEnsured((0, import_node_path50.join)(greeting, "index.ts"), webGreetingBarrel());
10684
+ replaceOnce((0, import_node_path53.join)(api, "src", "main.ts"), "app.get('/', helloHandler)", "app.get('/api/greeting', helloHandler)");
10685
+ const web = (0, import_node_path53.join)(workspaceRoot, "apps", projects.web);
10686
+ declareDependency((0, import_node_path53.join)(web, "package.json"), shared);
10687
+ const greeting = (0, import_node_path53.join)(web, "src", "greeting");
10688
+ writeFileEnsured((0, import_node_path53.join)(greeting, "greeting.client.ts"), webGreetingClient(shared));
10689
+ writeFileEnsured((0, import_node_path53.join)(greeting, "greeting.client.spec.ts"), webGreetingClientSpec());
10690
+ writeFileEnsured((0, import_node_path53.join)(greeting, "greeting.component.tsx"), webGreetingComponent(shared));
10691
+ writeFileEnsured((0, import_node_path53.join)(greeting, "greeting.component.spec.tsx"), webGreetingSpec());
10692
+ writeFileEnsured((0, import_node_path53.join)(greeting, "index.ts"), webGreetingBarrel());
10548
10693
  removeFiles(greeting, ["greet.use-case.ts", "greet.use-case.spec.ts", "greeting.contract.ts"]);
10549
- writeFileEnsured((0, import_node_path50.join)(web, "src", "app", "app.component.spec.tsx"), webAppSpec());
10550
- proxyApi((0, import_node_path50.join)(web, "vite.config.mts"));
10694
+ writeFileEnsured((0, import_node_path53.join)(web, "src", "app", "app.component.spec.tsx"), webAppSpec());
10695
+ proxyApi((0, import_node_path53.join)(web, "vite.config.mts"));
10551
10696
  }
10552
10697
 
10553
10698
  // src/workspace-presets/apply-preset.use-case.ts
@@ -10590,8 +10735,8 @@ async function applyPreset(workspaceRoot, presetId, dependencies = {}) {
10590
10735
  }
10591
10736
 
10592
10737
  // src/workspace-creation/adopt-directory.use-case.ts
10593
- var import_node_fs41 = require("fs");
10594
- var import_node_path51 = require("path");
10738
+ var import_node_fs42 = require("fs");
10739
+ var import_node_path54 = require("path");
10595
10740
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
10596
10741
  var AGENT_AND_CI_ENTRIES = [
10597
10742
  "AGENTS.md",
@@ -10622,13 +10767,13 @@ var PREFLIGHT_BLOCKERS = [
10622
10767
  "packages"
10623
10768
  ];
10624
10769
  function assertAdoptableDirectory(target) {
10625
- if (!(0, import_node_fs41.existsSync)(target)) {
10770
+ if (!(0, import_node_fs42.existsSync)(target)) {
10626
10771
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
10627
10772
  }
10628
- if (!(0, import_node_fs41.statSync)(target).isDirectory()) {
10773
+ if (!(0, import_node_fs42.statSync)(target).isDirectory()) {
10629
10774
  throw new Error(`--into '${target}' is not a directory.`);
10630
10775
  }
10631
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs41.existsSync)((0, import_node_path51.join)(target, entry)));
10776
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs42.existsSync)((0, import_node_path54.join)(target, entry)));
10632
10777
  if (blockers.length > 0) {
10633
10778
  throw new Error(
10634
10779
  `--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.`
@@ -10636,15 +10781,15 @@ function assertAdoptableDirectory(target) {
10636
10781
  }
10637
10782
  }
10638
10783
  function mergeGitignore(generatedFile, targetFile) {
10639
- const existing = (0, import_node_fs41.readFileSync)(targetFile, "utf8");
10784
+ const existing = (0, import_node_fs42.readFileSync)(targetFile, "utf8");
10640
10785
  const present = new Set(existing.split("\n").map((line) => line.trim()));
10641
- const additions = (0, import_node_fs41.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
10786
+ const additions = (0, import_node_fs42.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
10642
10787
  const trimmed = line.trim();
10643
10788
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
10644
10789
  });
10645
10790
  if (additions.length === 0) return false;
10646
10791
  const separator = existing.endsWith("\n") ? "" : "\n";
10647
- (0, import_node_fs41.writeFileSync)(
10792
+ (0, import_node_fs42.writeFileSync)(
10648
10793
  targetFile,
10649
10794
  `${existing}${separator}
10650
10795
  # Added by mnci (Nx workspace)
@@ -10654,9 +10799,9 @@ ${additions.join("\n")}
10654
10799
  return true;
10655
10800
  }
10656
10801
  function adoptGeneratedWorkspace(generatedRoot, target) {
10657
- const entries = (0, import_node_fs41.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
10802
+ const entries = (0, import_node_fs42.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
10658
10803
  const collisions = entries.filter(
10659
- (entry) => (0, import_node_fs41.existsSync)((0, import_node_path51.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
10804
+ (entry) => (0, import_node_fs42.existsSync)((0, import_node_path54.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
10660
10805
  );
10661
10806
  if (collisions.length > 0) {
10662
10807
  throw new Error(
@@ -10665,28 +10810,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
10665
10810
  }
10666
10811
  const result = { copied: [], kept: [], mergedGitignore: false };
10667
10812
  for (const entry of entries) {
10668
- const from = (0, import_node_path51.join)(generatedRoot, entry);
10669
- const to = (0, import_node_path51.join)(target, entry);
10670
- if (entry === ".gitignore" && (0, import_node_fs41.existsSync)(to)) {
10813
+ const from = (0, import_node_path54.join)(generatedRoot, entry);
10814
+ const to = (0, import_node_path54.join)(target, entry);
10815
+ if (entry === ".gitignore" && (0, import_node_fs42.existsSync)(to)) {
10671
10816
  result.mergedGitignore = mergeGitignore(from, to);
10672
10817
  result.kept.push(entry);
10673
10818
  continue;
10674
10819
  }
10675
- if ((0, import_node_fs41.existsSync)(to)) {
10820
+ if ((0, import_node_fs42.existsSync)(to)) {
10676
10821
  result.kept.push(entry);
10677
10822
  continue;
10678
10823
  }
10679
- (0, import_node_fs41.cpSync)(from, to, { recursive: true });
10824
+ (0, import_node_fs42.cpSync)(from, to, { recursive: true });
10680
10825
  result.copied.push(entry);
10681
10826
  }
10682
- (0, import_node_fs41.rmSync)(generatedRoot, { recursive: true, force: true });
10827
+ (0, import_node_fs42.rmSync)(generatedRoot, { recursive: true, force: true });
10683
10828
  return result;
10684
10829
  }
10685
10830
 
10686
10831
  // src/workspace-creation/create-workspace.use-case.ts
10687
- var import_node_fs42 = require("fs");
10832
+ var import_node_fs43 = require("fs");
10688
10833
  var import_node_os2 = require("os");
10689
- var import_node_path52 = require("path");
10834
+ var import_node_path55 = require("path");
10690
10835
  function nxCloudProviderValue(ci) {
10691
10836
  return ci === "azure" ? "azure" : "github";
10692
10837
  }
@@ -10729,10 +10874,10 @@ async function resolveRegistry2(options) {
10729
10874
  return await promptRegistry();
10730
10875
  }
10731
10876
  async function runNew(name, options) {
10732
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path52.resolve)(process.cwd(), options.into);
10877
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path55.resolve)(process.cwd(), options.into);
10733
10878
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
10734
10879
  if (options.preset !== void 0) findPreset(options.preset);
10735
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path52.basename)(adoptTarget));
10880
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path55.basename)(adoptTarget));
10736
10881
  assertValidProjectName(workspaceName, "Workspace name");
10737
10882
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
10738
10883
  const registry = await resolveRegistry2(options);
@@ -10745,8 +10890,8 @@ async function runNew(name, options) {
10745
10890
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
10746
10891
  const stack = await resolveStack(options);
10747
10892
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
10748
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs42.mkdtempSync)((0, import_node_path52.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
10749
- let workspaceRoot = (0, import_node_path52.join)(stagingParent, workspaceName);
10893
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs43.mkdtempSync)((0, import_node_path55.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
10894
+ let workspaceRoot = (0, import_node_path55.join)(stagingParent, workspaceName);
10750
10895
  try {
10751
10896
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
10752
10897
  runNpx(
@@ -10769,7 +10914,7 @@ async function runNew(name, options) {
10769
10914
  workspaceRoot = adoptTarget;
10770
10915
  }
10771
10916
  } finally {
10772
- if (adoptTarget !== void 0) (0, import_node_fs42.rmSync)(stagingParent, { recursive: true, force: true });
10917
+ if (adoptTarget !== void 0) (0, import_node_fs43.rmSync)(stagingParent, { recursive: true, force: true });
10773
10918
  }
10774
10919
  logger.step(
10775
10920
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -10779,8 +10924,8 @@ async function runNew(name, options) {
10779
10924
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
10780
10925
  logger.detail
10781
10926
  );
10782
- (0, import_node_fs42.rmSync)((0, import_node_path52.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
10783
- (0, import_node_fs42.rmSync)((0, import_node_path52.join)(workspaceRoot, "package-lock.json"), { force: true });
10927
+ (0, import_node_fs43.rmSync)((0, import_node_path55.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
10928
+ (0, import_node_fs43.rmSync)((0, import_node_path55.join)(workspaceRoot, "package-lock.json"), { force: true });
10784
10929
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
10785
10930
  const installStatus = runShell(
10786
10931
  "npm",