@mnci/cli 4.13.1 → 4.15.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
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(main_exports);
38
38
  var import_commander = require("commander");
39
39
 
40
40
  // src/project-scaffolding/add-project.use-case.ts
41
- var import_node_path19 = require("path");
41
+ var import_node_path20 = require("path");
42
42
  var import_prompts3 = require("@inquirer/prompts");
43
43
 
44
44
  // src/nx-workspace/nx.client.ts
@@ -434,11 +434,23 @@ ${feedShortKey}:email=npm-requires-this-and-never-uses-it
434
434
  `;
435
435
  }
436
436
  var VSCODE_EXTENSION_TAG = "type:vscode-extension";
437
+ var GO_RELEASE_TAG = "release:go";
438
+ var GO_CGO_TAG = "build:cgo";
439
+ function hasNativeGoApp(workspaceRoot) {
440
+ return (0, import_node_fs2.globSync)("apps/*/project.json", { cwd: workspaceRoot }).some((projectJson) => {
441
+ try {
442
+ const { tags } = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(workspaceRoot, projectJson), "utf8"));
443
+ return (tags ?? []).includes(GO_CGO_TAG);
444
+ } catch {
445
+ return false;
446
+ }
447
+ });
448
+ }
437
449
  function releaseConfig(ci) {
438
450
  const githubReleases = ci === "github";
439
451
  return {
440
452
  projectsRelationship: "independent",
441
- projects: ["packages/*", "python-packages/*", `tag:${VSCODE_EXTENSION_TAG}`, "!tag:type:go-lib"],
453
+ projects: ["packages/*", "python-packages/*", `tag:${VSCODE_EXTENSION_TAG}`, `tag:${GO_RELEASE_TAG}`, "!tag:type:go-lib"],
442
454
  releaseTag: { pattern: "{projectName}@{version}" },
443
455
  git: { commit: false, tag: true, push: githubReleases },
444
456
  version: {
@@ -1034,7 +1046,126 @@ var FLUTTER_TOOL_PATH_GITHUB = `node -e "${FLUTTER_TOOL_PATH_PRELUDE}if(!process
1034
1046
  var FLUTTER_PUB_GET_GUARD = `node -e "const fs=require('node:fs');if(!fs.existsSync('pubspec.yaml')){console.log('No Flutter projects - skipping.');process.exit(0)}process.exit(require('node:child_process').spawnSync('flutter',['pub','get'],{stdio:'inherit',shell:process.platform==='win32'}).status ?? 1)"`;
1035
1047
  var NPM_AUDIT_STEP = `node -e "const cp=require('node:child_process');const r=cp.spawnSync('npm',['audit','--json'],{encoding:'utf8',shell:process.platform==='win32',maxBuffer:33554432});let d;try{d=JSON.parse(r.stdout)}catch{console.log('npm audit produced no JSON (exit '+r.status+') - not blocking on a broken audit.');process.exit(0)}const all=Object.values(d.vulnerabilities||{});const BLOCK=['critical','high','moderate'];const major=v=>v.fixAvailable&&typeof v.fixAvailable==='object'&&v.fixAvailable.isSemVerMajor;const act=all.filter(v=>v.fixAvailable&&BLOCK.includes(v.severity)&&!major(v));const rest=all.filter(v=>!act.includes(v));for(const v of rest)console.log(' note ['+v.severity+'] '+v.name+(!v.fixAvailable?' - NO fix available upstream, nothing to do here':major(v)?' - only a semver-major change would remove it (often a parent downgrade), not applied automatically':' - fix available, below the blocking threshold'));if(act.length===0){console.log('npm audit - '+all.length+' advisory(ies), none actionable at moderate or above.');process.exit(0)}for(const v of act)console.log(' BLOCKING ['+v.severity+'] '+v.name+' - fix available');console.log('Each has a published fix. Add a targeted overrides entry in package.json rather than npm audit fix --force.');process.exit(1)"`;
1036
1048
  var VERIFY_TARGETS = "lint,typecheck,test,build";
1037
- var AFFECTED_OR_ALL_GUARD = `node -e "const cp=require('node:child_process');const T='${VERIFY_TARGETS}';const all=()=>process.exit(cp.spawnSync('npx nx run-many -t '+T,{stdio:'inherit',shell:true}).status ?? 1);const ref=process.env.GITHUB_BASE_REF||process.env.SYSTEM_PULLREQUEST_TARGETBRANCH||'';if(!ref){console.log('Not a pull request - verifying EVERY project.');all()}const target=ref.replace('refs/heads/','');const mergeBase=r=>{const o=cp.spawnSync('git',['merge-base',r,'HEAD'],{encoding:'utf8'});return o.status===0?o.stdout.trim():''};let base=mergeBase('origin/'+target);if(!base){console.log('No origin/'+target+' ref - fetching it to resolve a merge-base.');cp.spawnSync('git',['fetch','--no-tags','origin',target],{stdio:'inherit'});base=mergeBase('FETCH_HEAD')}if(!base){console.log('Could not resolve a merge-base with '+target+' - verifying EVERY project.');all()}console.log('Pull request against '+target+' - verifying projects affected since '+base);process.exit(cp.spawnSync('npx nx affected -t '+T+' --base='+base,{stdio:'inherit',shell:true}).status ?? 1)"`;
1049
+ function affectedOrAllGuard(exclude = "") {
1050
+ const extra = exclude === "" ? "" : `+' ${exclude}'`;
1051
+ return `node -e "const cp=require('node:child_process');const T='${VERIFY_TARGETS}';const all=()=>process.exit(cp.spawnSync('npx nx run-many -t '+T${extra},{stdio:'inherit',shell:true}).status ?? 1);const ref=process.env.GITHUB_BASE_REF||process.env.SYSTEM_PULLREQUEST_TARGETBRANCH||'';if(!ref){console.log('Not a pull request - verifying EVERY project.');all()}const target=ref.replace('refs/heads/','');const mergeBase=r=>{const o=cp.spawnSync('git',['merge-base',r,'HEAD'],{encoding:'utf8'});return o.status===0?o.stdout.trim():''};let base=mergeBase('origin/'+target);if(!base){console.log('No origin/'+target+' ref - fetching it to resolve a merge-base.');cp.spawnSync('git',['fetch','--no-tags','origin',target],{stdio:'inherit'});base=mergeBase('FETCH_HEAD')}if(!base){console.log('Could not resolve a merge-base with '+target+' - verifying EVERY project.');all()}console.log('Pull request against '+target+' - verifying projects affected since '+base);process.exit(cp.spawnSync('npx nx affected -t '+T+' --base='+base${extra},{stdio:'inherit',shell:true}).status ?? 1)"`;
1052
+ }
1053
+ var AFFECTED_OR_ALL_GUARD = affectedOrAllGuard();
1054
+ var AFFECTED_OR_ALL_GUARD_WITHOUT_NATIVE = affectedOrAllGuard(`--exclude=tag:${GO_CGO_TAG}`);
1055
+ var NATIVE_BUILD_COMMAND = `npx nx run-many -t lint,test,build-native,package-native --projects=tag:${GO_CGO_TAG}`;
1056
+ var NATIVE_LINUX_PREREQUISITES = "sudo apt-get update && sudo apt-get install -y gcc pkg-config";
1057
+ function githubNativeJob(npmAuthName, npmAuthValue, onMain) {
1058
+ return `
1059
+ # Apps that need a C toolchain (mnci add go-app --cgo) cannot be cross-compiled
1060
+ # from the job above, so each is linted, tested, built and packaged here, on a
1061
+ # runner of every OS it ships for, and is left out of that job's verify step.
1062
+ native:
1063
+ name: native (\${{ matrix.os }})
1064
+ needs: ci
1065
+ runs-on: \${{ matrix.os }}
1066
+ strategy:
1067
+ fail-fast: false
1068
+ matrix:
1069
+ os: [windows-latest, macos-latest, ubuntu-latest]
1070
+ steps:
1071
+ - uses: actions/checkout@${ACTION_VERSIONS["actions/checkout"]}
1072
+ with:
1073
+ fetch-depth: 0
1074
+
1075
+ # The release tags name the version a native build is stamped with.
1076
+ - run: git fetch --all --prune --tags
1077
+ name: Fetch branches and release tags
1078
+
1079
+ - uses: actions/setup-node@${ACTION_VERSIONS["actions/setup-node"]}
1080
+ with:
1081
+ node-version: ${NODE_VERSION}
1082
+ cache: npm
1083
+
1084
+ - run: npm install -g npm@${NPM_VERSION}
1085
+ name: Pin npm to the major mnci verifies against
1086
+
1087
+ - run: npm ci
1088
+ name: Install dependencies
1089
+ env:
1090
+ ${npmAuthName}: ${npmAuthValue}
1091
+
1092
+ - run: ${GO_MODULE_DOWNLOAD_GUARD}
1093
+ name: Download Go module dependencies
1094
+
1095
+ - run: ${GOLANGCI_LINT_INSTALL_GUARD}
1096
+ name: Install golangci-lint
1097
+
1098
+ - run: ${GO_TOOL_PATH_GITHUB}
1099
+ name: Add Go tool bin to PATH
1100
+
1101
+ # A C compiler and pkg-config, which is all mnci can know a cgo app needs.
1102
+ # Add the -dev packages your app links to this line, for example
1103
+ # libgtk-3-dev and libayatana-appindicator3-dev for a system-tray icon.
1104
+ # macOS and Windows runners ship their toolchains.
1105
+ - run: ${NATIVE_LINUX_PREREQUISITES}
1106
+ name: Install native prerequisites (Linux)
1107
+ if: \${{ runner.os == 'Linux' }}
1108
+
1109
+ - run: ${NATIVE_BUILD_COMMAND}
1110
+ name: Lint, test, build and package the native apps
1111
+
1112
+ - uses: actions/upload-artifact@${ACTION_VERSIONS["actions/upload-artifact"]}
1113
+ with:
1114
+ name: native-\${{ matrix.os }}
1115
+ path: dist/drop
1116
+ if-no-files-found: ignore
1117
+
1118
+ # A releasable native app (--cgo with --release) gets this OS's zip attached to
1119
+ # the GitHub Release the ci job just created, stamped with the tag's version.
1120
+ - run: node tools/go-app-release.cjs assets --native
1121
+ name: Attach this OS's zip to the GitHub Release (releasable native apps)
1122
+ if: \${{ ${onMain} && hashFiles('tools/go-app-release.cjs') != '' }}
1123
+ env:
1124
+ GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
1125
+ `;
1126
+ }
1127
+ function indentYaml(text, spaces) {
1128
+ const pad = " ".repeat(spaces);
1129
+ return text.split("\n").map((line) => line === "" ? line : pad + line).join("\n");
1130
+ }
1131
+ function withAzureNativeJob(document, nativeSteps) {
1132
+ const poolAt = document.indexOf("\npool:\n");
1133
+ const variablesAt = document.indexOf("\nvariables:\n");
1134
+ const stepsAt = document.indexOf("\nsteps:\n");
1135
+ if (poolAt === -1 || variablesAt < poolAt || stepsAt < variablesAt) {
1136
+ throw new Error("The Azure pipeline no longer has its pool, variables and steps blocks in that order.");
1137
+ }
1138
+ const head = document.slice(0, poolAt + 1);
1139
+ const pool2 = document.slice(poolAt + "\npool:\n".length, variablesAt).replace(/\n+$/, "");
1140
+ const variables = document.slice(variablesAt + 1, stepsAt).replace(/\n+$/, "");
1141
+ const steps = document.slice(stepsAt + "\nsteps:\n".length).replace(/\n+$/, "");
1142
+ const matrix = Object.entries({ windows: "windows-latest", macos: "macos-latest", linux: "ubuntu-latest" }).map(([leg, image]) => ` ${leg}:
1143
+ legName: ${leg}
1144
+ vmImage: ${image}`).join("\n");
1145
+ return `${head}${variables}
1146
+
1147
+ jobs:
1148
+ - job: ci
1149
+ pool:
1150
+ ${indentYaml(pool2, 4)}
1151
+ steps:
1152
+ ${indentYaml(steps, 4)}
1153
+
1154
+ # Apps that need a C toolchain (mnci add go-app --cgo) cannot be cross-compiled
1155
+ # from the job above, so each is linted, tested, built and packaged here, on an
1156
+ # agent of every OS it ships for, and is left out of that job's verify step.
1157
+ - job: native
1158
+ displayName: Native apps (cgo)
1159
+ dependsOn: ci
1160
+ strategy:
1161
+ matrix:
1162
+ ${matrix}
1163
+ pool:
1164
+ vmImage: $(vmImage)
1165
+ steps:
1166
+ ${indentYaml(nativeSteps, 4)}
1167
+ `;
1168
+ }
1038
1169
  var PACK_APPS_GUARD = `node -e "const fs=require('node:fs');fs.mkdirSync('dist/drop',{recursive:true});const hasProjectJson=fs.globSync('apps/*/project.json').length>0;const hasInlineNx=fs.globSync('apps/*/package.json').some((f)=>{try{return Boolean(JSON.parse(fs.readFileSync(f,'utf8')).nx)}catch{return false}});const hasCsproj=fs.globSync('apps/*/*.csproj').length>0;if(!hasProjectJson&&!hasInlineNx&&!hasCsproj){console.log('No apps to pack - skipping.');process.exit(0)}process.exit(require('node:child_process').spawnSync('npx nx run-many -t package',{stdio:'inherit',shell:true}).status ?? 1)"`;
1039
1170
  var NPM_AUTH_PREFLIGHT = `node -e "const fs=require('node:fs'),cp=require('node:child_process');if(fs.globSync('packages/*/package.json').length===0){console.log('No npm packages to release - skipping.');process.exit(0)}if(!process.env.NODE_AUTH_TOKEN){console.error('NPM_TOKEN is empty or unset, so the publish would fail AFTER nx release has already tagged. Add it as a repository secret named exactly NPM_TOKEN - under Actions, not the Dependabot or Codespaces tab, and not an Environment secret. Use an npm Automation token - a Publish token is refused by 2FA in CI.');process.exit(1)}const r=cp.spawnSync('npm',['whoami','--registry=https://registry.npmjs.org/'],{encoding:'utf8',shell:process.platform==='win32'});if(r.status!==0){console.error('NPM_TOKEN is set but the registry rejected it - '+((r.stderr||'')+(r.stdout||'')).trim()+'. Check that it has not expired and that it grants publish rights on this scope.');process.exit(1)}console.log('npm auth OK as '+r.stdout.trim())"`;
1040
1171
  function npmAuthPreflight(registryKind) {
@@ -1046,7 +1177,7 @@ function pypiReleasePreflight(registryKind) {
1046
1177
  }
1047
1178
  var SHALLOW_CLONE_GUARD = `node -e "const r=require('node:child_process').spawnSync('git',['rev-parse','--is-shallow-repository'],{encoding:'utf8'});if(r.status!==0){console.error('Could not determine whether this checkout has full history (git rev-parse --is-shallow-repository failed) - refusing to release. '+(r.stderr||'').trim());process.exit(1)}if(r.stdout.trim()==='true'){console.error('This checkout is a shallow clone. nx release resolves the current version of each package from its git tag, and silently falls back to the permanently-stale on-disk version when a tag cannot be found - which can propose, and publish, a version DOWNGRADE. Fetch full history before releasing - set fetchDepth (Azure) or fetch-depth (GitHub) to 0.');process.exit(1)}"`;
1048
1179
  function releaseGuard(pythonPublishEnv, nugetPublishEnv) {
1049
- return String.raw`node -e "const fs=require('node:fs'),cp=require('node:child_process');const npmCount=fs.globSync('packages/*/package.json').length;const csharpCount=fs.globSync('packages/*/*.csproj').length;const pythonCount=fs.globSync('python-packages/*/pyproject.toml').length;const dartCount=fs.globSync('packages/*/pubspec.yaml').length;const vscodeCount=fs.globSync('apps/*/package.json').filter(p=>{try{return(JSON.parse(fs.readFileSync(p,'utf8')).nx?.tags||[]).includes('${VSCODE_EXTENSION_TAG}')}catch{return false}}).length;const hasNpm=npmCount>0;const hasPython=pythonCount>0;const hasCsharp=csharpCount>0;const hasDart=dartCount>0;const hasVscode=vscodeCount>0;if(!hasNpm&&!hasPython&&!hasCsharp&&!hasDart&&!hasVscode){console.log('Nothing to release - skipping.');process.exit(0)}const specifier=process.env.RELEASE_SPECIFIER||'';let releaseCmd='npx nx release --yes';if(specifier){if(!/^(major|minor|patch|\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?)$/.test(specifier)){console.error('RELEASE_SPECIFIER value \''+specifier+'\' is invalid - use major, minor, patch, or an exact version like 1.2.3.');process.exit(1)}const releaseProjectCount=npmCount+csharpCount+pythonCount+dartCount+vscodeCount;if(/^(major|minor|patch)$/.test(specifier)&&releaseProjectCount>1){console.error('RELEASE_SPECIFIER is a keyword (\''+specifier+'\') but this workspace has '+releaseProjectCount+' releasable packages - a keyword under-bumps interdependent packages, because nx computes the dependency-bump pass from a stale cached version. Set RELEASE_SPECIFIER to an exact version instead, or clear it.');process.exit(1)}releaseCmd='npx nx release '+specifier+' --yes'}const env={...process.env};${pythonPublishEnv}${nugetPublishEnv}process.exit(cp.spawnSync(releaseCmd,{stdio:'inherit',shell:true,env}).status ?? 1)"`;
1180
+ return String.raw`node -e "const fs=require('node:fs'),cp=require('node:child_process');const npmCount=fs.globSync('packages/*/package.json').length;const csharpCount=fs.globSync('packages/*/*.csproj').length;const pythonCount=fs.globSync('python-packages/*/pyproject.toml').length;const dartCount=fs.globSync('packages/*/pubspec.yaml').length;const vscodeCount=fs.globSync('apps/*/package.json').filter(p=>{try{return(JSON.parse(fs.readFileSync(p,'utf8')).nx?.tags||[]).includes('${VSCODE_EXTENSION_TAG}')}catch{return false}}).length;const goCount=fs.globSync('apps/*/project.json').filter(p=>{try{return(JSON.parse(fs.readFileSync(p,'utf8')).tags||[]).includes('${GO_RELEASE_TAG}')}catch{return false}}).length;const hasNpm=npmCount>0;const hasPython=pythonCount>0;const hasCsharp=csharpCount>0;const hasDart=dartCount>0;const hasVscode=vscodeCount>0;const hasGo=goCount>0;if(!hasNpm&&!hasPython&&!hasCsharp&&!hasDart&&!hasVscode&&!hasGo){console.log('Nothing to release - skipping.');process.exit(0)}const specifier=process.env.RELEASE_SPECIFIER||'';let releaseCmd='npx nx release --yes';if(specifier){if(!/^(major|minor|patch|\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?)$/.test(specifier)){console.error('RELEASE_SPECIFIER value \''+specifier+'\' is invalid - use major, minor, patch, or an exact version like 1.2.3.');process.exit(1)}const releaseProjectCount=npmCount+csharpCount+pythonCount+dartCount+vscodeCount+goCount;if(/^(major|minor|patch)$/.test(specifier)&&releaseProjectCount>1){console.error('RELEASE_SPECIFIER is a keyword (\''+specifier+'\') but this workspace has '+releaseProjectCount+' releasable packages - a keyword under-bumps interdependent packages, because nx computes the dependency-bump pass from a stale cached version. Set RELEASE_SPECIFIER to an exact version instead, or clear it.');process.exit(1)}releaseCmd='npx nx release '+specifier+' --yes'}const env={...process.env};${pythonPublishEnv}${nugetPublishEnv}process.exit(cp.spawnSync(releaseCmd,{stdio:'inherit',shell:true,env}).status ?? 1)"`;
1050
1181
  }
1051
1182
  var PYPI_TOKEN_VARIABLE = "PYPI_TOKEN";
1052
1183
  var AZURE_PAT_VARIABLE = "PAT";
@@ -1075,7 +1206,7 @@ function npmAuthEnvVariable(registryKind, variableReference) {
1075
1206
  function poolBlock(agent) {
1076
1207
  return /^(?:ubuntu|windows|macos)-/i.test(agent) ? ` vmImage: ${agent}` : ` name: ${agent}`;
1077
1208
  }
1078
- function azurePipelinesYaml(agent, variableGroup, pythonPublishUrl2, registryKind = "azure-artifacts", nugetFeedUrl2, npmAuth = "pat") {
1209
+ function azurePipelinesYaml(agent, variableGroup, pythonPublishUrl2, registryKind = "azure-artifacts", nugetFeedUrl2, npmAuth = "pat", nativeApps = false) {
1079
1210
  const onMain = "and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'), eq(variables['Build.SourceBranchName'], 'main'))";
1080
1211
  const [npmAuthName, npmAuthValue] = npmAuthEnvVariable(registryKind, (name) => `$(${name})`);
1081
1212
  const buildIdentity = npmAuth === "build-identity" && registryKind === "azure-artifacts";
@@ -1093,7 +1224,7 @@ function azurePipelinesYaml(agent, variableGroup, pythonPublishUrl2, registryKin
1093
1224
  const npmCiEnv = buildIdentity ? "" : `
1094
1225
  env:
1095
1226
  ${npmAuthName}: ${npmAuthValue}`;
1096
- return `name: monorepo-ci-$(Date:yyyyMMdd)$(Rev:.r)
1227
+ const document = `name: monorepo-ci-$(Date:yyyyMMdd)$(Rev:.r)
1097
1228
 
1098
1229
  # Generated by MoNecromanCI. Deliberately thin: Nx builds, 'nx release'
1099
1230
  # versions from conventional commits and pushes ONLY a tag to main, and each
@@ -1304,7 +1435,7 @@ ${npmAuthenticateStep} - script: npm ci
1304
1435
  # 'npm run lint' is 'nx run-many -t lint', a strict subset of the targets
1305
1436
  # below, so adding it back as its own step would only duplicate work \u2014 and on
1306
1437
  # a pull request it would re-lint every project, discarding the point of this.
1307
- - script: ${AFFECTED_OR_ALL_GUARD}
1438
+ - script: ${nativeApps ? AFFECTED_OR_ALL_GUARD_WITHOUT_NATIVE : AFFECTED_OR_ALL_GUARD}
1308
1439
  displayName: Verify (affected on a PR, every project on main)
1309
1440
 
1310
1441
  # Pack every app into dist/drop/<type>-<name>.zip via each app's 'package'
@@ -1395,8 +1526,56 @@ ${npmAuthPreflight(registryKind) ? `
1395
1526
  displayName: Push release tags (nx release's own push never runs without a remote Release configured)
1396
1527
  condition: ${onMain}
1397
1528
  `;
1529
+ if (!nativeApps) {
1530
+ return document;
1531
+ }
1532
+ const nativeSteps = ` - checkout: self
1533
+ fetchDepth: 0
1534
+
1535
+ - task: UseNode@1
1536
+ inputs:
1537
+ version: 24.x
1538
+
1539
+ - task: Cache@2
1540
+ displayName: Cache npm packages
1541
+ inputs:
1542
+ key: 'npm | "$(Agent.OS)" | package-lock.json'
1543
+ restoreKeys: |
1544
+ npm | "$(Agent.OS)"
1545
+ path: $(npm_config_cache)
1546
+
1547
+ ${npmAuthenticateStep} - script: npm ci
1548
+ displayName: Install dependencies${npmCiEnv}
1549
+
1550
+ - script: ${GO_MODULE_DOWNLOAD_GUARD}
1551
+ displayName: Download Go module dependencies
1552
+
1553
+ - script: ${GOLANGCI_LINT_INSTALL_GUARD}
1554
+ displayName: Install golangci-lint
1555
+
1556
+ - script: ${GO_TOOL_PATH_AZURE}
1557
+ displayName: Add Go tool bin to PATH
1558
+
1559
+ # A C compiler and pkg-config, which is all mnci can know a cgo app needs. Add the
1560
+ # -dev packages your app links to this line, for example libgtk-3-dev and
1561
+ # libayatana-appindicator3-dev for a system-tray icon. macOS and Windows agents
1562
+ # ship their toolchains.
1563
+ - script: ${NATIVE_LINUX_PREREQUISITES}
1564
+ displayName: Install native prerequisites (Linux)
1565
+ condition: eq(variables['Agent.OS'], 'Linux')
1566
+
1567
+ - script: ${NATIVE_BUILD_COMMAND}
1568
+ displayName: Lint, test, build and package the native apps
1569
+
1570
+ - task: PublishBuildArtifacts@1
1571
+ displayName: Publish this OS's native zips
1572
+ inputs:
1573
+ PathtoPublish: $(Build.SourcesDirectory)/dist/drop
1574
+ ArtifactName: native-$(legName)
1575
+ `;
1576
+ return withAzureNativeJob(document, nativeSteps);
1398
1577
  }
1399
- function githubActionsYaml(agent, pythonPublishUrl2, registryKind = "azure-artifacts", ci = "github", nugetFeedUrl2) {
1578
+ function githubActionsYaml(agent, pythonPublishUrl2, registryKind = "azure-artifacts", ci = "github", nugetFeedUrl2, nativeApps = false) {
1400
1579
  const onMain = "github.event_name == 'push' && github.ref_name == 'main'";
1401
1580
  const [npmAuthName, npmAuthValue] = npmAuthEnvVariable(
1402
1581
  registryKind,
@@ -1565,7 +1744,7 @@ jobs:
1565
1744
  # below, so adding it back as its own step would only duplicate work \u2014 and
1566
1745
  # on a pull request it would re-lint every project, discarding the point
1567
1746
  # of this.
1568
- - run: ${AFFECTED_OR_ALL_GUARD}
1747
+ - run: ${nativeApps ? AFFECTED_OR_ALL_GUARD_WITHOUT_NATIVE : AFFECTED_OR_ALL_GUARD}
1569
1748
  name: Verify (affected on a PR, every project on main)
1570
1749
 
1571
1750
  # Pack every app into dist/drop/<type>-<name>.zip via each app's 'package'
@@ -1667,7 +1846,18 @@ ${npmAuthPreflight(registryKind) ? `
1667
1846
  VSCE_AUTH: \${{ vars.AZURE_CLIENT_ID != '' && 'entra' || '' }}
1668
1847
  VSCE_PAT: \${{ secrets.VSCE_PAT }}${githubReleases ? `
1669
1848
  GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}` : ""}
1670
- ${githubReleases ? "" : `
1849
+ ${githubReleases ? `
1850
+ # A releasable Go app (mnci add go-app --release) is versioned by its git
1851
+ # tag, and its per-platform zips are attached to the GitHub Release the step
1852
+ # above just created. Built here, after tagging, with VERSION set to the tag's
1853
+ # version so the binary reports it. A run that released no Go app uploads
1854
+ # nothing, and a workspace without one skips the step.
1855
+ - run: node tools/go-app-release.cjs assets
1856
+ name: Attach the per-platform zips to the GitHub Release (releasable Go apps)
1857
+ if: \${{ ${onMain} && hashFiles('tools/go-app-release.cjs') != '' }}
1858
+ env:
1859
+ GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
1860
+ ` : `
1671
1861
  # nx release's own git push (release.git.push) is deliberately left off: it
1672
1862
  # only runs when a remote GitHub/GitLab Release is configured, which this
1673
1863
  # workflow never does, so it would never push the tag the step above just
@@ -1676,7 +1866,7 @@ ${githubReleases ? "" : `
1676
1866
  - run: git push origin --tags
1677
1867
  name: Push release tags (nx release's own push never runs without a remote Release configured)
1678
1868
  if: \${{ ${onMain} }}
1679
- `}`;
1869
+ `}${nativeApps ? githubNativeJob(npmAuthName, npmAuthValue, onMain) : ""}`;
1680
1870
  }
1681
1871
  var PIP_PROJECT_GLOBS = ["apps", "python-packages", "libs"];
1682
1872
  var PUB_PROJECT_GLOBS = ["apps", "packages", "libs"];
@@ -1993,6 +2183,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
1993
2183
  }
1994
2184
  const publishUrl = pythonPublishUrl(options.registry);
1995
2185
  const nugetUrl = nugetFeedUrl(options.registry);
2186
+ const nativeApps = hasNativeGoApp(workspaceRoot);
1996
2187
  if (options.ci === "azure" || options.ci === "both") {
1997
2188
  onProgress("azure-pipelines.yml \u2014 build, verify, pack and release");
1998
2189
  writeFileEnsured(
@@ -2003,7 +2194,8 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2003
2194
  publishUrl,
2004
2195
  options.registry.kind,
2005
2196
  nugetUrl,
2006
- options.npmAuth
2197
+ options.npmAuth,
2198
+ nativeApps
2007
2199
  )
2008
2200
  );
2009
2201
  }
@@ -2011,7 +2203,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
2011
2203
  onProgress(".github/workflows/ci.yml and dependabot.yml");
2012
2204
  writeFileEnsured(
2013
2205
  (0, import_node_path2.join)(workspaceRoot, ".github/workflows/ci.yml"),
2014
- githubActionsYaml(options.agent, publishUrl, options.registry.kind, options.ci, nugetUrl)
2206
+ githubActionsYaml(options.agent, publishUrl, options.registry.kind, options.ci, nugetUrl, nativeApps)
2015
2207
  );
2016
2208
  writeFileEnsured((0, import_node_path2.join)(workspaceRoot, ".github/dependabot.yml"), dependabotConfig(workspaceRoot));
2017
2209
  }
@@ -2605,8 +2797,181 @@ function addFlutterInternalLib(workspaceRoot, name) {
2605
2797
  }
2606
2798
 
2607
2799
  // src/project-scaffolding/go.use-case.ts
2800
+ var import_node_fs6 = require("fs");
2801
+ var import_node_path7 = require("path");
2802
+
2803
+ // src/project-scaffolding/go-release.use-case.ts
2608
2804
  var import_node_fs5 = require("fs");
2609
2805
  var import_node_path6 = require("path");
2806
+ var GO_RELEASE_SCRIPT_PATH = "tools/go-app-release.cjs";
2807
+ var GO_RELEASE_SCRIPT = String.raw`#!/usr/bin/env node
2808
+ // Written by mnci: 'mnci add go-app --release' creates it and 'mnci upgrade'
2809
+ // rewrites it, so local edits do not survive an upgrade.
2810
+ //
2811
+ // A releasable Go app (tag release:go) is versioned from its git tag, with no
2812
+ // manifest, and its per-platform zips are attached to its GitHub Release:
2813
+ // release.version.versionActions this file, loaded by 'nx release'
2814
+ // node tools/go-app-release.cjs assets the apps built for all six platforms
2815
+ // node tools/go-app-release.cjs assets --native the apps that need a C toolchain, this OS only
2816
+ 'use strict'
2817
+ const { spawnSync } = require('node:child_process')
2818
+ const { existsSync, readdirSync, readFileSync } = require('node:fs')
2819
+ const { dirname, join } = require('node:path')
2820
+ const { VersionActions } = require('nx/release')
2821
+
2822
+ const FIRST_RELEASE_BASE = '0.0.0'
2823
+
2824
+ class GoAppVersionActions extends VersionActions {
2825
+ validManifestFilenames = null
2826
+
2827
+ async validate () {
2828
+ // Nothing on disk to check: there is no manifest.
2829
+ }
2830
+
2831
+ async readCurrentVersionFromSourceManifest () {
2832
+ // Reached only as the fallback of the git-tag resolver, i.e. before the first tag.
2833
+ return { currentVersion: FIRST_RELEASE_BASE, manifestPath: 'none (a Go app is versioned by its git tag)' }
2834
+ }
2835
+
2836
+ async readCurrentVersionFromRegistry () {
2837
+ return null
2838
+ }
2839
+
2840
+ async readCurrentVersionOfDependency () {
2841
+ return { currentVersion: null, dependencyCollection: null }
2842
+ }
2843
+
2844
+ async updateProjectVersion () {
2845
+ return []
2846
+ }
2847
+
2848
+ async updateProjectDependencies () {
2849
+ return []
2850
+ }
2851
+ }
2852
+
2853
+ module.exports = GoAppVersionActions
2854
+
2855
+ function fail (message) {
2856
+ console.error(message)
2857
+ process.exit(1)
2858
+ }
2859
+
2860
+ function run (command, args, env) {
2861
+ const result = spawnSync(command, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'], env: { ...process.env, ...env }, shell: false })
2862
+ if (result.status !== 0) fail(command + ' ' + args.join(' ') + ' failed (exit ' + result.status + ')')
2863
+
2864
+ return result.stdout
2865
+ }
2866
+
2867
+ function nx (args, env) {
2868
+ const manifest = require.resolve('nx/package.json')
2869
+ const bin = require(manifest).bin
2870
+ const entry = typeof bin === 'string' ? bin : bin.nx
2871
+
2872
+ return run(process.execPath, [join(dirname(manifest), entry), ...args], env)
2873
+ }
2874
+
2875
+ function releasableApps (native) {
2876
+ const names = existsSync('apps') ? readdirSync('apps') : []
2877
+
2878
+ return names.filter(name => {
2879
+ try {
2880
+ const tags = JSON.parse(readFileSync(join('apps', name, 'project.json'), 'utf8')).tags || []
2881
+
2882
+ return tags.includes('release:go') && tags.includes('build:cgo') === native
2883
+ } catch {
2884
+ return false
2885
+ }
2886
+ })
2887
+ }
2888
+
2889
+ function attachAssets (native) {
2890
+ const apps = releasableApps(native)
2891
+ if (apps.length === 0) {
2892
+ console.log('No releasable ' + (native ? 'native ' : '') + 'Go app - nothing to attach.')
2893
+
2894
+ return
2895
+ }
2896
+ const target = native ? 'package-native' : 'package-all'
2897
+ const tags = run('git', ['tag', '--points-at', 'HEAD']).split(/\r?\n/).filter(Boolean)
2898
+ let attached = 0
2899
+ for (const app of apps) {
2900
+ const tag = tags.find(each => each.startsWith(app + '@'))
2901
+ if (!tag) {
2902
+ console.log(app + ': not released by this run - skipping.')
2903
+ continue
2904
+ }
2905
+ const version = tag.slice(app.length + 1)
2906
+ console.log(app + ': ' + (native ? 'building for this OS' : 'building the six platforms') + ' as ' + version)
2907
+ nx(['run', app + ':' + target], { VERSION: version })
2908
+ const prefix = 'go-app-' + app + '-'
2909
+ const zips = existsSync('dist/drop') ? readdirSync('dist/drop').filter(each => each.startsWith(prefix) && each.endsWith('.zip')) : []
2910
+ if (zips.length === 0) fail(app + ': ' + target + ' produced no ' + prefix + '*.zip in dist/drop.')
2911
+ const upload = spawnSync('gh', ['release', 'upload', tag, ...zips.map(each => join('dist/drop', each)), '--clobber'], { stdio: 'inherit', shell: process.platform === 'win32' })
2912
+ if (upload.status !== 0) fail(app + ': could not attach the zips to the ' + tag + ' release (exit ' + upload.status + ').')
2913
+ console.log(app + ': attached ' + zips.length + ' zips to ' + tag)
2914
+ attached += 1
2915
+ }
2916
+ console.log(attached + ' release(s) carry their platform zips.')
2917
+ }
2918
+
2919
+ if (require.main === module) {
2920
+ if (process.argv[2] !== 'assets' || (process.argv[3] !== undefined && process.argv[3] !== '--native')) fail('Usage: node tools/go-app-release.cjs assets [--native]')
2921
+ attachAssets(process.argv[3] === '--native')
2922
+ }
2923
+ `;
2924
+ var GO_RELEASE_PUBLISH_TARGET = {
2925
+ executor: "nx:run-commands",
2926
+ options: {
2927
+ command: `node -e "console.log('Published by its git tag; the platform zips are attached to the GitHub Release by tools/go-app-release.cjs assets.')"`
2928
+ }
2929
+ };
2930
+ function makeGoAppReleasable(workspaceRoot, name) {
2931
+ const projectJsonPath = (0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json");
2932
+ if (!fileExists(projectJsonPath)) {
2933
+ throw new Error(`No Go app at apps/${name}: cannot make it releasable.`);
2934
+ }
2935
+ const project = readJson(projectJsonPath);
2936
+ writeFileEnsured(
2937
+ projectJsonPath,
2938
+ toJson({
2939
+ ...project,
2940
+ tags: [.../* @__PURE__ */ new Set([...project.tags ?? [], GO_RELEASE_TAG])],
2941
+ targets: { ...project.targets, "nx-release-publish": project.targets?.["nx-release-publish"] ?? GO_RELEASE_PUBLISH_TARGET },
2942
+ release: {
2943
+ ...project.release,
2944
+ version: {
2945
+ ...project.release?.version,
2946
+ versionActions: GO_RELEASE_SCRIPT_PATH,
2947
+ currentVersionResolver: "git-tag"
2948
+ }
2949
+ }
2950
+ })
2951
+ );
2952
+ writeFileEnsured((0, import_node_path6.join)(workspaceRoot, GO_RELEASE_SCRIPT_PATH), GO_RELEASE_SCRIPT);
2953
+ }
2954
+ function refreshGoReleaseScript(workspaceRoot) {
2955
+ const apps = (0, import_node_path6.join)(workspaceRoot, "apps");
2956
+ let entries;
2957
+ try {
2958
+ entries = (0, import_node_fs5.readdirSync)(apps);
2959
+ } catch {
2960
+ return false;
2961
+ }
2962
+ const hasReleasableApp = entries.some((entry) => {
2963
+ const projectJsonPath = (0, import_node_path6.join)(apps, entry, "project.json");
2964
+ return fileExists(projectJsonPath) && (readJson(projectJsonPath).tags ?? []).includes(GO_RELEASE_TAG);
2965
+ });
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) {
2968
+ return false;
2969
+ }
2970
+ writeFileEnsured(path, GO_RELEASE_SCRIPT);
2971
+ return true;
2972
+ }
2973
+
2974
+ // src/project-scaffolding/go.use-case.ts
2610
2975
  function ensureGo(workspaceRoot) {
2611
2976
  if (runShell("go", ["version"], workspaceRoot) !== 0) {
2612
2977
  throw new Error("Go not found. Install Go 1.21+ first: https://go.dev/dl/");
@@ -2633,7 +2998,7 @@ function ensureNxGoPlugin(workspaceRoot) {
2633
2998
  }
2634
2999
  }
2635
3000
  function ensureGoModule(workspaceRoot) {
2636
- if (fileExists((0, import_node_path6.join)(workspaceRoot, "go.mod"))) {
3001
+ if (fileExists((0, import_node_path7.join)(workspaceRoot, "go.mod"))) {
2637
3002
  return;
2638
3003
  }
2639
3004
  logger.step("Bootstrapping the workspace Go module (single root go.mod)");
@@ -2642,7 +3007,7 @@ function ensureGoModule(workspaceRoot) {
2642
3007
  }
2643
3008
  function goModulePath(workspaceRoot) {
2644
3009
  try {
2645
- const contents = (0, import_node_fs5.readFileSync)((0, import_node_path6.join)(workspaceRoot, "go.mod"), "utf8");
3010
+ const contents = (0, import_node_fs6.readFileSync)((0, import_node_path7.join)(workspaceRoot, "go.mod"), "utf8");
2646
3011
  return /^module\s+(\S+)/m.exec(contents)?.[1];
2647
3012
  } catch {
2648
3013
  return void 0;
@@ -2702,20 +3067,39 @@ function goPackageAllTarget(tag, name) {
2702
3067
  options: { command }
2703
3068
  };
2704
3069
  }
3070
+ var GO_HOST_PLATFORM = "const host=k=>spawnSync('go',['env',k],{encoding:'utf8'}).stdout.trim();const os=host('GOOS'),arch=host('GOARCH');";
3071
+ function goNativeBuildTarget(name) {
3072
+ const command = `node -e "const{spawnSync}=require('node:child_process');${GO_HOST_PLATFORM}const v=process.env.VERSION||'dev';const out='../../dist/platforms/${name}/'+os+'-'+arch+'/${name}'+(os==='windows'?'.exe':'');const r=spawnSync('go',['build','-trimpath','-ldflags','-s -w -X main.version='+v,'-o',out,'.'],{cwd:'apps/${name}',stdio:'inherit',env:{...process.env,CGO_ENABLED:'1'}});process.exit(r.status??1)"`;
3073
+ return {
3074
+ executor: "nx:run-commands",
3075
+ inputs: ["default", "^default", "{workspaceRoot}/go.mod", "{workspaceRoot}/go.sum", { env: "VERSION" }],
3076
+ outputs: [`{workspaceRoot}/dist/platforms/${name}`],
3077
+ options: { command }
3078
+ };
3079
+ }
3080
+ function goNativePackageTarget(name) {
3081
+ const command = `node -e "const fs=require('node:fs');const{spawnSync}=require('node:child_process');const A=require('adm-zip');${GO_HOST_PLATFORM}const d=os+'-'+arch;fs.mkdirSync('dist/drop',{recursive:true});const z=new A();z.addLocalFolder('dist/platforms/${name}/'+d);z.writeZip('dist/drop/go-app-${name}-'+d+'.zip')"`;
3082
+ return {
3083
+ executor: "nx:run-commands",
3084
+ dependsOn: ["build-native"],
3085
+ outputs: [`{workspaceRoot}/dist/drop/go-app-${name}-*.zip`],
3086
+ options: { command }
3087
+ };
3088
+ }
2705
3089
  function addGoPlatformTargets(workspaceRoot) {
2706
3090
  const changed = [];
2707
- const apps = (0, import_node_path6.join)(workspaceRoot, "apps");
3091
+ const apps = (0, import_node_path7.join)(workspaceRoot, "apps");
2708
3092
  if (!fileExists(apps)) {
2709
3093
  return changed;
2710
3094
  }
2711
- for (const name of (0, import_node_fs5.readdirSync)(apps)) {
2712
- const projectJsonPath = (0, import_node_path6.join)(apps, name, "project.json");
3095
+ for (const name of (0, import_node_fs6.readdirSync)(apps)) {
3096
+ const projectJsonPath = (0, import_node_path7.join)(apps, name, "project.json");
2713
3097
  if (!fileExists(projectJsonPath)) {
2714
3098
  continue;
2715
3099
  }
2716
- const project = JSON.parse((0, import_node_fs5.readFileSync)(projectJsonPath, "utf8"));
3100
+ const project = JSON.parse((0, import_node_fs6.readFileSync)(projectJsonPath, "utf8"));
2717
3101
  const tag = (project.tags ?? []).find((each) => each === "type:go-app" || each === "type:go-function-app")?.slice("type:".length);
2718
- if (tag === void 0) {
3102
+ if (tag === void 0 || (project.tags ?? []).includes(GO_CGO_TAG)) {
2719
3103
  continue;
2720
3104
  }
2721
3105
  const missing = {};
@@ -2749,8 +3133,8 @@ function goLibraryIdentifiers(projectName) {
2749
3133
  }
2750
3134
  function reshapeGoLibraryScaffold(projectRoot, projectName) {
2751
3135
  const { packageName, functionName, fileStem } = goLibraryIdentifiers(projectName);
2752
- (0, import_node_fs5.rmSync)((0, import_node_path6.join)(projectRoot, `${projectName}.go`), { force: true });
2753
- (0, import_node_fs5.rmSync)((0, import_node_path6.join)(projectRoot, `${projectName}_test.go`), { force: true });
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 });
2754
3138
  const files = [
2755
3139
  [
2756
3140
  "doc.go",
@@ -2760,14 +3144,14 @@ package ${packageName}
2760
3144
  `
2761
3145
  ],
2762
3146
  [
2763
- (0, import_node_path6.join)(packageName, "doc.go"),
3147
+ (0, import_node_path7.join)(packageName, "doc.go"),
2764
3148
  `// Package ${packageName} is the starter slice of ${projectName}: rename it after
2765
3149
  // the outcome it delivers, and add one package per further outcome.
2766
3150
  package ${packageName}
2767
3151
  `
2768
3152
  ],
2769
3153
  [
2770
- (0, import_node_path6.join)(packageName, `${fileStem}_use_case.go`),
3154
+ (0, import_node_path7.join)(packageName, `${fileStem}_use_case.go`),
2771
3155
  `package ${packageName}
2772
3156
 
2773
3157
  // ${functionName} is the generator's sample behaviour, kept so the slice builds and tests.
@@ -2777,7 +3161,7 @@ func ${functionName}(name string) string {
2777
3161
  `
2778
3162
  ],
2779
3163
  [
2780
- (0, import_node_path6.join)(packageName, `${fileStem}_use_case_test.go`),
3164
+ (0, import_node_path7.join)(packageName, `${fileStem}_use_case_test.go`),
2781
3165
  `package ${packageName}
2782
3166
 
2783
3167
  import "testing"
@@ -2791,7 +3175,7 @@ func Test${functionName}(t *testing.T) {
2791
3175
  ]
2792
3176
  ];
2793
3177
  for (const [relativePath, content] of files) {
2794
- const path = (0, import_node_path6.join)(projectRoot, relativePath);
3178
+ const path = (0, import_node_path7.join)(projectRoot, relativePath);
2795
3179
  if (!fileExists(path)) {
2796
3180
  writeFileEnsured(path, content);
2797
3181
  }
@@ -2804,7 +3188,8 @@ function prepareGo(workspaceRoot) {
2804
3188
  ensureNxGoPlugin(workspaceRoot);
2805
3189
  ensureGoModule(workspaceRoot);
2806
3190
  }
2807
- function addGoApp(workspaceRoot, name) {
3191
+ function addGoApp(workspaceRoot, name, options = {}) {
3192
+ const cgo = options.cgo === true;
2808
3193
  prepareGo(workspaceRoot);
2809
3194
  ensureAdmZip(workspaceRoot);
2810
3195
  runNx(
@@ -2813,21 +3198,31 @@ function addGoApp(workspaceRoot, name) {
2813
3198
  "@nx-go/nx-go:application",
2814
3199
  `apps/${name}`,
2815
3200
  `--name=${name}`,
2816
- "--tags=type:go-app",
3201
+ cgo ? `--tags=type:go-app,${GO_CGO_TAG}` : "--tags=type:go-app",
2817
3202
  "--no-interactive"
2818
3203
  ],
2819
3204
  workspaceRoot
2820
3205
  );
2821
- addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
2822
- "build": goBuildTarget(name),
2823
- "test": goTestTarget(),
2824
- "lint": goLintTarget(),
2825
- "package": goPackageTarget("go-app", name),
2826
- "build-all": goBuildAllTarget(name),
2827
- "package-all": goPackageAllTarget("go-app", name),
2828
- "start": goStartTarget(name)
3206
+ addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "apps", name, "project.json"), {
3207
+ build: goBuildTarget(name),
3208
+ test: goTestTarget(),
3209
+ lint: goLintTarget(),
3210
+ ...cgo ? { "build-native": goNativeBuildTarget(name), "package-native": goNativePackageTarget(name) } : {
3211
+ "package": goPackageTarget("go-app", name),
3212
+ "build-all": goBuildAllTarget(name),
3213
+ "package-all": goPackageAllTarget("go-app", name)
3214
+ },
3215
+ start: goStartTarget(name)
2829
3216
  });
3217
+ if (options.release === true) {
3218
+ makeGoAppReleasable(workspaceRoot, name);
3219
+ }
2830
3220
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
3221
+ if (cgo) {
3222
+ logger.warn(
3223
+ `${name} needs a C toolchain, so CI builds it on a runner of each OS. Run \`mnci upgrade\` to add the native job to your pipeline, and add the -dev packages it links to the Linux prerequisites step.`
3224
+ );
3225
+ }
2831
3226
  }
2832
3227
  function addGoFunctionApp(workspaceRoot, name) {
2833
3228
  prepareGo(workspaceRoot);
@@ -2843,7 +3238,7 @@ function addGoFunctionApp(workspaceRoot, name) {
2843
3238
  ],
2844
3239
  workspaceRoot
2845
3240
  );
2846
- addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
3241
+ addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "apps", name, "project.json"), {
2847
3242
  "build": goBuildTarget(name),
2848
3243
  "test": goTestTarget(),
2849
3244
  "lint": goLintTarget(),
@@ -2866,11 +3261,11 @@ function addGoLib(workspaceRoot, name) {
2866
3261
  ],
2867
3262
  workspaceRoot
2868
3263
  );
2869
- addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "packages", name, "project.json"), {
3264
+ addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "packages", name, "project.json"), {
2870
3265
  test: goTestTarget(),
2871
3266
  lint: goLintTarget()
2872
3267
  });
2873
- const slice = reshapeGoLibraryScaffold((0, import_node_path6.join)(workspaceRoot, "packages", name), name);
3268
+ const slice = reshapeGoLibraryScaffold((0, import_node_path7.join)(workspaceRoot, "packages", name), name);
2874
3269
  registerProjectCommands(workspaceRoot, name, { build: false });
2875
3270
  const module2 = goModulePath(workspaceRoot);
2876
3271
  if (module2) {
@@ -2890,11 +3285,11 @@ function addGoInternalLib(workspaceRoot, name) {
2890
3285
  ],
2891
3286
  workspaceRoot
2892
3287
  );
2893
- addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "libs", name, "project.json"), {
3288
+ addProjectJsonTargets((0, import_node_path7.join)(workspaceRoot, "libs", name, "project.json"), {
2894
3289
  test: goTestTarget(),
2895
3290
  lint: goLintTarget()
2896
3291
  });
2897
- const slice = reshapeGoLibraryScaffold((0, import_node_path6.join)(workspaceRoot, "libs", name), name);
3292
+ const slice = reshapeGoLibraryScaffold((0, import_node_path7.join)(workspaceRoot, "libs", name), name);
2898
3293
  registerProjectCommands(workspaceRoot, name, { build: false });
2899
3294
  const module2 = goModulePath(workspaceRoot);
2900
3295
  if (module2) {
@@ -2903,7 +3298,7 @@ function addGoInternalLib(workspaceRoot, name) {
2903
3298
  }
2904
3299
 
2905
3300
  // src/project-scaffolding/node.use-case.ts
2906
- var import_node_path7 = require("path");
3301
+ var import_node_path8 = require("path");
2907
3302
  function ensurePlugin2(workspaceRoot, packageName) {
2908
3303
  if (hasPlugin(workspaceRoot, packageName)) {
2909
3304
  return;
@@ -2927,12 +3322,12 @@ function runNodeApp(workspaceRoot, name, stack, framework) {
2927
3322
  ],
2928
3323
  workspaceRoot
2929
3324
  );
2930
- const appRoot = (0, import_node_path7.join)(workspaceRoot, "apps", name);
3325
+ const appRoot = (0, import_node_path8.join)(workspaceRoot, "apps", name);
2931
3326
  separateDeclarationOutput(appRoot);
2932
3327
  repairAssetMapping(appRoot, name);
2933
3328
  }
2934
3329
  function separateDeclarationOutput(appRoot) {
2935
- const tsconfigPath = (0, import_node_path7.join)(appRoot, "tsconfig.app.json");
3330
+ const tsconfigPath = (0, import_node_path8.join)(appRoot, "tsconfig.app.json");
2936
3331
  if (!fileExists(tsconfigPath)) {
2937
3332
  return;
2938
3333
  }
@@ -2954,7 +3349,7 @@ function separateDeclarationOutput(appRoot) {
2954
3349
  );
2955
3350
  }
2956
3351
  function repairAssetMapping(appRoot, name) {
2957
- const manifestPath = (0, import_node_path7.join)(appRoot, "package.json");
3352
+ const manifestPath = (0, import_node_path8.join)(appRoot, "package.json");
2958
3353
  if (!fileExists(manifestPath)) {
2959
3354
  return;
2960
3355
  }
@@ -2981,7 +3376,7 @@ function nodeAppPackageTarget(name) {
2981
3376
  function addNodeApp(workspaceRoot, name, stack, framework = "none") {
2982
3377
  runNodeApp(workspaceRoot, name, stack, framework);
2983
3378
  ensureAdmZip(workspaceRoot);
2984
- addNxTargets((0, import_node_path7.join)(workspaceRoot, "apps", name, "package.json"), {
3379
+ addNxTargets((0, import_node_path8.join)(workspaceRoot, "apps", name, "package.json"), {
2985
3380
  package: nodeAppPackageTarget(name)
2986
3381
  });
2987
3382
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
@@ -3037,10 +3432,10 @@ describe('buildGreeting', () => {
3037
3432
  })
3038
3433
  `;
3039
3434
  function repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot) {
3040
- const manifestPath = (0, import_node_path7.join)(nodeFunctionAppRoot, "package.json");
3435
+ const manifestPath = (0, import_node_path8.join)(nodeFunctionAppRoot, "package.json");
3041
3436
  const manifest = readJson(manifestPath);
3042
3437
  const azureFunctionsVersion = readJson(
3043
- (0, import_node_path7.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
3438
+ (0, import_node_path8.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
3044
3439
  ).version;
3045
3440
  const dependencies = manifest.dependencies ?? {};
3046
3441
  writeFileEnsured(
@@ -3083,21 +3478,21 @@ function nodeFunctionAppStartTarget(name) {
3083
3478
  function addNodeFunctionApp(workspaceRoot, name, stack) {
3084
3479
  runNodeApp(workspaceRoot, name, stack, "none");
3085
3480
  ensureAzureFunctionsPackage(workspaceRoot);
3086
- const nodeFunctionAppRoot = (0, import_node_path7.join)(workspaceRoot, "apps", name);
3087
- writeFileEnsured((0, import_node_path7.join)(nodeFunctionAppRoot, "src/main.ts"), NODE_FUNCTION_APP_MAIN);
3088
- writeFileEnsured((0, import_node_path7.join)(nodeFunctionAppRoot, "src/functions/hello.ts"), NODE_FUNCTION_APP_HELLO);
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);
3089
3484
  writeFileEnsured(
3090
- (0, import_node_path7.join)(nodeFunctionAppRoot, "src/functions/greeting.ts"),
3485
+ (0, import_node_path8.join)(nodeFunctionAppRoot, "src/functions/greeting.ts"),
3091
3486
  NODE_FUNCTION_APP_GREETING
3092
3487
  );
3093
3488
  writeFileEnsured(
3094
- (0, import_node_path7.join)(nodeFunctionAppRoot, "src/functions/greeting.spec.ts"),
3489
+ (0, import_node_path8.join)(nodeFunctionAppRoot, "src/functions/greeting.spec.ts"),
3095
3490
  NODE_FUNCTION_APP_GREETING_SPEC
3096
3491
  );
3097
- writeFileEnsured((0, import_node_path7.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
3492
+ writeFileEnsured((0, import_node_path8.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
3098
3493
  repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot);
3099
3494
  ensureAdmZip(workspaceRoot);
3100
- addNxTargets((0, import_node_path7.join)(nodeFunctionAppRoot, "package.json"), {
3495
+ addNxTargets((0, import_node_path8.join)(nodeFunctionAppRoot, "package.json"), {
3101
3496
  package: nodeFunctionAppPackageTarget(name),
3102
3497
  prune: nodeFunctionAppPruneTarget(name),
3103
3498
  start: nodeFunctionAppStartTarget(name)
@@ -3107,11 +3502,11 @@ function addNodeFunctionApp(workspaceRoot, name, stack) {
3107
3502
  }
3108
3503
 
3109
3504
  // src/project-scaffolding/npm-lib.use-case.ts
3110
- var import_node_path11 = require("path");
3505
+ var import_node_path12 = require("path");
3111
3506
 
3112
3507
  // src/rollup-library/repair-publishable-manifest.use-case.ts
3113
- var import_node_fs6 = require("fs");
3114
- var import_node_path8 = require("path");
3508
+ var import_node_fs7 = require("fs");
3509
+ var import_node_path9 = require("path");
3115
3510
  var WRONG_TYPES_PATH = "./dist/index.esm.d.ts";
3116
3511
  var ACTUAL_TYPES_PATH = "./dist/src/index.d.ts";
3117
3512
  var DECLARATION_MAP_EXCLUSION = "!**/*.d.ts.map";
@@ -3134,14 +3529,14 @@ function repairPublishableManifest(manifestPath) {
3134
3529
  }
3135
3530
  function repairPublishableManifests(workspaceRoot) {
3136
3531
  const changed = [];
3137
- const manifests = (0, import_node_fs6.globSync)(["packages/*/package.json", "libs/*/package.json"], {
3532
+ const manifests = (0, import_node_fs7.globSync)(["packages/*/package.json", "libs/*/package.json"], {
3138
3533
  cwd: workspaceRoot
3139
3534
  });
3140
3535
  for (const relativePath of manifests) {
3141
- const manifestPath = (0, import_node_path8.join)(workspaceRoot, relativePath);
3142
- const before = (0, import_node_fs6.readFileSync)(manifestPath, "utf8");
3536
+ const manifestPath = (0, import_node_path9.join)(workspaceRoot, relativePath);
3537
+ const before = (0, import_node_fs7.readFileSync)(manifestPath, "utf8");
3143
3538
  repairPublishableManifest(manifestPath);
3144
- const after = (0, import_node_fs6.readFileSync)(manifestPath, "utf8");
3539
+ const after = (0, import_node_fs7.readFileSync)(manifestPath, "utf8");
3145
3540
  if (after !== before) {
3146
3541
  changed.push(relativePath.replaceAll("\\", "/"));
3147
3542
  }
@@ -3150,8 +3545,8 @@ function repairPublishableManifests(workspaceRoot) {
3150
3545
  }
3151
3546
 
3152
3547
  // src/rollup-library/repair-rollup-config.use-case.ts
3153
- var import_node_fs7 = require("fs");
3154
- var import_node_path9 = require("path");
3548
+ var import_node_fs8 = require("fs");
3549
+ var import_node_path10 = require("path");
3155
3550
 
3156
3551
  // src/rollup-library/rollup-config.algorithm.ts
3157
3552
  var ROLLUP_CONFIG_PLACEHOLDER = [
@@ -3353,12 +3748,12 @@ function withUpgradedDeclarationSpecifierPlugin(config) {
3353
3748
  // src/rollup-library/repair-rollup-config.use-case.ts
3354
3749
  function repairRollupSourceMaps(workspaceRoot) {
3355
3750
  const changed = [];
3356
- const configs = (0, import_node_fs7.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
3751
+ const configs = (0, import_node_fs8.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
3357
3752
  cwd: workspaceRoot
3358
3753
  });
3359
3754
  for (const relativePath of configs) {
3360
- const configPath = (0, import_node_path9.join)(workspaceRoot, relativePath);
3361
- const before = (0, import_node_fs7.readFileSync)(configPath, "utf8");
3755
+ const configPath = (0, import_node_path10.join)(workspaceRoot, relativePath);
3756
+ const before = (0, import_node_fs8.readFileSync)(configPath, "utf8");
3362
3757
  const after = withRollupSourceMaps(before);
3363
3758
  if (after !== before) {
3364
3759
  writeFileEnsured(configPath, after);
@@ -3369,12 +3764,12 @@ function repairRollupSourceMaps(workspaceRoot) {
3369
3764
  }
3370
3765
  function upgradeDeclarationSpecifierPlugins(workspaceRoot) {
3371
3766
  const changed = [];
3372
- const configs = (0, import_node_fs7.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
3767
+ const configs = (0, import_node_fs8.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
3373
3768
  cwd: workspaceRoot
3374
3769
  });
3375
3770
  for (const relativePath of configs) {
3376
- const configPath = (0, import_node_path9.join)(workspaceRoot, relativePath);
3377
- const before = (0, import_node_fs7.readFileSync)(configPath, "utf8");
3771
+ const configPath = (0, import_node_path10.join)(workspaceRoot, relativePath);
3772
+ const before = (0, import_node_fs8.readFileSync)(configPath, "utf8");
3378
3773
  const after = withUpgradedDeclarationSpecifierPlugin(before);
3379
3774
  if (after !== before) {
3380
3775
  writeFileEnsured(configPath, after);
@@ -3384,11 +3779,11 @@ function upgradeDeclarationSpecifierPlugins(workspaceRoot) {
3384
3779
  return changed;
3385
3780
  }
3386
3781
  function repairDeclarationSpecifiers(projectRoot) {
3387
- const configPath = (0, import_node_path9.join)(projectRoot, "rollup.config.cjs");
3782
+ const configPath = (0, import_node_path10.join)(projectRoot, "rollup.config.cjs");
3388
3783
  if (!fileExists(configPath)) {
3389
3784
  return;
3390
3785
  }
3391
- const config = (0, import_node_fs7.readFileSync)(configPath, "utf8");
3786
+ const config = (0, import_node_fs8.readFileSync)(configPath, "utf8");
3392
3787
  if (!config.includes(ROLLUP_CONFIG_PLACEHOLDER)) {
3393
3788
  return;
3394
3789
  }
@@ -3397,10 +3792,10 @@ function repairDeclarationSpecifiers(projectRoot) {
3397
3792
  }
3398
3793
 
3399
3794
  // src/rollup-library/rollup-config.repository.ts
3400
- var import_node_fs8 = require("fs");
3401
- var import_node_path10 = require("path");
3795
+ var import_node_fs9 = require("fs");
3796
+ var import_node_path11 = require("path");
3402
3797
  function resolveRequireTarget(fromDir, specifier) {
3403
- const base = (0, import_node_path10.join)(fromDir, specifier);
3798
+ const base = (0, import_node_path11.join)(fromDir, specifier);
3404
3799
  return [base, `${base}.cjs`, `${base}.js`].find((candidate) => fileExists(candidate));
3405
3800
  }
3406
3801
  function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()) {
@@ -3410,7 +3805,7 @@ function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()
3410
3805
  visited.add(configPath);
3411
3806
  let text;
3412
3807
  try {
3413
- text = (0, import_node_fs8.readFileSync)(configPath, "utf8");
3808
+ text = (0, import_node_fs9.readFileSync)(configPath, "utf8");
3414
3809
  } catch {
3415
3810
  return "";
3416
3811
  }
@@ -3418,15 +3813,15 @@ function resolveRollupConfigText(configPath, visited = /* @__PURE__ */ new Set()
3418
3813
  text.matchAll(/require\((['"])(\.[^'"]*)\1\)/g),
3419
3814
  (match) => match[2]
3420
3815
  );
3421
- const requiredText = specifiers.map((specifier) => resolveRequireTarget((0, import_node_path10.dirname)(configPath), specifier)).filter((target) => target !== void 0).map((target) => resolveRollupConfigText(target, visited));
3816
+ const requiredText = specifiers.map((specifier) => resolveRequireTarget((0, import_node_path11.dirname)(configPath), specifier)).filter((target) => target !== void 0).map((target) => resolveRollupConfigText(target, visited));
3422
3817
  return [text, ...requiredText].join("\n");
3423
3818
  }
3424
3819
 
3425
3820
  // src/project-scaffolding/npm-lib.use-case.ts
3426
3821
  async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
3427
3822
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
3428
- const projectRoot = (0, import_node_path11.join)(workspaceRoot, "packages", name);
3429
- const manifestPath = (0, import_node_path11.join)(projectRoot, "package.json");
3823
+ const projectRoot = (0, import_node_path12.join)(workspaceRoot, "packages", name);
3824
+ const manifestPath = (0, import_node_path12.join)(projectRoot, "package.json");
3430
3825
  runGeneratorAndRepair(
3431
3826
  workspaceRoot,
3432
3827
  [
@@ -3455,8 +3850,8 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
3455
3850
  }
3456
3851
 
3457
3852
  // src/project-scaffolding/python.use-case.ts
3458
- var import_node_fs9 = require("fs");
3459
- var import_node_path12 = require("path");
3853
+ var import_node_fs10 = require("fs");
3854
+ var import_node_path13 = require("path");
3460
3855
  function ensurePython(workspaceRoot) {
3461
3856
  const hasPython = runShell("python3", ["--version"], workspaceRoot) === 0 || runShell("python", ["--version"], workspaceRoot) === 0;
3462
3857
  if (!hasPython) {
@@ -3479,7 +3874,7 @@ function ensurePythonPipPlugin(workspaceRoot) {
3479
3874
  registerPythonGraphPlugin(workspaceRoot);
3480
3875
  }
3481
3876
  function registerPythonGraphPlugin(workspaceRoot) {
3482
- const nxJsonPath = (0, import_node_path12.join)(workspaceRoot, "nx.json");
3877
+ const nxJsonPath = (0, import_node_path13.join)(workspaceRoot, "nx.json");
3483
3878
  if (!fileExists(nxJsonPath)) {
3484
3879
  return;
3485
3880
  }
@@ -3502,7 +3897,7 @@ pytest
3502
3897
  pip-audit
3503
3898
  `;
3504
3899
  function ensureRequirementsDev(workspaceRoot) {
3505
- const requirementsDevPath = (0, import_node_path12.join)(workspaceRoot, "requirements-dev.txt");
3900
+ const requirementsDevPath = (0, import_node_path13.join)(workspaceRoot, "requirements-dev.txt");
3506
3901
  if (!fileExists(requirementsDevPath)) {
3507
3902
  writeFileEnsured(requirementsDevPath, PYTHON_REQUIREMENTS_DEV);
3508
3903
  }
@@ -3562,8 +3957,8 @@ function addPythonApp(workspaceRoot, name) {
3562
3957
  ["g", "@mnci/nx-python-pip:application", name, `--directory=apps/${name}`, "--no-interactive"],
3563
3958
  workspaceRoot
3564
3959
  );
3565
- writeFileEnsured((0, import_node_path12.join)(workspaceRoot, "apps", name, "main.py"), pythonAppMain(name));
3566
- addProjectJsonTargets((0, import_node_path12.join)(workspaceRoot, "apps", name, "project.json"), {
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"), {
3567
3962
  package: pythonAppPackageTarget(name),
3568
3963
  start: pythonAppStartTarget(name)
3569
3964
  });
@@ -3585,7 +3980,7 @@ function addPythonFunctionApp(workspaceRoot, name) {
3585
3980
  workspaceRoot
3586
3981
  );
3587
3982
  const moduleDirectory = pythonModuleDirectory(name);
3588
- addProjectJsonTargets((0, import_node_path12.join)(workspaceRoot, "apps", name, "project.json"), {
3983
+ addProjectJsonTargets((0, import_node_path13.join)(workspaceRoot, "apps", name, "project.json"), {
3589
3984
  package: pythonFunctionAppPackageTarget(name, moduleDirectory),
3590
3985
  start: pythonFunctionAppStartTarget(name)
3591
3986
  });
@@ -3626,7 +4021,7 @@ function addPythonInternalLib(workspaceRoot, name) {
3626
4021
  var PYTHON_PROJECT_DIRS = ["apps", "python-packages", "libs"];
3627
4022
  function findPythonProjectDirectory(workspaceRoot, name) {
3628
4023
  return PYTHON_PROJECT_DIRS.find(
3629
- (directory) => fileExists((0, import_node_path12.join)(workspaceRoot, directory, name, "pyproject.toml"))
4024
+ (directory) => fileExists((0, import_node_path13.join)(workspaceRoot, directory, name, "pyproject.toml"))
3630
4025
  );
3631
4026
  }
3632
4027
  function parseVendorEntries(pyprojectToml) {
@@ -3665,7 +4060,7 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
3665
4060
  `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.`
3666
4061
  );
3667
4062
  }
3668
- if (!fileExists((0, import_node_path12.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
4063
+ if (!fileExists((0, import_node_path13.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
3669
4064
  throw new Error(
3670
4065
  `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.`
3671
4066
  );
@@ -3673,8 +4068,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
3673
4068
  if (consumerDirectory === "libs" && consumer === lib) {
3674
4069
  throw new Error(`'${consumer}' cannot vendor itself.`);
3675
4070
  }
3676
- const pyprojectPath = (0, import_node_path12.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
3677
- const pyprojectToml = (0, import_node_fs9.readFileSync)(pyprojectPath, "utf8");
4071
+ const pyprojectPath = (0, import_node_path13.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
4072
+ const pyprojectToml = (0, import_node_fs10.readFileSync)(pyprojectPath, "utf8");
3678
4073
  if (parseVendorEntries(pyprojectToml).includes(lib)) {
3679
4074
  logger.info(`'${consumer}' already vendors '${lib}' \u2014 nothing to do.`);
3680
4075
  return;
@@ -3686,8 +4081,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
3686
4081
  }
3687
4082
 
3688
4083
  // src/project-scaffolding/react-app.use-case.ts
3689
- var import_node_fs10 = require("fs");
3690
- var import_node_path13 = require("path");
4084
+ var import_node_fs11 = require("fs");
4085
+ var import_node_path14 = require("path");
3691
4086
  var REACT_ENVIRONMENTS = ["dev", "uat", "prod"];
3692
4087
  function reactEnvironmentFile(environment) {
3693
4088
  return `# Vite compiles VITE_-prefixed vars into the '${environment}' bundle at build time.
@@ -3724,12 +4119,12 @@ function reactAppTargets(name) {
3724
4119
  return targets;
3725
4120
  }
3726
4121
  function allowEnvFiles(workspaceRoot) {
3727
- const gitignorePath = (0, import_node_path13.join)(workspaceRoot, ".gitignore");
4122
+ const gitignorePath = (0, import_node_path14.join)(workspaceRoot, ".gitignore");
3728
4123
  if (!fileExists(gitignorePath)) {
3729
4124
  return;
3730
4125
  }
3731
4126
  const marker = "# MoNecromanCI: keep the committed per-environment Vite config (public VITE_ values)";
3732
- const current = (0, import_node_fs10.readFileSync)(gitignorePath, "utf8");
4127
+ const current = (0, import_node_fs11.readFileSync)(gitignorePath, "utf8");
3733
4128
  if (current.includes(marker)) {
3734
4129
  return;
3735
4130
  }
@@ -3756,24 +4151,24 @@ function addReactApp(workspaceRoot, name, stack) {
3756
4151
  workspaceRoot
3757
4152
  );
3758
4153
  ensureAdmZip(workspaceRoot);
3759
- const reactAppRoot = (0, import_node_path13.join)(workspaceRoot, "apps", name);
4154
+ const reactAppRoot = (0, import_node_path14.join)(workspaceRoot, "apps", name);
3760
4155
  for (const environment of REACT_ENVIRONMENTS) {
3761
- writeFileEnsured((0, import_node_path13.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
4156
+ writeFileEnsured((0, import_node_path14.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
3762
4157
  }
3763
4158
  allowEnvFiles(workspaceRoot);
3764
- addNxTargets((0, import_node_path13.join)(reactAppRoot, "package.json"), reactAppTargets(name));
4159
+ addNxTargets((0, import_node_path14.join)(reactAppRoot, "package.json"), reactAppTargets(name));
3765
4160
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
3766
4161
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:serve` });
3767
4162
  }
3768
4163
 
3769
4164
  // src/project-scaffolding/react-lib.use-case.ts
3770
- var import_node_path14 = require("path");
4165
+ var import_node_path15 = require("path");
3771
4166
  var REACT_LIB_BUNDLER = "rollup";
3772
4167
  async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
3773
4168
  ensurePlugin(workspaceRoot, "@nx/react");
3774
4169
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
3775
- const projectRoot = (0, import_node_path14.join)(workspaceRoot, "packages", name);
3776
- const publishableManifest = (0, import_node_path14.join)(projectRoot, "package.json");
4170
+ const projectRoot = (0, import_node_path15.join)(workspaceRoot, "packages", name);
4171
+ const publishableManifest = (0, import_node_path15.join)(projectRoot, "package.json");
3777
4172
  runGeneratorAndRepair(
3778
4173
  workspaceRoot,
3779
4174
  [
@@ -3802,8 +4197,8 @@ async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
3802
4197
  }
3803
4198
  function addReactInternalLib(workspaceRoot, name, stack) {
3804
4199
  ensurePlugin(workspaceRoot, "@nx/react");
3805
- const projectRoot = (0, import_node_path14.join)(workspaceRoot, "libs", name);
3806
- const privateManifest = (0, import_node_path14.join)(projectRoot, "package.json");
4200
+ const projectRoot = (0, import_node_path15.join)(workspaceRoot, "libs", name);
4201
+ const privateManifest = (0, import_node_path15.join)(projectRoot, "package.json");
3807
4202
  runGeneratorAndRepair(
3808
4203
  workspaceRoot,
3809
4204
  [
@@ -3829,8 +4224,8 @@ function addReactInternalLib(workspaceRoot, name, stack) {
3829
4224
  }
3830
4225
 
3831
4226
  // src/project-scaffolding/vscode-extension.use-case.ts
3832
- var import_node_fs11 = require("fs");
3833
- var import_node_path15 = require("path");
4227
+ var import_node_fs12 = require("fs");
4228
+ var import_node_path16 = require("path");
3834
4229
  var VSCODE_EXTENSION_SCRIPT_PATH = "tools/vscode-extension.cjs";
3835
4230
  var VSCODE_SIDECAR_TARGETS = {
3836
4231
  "win32-x64": "windows-amd64",
@@ -4014,8 +4409,8 @@ export const window = {
4014
4409
  var VSCODE_STUB_PATH = "test/vscode.stub.ts";
4015
4410
  function mapVscodeToStub(projectRoot, testRunner) {
4016
4411
  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}\` },`];
4017
- const path = (0, import_node_path15.join)(projectRoot, file);
4018
- const content = fileExists(path) ? (0, import_node_fs11.readFileSync)(path, "utf8") : "";
4412
+ const path = (0, import_node_path16.join)(projectRoot, file);
4413
+ const content = fileExists(path) ? (0, import_node_fs12.readFileSync)(path, "utf8") : "";
4019
4414
  const line = content.split("\n").find((candidate) => candidate.trim() === anchor);
4020
4415
  if (line === void 0) {
4021
4416
  throw new Error(`${file} has no "${anchor}" line to map the vscode module after; map 'vscode' to ${VSCODE_STUB_PATH} by hand.`);
@@ -4035,11 +4430,11 @@ function ensureVscodeToolchain(workspaceRoot) {
4035
4430
  }
4036
4431
  }
4037
4432
  function defaultPublisher(workspaceRoot) {
4038
- const { name } = readJson((0, import_node_path15.join)(workspaceRoot, "package.json"));
4433
+ const { name } = readJson((0, import_node_path16.join)(workspaceRoot, "package.json"));
4039
4434
  return (name ?? "publisher").replace(/^@/, "").split("/", 1)[0];
4040
4435
  }
4041
4436
  function reshapeManifest(projectRoot, name, publisher, typesVersion) {
4042
- const manifestPath = (0, import_node_path15.join)(projectRoot, "package.json");
4437
+ const manifestPath = (0, import_node_path16.join)(projectRoot, "package.json");
4043
4438
  const manifest = readJson(manifestPath);
4044
4439
  const { nx = {}, ...rest } = manifest;
4045
4440
  const targets = { ...nx.targets };
@@ -4103,11 +4498,11 @@ function vscodeExtensionPublishTarget(name, sidecar) {
4103
4498
  };
4104
4499
  }
4105
4500
  function addDebugLaunch(workspaceRoot, name) {
4106
- const file = (0, import_node_fs11.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
4501
+ const file = (0, import_node_fs12.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
4107
4502
  if (file === void 0) {
4108
4503
  return;
4109
4504
  }
4110
- const path = (0, import_node_path15.join)(workspaceRoot, file);
4505
+ const path = (0, import_node_path16.join)(workspaceRoot, file);
4111
4506
  const workspace = readCodeWorkspace(path) ?? {};
4112
4507
  const folder = `\${workspaceFolder:${workspace.folders?.[0]?.name ?? file.replace(/\.code-workspace$/, "")}}`;
4113
4508
  const taskLabel = `${name}: build (development)`;
@@ -4140,39 +4535,39 @@ function addDebugLaunch(workspaceRoot, name) {
4140
4535
  );
4141
4536
  }
4142
4537
  function refreshVscodeExtensionScript(workspaceRoot) {
4143
- const apps = (0, import_node_path15.join)(workspaceRoot, "apps");
4538
+ const apps = (0, import_node_path16.join)(workspaceRoot, "apps");
4144
4539
  let entries;
4145
4540
  try {
4146
- entries = (0, import_node_fs11.readdirSync)(apps);
4541
+ entries = (0, import_node_fs12.readdirSync)(apps);
4147
4542
  } catch {
4148
4543
  return false;
4149
4544
  }
4150
4545
  const hasExtension = entries.some((entry) => {
4151
- const manifestPath = (0, import_node_path15.join)(apps, entry, "package.json");
4546
+ const manifestPath = (0, import_node_path16.join)(apps, entry, "package.json");
4152
4547
  if (!fileExists(manifestPath)) {
4153
4548
  return false;
4154
4549
  }
4155
4550
  const tags = readJson(manifestPath).nx?.tags ?? [];
4156
4551
  return tags.includes(VSCODE_EXTENSION_TAG);
4157
4552
  });
4158
- const path = (0, import_node_path15.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
4159
- if (!hasExtension || fileExists(path) && (0, import_node_fs11.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
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) {
4160
4555
  return false;
4161
4556
  }
4162
4557
  writeFileEnsured(path, VSCODE_EXTENSION_SCRIPT);
4163
4558
  return true;
4164
4559
  }
4165
4560
  function pinVscodeExtensionProjectNames(workspaceRoot) {
4166
- const apps = (0, import_node_path15.join)(workspaceRoot, "apps");
4561
+ const apps = (0, import_node_path16.join)(workspaceRoot, "apps");
4167
4562
  let entries;
4168
4563
  try {
4169
- entries = (0, import_node_fs11.readdirSync)(apps);
4564
+ entries = (0, import_node_fs12.readdirSync)(apps);
4170
4565
  } catch {
4171
4566
  return [];
4172
4567
  }
4173
4568
  const updated = [];
4174
4569
  for (const entry of entries) {
4175
- const manifestPath = (0, import_node_path15.join)(apps, entry, "package.json");
4570
+ const manifestPath = (0, import_node_path16.join)(apps, entry, "package.json");
4176
4571
  if (!fileExists(manifestPath)) {
4177
4572
  continue;
4178
4573
  }
@@ -4192,23 +4587,23 @@ function refreshLockFile(workspaceRoot, name) {
4192
4587
  }
4193
4588
  function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4194
4589
  const { sidecar } = options;
4195
- if (sidecar !== void 0 && !fileExists((0, import_node_path15.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
4590
+ if (sidecar !== void 0 && !fileExists((0, import_node_path16.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
4196
4591
  throw new Error(`--sidecar ${sidecar}: no Go app at apps/${sidecar}. Add it first with \`mnci add go-app ${sidecar}\`.`);
4197
4592
  }
4198
4593
  runNodeApp(workspaceRoot, name, stack, "none");
4199
4594
  ensureVscodeToolchain(workspaceRoot);
4200
- const projectRoot = (0, import_node_path15.join)(workspaceRoot, "apps", name);
4201
- const typesVersion = readJson((0, import_node_path15.join)(workspaceRoot, "node_modules/@types/vscode/package.json")).version;
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;
4202
4597
  reshapeManifest(projectRoot, name, options.publisher ?? defaultPublisher(workspaceRoot), typesVersion);
4203
- addVscodeTypes((0, import_node_path15.join)(projectRoot, "tsconfig.app.json"));
4204
- addVscodeTypes((0, import_node_path15.join)(projectRoot, "tsconfig.spec.json"));
4205
- writeFileEnsured((0, import_node_path15.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
4206
- writeFileEnsured((0, import_node_path15.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
4207
- writeFileEnsured((0, import_node_path15.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
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);
4208
4603
  mapVscodeToStub(projectRoot, stack.testRunner);
4209
- writeFileEnsured((0, import_node_path15.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
4210
- writeFileEnsured((0, import_node_path15.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
4211
- addNxTargets((0, import_node_path15.join)(projectRoot, "package.json"), {
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"), {
4212
4607
  "package": vscodeExtensionPackageTarget(name, sidecar),
4213
4608
  "nx-release-publish": vscodeExtensionPublishTarget(name, sidecar)
4214
4609
  });
@@ -4219,11 +4614,11 @@ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4219
4614
  }
4220
4615
 
4221
4616
  // src/dependency-management/sync-dependencies.use-case.ts
4222
- var import_node_path17 = require("path");
4617
+ var import_node_path18 = require("path");
4223
4618
 
4224
4619
  // src/dependency-management/manifest.repository.ts
4225
- var import_node_fs12 = require("fs");
4226
- var import_node_path16 = require("path");
4620
+ var import_node_fs13 = require("fs");
4621
+ var import_node_path17 = require("path");
4227
4622
  var ECOSYSTEMS = ["npm", "pip", "pub", "nuget", "go"];
4228
4623
  var ROOT_LABEL = "(root)";
4229
4624
  var MANIFEST_GLOBS = {
@@ -4256,23 +4651,23 @@ function projectOf(manifestRelativePath) {
4256
4651
  }
4257
4652
  function hasEcosystem(workspaceRoot, ecosystem) {
4258
4653
  if (ecosystem === "go") {
4259
- return fileExists((0, import_node_path16.join)(workspaceRoot, "go.mod"));
4654
+ return fileExists((0, import_node_path17.join)(workspaceRoot, "go.mod"));
4260
4655
  }
4261
4656
  if (ecosystem === "nuget") {
4262
- return (0, import_node_fs12.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
4657
+ return (0, import_node_fs13.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
4263
4658
  }
4264
4659
  const rootMarker = {
4265
4660
  npm: "package.json",
4266
4661
  pip: "requirements-dev.txt",
4267
4662
  pub: "pubspec.yaml"
4268
4663
  };
4269
- return fileExists((0, import_node_path16.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs12.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
4664
+ return fileExists((0, import_node_path17.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs13.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
4270
4665
  }
4271
4666
  function collectNpm(workspaceRoot) {
4272
4667
  const sites = [];
4273
- const relativePaths = ["package.json", ...(0, import_node_fs12.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
4668
+ const relativePaths = ["package.json", ...(0, import_node_fs13.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
4274
4669
  for (const relativePath of relativePaths) {
4275
- const manifestPath = (0, import_node_path16.join)(workspaceRoot, relativePath);
4670
+ const manifestPath = (0, import_node_path17.join)(workspaceRoot, relativePath);
4276
4671
  try {
4277
4672
  const manifest = readJson(manifestPath);
4278
4673
  sites.push(...npmManifestSites(manifest, relativePath, manifestPath));
@@ -4333,17 +4728,17 @@ function collectPip(workspaceRoot) {
4333
4728
  name: parsed.name,
4334
4729
  ecosystem: "pip",
4335
4730
  project: projectOf(relativePath),
4336
- manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
4731
+ manifestPath: (0, import_node_path17.join)(workspaceRoot, relativePath),
4337
4732
  section,
4338
4733
  spec: parsed.spec,
4339
4734
  rewritable: parsed.rewritable && parsed.spec !== ""
4340
4735
  });
4341
4736
  };
4342
- const pyprojectPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
4737
+ const pyprojectPaths = (0, import_node_fs13.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
4343
4738
  for (const relativePath of pyprojectPaths) {
4344
4739
  let content;
4345
4740
  try {
4346
- content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
4741
+ content = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8");
4347
4742
  } catch {
4348
4743
  continue;
4349
4744
  }
@@ -4354,14 +4749,14 @@ function collectPip(workspaceRoot) {
4354
4749
  }
4355
4750
  const requirementsPaths = [
4356
4751
  "requirements-dev.txt",
4357
- ...(0, import_node_fs12.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
4752
+ ...(0, import_node_fs13.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
4358
4753
  ];
4359
4754
  for (const relativePath of requirementsPaths) {
4360
- if (!fileExists((0, import_node_path16.join)(workspaceRoot, relativePath))) {
4755
+ if (!fileExists((0, import_node_path17.join)(workspaceRoot, relativePath))) {
4361
4756
  continue;
4362
4757
  }
4363
4758
  const section = relativePath === "requirements-dev.txt" ? "devDep" : "dep";
4364
- const lines = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
4759
+ const lines = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
4365
4760
  for (const line of lines) {
4366
4761
  push(relativePath, section, line);
4367
4762
  }
@@ -4399,11 +4794,11 @@ function pyprojectDependencies(content) {
4399
4794
  }
4400
4795
  function collectPub(workspaceRoot) {
4401
4796
  const sites = [];
4402
- const pubspecPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
4797
+ const pubspecPaths = (0, import_node_fs13.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
4403
4798
  for (const relativePath of pubspecPaths) {
4404
4799
  let content;
4405
4800
  try {
4406
- content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
4801
+ content = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8");
4407
4802
  } catch {
4408
4803
  continue;
4409
4804
  }
@@ -4413,7 +4808,7 @@ function collectPub(workspaceRoot) {
4413
4808
  name: entry.name,
4414
4809
  ecosystem: "pub",
4415
4810
  project: projectOf(relativePath),
4416
- manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
4811
+ manifestPath: (0, import_node_path17.join)(workspaceRoot, relativePath),
4417
4812
  section: block === "dependencies" ? "dep" : "devDep",
4418
4813
  spec: entry.spec,
4419
4814
  rewritable: entry.spec !== ""
@@ -4463,11 +4858,11 @@ function stripQuotes(value) {
4463
4858
  }
4464
4859
  function collectNuget(workspaceRoot) {
4465
4860
  const sites = [];
4466
- const csprojPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
4861
+ const csprojPaths = (0, import_node_fs13.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
4467
4862
  for (const relativePath of csprojPaths) {
4468
4863
  let content;
4469
4864
  try {
4470
- content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
4865
+ content = (0, import_node_fs13.readFileSync)((0, import_node_path17.join)(workspaceRoot, relativePath), "utf8");
4471
4866
  } catch {
4472
4867
  continue;
4473
4868
  }
@@ -4476,7 +4871,7 @@ function collectNuget(workspaceRoot) {
4476
4871
  name: entry.name,
4477
4872
  ecosystem: "nuget",
4478
4873
  project: projectOf(relativePath),
4479
- manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
4874
+ manifestPath: (0, import_node_path17.join)(workspaceRoot, relativePath),
4480
4875
  section: "dep",
4481
4876
  spec: entry.spec,
4482
4877
  // A plain SemVer string is rewritable; an MSBuild property reference
@@ -4501,13 +4896,13 @@ function csprojPackageReferences(content) {
4501
4896
  return entries;
4502
4897
  }
4503
4898
  function collectGo(workspaceRoot) {
4504
- const manifestPath = (0, import_node_path16.join)(workspaceRoot, "go.mod");
4899
+ const manifestPath = (0, import_node_path17.join)(workspaceRoot, "go.mod");
4505
4900
  if (!fileExists(manifestPath)) {
4506
4901
  return [];
4507
4902
  }
4508
4903
  let content;
4509
4904
  try {
4510
- content = (0, import_node_fs12.readFileSync)(manifestPath, "utf8");
4905
+ content = (0, import_node_fs13.readFileSync)(manifestPath, "utf8");
4511
4906
  } catch {
4512
4907
  return [];
4513
4908
  }
@@ -4564,7 +4959,7 @@ function rewriteSpec(site, spec) {
4564
4959
  writeFileEnsured(site.manifestPath, toJson(manifest));
4565
4960
  return true;
4566
4961
  }
4567
- const before = (0, import_node_fs12.readFileSync)(site.manifestPath, "utf8");
4962
+ const before = (0, import_node_fs13.readFileSync)(site.manifestPath, "utf8");
4568
4963
  const after = (() => {
4569
4964
  switch (site.ecosystem) {
4570
4965
  case "pip": {
@@ -4620,13 +5015,13 @@ function escapeForRegex(value) {
4620
5015
  function isWorkspaceProject(workspaceRoot, name) {
4621
5016
  const short = name.includes("/") ? name.split("/").at(-1) : name;
4622
5017
  return ["apps", "libs", "packages"].some(
4623
- (directory) => fileExists((0, import_node_path16.join)(workspaceRoot, directory, short ?? name, "package.json"))
5018
+ (directory) => fileExists((0, import_node_path17.join)(workspaceRoot, directory, short ?? name, "package.json"))
4624
5019
  );
4625
5020
  }
4626
5021
  function isAliasedInstall(workspaceRoot, name) {
4627
5022
  try {
4628
5023
  const installed = readJson(
4629
- (0, import_node_path16.join)(workspaceRoot, "node_modules", name, "package.json")
5024
+ (0, import_node_path17.join)(workspaceRoot, "node_modules", name, "package.json")
4630
5025
  );
4631
5026
  return installed.name !== void 0 && installed.name !== name;
4632
5027
  } catch {
@@ -4637,14 +5032,14 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
4637
5032
  if (ecosystem === "npm") {
4638
5033
  try {
4639
5034
  return readJson(
4640
- (0, import_node_path16.join)(workspaceRoot, "node_modules", name, "package.json")
5035
+ (0, import_node_path17.join)(workspaceRoot, "node_modules", name, "package.json")
4641
5036
  ).version;
4642
5037
  } catch {
4643
5038
  return void 0;
4644
5039
  }
4645
5040
  }
4646
5041
  if (ecosystem === "pub") {
4647
- const lockPath = (0, import_node_path16.join)(workspaceRoot, "pubspec.lock");
5042
+ const lockPath = (0, import_node_path17.join)(workspaceRoot, "pubspec.lock");
4648
5043
  if (!fileExists(lockPath)) {
4649
5044
  return void 0;
4650
5045
  }
@@ -4652,7 +5047,7 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
4652
5047
  const match = new RegExp(
4653
5048
  String.raw`^\s{2}${escapeForRegex(name)}:[^]*?^\s+version:\s*["']?([^"'\s]+)`,
4654
5049
  "m"
4655
- ).exec((0, import_node_fs12.readFileSync)(lockPath, "utf8"));
5050
+ ).exec((0, import_node_fs13.readFileSync)(lockPath, "utf8"));
4656
5051
  return match?.[1];
4657
5052
  } catch {
4658
5053
  return void 0;
@@ -4844,7 +5239,7 @@ function describe(finding) {
4844
5239
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
4845
5240
  }
4846
5241
  function runSync(workspaceRoot, options) {
4847
- if (!fileExists((0, import_node_path17.join)(workspaceRoot, "nx.json"))) {
5242
+ if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
4848
5243
  throw new Error(
4849
5244
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
4850
5245
  );
@@ -4894,7 +5289,7 @@ function runSync(workspaceRoot, options) {
4894
5289
  }
4895
5290
 
4896
5291
  // src/dependency-management/update-dependencies.use-case.ts
4897
- var import_node_path18 = require("path");
5292
+ var import_node_path19 = require("path");
4898
5293
  var import_prompts2 = require("@inquirer/prompts");
4899
5294
 
4900
5295
  // src/dependency-management/registry.client.ts
@@ -5177,7 +5572,7 @@ function reinstall(workspaceRoot, ecosystems) {
5177
5572
  function hasPythonInstallScript(workspaceRoot) {
5178
5573
  try {
5179
5574
  const manifest = readJson(
5180
- (0, import_node_path18.join)(workspaceRoot, "package.json")
5575
+ (0, import_node_path19.join)(workspaceRoot, "package.json")
5181
5576
  );
5182
5577
  return manifest.scripts?.["python:install"] !== void 0;
5183
5578
  } catch {
@@ -5193,7 +5588,7 @@ function applyGoUpdates(workspaceRoot, entries) {
5193
5588
  }
5194
5589
  }
5195
5590
  async function runUp(workspaceRoot, options) {
5196
- if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
5591
+ if (!fileExists((0, import_node_path19.join)(workspaceRoot, "nx.json"))) {
5197
5592
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
5198
5593
  }
5199
5594
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -5269,7 +5664,7 @@ var PROJECT_KINDS = [
5269
5664
  ];
5270
5665
  async function runAdd(kind, name, options) {
5271
5666
  const workspaceRoot = process.cwd();
5272
- if (!fileExists((0, import_node_path19.join)(workspaceRoot, "nx.json"))) {
5667
+ if (!fileExists((0, import_node_path20.join)(workspaceRoot, "nx.json"))) {
5273
5668
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
5274
5669
  }
5275
5670
  const stack = readWorkspaceStack(workspaceRoot);
@@ -5278,6 +5673,11 @@ async function runAdd(kind, name, options) {
5278
5673
  message: "What kind of project?",
5279
5674
  choices: PROJECT_KINDS.map((value) => ({ name: value, value }))
5280
5675
  });
5676
+ for (const [flag, requested] of [["--release", options.release], ["--cgo", options.cgo]]) {
5677
+ if (resolvedKind !== "go-app" && requested === true) {
5678
+ throw new Error(`${flag} applies to go-app only, not ${resolvedKind}.`);
5679
+ }
5680
+ }
5281
5681
  const resolvedName = name ?? await promptText("Project name");
5282
5682
  assertValidProjectName(resolvedName, "Project name");
5283
5683
  const rootDependenciesBefore = rootRuntimeDependencies(workspaceRoot);
@@ -5320,8 +5720,8 @@ async function runAdd(kind, name, options) {
5320
5720
  ],
5321
5721
  workspaceRoot
5322
5722
  );
5323
- markPrivate((0, import_node_path19.join)(workspaceRoot, "libs", resolvedName, "package.json"));
5324
- renameScaffoldPlaceholder((0, import_node_path19.join)(workspaceRoot, "libs", resolvedName), resolvedName);
5723
+ markPrivate((0, import_node_path20.join)(workspaceRoot, "libs", resolvedName, "package.json"));
5724
+ renameScaffoldPlaceholder((0, import_node_path20.join)(workspaceRoot, "libs", resolvedName), resolvedName);
5325
5725
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
5326
5726
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
5327
5727
  break;
@@ -5343,7 +5743,7 @@ async function runAdd(kind, name, options) {
5343
5743
  break;
5344
5744
  }
5345
5745
  case "go-app": {
5346
- addGoApp(workspaceRoot, resolvedName);
5746
+ addGoApp(workspaceRoot, resolvedName, { release: options.release, cgo: options.cgo });
5347
5747
  break;
5348
5748
  }
5349
5749
  case "go-function-app": {
@@ -5413,7 +5813,7 @@ async function runAdd(kind, name, options) {
5413
5813
  }
5414
5814
  function readWorkspaceStack(workspaceRoot) {
5415
5815
  const nxJson = readJson(
5416
- (0, import_node_path19.join)(workspaceRoot, "nx.json")
5816
+ (0, import_node_path20.join)(workspaceRoot, "nx.json")
5417
5817
  );
5418
5818
  const stack = nxJson.mnci?.stack;
5419
5819
  return {
@@ -5422,15 +5822,16 @@ function readWorkspaceStack(workspaceRoot) {
5422
5822
  }
5423
5823
 
5424
5824
  // src/workspace-diagnostics/check-invariants.use-case.ts
5425
- var import_node_fs13 = require("fs");
5426
- var import_node_path20 = require("path");
5825
+ var import_node_child_process = require("child_process");
5826
+ var import_node_fs14 = require("fs");
5827
+ var import_node_path21 = require("path");
5427
5828
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
5428
5829
  function toPosix2(path) {
5429
5830
  return path.replaceAll("\\", "/");
5430
5831
  }
5431
5832
  function checkEslintConfigs(workspaceRoot) {
5432
- const rootConfigs = (0, import_node_fs13.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
5433
- const projectConfigs = (0, import_node_fs13.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
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}", {
5434
5835
  cwd: workspaceRoot
5435
5836
  }).map((config) => toPosix2(config));
5436
5837
  return [
@@ -5450,10 +5851,10 @@ function checkEslintConfigs(workspaceRoot) {
5450
5851
  ];
5451
5852
  }
5452
5853
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
5453
- const rules = (0, import_node_path20.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
5454
- if (!(0, import_node_fs13.existsSync)(rules)) return [];
5455
- const entryPoint = (0, import_node_path20.join)(workspaceRoot, ESLINT_USER_FILENAME);
5456
- const source = (0, import_node_fs13.existsSync)(entryPoint) ? (0, import_node_fs13.readFileSync)(entryPoint, "utf8") : "";
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") : "";
5457
5858
  return [
5458
5859
  {
5459
5860
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -5466,7 +5867,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
5466
5867
  function declaredDevDependencies(workspaceRoot) {
5467
5868
  try {
5468
5869
  const manifest = readJson(
5469
- (0, import_node_path20.join)(workspaceRoot, "package.json")
5870
+ (0, import_node_path21.join)(workspaceRoot, "package.json")
5470
5871
  );
5471
5872
  return manifest.devDependencies ?? {};
5472
5873
  } catch {
@@ -5474,7 +5875,7 @@ function declaredDevDependencies(workspaceRoot) {
5474
5875
  }
5475
5876
  }
5476
5877
  function checkNoRetiredFormatter(workspaceRoot) {
5477
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path20.join)(workspaceRoot, file)));
5878
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path21.join)(workspaceRoot, file)));
5478
5879
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
5479
5880
  const stale = [...files, ...declared];
5480
5881
  if (stale.length === 0) {
@@ -5500,7 +5901,7 @@ function checkEslintPlugin(nxJson) {
5500
5901
  };
5501
5902
  }
5502
5903
  function checkResolvedEslint(workspaceRoot) {
5503
- const manifestPath = (0, import_node_path20.join)(workspaceRoot, "node_modules/eslint/package.json");
5904
+ const manifestPath = (0, import_node_path21.join)(workspaceRoot, "node_modules/eslint/package.json");
5504
5905
  if (!fileExists(manifestPath)) {
5505
5906
  return void 0;
5506
5907
  }
@@ -5518,11 +5919,11 @@ function checkResolvedEslint(workspaceRoot) {
5518
5919
  }
5519
5920
  }
5520
5921
  function checkNpmrc(workspaceRoot, registry, scope) {
5521
- const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5922
+ const npmrcPath = (0, import_node_path21.join)(workspaceRoot, ".npmrc");
5522
5923
  if (!registry || !fileExists(npmrcPath)) {
5523
5924
  return void 0;
5524
5925
  }
5525
- const npmrc = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8");
5926
+ const npmrc = (0, import_node_fs14.readFileSync)(npmrcPath, "utf8");
5526
5927
  if (registry.kind === "npm") {
5527
5928
  return {
5528
5929
  check: ".npmrc authenticates the public registry",
@@ -5539,11 +5940,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
5539
5940
  };
5540
5941
  }
5541
5942
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
5542
- const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5943
+ const npmrcPath = (0, import_node_path21.join)(workspaceRoot, ".npmrc");
5543
5944
  if (!fileExists(npmrcPath)) {
5544
5945
  return void 0;
5545
5946
  }
5546
- const npmrc = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8");
5947
+ const npmrc = (0, import_node_fs14.readFileSync)(npmrcPath, "utf8");
5547
5948
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5548
5949
  const referenced = [
5549
5950
  ...new Set(
@@ -5567,13 +5968,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
5567
5968
  };
5568
5969
  }
5569
5970
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
5570
- const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5571
- const pipelinePath = (0, import_node_path20.join)(workspaceRoot, "azure-pipelines.yml");
5971
+ const npmrcPath = (0, import_node_path21.join)(workspaceRoot, ".npmrc");
5972
+ const pipelinePath = (0, import_node_path21.join)(workspaceRoot, "azure-pipelines.yml");
5572
5973
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
5573
5974
  return void 0;
5574
5975
  }
5575
- const holdsCredentials = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5576
- const runsTask = (0, import_node_fs13.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
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");
5577
5978
  if (!holdsCredentials && !runsTask) {
5578
5979
  return {
5579
5980
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -5618,13 +6019,13 @@ function npmjsCredentialShape(credentials, environment) {
5618
6019
  }
5619
6020
  function checkVersionActions(workspaceRoot) {
5620
6021
  const candidates = [
5621
- ...(0, import_node_fs13.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
5622
- ...(0, import_node_fs13.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
5623
- ...(0, import_node_fs13.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
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 })
5624
6025
  ].map((manifest) => toPosix2(manifest));
5625
6026
  return candidates.flatMap((manifest) => {
5626
6027
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
5627
- const projectJsonPath = (0, import_node_path20.join)(workspaceRoot, projectRoot, "project.json");
6028
+ const projectJsonPath = (0, import_node_path21.join)(workspaceRoot, projectRoot, "project.json");
5628
6029
  let hasOverride = false;
5629
6030
  try {
5630
6031
  const projectJson = readJson(projectJsonPath);
@@ -5653,7 +6054,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
5653
6054
  ]) {
5654
6055
  try {
5655
6056
  const targets = extract(
5656
- readJson((0, import_node_path20.join)(workspaceRoot, projectRoot, file))
6057
+ readJson((0, import_node_path21.join)(workspaceRoot, projectRoot, file))
5657
6058
  );
5658
6059
  if (targets && typeof targets === "object") {
5659
6060
  sources.push({
@@ -5669,8 +6070,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
5669
6070
  function checkTargetFilesExist(workspaceRoot) {
5670
6071
  const projectRoots = new Set(
5671
6072
  [
5672
- ...(0, import_node_fs13.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
5673
- ...(0, import_node_fs13.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
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 })
5674
6075
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
5675
6076
  );
5676
6077
  return [...projectRoots].flatMap(
@@ -5685,7 +6086,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
5685
6086
  return TARGET_FILE_OPTIONS.flatMap((option) => {
5686
6087
  const value = target?.options?.[option];
5687
6088
  const checkable = typeof value === "string" && !value.includes("{");
5688
- if (!checkable || fileExists((0, import_node_path20.join)(workspaceRoot, value))) {
6089
+ if (!checkable || fileExists((0, import_node_path21.join)(workspaceRoot, value))) {
5689
6090
  return [];
5690
6091
  }
5691
6092
  return [
@@ -5706,8 +6107,34 @@ function checkSync(workspaceRoot) {
5706
6107
  remedy: "run `npx nx sync` and commit the result"
5707
6108
  };
5708
6109
  }
6110
+ function hasCCompiler() {
6111
+ const candidates = [process.env.CC?.split(" ", 1)[0], "gcc", "clang", "cc"];
6112
+ return candidates.some((command) => command !== void 0 && command !== "" && (0, import_node_child_process.spawnSync)(command, ["--version"], { stdio: "ignore" }).status === 0);
6113
+ }
6114
+ function checkNativeApps(workspaceRoot) {
6115
+ if (!hasNativeGoApp(workspaceRoot)) {
6116
+ return [];
6117
+ }
6118
+ const pipelines = [
6119
+ { file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
6120
+ { file: "azure-pipelines.yml", marker: "- job: native" }
6121
+ ];
6122
+ const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path21.join)(workspaceRoot, file))).map(({ file, marker }) => ({
6123
+ 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),
6125
+ detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
6126
+ remedy: "run `mnci upgrade`"
6127
+ }));
6128
+ findings.push({
6129
+ check: "a C compiler is installed (cgo needs one)",
6130
+ ok: hasCCompiler(),
6131
+ detail: "none of CC, gcc, clang or cc answered --version, so nx run <app>:build-native cannot build here",
6132
+ remedy: "install one: Xcode command line tools on macOS, build-essential on Linux, MinGW-w64 (gcc) on Windows"
6133
+ });
6134
+ return findings;
6135
+ }
5709
6136
  function checkNoRootRuntimeDependencies(workspaceRoot) {
5710
- const manifestPath = (0, import_node_path20.join)(workspaceRoot, "package.json");
6137
+ const manifestPath = (0, import_node_path21.join)(workspaceRoot, "package.json");
5711
6138
  if (!fileExists(manifestPath)) {
5712
6139
  return void 0;
5713
6140
  }
@@ -5727,14 +6154,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
5727
6154
  };
5728
6155
  }
5729
6156
  function checkRollupSourceMaps(workspaceRoot) {
5730
- const configs = (0, import_node_fs13.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6157
+ const configs = (0, import_node_fs14.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5731
6158
  cwd: workspaceRoot
5732
6159
  }).map((config) => toPosix2(config));
5733
6160
  return configs.flatMap((relativePath) => {
5734
- const configPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
6161
+ const configPath = (0, import_node_path21.join)(workspaceRoot, relativePath);
5735
6162
  let config;
5736
6163
  try {
5737
- config = (0, import_node_fs13.readFileSync)(configPath, "utf8");
6164
+ config = (0, import_node_fs14.readFileSync)(configPath, "utf8");
5738
6165
  } catch {
5739
6166
  return [];
5740
6167
  }
@@ -5749,11 +6176,11 @@ function checkRollupSourceMaps(workspaceRoot) {
5749
6176
  });
5750
6177
  }
5751
6178
  function checkDeclarationSpecifiers(workspaceRoot) {
5752
- const configs = (0, import_node_fs13.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
6179
+ const configs = (0, import_node_fs14.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5753
6180
  cwd: workspaceRoot
5754
6181
  }).map((config) => toPosix2(config));
5755
6182
  return configs.flatMap((relativePath) => {
5756
- const configPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
6183
+ const configPath = (0, import_node_path21.join)(workspaceRoot, relativePath);
5757
6184
  if (!fileExists(configPath)) {
5758
6185
  return [];
5759
6186
  }
@@ -5787,7 +6214,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
5787
6214
  });
5788
6215
  }
5789
6216
  function collectFindings(workspaceRoot) {
5790
- const nxJsonPath = (0, import_node_path20.join)(workspaceRoot, "nx.json");
6217
+ const nxJsonPath = (0, import_node_path21.join)(workspaceRoot, "nx.json");
5791
6218
  if (!fileExists(nxJsonPath)) {
5792
6219
  throw new Error(
5793
6220
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -5807,7 +6234,8 @@ function collectFindings(workspaceRoot) {
5807
6234
  ...checkDeclarationSpecifiers(workspaceRoot),
5808
6235
  ...checkVersionActions(workspaceRoot),
5809
6236
  ...checkTargetFilesExist(workspaceRoot),
5810
- checkSync(workspaceRoot)
6237
+ checkSync(workspaceRoot),
6238
+ ...checkNativeApps(workspaceRoot)
5811
6239
  ].filter((finding) => finding !== void 0);
5812
6240
  }
5813
6241
  function runDoctor(workspaceRoot) {
@@ -5832,8 +6260,8 @@ function runDoctor(workspaceRoot) {
5832
6260
  }
5833
6261
 
5834
6262
  // src/workspace-creation/adopt-directory.use-case.ts
5835
- var import_node_fs14 = require("fs");
5836
- var import_node_path21 = require("path");
6263
+ var import_node_fs15 = require("fs");
6264
+ var import_node_path22 = require("path");
5837
6265
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
5838
6266
  var AGENT_AND_CI_ENTRIES = [
5839
6267
  "AGENTS.md",
@@ -5864,13 +6292,13 @@ var PREFLIGHT_BLOCKERS = [
5864
6292
  "packages"
5865
6293
  ];
5866
6294
  function assertAdoptableDirectory(target) {
5867
- if (!(0, import_node_fs14.existsSync)(target)) {
6295
+ if (!(0, import_node_fs15.existsSync)(target)) {
5868
6296
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
5869
6297
  }
5870
- if (!(0, import_node_fs14.statSync)(target).isDirectory()) {
6298
+ if (!(0, import_node_fs15.statSync)(target).isDirectory()) {
5871
6299
  throw new Error(`--into '${target}' is not a directory.`);
5872
6300
  }
5873
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs14.existsSync)((0, import_node_path21.join)(target, entry)));
6301
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs15.existsSync)((0, import_node_path22.join)(target, entry)));
5874
6302
  if (blockers.length > 0) {
5875
6303
  throw new Error(
5876
6304
  `--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.`
@@ -5878,15 +6306,15 @@ function assertAdoptableDirectory(target) {
5878
6306
  }
5879
6307
  }
5880
6308
  function mergeGitignore(generatedFile, targetFile) {
5881
- const existing = (0, import_node_fs14.readFileSync)(targetFile, "utf8");
6309
+ const existing = (0, import_node_fs15.readFileSync)(targetFile, "utf8");
5882
6310
  const present = new Set(existing.split("\n").map((line) => line.trim()));
5883
- const additions = (0, import_node_fs14.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
6311
+ const additions = (0, import_node_fs15.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
5884
6312
  const trimmed = line.trim();
5885
6313
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
5886
6314
  });
5887
6315
  if (additions.length === 0) return false;
5888
6316
  const separator = existing.endsWith("\n") ? "" : "\n";
5889
- (0, import_node_fs14.writeFileSync)(
6317
+ (0, import_node_fs15.writeFileSync)(
5890
6318
  targetFile,
5891
6319
  `${existing}${separator}
5892
6320
  # Added by mnci (Nx workspace)
@@ -5896,9 +6324,9 @@ ${additions.join("\n")}
5896
6324
  return true;
5897
6325
  }
5898
6326
  function adoptGeneratedWorkspace(generatedRoot, target) {
5899
- const entries = (0, import_node_fs14.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
6327
+ const entries = (0, import_node_fs15.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
5900
6328
  const collisions = entries.filter(
5901
- (entry) => (0, import_node_fs14.existsSync)((0, import_node_path21.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
6329
+ (entry) => (0, import_node_fs15.existsSync)((0, import_node_path22.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
5902
6330
  );
5903
6331
  if (collisions.length > 0) {
5904
6332
  throw new Error(
@@ -5907,28 +6335,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
5907
6335
  }
5908
6336
  const result = { copied: [], kept: [], mergedGitignore: false };
5909
6337
  for (const entry of entries) {
5910
- const from = (0, import_node_path21.join)(generatedRoot, entry);
5911
- const to = (0, import_node_path21.join)(target, entry);
5912
- if (entry === ".gitignore" && (0, import_node_fs14.existsSync)(to)) {
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)) {
5913
6341
  result.mergedGitignore = mergeGitignore(from, to);
5914
6342
  result.kept.push(entry);
5915
6343
  continue;
5916
6344
  }
5917
- if ((0, import_node_fs14.existsSync)(to)) {
6345
+ if ((0, import_node_fs15.existsSync)(to)) {
5918
6346
  result.kept.push(entry);
5919
6347
  continue;
5920
6348
  }
5921
- (0, import_node_fs14.cpSync)(from, to, { recursive: true });
6349
+ (0, import_node_fs15.cpSync)(from, to, { recursive: true });
5922
6350
  result.copied.push(entry);
5923
6351
  }
5924
- (0, import_node_fs14.rmSync)(generatedRoot, { recursive: true, force: true });
6352
+ (0, import_node_fs15.rmSync)(generatedRoot, { recursive: true, force: true });
5925
6353
  return result;
5926
6354
  }
5927
6355
 
5928
6356
  // src/workspace-creation/create-workspace.use-case.ts
5929
- var import_node_fs15 = require("fs");
6357
+ var import_node_fs16 = require("fs");
5930
6358
  var import_node_os = require("os");
5931
- var import_node_path22 = require("path");
6359
+ var import_node_path23 = require("path");
5932
6360
  function nxCloudProviderValue(ci) {
5933
6361
  return ci === "azure" ? "azure" : "github";
5934
6362
  }
@@ -5964,9 +6392,9 @@ async function resolveRegistry(options) {
5964
6392
  return await promptRegistry();
5965
6393
  }
5966
6394
  async function runNew(name, options) {
5967
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path22.resolve)(process.cwd(), options.into);
6395
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path23.resolve)(process.cwd(), options.into);
5968
6396
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
5969
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path22.basename)(adoptTarget));
6397
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path23.basename)(adoptTarget));
5970
6398
  assertValidProjectName(workspaceName, "Workspace name");
5971
6399
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
5972
6400
  const registry = await resolveRegistry(options);
@@ -5979,8 +6407,8 @@ async function runNew(name, options) {
5979
6407
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
5980
6408
  const stack = await resolveStack(options);
5981
6409
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
5982
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs15.mkdtempSync)((0, import_node_path22.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
5983
- let workspaceRoot = (0, import_node_path22.join)(stagingParent, workspaceName);
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);
5984
6412
  try {
5985
6413
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
5986
6414
  runNpx(
@@ -6003,7 +6431,7 @@ async function runNew(name, options) {
6003
6431
  workspaceRoot = adoptTarget;
6004
6432
  }
6005
6433
  } finally {
6006
- if (adoptTarget !== void 0) (0, import_node_fs15.rmSync)(stagingParent, { recursive: true, force: true });
6434
+ if (adoptTarget !== void 0) (0, import_node_fs16.rmSync)(stagingParent, { recursive: true, force: true });
6007
6435
  }
6008
6436
  logger.step(
6009
6437
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -6013,8 +6441,8 @@ async function runNew(name, options) {
6013
6441
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
6014
6442
  logger.detail
6015
6443
  );
6016
- (0, import_node_fs15.rmSync)((0, import_node_path22.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
6017
- (0, import_node_fs15.rmSync)((0, import_node_path22.join)(workspaceRoot, "package-lock.json"), { force: true });
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 });
6018
6446
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
6019
6447
  const installStatus = runShell(
6020
6448
  "npm",
@@ -6045,12 +6473,12 @@ async function runNew(name, options) {
6045
6473
  }
6046
6474
 
6047
6475
  // src/workspace-creation/interactive-wizard.use-case.ts
6048
- var import_node_path24 = require("path");
6476
+ var import_node_path25 = require("path");
6049
6477
  var import_prompts4 = require("@inquirer/prompts");
6050
6478
 
6051
6479
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
6052
- var import_node_fs16 = require("fs");
6053
- var import_node_path23 = require("path");
6480
+ var import_node_fs17 = require("fs");
6481
+ var import_node_path24 = require("path");
6054
6482
  function resolveRegistry2(options, persisted) {
6055
6483
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
6056
6484
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -6079,7 +6507,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6079
6507
  return persisted.workspaceName;
6080
6508
  }
6081
6509
  try {
6082
- const existing = (0, import_node_fs16.readdirSync)(workspaceRoot).find(
6510
+ const existing = (0, import_node_fs17.readdirSync)(workspaceRoot).find(
6083
6511
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
6084
6512
  );
6085
6513
  if (existing) {
@@ -6087,11 +6515,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
6087
6515
  }
6088
6516
  } catch {
6089
6517
  }
6090
- return (0, import_node_path23.basename)(workspaceRoot);
6518
+ return (0, import_node_path24.basename)(workspaceRoot);
6091
6519
  }
6092
6520
  function detectNpmAuth(workspaceRoot) {
6093
6521
  try {
6094
- return (0, import_node_fs16.readFileSync)((0, import_node_path23.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6522
+ return (0, import_node_fs17.readFileSync)((0, import_node_path24.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6095
6523
  } catch {
6096
6524
  return void 0;
6097
6525
  }
@@ -6138,7 +6566,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
6138
6566
  };
6139
6567
  }
6140
6568
  function runUpgrade(workspaceRoot, options) {
6141
- if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
6569
+ if (!fileExists((0, import_node_path24.join)(workspaceRoot, "nx.json"))) {
6142
6570
  throw new Error(
6143
6571
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
6144
6572
  );
@@ -6179,6 +6607,10 @@ function runUpgrade(workspaceRoot, options) {
6179
6607
  logger.step("Updating the VS Code extension packaging script");
6180
6608
  logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
6181
6609
  }
6610
+ if (refreshGoReleaseScript(workspaceRoot)) {
6611
+ logger.step("Updating the releasable Go app script");
6612
+ logger.detail(`updated ${GO_RELEASE_SCRIPT_PATH}`);
6613
+ }
6182
6614
  const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
6183
6615
  if (upgradedDtsPlugins.length > 0) {
6184
6616
  logger.step("Upgrading declaration specifiers to resolve under nodenext");
@@ -6195,7 +6627,7 @@ function runUpgrade(workspaceRoot, options) {
6195
6627
 
6196
6628
  // src/workspace-creation/interactive-wizard.use-case.ts
6197
6629
  async function runInteractive() {
6198
- const inWorkspace = fileExists((0, import_node_path24.join)(process.cwd(), "nx.json"));
6630
+ const inWorkspace = fileExists((0, import_node_path25.join)(process.cwd(), "nx.json"));
6199
6631
  const choiceNew = { name: "Create a new monorepo", value: "new" };
6200
6632
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
6201
6633
  const choiceUpgrade = {
@@ -6216,8 +6648,8 @@ async function runInteractive() {
6216
6648
  }
6217
6649
 
6218
6650
  // src/cli-version/check-for-update.use-case.ts
6219
- var import_node_fs17 = require("fs");
6220
- var import_node_path25 = require("path");
6651
+ var import_node_fs18 = require("fs");
6652
+ var import_node_path26 = require("path");
6221
6653
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
6222
6654
  var PACKAGE_NAME = "@mnci/cli";
6223
6655
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -6273,8 +6705,8 @@ function releaseTriple(version) {
6273
6705
  }
6274
6706
  function readCliVersion(packageDirectory) {
6275
6707
  try {
6276
- const manifestPath = (0, import_node_path25.join)(packageDirectory, "..", "package.json");
6277
- const manifest = JSON.parse((0, import_node_fs17.readFileSync)(manifestPath, "utf8"));
6708
+ const manifestPath = (0, import_node_path26.join)(packageDirectory, "..", "package.json");
6709
+ const manifest = JSON.parse((0, import_node_fs18.readFileSync)(manifestPath, "utf8"));
6278
6710
  return manifest.version ?? "0.0.0";
6279
6711
  } catch {
6280
6712
  return "0.0.0";
@@ -6335,6 +6767,12 @@ function buildProgram(cliVersion) {
6335
6767
  ).option(
6336
6768
  "--sidecar <go-app>",
6337
6769
  "vscode-extension only: a go-app whose six-platform build ships in the extension, one .vsix per platform"
6770
+ ).option(
6771
+ "--release",
6772
+ "go-app only: release the app. Versioned from its git tag, its six-platform zips attached to its GitHub Release"
6773
+ ).option(
6774
+ "--cgo",
6775
+ "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"
6338
6776
  ).action(
6339
6777
  async (kind, name, options) => {
6340
6778
  await runAdd(kind, name, options);