@mnci/cli 4.15.0 → 4.17.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
@@ -37,9 +37,9 @@ __export(main_exports, {
37
37
  module.exports = __toCommonJS(main_exports);
38
38
  var import_commander = require("commander");
39
39
 
40
- // src/project-scaffolding/add-project.use-case.ts
41
- var import_node_path20 = require("path");
42
- var import_prompts3 = require("@inquirer/prompts");
40
+ // src/ci-pipeline/pack.use-case.ts
41
+ var import_node_fs = require("fs");
42
+ var import_node_path = require("path");
43
43
 
44
44
  // src/nx-workspace/nx.client.ts
45
45
  var import_cross_spawn = __toESM(require("cross-spawn"));
@@ -200,11 +200,95 @@ function runFormatter(cwd, target = ".") {
200
200
  }
201
201
  }
202
202
 
203
+ // src/ci-pipeline/ci-environment.client.ts
204
+ function detectCiHost(environment) {
205
+ if (environment.GITHUB_ACTIONS === "true") {
206
+ return "github";
207
+ }
208
+ if (environment.TF_BUILD !== void 0 && environment.TF_BUILD !== "") {
209
+ return "azure";
210
+ }
211
+ return "local";
212
+ }
213
+ function pullRequestTarget(environment) {
214
+ const reference = environment.GITHUB_BASE_REF || environment.SYSTEM_PULLREQUEST_TARGETBRANCH || "";
215
+ return reference === "" ? void 0 : reference.replace("refs/heads/", "");
216
+ }
217
+ function groupStart(host, title) {
218
+ switch (host) {
219
+ case "github": {
220
+ return `::group::${title}`;
221
+ }
222
+ case "azure": {
223
+ return `##[group]${title}`;
224
+ }
225
+ case "local": {
226
+ return `
227
+ \u25B8 ${title}`;
228
+ }
229
+ }
230
+ }
231
+ function groupEnd(host) {
232
+ switch (host) {
233
+ case "github": {
234
+ return "::endgroup::";
235
+ }
236
+ case "azure": {
237
+ return "##[endgroup]";
238
+ }
239
+ case "local": {
240
+ return void 0;
241
+ }
242
+ }
243
+ }
244
+
245
+ // src/ci-pipeline/pack.use-case.ts
246
+ function hasAppToPack(workspaceRoot) {
247
+ const hasProjectJson = (0, import_node_fs.globSync)("apps/*/project.json", { cwd: workspaceRoot }).length > 0;
248
+ const hasInlineNx = (0, import_node_fs.globSync)("apps/*/package.json", { cwd: workspaceRoot }).some((manifest) => {
249
+ try {
250
+ const parsed = JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path.join)(workspaceRoot, manifest), "utf8"));
251
+ return Boolean(parsed.nx);
252
+ } catch {
253
+ return false;
254
+ }
255
+ });
256
+ const hasCsproj = (0, import_node_fs.globSync)("apps/*/*.csproj", { cwd: workspaceRoot }).length > 0;
257
+ return hasProjectJson || hasInlineNx || hasCsproj;
258
+ }
259
+ function runPack(workspaceRoot, dependencies = {}) {
260
+ const environment = dependencies.environment ?? process.env;
261
+ const processes = dependencies.processes ?? {
262
+ run: (command, arguments_) => runShell(command, arguments_, workspaceRoot),
263
+ capture: () => ({ status: 1, stdout: "" })
264
+ };
265
+ const log = dependencies.log ?? ((message) => {
266
+ console.log(message);
267
+ });
268
+ const host = detectCiHost(environment);
269
+ (0, import_node_fs.mkdirSync)((0, import_node_path.join)(workspaceRoot, "dist", "drop"), { recursive: true });
270
+ if (!hasAppToPack(workspaceRoot)) {
271
+ log("No apps to pack - skipping.");
272
+ return 0;
273
+ }
274
+ log(groupStart(host, "Pack all apps"));
275
+ const status = processes.run("npx", ["nx", "run-many", "-t", "package"]);
276
+ const closing = groupEnd(host);
277
+ if (closing !== void 0) {
278
+ log(closing);
279
+ }
280
+ return status;
281
+ }
282
+
283
+ // src/workspace-overlay/overlay.use-case.ts
284
+ var import_node_fs3 = require("fs");
285
+ var import_node_path3 = require("path");
286
+
203
287
  // src/file-system/file-system.client.ts
204
- var import_node_fs = require("fs");
205
- var import_node_path = require("path");
288
+ var import_node_fs2 = require("fs");
289
+ var import_node_path2 = require("path");
206
290
  function readJson(path) {
207
- return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
291
+ return JSON.parse((0, import_node_fs2.readFileSync)(path, "utf8"));
208
292
  }
209
293
  function stripJsonComments(text) {
210
294
  let result = "";
@@ -261,7 +345,7 @@ function stripJsonComments(text) {
261
345
  }
262
346
  function readCodeWorkspace(path) {
263
347
  try {
264
- const withoutComments = stripJsonComments((0, import_node_fs.readFileSync)(path, "utf8"));
348
+ const withoutComments = stripJsonComments((0, import_node_fs2.readFileSync)(path, "utf8"));
265
349
  return JSON.parse(withoutComments.replaceAll(/,(\s*[}\]])/g, "$1"));
266
350
  } catch {
267
351
  return void 0;
@@ -272,32 +356,17 @@ function toJson(value) {
272
356
  `;
273
357
  }
274
358
  function writeFileEnsured(path, content) {
275
- (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(path), { recursive: true });
276
- (0, import_node_fs.writeFileSync)(path, content);
359
+ (0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(path), { recursive: true });
360
+ (0, import_node_fs2.writeFileSync)(path, content);
277
361
  }
278
362
  function markExecutable(path) {
279
- (0, import_node_fs.chmodSync)(path, 493);
363
+ (0, import_node_fs2.chmodSync)(path, 493);
280
364
  }
281
365
  function fileExists(path) {
282
- return (0, import_node_fs.existsSync)(path);
366
+ return (0, import_node_fs2.existsSync)(path);
283
367
  }
284
368
 
285
- // src/project-name/project-name.validator.ts
286
- function assertValidProjectName(name, label) {
287
- if (!/^[a-z][a-z0-9-]*(?:\.[a-z0-9-]+)*$/.test(name)) {
288
- throw new Error(
289
- `${label} '${name}' is invalid \u2014 use lowercase letters, digits, hyphens and dots, starting with a letter, with no leading, trailing or repeated dot (e.g. 'my-project', 'my.service').`
290
- );
291
- }
292
- }
293
-
294
- // src/project-scaffolding/csharp.use-case.ts
295
- var import_node_fs4 = require("fs");
296
- var import_node_path4 = require("path");
297
-
298
369
  // src/workspace-overlay/overlay.use-case.ts
299
- var import_node_fs2 = require("fs");
300
- var import_node_path2 = require("path");
301
370
  var DEFAULT_STACK = { testRunner: "jest" };
302
371
  var TS_COMPILER_DEPENDENCIES = {
303
372
  "@typescript/native": "npm:typescript@^7.0.2",
@@ -437,9 +506,9 @@ var VSCODE_EXTENSION_TAG = "type:vscode-extension";
437
506
  var GO_RELEASE_TAG = "release:go";
438
507
  var GO_CGO_TAG = "build:cgo";
439
508
  function hasNativeGoApp(workspaceRoot) {
440
- return (0, import_node_fs2.globSync)("apps/*/project.json", { cwd: workspaceRoot }).some((projectJson) => {
509
+ return (0, import_node_fs3.globSync)("apps/*/project.json", { cwd: workspaceRoot }).some((projectJson) => {
441
510
  try {
442
- const { tags } = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(workspaceRoot, projectJson), "utf8"));
511
+ const { tags } = JSON.parse((0, import_node_fs3.readFileSync)((0, import_node_path3.join)(workspaceRoot, projectJson), "utf8"));
443
512
  return (tags ?? []).includes(GO_CGO_TAG);
444
513
  } catch {
445
514
  return false;
@@ -780,8 +849,8 @@ function isUnmodifiedMnciEslintConfig(content) {
780
849
  return code.length === 2 && code[0] === "import mnci from '@mnci/eslint-config'" && code[1] === "export default mnci({ workspaceRoot: import.meta.dirname })";
781
850
  }
782
851
  function writeEslintEntryPoint(workspaceRoot, onProgress) {
783
- const path = (0, import_node_path2.join)(workspaceRoot, ESLINT_USER_FILENAME);
784
- if ((0, import_node_fs2.existsSync)(path) && !isUnmodifiedMnciEslintConfig((0, import_node_fs2.readFileSync)(path, "utf8"))) {
852
+ const path = (0, import_node_path3.join)(workspaceRoot, ESLINT_USER_FILENAME);
853
+ if ((0, import_node_fs3.existsSync)(path) && !isUnmodifiedMnciEslintConfig((0, import_node_fs3.readFileSync)(path, "utf8"))) {
785
854
  onProgress(`${ESLINT_USER_FILENAME} \u2014 kept as it is, it is yours`);
786
855
  return;
787
856
  }
@@ -949,7 +1018,7 @@ function mnciConfig(options) {
949
1018
  };
950
1019
  }
951
1020
  function readMnciConfig(workspaceRoot) {
952
- const nxJson = readJson((0, import_node_path2.join)(workspaceRoot, "nx.json"));
1021
+ const nxJson = readJson((0, import_node_path3.join)(workspaceRoot, "nx.json"));
953
1022
  return nxJson.mnci ?? {};
954
1023
  }
955
1024
  function pythonPublishUrl(registry) {
@@ -1876,12 +1945,12 @@ var ECOSYSTEM_MANIFESTS = {
1876
1945
  };
1877
1946
  function hasEcosystemProject(workspaceRoot, roots, manifests) {
1878
1947
  return roots.some((root) => {
1879
- const base = (0, import_node_path2.join)(workspaceRoot, root);
1880
- if (!(0, import_node_fs2.existsSync)(base)) {
1948
+ const base = (0, import_node_path3.join)(workspaceRoot, root);
1949
+ if (!(0, import_node_fs3.existsSync)(base)) {
1881
1950
  return false;
1882
1951
  }
1883
- return (0, import_node_fs2.readdirSync)(base, { withFileTypes: true }).some(
1884
- (entry) => entry.isDirectory() && manifests.some((manifest) => (0, import_node_fs2.existsSync)((0, import_node_path2.join)(base, entry.name, manifest)))
1952
+ return (0, import_node_fs3.readdirSync)(base, { withFileTypes: true }).some(
1953
+ (entry) => entry.isDirectory() && manifests.some((manifest) => (0, import_node_fs3.existsSync)((0, import_node_path3.join)(base, entry.name, manifest)))
1885
1954
  );
1886
1955
  });
1887
1956
  }
@@ -1959,11 +2028,11 @@ var LOCAL_REGISTRY_SCAFFOLDING = {
1959
2028
  rootTarget: "local-registry"
1960
2029
  };
1961
2030
  function removeLocalRegistryScaffolding(workspaceRoot) {
1962
- (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, LOCAL_REGISTRY_SCAFFOLDING.directory), {
2031
+ (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, LOCAL_REGISTRY_SCAFFOLDING.directory), {
1963
2032
  recursive: true,
1964
2033
  force: true
1965
2034
  });
1966
- const manifestPath = (0, import_node_path2.join)(workspaceRoot, "package.json");
2035
+ const manifestPath = (0, import_node_path3.join)(workspaceRoot, "package.json");
1967
2036
  if (!fileExists(manifestPath)) return;
1968
2037
  const manifest = readJson(manifestPath);
1969
2038
  if (manifest.devDependencies?.[LOCAL_REGISTRY_SCAFFOLDING.devDependency] !== void 0) {
@@ -1979,23 +2048,23 @@ function removeLocalRegistryScaffolding(workspaceRoot) {
1979
2048
  }
1980
2049
  function removeNxScaffolding(workspaceRoot) {
1981
2050
  for (const entry of NX_SCAFFOLDING_TO_REMOVE) {
1982
- (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, entry), { recursive: true, force: true });
2051
+ (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, entry), { recursive: true, force: true });
1983
2052
  }
1984
2053
  removeNxAuthoredAgentFiles(workspaceRoot);
1985
2054
  removeProjectEslintConfigs(workspaceRoot);
1986
2055
  }
1987
2056
  function removeNxAuthoredAgentFiles(workspaceRoot) {
1988
- (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, NX_CLAUDE_SETTINGS), { force: true });
1989
- const claudeDirectory = (0, import_node_path2.join)(workspaceRoot, (0, import_node_path2.dirname)(NX_CLAUDE_SETTINGS));
1990
- if ((0, import_node_fs2.existsSync)(claudeDirectory) && (0, import_node_fs2.readdirSync)(claudeDirectory).length === 0) {
1991
- (0, import_node_fs2.rmSync)(claudeDirectory, { recursive: true, force: true });
2057
+ (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, NX_CLAUDE_SETTINGS), { force: true });
2058
+ const claudeDirectory = (0, import_node_path3.join)(workspaceRoot, (0, import_node_path3.dirname)(NX_CLAUDE_SETTINGS));
2059
+ if ((0, import_node_fs3.existsSync)(claudeDirectory) && (0, import_node_fs3.readdirSync)(claudeDirectory).length === 0) {
2060
+ (0, import_node_fs3.rmSync)(claudeDirectory, { recursive: true, force: true });
1992
2061
  }
1993
2062
  for (const name of NX_AUTHORED_AGENT_FILES) {
1994
- const path = (0, import_node_path2.join)(workspaceRoot, name);
1995
- if (!(0, import_node_fs2.existsSync)(path)) continue;
1996
- const kept = withoutNxAgentRules((0, import_node_fs2.readFileSync)(path, "utf8"));
2063
+ const path = (0, import_node_path3.join)(workspaceRoot, name);
2064
+ if (!(0, import_node_fs3.existsSync)(path)) continue;
2065
+ const kept = withoutNxAgentRules((0, import_node_fs3.readFileSync)(path, "utf8"));
1997
2066
  if (kept === void 0) continue;
1998
- if (kept.trim() === "") (0, import_node_fs2.rmSync)(path, { force: true });
2067
+ if (kept.trim() === "") (0, import_node_fs3.rmSync)(path, { force: true });
1999
2068
  else writeFileEnsured(path, kept);
2000
2069
  }
2001
2070
  }
@@ -2010,14 +2079,14 @@ function withoutNxAgentRules(content) {
2010
2079
  return `${content.slice(0, start)}${rest}`.replace(/^[\r\n]+/, "");
2011
2080
  }
2012
2081
  function removeIfPresent(path) {
2013
- (0, import_node_fs2.rmSync)(path, { recursive: true, force: true });
2082
+ (0, import_node_fs3.rmSync)(path, { recursive: true, force: true });
2014
2083
  }
2015
2084
  function ensureEslintCacheIgnored(workspaceRoot) {
2016
- const gitignorePath = (0, import_node_path2.join)(workspaceRoot, ".gitignore");
2085
+ const gitignorePath = (0, import_node_path3.join)(workspaceRoot, ".gitignore");
2017
2086
  if (!fileExists(gitignorePath)) {
2018
2087
  return;
2019
2088
  }
2020
- const current = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
2089
+ const current = (0, import_node_fs3.readFileSync)(gitignorePath, "utf8");
2021
2090
  if (current.split("\n").some((line) => line.trim() === ".eslintcache")) {
2022
2091
  return;
2023
2092
  }
@@ -2032,18 +2101,18 @@ function ensureEslintCacheIgnored(workspaceRoot) {
2032
2101
  }
2033
2102
  var PYTHON_ARTEFACT_IGNORES = ["__pycache__/", "*.py[cod]"];
2034
2103
  function ensurePythonArtefactsIgnored(workspaceRoot) {
2035
- const gitignorePath = (0, import_node_path2.join)(workspaceRoot, ".gitignore");
2104
+ const gitignorePath = (0, import_node_path3.join)(workspaceRoot, ".gitignore");
2036
2105
  if (!fileExists(gitignorePath)) {
2037
2106
  return;
2038
2107
  }
2039
- const hasPython = (0, import_node_fs2.globSync)(
2108
+ const hasPython = (0, import_node_fs3.globSync)(
2040
2109
  ["python-packages/*/pyproject.toml", "apps/*/pyproject.toml", "libs/*/pyproject.toml"],
2041
2110
  { cwd: workspaceRoot }
2042
2111
  ).length > 0;
2043
2112
  if (!hasPython) {
2044
2113
  return;
2045
2114
  }
2046
- const current = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
2115
+ const current = (0, import_node_fs3.readFileSync)(gitignorePath, "utf8");
2047
2116
  const present = new Set(current.split("\n").map((line) => line.trim()));
2048
2117
  const missing = PYTHON_ARTEFACT_IGNORES.filter((line) => !present.has(line));
2049
2118
  if (missing.length === 0) {
@@ -2063,16 +2132,16 @@ ${missing.join("\n")}
2063
2132
  );
2064
2133
  }
2065
2134
  function removeProjectEslintConfigs(workspaceRoot) {
2066
- const matches = (0, import_node_fs2.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
2135
+ const matches = (0, import_node_fs3.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
2067
2136
  cwd: workspaceRoot
2068
2137
  });
2069
2138
  for (const match of matches) {
2070
- (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, match), { force: true });
2139
+ (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, match), { force: true });
2071
2140
  }
2072
2141
  }
2073
2142
  function applyOverlay(workspaceRoot, options, onProgress = () => {
2074
2143
  }) {
2075
- const nxJsonPath = (0, import_node_path2.join)(workspaceRoot, "nx.json");
2144
+ const nxJsonPath = (0, import_node_path3.join)(workspaceRoot, "nx.json");
2076
2145
  const nxJson = readJson(nxJsonPath);
2077
2146
  const generators = {
2078
2147
  ...nxJson.generators,
@@ -2080,7 +2149,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2080
2149
  };
2081
2150
  const sync = { ...nxJson.sync, ...SYNC_CONFIG };
2082
2151
  const mnci = { ...nxJson.mnci, ...mnciConfig(options) };
2083
- const rootManifest = readJson((0, import_node_path2.join)(workspaceRoot, "package.json"));
2152
+ const rootManifest = readJson((0, import_node_path3.join)(workspaceRoot, "package.json"));
2084
2153
  const hasPythonPlugin = (rootManifest.devDependencies ?? {})["@mnci/nx-python-pip"] !== void 0 || (rootManifest.dependencies ?? {})["@mnci/nx-python-pip"] !== void 0;
2085
2154
  const withRelease = withReleaseConfig(nxJson, options.ci);
2086
2155
  const patched = withPythonGraphPlugin(
@@ -2090,7 +2159,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2090
2159
  onProgress("nx.json \u2014 release, sync, generators, shared inputs, mnci block");
2091
2160
  writeFileEnsured(nxJsonPath, toJson({ ...patched, generators, sync, mnci }));
2092
2161
  onProgress("package.json \u2014 root scripts, TS compilers, ESLint toolchain, overrides");
2093
- const manifestPath = (0, import_node_path2.join)(workspaceRoot, "package.json");
2162
+ const manifestPath = (0, import_node_path3.join)(workspaceRoot, "package.json");
2094
2163
  const manifest = readJson(manifestPath);
2095
2164
  const scripts = {
2096
2165
  ...manifest.scripts,
@@ -2142,32 +2211,32 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2142
2211
  `.npmrc \u2014 ${options.registry.kind === "azure-artifacts" ? "Azure Artifacts feed routing and credentials" : "public npm registry auth"}`
2143
2212
  );
2144
2213
  writeFileEnsured(
2145
- (0, import_node_path2.join)(workspaceRoot, ".npmrc"),
2214
+ (0, import_node_path3.join)(workspaceRoot, ".npmrc"),
2146
2215
  npmrcContent(options.registry, options.scope, options.npmAuth)
2147
2216
  );
2148
2217
  onProgress("commitlint.config.mjs and .husky/commit-msg \u2014 conventional commit enforcement");
2149
- writeFileEnsured((0, import_node_path2.join)(workspaceRoot, "commitlint.config.mjs"), COMMITLINT_CONFIG);
2150
- const hookPath = (0, import_node_path2.join)(workspaceRoot, ".husky/commit-msg");
2218
+ writeFileEnsured((0, import_node_path3.join)(workspaceRoot, "commitlint.config.mjs"), COMMITLINT_CONFIG);
2219
+ const hookPath = (0, import_node_path3.join)(workspaceRoot, ".husky/commit-msg");
2151
2220
  writeFileEnsured(hookPath, COMMIT_MSG_HOOK);
2152
2221
  markExecutable(hookPath);
2153
2222
  onProgress(`${ESLINT_MNCI_FILENAME} \u2014 the shared lint AND formatting opinion`);
2154
- writeFileEnsured((0, import_node_path2.join)(workspaceRoot, ESLINT_MNCI_FILENAME), ESLINT_MNCI_CONFIG);
2223
+ writeFileEnsured((0, import_node_path3.join)(workspaceRoot, ESLINT_MNCI_FILENAME), ESLINT_MNCI_CONFIG);
2155
2224
  writeEslintEntryPoint(workspaceRoot, onProgress);
2156
2225
  ensureEslintCacheIgnored(workspaceRoot);
2157
2226
  ensurePythonArtefactsIgnored(workspaceRoot);
2158
2227
  for (const retired of RETIRED_FORMATTER_FILES) {
2159
- removeIfPresent((0, import_node_path2.join)(workspaceRoot, retired));
2228
+ removeIfPresent((0, import_node_path3.join)(workspaceRoot, retired));
2160
2229
  }
2161
2230
  onProgress(".devcontainer/devcontainer.json \u2014 a local toolchain matching CI");
2162
2231
  writeFileEnsured(
2163
- (0, import_node_path2.join)(workspaceRoot, ".devcontainer/devcontainer.json"),
2232
+ (0, import_node_path3.join)(workspaceRoot, ".devcontainer/devcontainer.json"),
2164
2233
  devcontainerJson(options.workspaceName)
2165
2234
  );
2166
2235
  removeNxScaffolding(workspaceRoot);
2167
2236
  onProgress(
2168
2237
  `${options.workspaceName}.code-workspace \u2014 settings, extensions, launch configs`
2169
2238
  );
2170
- const codeWorkspacePath = (0, import_node_path2.join)(workspaceRoot, `${options.workspaceName}.code-workspace`);
2239
+ const codeWorkspacePath = (0, import_node_path3.join)(workspaceRoot, `${options.workspaceName}.code-workspace`);
2171
2240
  const existing = readCodeWorkspace(codeWorkspacePath);
2172
2241
  writeFileEnsured(
2173
2242
  codeWorkspacePath,
@@ -2179,7 +2248,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2179
2248
  )
2180
2249
  );
2181
2250
  if (options.workspaceName !== "undefined") {
2182
- (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, "undefined.code-workspace"), { force: true });
2251
+ (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, "undefined.code-workspace"), { force: true });
2183
2252
  }
2184
2253
  const publishUrl = pythonPublishUrl(options.registry);
2185
2254
  const nugetUrl = nugetFeedUrl(options.registry);
@@ -2187,7 +2256,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2187
2256
  if (options.ci === "azure" || options.ci === "both") {
2188
2257
  onProgress("azure-pipelines.yml \u2014 build, verify, pack and release");
2189
2258
  writeFileEnsured(
2190
- (0, import_node_path2.join)(workspaceRoot, "azure-pipelines.yml"),
2259
+ (0, import_node_path3.join)(workspaceRoot, "azure-pipelines.yml"),
2191
2260
  azurePipelinesYaml(
2192
2261
  options.agent,
2193
2262
  options.variableGroup,
@@ -2202,18 +2271,98 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2202
2271
  if (options.ci === "github" || options.ci === "both") {
2203
2272
  onProgress(".github/workflows/ci.yml and dependabot.yml");
2204
2273
  writeFileEnsured(
2205
- (0, import_node_path2.join)(workspaceRoot, ".github/workflows/ci.yml"),
2274
+ (0, import_node_path3.join)(workspaceRoot, ".github/workflows/ci.yml"),
2206
2275
  githubActionsYaml(options.agent, publishUrl, options.registry.kind, options.ci, nugetUrl, nativeApps)
2207
2276
  );
2208
- writeFileEnsured((0, import_node_path2.join)(workspaceRoot, ".github/dependabot.yml"), dependabotConfig(workspaceRoot));
2277
+ writeFileEnsured((0, import_node_path3.join)(workspaceRoot, ".github/dependabot.yml"), dependabotConfig(workspaceRoot));
2278
+ }
2279
+ }
2280
+
2281
+ // src/ci-pipeline/verify.use-case.ts
2282
+ function runVerify(workspaceRoot, dependencies = {}) {
2283
+ const environment = dependencies.environment ?? process.env;
2284
+ const processes = dependencies.processes ?? {
2285
+ run: (command, arguments_) => runShell(command, arguments_, workspaceRoot),
2286
+ capture: (command, arguments_) => runCapture(command, arguments_, workspaceRoot)
2287
+ };
2288
+ const log = dependencies.log ?? ((message) => {
2289
+ console.log(message);
2290
+ });
2291
+ const host = detectCiHost(environment);
2292
+ const inGroup = (title, command, arguments_) => {
2293
+ log(groupStart(host, title));
2294
+ const status = processes.run(command, arguments_);
2295
+ const closing = groupEnd(host);
2296
+ if (closing !== void 0) {
2297
+ log(closing);
2298
+ }
2299
+ return status;
2300
+ };
2301
+ const synced = inGroup("Verify the workspace is synced", "npx", ["nx", "sync:check"]);
2302
+ if (synced !== 0) {
2303
+ log("The workspace is not synced: run 'npx nx sync' locally and commit the result.");
2304
+ return synced;
2305
+ }
2306
+ const exclude = hasNativeGoApp(workspaceRoot) ? [`--exclude=tag:${GO_CGO_TAG}`] : [];
2307
+ const everything = () => inGroup("Verify every project", "npx", ["nx", "run-many", "-t", VERIFY_TARGETS, ...exclude]);
2308
+ const target = pullRequestTarget(environment);
2309
+ if (target === void 0) {
2310
+ log("Not a pull request - verifying EVERY project.");
2311
+ return everything();
2312
+ }
2313
+ const mergeBase = (reference) => {
2314
+ const result = processes.capture("git", ["merge-base", reference, "HEAD"]);
2315
+ return result.status === 0 ? result.stdout.trim() : "";
2316
+ };
2317
+ let base = mergeBase(`origin/${target}`);
2318
+ if (base === "") {
2319
+ log(`No origin/${target} ref - fetching it to resolve a merge-base.`);
2320
+ processes.run("git", ["fetch", "--no-tags", "origin", target]);
2321
+ base = mergeBase("FETCH_HEAD");
2322
+ }
2323
+ if (base === "") {
2324
+ log(`Could not resolve a merge-base with ${target} - verifying EVERY project.`);
2325
+ return everything();
2326
+ }
2327
+ log(`Pull request against ${target} - verifying projects affected since ${base}`);
2328
+ return inGroup("Verify the affected projects", "npx", ["nx", "affected", "-t", VERIFY_TARGETS, `--base=${base}`, ...exclude]);
2329
+ }
2330
+
2331
+ // src/ci-pipeline/index.ts
2332
+ var CI_PHASES = ["verify", "pack"];
2333
+ function runCiPhase(phase, workspaceRoot, dependencies = {}) {
2334
+ switch (phase) {
2335
+ case "verify": {
2336
+ return runVerify(workspaceRoot, dependencies);
2337
+ }
2338
+ case "pack": {
2339
+ return runPack(workspaceRoot, dependencies);
2340
+ }
2341
+ }
2342
+ }
2343
+
2344
+ // src/project-scaffolding/add-project.use-case.ts
2345
+ var import_node_path23 = require("path");
2346
+ var import_prompts3 = require("@inquirer/prompts");
2347
+
2348
+ // src/project-name/project-name.validator.ts
2349
+ function assertValidProjectName(name, label) {
2350
+ if (!/^[a-z][a-z0-9-]*(?:\.[a-z0-9-]+)*$/.test(name)) {
2351
+ throw new Error(
2352
+ `${label} '${name}' is invalid \u2014 use lowercase letters, digits, hyphens and dots, starting with a letter, with no leading, trailing or repeated dot (e.g. 'my-project', 'my.service').`
2353
+ );
2209
2354
  }
2210
2355
  }
2211
2356
 
2357
+ // src/project-scaffolding/csharp.use-case.ts
2358
+ var import_node_fs5 = require("fs");
2359
+ var import_node_path5 = require("path");
2360
+
2212
2361
  // src/project-scaffolding/post-generation.use-case.ts
2213
- var import_node_fs3 = require("fs");
2214
- var import_node_path3 = require("path");
2362
+ var import_node_fs4 = require("fs");
2363
+ var import_node_path4 = require("path");
2215
2364
  function hasPlugin(workspaceRoot, packageName) {
2216
- const manifest = readJson((0, import_node_path3.join)(workspaceRoot, "package.json"));
2365
+ const manifest = readJson((0, import_node_path4.join)(workspaceRoot, "package.json"));
2217
2366
  const installed = { ...manifest.dependencies, ...manifest.devDependencies };
2218
2367
  return Object.hasOwn(installed, packageName);
2219
2368
  }
@@ -2252,7 +2401,7 @@ function markPublic(manifestPath) {
2252
2401
  function writeProjectReadme(projectRoot, projectName, testRunner) {
2253
2402
  const runner = testRunner === "vitest" ? "[Vitest](https://vitest.dev)" : "[Jest](https://jestjs.io)";
2254
2403
  writeFileEnsured(
2255
- (0, import_node_path3.join)(projectRoot, "README.md"),
2404
+ (0, import_node_path4.join)(projectRoot, "README.md"),
2256
2405
  [
2257
2406
  `# ${projectName}`,
2258
2407
  "",
@@ -2271,13 +2420,13 @@ function writeProjectReadme(projectRoot, projectName, testRunner) {
2271
2420
  }
2272
2421
  function removeStaleGitkeeps(workspaceRoot) {
2273
2422
  for (const scaffold of ["apps", "libs", "packages"]) {
2274
- const directory = (0, import_node_path3.join)(workspaceRoot, scaffold);
2423
+ const directory = (0, import_node_path4.join)(workspaceRoot, scaffold);
2275
2424
  try {
2276
- const holdsAProject = (0, import_node_fs3.readdirSync)(directory, { withFileTypes: true }).some(
2425
+ const holdsAProject = (0, import_node_fs4.readdirSync)(directory, { withFileTypes: true }).some(
2277
2426
  (entry) => entry.isDirectory()
2278
2427
  );
2279
2428
  if (holdsAProject) {
2280
- (0, import_node_fs3.rmSync)((0, import_node_path3.join)(directory, ".gitkeep"), { force: true });
2429
+ (0, import_node_fs4.rmSync)((0, import_node_path4.join)(directory, ".gitkeep"), { force: true });
2281
2430
  }
2282
2431
  } catch {
2283
2432
  }
@@ -2297,7 +2446,7 @@ function ensureAdmZip(workspaceRoot) {
2297
2446
  }
2298
2447
  }
2299
2448
  function defaultScope(workspaceRoot) {
2300
- const { name } = readJson((0, import_node_path3.join)(workspaceRoot, "package.json"));
2449
+ const { name } = readJson((0, import_node_path4.join)(workspaceRoot, "package.json"));
2301
2450
  const base = (name.startsWith("@") ? name.slice(1) : name).split("/", 1)[0];
2302
2451
  return `@${base}`;
2303
2452
  }
@@ -2325,14 +2474,14 @@ var ESLINT_CONFIG_FILENAMES = [
2325
2474
  ];
2326
2475
  function removeGeneratedEslintConfig(workspaceRoot, projectRoot) {
2327
2476
  for (const filename of ESLINT_CONFIG_FILENAMES) {
2328
- (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, projectRoot, filename), { force: true });
2477
+ (0, import_node_fs4.rmSync)((0, import_node_path4.join)(workspaceRoot, projectRoot, filename), { force: true });
2329
2478
  }
2330
- (0, import_node_fs3.rmSync)((0, import_node_path3.join)(workspaceRoot, ".vscode"), { recursive: true, force: true });
2479
+ (0, import_node_fs4.rmSync)((0, import_node_path4.join)(workspaceRoot, ".vscode"), { recursive: true, force: true });
2331
2480
  }
2332
2481
  function findCodeWorkspaceFile(workspaceRoot) {
2333
2482
  try {
2334
- const entry = (0, import_node_fs3.readdirSync)(workspaceRoot).find((file) => file.endsWith(".code-workspace"));
2335
- return entry ? (0, import_node_path3.join)(workspaceRoot, entry) : void 0;
2483
+ const entry = (0, import_node_fs4.readdirSync)(workspaceRoot).find((file) => file.endsWith(".code-workspace"));
2484
+ return entry ? (0, import_node_path4.join)(workspaceRoot, entry) : void 0;
2336
2485
  } catch {
2337
2486
  return void 0;
2338
2487
  }
@@ -2343,25 +2492,25 @@ function projectTask(name, kind) {
2343
2492
  return kind === "start" ? { ...base, isBackground: true } : { ...base, group: kind };
2344
2493
  }
2345
2494
  function renameScaffoldPlaceholder(projectRoot, name) {
2346
- const placeholder = (0, import_node_path3.join)(projectRoot, "src", "lib", `${name}.ts`);
2347
- if (!(0, import_node_fs3.existsSync)(placeholder)) {
2495
+ const placeholder = (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.ts`);
2496
+ if (!(0, import_node_fs4.existsSync)(placeholder)) {
2348
2497
  return;
2349
2498
  }
2350
- (0, import_node_fs3.renameSync)(placeholder, (0, import_node_path3.join)(projectRoot, "src", "lib", `${name}.use-case.ts`));
2351
- const spec = (0, import_node_path3.join)(projectRoot, "src", "lib", `${name}.spec.ts`);
2352
- if ((0, import_node_fs3.existsSync)(spec)) {
2353
- const renamed = (0, import_node_path3.join)(projectRoot, "src", "lib", `${name}.use-case.spec.ts`);
2354
- (0, import_node_fs3.renameSync)(spec, renamed);
2499
+ (0, import_node_fs4.renameSync)(placeholder, (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.use-case.ts`));
2500
+ const spec = (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.spec.ts`);
2501
+ if ((0, import_node_fs4.existsSync)(spec)) {
2502
+ const renamed = (0, import_node_path4.join)(projectRoot, "src", "lib", `${name}.use-case.spec.ts`);
2503
+ (0, import_node_fs4.renameSync)(spec, renamed);
2355
2504
  writeFileEnsured(
2356
2505
  renamed,
2357
- repointSpecifier((0, import_node_fs3.readFileSync)(renamed, "utf8"), `./${name}`, `./${name}.use-case`)
2506
+ repointSpecifier((0, import_node_fs4.readFileSync)(renamed, "utf8"), `./${name}`, `./${name}.use-case`)
2358
2507
  );
2359
2508
  }
2360
- const barrel = (0, import_node_path3.join)(projectRoot, "src", "index.ts");
2361
- if ((0, import_node_fs3.existsSync)(barrel)) {
2509
+ const barrel = (0, import_node_path4.join)(projectRoot, "src", "index.ts");
2510
+ if ((0, import_node_fs4.existsSync)(barrel)) {
2362
2511
  writeFileEnsured(
2363
2512
  barrel,
2364
- repointSpecifier((0, import_node_fs3.readFileSync)(barrel, "utf8"), `./lib/${name}`, `./lib/${name}.use-case`)
2513
+ repointSpecifier((0, import_node_fs4.readFileSync)(barrel, "utf8"), `./lib/${name}`, `./lib/${name}.use-case`)
2365
2514
  );
2366
2515
  }
2367
2516
  }
@@ -2369,8 +2518,8 @@ function repointSpecifier(source, from, to) {
2369
2518
  return source.replaceAll(`${from}'`, () => `${to}'`).replaceAll(`${from}.js'`, () => `${to}.js'`);
2370
2519
  }
2371
2520
  function ensureNxPeerOverrides(workspaceRoot) {
2372
- const manifestPath = (0, import_node_path3.join)(workspaceRoot, "package.json");
2373
- if (!(0, import_node_fs3.existsSync)(manifestPath)) {
2521
+ const manifestPath = (0, import_node_path4.join)(workspaceRoot, "package.json");
2522
+ if (!(0, import_node_fs4.existsSync)(manifestPath)) {
2374
2523
  return;
2375
2524
  }
2376
2525
  const manifest = readJson(manifestPath);
@@ -2393,11 +2542,11 @@ function registerProjectCommands(workspaceRoot, name, commands) {
2393
2542
  if (commands.start) {
2394
2543
  scripts[`${name}:start`] = commands.start;
2395
2544
  }
2396
- const dependabotPath = (0, import_node_path3.join)(workspaceRoot, ".github/dependabot.yml");
2397
- if ((0, import_node_fs3.existsSync)(dependabotPath)) {
2545
+ const dependabotPath = (0, import_node_path4.join)(workspaceRoot, ".github/dependabot.yml");
2546
+ if ((0, import_node_fs4.existsSync)(dependabotPath)) {
2398
2547
  writeFileEnsured(dependabotPath, dependabotConfig(workspaceRoot));
2399
2548
  }
2400
- const manifestPath = (0, import_node_path3.join)(workspaceRoot, "package.json");
2549
+ const manifestPath = (0, import_node_path4.join)(workspaceRoot, "package.json");
2401
2550
  const manifest = readJson(manifestPath);
2402
2551
  const existingScripts = manifest.scripts ?? {};
2403
2552
  writeFileEnsured(
@@ -2435,7 +2584,7 @@ function registerProjectCommands(workspaceRoot, name, commands) {
2435
2584
  var PROJECT_MANIFEST_ROOTS = ["apps", "packages", "libs"];
2436
2585
  function rootRuntimeDependencies(workspaceRoot) {
2437
2586
  try {
2438
- return readJson((0, import_node_path3.join)(workspaceRoot, "package.json")).dependencies ?? {};
2587
+ return readJson((0, import_node_path4.join)(workspaceRoot, "package.json")).dependencies ?? {};
2439
2588
  } catch {
2440
2589
  return {};
2441
2590
  }
@@ -2447,7 +2596,7 @@ function relocateRootRuntimeDependencies(workspaceRoot, projectName, before) {
2447
2596
  return;
2448
2597
  }
2449
2598
  const manifestPath = PROJECT_MANIFEST_ROOTS.map(
2450
- (root) => (0, import_node_path3.join)(workspaceRoot, root, projectName, "package.json")
2599
+ (root) => (0, import_node_path4.join)(workspaceRoot, root, projectName, "package.json")
2451
2600
  ).find((candidate) => fileExists(candidate));
2452
2601
  if (manifestPath === void 0) {
2453
2602
  return;
@@ -2459,10 +2608,10 @@ function relocateRootRuntimeDependencies(workspaceRoot, projectName, before) {
2459
2608
  const remaining = Object.fromEntries(
2460
2609
  Object.entries(after).filter(([name]) => !added.includes(name))
2461
2610
  );
2462
- const rootManifest = readJson((0, import_node_path3.join)(workspaceRoot, "package.json"));
2611
+ const rootManifest = readJson((0, import_node_path4.join)(workspaceRoot, "package.json"));
2463
2612
  const { dependencies: _dropped, ...rest } = rootManifest;
2464
2613
  writeFileEnsured(
2465
- (0, import_node_path3.join)(workspaceRoot, "package.json"),
2614
+ (0, import_node_path4.join)(workspaceRoot, "package.json"),
2466
2615
  toJson(Object.keys(remaining).length > 0 ? { ...rest, dependencies: remaining } : rest)
2467
2616
  );
2468
2617
  logger.step(`Moved ${added.join(", ")} into ${projectName}'s own manifest`);
@@ -2522,7 +2671,7 @@ function addCsharpApp(workspaceRoot, name, template = "console") {
2522
2671
  ensureAdmZip(workspaceRoot);
2523
2672
  const projectRoot = `apps/${name}`;
2524
2673
  scaffoldDotnetProject(workspaceRoot, projectRoot, pascalCase(name), template);
2525
- addProjectJsonTargets((0, import_node_path4.join)(workspaceRoot, projectRoot, "project.json"), {
2674
+ addProjectJsonTargets((0, import_node_path5.join)(workspaceRoot, projectRoot, "project.json"), {
2526
2675
  package: csharpAppPackageTarget("csharp-app", projectRoot, name),
2527
2676
  start: csharpAppStartTarget(projectRoot)
2528
2677
  });
@@ -2615,7 +2764,7 @@ class CsharpVersionActions extends VersionActions {
2615
2764
  module.exports = CsharpVersionActions
2616
2765
  `;
2617
2766
  function writeCsharpVersionActions(workspaceRoot) {
2618
- writeFileEnsured((0, import_node_path4.join)(workspaceRoot, CSHARP_VERSION_ACTIONS_PATH), CSHARP_VERSION_ACTIONS);
2767
+ writeFileEnsured((0, import_node_path5.join)(workspaceRoot, CSHARP_VERSION_ACTIONS_PATH), CSHARP_VERSION_ACTIONS);
2619
2768
  }
2620
2769
  function addProjectJsonReleaseVersionActions(projectJsonPath) {
2621
2770
  const project = fileExists(projectJsonPath) ? readJson(projectJsonPath) : {};
@@ -2630,7 +2779,7 @@ function addProjectJsonReleaseVersionActions(projectJsonPath) {
2630
2779
  );
2631
2780
  }
2632
2781
  function addInitialVersion(csprojPath) {
2633
- const contents = (0, import_node_fs4.readFileSync)(csprojPath, "utf8");
2782
+ const contents = (0, import_node_fs5.readFileSync)(csprojPath, "utf8");
2634
2783
  writeFileEnsured(csprojPath, contents.replace("<PropertyGroup>", "<PropertyGroup>\n <Version>0.1.0</Version>"));
2635
2784
  }
2636
2785
  function csharpLibPublishTarget(projectRoot) {
@@ -2645,14 +2794,14 @@ async function addCsharpLib(workspaceRoot, name, options, kindProvided) {
2645
2794
  const projectRoot = `packages/${name}`;
2646
2795
  const identity = `${pascalScope(scope)}.${pascalCase(name)}`;
2647
2796
  scaffoldDotnetProject(workspaceRoot, projectRoot, identity, "classlib");
2648
- addInitialVersion((0, import_node_path4.join)(workspaceRoot, projectRoot, `${identity}.csproj`));
2797
+ addInitialVersion((0, import_node_path5.join)(workspaceRoot, projectRoot, `${identity}.csproj`));
2649
2798
  writeCsharpVersionActions(workspaceRoot);
2650
- addProjectJsonReleaseVersionActions((0, import_node_path4.join)(workspaceRoot, projectRoot, "project.json"));
2651
- addProjectJsonTargets((0, import_node_path4.join)(workspaceRoot, projectRoot, "project.json"), {
2799
+ addProjectJsonReleaseVersionActions((0, import_node_path5.join)(workspaceRoot, projectRoot, "project.json"));
2800
+ addProjectJsonTargets((0, import_node_path5.join)(workspaceRoot, projectRoot, "project.json"), {
2652
2801
  "nx-release-publish": csharpLibPublishTarget(projectRoot)
2653
2802
  });
2654
2803
  const registry = readMnciConfig(workspaceRoot).registry ?? { kind: "npm" };
2655
- writeFileEnsured((0, import_node_path4.join)(workspaceRoot, "nuget.config"), nugetConfigContent(registry, scope));
2804
+ writeFileEnsured((0, import_node_path5.join)(workspaceRoot, "nuget.config"), nugetConfigContent(registry, scope));
2656
2805
  registerProjectCommands(workspaceRoot, name, { build: true });
2657
2806
  }
2658
2807
  function addCsharpInternalLib(workspaceRoot, name) {
@@ -2728,15 +2877,15 @@ function addCsharpFunctionApp(workspaceRoot, name) {
2728
2877
  const projectRoot = `apps/${name}`;
2729
2878
  const identity = pascalCase(name);
2730
2879
  scaffoldDotnetProject(workspaceRoot, projectRoot, identity, "console");
2731
- const absoluteRoot = (0, import_node_path4.join)(workspaceRoot, projectRoot);
2732
- writeFileEnsured((0, import_node_path4.join)(absoluteRoot, `${identity}.csproj`), csharpFunctionAppCsproj());
2733
- writeFileEnsured((0, import_node_path4.join)(absoluteRoot, "Program.cs"), CSHARP_FUNCTION_APP_PROGRAM);
2734
- writeFileEnsured((0, import_node_path4.join)(absoluteRoot, "Hello.cs"), csharpFunctionAppHello(identity));
2735
- writeFileEnsured((0, import_node_path4.join)(absoluteRoot, "host.json"), CSHARP_FUNCTION_APP_HOST_JSON);
2880
+ const absoluteRoot = (0, import_node_path5.join)(workspaceRoot, projectRoot);
2881
+ writeFileEnsured((0, import_node_path5.join)(absoluteRoot, `${identity}.csproj`), csharpFunctionAppCsproj());
2882
+ writeFileEnsured((0, import_node_path5.join)(absoluteRoot, "Program.cs"), CSHARP_FUNCTION_APP_PROGRAM);
2883
+ writeFileEnsured((0, import_node_path5.join)(absoluteRoot, "Hello.cs"), csharpFunctionAppHello(identity));
2884
+ writeFileEnsured((0, import_node_path5.join)(absoluteRoot, "host.json"), CSHARP_FUNCTION_APP_HOST_JSON);
2736
2885
  if (runShell("dotnet", ["restore", projectRoot], workspaceRoot) !== 0) {
2737
2886
  throw new Error(`dotnet restore failed for ${projectRoot}`);
2738
2887
  }
2739
- addProjectJsonTargets((0, import_node_path4.join)(absoluteRoot, "project.json"), {
2888
+ addProjectJsonTargets((0, import_node_path5.join)(absoluteRoot, "project.json"), {
2740
2889
  package: csharpAppPackageTarget("csharp-function-app", projectRoot, name),
2741
2890
  start: csharpFunctionAppStartTarget(projectRoot)
2742
2891
  });
@@ -2744,7 +2893,7 @@ function addCsharpFunctionApp(workspaceRoot, name) {
2744
2893
  }
2745
2894
 
2746
2895
  // src/project-scaffolding/flutter.use-case.ts
2747
- var import_node_path5 = require("path");
2896
+ var import_node_path6 = require("path");
2748
2897
  function flutterAppStartTarget(name) {
2749
2898
  return {
2750
2899
  executor: "nx:run-commands",
@@ -2780,7 +2929,7 @@ function addFlutterApp(workspaceRoot, name) {
2780
2929
  prepareFlutter(workspaceRoot);
2781
2930
  ensureAdmZip(workspaceRoot);
2782
2931
  runNx(["g", "@mnci/nx-flutter:application", name, "--no-interactive"], workspaceRoot);
2783
- addProjectJsonTargets((0, import_node_path5.join)(workspaceRoot, "apps", name, "project.json"), {
2932
+ addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
2784
2933
  start: flutterAppStartTarget(name)
2785
2934
  });
2786
2935
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
@@ -2797,12 +2946,44 @@ function addFlutterInternalLib(workspaceRoot, name) {
2797
2946
  }
2798
2947
 
2799
2948
  // src/project-scaffolding/go.use-case.ts
2949
+ var import_node_fs9 = require("fs");
2950
+ var import_node_path10 = require("path");
2951
+
2952
+ // src/go-workspace/go-plugin.use-case.ts
2800
2953
  var import_node_fs6 = require("fs");
2801
2954
  var import_node_path7 = require("path");
2955
+ var NX_GO_PLUGIN = "@nx-go/nx-go";
2956
+ function hasGoProject(workspaceRoot) {
2957
+ const projectFiles = ["apps", "libs", "packages"].flatMap((directory) => (0, import_node_fs6.globSync)(`${directory}/*/project.json`, { cwd: workspaceRoot }));
2958
+ return projectFiles.some((projectFile) => {
2959
+ try {
2960
+ const { tags } = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path7.join)(workspaceRoot, projectFile), "utf8"));
2961
+ return (tags ?? []).some((tag) => tag.startsWith("type:go-"));
2962
+ } catch {
2963
+ return false;
2964
+ }
2965
+ });
2966
+ }
2967
+ function isNxGoPluginRegistered(workspaceRoot) {
2968
+ const nxJsonPath = (0, import_node_path7.join)(workspaceRoot, "nx.json");
2969
+ if (!fileExists(nxJsonPath)) {
2970
+ return false;
2971
+ }
2972
+ return (readJson(nxJsonPath).plugins ?? []).some((entry) => (typeof entry === "string" ? entry : entry.plugin) === NX_GO_PLUGIN);
2973
+ }
2974
+ function registerNxGoPlugin(workspaceRoot) {
2975
+ const nxJsonPath = (0, import_node_path7.join)(workspaceRoot, "nx.json");
2976
+ if (!fileExists(nxJsonPath) || isNxGoPluginRegistered(workspaceRoot)) {
2977
+ return false;
2978
+ }
2979
+ const nxJson = readJson(nxJsonPath);
2980
+ writeFileEnsured(nxJsonPath, toJson({ ...nxJson, plugins: [...nxJson.plugins ?? [], NX_GO_PLUGIN] }));
2981
+ return true;
2982
+ }
2802
2983
 
2803
2984
  // src/project-scaffolding/go-release.use-case.ts
2804
- var import_node_fs5 = require("fs");
2805
- var import_node_path6 = require("path");
2985
+ var import_node_fs7 = require("fs");
2986
+ var import_node_path8 = require("path");
2806
2987
  var GO_RELEASE_SCRIPT_PATH = "tools/go-app-release.cjs";
2807
2988
  var GO_RELEASE_SCRIPT = String.raw`#!/usr/bin/env node
2808
2989
  // Written by mnci: 'mnci add go-app --release' creates it and 'mnci upgrade'
@@ -2928,7 +3109,7 @@ var GO_RELEASE_PUBLISH_TARGET = {
2928
3109
  }
2929
3110
  };
2930
3111
  function makeGoAppReleasable(workspaceRoot, name) {
2931
- const projectJsonPath = (0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json");
3112
+ const projectJsonPath = (0, import_node_path8.join)(workspaceRoot, "apps", name, "project.json");
2932
3113
  if (!fileExists(projectJsonPath)) {
2933
3114
  throw new Error(`No Go app at apps/${name}: cannot make it releasable.`);
2934
3115
  }
@@ -2949,28 +3130,171 @@ function makeGoAppReleasable(workspaceRoot, name) {
2949
3130
  }
2950
3131
  })
2951
3132
  );
2952
- writeFileEnsured((0, import_node_path6.join)(workspaceRoot, GO_RELEASE_SCRIPT_PATH), GO_RELEASE_SCRIPT);
3133
+ writeFileEnsured((0, import_node_path8.join)(workspaceRoot, GO_RELEASE_SCRIPT_PATH), GO_RELEASE_SCRIPT);
2953
3134
  }
2954
3135
  function refreshGoReleaseScript(workspaceRoot) {
2955
- const apps = (0, import_node_path6.join)(workspaceRoot, "apps");
3136
+ const apps = (0, import_node_path8.join)(workspaceRoot, "apps");
2956
3137
  let entries;
2957
3138
  try {
2958
- entries = (0, import_node_fs5.readdirSync)(apps);
3139
+ entries = (0, import_node_fs7.readdirSync)(apps);
2959
3140
  } catch {
2960
3141
  return false;
2961
3142
  }
2962
3143
  const hasReleasableApp = entries.some((entry) => {
2963
- const projectJsonPath = (0, import_node_path6.join)(apps, entry, "project.json");
3144
+ const projectJsonPath = (0, import_node_path8.join)(apps, entry, "project.json");
2964
3145
  return fileExists(projectJsonPath) && (readJson(projectJsonPath).tags ?? []).includes(GO_RELEASE_TAG);
2965
3146
  });
2966
- const path = (0, import_node_path6.join)(workspaceRoot, GO_RELEASE_SCRIPT_PATH);
2967
- if (!hasReleasableApp || fileExists(path) && (0, import_node_fs5.readFileSync)(path, "utf8") === GO_RELEASE_SCRIPT) {
3147
+ const path = (0, import_node_path8.join)(workspaceRoot, GO_RELEASE_SCRIPT_PATH);
3148
+ if (!hasReleasableApp || fileExists(path) && (0, import_node_fs7.readFileSync)(path, "utf8") === GO_RELEASE_SCRIPT) {
2968
3149
  return false;
2969
3150
  }
2970
3151
  writeFileEnsured(path, GO_RELEASE_SCRIPT);
2971
3152
  return true;
2972
3153
  }
2973
3154
 
3155
+ // src/project-scaffolding/go-web.use-case.ts
3156
+ var import_node_fs8 = require("fs");
3157
+ var import_node_path9 = require("path");
3158
+ var TARGETS_NEEDING_THE_FRONTEND = ["build", "test", "lint", "start", "build-all", "build-native"];
3159
+ var DEFAULT_ADDRESS = "127.0.0.1:8080";
3160
+ var GO_WEB_SOURCE = `package main
3161
+
3162
+ import (
3163
+ "embed"
3164
+ "io/fs"
3165
+ "net/http"
3166
+ "path"
3167
+ )
3168
+
3169
+ // The built frontend. The stage-web target copies it into web/ before Go compiles.
3170
+ //
3171
+ //go:embed all:web
3172
+ var webFiles embed.FS
3173
+
3174
+ // webHandler serves the built frontend. A path that is not a file falls back to
3175
+ // index.html, so a client-side route survives a reload.
3176
+ func webHandler() http.Handler {
3177
+ root, err := fs.Sub(webFiles, "web")
3178
+ if err != nil {
3179
+ panic(err)
3180
+ }
3181
+ files := http.FileServer(http.FS(root))
3182
+
3183
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3184
+ name := path.Clean(r.URL.Path)[1:]
3185
+ if name != "" {
3186
+ if _, err := fs.Stat(root, name); err != nil {
3187
+ r.URL.Path = "/"
3188
+ }
3189
+ }
3190
+ files.ServeHTTP(w, r)
3191
+ })
3192
+ }
3193
+ `;
3194
+ var GO_WEB_MAIN = `package main
3195
+
3196
+ import (
3197
+ "log"
3198
+ "net/http"
3199
+ "os"
3200
+ )
3201
+
3202
+ var version = "dev"
3203
+
3204
+ func main() {
3205
+ address := os.Getenv("ADDR")
3206
+ if address == "" {
3207
+ address = "${DEFAULT_ADDRESS}"
3208
+ }
3209
+ mux := http.NewServeMux()
3210
+ mux.Handle("/", webHandler())
3211
+ log.Printf("%s serving on http://%s", version, address)
3212
+ log.Fatal(http.ListenAndServe(address, mux))
3213
+ }
3214
+ `;
3215
+ var GO_WEB_MAIN_TEST = `package main
3216
+
3217
+ import (
3218
+ "net/http"
3219
+ "net/http/httptest"
3220
+ "strings"
3221
+ "testing"
3222
+ )
3223
+
3224
+ func TestWebHandlerServesTheBuiltFrontend(t *testing.T) {
3225
+ for _, target := range []string{"/", "/a/client/side/route"} {
3226
+ recorder := httptest.NewRecorder()
3227
+ webHandler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, target, nil))
3228
+ if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), "<html") {
3229
+ t.Fatalf("GET %s: %d %q", target, recorder.Code, recorder.Body.String())
3230
+ }
3231
+ }
3232
+ }
3233
+ `;
3234
+ function assertWebApp(workspaceRoot, web) {
3235
+ const directory = (0, import_node_path9.join)(workspaceRoot, "apps", web);
3236
+ const isReactApp = fileExists((0, import_node_path9.join)(directory, "package.json")) && (0, import_node_fs8.readdirSync)(directory).some((entry) => entry.startsWith("vite.config."));
3237
+ if (!isReactApp) {
3238
+ throw new Error(`--web ${web}: no React app at apps/${web}. Add it first with \`mnci add react-app ${web}\`.`);
3239
+ }
3240
+ }
3241
+ function webProjectName(workspaceRoot, web) {
3242
+ const manifest = readJson((0, import_node_path9.join)(workspaceRoot, "apps", web, "package.json"));
3243
+ return manifest.nx?.name ?? manifest.name ?? web;
3244
+ }
3245
+ function addApiProxy(viteConfigPath) {
3246
+ const source = (0, import_node_fs8.readFileSync)(viteConfigPath, "utf8");
3247
+ if (source.includes("'/api'") || source.includes('"/api"')) {
3248
+ return false;
3249
+ }
3250
+ const patched = source.replace(/server:\s*\{/, (serverBlock) => `${serverBlock}
3251
+ proxy: { '/api': 'http://${DEFAULT_ADDRESS}' },`);
3252
+ if (patched === source) {
3253
+ return false;
3254
+ }
3255
+ writeFileEnsured(viteConfigPath, patched);
3256
+ return true;
3257
+ }
3258
+ function wireGoAppToWeb(workspaceRoot, name, web) {
3259
+ const projectJsonPath = (0, import_node_path9.join)(workspaceRoot, "apps", name, "project.json");
3260
+ const project = readJson(projectJsonPath);
3261
+ const webName = webProjectName(workspaceRoot, web);
3262
+ const targets = project.targets ?? {};
3263
+ for (const target of TARGETS_NEEDING_THE_FRONTEND) {
3264
+ if (targets[target] !== void 0) {
3265
+ targets[target].dependsOn = [.../* @__PURE__ */ new Set([...targets[target].dependsOn ?? [], "stage-web"])];
3266
+ }
3267
+ }
3268
+ targets["stage-web"] = {
3269
+ executor: "nx:run-commands",
3270
+ dependsOn: [{ projects: [webName], target: "build" }],
3271
+ inputs: [{ dependentTasksOutputFiles: "**/*" }],
3272
+ outputs: [`{workspaceRoot}/apps/${name}/web`],
3273
+ options: {
3274
+ command: `node -e "const fs=require('node:fs');fs.rmSync('apps/${name}/web',{recursive:true,force:true});fs.cpSync('apps/${web}/dist','apps/${name}/web',{recursive:true})"`
3275
+ }
3276
+ };
3277
+ targets.dev = {
3278
+ executor: "nx:run-commands",
3279
+ options: { commands: [`nx run ${webName}:serve`, `nx run ${name}:start`], parallel: true }
3280
+ };
3281
+ writeFileEnsured(
3282
+ projectJsonPath,
3283
+ toJson({ ...project, implicitDependencies: [.../* @__PURE__ */ new Set([...project.implicitDependencies ?? [], webName])], targets })
3284
+ );
3285
+ const directory = (0, import_node_path9.join)(workspaceRoot, "apps", name);
3286
+ writeFileEnsured((0, import_node_path9.join)(directory, ".gitignore"), "/web/\n");
3287
+ writeFileEnsured((0, import_node_path9.join)(directory, "web.go"), GO_WEB_SOURCE);
3288
+ writeFileEnsured((0, import_node_path9.join)(directory, "main.go"), GO_WEB_MAIN);
3289
+ writeFileEnsured((0, import_node_path9.join)(directory, "main_test.go"), GO_WEB_MAIN_TEST);
3290
+ const viteConfig = (0, import_node_fs8.readdirSync)((0, import_node_path9.join)(workspaceRoot, "apps", web)).find((entry) => entry.startsWith("vite.config."));
3291
+ if (viteConfig === void 0 || !addApiProxy((0, import_node_path9.join)(workspaceRoot, "apps", web, viteConfig))) {
3292
+ logger.warn(
3293
+ `Could not add the /api proxy to apps/${web}'s Vite config: add \`server: { proxy: { '/api': 'http://${DEFAULT_ADDRESS}' } }\` yourself, so \`nx run ${name}:dev\` reaches the Go server.`
3294
+ );
3295
+ }
3296
+ }
3297
+
2974
3298
  // src/project-scaffolding/go.use-case.ts
2975
3299
  function ensureGo(workspaceRoot) {
2976
3300
  if (runShell("go", ["version"], workspaceRoot) !== 0) {
@@ -2998,7 +3322,7 @@ function ensureNxGoPlugin(workspaceRoot) {
2998
3322
  }
2999
3323
  }
3000
3324
  function ensureGoModule(workspaceRoot) {
3001
- if (fileExists((0, import_node_path7.join)(workspaceRoot, "go.mod"))) {
3325
+ if (fileExists((0, import_node_path10.join)(workspaceRoot, "go.mod"))) {
3002
3326
  return;
3003
3327
  }
3004
3328
  logger.step("Bootstrapping the workspace Go module (single root go.mod)");
@@ -3007,7 +3331,7 @@ function ensureGoModule(workspaceRoot) {
3007
3331
  }
3008
3332
  function goModulePath(workspaceRoot) {
3009
3333
  try {
3010
- const contents = (0, import_node_fs6.readFileSync)((0, import_node_path7.join)(workspaceRoot, "go.mod"), "utf8");
3334
+ const contents = (0, import_node_fs9.readFileSync)((0, import_node_path10.join)(workspaceRoot, "go.mod"), "utf8");
3011
3335
  return /^module\s+(\S+)/m.exec(contents)?.[1];
3012
3336
  } catch {
3013
3337
  return void 0;
@@ -3088,16 +3412,16 @@ function goNativePackageTarget(name) {
3088
3412
  }
3089
3413
  function addGoPlatformTargets(workspaceRoot) {
3090
3414
  const changed = [];
3091
- const apps = (0, import_node_path7.join)(workspaceRoot, "apps");
3415
+ const apps = (0, import_node_path10.join)(workspaceRoot, "apps");
3092
3416
  if (!fileExists(apps)) {
3093
3417
  return changed;
3094
3418
  }
3095
- for (const name of (0, import_node_fs6.readdirSync)(apps)) {
3096
- const projectJsonPath = (0, import_node_path7.join)(apps, name, "project.json");
3419
+ for (const name of (0, import_node_fs9.readdirSync)(apps)) {
3420
+ const projectJsonPath = (0, import_node_path10.join)(apps, name, "project.json");
3097
3421
  if (!fileExists(projectJsonPath)) {
3098
3422
  continue;
3099
3423
  }
3100
- const project = JSON.parse((0, import_node_fs6.readFileSync)(projectJsonPath, "utf8"));
3424
+ const project = JSON.parse((0, import_node_fs9.readFileSync)(projectJsonPath, "utf8"));
3101
3425
  const tag = (project.tags ?? []).find((each) => each === "type:go-app" || each === "type:go-function-app")?.slice("type:".length);
3102
3426
  if (tag === void 0 || (project.tags ?? []).includes(GO_CGO_TAG)) {
3103
3427
  continue;
@@ -3133,8 +3457,8 @@ function goLibraryIdentifiers(projectName) {
3133
3457
  }
3134
3458
  function reshapeGoLibraryScaffold(projectRoot, projectName) {
3135
3459
  const { packageName, functionName, fileStem } = goLibraryIdentifiers(projectName);
3136
- (0, import_node_fs6.rmSync)((0, import_node_path7.join)(projectRoot, `${projectName}.go`), { force: true });
3137
- (0, import_node_fs6.rmSync)((0, import_node_path7.join)(projectRoot, `${projectName}_test.go`), { force: true });
3460
+ (0, import_node_fs9.rmSync)((0, import_node_path10.join)(projectRoot, `${projectName}.go`), { force: true });
3461
+ (0, import_node_fs9.rmSync)((0, import_node_path10.join)(projectRoot, `${projectName}_test.go`), { force: true });
3138
3462
  const files = [
3139
3463
  [
3140
3464
  "doc.go",
@@ -3144,14 +3468,14 @@ package ${packageName}
3144
3468
  `
3145
3469
  ],
3146
3470
  [
3147
- (0, import_node_path7.join)(packageName, "doc.go"),
3471
+ (0, import_node_path10.join)(packageName, "doc.go"),
3148
3472
  `// Package ${packageName} is the starter slice of ${projectName}: rename it after
3149
3473
  // the outcome it delivers, and add one package per further outcome.
3150
3474
  package ${packageName}
3151
3475
  `
3152
3476
  ],
3153
3477
  [
3154
- (0, import_node_path7.join)(packageName, `${fileStem}_use_case.go`),
3478
+ (0, import_node_path10.join)(packageName, `${fileStem}_use_case.go`),
3155
3479
  `package ${packageName}
3156
3480
 
3157
3481
  // ${functionName} is the generator's sample behaviour, kept so the slice builds and tests.
@@ -3161,7 +3485,7 @@ func ${functionName}(name string) string {
3161
3485
  `
3162
3486
  ],
3163
3487
  [
3164
- (0, import_node_path7.join)(packageName, `${fileStem}_use_case_test.go`),
3488
+ (0, import_node_path10.join)(packageName, `${fileStem}_use_case_test.go`),
3165
3489
  `package ${packageName}
3166
3490
 
3167
3491
  import "testing"
@@ -3175,7 +3499,7 @@ func Test${functionName}(t *testing.T) {
3175
3499
  ]
3176
3500
  ];
3177
3501
  for (const [relativePath, content] of files) {
3178
- const path = (0, import_node_path7.join)(projectRoot, relativePath);
3502
+ const path = (0, import_node_path10.join)(projectRoot, relativePath);
3179
3503
  if (!fileExists(path)) {
3180
3504
  writeFileEnsured(path, content);
3181
3505
  }
@@ -3187,9 +3511,15 @@ function prepareGo(workspaceRoot) {
3187
3511
  warnIfNoGolangciLint(workspaceRoot);
3188
3512
  ensureNxGoPlugin(workspaceRoot);
3189
3513
  ensureGoModule(workspaceRoot);
3514
+ if (registerNxGoPlugin(workspaceRoot)) {
3515
+ logger.step("Registering the Go plugin in nx.json, so Nx can see which Go project imports which");
3516
+ }
3190
3517
  }
3191
3518
  function addGoApp(workspaceRoot, name, options = {}) {
3192
3519
  const cgo = options.cgo === true;
3520
+ if (options.web !== void 0) {
3521
+ assertWebApp(workspaceRoot, options.web);
3522
+ }
3193
3523
  prepareGo(workspaceRoot);
3194
3524
  ensureAdmZip(workspaceRoot);
3195
3525
  runNx(
@@ -3203,7 +3533,7 @@ function addGoApp(workspaceRoot, name, options = {}) {
3203
3533
  ],
3204
3534
  workspaceRoot
3205
3535
  );
3206
- addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "apps", name, "project.json"), {
3536
+ addProjectJsonTargets((0, import_node_path10.join)(workspaceRoot, "apps", name, "project.json"), {
3207
3537
  build: goBuildTarget(name),
3208
3538
  test: goTestTarget(),
3209
3539
  lint: goLintTarget(),
@@ -3217,6 +3547,9 @@ function addGoApp(workspaceRoot, name, options = {}) {
3217
3547
  if (options.release === true) {
3218
3548
  makeGoAppReleasable(workspaceRoot, name);
3219
3549
  }
3550
+ if (options.web !== void 0) {
3551
+ wireGoAppToWeb(workspaceRoot, name, options.web);
3552
+ }
3220
3553
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
3221
3554
  if (cgo) {
3222
3555
  logger.warn(
@@ -3238,7 +3571,7 @@ function addGoFunctionApp(workspaceRoot, name) {
3238
3571
  ],
3239
3572
  workspaceRoot
3240
3573
  );
3241
- addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "apps", name, "project.json"), {
3574
+ addProjectJsonTargets((0, import_node_path10.join)(workspaceRoot, "apps", name, "project.json"), {
3242
3575
  "build": goBuildTarget(name),
3243
3576
  "test": goTestTarget(),
3244
3577
  "lint": goLintTarget(),
@@ -3261,11 +3594,11 @@ function addGoLib(workspaceRoot, name) {
3261
3594
  ],
3262
3595
  workspaceRoot
3263
3596
  );
3264
- addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "packages", name, "project.json"), {
3597
+ addProjectJsonTargets((0, import_node_path10.join)(workspaceRoot, "packages", name, "project.json"), {
3265
3598
  test: goTestTarget(),
3266
3599
  lint: goLintTarget()
3267
3600
  });
3268
- const slice = reshapeGoLibraryScaffold((0, import_node_path7.join)(workspaceRoot, "packages", name), name);
3601
+ const slice = reshapeGoLibraryScaffold((0, import_node_path10.join)(workspaceRoot, "packages", name), name);
3269
3602
  registerProjectCommands(workspaceRoot, name, { build: false });
3270
3603
  const module2 = goModulePath(workspaceRoot);
3271
3604
  if (module2) {
@@ -3285,11 +3618,11 @@ function addGoInternalLib(workspaceRoot, name) {
3285
3618
  ],
3286
3619
  workspaceRoot
3287
3620
  );
3288
- addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "libs", name, "project.json"), {
3621
+ addProjectJsonTargets((0, import_node_path10.join)(workspaceRoot, "libs", name, "project.json"), {
3289
3622
  test: goTestTarget(),
3290
3623
  lint: goLintTarget()
3291
3624
  });
3292
- const slice = reshapeGoLibraryScaffold((0, import_node_path7.join)(workspaceRoot, "libs", name), name);
3625
+ const slice = reshapeGoLibraryScaffold((0, import_node_path10.join)(workspaceRoot, "libs", name), name);
3293
3626
  registerProjectCommands(workspaceRoot, name, { build: false });
3294
3627
  const module2 = goModulePath(workspaceRoot);
3295
3628
  if (module2) {
@@ -3298,7 +3631,7 @@ function addGoInternalLib(workspaceRoot, name) {
3298
3631
  }
3299
3632
 
3300
3633
  // src/project-scaffolding/node.use-case.ts
3301
- var import_node_path8 = require("path");
3634
+ var import_node_path11 = require("path");
3302
3635
  function ensurePlugin2(workspaceRoot, packageName) {
3303
3636
  if (hasPlugin(workspaceRoot, packageName)) {
3304
3637
  return;
@@ -3322,12 +3655,12 @@ function runNodeApp(workspaceRoot, name, stack, framework) {
3322
3655
  ],
3323
3656
  workspaceRoot
3324
3657
  );
3325
- const appRoot = (0, import_node_path8.join)(workspaceRoot, "apps", name);
3658
+ const appRoot = (0, import_node_path11.join)(workspaceRoot, "apps", name);
3326
3659
  separateDeclarationOutput(appRoot);
3327
3660
  repairAssetMapping(appRoot, name);
3328
3661
  }
3329
3662
  function separateDeclarationOutput(appRoot) {
3330
- const tsconfigPath = (0, import_node_path8.join)(appRoot, "tsconfig.app.json");
3663
+ const tsconfigPath = (0, import_node_path11.join)(appRoot, "tsconfig.app.json");
3331
3664
  if (!fileExists(tsconfigPath)) {
3332
3665
  return;
3333
3666
  }
@@ -3349,7 +3682,7 @@ function separateDeclarationOutput(appRoot) {
3349
3682
  );
3350
3683
  }
3351
3684
  function repairAssetMapping(appRoot, name) {
3352
- const manifestPath = (0, import_node_path8.join)(appRoot, "package.json");
3685
+ const manifestPath = (0, import_node_path11.join)(appRoot, "package.json");
3353
3686
  if (!fileExists(manifestPath)) {
3354
3687
  return;
3355
3688
  }
@@ -3376,7 +3709,7 @@ function nodeAppPackageTarget(name) {
3376
3709
  function addNodeApp(workspaceRoot, name, stack, framework = "none") {
3377
3710
  runNodeApp(workspaceRoot, name, stack, framework);
3378
3711
  ensureAdmZip(workspaceRoot);
3379
- addNxTargets((0, import_node_path8.join)(workspaceRoot, "apps", name, "package.json"), {
3712
+ addNxTargets((0, import_node_path11.join)(workspaceRoot, "apps", name, "package.json"), {
3380
3713
  package: nodeAppPackageTarget(name)
3381
3714
  });
3382
3715
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
@@ -3432,10 +3765,10 @@ describe('buildGreeting', () => {
3432
3765
  })
3433
3766
  `;
3434
3767
  function repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot) {
3435
- const manifestPath = (0, import_node_path8.join)(nodeFunctionAppRoot, "package.json");
3768
+ const manifestPath = (0, import_node_path11.join)(nodeFunctionAppRoot, "package.json");
3436
3769
  const manifest = readJson(manifestPath);
3437
3770
  const azureFunctionsVersion = readJson(
3438
- (0, import_node_path8.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
3771
+ (0, import_node_path11.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
3439
3772
  ).version;
3440
3773
  const dependencies = manifest.dependencies ?? {};
3441
3774
  writeFileEnsured(
@@ -3478,21 +3811,21 @@ function nodeFunctionAppStartTarget(name) {
3478
3811
  function addNodeFunctionApp(workspaceRoot, name, stack) {
3479
3812
  runNodeApp(workspaceRoot, name, stack, "none");
3480
3813
  ensureAzureFunctionsPackage(workspaceRoot);
3481
- const nodeFunctionAppRoot = (0, import_node_path8.join)(workspaceRoot, "apps", name);
3482
- writeFileEnsured((0, import_node_path8.join)(nodeFunctionAppRoot, "src/main.ts"), NODE_FUNCTION_APP_MAIN);
3483
- writeFileEnsured((0, import_node_path8.join)(nodeFunctionAppRoot, "src/functions/hello.ts"), NODE_FUNCTION_APP_HELLO);
3814
+ const nodeFunctionAppRoot = (0, import_node_path11.join)(workspaceRoot, "apps", name);
3815
+ writeFileEnsured((0, import_node_path11.join)(nodeFunctionAppRoot, "src/main.ts"), NODE_FUNCTION_APP_MAIN);
3816
+ writeFileEnsured((0, import_node_path11.join)(nodeFunctionAppRoot, "src/functions/hello.ts"), NODE_FUNCTION_APP_HELLO);
3484
3817
  writeFileEnsured(
3485
- (0, import_node_path8.join)(nodeFunctionAppRoot, "src/functions/greeting.ts"),
3818
+ (0, import_node_path11.join)(nodeFunctionAppRoot, "src/functions/greeting.ts"),
3486
3819
  NODE_FUNCTION_APP_GREETING
3487
3820
  );
3488
3821
  writeFileEnsured(
3489
- (0, import_node_path8.join)(nodeFunctionAppRoot, "src/functions/greeting.spec.ts"),
3822
+ (0, import_node_path11.join)(nodeFunctionAppRoot, "src/functions/greeting.spec.ts"),
3490
3823
  NODE_FUNCTION_APP_GREETING_SPEC
3491
3824
  );
3492
- writeFileEnsured((0, import_node_path8.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
3825
+ writeFileEnsured((0, import_node_path11.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
3493
3826
  repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot);
3494
3827
  ensureAdmZip(workspaceRoot);
3495
- addNxTargets((0, import_node_path8.join)(nodeFunctionAppRoot, "package.json"), {
3828
+ addNxTargets((0, import_node_path11.join)(nodeFunctionAppRoot, "package.json"), {
3496
3829
  package: nodeFunctionAppPackageTarget(name),
3497
3830
  prune: nodeFunctionAppPruneTarget(name),
3498
3831
  start: nodeFunctionAppStartTarget(name)
@@ -3502,11 +3835,11 @@ function addNodeFunctionApp(workspaceRoot, name, stack) {
3502
3835
  }
3503
3836
 
3504
3837
  // src/project-scaffolding/npm-lib.use-case.ts
3505
- var import_node_path12 = require("path");
3838
+ var import_node_path15 = require("path");
3506
3839
 
3507
3840
  // src/rollup-library/repair-publishable-manifest.use-case.ts
3508
- var import_node_fs7 = require("fs");
3509
- var import_node_path9 = require("path");
3841
+ var import_node_fs10 = require("fs");
3842
+ var import_node_path12 = require("path");
3510
3843
  var WRONG_TYPES_PATH = "./dist/index.esm.d.ts";
3511
3844
  var ACTUAL_TYPES_PATH = "./dist/src/index.d.ts";
3512
3845
  var DECLARATION_MAP_EXCLUSION = "!**/*.d.ts.map";
@@ -3529,14 +3862,14 @@ function repairPublishableManifest(manifestPath) {
3529
3862
  }
3530
3863
  function repairPublishableManifests(workspaceRoot) {
3531
3864
  const changed = [];
3532
- const manifests = (0, import_node_fs7.globSync)(["packages/*/package.json", "libs/*/package.json"], {
3865
+ const manifests = (0, import_node_fs10.globSync)(["packages/*/package.json", "libs/*/package.json"], {
3533
3866
  cwd: workspaceRoot
3534
3867
  });
3535
3868
  for (const relativePath of manifests) {
3536
- const manifestPath = (0, import_node_path9.join)(workspaceRoot, relativePath);
3537
- const before = (0, import_node_fs7.readFileSync)(manifestPath, "utf8");
3869
+ const manifestPath = (0, import_node_path12.join)(workspaceRoot, relativePath);
3870
+ const before = (0, import_node_fs10.readFileSync)(manifestPath, "utf8");
3538
3871
  repairPublishableManifest(manifestPath);
3539
- const after = (0, import_node_fs7.readFileSync)(manifestPath, "utf8");
3872
+ const after = (0, import_node_fs10.readFileSync)(manifestPath, "utf8");
3540
3873
  if (after !== before) {
3541
3874
  changed.push(relativePath.replaceAll("\\", "/"));
3542
3875
  }
@@ -3545,8 +3878,8 @@ function repairPublishableManifests(workspaceRoot) {
3545
3878
  }
3546
3879
 
3547
3880
  // src/rollup-library/repair-rollup-config.use-case.ts
3548
- var import_node_fs8 = require("fs");
3549
- var import_node_path10 = require("path");
3881
+ var import_node_fs11 = require("fs");
3882
+ var import_node_path13 = require("path");
3550
3883
 
3551
3884
  // src/rollup-library/rollup-config.algorithm.ts
3552
3885
  var ROLLUP_CONFIG_PLACEHOLDER = [
@@ -3748,12 +4081,12 @@ function withUpgradedDeclarationSpecifierPlugin(config) {
3748
4081
  // src/rollup-library/repair-rollup-config.use-case.ts
3749
4082
  function repairRollupSourceMaps(workspaceRoot) {
3750
4083
  const changed = [];
3751
- const configs = (0, import_node_fs8.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
4084
+ const configs = (0, import_node_fs11.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
3752
4085
  cwd: workspaceRoot
3753
4086
  });
3754
4087
  for (const relativePath of configs) {
3755
- const configPath = (0, import_node_path10.join)(workspaceRoot, relativePath);
3756
- const before = (0, import_node_fs8.readFileSync)(configPath, "utf8");
4088
+ const configPath = (0, import_node_path13.join)(workspaceRoot, relativePath);
4089
+ const before = (0, import_node_fs11.readFileSync)(configPath, "utf8");
3757
4090
  const after = withRollupSourceMaps(before);
3758
4091
  if (after !== before) {
3759
4092
  writeFileEnsured(configPath, after);
@@ -3764,12 +4097,12 @@ function repairRollupSourceMaps(workspaceRoot) {
3764
4097
  }
3765
4098
  function upgradeDeclarationSpecifierPlugins(workspaceRoot) {
3766
4099
  const changed = [];
3767
- const configs = (0, import_node_fs8.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
4100
+ const configs = (0, import_node_fs11.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
3768
4101
  cwd: workspaceRoot
3769
4102
  });
3770
4103
  for (const relativePath of configs) {
3771
- const configPath = (0, import_node_path10.join)(workspaceRoot, relativePath);
3772
- const before = (0, import_node_fs8.readFileSync)(configPath, "utf8");
4104
+ const configPath = (0, import_node_path13.join)(workspaceRoot, relativePath);
4105
+ const before = (0, import_node_fs11.readFileSync)(configPath, "utf8");
3773
4106
  const after = withUpgradedDeclarationSpecifierPlugin(before);
3774
4107
  if (after !== before) {
3775
4108
  writeFileEnsured(configPath, after);
@@ -3779,11 +4112,11 @@ function upgradeDeclarationSpecifierPlugins(workspaceRoot) {
3779
4112
  return changed;
3780
4113
  }
3781
4114
  function repairDeclarationSpecifiers(projectRoot) {
3782
- const configPath = (0, import_node_path10.join)(projectRoot, "rollup.config.cjs");
4115
+ const configPath = (0, import_node_path13.join)(projectRoot, "rollup.config.cjs");
3783
4116
  if (!fileExists(configPath)) {
3784
4117
  return;
3785
4118
  }
3786
- const config = (0, import_node_fs8.readFileSync)(configPath, "utf8");
4119
+ const config = (0, import_node_fs11.readFileSync)(configPath, "utf8");
3787
4120
  if (!config.includes(ROLLUP_CONFIG_PLACEHOLDER)) {
3788
4121
  return;
3789
4122
  }
@@ -3792,10 +4125,10 @@ function repairDeclarationSpecifiers(projectRoot) {
3792
4125
  }
3793
4126
 
3794
4127
  // src/rollup-library/rollup-config.repository.ts
3795
- var import_node_fs9 = require("fs");
3796
- var import_node_path11 = require("path");
4128
+ var import_node_fs12 = require("fs");
4129
+ var import_node_path14 = require("path");
3797
4130
  function resolveRequireTarget(fromDir, specifier) {
3798
- const base = (0, import_node_path11.join)(fromDir, specifier);
4131
+ const base = (0, import_node_path14.join)(fromDir, specifier);
3799
4132
  return [base, `${base}.cjs`, `${base}.js`].find((candidate) => fileExists(candidate));
3800
4133
  }
3801
4134
  function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()) {
@@ -3805,7 +4138,7 @@ function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()
3805
4138
  visited.add(configPath);
3806
4139
  let text;
3807
4140
  try {
3808
- text = (0, import_node_fs9.readFileSync)(configPath, "utf8");
4141
+ text = (0, import_node_fs12.readFileSync)(configPath, "utf8");
3809
4142
  } catch {
3810
4143
  return "";
3811
4144
  }
@@ -3813,15 +4146,15 @@ function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()
3813
4146
  text.matchAll(/require\((['"])(\.[^'"]*)\1\)/g),
3814
4147
  (match) => match[2]
3815
4148
  );
3816
- const requiredText = specifiers.map((specifier) => resolveRequireTarget((0, import_node_path11.dirname)(configPath), specifier)).filter((target) => target !== void 0).map((target) => resolveRollupConfigText(target, visited));
4149
+ const requiredText = specifiers.map((specifier) => resolveRequireTarget((0, import_node_path14.dirname)(configPath), specifier)).filter((target) => target !== void 0).map((target) => resolveRollupConfigText(target, visited));
3817
4150
  return [text, ...requiredText].join("\n");
3818
4151
  }
3819
4152
 
3820
4153
  // src/project-scaffolding/npm-lib.use-case.ts
3821
4154
  async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
3822
4155
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
3823
- const projectRoot = (0, import_node_path12.join)(workspaceRoot, "packages", name);
3824
- const manifestPath = (0, import_node_path12.join)(projectRoot, "package.json");
4156
+ const projectRoot = (0, import_node_path15.join)(workspaceRoot, "packages", name);
4157
+ const manifestPath = (0, import_node_path15.join)(projectRoot, "package.json");
3825
4158
  runGeneratorAndRepair(
3826
4159
  workspaceRoot,
3827
4160
  [
@@ -3850,8 +4183,8 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
3850
4183
  }
3851
4184
 
3852
4185
  // src/project-scaffolding/python.use-case.ts
3853
- var import_node_fs10 = require("fs");
3854
- var import_node_path13 = require("path");
4186
+ var import_node_fs13 = require("fs");
4187
+ var import_node_path16 = require("path");
3855
4188
  function ensurePython(workspaceRoot) {
3856
4189
  const hasPython = runShell("python3", ["--version"], workspaceRoot) === 0 || runShell("python", ["--version"], workspaceRoot) === 0;
3857
4190
  if (!hasPython) {
@@ -3874,7 +4207,7 @@ function ensurePythonPipPlugin(workspaceRoot) {
3874
4207
  registerPythonGraphPlugin(workspaceRoot);
3875
4208
  }
3876
4209
  function registerPythonGraphPlugin(workspaceRoot) {
3877
- const nxJsonPath = (0, import_node_path13.join)(workspaceRoot, "nx.json");
4210
+ const nxJsonPath = (0, import_node_path16.join)(workspaceRoot, "nx.json");
3878
4211
  if (!fileExists(nxJsonPath)) {
3879
4212
  return;
3880
4213
  }
@@ -3897,7 +4230,7 @@ pytest
3897
4230
  pip-audit
3898
4231
  `;
3899
4232
  function ensureRequirementsDev(workspaceRoot) {
3900
- const requirementsDevPath = (0, import_node_path13.join)(workspaceRoot, "requirements-dev.txt");
4233
+ const requirementsDevPath = (0, import_node_path16.join)(workspaceRoot, "requirements-dev.txt");
3901
4234
  if (!fileExists(requirementsDevPath)) {
3902
4235
  writeFileEnsured(requirementsDevPath, PYTHON_REQUIREMENTS_DEV);
3903
4236
  }
@@ -3957,8 +4290,8 @@ function addPythonApp(workspaceRoot, name) {
3957
4290
  ["g", "@mnci/nx-python-pip:application", name, `--directory=apps/${name}`, "--no-interactive"],
3958
4291
  workspaceRoot
3959
4292
  );
3960
- writeFileEnsured((0, import_node_path13.join)(workspaceRoot, "apps", name, "main.py"), pythonAppMain(name));
3961
- addProjectJsonTargets((0, import_node_path13.join)(workspaceRoot, "apps", name, "project.json"), {
4293
+ writeFileEnsured((0, import_node_path16.join)(workspaceRoot, "apps", name, "main.py"), pythonAppMain(name));
4294
+ addProjectJsonTargets((0, import_node_path16.join)(workspaceRoot, "apps", name, "project.json"), {
3962
4295
  package: pythonAppPackageTarget(name),
3963
4296
  start: pythonAppStartTarget(name)
3964
4297
  });
@@ -3980,7 +4313,7 @@ function addPythonFunctionApp(workspaceRoot, name) {
3980
4313
  workspaceRoot
3981
4314
  );
3982
4315
  const moduleDirectory = pythonModuleDirectory(name);
3983
- addProjectJsonTargets((0, import_node_path13.join)(workspaceRoot, "apps", name, "project.json"), {
4316
+ addProjectJsonTargets((0, import_node_path16.join)(workspaceRoot, "apps", name, "project.json"), {
3984
4317
  package: pythonFunctionAppPackageTarget(name, moduleDirectory),
3985
4318
  start: pythonFunctionAppStartTarget(name)
3986
4319
  });
@@ -4021,7 +4354,7 @@ function addPythonInternalLib(workspaceRoot, name) {
4021
4354
  var PYTHON_PROJECT_DIRS = ["apps", "python-packages", "libs"];
4022
4355
  function findPythonProjectDirectory(workspaceRoot, name) {
4023
4356
  return PYTHON_PROJECT_DIRS.find(
4024
- (directory) => fileExists((0, import_node_path13.join)(workspaceRoot, directory, name, "pyproject.toml"))
4357
+ (directory) => fileExists((0, import_node_path16.join)(workspaceRoot, directory, name, "pyproject.toml"))
4025
4358
  );
4026
4359
  }
4027
4360
  function parseVendorEntries(pyprojectToml) {
@@ -4060,7 +4393,7 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
4060
4393
  `No Python project named '${consumer}' with a pyproject.toml found (checked apps/, python-packages/, libs/). A Python function app has no pyproject.toml \u2014 there is nothing to vendor into.`
4061
4394
  );
4062
4395
  }
4063
- if (!fileExists((0, import_node_path13.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
4396
+ if (!fileExists((0, import_node_path16.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
4064
4397
  throw new Error(
4065
4398
  `No internal Python library named '${lib}' found at libs/${lib}/pyproject.toml. Only an internal library (added via 'mnci add python-internal-lib') can be vendored.`
4066
4399
  );
@@ -4068,8 +4401,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
4068
4401
  if (consumerDirectory === "libs" && consumer === lib) {
4069
4402
  throw new Error(`'${consumer}' cannot vendor itself.`);
4070
4403
  }
4071
- const pyprojectPath = (0, import_node_path13.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
4072
- const pyprojectToml = (0, import_node_fs10.readFileSync)(pyprojectPath, "utf8");
4404
+ const pyprojectPath = (0, import_node_path16.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
4405
+ const pyprojectToml = (0, import_node_fs13.readFileSync)(pyprojectPath, "utf8");
4073
4406
  if (parseVendorEntries(pyprojectToml).includes(lib)) {
4074
4407
  logger.info(`'${consumer}' already vendors '${lib}' \u2014 nothing to do.`);
4075
4408
  return;
@@ -4081,8 +4414,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
4081
4414
  }
4082
4415
 
4083
4416
  // src/project-scaffolding/react-app.use-case.ts
4084
- var import_node_fs11 = require("fs");
4085
- var import_node_path14 = require("path");
4417
+ var import_node_fs14 = require("fs");
4418
+ var import_node_path17 = require("path");
4086
4419
  var REACT_ENVIRONMENTS = ["dev", "uat", "prod"];
4087
4420
  function reactEnvironmentFile(environment) {
4088
4421
  return `# Vite compiles VITE_-prefixed vars into the '${environment}' bundle at build time.
@@ -4119,12 +4452,12 @@ function reactAppTargets(name) {
4119
4452
  return targets;
4120
4453
  }
4121
4454
  function allowEnvFiles(workspaceRoot) {
4122
- const gitignorePath = (0, import_node_path14.join)(workspaceRoot, ".gitignore");
4455
+ const gitignorePath = (0, import_node_path17.join)(workspaceRoot, ".gitignore");
4123
4456
  if (!fileExists(gitignorePath)) {
4124
4457
  return;
4125
4458
  }
4126
4459
  const marker = "# MoNecromanCI: keep the committed per-environment Vite config (public VITE_ values)";
4127
- const current = (0, import_node_fs11.readFileSync)(gitignorePath, "utf8");
4460
+ const current = (0, import_node_fs14.readFileSync)(gitignorePath, "utf8");
4128
4461
  if (current.includes(marker)) {
4129
4462
  return;
4130
4463
  }
@@ -4151,24 +4484,24 @@ function addReactApp(workspaceRoot, name, stack) {
4151
4484
  workspaceRoot
4152
4485
  );
4153
4486
  ensureAdmZip(workspaceRoot);
4154
- const reactAppRoot = (0, import_node_path14.join)(workspaceRoot, "apps", name);
4487
+ const reactAppRoot = (0, import_node_path17.join)(workspaceRoot, "apps", name);
4155
4488
  for (const environment of REACT_ENVIRONMENTS) {
4156
- writeFileEnsured((0, import_node_path14.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
4489
+ writeFileEnsured((0, import_node_path17.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
4157
4490
  }
4158
4491
  allowEnvFiles(workspaceRoot);
4159
- addNxTargets((0, import_node_path14.join)(reactAppRoot, "package.json"), reactAppTargets(name));
4492
+ addNxTargets((0, import_node_path17.join)(reactAppRoot, "package.json"), reactAppTargets(name));
4160
4493
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
4161
4494
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:serve` });
4162
4495
  }
4163
4496
 
4164
4497
  // src/project-scaffolding/react-lib.use-case.ts
4165
- var import_node_path15 = require("path");
4498
+ var import_node_path18 = require("path");
4166
4499
  var REACT_LIB_BUNDLER = "rollup";
4167
4500
  async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
4168
4501
  ensurePlugin(workspaceRoot, "@nx/react");
4169
4502
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
4170
- const projectRoot = (0, import_node_path15.join)(workspaceRoot, "packages", name);
4171
- const publishableManifest = (0, import_node_path15.join)(projectRoot, "package.json");
4503
+ const projectRoot = (0, import_node_path18.join)(workspaceRoot, "packages", name);
4504
+ const publishableManifest = (0, import_node_path18.join)(projectRoot, "package.json");
4172
4505
  runGeneratorAndRepair(
4173
4506
  workspaceRoot,
4174
4507
  [
@@ -4197,8 +4530,8 @@ async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
4197
4530
  }
4198
4531
  function addReactInternalLib(workspaceRoot, name, stack) {
4199
4532
  ensurePlugin(workspaceRoot, "@nx/react");
4200
- const projectRoot = (0, import_node_path15.join)(workspaceRoot, "libs", name);
4201
- const privateManifest = (0, import_node_path15.join)(projectRoot, "package.json");
4533
+ const projectRoot = (0, import_node_path18.join)(workspaceRoot, "libs", name);
4534
+ const privateManifest = (0, import_node_path18.join)(projectRoot, "package.json");
4202
4535
  runGeneratorAndRepair(
4203
4536
  workspaceRoot,
4204
4537
  [
@@ -4224,8 +4557,8 @@ function addReactInternalLib(workspaceRoot, name, stack) {
4224
4557
  }
4225
4558
 
4226
4559
  // src/project-scaffolding/vscode-extension.use-case.ts
4227
- var import_node_fs12 = require("fs");
4228
- var import_node_path16 = require("path");
4560
+ var import_node_fs15 = require("fs");
4561
+ var import_node_path19 = require("path");
4229
4562
  var VSCODE_EXTENSION_SCRIPT_PATH = "tools/vscode-extension.cjs";
4230
4563
  var VSCODE_SIDECAR_TARGETS = {
4231
4564
  "win32-x64": "windows-amd64",
@@ -4409,8 +4742,8 @@ export const window = {
4409
4742
  var VSCODE_STUB_PATH = "test/vscode.stub.ts";
4410
4743
  function mapVscodeToStub(projectRoot, testRunner) {
4411
4744
  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}\` },`];
4412
- const path = (0, import_node_path16.join)(projectRoot, file);
4413
- const content = fileExists(path) ? (0, import_node_fs12.readFileSync)(path, "utf8") : "";
4745
+ const path = (0, import_node_path19.join)(projectRoot, file);
4746
+ const content = fileExists(path) ? (0, import_node_fs15.readFileSync)(path, "utf8") : "";
4414
4747
  const line = content.split("\n").find((candidate) => candidate.trim() === anchor);
4415
4748
  if (line === void 0) {
4416
4749
  throw new Error(`${file} has no "${anchor}" line to map the vscode module after; map 'vscode' to ${VSCODE_STUB_PATH} by hand.`);
@@ -4430,11 +4763,11 @@ function ensureVscodeToolchain(workspaceRoot) {
4430
4763
  }
4431
4764
  }
4432
4765
  function defaultPublisher(workspaceRoot) {
4433
- const { name } = readJson((0, import_node_path16.join)(workspaceRoot, "package.json"));
4766
+ const { name } = readJson((0, import_node_path19.join)(workspaceRoot, "package.json"));
4434
4767
  return (name ?? "publisher").replace(/^@/, "").split("/", 1)[0];
4435
4768
  }
4436
4769
  function reshapeManifest(projectRoot, name, publisher, typesVersion) {
4437
- const manifestPath = (0, import_node_path16.join)(projectRoot, "package.json");
4770
+ const manifestPath = (0, import_node_path19.join)(projectRoot, "package.json");
4438
4771
  const manifest = readJson(manifestPath);
4439
4772
  const { nx = {}, ...rest } = manifest;
4440
4773
  const targets = { ...nx.targets };
@@ -4498,11 +4831,11 @@ function vscodeExtensionPublishTarget(name, sidecar) {
4498
4831
  };
4499
4832
  }
4500
4833
  function addDebugLaunch(workspaceRoot, name) {
4501
- const file = (0, import_node_fs12.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
4834
+ const file = (0, import_node_fs15.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
4502
4835
  if (file === void 0) {
4503
4836
  return;
4504
4837
  }
4505
- const path = (0, import_node_path16.join)(workspaceRoot, file);
4838
+ const path = (0, import_node_path19.join)(workspaceRoot, file);
4506
4839
  const workspace = readCodeWorkspace(path) ?? {};
4507
4840
  const folder = `\${workspaceFolder:${workspace.folders?.[0]?.name ?? file.replace(/\.code-workspace$/, "")}}`;
4508
4841
  const taskLabel = `${name}: build (development)`;
@@ -4535,39 +4868,39 @@ function addDebugLaunch(workspaceRoot, name) {
4535
4868
  );
4536
4869
  }
4537
4870
  function refreshVscodeExtensionScript(workspaceRoot) {
4538
- const apps = (0, import_node_path16.join)(workspaceRoot, "apps");
4871
+ const apps = (0, import_node_path19.join)(workspaceRoot, "apps");
4539
4872
  let entries;
4540
4873
  try {
4541
- entries = (0, import_node_fs12.readdirSync)(apps);
4874
+ entries = (0, import_node_fs15.readdirSync)(apps);
4542
4875
  } catch {
4543
4876
  return false;
4544
4877
  }
4545
4878
  const hasExtension = entries.some((entry) => {
4546
- const manifestPath = (0, import_node_path16.join)(apps, entry, "package.json");
4879
+ const manifestPath = (0, import_node_path19.join)(apps, entry, "package.json");
4547
4880
  if (!fileExists(manifestPath)) {
4548
4881
  return false;
4549
4882
  }
4550
4883
  const tags = readJson(manifestPath).nx?.tags ?? [];
4551
4884
  return tags.includes(VSCODE_EXTENSION_TAG);
4552
4885
  });
4553
- const path = (0, import_node_path16.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
4554
- if (!hasExtension || fileExists(path) && (0, import_node_fs12.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
4886
+ const path = (0, import_node_path19.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
4887
+ if (!hasExtension || fileExists(path) && (0, import_node_fs15.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
4555
4888
  return false;
4556
4889
  }
4557
4890
  writeFileEnsured(path, VSCODE_EXTENSION_SCRIPT);
4558
4891
  return true;
4559
4892
  }
4560
4893
  function pinVscodeExtensionProjectNames(workspaceRoot) {
4561
- const apps = (0, import_node_path16.join)(workspaceRoot, "apps");
4894
+ const apps = (0, import_node_path19.join)(workspaceRoot, "apps");
4562
4895
  let entries;
4563
4896
  try {
4564
- entries = (0, import_node_fs12.readdirSync)(apps);
4897
+ entries = (0, import_node_fs15.readdirSync)(apps);
4565
4898
  } catch {
4566
4899
  return [];
4567
4900
  }
4568
4901
  const updated = [];
4569
4902
  for (const entry of entries) {
4570
- const manifestPath = (0, import_node_path16.join)(apps, entry, "package.json");
4903
+ const manifestPath = (0, import_node_path19.join)(apps, entry, "package.json");
4571
4904
  if (!fileExists(manifestPath)) {
4572
4905
  continue;
4573
4906
  }
@@ -4587,23 +4920,23 @@ function refreshLockFile(workspaceRoot, name) {
4587
4920
  }
4588
4921
  function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4589
4922
  const { sidecar } = options;
4590
- if (sidecar !== void 0 && !fileExists((0, import_node_path16.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
4923
+ if (sidecar !== void 0 && !fileExists((0, import_node_path19.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
4591
4924
  throw new Error(`--sidecar ${sidecar}: no Go app at apps/${sidecar}. Add it first with \`mnci add go-app ${sidecar}\`.`);
4592
4925
  }
4593
4926
  runNodeApp(workspaceRoot, name, stack, "none");
4594
4927
  ensureVscodeToolchain(workspaceRoot);
4595
- const projectRoot = (0, import_node_path16.join)(workspaceRoot, "apps", name);
4596
- const typesVersion = readJson((0, import_node_path16.join)(workspaceRoot, "node_modules/@types/vscode/package.json")).version;
4928
+ const projectRoot = (0, import_node_path19.join)(workspaceRoot, "apps", name);
4929
+ const typesVersion = readJson((0, import_node_path19.join)(workspaceRoot, "node_modules/@types/vscode/package.json")).version;
4597
4930
  reshapeManifest(projectRoot, name, options.publisher ?? defaultPublisher(workspaceRoot), typesVersion);
4598
- addVscodeTypes((0, import_node_path16.join)(projectRoot, "tsconfig.app.json"));
4599
- addVscodeTypes((0, import_node_path16.join)(projectRoot, "tsconfig.spec.json"));
4600
- writeFileEnsured((0, import_node_path16.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
4601
- writeFileEnsured((0, import_node_path16.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
4602
- writeFileEnsured((0, import_node_path16.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
4931
+ addVscodeTypes((0, import_node_path19.join)(projectRoot, "tsconfig.app.json"));
4932
+ addVscodeTypes((0, import_node_path19.join)(projectRoot, "tsconfig.spec.json"));
4933
+ writeFileEnsured((0, import_node_path19.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
4934
+ writeFileEnsured((0, import_node_path19.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
4935
+ writeFileEnsured((0, import_node_path19.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
4603
4936
  mapVscodeToStub(projectRoot, stack.testRunner);
4604
- writeFileEnsured((0, import_node_path16.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
4605
- writeFileEnsured((0, import_node_path16.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
4606
- addNxTargets((0, import_node_path16.join)(projectRoot, "package.json"), {
4937
+ writeFileEnsured((0, import_node_path19.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
4938
+ writeFileEnsured((0, import_node_path19.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
4939
+ addNxTargets((0, import_node_path19.join)(projectRoot, "package.json"), {
4607
4940
  "package": vscodeExtensionPackageTarget(name, sidecar),
4608
4941
  "nx-release-publish": vscodeExtensionPublishTarget(name, sidecar)
4609
4942
  });
@@ -4614,11 +4947,11 @@ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4614
4947
  }
4615
4948
 
4616
4949
  // src/dependency-management/sync-dependencies.use-case.ts
4617
- var import_node_path18 = require("path");
4950
+ var import_node_path21 = require("path");
4618
4951
 
4619
4952
  // src/dependency-management/manifest.repository.ts
4620
- var import_node_fs13 = require("fs");
4621
- var import_node_path17 = require("path");
4953
+ var import_node_fs16 = require("fs");
4954
+ var import_node_path20 = require("path");
4622
4955
  var ECOSYSTEMS = ["npm", "pip", "pub", "nuget", "go"];
4623
4956
  var ROOT_LABEL = "(root)";
4624
4957
  var MANIFEST_GLOBS = {
@@ -4651,23 +4984,23 @@ function projectOf(manifestRelativePath) {
4651
4984
  }
4652
4985
  function hasEcosystem(workspaceRoot, ecosystem) {
4653
4986
  if (ecosystem === "go") {
4654
- return fileExists((0, import_node_path17.join)(workspaceRoot, "go.mod"));
4987
+ return fileExists((0, import_node_path20.join)(workspaceRoot, "go.mod"));
4655
4988
  }
4656
4989
  if (ecosystem === "nuget") {
4657
- return (0, import_node_fs13.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
4990
+ return (0, import_node_fs16.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
4658
4991
  }
4659
4992
  const rootMarker = {
4660
4993
  npm: "package.json",
4661
4994
  pip: "requirements-dev.txt",
4662
4995
  pub: "pubspec.yaml"
4663
4996
  };
4664
- return fileExists((0, import_node_path17.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs13.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
4997
+ return fileExists((0, import_node_path20.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs16.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
4665
4998
  }
4666
4999
  function collectNpm(workspaceRoot) {
4667
5000
  const sites = [];
4668
- const relativePaths = ["package.json", ...(0, import_node_fs13.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
5001
+ const relativePaths = ["package.json", ...(0, import_node_fs16.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
4669
5002
  for (const relativePath of relativePaths) {
4670
- const manifestPath = (0, import_node_path17.join)(workspaceRoot, relativePath);
5003
+ const manifestPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
4671
5004
  try {
4672
5005
  const manifest = readJson(manifestPath);
4673
5006
  sites.push(...npmManifestSites(manifest, relativePath, manifestPath));
@@ -4728,17 +5061,17 @@ function collectPip(workspaceRoot) {
4728
5061
  name: parsed.name,
4729
5062
  ecosystem: "pip",
4730
5063
  project: projectOf(relativePath),
4731
- manifestPath: (0, import_node_path17.join)(workspaceRoot, relativePath),
5064
+ manifestPath: (0, import_node_path20.join)(workspaceRoot, relativePath),
4732
5065
  section,
4733
5066
  spec: parsed.spec,
4734
5067
  rewritable: parsed.rewritable && parsed.spec !== ""
4735
5068
  });
4736
5069
  };
4737
- const pyprojectPaths = (0, import_node_fs13.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
5070
+ const pyprojectPaths = (0, import_node_fs16.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
4738
5071
  for (const relativePath of pyprojectPaths) {
4739
5072
  let content;
4740
5073
  try {
4741
- content = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8");
5074
+ content = (0, import_node_fs16.readFileSync)((0, import_node_path20.join)(workspaceRoot, relativePath), "utf8");
4742
5075
  } catch {
4743
5076
  continue;
4744
5077
  }
@@ -4749,14 +5082,14 @@ function collectPip(workspaceRoot) {
4749
5082
  }
4750
5083
  const requirementsPaths = [
4751
5084
  "requirements-dev.txt",
4752
- ...(0, import_node_fs13.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
5085
+ ...(0, import_node_fs16.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
4753
5086
  ];
4754
5087
  for (const relativePath of requirementsPaths) {
4755
- if (!fileExists((0, import_node_path17.join)(workspaceRoot, relativePath))) {
5088
+ if (!fileExists((0, import_node_path20.join)(workspaceRoot, relativePath))) {
4756
5089
  continue;
4757
5090
  }
4758
5091
  const section = relativePath === "requirements-dev.txt" ? "devDep" : "dep";
4759
- const lines = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
5092
+ const lines = (0, import_node_fs16.readFileSync)((0, import_node_path20.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
4760
5093
  for (const line of lines) {
4761
5094
  push(relativePath, section, line);
4762
5095
  }
@@ -4794,11 +5127,11 @@ function pyprojectDependencies(content) {
4794
5127
  }
4795
5128
  function collectPub(workspaceRoot) {
4796
5129
  const sites = [];
4797
- const pubspecPaths = (0, import_node_fs13.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
5130
+ const pubspecPaths = (0, import_node_fs16.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
4798
5131
  for (const relativePath of pubspecPaths) {
4799
5132
  let content;
4800
5133
  try {
4801
- content = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8");
5134
+ content = (0, import_node_fs16.readFileSync)((0, import_node_path20.join)(workspaceRoot, relativePath), "utf8");
4802
5135
  } catch {
4803
5136
  continue;
4804
5137
  }
@@ -4808,7 +5141,7 @@ function collectPub(workspaceRoot) {
4808
5141
  name: entry.name,
4809
5142
  ecosystem: "pub",
4810
5143
  project: projectOf(relativePath),
4811
- manifestPath: (0, import_node_path17.join)(workspaceRoot, relativePath),
5144
+ manifestPath: (0, import_node_path20.join)(workspaceRoot, relativePath),
4812
5145
  section: block === "dependencies" ? "dep" : "devDep",
4813
5146
  spec: entry.spec,
4814
5147
  rewritable: entry.spec !== ""
@@ -4858,11 +5191,11 @@ function stripQuotes(value) {
4858
5191
  }
4859
5192
  function collectNuget(workspaceRoot) {
4860
5193
  const sites = [];
4861
- const csprojPaths = (0, import_node_fs13.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
5194
+ const csprojPaths = (0, import_node_fs16.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
4862
5195
  for (const relativePath of csprojPaths) {
4863
5196
  let content;
4864
5197
  try {
4865
- content = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8");
5198
+ content = (0, import_node_fs16.readFileSync)((0, import_node_path20.join)(workspaceRoot, relativePath), "utf8");
4866
5199
  } catch {
4867
5200
  continue;
4868
5201
  }
@@ -4871,7 +5204,7 @@ function collectNuget(workspaceRoot) {
4871
5204
  name: entry.name,
4872
5205
  ecosystem: "nuget",
4873
5206
  project: projectOf(relativePath),
4874
- manifestPath: (0, import_node_path17.join)(workspaceRoot, relativePath),
5207
+ manifestPath: (0, import_node_path20.join)(workspaceRoot, relativePath),
4875
5208
  section: "dep",
4876
5209
  spec: entry.spec,
4877
5210
  // A plain SemVer string is rewritable; an MSBuild property reference
@@ -4896,13 +5229,13 @@ function csprojPackageReferences(content) {
4896
5229
  return entries;
4897
5230
  }
4898
5231
  function collectGo(workspaceRoot) {
4899
- const manifestPath = (0, import_node_path17.join)(workspaceRoot, "go.mod");
5232
+ const manifestPath = (0, import_node_path20.join)(workspaceRoot, "go.mod");
4900
5233
  if (!fileExists(manifestPath)) {
4901
5234
  return [];
4902
5235
  }
4903
5236
  let content;
4904
5237
  try {
4905
- content = (0, import_node_fs13.readFileSync)(manifestPath, "utf8");
5238
+ content = (0, import_node_fs16.readFileSync)(manifestPath, "utf8");
4906
5239
  } catch {
4907
5240
  return [];
4908
5241
  }
@@ -4959,7 +5292,7 @@ function rewriteSpec(site, spec) {
4959
5292
  writeFileEnsured(site.manifestPath, toJson(manifest));
4960
5293
  return true;
4961
5294
  }
4962
- const before = (0, import_node_fs13.readFileSync)(site.manifestPath, "utf8");
5295
+ const before = (0, import_node_fs16.readFileSync)(site.manifestPath, "utf8");
4963
5296
  const after = (() => {
4964
5297
  switch (site.ecosystem) {
4965
5298
  case "pip": {
@@ -5015,13 +5348,13 @@ function escapeForRegex(value) {
5015
5348
  function isWorkspaceProject(workspaceRoot, name) {
5016
5349
  const short = name.includes("/") ? name.split("/").at(-1) : name;
5017
5350
  return ["apps", "libs", "packages"].some(
5018
- (directory) => fileExists((0, import_node_path17.join)(workspaceRoot, directory, short ?? name, "package.json"))
5351
+ (directory) => fileExists((0, import_node_path20.join)(workspaceRoot, directory, short ?? name, "package.json"))
5019
5352
  );
5020
5353
  }
5021
5354
  function isAliasedInstall(workspaceRoot, name) {
5022
5355
  try {
5023
5356
  const installed = readJson(
5024
- (0, import_node_path17.join)(workspaceRoot, "node_modules", name, "package.json")
5357
+ (0, import_node_path20.join)(workspaceRoot, "node_modules", name, "package.json")
5025
5358
  );
5026
5359
  return installed.name !== void 0 && installed.name !== name;
5027
5360
  } catch {
@@ -5032,14 +5365,14 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
5032
5365
  if (ecosystem === "npm") {
5033
5366
  try {
5034
5367
  return readJson(
5035
- (0, import_node_path17.join)(workspaceRoot, "node_modules", name, "package.json")
5368
+ (0, import_node_path20.join)(workspaceRoot, "node_modules", name, "package.json")
5036
5369
  ).version;
5037
5370
  } catch {
5038
5371
  return void 0;
5039
5372
  }
5040
5373
  }
5041
5374
  if (ecosystem === "pub") {
5042
- const lockPath = (0, import_node_path17.join)(workspaceRoot, "pubspec.lock");
5375
+ const lockPath = (0, import_node_path20.join)(workspaceRoot, "pubspec.lock");
5043
5376
  if (!fileExists(lockPath)) {
5044
5377
  return void 0;
5045
5378
  }
@@ -5047,7 +5380,7 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
5047
5380
  const match = new RegExp(
5048
5381
  String.raw`^\s{2}${escapeForRegex(name)}:[^]*?^\s+version:\s*["']?([^"'\s]+)`,
5049
5382
  "m"
5050
- ).exec((0, import_node_fs13.readFileSync)(lockPath, "utf8"));
5383
+ ).exec((0, import_node_fs16.readFileSync)(lockPath, "utf8"));
5051
5384
  return match?.[1];
5052
5385
  } catch {
5053
5386
  return void 0;
@@ -5239,7 +5572,7 @@ function describe(finding) {
5239
5572
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
5240
5573
  }
5241
5574
  function runSync(workspaceRoot, options) {
5242
- if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
5575
+ if (!fileExists((0, import_node_path21.join)(workspaceRoot, "nx.json"))) {
5243
5576
  throw new Error(
5244
5577
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
5245
5578
  );
@@ -5289,7 +5622,7 @@ function runSync(workspaceRoot, options) {
5289
5622
  }
5290
5623
 
5291
5624
  // src/dependency-management/update-dependencies.use-case.ts
5292
- var import_node_path19 = require("path");
5625
+ var import_node_path22 = require("path");
5293
5626
  var import_prompts2 = require("@inquirer/prompts");
5294
5627
 
5295
5628
  // src/dependency-management/registry.client.ts
@@ -5572,7 +5905,7 @@ function reinstall(workspaceRoot, ecosystems) {
5572
5905
  function hasPythonInstallScript(workspaceRoot) {
5573
5906
  try {
5574
5907
  const manifest = readJson(
5575
- (0, import_node_path19.join)(workspaceRoot, "package.json")
5908
+ (0, import_node_path22.join)(workspaceRoot, "package.json")
5576
5909
  );
5577
5910
  return manifest.scripts?.["python:install"] !== void 0;
5578
5911
  } catch {
@@ -5588,7 +5921,7 @@ function applyGoUpdates(workspaceRoot, entries) {
5588
5921
  }
5589
5922
  }
5590
5923
  async function runUp(workspaceRoot, options) {
5591
- if (!fileExists((0, import_node_path19.join)(workspaceRoot, "nx.json"))) {
5924
+ if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
5592
5925
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
5593
5926
  }
5594
5927
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -5664,7 +5997,7 @@ var PROJECT_KINDS = [
5664
5997
  ];
5665
5998
  async function runAdd(kind, name, options) {
5666
5999
  const workspaceRoot = process.cwd();
5667
- if (!fileExists((0, import_node_path20.join)(workspaceRoot, "nx.json"))) {
6000
+ if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
5668
6001
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
5669
6002
  }
5670
6003
  const stack = readWorkspaceStack(workspaceRoot);
@@ -5673,8 +6006,12 @@ async function runAdd(kind, name, options) {
5673
6006
  message: "What kind of project?",
5674
6007
  choices: PROJECT_KINDS.map((value) => ({ name: value, value }))
5675
6008
  });
5676
- for (const [flag, requested] of [["--release", options.release], ["--cgo", options.cgo]]) {
5677
- if (resolvedKind !== "go-app" && requested === true) {
6009
+ for (const [flag, requested] of [
6010
+ ["--release", options.release === true],
6011
+ ["--cgo", options.cgo === true],
6012
+ ["--web", options.web !== void 0]
6013
+ ]) {
6014
+ if (resolvedKind !== "go-app" && requested) {
5678
6015
  throw new Error(`${flag} applies to go-app only, not ${resolvedKind}.`);
5679
6016
  }
5680
6017
  }
@@ -5720,8 +6057,8 @@ async function runAdd(kind, name, options) {
5720
6057
  ],
5721
6058
  workspaceRoot
5722
6059
  );
5723
- markPrivate((0, import_node_path20.join)(workspaceRoot, "libs", resolvedName, "package.json"));
5724
- renameScaffoldPlaceholder((0, import_node_path20.join)(workspaceRoot, "libs", resolvedName), resolvedName);
6060
+ markPrivate((0, import_node_path23.join)(workspaceRoot, "libs", resolvedName, "package.json"));
6061
+ renameScaffoldPlaceholder((0, import_node_path23.join)(workspaceRoot, "libs", resolvedName), resolvedName);
5725
6062
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
5726
6063
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
5727
6064
  break;
@@ -5743,7 +6080,7 @@ async function runAdd(kind, name, options) {
5743
6080
  break;
5744
6081
  }
5745
6082
  case "go-app": {
5746
- addGoApp(workspaceRoot, resolvedName, { release: options.release, cgo: options.cgo });
6083
+ addGoApp(workspaceRoot, resolvedName, { release: options.release, cgo: options.cgo, web: options.web });
5747
6084
  break;
5748
6085
  }
5749
6086
  case "go-function-app": {
@@ -5813,7 +6150,7 @@ async function runAdd(kind, name, options) {
5813
6150
  }
5814
6151
  function readWorkspaceStack(workspaceRoot) {
5815
6152
  const nxJson = readJson(
5816
- (0, import_node_path20.join)(workspaceRoot, "nx.json")
6153
+ (0, import_node_path23.join)(workspaceRoot, "nx.json")
5817
6154
  );
5818
6155
  const stack = nxJson.mnci?.stack;
5819
6156
  return {
@@ -5823,15 +6160,15 @@ function readWorkspaceStack(workspaceRoot) {
5823
6160
 
5824
6161
  // src/workspace-diagnostics/check-invariants.use-case.ts
5825
6162
  var import_node_child_process = require("child_process");
5826
- var import_node_fs14 = require("fs");
5827
- var import_node_path21 = require("path");
6163
+ var import_node_fs17 = require("fs");
6164
+ var import_node_path24 = require("path");
5828
6165
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
5829
6166
  function toPosix2(path) {
5830
6167
  return path.replaceAll("\\", "/");
5831
6168
  }
5832
6169
  function checkEslintConfigs(workspaceRoot) {
5833
- const rootConfigs = (0, import_node_fs14.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
5834
- const projectConfigs = (0, import_node_fs14.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
6170
+ const rootConfigs = (0, import_node_fs17.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
6171
+ const projectConfigs = (0, import_node_fs17.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
5835
6172
  cwd: workspaceRoot
5836
6173
  }).map((config) => toPosix2(config));
5837
6174
  return [
@@ -5851,10 +6188,10 @@ function checkEslintConfigs(workspaceRoot) {
5851
6188
  ];
5852
6189
  }
5853
6190
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
5854
- const rules = (0, import_node_path21.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
5855
- if (!(0, import_node_fs14.existsSync)(rules)) return [];
5856
- const entryPoint = (0, import_node_path21.join)(workspaceRoot, ESLINT_USER_FILENAME);
5857
- const source = (0, import_node_fs14.existsSync)(entryPoint) ? (0, import_node_fs14.readFileSync)(entryPoint, "utf8") : "";
6191
+ const rules = (0, import_node_path24.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
6192
+ if (!(0, import_node_fs17.existsSync)(rules)) return [];
6193
+ const entryPoint = (0, import_node_path24.join)(workspaceRoot, ESLINT_USER_FILENAME);
6194
+ const source = (0, import_node_fs17.existsSync)(entryPoint) ? (0, import_node_fs17.readFileSync)(entryPoint, "utf8") : "";
5858
6195
  return [
5859
6196
  {
5860
6197
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -5867,7 +6204,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
5867
6204
  function declaredDevDependencies(workspaceRoot) {
5868
6205
  try {
5869
6206
  const manifest = readJson(
5870
- (0, import_node_path21.join)(workspaceRoot, "package.json")
6207
+ (0, import_node_path24.join)(workspaceRoot, "package.json")
5871
6208
  );
5872
6209
  return manifest.devDependencies ?? {};
5873
6210
  } catch {
@@ -5875,7 +6212,7 @@ function declaredDevDependencies(workspaceRoot) {
5875
6212
  }
5876
6213
  }
5877
6214
  function checkNoRetiredFormatter(workspaceRoot) {
5878
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path21.join)(workspaceRoot, file)));
6215
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path24.join)(workspaceRoot, file)));
5879
6216
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
5880
6217
  const stale = [...files, ...declared];
5881
6218
  if (stale.length === 0) {
@@ -5901,7 +6238,7 @@ function checkEslintPlugin(nxJson) {
5901
6238
  };
5902
6239
  }
5903
6240
  function checkResolvedEslint(workspaceRoot) {
5904
- const manifestPath = (0, import_node_path21.join)(workspaceRoot, "node_modules/eslint/package.json");
6241
+ const manifestPath = (0, import_node_path24.join)(workspaceRoot, "node_modules/eslint/package.json");
5905
6242
  if (!fileExists(manifestPath)) {
5906
6243
  return void 0;
5907
6244
  }
@@ -5919,11 +6256,11 @@ function checkResolvedEslint(workspaceRoot) {
5919
6256
  }
5920
6257
  }
5921
6258
  function checkNpmrc(workspaceRoot, registry, scope) {
5922
- const npmrcPath = (0, import_node_path21.join)(workspaceRoot, ".npmrc");
6259
+ const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
5923
6260
  if (!registry || !fileExists(npmrcPath)) {
5924
6261
  return void 0;
5925
6262
  }
5926
- const npmrc = (0, import_node_fs14.readFileSync)(npmrcPath, "utf8");
6263
+ const npmrc = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8");
5927
6264
  if (registry.kind === "npm") {
5928
6265
  return {
5929
6266
  check: ".npmrc authenticates the public registry",
@@ -5940,11 +6277,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
5940
6277
  };
5941
6278
  }
5942
6279
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
5943
- const npmrcPath = (0, import_node_path21.join)(workspaceRoot, ".npmrc");
6280
+ const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
5944
6281
  if (!fileExists(npmrcPath)) {
5945
6282
  return void 0;
5946
6283
  }
5947
- const npmrc = (0, import_node_fs14.readFileSync)(npmrcPath, "utf8");
6284
+ const npmrc = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8");
5948
6285
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5949
6286
  const referenced = [
5950
6287
  ...new Set(
@@ -5968,13 +6305,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
5968
6305
  };
5969
6306
  }
5970
6307
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
5971
- const npmrcPath = (0, import_node_path21.join)(workspaceRoot, ".npmrc");
5972
- const pipelinePath = (0, import_node_path21.join)(workspaceRoot, "azure-pipelines.yml");
6308
+ const npmrcPath = (0, import_node_path24.join)(workspaceRoot, ".npmrc");
6309
+ const pipelinePath = (0, import_node_path24.join)(workspaceRoot, "azure-pipelines.yml");
5973
6310
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
5974
6311
  return void 0;
5975
6312
  }
5976
- const holdsCredentials = (0, import_node_fs14.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5977
- const runsTask = (0, import_node_fs14.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
6313
+ const holdsCredentials = (0, import_node_fs17.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
6314
+ const runsTask = (0, import_node_fs17.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
5978
6315
  if (!holdsCredentials && !runsTask) {
5979
6316
  return {
5980
6317
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -6019,13 +6356,13 @@ function npmjsCredentialShape(credentials, environment) {
6019
6356
  }
6020
6357
  function checkVersionActions(workspaceRoot) {
6021
6358
  const candidates = [
6022
- ...(0, import_node_fs14.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
6023
- ...(0, import_node_fs14.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
6024
- ...(0, import_node_fs14.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
6359
+ ...(0, import_node_fs17.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
6360
+ ...(0, import_node_fs17.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
6361
+ ...(0, import_node_fs17.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
6025
6362
  ].map((manifest) => toPosix2(manifest));
6026
6363
  return candidates.flatMap((manifest) => {
6027
6364
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
6028
- const projectJsonPath = (0, import_node_path21.join)(workspaceRoot, projectRoot, "project.json");
6365
+ const projectJsonPath = (0, import_node_path24.join)(workspaceRoot, projectRoot, "project.json");
6029
6366
  let hasOverride = false;
6030
6367
  try {
6031
6368
  const projectJson = readJson(projectJsonPath);
@@ -6054,7 +6391,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
6054
6391
  ]) {
6055
6392
  try {
6056
6393
  const targets = extract(
6057
- readJson((0, import_node_path21.join)(workspaceRoot, projectRoot, file))
6394
+ readJson((0, import_node_path24.join)(workspaceRoot, projectRoot, file))
6058
6395
  );
6059
6396
  if (targets && typeof targets === "object") {
6060
6397
  sources.push({
@@ -6070,8 +6407,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
6070
6407
  function checkTargetFilesExist(workspaceRoot) {
6071
6408
  const projectRoots = new Set(
6072
6409
  [
6073
- ...(0, import_node_fs14.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
6074
- ...(0, import_node_fs14.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
6410
+ ...(0, import_node_fs17.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
6411
+ ...(0, import_node_fs17.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
6075
6412
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
6076
6413
  );
6077
6414
  return [...projectRoots].flatMap(
@@ -6086,7 +6423,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
6086
6423
  return TARGET_FILE_OPTIONS.flatMap((option) => {
6087
6424
  const value = target?.options?.[option];
6088
6425
  const checkable = typeof value === "string" && !value.includes("{");
6089
- if (!checkable || fileExists((0, import_node_path21.join)(workspaceRoot, value))) {
6426
+ if (!checkable || fileExists((0, import_node_path24.join)(workspaceRoot, value))) {
6090
6427
  return [];
6091
6428
  }
6092
6429
  return [
@@ -6111,6 +6448,17 @@ function hasCCompiler() {
6111
6448
  const candidates = [process.env.CC?.split(" ", 1)[0], "gcc", "clang", "cc"];
6112
6449
  return candidates.some((command) => command !== void 0 && command !== "" && (0, import_node_child_process.spawnSync)(command, ["--version"], { stdio: "ignore" }).status === 0);
6113
6450
  }
6451
+ function checkGoPluginRegistered(workspaceRoot) {
6452
+ if (!hasGoProject(workspaceRoot)) {
6453
+ return void 0;
6454
+ }
6455
+ return {
6456
+ check: `${NX_GO_PLUGIN} is registered in nx.json, so Nx knows which Go project imports which`,
6457
+ ok: isNxGoPluginRegistered(workspaceRoot),
6458
+ detail: `${NX_GO_PLUGIN} is not in nx.json plugins: the project graph has no Go edge, so \`nx affected\` skips an app that imports a changed library`,
6459
+ remedy: "run `mnci upgrade`"
6460
+ };
6461
+ }
6114
6462
  function checkNativeApps(workspaceRoot) {
6115
6463
  if (!hasNativeGoApp(workspaceRoot)) {
6116
6464
  return [];
@@ -6119,9 +6467,9 @@ function checkNativeApps(workspaceRoot) {
6119
6467
  { file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
6120
6468
  { file: "azure-pipelines.yml", marker: "- job: native" }
6121
6469
  ];
6122
- const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path21.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6470
+ const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path24.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6123
6471
  check: `${file} builds the native apps on every OS`,
6124
- ok: (0, import_node_fs14.readFileSync)((0, import_node_path21.join)(workspaceRoot, file), "utf8").includes(marker),
6472
+ ok: (0, import_node_fs17.readFileSync)((0, import_node_path24.join)(workspaceRoot, file), "utf8").includes(marker),
6125
6473
  detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
6126
6474
  remedy: "run `mnci upgrade`"
6127
6475
  }));
@@ -6134,7 +6482,7 @@ function checkNativeApps(workspaceRoot) {
6134
6482
  return findings;
6135
6483
  }
6136
6484
  function checkNoRootRuntimeDependencies(workspaceRoot) {
6137
- const manifestPath = (0, import_node_path21.join)(workspaceRoot, "package.json");
6485
+ const manifestPath = (0, import_node_path24.join)(workspaceRoot, "package.json");
6138
6486
  if (!fileExists(manifestPath)) {
6139
6487
  return void 0;
6140
6488
  }
@@ -6154,14 +6502,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
6154
6502
  };
6155
6503
  }
6156
6504
  function checkRollupSourceMaps(workspaceRoot) {
6157
- const configs = (0, import_node_fs14.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6505
+ const configs = (0, import_node_fs17.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6158
6506
  cwd: workspaceRoot
6159
6507
  }).map((config) => toPosix2(config));
6160
6508
  return configs.flatMap((relativePath) => {
6161
- const configPath = (0, import_node_path21.join)(workspaceRoot, relativePath);
6509
+ const configPath = (0, import_node_path24.join)(workspaceRoot, relativePath);
6162
6510
  let config;
6163
6511
  try {
6164
- config = (0, import_node_fs14.readFileSync)(configPath, "utf8");
6512
+ config = (0, import_node_fs17.readFileSync)(configPath, "utf8");
6165
6513
  } catch {
6166
6514
  return [];
6167
6515
  }
@@ -6176,11 +6524,11 @@ function checkRollupSourceMaps(workspaceRoot) {
6176
6524
  });
6177
6525
  }
6178
6526
  function checkDeclarationSpecifiers(workspaceRoot) {
6179
- const configs = (0, import_node_fs14.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6527
+ const configs = (0, import_node_fs17.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6180
6528
  cwd: workspaceRoot
6181
6529
  }).map((config) => toPosix2(config));
6182
6530
  return configs.flatMap((relativePath) => {
6183
- const configPath = (0, import_node_path21.join)(workspaceRoot, relativePath);
6531
+ const configPath = (0, import_node_path24.join)(workspaceRoot, relativePath);
6184
6532
  if (!fileExists(configPath)) {
6185
6533
  return [];
6186
6534
  }
@@ -6214,7 +6562,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
6214
6562
  });
6215
6563
  }
6216
6564
  function collectFindings(workspaceRoot) {
6217
- const nxJsonPath = (0, import_node_path21.join)(workspaceRoot, "nx.json");
6565
+ const nxJsonPath = (0, import_node_path24.join)(workspaceRoot, "nx.json");
6218
6566
  if (!fileExists(nxJsonPath)) {
6219
6567
  throw new Error(
6220
6568
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -6235,6 +6583,7 @@ function collectFindings(workspaceRoot) {
6235
6583
  ...checkVersionActions(workspaceRoot),
6236
6584
  ...checkTargetFilesExist(workspaceRoot),
6237
6585
  checkSync(workspaceRoot),
6586
+ checkGoPluginRegistered(workspaceRoot),
6238
6587
  ...checkNativeApps(workspaceRoot)
6239
6588
  ].filter((finding) => finding !== void 0);
6240
6589
  }
@@ -6260,8 +6609,8 @@ function runDoctor(workspaceRoot) {
6260
6609
  }
6261
6610
 
6262
6611
  // src/workspace-creation/adopt-directory.use-case.ts
6263
- var import_node_fs15 = require("fs");
6264
- var import_node_path22 = require("path");
6612
+ var import_node_fs18 = require("fs");
6613
+ var import_node_path25 = require("path");
6265
6614
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
6266
6615
  var AGENT_AND_CI_ENTRIES = [
6267
6616
  "AGENTS.md",
@@ -6292,13 +6641,13 @@ var PREFLIGHT_BLOCKERS = [
6292
6641
  "packages"
6293
6642
  ];
6294
6643
  function assertAdoptableDirectory(target) {
6295
- if (!(0, import_node_fs15.existsSync)(target)) {
6644
+ if (!(0, import_node_fs18.existsSync)(target)) {
6296
6645
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
6297
6646
  }
6298
- if (!(0, import_node_fs15.statSync)(target).isDirectory()) {
6647
+ if (!(0, import_node_fs18.statSync)(target).isDirectory()) {
6299
6648
  throw new Error(`--into '${target}' is not a directory.`);
6300
6649
  }
6301
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs15.existsSync)((0, import_node_path22.join)(target, entry)));
6650
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs18.existsSync)((0, import_node_path25.join)(target, entry)));
6302
6651
  if (blockers.length > 0) {
6303
6652
  throw new Error(
6304
6653
  `--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.`
@@ -6306,15 +6655,15 @@ function assertAdoptableDirectory(target) {
6306
6655
  }
6307
6656
  }
6308
6657
  function mergeGitignore(generatedFile, targetFile) {
6309
- const existing = (0, import_node_fs15.readFileSync)(targetFile, "utf8");
6658
+ const existing = (0, import_node_fs18.readFileSync)(targetFile, "utf8");
6310
6659
  const present = new Set(existing.split("\n").map((line) => line.trim()));
6311
- const additions = (0, import_node_fs15.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
6660
+ const additions = (0, import_node_fs18.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
6312
6661
  const trimmed = line.trim();
6313
6662
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
6314
6663
  });
6315
6664
  if (additions.length === 0) return false;
6316
6665
  const separator = existing.endsWith("\n") ? "" : "\n";
6317
- (0, import_node_fs15.writeFileSync)(
6666
+ (0, import_node_fs18.writeFileSync)(
6318
6667
  targetFile,
6319
6668
  `${existing}${separator}
6320
6669
  # Added by mnci (Nx workspace)
@@ -6324,9 +6673,9 @@ ${additions.join("\n")}
6324
6673
  return true;
6325
6674
  }
6326
6675
  function adoptGeneratedWorkspace(generatedRoot, target) {
6327
- const entries = (0, import_node_fs15.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6676
+ const entries = (0, import_node_fs18.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6328
6677
  const collisions = entries.filter(
6329
- (entry) => (0, import_node_fs15.existsSync)((0, import_node_path22.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6678
+ (entry) => (0, import_node_fs18.existsSync)((0, import_node_path25.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6330
6679
  );
6331
6680
  if (collisions.length > 0) {
6332
6681
  throw new Error(
@@ -6335,28 +6684,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
6335
6684
  }
6336
6685
  const result = { copied: [], kept: [], mergedGitignore: false };
6337
6686
  for (const entry of entries) {
6338
- const from = (0, import_node_path22.join)(generatedRoot, entry);
6339
- const to = (0, import_node_path22.join)(target, entry);
6340
- if (entry === ".gitignore" && (0, import_node_fs15.existsSync)(to)) {
6687
+ const from = (0, import_node_path25.join)(generatedRoot, entry);
6688
+ const to = (0, import_node_path25.join)(target, entry);
6689
+ if (entry === ".gitignore" && (0, import_node_fs18.existsSync)(to)) {
6341
6690
  result.mergedGitignore = mergeGitignore(from, to);
6342
6691
  result.kept.push(entry);
6343
6692
  continue;
6344
6693
  }
6345
- if ((0, import_node_fs15.existsSync)(to)) {
6694
+ if ((0, import_node_fs18.existsSync)(to)) {
6346
6695
  result.kept.push(entry);
6347
6696
  continue;
6348
6697
  }
6349
- (0, import_node_fs15.cpSync)(from, to, { recursive: true });
6698
+ (0, import_node_fs18.cpSync)(from, to, { recursive: true });
6350
6699
  result.copied.push(entry);
6351
6700
  }
6352
- (0, import_node_fs15.rmSync)(generatedRoot, { recursive: true, force: true });
6701
+ (0, import_node_fs18.rmSync)(generatedRoot, { recursive: true, force: true });
6353
6702
  return result;
6354
6703
  }
6355
6704
 
6356
6705
  // src/workspace-creation/create-workspace.use-case.ts
6357
- var import_node_fs16 = require("fs");
6706
+ var import_node_fs19 = require("fs");
6358
6707
  var import_node_os = require("os");
6359
- var import_node_path23 = require("path");
6708
+ var import_node_path26 = require("path");
6360
6709
  function nxCloudProviderValue(ci) {
6361
6710
  return ci === "azure" ? "azure" : "github";
6362
6711
  }
@@ -6392,9 +6741,9 @@ async function resolveRegistry(options) {
6392
6741
  return await promptRegistry();
6393
6742
  }
6394
6743
  async function runNew(name, options) {
6395
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path23.resolve)(process.cwd(), options.into);
6744
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path26.resolve)(process.cwd(), options.into);
6396
6745
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
6397
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path23.basename)(adoptTarget));
6746
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path26.basename)(adoptTarget));
6398
6747
  assertValidProjectName(workspaceName, "Workspace name");
6399
6748
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
6400
6749
  const registry = await resolveRegistry(options);
@@ -6407,8 +6756,8 @@ async function runNew(name, options) {
6407
6756
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
6408
6757
  const stack = await resolveStack(options);
6409
6758
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
6410
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs16.mkdtempSync)((0, import_node_path23.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
6411
- let workspaceRoot = (0, import_node_path23.join)(stagingParent, workspaceName);
6759
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs19.mkdtempSync)((0, import_node_path26.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
6760
+ let workspaceRoot = (0, import_node_path26.join)(stagingParent, workspaceName);
6412
6761
  try {
6413
6762
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
6414
6763
  runNpx(
@@ -6431,7 +6780,7 @@ async function runNew(name, options) {
6431
6780
  workspaceRoot = adoptTarget;
6432
6781
  }
6433
6782
  } finally {
6434
- if (adoptTarget !== void 0) (0, import_node_fs16.rmSync)(stagingParent, { recursive: true, force: true });
6783
+ if (adoptTarget !== void 0) (0, import_node_fs19.rmSync)(stagingParent, { recursive: true, force: true });
6435
6784
  }
6436
6785
  logger.step(
6437
6786
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -6441,8 +6790,8 @@ async function runNew(name, options) {
6441
6790
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
6442
6791
  logger.detail
6443
6792
  );
6444
- (0, import_node_fs16.rmSync)((0, import_node_path23.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
6445
- (0, import_node_fs16.rmSync)((0, import_node_path23.join)(workspaceRoot, "package-lock.json"), { force: true });
6793
+ (0, import_node_fs19.rmSync)((0, import_node_path26.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
6794
+ (0, import_node_fs19.rmSync)((0, import_node_path26.join)(workspaceRoot, "package-lock.json"), { force: true });
6446
6795
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
6447
6796
  const installStatus = runShell(
6448
6797
  "npm",
@@ -6473,12 +6822,12 @@ async function runNew(name, options) {
6473
6822
  }
6474
6823
 
6475
6824
  // src/workspace-creation/interactive-wizard.use-case.ts
6476
- var import_node_path25 = require("path");
6825
+ var import_node_path28 = require("path");
6477
6826
  var import_prompts4 = require("@inquirer/prompts");
6478
6827
 
6479
6828
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
6480
- var import_node_fs17 = require("fs");
6481
- var import_node_path24 = require("path");
6829
+ var import_node_fs20 = require("fs");
6830
+ var import_node_path27 = require("path");
6482
6831
  function resolveRegistry2(options, persisted) {
6483
6832
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
6484
6833
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -6507,7 +6856,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6507
6856
  return persisted.workspaceName;
6508
6857
  }
6509
6858
  try {
6510
- const existing = (0, import_node_fs17.readdirSync)(workspaceRoot).find(
6859
+ const existing = (0, import_node_fs20.readdirSync)(workspaceRoot).find(
6511
6860
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
6512
6861
  );
6513
6862
  if (existing) {
@@ -6515,11 +6864,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6515
6864
  }
6516
6865
  } catch {
6517
6866
  }
6518
- return (0, import_node_path24.basename)(workspaceRoot);
6867
+ return (0, import_node_path27.basename)(workspaceRoot);
6519
6868
  }
6520
6869
  function detectNpmAuth(workspaceRoot) {
6521
6870
  try {
6522
- return (0, import_node_fs17.readFileSync)((0, import_node_path24.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6871
+ return (0, import_node_fs20.readFileSync)((0, import_node_path27.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6523
6872
  } catch {
6524
6873
  return void 0;
6525
6874
  }
@@ -6566,7 +6915,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
6566
6915
  };
6567
6916
  }
6568
6917
  function runUpgrade(workspaceRoot, options) {
6569
- if (!fileExists((0, import_node_path24.join)(workspaceRoot, "nx.json"))) {
6918
+ if (!fileExists((0, import_node_path27.join)(workspaceRoot, "nx.json"))) {
6570
6919
  throw new Error(
6571
6920
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
6572
6921
  );
@@ -6611,6 +6960,10 @@ function runUpgrade(workspaceRoot, options) {
6611
6960
  logger.step("Updating the releasable Go app script");
6612
6961
  logger.detail(`updated ${GO_RELEASE_SCRIPT_PATH}`);
6613
6962
  }
6963
+ if (hasGoProject(workspaceRoot) && registerNxGoPlugin(workspaceRoot)) {
6964
+ logger.step("Registering the Go plugin in nx.json, so Nx can see which Go project imports which");
6965
+ logger.detail("updated nx.json");
6966
+ }
6614
6967
  const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
6615
6968
  if (upgradedDtsPlugins.length > 0) {
6616
6969
  logger.step("Upgrading declaration specifiers to resolve under nodenext");
@@ -6627,7 +6980,7 @@ function runUpgrade(workspaceRoot, options) {
6627
6980
 
6628
6981
  // src/workspace-creation/interactive-wizard.use-case.ts
6629
6982
  async function runInteractive() {
6630
- const inWorkspace = fileExists((0, import_node_path25.join)(process.cwd(), "nx.json"));
6983
+ const inWorkspace = fileExists((0, import_node_path28.join)(process.cwd(), "nx.json"));
6631
6984
  const choiceNew = { name: "Create a new monorepo", value: "new" };
6632
6985
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
6633
6986
  const choiceUpgrade = {
@@ -6648,8 +7001,8 @@ async function runInteractive() {
6648
7001
  }
6649
7002
 
6650
7003
  // src/cli-version/check-for-update.use-case.ts
6651
- var import_node_fs18 = require("fs");
6652
- var import_node_path26 = require("path");
7004
+ var import_node_fs21 = require("fs");
7005
+ var import_node_path29 = require("path");
6653
7006
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
6654
7007
  var PACKAGE_NAME = "@mnci/cli";
6655
7008
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -6705,8 +7058,8 @@ function releaseTriple(version) {
6705
7058
  }
6706
7059
  function readCliVersion(packageDirectory) {
6707
7060
  try {
6708
- const manifestPath = (0, import_node_path26.join)(packageDirectory, "..", "package.json");
6709
- const manifest = JSON.parse((0, import_node_fs18.readFileSync)(manifestPath, "utf8"));
7061
+ const manifestPath = (0, import_node_path29.join)(packageDirectory, "..", "package.json");
7062
+ const manifest = JSON.parse((0, import_node_fs21.readFileSync)(manifestPath, "utf8"));
6710
7063
  return manifest.version ?? "0.0.0";
6711
7064
  } catch {
6712
7065
  return "0.0.0";
@@ -6745,6 +7098,11 @@ function buildProgram(cliVersion) {
6745
7098
  ).action(() => {
6746
7099
  runDoctor(process.cwd());
6747
7100
  });
7101
+ program.command("ci").addArgument(new import_commander.Argument("<phase>", "which phase of the pipeline to run").choices(CI_PHASES)).description(
7102
+ "Run a phase of the CI pipeline here, the same way CI runs it: `verify` is the sync check and then every project (or, in a pull request, the affected ones) through lint, typecheck, test and build. Exits non-zero when it fails"
7103
+ ).action((phase) => {
7104
+ process.exitCode = runCiPhase(phase, process.cwd());
7105
+ });
6748
7106
  program.command("sync").description(
6749
7107
  "Make every project agree: converge external dependency ranges declared at more than one version, then run 'nx sync' for TypeScript project references. Go is a no-op \u2014 one root go.mod means one version of every module"
6750
7108
  ).option("--check", "report drift and exit non-zero without writing anything").option("--ecosystem <name>", "restrict to one ecosystem: npm | pip | pub | go").action((options) => {
@@ -6773,6 +7131,9 @@ function buildProgram(cliVersion) {
6773
7131
  ).option(
6774
7132
  "--cgo",
6775
7133
  "go-app only: the app needs a C toolchain (a tray icon, a native GUI, a cgo driver), so CI builds it on a runner of each OS instead of cross-compiling"
7134
+ ).option(
7135
+ "--web <react-app>",
7136
+ "go-app only: embed and serve this React app (apps/<react-app>, added first): built before the Go app, staged for go:embed, with a dev target that runs both"
6776
7137
  ).action(
6777
7138
  async (kind, name, options) => {
6778
7139
  await runAdd(kind, name, options);