@mnci/cli 4.11.0 → 4.12.1

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_path18 = require("path");
41
+ var import_node_path19 = require("path");
42
42
  var import_prompts3 = require("@inquirer/prompts");
43
43
 
44
44
  // src/nx-workspace/nx.client.ts
@@ -433,11 +433,12 @@ ${feedShortKey}:_password=\${PAT}
433
433
  ${feedShortKey}:email=npm-requires-this-and-never-uses-it
434
434
  `;
435
435
  }
436
+ var VSCODE_EXTENSION_TAG = "type:vscode-extension";
436
437
  function releaseConfig(ci) {
437
438
  const githubReleases = ci === "github";
438
439
  return {
439
440
  projectsRelationship: "independent",
440
- projects: ["packages/*", "python-packages/*", "!tag:type:go-lib"],
441
+ projects: ["packages/*", "python-packages/*", `tag:${VSCODE_EXTENSION_TAG}`, "!tag:type:go-lib"],
441
442
  releaseTag: { pattern: "{projectName}@{version}" },
442
443
  git: { commit: false, tag: true, push: githubReleases },
443
444
  version: {
@@ -449,7 +450,7 @@ function releaseConfig(ci) {
449
450
  // Set here at `new` time it wins: the generator only fills this in when
450
451
  // absent (it spreads the existing release.version over its default). Both
451
452
  // globs are listed; `nx run-many` no-ops cleanly when one matches nothing.
452
- preVersionCommand: "npx nx run-many -t build --projects=packages/*,python-packages/*",
453
+ preVersionCommand: `npx nx run-many -t build --projects=packages/*,python-packages/*,tag:${VSCODE_EXTENSION_TAG}`,
453
454
  // The lock file resync is OFF, and the reason is that it cannot succeed
454
455
  // on the one release where it would matter.
455
456
  //
@@ -476,7 +477,12 @@ function releaseConfig(ci) {
476
477
  },
477
478
  changelog: githubReleases ? {
478
479
  workspaceChangelog: false,
479
- projectChangelogs: { createRelease: "github", file: false }
480
+ projectChangelogs: { createRelease: "github", file: false },
481
+ // A GitHub Release needs a changelog, and a changelog needs a ref to start
482
+ // from. On the first release of a repository there is no tag to start from,
483
+ // and nx release dies after versioning (#243, measured). With this set it
484
+ // starts from the first commit; once a tag exists it is never consulted.
485
+ automaticFromRef: true
480
486
  } : { workspaceChangelog: false }
481
487
  };
482
488
  }
@@ -1039,7 +1045,7 @@ function pypiReleasePreflight(registryKind) {
1039
1045
  }
1040
1046
  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)}"`;
1041
1047
  function releaseGuard(pythonPublishEnv, nugetPublishEnv) {
1042
- 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 hasNpm=npmCount>0;const hasPython=pythonCount>0;const hasCsharp=csharpCount>0;const hasDart=dartCount>0;if(!hasNpm&&!hasPython&&!hasCsharp&&!hasDart){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;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)"`;
1048
+ 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)"`;
1043
1049
  }
1044
1050
  var PYPI_TOKEN_VARIABLE = "PYPI_TOKEN";
1045
1051
  var AZURE_PAT_VARIABLE = "PAT";
@@ -1370,11 +1376,14 @@ ${npmAuthPreflight(registryKind) ? `
1370
1376
  # the run rather than under-bumping silently: clear the variable back to
1371
1377
  # '' once the override is no longer needed.
1372
1378
  - script: ${releaseGuard(pythonPublishEnvFragment(pythonPublishUrl2, registryKind), nugetPublishEnvFragment(nugetFeedUrl2))}
1373
- displayName: Release \u2014 version, tag and publish (npm + Python + C#)
1379
+ displayName: Release \u2014 version, tag and publish (npm + Python + C# + VS Code)
1374
1380
  condition: ${onMain}
1375
1381
  env:
1376
1382
  ${npmAuthName}: ${npmAuthValue}${pypiTokenEnvLine(registryKind, (name) => `$(${name})`, " ".repeat(6))}
1377
1383
  RELEASE_SPECIFIER: $(RELEASE_SPECIFIER)
1384
+ # A VS Code extension publishes with it; tools/vscode-extension.cjs skips the
1385
+ # Marketplace when it is unset, including when Azure leaves it as '$(VSCE_PAT)'.
1386
+ VSCE_PAT: $(VSCE_PAT)
1378
1387
 
1379
1388
  # nx release's own git push (release.git.push) is deliberately left off: it
1380
1389
  # only runs when a remote GitHub/GitLab Release is configured, which this
@@ -1626,11 +1635,14 @@ ${npmAuthPreflight(registryKind) ? `
1626
1635
  # releaseConfig's remarks for why that is safe on this Nx version and
1627
1636
  # why every other provider combination keeps the explicit push step below.` : ""}
1628
1637
  - run: ${releaseGuard(pythonPublishEnvFragment(pythonPublishUrl2, registryKind), nugetPublishEnvFragment(nugetFeedUrl2))}
1629
- name: Release \u2014 version, tag${githubReleases ? ", publish and GitHub Release" : " and publish"} (npm + Python + C#)
1638
+ name: Release \u2014 version, tag${githubReleases ? ", publish and GitHub Release" : " and publish"} (npm + Python + C# + VS Code)
1630
1639
  if: \${{ ${onMain} }}
1631
1640
  env:
1632
1641
  ${npmAuthName}: ${npmAuthValue}${pypiTokenEnvLine(registryKind, (name) => `\${{ secrets.${name} }}`, " ".repeat(10))}
1633
- RELEASE_SPECIFIER: \${{ vars.RELEASE_SPECIFIER }}${githubReleases ? `
1642
+ RELEASE_SPECIFIER: \${{ vars.RELEASE_SPECIFIER }}
1643
+ # A VS Code extension publishes with it; tools/vscode-extension.cjs
1644
+ # skips the Marketplace when it is unset.
1645
+ VSCE_PAT: \${{ secrets.VSCE_PAT }}${githubReleases ? `
1634
1646
  GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}` : ""}
1635
1647
  ${githubReleases ? "" : `
1636
1648
  # nx release's own git push (release.git.push) is deliberately left off: it
@@ -3789,12 +3801,392 @@ function addReactInternalLib(workspaceRoot, name, stack) {
3789
3801
  );
3790
3802
  }
3791
3803
 
3804
+ // src/project-scaffolding/vscode-extension.use-case.ts
3805
+ var import_node_fs11 = require("fs");
3806
+ var import_node_path15 = require("path");
3807
+ var VSCODE_EXTENSION_SCRIPT_PATH = "tools/vscode-extension.cjs";
3808
+ var VSCODE_SIDECAR_TARGETS = {
3809
+ "win32-x64": "windows-amd64",
3810
+ "win32-arm64": "windows-arm64",
3811
+ "linux-x64": "linux-amd64",
3812
+ "linux-arm64": "linux-arm64",
3813
+ "alpine-x64": "linux-amd64",
3814
+ "alpine-arm64": "linux-arm64",
3815
+ "darwin-x64": "darwin-amd64",
3816
+ "darwin-arm64": "darwin-arm64"
3817
+ };
3818
+ var VSCODE_EXTENSION_SCRIPT = String.raw`#!/usr/bin/env node
3819
+ // Written by mnci: 'mnci add vscode-extension' creates it and 'mnci upgrade'
3820
+ // rewrites it, so local edits do not survive an upgrade.
3821
+ //
3822
+ // Packages and publishes a VS Code extension project. Its Nx targets call it:
3823
+ // node tools/vscode-extension.cjs package apps/<name> [--sidecar <go-app>]
3824
+ // node tools/vscode-extension.cjs publish apps/<name> [--sidecar <go-app>]
3825
+ // Without --sidecar: one universal dist/drop/<project>.vsix.
3826
+ // With --sidecar: one dist/drop/<project>-<target>.vsix per Marketplace target, each
3827
+ // carrying that platform's binary from the Go app's build-all in bin/.
3828
+ 'use strict'
3829
+ const { spawnSync } = require('node:child_process')
3830
+ const { cpSync, existsSync, mkdirSync, readFileSync, rmSync } = require('node:fs')
3831
+ const { basename, dirname, join, resolve } = require('node:path')
3832
+
3833
+ const TARGETS = ${JSON.stringify(VSCODE_SIDECAR_TARGETS)}
3834
+ const DROP = resolve('dist/drop')
3835
+ const VSCE_FLAGS = ['--no-dependencies', '--skip-license', '--allow-missing-repository']
3836
+
3837
+ function fail (message) {
3838
+ console.error(message)
3839
+ process.exit(1)
3840
+ }
3841
+
3842
+ function bin (packageName, command) {
3843
+ const manifestPath = require.resolve(packageName + '/package.json', { paths: [process.cwd()] })
3844
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
3845
+ const entry = typeof manifest.bin === 'string' ? manifest.bin : manifest.bin[command]
3846
+
3847
+ return join(dirname(manifestPath), entry)
3848
+ }
3849
+
3850
+ function run (packageName, command, args, options) {
3851
+ const result = spawnSync(process.execPath, [bin(packageName, command), ...args], { stdio: 'inherit', ...options })
3852
+ if (result.status !== 0) process.exit(result.status ?? 1)
3853
+ }
3854
+
3855
+ function vsixFiles (name, sidecar) {
3856
+ return sidecar
3857
+ ? Object.keys(TARGETS).map(target => join(DROP, name + '-' + target + '.vsix'))
3858
+ : [join(DROP, name + '.vsix')]
3859
+ }
3860
+
3861
+ function packageExtension (projectRoot, manifest, sidecar) {
3862
+ mkdirSync(DROP, { recursive: true })
3863
+ if (!sidecar) {
3864
+ run('@vscode/vsce', 'vsce', ['package', ...VSCE_FLAGS, '--out', vsixFiles(project)[0]], { cwd: projectRoot })
3865
+
3866
+ return
3867
+ }
3868
+ run('nx', 'nx', ['run', sidecar + ':build-all'], { env: { ...process.env, VERSION: manifest.version } })
3869
+ const staging = join(projectRoot, 'bin')
3870
+ try {
3871
+ for (const [target, platform] of Object.entries(TARGETS)) {
3872
+ const source = join('dist/platforms', sidecar, platform)
3873
+ if (!existsSync(source)) fail('No ' + platform + ' build of ' + sidecar + ' at ' + source + ' - its build-all target did not write one.')
3874
+ rmSync(staging, { recursive: true, force: true })
3875
+ cpSync(source, staging, { recursive: true })
3876
+ run('@vscode/vsce', 'vsce', ['package', '--target', target, ...VSCE_FLAGS, '--out', join(DROP, project + '-' + target + '.vsix')], { cwd: projectRoot })
3877
+ }
3878
+ } finally {
3879
+ rmSync(staging, { recursive: true, force: true })
3880
+ }
3881
+ }
3882
+
3883
+ function publishExtension (manifest, sidecar, dryRun) {
3884
+ if (dryRun) {
3885
+ console.log('Dry run - would publish ' + vsixFiles(project, sidecar).join(', ') + ' to the Marketplace.')
3886
+
3887
+ return
3888
+ }
3889
+ const token = process.env.VSCE_PAT ?? ''
3890
+ if (token === '' || /^\$\(.*\)$/.test(token)) {
3891
+ console.log('VSCE_PAT is not set - skipping the Marketplace publish of ' + manifest.name + '. Add it as a CI secret to publish.')
3892
+
3893
+ return
3894
+ }
3895
+ const files = vsixFiles(project, sidecar)
3896
+ const missing = files.filter(file => !existsSync(file))
3897
+ if (missing.length > 0) fail('Nothing to publish: ' + missing.join(', ') + ' not found - run the package target first.')
3898
+ run('@vscode/vsce', 'vsce', ['publish', '--packagePath', ...files, '--skip-duplicate'])
3899
+ }
3900
+
3901
+ const [command, projectRoot, ...rest] = process.argv.slice(2)
3902
+ const sidecarIndex = rest.indexOf('--sidecar')
3903
+ const sidecar = sidecarIndex === -1 ? undefined : rest[sidecarIndex + 1]
3904
+ if (!projectRoot || !existsSync(join(projectRoot, 'package.json'))) fail('Usage: node tools/vscode-extension.cjs package|publish <project root> [--sidecar <go-app>]')
3905
+ const manifest = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8'))
3906
+ // Packages are named after the project folder, never the manifest name, which is
3907
+ // free to change (the Marketplace id need not match the folder).
3908
+ const project = basename(resolve(projectRoot))
3909
+ // nx release --dry-run hands the publish target --dryRun=true and sets NX_DRY_RUN
3910
+ // (measured on Nx 23), so a dry run never reaches the Marketplace, token or not.
3911
+ const dryRun = rest.some(argument => /^--dry-?run(=true)?$/i.test(argument)) || process.env.NX_DRY_RUN === 'true'
3912
+ if (command === 'package') packageExtension(projectRoot, manifest, sidecar)
3913
+ else if (command === 'publish') publishExtension(manifest, sidecar, dryRun)
3914
+ else fail('Unknown command ' + command + ' - expected package or publish.')
3915
+ `;
3916
+ var VSCODE_IGNORE = `src/**
3917
+ test/**
3918
+ out-tsc/**
3919
+ test-output/**
3920
+ **/*.map
3921
+ **/*.d.ts
3922
+ **/*.spec.*
3923
+ tsconfig*.json
3924
+ jest.config.*
3925
+ vitest.config.*
3926
+ .spec.swcrc
3927
+ node_modules/**
3928
+ `;
3929
+ function vscodeExtensionMain(name) {
3930
+ return `import * as vscode from 'vscode'
3931
+
3932
+ export function activate (context: vscode.ExtensionContext): void {
3933
+ context.subscriptions.push(
3934
+ vscode.commands.registerCommand('${name}.hello', () => {
3935
+ void vscode.window.showInformationMessage('Hello from ${name}')
3936
+ }),
3937
+ )
3938
+ }
3939
+
3940
+ export function deactivate (): void {}
3941
+ `;
3942
+ }
3943
+ function vscodeExtensionMainSpec(name) {
3944
+ return `import * as vscode from 'vscode'
3945
+ import { activate } from './main'
3946
+
3947
+ describe('activate', () => {
3948
+ it('registers the ${name}.hello command', async () => {
3949
+ const context = { subscriptions: [] } as unknown as vscode.ExtensionContext
3950
+
3951
+ activate(context)
3952
+
3953
+ expect(context.subscriptions).toHaveLength(1)
3954
+ expect(await vscode.commands.getCommands()).toContain('${name}.hello')
3955
+ })
3956
+ })
3957
+ `;
3958
+ }
3959
+ var VSCODE_STUB = `// Stands in for the 'vscode' module in unit tests: that module exists only
3960
+ // inside the extension host. Extend it as the extension reaches for more API.
3961
+ const registered = new Map<string, (...arguments_: unknown[]) => unknown>()
3962
+
3963
+ export const commands = {
3964
+ registerCommand (id: string, handler: (...arguments_: unknown[]) => unknown): { dispose: () => void } {
3965
+ registered.set(id, handler)
3966
+
3967
+ return { dispose: () => { registered.delete(id) } }
3968
+ },
3969
+ getCommands (): Promise<string[]> {
3970
+ return Promise.resolve(registered.keys().toArray())
3971
+ },
3972
+ executeCommand (id: string, ...arguments_: unknown[]): Promise<unknown> {
3973
+ return Promise.resolve(registered.get(id)?.(...arguments_))
3974
+ },
3975
+ }
3976
+
3977
+ export const window = {
3978
+ showInformationMessage (_message: string): Promise<undefined> {
3979
+ return Promise.resolve(undefined)
3980
+ },
3981
+ }
3982
+ `;
3983
+ var VSCODE_STUB_PATH = "test/vscode.stub.ts";
3984
+ function mapVscodeToStub(projectRoot, testRunner) {
3985
+ 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}\` },`];
3986
+ const path = (0, import_node_path15.join)(projectRoot, file);
3987
+ const content = fileExists(path) ? (0, import_node_fs11.readFileSync)(path, "utf8") : "";
3988
+ const line = content.split("\n").find((candidate) => candidate.trim() === anchor);
3989
+ if (line === void 0) {
3990
+ throw new Error(`${file} has no "${anchor}" line to map the vscode module after; map 'vscode' to ${VSCODE_STUB_PATH} by hand.`);
3991
+ }
3992
+ const indent = line.slice(0, line.indexOf(anchor));
3993
+ writeFileEnsured(path, content.replace(line, () => `${line}
3994
+ ${indent}${mapping}`));
3995
+ }
3996
+ function ensureVscodeToolchain(workspaceRoot) {
3997
+ const missing = ["@types/vscode", "@vscode/vsce"].filter((name) => !hasPlugin(workspaceRoot, name));
3998
+ if (missing.length === 0) {
3999
+ return;
4000
+ }
4001
+ logger.step(`Installing the VS Code extension toolchain (${missing.join(", ")})`);
4002
+ if (runShell("npm", ["install", "--save-dev", ...missing, "--no-audit", "--no-fund"], workspaceRoot) !== 0) {
4003
+ throw new Error(`npm install of ${missing.join(", ")} failed`);
4004
+ }
4005
+ }
4006
+ function defaultPublisher(workspaceRoot) {
4007
+ const { name } = readJson((0, import_node_path15.join)(workspaceRoot, "package.json"));
4008
+ return (name ?? "publisher").replace(/^@/, "").split("/", 1)[0];
4009
+ }
4010
+ function reshapeManifest(projectRoot, name, publisher, typesVersion) {
4011
+ const manifestPath = (0, import_node_path15.join)(projectRoot, "package.json");
4012
+ const manifest = readJson(manifestPath);
4013
+ const { nx = {}, ...rest } = manifest;
4014
+ const targets = { ...nx.targets };
4015
+ for (const target of ["serve", "prune", "prune-lockfile", "copy-workspace-modules"]) {
4016
+ delete targets[target];
4017
+ }
4018
+ const build = targets.build ?? {};
4019
+ targets.build = {
4020
+ ...build,
4021
+ options: {
4022
+ ...build.options,
4023
+ bundle: true,
4024
+ thirdParty: true,
4025
+ external: ["vscode"],
4026
+ generatePackageJson: false
4027
+ }
4028
+ };
4029
+ writeFileEnsured(
4030
+ manifestPath,
4031
+ toJson({
4032
+ ...rest,
4033
+ name,
4034
+ displayName: name,
4035
+ version: rest.version ?? "0.0.1",
4036
+ publisher,
4037
+ engines: { vscode: `^${typesVersion}` },
4038
+ categories: ["Other"],
4039
+ main: "./dist/main.js",
4040
+ activationEvents: [],
4041
+ contributes: { commands: [{ command: `${name}.hello`, title: `${name}: Hello` }] },
4042
+ nx: { ...nx, name, tags: [.../* @__PURE__ */ new Set([...nx.tags ?? [], VSCODE_EXTENSION_TAG])], targets }
4043
+ })
4044
+ );
4045
+ }
4046
+ function addVscodeTypes(tsconfigPath) {
4047
+ if (!fileExists(tsconfigPath)) {
4048
+ return;
4049
+ }
4050
+ const tsconfig = readJson(tsconfigPath);
4051
+ const compilerOptions = tsconfig.compilerOptions ?? {};
4052
+ const types = compilerOptions.types ?? [];
4053
+ if (types.includes("vscode")) {
4054
+ return;
4055
+ }
4056
+ writeFileEnsured(tsconfigPath, toJson({ ...tsconfig, compilerOptions: { ...compilerOptions, types: [...types, "vscode"] } }));
4057
+ }
4058
+ function vscodeExtensionPackageTarget(name, sidecar) {
4059
+ const outputs = sidecar ? Object.keys(VSCODE_SIDECAR_TARGETS).map((target) => `{workspaceRoot}/dist/drop/${name}-${target}.vsix`) : [`{workspaceRoot}/dist/drop/${name}.vsix`];
4060
+ return {
4061
+ executor: "nx:run-commands",
4062
+ dependsOn: ["build"],
4063
+ outputs,
4064
+ options: { command: `node ${VSCODE_EXTENSION_SCRIPT_PATH} package apps/${name}${sidecar ? ` --sidecar ${sidecar}` : ""}` }
4065
+ };
4066
+ }
4067
+ function vscodeExtensionPublishTarget(name, sidecar) {
4068
+ return {
4069
+ executor: "nx:run-commands",
4070
+ dependsOn: ["package"],
4071
+ options: { command: `node ${VSCODE_EXTENSION_SCRIPT_PATH} publish apps/${name}${sidecar ? ` --sidecar ${sidecar}` : ""}` }
4072
+ };
4073
+ }
4074
+ function addDebugLaunch(workspaceRoot, name) {
4075
+ const file = (0, import_node_fs11.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
4076
+ if (file === void 0) {
4077
+ return;
4078
+ }
4079
+ const path = (0, import_node_path15.join)(workspaceRoot, file);
4080
+ const workspace = readCodeWorkspace(path) ?? {};
4081
+ const folder = `\${workspaceFolder:${workspace.folders?.[0]?.name ?? file.replace(/\.code-workspace$/, "")}}`;
4082
+ const taskLabel = `${name}: build (development)`;
4083
+ const launchName = `${name}: debug`;
4084
+ const tasks = (workspace.tasks?.tasks ?? []).filter((task) => task.label !== taskLabel);
4085
+ const configurations = (workspace.launch?.configurations ?? []).filter((configuration) => configuration.name !== launchName);
4086
+ writeFileEnsured(
4087
+ path,
4088
+ toJson({
4089
+ ...workspace,
4090
+ tasks: {
4091
+ version: workspace.tasks?.version ?? "2.0.0",
4092
+ tasks: [...tasks, { label: taskLabel, type: "shell", command: `npx nx run ${name}:build:development`, problemMatcher: [] }]
4093
+ },
4094
+ launch: {
4095
+ version: workspace.launch?.version ?? "0.2.0",
4096
+ configurations: [
4097
+ ...configurations,
4098
+ {
4099
+ name: launchName,
4100
+ type: "extensionHost",
4101
+ request: "launch",
4102
+ args: [`--extensionDevelopmentPath=${folder}/apps/${name}`],
4103
+ outFiles: [`${folder}/apps/${name}/dist/**/*.js`],
4104
+ preLaunchTask: taskLabel
4105
+ }
4106
+ ]
4107
+ }
4108
+ })
4109
+ );
4110
+ }
4111
+ function refreshVscodeExtensionScript(workspaceRoot) {
4112
+ const apps = (0, import_node_path15.join)(workspaceRoot, "apps");
4113
+ let entries;
4114
+ try {
4115
+ entries = (0, import_node_fs11.readdirSync)(apps);
4116
+ } catch {
4117
+ return false;
4118
+ }
4119
+ const hasExtension = entries.some((entry) => {
4120
+ const manifestPath = (0, import_node_path15.join)(apps, entry, "package.json");
4121
+ if (!fileExists(manifestPath)) {
4122
+ return false;
4123
+ }
4124
+ const tags = readJson(manifestPath).nx?.tags ?? [];
4125
+ return tags.includes(VSCODE_EXTENSION_TAG);
4126
+ });
4127
+ const path = (0, import_node_path15.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
4128
+ if (!hasExtension || fileExists(path) && (0, import_node_fs11.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
4129
+ return false;
4130
+ }
4131
+ writeFileEnsured(path, VSCODE_EXTENSION_SCRIPT);
4132
+ return true;
4133
+ }
4134
+ function pinVscodeExtensionProjectNames(workspaceRoot) {
4135
+ const apps = (0, import_node_path15.join)(workspaceRoot, "apps");
4136
+ let entries;
4137
+ try {
4138
+ entries = (0, import_node_fs11.readdirSync)(apps);
4139
+ } catch {
4140
+ return [];
4141
+ }
4142
+ const updated = [];
4143
+ for (const entry of entries) {
4144
+ const manifestPath = (0, import_node_path15.join)(apps, entry, "package.json");
4145
+ if (!fileExists(manifestPath)) {
4146
+ continue;
4147
+ }
4148
+ const manifest = readJson(manifestPath);
4149
+ if (!manifest.nx?.tags?.includes(VSCODE_EXTENSION_TAG) || manifest.nx.name !== void 0 || manifest.name === void 0) {
4150
+ continue;
4151
+ }
4152
+ writeFileEnsured(manifestPath, toJson({ ...manifest, nx: { ...manifest.nx, name: manifest.name } }));
4153
+ updated.push(`apps/${entry}/package.json`);
4154
+ }
4155
+ return updated;
4156
+ }
4157
+ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4158
+ const { sidecar } = options;
4159
+ if (sidecar !== void 0 && !fileExists((0, import_node_path15.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
4160
+ throw new Error(`--sidecar ${sidecar}: no Go app at apps/${sidecar}. Add it first with \`mnci add go-app ${sidecar}\`.`);
4161
+ }
4162
+ runNodeApp(workspaceRoot, name, stack, "none");
4163
+ ensureVscodeToolchain(workspaceRoot);
4164
+ const projectRoot = (0, import_node_path15.join)(workspaceRoot, "apps", name);
4165
+ const typesVersion = readJson((0, import_node_path15.join)(workspaceRoot, "node_modules/@types/vscode/package.json")).version;
4166
+ reshapeManifest(projectRoot, name, options.publisher ?? defaultPublisher(workspaceRoot), typesVersion);
4167
+ addVscodeTypes((0, import_node_path15.join)(projectRoot, "tsconfig.app.json"));
4168
+ addVscodeTypes((0, import_node_path15.join)(projectRoot, "tsconfig.spec.json"));
4169
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
4170
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
4171
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
4172
+ mapVscodeToStub(projectRoot, stack.testRunner);
4173
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
4174
+ writeFileEnsured((0, import_node_path15.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
4175
+ addNxTargets((0, import_node_path15.join)(projectRoot, "package.json"), {
4176
+ "package": vscodeExtensionPackageTarget(name, sidecar),
4177
+ "nx-release-publish": vscodeExtensionPublishTarget(name, sidecar)
4178
+ });
4179
+ removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
4180
+ registerProjectCommands(workspaceRoot, name, { build: true });
4181
+ addDebugLaunch(workspaceRoot, name);
4182
+ }
4183
+
3792
4184
  // src/dependency-management/sync-dependencies.use-case.ts
3793
- var import_node_path16 = require("path");
4185
+ var import_node_path17 = require("path");
3794
4186
 
3795
4187
  // src/dependency-management/manifest.repository.ts
3796
- var import_node_fs11 = require("fs");
3797
- var import_node_path15 = require("path");
4188
+ var import_node_fs12 = require("fs");
4189
+ var import_node_path16 = require("path");
3798
4190
  var ECOSYSTEMS = ["npm", "pip", "pub", "nuget", "go"];
3799
4191
  var ROOT_LABEL = "(root)";
3800
4192
  var MANIFEST_GLOBS = {
@@ -3827,23 +4219,23 @@ function projectOf(manifestRelativePath) {
3827
4219
  }
3828
4220
  function hasEcosystem(workspaceRoot, ecosystem) {
3829
4221
  if (ecosystem === "go") {
3830
- return fileExists((0, import_node_path15.join)(workspaceRoot, "go.mod"));
4222
+ return fileExists((0, import_node_path16.join)(workspaceRoot, "go.mod"));
3831
4223
  }
3832
4224
  if (ecosystem === "nuget") {
3833
- return (0, import_node_fs11.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
4225
+ return (0, import_node_fs12.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
3834
4226
  }
3835
4227
  const rootMarker = {
3836
4228
  npm: "package.json",
3837
4229
  pip: "requirements-dev.txt",
3838
4230
  pub: "pubspec.yaml"
3839
4231
  };
3840
- return fileExists((0, import_node_path15.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs11.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
4232
+ return fileExists((0, import_node_path16.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs12.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
3841
4233
  }
3842
4234
  function collectNpm(workspaceRoot) {
3843
4235
  const sites = [];
3844
- const relativePaths = ["package.json", ...(0, import_node_fs11.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
4236
+ const relativePaths = ["package.json", ...(0, import_node_fs12.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
3845
4237
  for (const relativePath of relativePaths) {
3846
- const manifestPath = (0, import_node_path15.join)(workspaceRoot, relativePath);
4238
+ const manifestPath = (0, import_node_path16.join)(workspaceRoot, relativePath);
3847
4239
  try {
3848
4240
  const manifest = readJson(manifestPath);
3849
4241
  sites.push(...npmManifestSites(manifest, relativePath, manifestPath));
@@ -3904,17 +4296,17 @@ function collectPip(workspaceRoot) {
3904
4296
  name: parsed.name,
3905
4297
  ecosystem: "pip",
3906
4298
  project: projectOf(relativePath),
3907
- manifestPath: (0, import_node_path15.join)(workspaceRoot, relativePath),
4299
+ manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
3908
4300
  section,
3909
4301
  spec: parsed.spec,
3910
4302
  rewritable: parsed.rewritable && parsed.spec !== ""
3911
4303
  });
3912
4304
  };
3913
- const pyprojectPaths = (0, import_node_fs11.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
4305
+ const pyprojectPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
3914
4306
  for (const relativePath of pyprojectPaths) {
3915
4307
  let content;
3916
4308
  try {
3917
- content = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8");
4309
+ content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
3918
4310
  } catch {
3919
4311
  continue;
3920
4312
  }
@@ -3925,14 +4317,14 @@ function collectPip(workspaceRoot) {
3925
4317
  }
3926
4318
  const requirementsPaths = [
3927
4319
  "requirements-dev.txt",
3928
- ...(0, import_node_fs11.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
4320
+ ...(0, import_node_fs12.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
3929
4321
  ];
3930
4322
  for (const relativePath of requirementsPaths) {
3931
- if (!fileExists((0, import_node_path15.join)(workspaceRoot, relativePath))) {
4323
+ if (!fileExists((0, import_node_path16.join)(workspaceRoot, relativePath))) {
3932
4324
  continue;
3933
4325
  }
3934
4326
  const section = relativePath === "requirements-dev.txt" ? "devDep" : "dep";
3935
- const lines = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
4327
+ const lines = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
3936
4328
  for (const line of lines) {
3937
4329
  push(relativePath, section, line);
3938
4330
  }
@@ -3970,11 +4362,11 @@ function pyprojectDependencies(content) {
3970
4362
  }
3971
4363
  function collectPub(workspaceRoot) {
3972
4364
  const sites = [];
3973
- const pubspecPaths = (0, import_node_fs11.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
4365
+ const pubspecPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
3974
4366
  for (const relativePath of pubspecPaths) {
3975
4367
  let content;
3976
4368
  try {
3977
- content = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8");
4369
+ content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
3978
4370
  } catch {
3979
4371
  continue;
3980
4372
  }
@@ -3984,7 +4376,7 @@ function collectPub(workspaceRoot) {
3984
4376
  name: entry.name,
3985
4377
  ecosystem: "pub",
3986
4378
  project: projectOf(relativePath),
3987
- manifestPath: (0, import_node_path15.join)(workspaceRoot, relativePath),
4379
+ manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
3988
4380
  section: block === "dependencies" ? "dep" : "devDep",
3989
4381
  spec: entry.spec,
3990
4382
  rewritable: entry.spec !== ""
@@ -4034,11 +4426,11 @@ function stripQuotes(value) {
4034
4426
  }
4035
4427
  function collectNuget(workspaceRoot) {
4036
4428
  const sites = [];
4037
- const csprojPaths = (0, import_node_fs11.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
4429
+ const csprojPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
4038
4430
  for (const relativePath of csprojPaths) {
4039
4431
  let content;
4040
4432
  try {
4041
- content = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8");
4433
+ content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
4042
4434
  } catch {
4043
4435
  continue;
4044
4436
  }
@@ -4047,7 +4439,7 @@ function collectNuget(workspaceRoot) {
4047
4439
  name: entry.name,
4048
4440
  ecosystem: "nuget",
4049
4441
  project: projectOf(relativePath),
4050
- manifestPath: (0, import_node_path15.join)(workspaceRoot, relativePath),
4442
+ manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
4051
4443
  section: "dep",
4052
4444
  spec: entry.spec,
4053
4445
  // A plain SemVer string is rewritable; an MSBuild property reference
@@ -4072,13 +4464,13 @@ function csprojPackageReferences(content) {
4072
4464
  return entries;
4073
4465
  }
4074
4466
  function collectGo(workspaceRoot) {
4075
- const manifestPath = (0, import_node_path15.join)(workspaceRoot, "go.mod");
4467
+ const manifestPath = (0, import_node_path16.join)(workspaceRoot, "go.mod");
4076
4468
  if (!fileExists(manifestPath)) {
4077
4469
  return [];
4078
4470
  }
4079
4471
  let content;
4080
4472
  try {
4081
- content = (0, import_node_fs11.readFileSync)(manifestPath, "utf8");
4473
+ content = (0, import_node_fs12.readFileSync)(manifestPath, "utf8");
4082
4474
  } catch {
4083
4475
  return [];
4084
4476
  }
@@ -4135,7 +4527,7 @@ function rewriteSpec(site, spec) {
4135
4527
  writeFileEnsured(site.manifestPath, toJson(manifest));
4136
4528
  return true;
4137
4529
  }
4138
- const before = (0, import_node_fs11.readFileSync)(site.manifestPath, "utf8");
4530
+ const before = (0, import_node_fs12.readFileSync)(site.manifestPath, "utf8");
4139
4531
  const after = (() => {
4140
4532
  switch (site.ecosystem) {
4141
4533
  case "pip": {
@@ -4191,13 +4583,13 @@ function escapeForRegex(value) {
4191
4583
  function isWorkspaceProject(workspaceRoot, name) {
4192
4584
  const short = name.includes("/") ? name.split("/").at(-1) : name;
4193
4585
  return ["apps", "libs", "packages"].some(
4194
- (directory) => fileExists((0, import_node_path15.join)(workspaceRoot, directory, short ?? name, "package.json"))
4586
+ (directory) => fileExists((0, import_node_path16.join)(workspaceRoot, directory, short ?? name, "package.json"))
4195
4587
  );
4196
4588
  }
4197
4589
  function isAliasedInstall(workspaceRoot, name) {
4198
4590
  try {
4199
4591
  const installed = readJson(
4200
- (0, import_node_path15.join)(workspaceRoot, "node_modules", name, "package.json")
4592
+ (0, import_node_path16.join)(workspaceRoot, "node_modules", name, "package.json")
4201
4593
  );
4202
4594
  return installed.name !== void 0 && installed.name !== name;
4203
4595
  } catch {
@@ -4208,14 +4600,14 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
4208
4600
  if (ecosystem === "npm") {
4209
4601
  try {
4210
4602
  return readJson(
4211
- (0, import_node_path15.join)(workspaceRoot, "node_modules", name, "package.json")
4603
+ (0, import_node_path16.join)(workspaceRoot, "node_modules", name, "package.json")
4212
4604
  ).version;
4213
4605
  } catch {
4214
4606
  return void 0;
4215
4607
  }
4216
4608
  }
4217
4609
  if (ecosystem === "pub") {
4218
- const lockPath = (0, import_node_path15.join)(workspaceRoot, "pubspec.lock");
4610
+ const lockPath = (0, import_node_path16.join)(workspaceRoot, "pubspec.lock");
4219
4611
  if (!fileExists(lockPath)) {
4220
4612
  return void 0;
4221
4613
  }
@@ -4223,7 +4615,7 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
4223
4615
  const match = new RegExp(
4224
4616
  String.raw`^\s{2}${escapeForRegex(name)}:[^]*?^\s+version:\s*["']?([^"'\s]+)`,
4225
4617
  "m"
4226
- ).exec((0, import_node_fs11.readFileSync)(lockPath, "utf8"));
4618
+ ).exec((0, import_node_fs12.readFileSync)(lockPath, "utf8"));
4227
4619
  return match?.[1];
4228
4620
  } catch {
4229
4621
  return void 0;
@@ -4415,7 +4807,7 @@ function describe(finding) {
4415
4807
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
4416
4808
  }
4417
4809
  function runSync(workspaceRoot, options) {
4418
- if (!fileExists((0, import_node_path16.join)(workspaceRoot, "nx.json"))) {
4810
+ if (!fileExists((0, import_node_path17.join)(workspaceRoot, "nx.json"))) {
4419
4811
  throw new Error(
4420
4812
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
4421
4813
  );
@@ -4465,7 +4857,7 @@ function runSync(workspaceRoot, options) {
4465
4857
  }
4466
4858
 
4467
4859
  // src/dependency-management/update-dependencies.use-case.ts
4468
- var import_node_path17 = require("path");
4860
+ var import_node_path18 = require("path");
4469
4861
  var import_prompts2 = require("@inquirer/prompts");
4470
4862
 
4471
4863
  // src/dependency-management/registry.client.ts
@@ -4748,7 +5140,7 @@ function reinstall(workspaceRoot, ecosystems) {
4748
5140
  function hasPythonInstallScript(workspaceRoot) {
4749
5141
  try {
4750
5142
  const manifest = readJson(
4751
- (0, import_node_path17.join)(workspaceRoot, "package.json")
5143
+ (0, import_node_path18.join)(workspaceRoot, "package.json")
4752
5144
  );
4753
5145
  return manifest.scripts?.["python:install"] !== void 0;
4754
5146
  } catch {
@@ -4764,7 +5156,7 @@ function applyGoUpdates(workspaceRoot, entries) {
4764
5156
  }
4765
5157
  }
4766
5158
  async function runUp(workspaceRoot, options) {
4767
- if (!fileExists((0, import_node_path17.join)(workspaceRoot, "nx.json"))) {
5159
+ if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
4768
5160
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
4769
5161
  }
4770
5162
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -4835,11 +5227,12 @@ var PROJECT_KINDS = [
4835
5227
  "csharp-app",
4836
5228
  "csharp-function-app",
4837
5229
  "csharp-lib",
4838
- "csharp-internal-lib"
5230
+ "csharp-internal-lib",
5231
+ "vscode-extension"
4839
5232
  ];
4840
5233
  async function runAdd(kind, name, options) {
4841
5234
  const workspaceRoot = process.cwd();
4842
- if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
5235
+ if (!fileExists((0, import_node_path19.join)(workspaceRoot, "nx.json"))) {
4843
5236
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
4844
5237
  }
4845
5238
  const stack = readWorkspaceStack(workspaceRoot);
@@ -4890,8 +5283,8 @@ async function runAdd(kind, name, options) {
4890
5283
  ],
4891
5284
  workspaceRoot
4892
5285
  );
4893
- markPrivate((0, import_node_path18.join)(workspaceRoot, "libs", resolvedName, "package.json"));
4894
- renameScaffoldPlaceholder((0, import_node_path18.join)(workspaceRoot, "libs", resolvedName), resolvedName);
5286
+ markPrivate((0, import_node_path19.join)(workspaceRoot, "libs", resolvedName, "package.json"));
5287
+ renameScaffoldPlaceholder((0, import_node_path19.join)(workspaceRoot, "libs", resolvedName), resolvedName);
4895
5288
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
4896
5289
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
4897
5290
  break;
@@ -4956,6 +5349,13 @@ async function runAdd(kind, name, options) {
4956
5349
  addCsharpInternalLib(workspaceRoot, resolvedName);
4957
5350
  break;
4958
5351
  }
5352
+ case "vscode-extension": {
5353
+ addVscodeExtension(workspaceRoot, resolvedName, stack, {
5354
+ publisher: options.publisher,
5355
+ sidecar: options.sidecar
5356
+ });
5357
+ break;
5358
+ }
4959
5359
  case "python-vendor": {
4960
5360
  await addPythonVendor(workspaceRoot, resolvedName, options, kindProvided);
4961
5361
  syncProjectReferences(workspaceRoot);
@@ -4976,7 +5376,7 @@ async function runAdd(kind, name, options) {
4976
5376
  }
4977
5377
  function readWorkspaceStack(workspaceRoot) {
4978
5378
  const nxJson = readJson(
4979
- (0, import_node_path18.join)(workspaceRoot, "nx.json")
5379
+ (0, import_node_path19.join)(workspaceRoot, "nx.json")
4980
5380
  );
4981
5381
  const stack = nxJson.mnci?.stack;
4982
5382
  return {
@@ -4985,15 +5385,15 @@ function readWorkspaceStack(workspaceRoot) {
4985
5385
  }
4986
5386
 
4987
5387
  // src/workspace-diagnostics/check-invariants.use-case.ts
4988
- var import_node_fs12 = require("fs");
4989
- var import_node_path19 = require("path");
5388
+ var import_node_fs13 = require("fs");
5389
+ var import_node_path20 = require("path");
4990
5390
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
4991
5391
  function toPosix2(path) {
4992
5392
  return path.replaceAll("\\", "/");
4993
5393
  }
4994
5394
  function checkEslintConfigs(workspaceRoot) {
4995
- const rootConfigs = (0, import_node_fs12.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
4996
- const projectConfigs = (0, import_node_fs12.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
5395
+ const rootConfigs = (0, import_node_fs13.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
5396
+ const projectConfigs = (0, import_node_fs13.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
4997
5397
  cwd: workspaceRoot
4998
5398
  }).map((config) => toPosix2(config));
4999
5399
  return [
@@ -5013,10 +5413,10 @@ function checkEslintConfigs(workspaceRoot) {
5013
5413
  ];
5014
5414
  }
5015
5415
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
5016
- const rules = (0, import_node_path19.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
5017
- if (!(0, import_node_fs12.existsSync)(rules)) return [];
5018
- const entryPoint = (0, import_node_path19.join)(workspaceRoot, ESLINT_USER_FILENAME);
5019
- const source = (0, import_node_fs12.existsSync)(entryPoint) ? (0, import_node_fs12.readFileSync)(entryPoint, "utf8") : "";
5416
+ const rules = (0, import_node_path20.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
5417
+ if (!(0, import_node_fs13.existsSync)(rules)) return [];
5418
+ const entryPoint = (0, import_node_path20.join)(workspaceRoot, ESLINT_USER_FILENAME);
5419
+ const source = (0, import_node_fs13.existsSync)(entryPoint) ? (0, import_node_fs13.readFileSync)(entryPoint, "utf8") : "";
5020
5420
  return [
5021
5421
  {
5022
5422
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -5029,7 +5429,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
5029
5429
  function declaredDevDependencies(workspaceRoot) {
5030
5430
  try {
5031
5431
  const manifest = readJson(
5032
- (0, import_node_path19.join)(workspaceRoot, "package.json")
5432
+ (0, import_node_path20.join)(workspaceRoot, "package.json")
5033
5433
  );
5034
5434
  return manifest.devDependencies ?? {};
5035
5435
  } catch {
@@ -5037,7 +5437,7 @@ function declaredDevDependencies(workspaceRoot) {
5037
5437
  }
5038
5438
  }
5039
5439
  function checkNoRetiredFormatter(workspaceRoot) {
5040
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path19.join)(workspaceRoot, file)));
5440
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path20.join)(workspaceRoot, file)));
5041
5441
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
5042
5442
  const stale = [...files, ...declared];
5043
5443
  if (stale.length === 0) {
@@ -5063,7 +5463,7 @@ function checkEslintPlugin(nxJson) {
5063
5463
  };
5064
5464
  }
5065
5465
  function checkResolvedEslint(workspaceRoot) {
5066
- const manifestPath = (0, import_node_path19.join)(workspaceRoot, "node_modules/eslint/package.json");
5466
+ const manifestPath = (0, import_node_path20.join)(workspaceRoot, "node_modules/eslint/package.json");
5067
5467
  if (!fileExists(manifestPath)) {
5068
5468
  return void 0;
5069
5469
  }
@@ -5081,11 +5481,11 @@ function checkResolvedEslint(workspaceRoot) {
5081
5481
  }
5082
5482
  }
5083
5483
  function checkNpmrc(workspaceRoot, registry, scope) {
5084
- const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
5484
+ const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5085
5485
  if (!registry || !fileExists(npmrcPath)) {
5086
5486
  return void 0;
5087
5487
  }
5088
- const npmrc = (0, import_node_fs12.readFileSync)(npmrcPath, "utf8");
5488
+ const npmrc = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8");
5089
5489
  if (registry.kind === "npm") {
5090
5490
  return {
5091
5491
  check: ".npmrc authenticates the public registry",
@@ -5102,11 +5502,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
5102
5502
  };
5103
5503
  }
5104
5504
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
5105
- const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
5505
+ const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5106
5506
  if (!fileExists(npmrcPath)) {
5107
5507
  return void 0;
5108
5508
  }
5109
- const npmrc = (0, import_node_fs12.readFileSync)(npmrcPath, "utf8");
5509
+ const npmrc = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8");
5110
5510
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5111
5511
  const referenced = [
5112
5512
  ...new Set(
@@ -5130,13 +5530,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
5130
5530
  };
5131
5531
  }
5132
5532
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
5133
- const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
5134
- const pipelinePath = (0, import_node_path19.join)(workspaceRoot, "azure-pipelines.yml");
5533
+ const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5534
+ const pipelinePath = (0, import_node_path20.join)(workspaceRoot, "azure-pipelines.yml");
5135
5535
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
5136
5536
  return void 0;
5137
5537
  }
5138
- const holdsCredentials = (0, import_node_fs12.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5139
- const runsTask = (0, import_node_fs12.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
5538
+ 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));
5539
+ const runsTask = (0, import_node_fs13.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
5140
5540
  if (!holdsCredentials && !runsTask) {
5141
5541
  return {
5142
5542
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -5181,13 +5581,13 @@ function npmjsCredentialShape(credentials, environment) {
5181
5581
  }
5182
5582
  function checkVersionActions(workspaceRoot) {
5183
5583
  const candidates = [
5184
- ...(0, import_node_fs12.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
5185
- ...(0, import_node_fs12.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
5186
- ...(0, import_node_fs12.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
5584
+ ...(0, import_node_fs13.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
5585
+ ...(0, import_node_fs13.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
5586
+ ...(0, import_node_fs13.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
5187
5587
  ].map((manifest) => toPosix2(manifest));
5188
5588
  return candidates.flatMap((manifest) => {
5189
5589
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
5190
- const projectJsonPath = (0, import_node_path19.join)(workspaceRoot, projectRoot, "project.json");
5590
+ const projectJsonPath = (0, import_node_path20.join)(workspaceRoot, projectRoot, "project.json");
5191
5591
  let hasOverride = false;
5192
5592
  try {
5193
5593
  const projectJson = readJson(projectJsonPath);
@@ -5216,7 +5616,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
5216
5616
  ]) {
5217
5617
  try {
5218
5618
  const targets = extract(
5219
- readJson((0, import_node_path19.join)(workspaceRoot, projectRoot, file))
5619
+ readJson((0, import_node_path20.join)(workspaceRoot, projectRoot, file))
5220
5620
  );
5221
5621
  if (targets && typeof targets === "object") {
5222
5622
  sources.push({
@@ -5232,8 +5632,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
5232
5632
  function checkTargetFilesExist(workspaceRoot) {
5233
5633
  const projectRoots = new Set(
5234
5634
  [
5235
- ...(0, import_node_fs12.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
5236
- ...(0, import_node_fs12.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
5635
+ ...(0, import_node_fs13.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
5636
+ ...(0, import_node_fs13.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
5237
5637
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
5238
5638
  );
5239
5639
  return [...projectRoots].flatMap(
@@ -5248,7 +5648,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
5248
5648
  return TARGET_FILE_OPTIONS.flatMap((option) => {
5249
5649
  const value = target?.options?.[option];
5250
5650
  const checkable = typeof value === "string" && !value.includes("{");
5251
- if (!checkable || fileExists((0, import_node_path19.join)(workspaceRoot, value))) {
5651
+ if (!checkable || fileExists((0, import_node_path20.join)(workspaceRoot, value))) {
5252
5652
  return [];
5253
5653
  }
5254
5654
  return [
@@ -5270,7 +5670,7 @@ function checkSync(workspaceRoot) {
5270
5670
  };
5271
5671
  }
5272
5672
  function checkNoRootRuntimeDependencies(workspaceRoot) {
5273
- const manifestPath = (0, import_node_path19.join)(workspaceRoot, "package.json");
5673
+ const manifestPath = (0, import_node_path20.join)(workspaceRoot, "package.json");
5274
5674
  if (!fileExists(manifestPath)) {
5275
5675
  return void 0;
5276
5676
  }
@@ -5290,14 +5690,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
5290
5690
  };
5291
5691
  }
5292
5692
  function checkRollupSourceMaps(workspaceRoot) {
5293
- const configs = (0, import_node_fs12.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5693
+ const configs = (0, import_node_fs13.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5294
5694
  cwd: workspaceRoot
5295
5695
  }).map((config) => toPosix2(config));
5296
5696
  return configs.flatMap((relativePath) => {
5297
- const configPath = (0, import_node_path19.join)(workspaceRoot, relativePath);
5697
+ const configPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
5298
5698
  let config;
5299
5699
  try {
5300
- config = (0, import_node_fs12.readFileSync)(configPath, "utf8");
5700
+ config = (0, import_node_fs13.readFileSync)(configPath, "utf8");
5301
5701
  } catch {
5302
5702
  return [];
5303
5703
  }
@@ -5312,11 +5712,11 @@ function checkRollupSourceMaps(workspaceRoot) {
5312
5712
  });
5313
5713
  }
5314
5714
  function checkDeclarationSpecifiers(workspaceRoot) {
5315
- const configs = (0, import_node_fs12.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5715
+ const configs = (0, import_node_fs13.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5316
5716
  cwd: workspaceRoot
5317
5717
  }).map((config) => toPosix2(config));
5318
5718
  return configs.flatMap((relativePath) => {
5319
- const configPath = (0, import_node_path19.join)(workspaceRoot, relativePath);
5719
+ const configPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
5320
5720
  if (!fileExists(configPath)) {
5321
5721
  return [];
5322
5722
  }
@@ -5350,7 +5750,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
5350
5750
  });
5351
5751
  }
5352
5752
  function collectFindings(workspaceRoot) {
5353
- const nxJsonPath = (0, import_node_path19.join)(workspaceRoot, "nx.json");
5753
+ const nxJsonPath = (0, import_node_path20.join)(workspaceRoot, "nx.json");
5354
5754
  if (!fileExists(nxJsonPath)) {
5355
5755
  throw new Error(
5356
5756
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -5395,8 +5795,8 @@ function runDoctor(workspaceRoot) {
5395
5795
  }
5396
5796
 
5397
5797
  // src/workspace-creation/adopt-directory.use-case.ts
5398
- var import_node_fs13 = require("fs");
5399
- var import_node_path20 = require("path");
5798
+ var import_node_fs14 = require("fs");
5799
+ var import_node_path21 = require("path");
5400
5800
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
5401
5801
  var AGENT_AND_CI_ENTRIES = [
5402
5802
  "AGENTS.md",
@@ -5427,13 +5827,13 @@ var PREFLIGHT_BLOCKERS = [
5427
5827
  "packages"
5428
5828
  ];
5429
5829
  function assertAdoptableDirectory(target) {
5430
- if (!(0, import_node_fs13.existsSync)(target)) {
5830
+ if (!(0, import_node_fs14.existsSync)(target)) {
5431
5831
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
5432
5832
  }
5433
- if (!(0, import_node_fs13.statSync)(target).isDirectory()) {
5833
+ if (!(0, import_node_fs14.statSync)(target).isDirectory()) {
5434
5834
  throw new Error(`--into '${target}' is not a directory.`);
5435
5835
  }
5436
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)));
5836
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs14.existsSync)((0, import_node_path21.join)(target, entry)));
5437
5837
  if (blockers.length > 0) {
5438
5838
  throw new Error(
5439
5839
  `--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.`
@@ -5441,15 +5841,15 @@ function assertAdoptableDirectory(target) {
5441
5841
  }
5442
5842
  }
5443
5843
  function mergeGitignore(generatedFile, targetFile) {
5444
- const existing = (0, import_node_fs13.readFileSync)(targetFile, "utf8");
5844
+ const existing = (0, import_node_fs14.readFileSync)(targetFile, "utf8");
5445
5845
  const present = new Set(existing.split("\n").map((line) => line.trim()));
5446
- const additions = (0, import_node_fs13.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
5846
+ const additions = (0, import_node_fs14.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
5447
5847
  const trimmed = line.trim();
5448
5848
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
5449
5849
  });
5450
5850
  if (additions.length === 0) return false;
5451
5851
  const separator = existing.endsWith("\n") ? "" : "\n";
5452
- (0, import_node_fs13.writeFileSync)(
5852
+ (0, import_node_fs14.writeFileSync)(
5453
5853
  targetFile,
5454
5854
  `${existing}${separator}
5455
5855
  # Added by mnci (Nx workspace)
@@ -5459,9 +5859,9 @@ ${additions.join("\n")}
5459
5859
  return true;
5460
5860
  }
5461
5861
  function adoptGeneratedWorkspace(generatedRoot, target) {
5462
- const entries = (0, import_node_fs13.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
5862
+ const entries = (0, import_node_fs14.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
5463
5863
  const collisions = entries.filter(
5464
- (entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
5864
+ (entry) => (0, import_node_fs14.existsSync)((0, import_node_path21.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
5465
5865
  );
5466
5866
  if (collisions.length > 0) {
5467
5867
  throw new Error(
@@ -5470,28 +5870,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
5470
5870
  }
5471
5871
  const result = { copied: [], kept: [], mergedGitignore: false };
5472
5872
  for (const entry of entries) {
5473
- const from = (0, import_node_path20.join)(generatedRoot, entry);
5474
- const to = (0, import_node_path20.join)(target, entry);
5475
- if (entry === ".gitignore" && (0, import_node_fs13.existsSync)(to)) {
5873
+ const from = (0, import_node_path21.join)(generatedRoot, entry);
5874
+ const to = (0, import_node_path21.join)(target, entry);
5875
+ if (entry === ".gitignore" && (0, import_node_fs14.existsSync)(to)) {
5476
5876
  result.mergedGitignore = mergeGitignore(from, to);
5477
5877
  result.kept.push(entry);
5478
5878
  continue;
5479
5879
  }
5480
- if ((0, import_node_fs13.existsSync)(to)) {
5880
+ if ((0, import_node_fs14.existsSync)(to)) {
5481
5881
  result.kept.push(entry);
5482
5882
  continue;
5483
5883
  }
5484
- (0, import_node_fs13.cpSync)(from, to, { recursive: true });
5884
+ (0, import_node_fs14.cpSync)(from, to, { recursive: true });
5485
5885
  result.copied.push(entry);
5486
5886
  }
5487
- (0, import_node_fs13.rmSync)(generatedRoot, { recursive: true, force: true });
5887
+ (0, import_node_fs14.rmSync)(generatedRoot, { recursive: true, force: true });
5488
5888
  return result;
5489
5889
  }
5490
5890
 
5491
5891
  // src/workspace-creation/create-workspace.use-case.ts
5492
- var import_node_fs14 = require("fs");
5892
+ var import_node_fs15 = require("fs");
5493
5893
  var import_node_os = require("os");
5494
- var import_node_path21 = require("path");
5894
+ var import_node_path22 = require("path");
5495
5895
  function nxCloudProviderValue(ci) {
5496
5896
  return ci === "azure" ? "azure" : "github";
5497
5897
  }
@@ -5527,9 +5927,9 @@ async function resolveRegistry(options) {
5527
5927
  return await promptRegistry();
5528
5928
  }
5529
5929
  async function runNew(name, options) {
5530
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path21.resolve)(process.cwd(), options.into);
5930
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path22.resolve)(process.cwd(), options.into);
5531
5931
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
5532
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path21.basename)(adoptTarget));
5932
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path22.basename)(adoptTarget));
5533
5933
  assertValidProjectName(workspaceName, "Workspace name");
5534
5934
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
5535
5935
  const registry = await resolveRegistry(options);
@@ -5542,8 +5942,8 @@ async function runNew(name, options) {
5542
5942
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
5543
5943
  const stack = await resolveStack(options);
5544
5944
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
5545
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs14.mkdtempSync)((0, import_node_path21.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
5546
- let workspaceRoot = (0, import_node_path21.join)(stagingParent, workspaceName);
5945
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs15.mkdtempSync)((0, import_node_path22.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
5946
+ let workspaceRoot = (0, import_node_path22.join)(stagingParent, workspaceName);
5547
5947
  try {
5548
5948
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
5549
5949
  runNpx(
@@ -5566,7 +5966,7 @@ async function runNew(name, options) {
5566
5966
  workspaceRoot = adoptTarget;
5567
5967
  }
5568
5968
  } finally {
5569
- if (adoptTarget !== void 0) (0, import_node_fs14.rmSync)(stagingParent, { recursive: true, force: true });
5969
+ if (adoptTarget !== void 0) (0, import_node_fs15.rmSync)(stagingParent, { recursive: true, force: true });
5570
5970
  }
5571
5971
  logger.step(
5572
5972
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -5576,8 +5976,8 @@ async function runNew(name, options) {
5576
5976
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
5577
5977
  logger.detail
5578
5978
  );
5579
- (0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
5580
- (0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "package-lock.json"), { force: true });
5979
+ (0, import_node_fs15.rmSync)((0, import_node_path22.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
5980
+ (0, import_node_fs15.rmSync)((0, import_node_path22.join)(workspaceRoot, "package-lock.json"), { force: true });
5581
5981
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
5582
5982
  const installStatus = runShell(
5583
5983
  "npm",
@@ -5601,18 +6001,19 @@ async function runNew(name, options) {
5601
6001
  " # go-app, go-function-app, go-lib, go-internal-lib,"
5602
6002
  );
5603
6003
  logger.info(
5604
- " # flutter-app, flutter-lib, flutter-internal-lib"
6004
+ " # flutter-app, flutter-lib, flutter-internal-lib,"
5605
6005
  );
6006
+ logger.info(" # vscode-extension");
5606
6007
  logger.info(' git add -A && git commit -m "feat: initial workspace"');
5607
6008
  }
5608
6009
 
5609
6010
  // src/workspace-creation/interactive-wizard.use-case.ts
5610
- var import_node_path23 = require("path");
6011
+ var import_node_path24 = require("path");
5611
6012
  var import_prompts4 = require("@inquirer/prompts");
5612
6013
 
5613
6014
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
5614
- var import_node_fs15 = require("fs");
5615
- var import_node_path22 = require("path");
6015
+ var import_node_fs16 = require("fs");
6016
+ var import_node_path23 = require("path");
5616
6017
  function resolveRegistry2(options, persisted) {
5617
6018
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
5618
6019
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -5641,7 +6042,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
5641
6042
  return persisted.workspaceName;
5642
6043
  }
5643
6044
  try {
5644
- const existing = (0, import_node_fs15.readdirSync)(workspaceRoot).find(
6045
+ const existing = (0, import_node_fs16.readdirSync)(workspaceRoot).find(
5645
6046
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
5646
6047
  );
5647
6048
  if (existing) {
@@ -5649,11 +6050,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
5649
6050
  }
5650
6051
  } catch {
5651
6052
  }
5652
- return (0, import_node_path22.basename)(workspaceRoot);
6053
+ return (0, import_node_path23.basename)(workspaceRoot);
5653
6054
  }
5654
6055
  function detectNpmAuth(workspaceRoot) {
5655
6056
  try {
5656
- return (0, import_node_fs15.readFileSync)((0, import_node_path22.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6057
+ return (0, import_node_fs16.readFileSync)((0, import_node_path23.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
5657
6058
  } catch {
5658
6059
  return void 0;
5659
6060
  }
@@ -5700,7 +6101,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
5700
6101
  };
5701
6102
  }
5702
6103
  function runUpgrade(workspaceRoot, options) {
5703
- if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
6104
+ if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
5704
6105
  throw new Error(
5705
6106
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
5706
6107
  );
@@ -5730,6 +6131,17 @@ function runUpgrade(workspaceRoot, options) {
5730
6131
  logger.detail(`updated ${path}`);
5731
6132
  }
5732
6133
  }
6134
+ const pinnedExtensions = pinVscodeExtensionProjectNames(workspaceRoot);
6135
+ if (pinnedExtensions.length > 0) {
6136
+ logger.step("Pinning the Nx project name of VS Code extensions (nx.name)");
6137
+ for (const path of pinnedExtensions) {
6138
+ logger.detail(`updated ${path}`);
6139
+ }
6140
+ }
6141
+ if (refreshVscodeExtensionScript(workspaceRoot)) {
6142
+ logger.step("Updating the VS Code extension packaging script");
6143
+ logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
6144
+ }
5733
6145
  const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
5734
6146
  if (upgradedDtsPlugins.length > 0) {
5735
6147
  logger.step("Upgrading declaration specifiers to resolve under nodenext");
@@ -5746,7 +6158,7 @@ function runUpgrade(workspaceRoot, options) {
5746
6158
 
5747
6159
  // src/workspace-creation/interactive-wizard.use-case.ts
5748
6160
  async function runInteractive() {
5749
- const inWorkspace = fileExists((0, import_node_path23.join)(process.cwd(), "nx.json"));
6161
+ const inWorkspace = fileExists((0, import_node_path24.join)(process.cwd(), "nx.json"));
5750
6162
  const choiceNew = { name: "Create a new monorepo", value: "new" };
5751
6163
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
5752
6164
  const choiceUpgrade = {
@@ -5767,8 +6179,8 @@ async function runInteractive() {
5767
6179
  }
5768
6180
 
5769
6181
  // src/cli-version/check-for-update.use-case.ts
5770
- var import_node_fs16 = require("fs");
5771
- var import_node_path24 = require("path");
6182
+ var import_node_fs17 = require("fs");
6183
+ var import_node_path25 = require("path");
5772
6184
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
5773
6185
  var PACKAGE_NAME = "@mnci/cli";
5774
6186
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -5824,8 +6236,8 @@ function releaseTriple(version) {
5824
6236
  }
5825
6237
  function readCliVersion(packageDirectory) {
5826
6238
  try {
5827
- const manifestPath = (0, import_node_path24.join)(packageDirectory, "..", "package.json");
5828
- const manifest = JSON.parse((0, import_node_fs16.readFileSync)(manifestPath, "utf8"));
6239
+ const manifestPath = (0, import_node_path25.join)(packageDirectory, "..", "package.json");
6240
+ const manifest = JSON.parse((0, import_node_fs17.readFileSync)(manifestPath, "utf8"));
5829
6241
  return manifest.version ?? "0.0.0";
5830
6242
  } catch {
5831
6243
  return "0.0.0";
@@ -5880,6 +6292,12 @@ function buildProgram(cliVersion) {
5880
6292
  ).option(
5881
6293
  "--lib <name>",
5882
6294
  "python-vendor only: the internal Python library (libs/<name>) to vendor into <name>"
6295
+ ).option(
6296
+ "--publisher <id>",
6297
+ "vscode-extension only: the Marketplace publisher id (defaults to the workspace scope without @)"
6298
+ ).option(
6299
+ "--sidecar <go-app>",
6300
+ "vscode-extension only: a go-app whose six-platform build ships in the extension, one .vsix per platform"
5883
6301
  ).action(
5884
6302
  async (kind, name, options) => {
5885
6303
  await runAdd(kind, name, options);