@mnci/cli 4.10.8 → 4.12.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_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
@@ -2636,6 +2648,63 @@ function goPackageTarget(tag, name) {
2636
2648
  options: { command }
2637
2649
  };
2638
2650
  }
2651
+ var GO_PLATFORMS = [
2652
+ "windows/amd64",
2653
+ "windows/arm64",
2654
+ "linux/amd64",
2655
+ "linux/arm64",
2656
+ "darwin/amd64",
2657
+ "darwin/arm64"
2658
+ ];
2659
+ function goBuildAllTarget(name) {
2660
+ const platforms = JSON.stringify(GO_PLATFORMS).replaceAll('"', "'");
2661
+ const command = `node -e "const{spawnSync}=require('node:child_process');const v=process.env.VERSION||'dev';for(const p of ${platforms}){const[os,arch]=p.split('/');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:'0',GOOS:os,GOARCH:arch}});if(r.status!==0)process.exit(r.status??1)}"`;
2662
+ return {
2663
+ executor: "nx:run-commands",
2664
+ inputs: ["default", "^default", "{workspaceRoot}/go.mod", "{workspaceRoot}/go.sum", { env: "VERSION" }],
2665
+ outputs: [`{workspaceRoot}/dist/platforms/${name}`],
2666
+ options: { command }
2667
+ };
2668
+ }
2669
+ function goPackageAllTarget(tag, name) {
2670
+ const command = `node -e "const fs=require('node:fs');const A=require('adm-zip');fs.mkdirSync('dist/drop',{recursive:true});for(const d of fs.readdirSync('dist/platforms/${name}')){const z=new A();z.addLocalFolder('dist/platforms/${name}/'+d);z.writeZip('dist/drop/${tag}-${name}-'+d+'.zip')}"`;
2671
+ return {
2672
+ executor: "nx:run-commands",
2673
+ dependsOn: ["build-all"],
2674
+ outputs: [`{workspaceRoot}/dist/drop/${tag}-${name}-*.zip`],
2675
+ options: { command }
2676
+ };
2677
+ }
2678
+ function addGoPlatformTargets(workspaceRoot) {
2679
+ const changed = [];
2680
+ const apps = (0, import_node_path6.join)(workspaceRoot, "apps");
2681
+ if (!fileExists(apps)) {
2682
+ return changed;
2683
+ }
2684
+ for (const name of (0, import_node_fs5.readdirSync)(apps)) {
2685
+ const projectJsonPath = (0, import_node_path6.join)(apps, name, "project.json");
2686
+ if (!fileExists(projectJsonPath)) {
2687
+ continue;
2688
+ }
2689
+ const project = JSON.parse((0, import_node_fs5.readFileSync)(projectJsonPath, "utf8"));
2690
+ const tag = (project.tags ?? []).find((each) => each === "type:go-app" || each === "type:go-function-app")?.slice("type:".length);
2691
+ if (tag === void 0) {
2692
+ continue;
2693
+ }
2694
+ const missing = {};
2695
+ if (project.targets?.["build-all"] === void 0) {
2696
+ missing["build-all"] = goBuildAllTarget(name);
2697
+ }
2698
+ if (project.targets?.["package-all"] === void 0) {
2699
+ missing["package-all"] = goPackageAllTarget(tag, name);
2700
+ }
2701
+ if (Object.keys(missing).length > 0) {
2702
+ addProjectJsonTargets(projectJsonPath, missing);
2703
+ changed.push(`apps/${name}/project.json`);
2704
+ }
2705
+ }
2706
+ return changed;
2707
+ }
2639
2708
  function goStartTarget(name) {
2640
2709
  return {
2641
2710
  executor: "nx:run-commands",
@@ -2723,11 +2792,13 @@ function addGoApp(workspaceRoot, name) {
2723
2792
  workspaceRoot
2724
2793
  );
2725
2794
  addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
2726
- build: goBuildTarget(name),
2727
- test: goTestTarget(),
2728
- lint: goLintTarget(),
2729
- package: goPackageTarget("go-app", name),
2730
- start: goStartTarget(name)
2795
+ "build": goBuildTarget(name),
2796
+ "test": goTestTarget(),
2797
+ "lint": goLintTarget(),
2798
+ "package": goPackageTarget("go-app", name),
2799
+ "build-all": goBuildAllTarget(name),
2800
+ "package-all": goPackageAllTarget("go-app", name),
2801
+ "start": goStartTarget(name)
2731
2802
  });
2732
2803
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
2733
2804
  }
@@ -2746,10 +2817,12 @@ function addGoFunctionApp(workspaceRoot, name) {
2746
2817
  workspaceRoot
2747
2818
  );
2748
2819
  addProjectJsonTargets((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
2749
- build: goBuildTarget(name),
2750
- test: goTestTarget(),
2751
- lint: goLintTarget(),
2752
- package: goPackageTarget("go-function-app", name)
2820
+ "build": goBuildTarget(name),
2821
+ "test": goTestTarget(),
2822
+ "lint": goLintTarget(),
2823
+ "package": goPackageTarget("go-function-app", name),
2824
+ "build-all": goBuildAllTarget(name),
2825
+ "package-all": goPackageAllTarget("go-function-app", name)
2753
2826
  });
2754
2827
  registerProjectCommands(workspaceRoot, name, { build: true });
2755
2828
  }
@@ -3728,12 +3801,366 @@ function addReactInternalLib(workspaceRoot, name, stack) {
3728
3801
  );
3729
3802
  }
3730
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/<name>.vsix.
3826
+ // With --sidecar: one dist/drop/<name>-<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 { 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(manifest.name)[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, manifest.name + '-' + 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(manifest.name, 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(manifest.name, 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
+ // nx release --dry-run hands the publish target --dryRun=true and sets NX_DRY_RUN
3907
+ // (measured on Nx 23), so a dry run never reaches the Marketplace, token or not.
3908
+ const dryRun = rest.some(argument => /^--dry-?run(=true)?$/i.test(argument)) || process.env.NX_DRY_RUN === 'true'
3909
+ if (command === 'package') packageExtension(projectRoot, manifest, sidecar)
3910
+ else if (command === 'publish') publishExtension(manifest, sidecar, dryRun)
3911
+ else fail('Unknown command ' + command + ' - expected package or publish.')
3912
+ `;
3913
+ var VSCODE_IGNORE = `src/**
3914
+ test/**
3915
+ out-tsc/**
3916
+ test-output/**
3917
+ **/*.map
3918
+ **/*.d.ts
3919
+ **/*.spec.*
3920
+ tsconfig*.json
3921
+ jest.config.*
3922
+ vitest.config.*
3923
+ .spec.swcrc
3924
+ node_modules/**
3925
+ `;
3926
+ function vscodeExtensionMain(name) {
3927
+ return `import * as vscode from 'vscode'
3928
+
3929
+ export function activate (context: vscode.ExtensionContext): void {
3930
+ context.subscriptions.push(
3931
+ vscode.commands.registerCommand('${name}.hello', () => {
3932
+ void vscode.window.showInformationMessage('Hello from ${name}')
3933
+ }),
3934
+ )
3935
+ }
3936
+
3937
+ export function deactivate (): void {}
3938
+ `;
3939
+ }
3940
+ function vscodeExtensionMainSpec(name) {
3941
+ return `import * as vscode from 'vscode'
3942
+ import { activate } from './main'
3943
+
3944
+ describe('activate', () => {
3945
+ it('registers the ${name}.hello command', async () => {
3946
+ const context = { subscriptions: [] } as unknown as vscode.ExtensionContext
3947
+
3948
+ activate(context)
3949
+
3950
+ expect(context.subscriptions).toHaveLength(1)
3951
+ expect(await vscode.commands.getCommands()).toContain('${name}.hello')
3952
+ })
3953
+ })
3954
+ `;
3955
+ }
3956
+ var VSCODE_STUB = `// Stands in for the 'vscode' module in unit tests: that module exists only
3957
+ // inside the extension host. Extend it as the extension reaches for more API.
3958
+ const registered = new Map<string, (...arguments_: unknown[]) => unknown>()
3959
+
3960
+ export const commands = {
3961
+ registerCommand (id: string, handler: (...arguments_: unknown[]) => unknown): { dispose: () => void } {
3962
+ registered.set(id, handler)
3963
+
3964
+ return { dispose: () => { registered.delete(id) } }
3965
+ },
3966
+ getCommands (): Promise<string[]> {
3967
+ return Promise.resolve(registered.keys().toArray())
3968
+ },
3969
+ executeCommand (id: string, ...arguments_: unknown[]): Promise<unknown> {
3970
+ return Promise.resolve(registered.get(id)?.(...arguments_))
3971
+ },
3972
+ }
3973
+
3974
+ export const window = {
3975
+ showInformationMessage (_message: string): Promise<undefined> {
3976
+ return Promise.resolve(undefined)
3977
+ },
3978
+ }
3979
+ `;
3980
+ var VSCODE_STUB_PATH = "test/vscode.stub.ts";
3981
+ function mapVscodeToStub(projectRoot, testRunner) {
3982
+ 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}\` },`];
3983
+ const path = (0, import_node_path15.join)(projectRoot, file);
3984
+ const content = fileExists(path) ? (0, import_node_fs11.readFileSync)(path, "utf8") : "";
3985
+ const line = content.split("\n").find((candidate) => candidate.trim() === anchor);
3986
+ if (line === void 0) {
3987
+ throw new Error(`${file} has no "${anchor}" line to map the vscode module after; map 'vscode' to ${VSCODE_STUB_PATH} by hand.`);
3988
+ }
3989
+ const indent = line.slice(0, line.indexOf(anchor));
3990
+ writeFileEnsured(path, content.replace(line, () => `${line}
3991
+ ${indent}${mapping}`));
3992
+ }
3993
+ function ensureVscodeToolchain(workspaceRoot) {
3994
+ const missing = ["@types/vscode", "@vscode/vsce"].filter((name) => !hasPlugin(workspaceRoot, name));
3995
+ if (missing.length === 0) {
3996
+ return;
3997
+ }
3998
+ logger.step(`Installing the VS Code extension toolchain (${missing.join(", ")})`);
3999
+ if (runShell("npm", ["install", "--save-dev", ...missing, "--no-audit", "--no-fund"], workspaceRoot) !== 0) {
4000
+ throw new Error(`npm install of ${missing.join(", ")} failed`);
4001
+ }
4002
+ }
4003
+ function defaultPublisher(workspaceRoot) {
4004
+ const { name } = readJson((0, import_node_path15.join)(workspaceRoot, "package.json"));
4005
+ return (name ?? "publisher").replace(/^@/, "").split("/", 1)[0];
4006
+ }
4007
+ function reshapeManifest(projectRoot, name, publisher, typesVersion) {
4008
+ const manifestPath = (0, import_node_path15.join)(projectRoot, "package.json");
4009
+ const manifest = readJson(manifestPath);
4010
+ const { nx = {}, ...rest } = manifest;
4011
+ const targets = { ...nx.targets };
4012
+ for (const target of ["serve", "prune", "prune-lockfile", "copy-workspace-modules"]) {
4013
+ delete targets[target];
4014
+ }
4015
+ const build = targets.build ?? {};
4016
+ targets.build = {
4017
+ ...build,
4018
+ options: {
4019
+ ...build.options,
4020
+ bundle: true,
4021
+ thirdParty: true,
4022
+ external: ["vscode"],
4023
+ generatePackageJson: false
4024
+ }
4025
+ };
4026
+ writeFileEnsured(
4027
+ manifestPath,
4028
+ toJson({
4029
+ ...rest,
4030
+ name,
4031
+ displayName: name,
4032
+ version: rest.version ?? "0.0.1",
4033
+ publisher,
4034
+ engines: { vscode: `^${typesVersion}` },
4035
+ categories: ["Other"],
4036
+ main: "./dist/main.js",
4037
+ activationEvents: [],
4038
+ contributes: { commands: [{ command: `${name}.hello`, title: `${name}: Hello` }] },
4039
+ nx: { ...nx, tags: [.../* @__PURE__ */ new Set([...nx.tags ?? [], VSCODE_EXTENSION_TAG])], targets }
4040
+ })
4041
+ );
4042
+ }
4043
+ function addVscodeTypes(tsconfigPath) {
4044
+ if (!fileExists(tsconfigPath)) {
4045
+ return;
4046
+ }
4047
+ const tsconfig = readJson(tsconfigPath);
4048
+ const compilerOptions = tsconfig.compilerOptions ?? {};
4049
+ const types = compilerOptions.types ?? [];
4050
+ if (types.includes("vscode")) {
4051
+ return;
4052
+ }
4053
+ writeFileEnsured(tsconfigPath, toJson({ ...tsconfig, compilerOptions: { ...compilerOptions, types: [...types, "vscode"] } }));
4054
+ }
4055
+ function vscodeExtensionPackageTarget(name, sidecar) {
4056
+ const outputs = sidecar ? Object.keys(VSCODE_SIDECAR_TARGETS).map((target) => `{workspaceRoot}/dist/drop/${name}-${target}.vsix`) : [`{workspaceRoot}/dist/drop/${name}.vsix`];
4057
+ return {
4058
+ executor: "nx:run-commands",
4059
+ dependsOn: ["build"],
4060
+ outputs,
4061
+ options: { command: `node ${VSCODE_EXTENSION_SCRIPT_PATH} package apps/${name}${sidecar ? ` --sidecar ${sidecar}` : ""}` }
4062
+ };
4063
+ }
4064
+ function vscodeExtensionPublishTarget(name, sidecar) {
4065
+ return {
4066
+ executor: "nx:run-commands",
4067
+ dependsOn: ["package"],
4068
+ options: { command: `node ${VSCODE_EXTENSION_SCRIPT_PATH} publish apps/${name}${sidecar ? ` --sidecar ${sidecar}` : ""}` }
4069
+ };
4070
+ }
4071
+ function addDebugLaunch(workspaceRoot, name) {
4072
+ const file = (0, import_node_fs11.readdirSync)(workspaceRoot).find((entry) => entry.endsWith(".code-workspace"));
4073
+ if (file === void 0) {
4074
+ return;
4075
+ }
4076
+ const path = (0, import_node_path15.join)(workspaceRoot, file);
4077
+ const workspace = readCodeWorkspace(path) ?? {};
4078
+ const folder = `\${workspaceFolder:${workspace.folders?.[0]?.name ?? file.replace(/\.code-workspace$/, "")}}`;
4079
+ const taskLabel = `${name}: build (development)`;
4080
+ const launchName = `${name}: debug`;
4081
+ const tasks = (workspace.tasks?.tasks ?? []).filter((task) => task.label !== taskLabel);
4082
+ const configurations = (workspace.launch?.configurations ?? []).filter((configuration) => configuration.name !== launchName);
4083
+ writeFileEnsured(
4084
+ path,
4085
+ toJson({
4086
+ ...workspace,
4087
+ tasks: {
4088
+ version: workspace.tasks?.version ?? "2.0.0",
4089
+ tasks: [...tasks, { label: taskLabel, type: "shell", command: `npx nx run ${name}:build:development`, problemMatcher: [] }]
4090
+ },
4091
+ launch: {
4092
+ version: workspace.launch?.version ?? "0.2.0",
4093
+ configurations: [
4094
+ ...configurations,
4095
+ {
4096
+ name: launchName,
4097
+ type: "extensionHost",
4098
+ request: "launch",
4099
+ args: [`--extensionDevelopmentPath=${folder}/apps/${name}`],
4100
+ outFiles: [`${folder}/apps/${name}/dist/**/*.js`],
4101
+ preLaunchTask: taskLabel
4102
+ }
4103
+ ]
4104
+ }
4105
+ })
4106
+ );
4107
+ }
4108
+ function refreshVscodeExtensionScript(workspaceRoot) {
4109
+ const apps = (0, import_node_path15.join)(workspaceRoot, "apps");
4110
+ let entries;
4111
+ try {
4112
+ entries = (0, import_node_fs11.readdirSync)(apps);
4113
+ } catch {
4114
+ return false;
4115
+ }
4116
+ const hasExtension = entries.some((entry) => {
4117
+ const manifestPath = (0, import_node_path15.join)(apps, entry, "package.json");
4118
+ if (!fileExists(manifestPath)) {
4119
+ return false;
4120
+ }
4121
+ const tags = readJson(manifestPath).nx?.tags ?? [];
4122
+ return tags.includes(VSCODE_EXTENSION_TAG);
4123
+ });
4124
+ const path = (0, import_node_path15.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH);
4125
+ if (!hasExtension || fileExists(path) && (0, import_node_fs11.readFileSync)(path, "utf8") === VSCODE_EXTENSION_SCRIPT) {
4126
+ return false;
4127
+ }
4128
+ writeFileEnsured(path, VSCODE_EXTENSION_SCRIPT);
4129
+ return true;
4130
+ }
4131
+ function addVscodeExtension(workspaceRoot, name, stack, options = {}) {
4132
+ const { sidecar } = options;
4133
+ if (sidecar !== void 0 && !fileExists((0, import_node_path15.join)(workspaceRoot, "apps", sidecar, "project.json"))) {
4134
+ throw new Error(`--sidecar ${sidecar}: no Go app at apps/${sidecar}. Add it first with \`mnci add go-app ${sidecar}\`.`);
4135
+ }
4136
+ runNodeApp(workspaceRoot, name, stack, "none");
4137
+ ensureVscodeToolchain(workspaceRoot);
4138
+ const projectRoot = (0, import_node_path15.join)(workspaceRoot, "apps", name);
4139
+ const typesVersion = readJson((0, import_node_path15.join)(workspaceRoot, "node_modules/@types/vscode/package.json")).version;
4140
+ reshapeManifest(projectRoot, name, options.publisher ?? defaultPublisher(workspaceRoot), typesVersion);
4141
+ addVscodeTypes((0, import_node_path15.join)(projectRoot, "tsconfig.app.json"));
4142
+ addVscodeTypes((0, import_node_path15.join)(projectRoot, "tsconfig.spec.json"));
4143
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, "src/main.ts"), vscodeExtensionMain(name));
4144
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, "src/main.spec.ts"), vscodeExtensionMainSpec(name));
4145
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, VSCODE_STUB_PATH), VSCODE_STUB);
4146
+ mapVscodeToStub(projectRoot, stack.testRunner);
4147
+ writeFileEnsured((0, import_node_path15.join)(projectRoot, ".vscodeignore"), VSCODE_IGNORE);
4148
+ writeFileEnsured((0, import_node_path15.join)(workspaceRoot, VSCODE_EXTENSION_SCRIPT_PATH), VSCODE_EXTENSION_SCRIPT);
4149
+ addNxTargets((0, import_node_path15.join)(projectRoot, "package.json"), {
4150
+ "package": vscodeExtensionPackageTarget(name, sidecar),
4151
+ "nx-release-publish": vscodeExtensionPublishTarget(name, sidecar)
4152
+ });
4153
+ removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
4154
+ registerProjectCommands(workspaceRoot, name, { build: true });
4155
+ addDebugLaunch(workspaceRoot, name);
4156
+ }
4157
+
3731
4158
  // src/dependency-management/sync-dependencies.use-case.ts
3732
- var import_node_path16 = require("path");
4159
+ var import_node_path17 = require("path");
3733
4160
 
3734
4161
  // src/dependency-management/manifest.repository.ts
3735
- var import_node_fs11 = require("fs");
3736
- var import_node_path15 = require("path");
4162
+ var import_node_fs12 = require("fs");
4163
+ var import_node_path16 = require("path");
3737
4164
  var ECOSYSTEMS = ["npm", "pip", "pub", "nuget", "go"];
3738
4165
  var ROOT_LABEL = "(root)";
3739
4166
  var MANIFEST_GLOBS = {
@@ -3766,23 +4193,23 @@ function projectOf(manifestRelativePath) {
3766
4193
  }
3767
4194
  function hasEcosystem(workspaceRoot, ecosystem) {
3768
4195
  if (ecosystem === "go") {
3769
- return fileExists((0, import_node_path15.join)(workspaceRoot, "go.mod"));
4196
+ return fileExists((0, import_node_path16.join)(workspaceRoot, "go.mod"));
3770
4197
  }
3771
4198
  if (ecosystem === "nuget") {
3772
- return (0, import_node_fs11.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
4199
+ return (0, import_node_fs12.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot }).length > 0;
3773
4200
  }
3774
4201
  const rootMarker = {
3775
4202
  npm: "package.json",
3776
4203
  pip: "requirements-dev.txt",
3777
4204
  pub: "pubspec.yaml"
3778
4205
  };
3779
- return fileExists((0, import_node_path15.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs11.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
4206
+ return fileExists((0, import_node_path16.join)(workspaceRoot, rootMarker[ecosystem])) || (0, import_node_fs12.globSync)(MANIFEST_GLOBS[ecosystem], { cwd: workspaceRoot }).length > 0;
3780
4207
  }
3781
4208
  function collectNpm(workspaceRoot) {
3782
4209
  const sites = [];
3783
- const relativePaths = ["package.json", ...(0, import_node_fs11.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
4210
+ const relativePaths = ["package.json", ...(0, import_node_fs12.globSync)(MANIFEST_GLOBS.npm, { cwd: workspaceRoot })];
3784
4211
  for (const relativePath of relativePaths) {
3785
- const manifestPath = (0, import_node_path15.join)(workspaceRoot, relativePath);
4212
+ const manifestPath = (0, import_node_path16.join)(workspaceRoot, relativePath);
3786
4213
  try {
3787
4214
  const manifest = readJson(manifestPath);
3788
4215
  sites.push(...npmManifestSites(manifest, relativePath, manifestPath));
@@ -3843,17 +4270,17 @@ function collectPip(workspaceRoot) {
3843
4270
  name: parsed.name,
3844
4271
  ecosystem: "pip",
3845
4272
  project: projectOf(relativePath),
3846
- manifestPath: (0, import_node_path15.join)(workspaceRoot, relativePath),
4273
+ manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
3847
4274
  section,
3848
4275
  spec: parsed.spec,
3849
4276
  rewritable: parsed.rewritable && parsed.spec !== ""
3850
4277
  });
3851
4278
  };
3852
- const pyprojectPaths = (0, import_node_fs11.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
4279
+ const pyprojectPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.pip, { cwd: workspaceRoot });
3853
4280
  for (const relativePath of pyprojectPaths) {
3854
4281
  let content;
3855
4282
  try {
3856
- content = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8");
4283
+ content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
3857
4284
  } catch {
3858
4285
  continue;
3859
4286
  }
@@ -3864,14 +4291,14 @@ function collectPip(workspaceRoot) {
3864
4291
  }
3865
4292
  const requirementsPaths = [
3866
4293
  "requirements-dev.txt",
3867
- ...(0, import_node_fs11.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
4294
+ ...(0, import_node_fs12.globSync)("apps/*/requirements.txt", { cwd: workspaceRoot })
3868
4295
  ];
3869
4296
  for (const relativePath of requirementsPaths) {
3870
- if (!fileExists((0, import_node_path15.join)(workspaceRoot, relativePath))) {
4297
+ if (!fileExists((0, import_node_path16.join)(workspaceRoot, relativePath))) {
3871
4298
  continue;
3872
4299
  }
3873
4300
  const section = relativePath === "requirements-dev.txt" ? "devDep" : "dep";
3874
- const lines = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
4301
+ const lines = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8").split(/\r?\n/);
3875
4302
  for (const line of lines) {
3876
4303
  push(relativePath, section, line);
3877
4304
  }
@@ -3909,11 +4336,11 @@ function pyprojectDependencies(content) {
3909
4336
  }
3910
4337
  function collectPub(workspaceRoot) {
3911
4338
  const sites = [];
3912
- const pubspecPaths = (0, import_node_fs11.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
4339
+ const pubspecPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.pub, { cwd: workspaceRoot });
3913
4340
  for (const relativePath of pubspecPaths) {
3914
4341
  let content;
3915
4342
  try {
3916
- content = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8");
4343
+ content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
3917
4344
  } catch {
3918
4345
  continue;
3919
4346
  }
@@ -3923,7 +4350,7 @@ function collectPub(workspaceRoot) {
3923
4350
  name: entry.name,
3924
4351
  ecosystem: "pub",
3925
4352
  project: projectOf(relativePath),
3926
- manifestPath: (0, import_node_path15.join)(workspaceRoot, relativePath),
4353
+ manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
3927
4354
  section: block === "dependencies" ? "dep" : "devDep",
3928
4355
  spec: entry.spec,
3929
4356
  rewritable: entry.spec !== ""
@@ -3973,11 +4400,11 @@ function stripQuotes(value) {
3973
4400
  }
3974
4401
  function collectNuget(workspaceRoot) {
3975
4402
  const sites = [];
3976
- const csprojPaths = (0, import_node_fs11.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
4403
+ const csprojPaths = (0, import_node_fs12.globSync)(MANIFEST_GLOBS.nuget, { cwd: workspaceRoot });
3977
4404
  for (const relativePath of csprojPaths) {
3978
4405
  let content;
3979
4406
  try {
3980
- content = (0, import_node_fs11.readFileSync)((0, import_node_path15.join)(workspaceRoot, relativePath), "utf8");
4407
+ content = (0, import_node_fs12.readFileSync)((0, import_node_path16.join)(workspaceRoot, relativePath), "utf8");
3981
4408
  } catch {
3982
4409
  continue;
3983
4410
  }
@@ -3986,7 +4413,7 @@ function collectNuget(workspaceRoot) {
3986
4413
  name: entry.name,
3987
4414
  ecosystem: "nuget",
3988
4415
  project: projectOf(relativePath),
3989
- manifestPath: (0, import_node_path15.join)(workspaceRoot, relativePath),
4416
+ manifestPath: (0, import_node_path16.join)(workspaceRoot, relativePath),
3990
4417
  section: "dep",
3991
4418
  spec: entry.spec,
3992
4419
  // A plain SemVer string is rewritable; an MSBuild property reference
@@ -4011,13 +4438,13 @@ function csprojPackageReferences(content) {
4011
4438
  return entries;
4012
4439
  }
4013
4440
  function collectGo(workspaceRoot) {
4014
- const manifestPath = (0, import_node_path15.join)(workspaceRoot, "go.mod");
4441
+ const manifestPath = (0, import_node_path16.join)(workspaceRoot, "go.mod");
4015
4442
  if (!fileExists(manifestPath)) {
4016
4443
  return [];
4017
4444
  }
4018
4445
  let content;
4019
4446
  try {
4020
- content = (0, import_node_fs11.readFileSync)(manifestPath, "utf8");
4447
+ content = (0, import_node_fs12.readFileSync)(manifestPath, "utf8");
4021
4448
  } catch {
4022
4449
  return [];
4023
4450
  }
@@ -4074,7 +4501,7 @@ function rewriteSpec(site, spec) {
4074
4501
  writeFileEnsured(site.manifestPath, toJson(manifest));
4075
4502
  return true;
4076
4503
  }
4077
- const before = (0, import_node_fs11.readFileSync)(site.manifestPath, "utf8");
4504
+ const before = (0, import_node_fs12.readFileSync)(site.manifestPath, "utf8");
4078
4505
  const after = (() => {
4079
4506
  switch (site.ecosystem) {
4080
4507
  case "pip": {
@@ -4130,13 +4557,13 @@ function escapeForRegex(value) {
4130
4557
  function isWorkspaceProject(workspaceRoot, name) {
4131
4558
  const short = name.includes("/") ? name.split("/").at(-1) : name;
4132
4559
  return ["apps", "libs", "packages"].some(
4133
- (directory) => fileExists((0, import_node_path15.join)(workspaceRoot, directory, short ?? name, "package.json"))
4560
+ (directory) => fileExists((0, import_node_path16.join)(workspaceRoot, directory, short ?? name, "package.json"))
4134
4561
  );
4135
4562
  }
4136
4563
  function isAliasedInstall(workspaceRoot, name) {
4137
4564
  try {
4138
4565
  const installed = readJson(
4139
- (0, import_node_path15.join)(workspaceRoot, "node_modules", name, "package.json")
4566
+ (0, import_node_path16.join)(workspaceRoot, "node_modules", name, "package.json")
4140
4567
  );
4141
4568
  return installed.name !== void 0 && installed.name !== name;
4142
4569
  } catch {
@@ -4147,14 +4574,14 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
4147
4574
  if (ecosystem === "npm") {
4148
4575
  try {
4149
4576
  return readJson(
4150
- (0, import_node_path15.join)(workspaceRoot, "node_modules", name, "package.json")
4577
+ (0, import_node_path16.join)(workspaceRoot, "node_modules", name, "package.json")
4151
4578
  ).version;
4152
4579
  } catch {
4153
4580
  return void 0;
4154
4581
  }
4155
4582
  }
4156
4583
  if (ecosystem === "pub") {
4157
- const lockPath = (0, import_node_path15.join)(workspaceRoot, "pubspec.lock");
4584
+ const lockPath = (0, import_node_path16.join)(workspaceRoot, "pubspec.lock");
4158
4585
  if (!fileExists(lockPath)) {
4159
4586
  return void 0;
4160
4587
  }
@@ -4162,7 +4589,7 @@ function resolvedVersion(workspaceRoot, ecosystem, name) {
4162
4589
  const match = new RegExp(
4163
4590
  String.raw`^\s{2}${escapeForRegex(name)}:[^]*?^\s+version:\s*["']?([^"'\s]+)`,
4164
4591
  "m"
4165
- ).exec((0, import_node_fs11.readFileSync)(lockPath, "utf8"));
4592
+ ).exec((0, import_node_fs12.readFileSync)(lockPath, "utf8"));
4166
4593
  return match?.[1];
4167
4594
  } catch {
4168
4595
  return void 0;
@@ -4354,7 +4781,7 @@ function describe(finding) {
4354
4781
  return `${finding.name} \u2192 ${finding.target} (${finding.reason}); disagreeing: ${sites}`;
4355
4782
  }
4356
4783
  function runSync(workspaceRoot, options) {
4357
- if (!fileExists((0, import_node_path16.join)(workspaceRoot, "nx.json"))) {
4784
+ if (!fileExists((0, import_node_path17.join)(workspaceRoot, "nx.json"))) {
4358
4785
  throw new Error(
4359
4786
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci sync' from the workspace root.`
4360
4787
  );
@@ -4404,7 +4831,7 @@ function runSync(workspaceRoot, options) {
4404
4831
  }
4405
4832
 
4406
4833
  // src/dependency-management/update-dependencies.use-case.ts
4407
- var import_node_path17 = require("path");
4834
+ var import_node_path18 = require("path");
4408
4835
  var import_prompts2 = require("@inquirer/prompts");
4409
4836
 
4410
4837
  // src/dependency-management/registry.client.ts
@@ -4687,7 +5114,7 @@ function reinstall(workspaceRoot, ecosystems) {
4687
5114
  function hasPythonInstallScript(workspaceRoot) {
4688
5115
  try {
4689
5116
  const manifest = readJson(
4690
- (0, import_node_path17.join)(workspaceRoot, "package.json")
5117
+ (0, import_node_path18.join)(workspaceRoot, "package.json")
4691
5118
  );
4692
5119
  return manifest.scripts?.["python:install"] !== void 0;
4693
5120
  } catch {
@@ -4703,7 +5130,7 @@ function applyGoUpdates(workspaceRoot, entries) {
4703
5130
  }
4704
5131
  }
4705
5132
  async function runUp(workspaceRoot, options) {
4706
- if (!fileExists((0, import_node_path17.join)(workspaceRoot, "nx.json"))) {
5133
+ if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
4707
5134
  throw new Error(`No nx.json found in ${workspaceRoot} \u2014 run 'mnci up' from the workspace root.`);
4708
5135
  }
4709
5136
  const ecosystems = resolveEcosystems(options.ecosystem);
@@ -4774,11 +5201,12 @@ var PROJECT_KINDS = [
4774
5201
  "csharp-app",
4775
5202
  "csharp-function-app",
4776
5203
  "csharp-lib",
4777
- "csharp-internal-lib"
5204
+ "csharp-internal-lib",
5205
+ "vscode-extension"
4778
5206
  ];
4779
5207
  async function runAdd(kind, name, options) {
4780
5208
  const workspaceRoot = process.cwd();
4781
- if (!fileExists((0, import_node_path18.join)(workspaceRoot, "nx.json"))) {
5209
+ if (!fileExists((0, import_node_path19.join)(workspaceRoot, "nx.json"))) {
4782
5210
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
4783
5211
  }
4784
5212
  const stack = readWorkspaceStack(workspaceRoot);
@@ -4829,8 +5257,8 @@ async function runAdd(kind, name, options) {
4829
5257
  ],
4830
5258
  workspaceRoot
4831
5259
  );
4832
- markPrivate((0, import_node_path18.join)(workspaceRoot, "libs", resolvedName, "package.json"));
4833
- renameScaffoldPlaceholder((0, import_node_path18.join)(workspaceRoot, "libs", resolvedName), resolvedName);
5260
+ markPrivate((0, import_node_path19.join)(workspaceRoot, "libs", resolvedName, "package.json"));
5261
+ renameScaffoldPlaceholder((0, import_node_path19.join)(workspaceRoot, "libs", resolvedName), resolvedName);
4834
5262
  removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
4835
5263
  registerProjectCommands(workspaceRoot, resolvedName, { build: true });
4836
5264
  break;
@@ -4895,6 +5323,13 @@ async function runAdd(kind, name, options) {
4895
5323
  addCsharpInternalLib(workspaceRoot, resolvedName);
4896
5324
  break;
4897
5325
  }
5326
+ case "vscode-extension": {
5327
+ addVscodeExtension(workspaceRoot, resolvedName, stack, {
5328
+ publisher: options.publisher,
5329
+ sidecar: options.sidecar
5330
+ });
5331
+ break;
5332
+ }
4898
5333
  case "python-vendor": {
4899
5334
  await addPythonVendor(workspaceRoot, resolvedName, options, kindProvided);
4900
5335
  syncProjectReferences(workspaceRoot);
@@ -4915,7 +5350,7 @@ async function runAdd(kind, name, options) {
4915
5350
  }
4916
5351
  function readWorkspaceStack(workspaceRoot) {
4917
5352
  const nxJson = readJson(
4918
- (0, import_node_path18.join)(workspaceRoot, "nx.json")
5353
+ (0, import_node_path19.join)(workspaceRoot, "nx.json")
4919
5354
  );
4920
5355
  const stack = nxJson.mnci?.stack;
4921
5356
  return {
@@ -4924,15 +5359,15 @@ function readWorkspaceStack(workspaceRoot) {
4924
5359
  }
4925
5360
 
4926
5361
  // src/workspace-diagnostics/check-invariants.use-case.ts
4927
- var import_node_fs12 = require("fs");
4928
- var import_node_path19 = require("path");
5362
+ var import_node_fs13 = require("fs");
5363
+ var import_node_path20 = require("path");
4929
5364
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
4930
5365
  function toPosix2(path) {
4931
5366
  return path.replaceAll("\\", "/");
4932
5367
  }
4933
5368
  function checkEslintConfigs(workspaceRoot) {
4934
- const rootConfigs = (0, import_node_fs12.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
4935
- const projectConfigs = (0, import_node_fs12.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
5369
+ const rootConfigs = (0, import_node_fs13.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
5370
+ const projectConfigs = (0, import_node_fs13.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
4936
5371
  cwd: workspaceRoot
4937
5372
  }).map((config) => toPosix2(config));
4938
5373
  return [
@@ -4952,10 +5387,10 @@ function checkEslintConfigs(workspaceRoot) {
4952
5387
  ];
4953
5388
  }
4954
5389
  function checkEslintEntryPointReachesTheRules(workspaceRoot) {
4955
- const rules = (0, import_node_path19.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
4956
- if (!(0, import_node_fs12.existsSync)(rules)) return [];
4957
- const entryPoint = (0, import_node_path19.join)(workspaceRoot, ESLINT_USER_FILENAME);
4958
- const source = (0, import_node_fs12.existsSync)(entryPoint) ? (0, import_node_fs12.readFileSync)(entryPoint, "utf8") : "";
5390
+ const rules = (0, import_node_path20.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
5391
+ if (!(0, import_node_fs13.existsSync)(rules)) return [];
5392
+ const entryPoint = (0, import_node_path20.join)(workspaceRoot, ESLINT_USER_FILENAME);
5393
+ const source = (0, import_node_fs13.existsSync)(entryPoint) ? (0, import_node_fs13.readFileSync)(entryPoint, "utf8") : "";
4959
5394
  return [
4960
5395
  {
4961
5396
  check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
@@ -4968,7 +5403,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
4968
5403
  function declaredDevDependencies(workspaceRoot) {
4969
5404
  try {
4970
5405
  const manifest = readJson(
4971
- (0, import_node_path19.join)(workspaceRoot, "package.json")
5406
+ (0, import_node_path20.join)(workspaceRoot, "package.json")
4972
5407
  );
4973
5408
  return manifest.devDependencies ?? {};
4974
5409
  } catch {
@@ -4976,7 +5411,7 @@ function declaredDevDependencies(workspaceRoot) {
4976
5411
  }
4977
5412
  }
4978
5413
  function checkNoRetiredFormatter(workspaceRoot) {
4979
- const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path19.join)(workspaceRoot, file)));
5414
+ const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path20.join)(workspaceRoot, file)));
4980
5415
  const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
4981
5416
  const stale = [...files, ...declared];
4982
5417
  if (stale.length === 0) {
@@ -5002,7 +5437,7 @@ function checkEslintPlugin(nxJson) {
5002
5437
  };
5003
5438
  }
5004
5439
  function checkResolvedEslint(workspaceRoot) {
5005
- const manifestPath = (0, import_node_path19.join)(workspaceRoot, "node_modules/eslint/package.json");
5440
+ const manifestPath = (0, import_node_path20.join)(workspaceRoot, "node_modules/eslint/package.json");
5006
5441
  if (!fileExists(manifestPath)) {
5007
5442
  return void 0;
5008
5443
  }
@@ -5020,11 +5455,11 @@ function checkResolvedEslint(workspaceRoot) {
5020
5455
  }
5021
5456
  }
5022
5457
  function checkNpmrc(workspaceRoot, registry, scope) {
5023
- const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
5458
+ const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5024
5459
  if (!registry || !fileExists(npmrcPath)) {
5025
5460
  return void 0;
5026
5461
  }
5027
- const npmrc = (0, import_node_fs12.readFileSync)(npmrcPath, "utf8");
5462
+ const npmrc = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8");
5028
5463
  if (registry.kind === "npm") {
5029
5464
  return {
5030
5465
  check: ".npmrc authenticates the public registry",
@@ -5041,11 +5476,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
5041
5476
  };
5042
5477
  }
5043
5478
  function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
5044
- const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
5479
+ const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5045
5480
  if (!fileExists(npmrcPath)) {
5046
5481
  return void 0;
5047
5482
  }
5048
- const npmrc = (0, import_node_fs12.readFileSync)(npmrcPath, "utf8");
5483
+ const npmrc = (0, import_node_fs13.readFileSync)(npmrcPath, "utf8");
5049
5484
  const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
5050
5485
  const referenced = [
5051
5486
  ...new Set(
@@ -5069,13 +5504,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
5069
5504
  };
5070
5505
  }
5071
5506
  function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
5072
- const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
5073
- const pipelinePath = (0, import_node_path19.join)(workspaceRoot, "azure-pipelines.yml");
5507
+ const npmrcPath = (0, import_node_path20.join)(workspaceRoot, ".npmrc");
5508
+ const pipelinePath = (0, import_node_path20.join)(workspaceRoot, "azure-pipelines.yml");
5074
5509
  if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
5075
5510
  return void 0;
5076
5511
  }
5077
- 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));
5078
- const runsTask = (0, import_node_fs12.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
5512
+ 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));
5513
+ const runsTask = (0, import_node_fs13.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
5079
5514
  if (!holdsCredentials && !runsTask) {
5080
5515
  return {
5081
5516
  check: "npm auth: .npmrc and azure-pipelines.yml agree",
@@ -5120,13 +5555,13 @@ function npmjsCredentialShape(credentials, environment) {
5120
5555
  }
5121
5556
  function checkVersionActions(workspaceRoot) {
5122
5557
  const candidates = [
5123
- ...(0, import_node_fs12.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
5124
- ...(0, import_node_fs12.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
5125
- ...(0, import_node_fs12.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
5558
+ ...(0, import_node_fs13.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
5559
+ ...(0, import_node_fs13.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
5560
+ ...(0, import_node_fs13.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
5126
5561
  ].map((manifest) => toPosix2(manifest));
5127
5562
  return candidates.flatMap((manifest) => {
5128
5563
  const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
5129
- const projectJsonPath = (0, import_node_path19.join)(workspaceRoot, projectRoot, "project.json");
5564
+ const projectJsonPath = (0, import_node_path20.join)(workspaceRoot, projectRoot, "project.json");
5130
5565
  let hasOverride = false;
5131
5566
  try {
5132
5567
  const projectJson = readJson(projectJsonPath);
@@ -5155,7 +5590,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
5155
5590
  ]) {
5156
5591
  try {
5157
5592
  const targets = extract(
5158
- readJson((0, import_node_path19.join)(workspaceRoot, projectRoot, file))
5593
+ readJson((0, import_node_path20.join)(workspaceRoot, projectRoot, file))
5159
5594
  );
5160
5595
  if (targets && typeof targets === "object") {
5161
5596
  sources.push({
@@ -5171,8 +5606,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
5171
5606
  function checkTargetFilesExist(workspaceRoot) {
5172
5607
  const projectRoots = new Set(
5173
5608
  [
5174
- ...(0, import_node_fs12.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
5175
- ...(0, import_node_fs12.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
5609
+ ...(0, import_node_fs13.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
5610
+ ...(0, import_node_fs13.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
5176
5611
  ].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
5177
5612
  );
5178
5613
  return [...projectRoots].flatMap(
@@ -5187,7 +5622,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
5187
5622
  return TARGET_FILE_OPTIONS.flatMap((option) => {
5188
5623
  const value = target?.options?.[option];
5189
5624
  const checkable = typeof value === "string" && !value.includes("{");
5190
- if (!checkable || fileExists((0, import_node_path19.join)(workspaceRoot, value))) {
5625
+ if (!checkable || fileExists((0, import_node_path20.join)(workspaceRoot, value))) {
5191
5626
  return [];
5192
5627
  }
5193
5628
  return [
@@ -5209,7 +5644,7 @@ function checkSync(workspaceRoot) {
5209
5644
  };
5210
5645
  }
5211
5646
  function checkNoRootRuntimeDependencies(workspaceRoot) {
5212
- const manifestPath = (0, import_node_path19.join)(workspaceRoot, "package.json");
5647
+ const manifestPath = (0, import_node_path20.join)(workspaceRoot, "package.json");
5213
5648
  if (!fileExists(manifestPath)) {
5214
5649
  return void 0;
5215
5650
  }
@@ -5229,14 +5664,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
5229
5664
  };
5230
5665
  }
5231
5666
  function checkRollupSourceMaps(workspaceRoot) {
5232
- const configs = (0, import_node_fs12.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5667
+ const configs = (0, import_node_fs13.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5233
5668
  cwd: workspaceRoot
5234
5669
  }).map((config) => toPosix2(config));
5235
5670
  return configs.flatMap((relativePath) => {
5236
- const configPath = (0, import_node_path19.join)(workspaceRoot, relativePath);
5671
+ const configPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
5237
5672
  let config;
5238
5673
  try {
5239
- config = (0, import_node_fs12.readFileSync)(configPath, "utf8");
5674
+ config = (0, import_node_fs13.readFileSync)(configPath, "utf8");
5240
5675
  } catch {
5241
5676
  return [];
5242
5677
  }
@@ -5251,11 +5686,11 @@ function checkRollupSourceMaps(workspaceRoot) {
5251
5686
  });
5252
5687
  }
5253
5688
  function checkDeclarationSpecifiers(workspaceRoot) {
5254
- const configs = (0, import_node_fs12.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5689
+ const configs = (0, import_node_fs13.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
5255
5690
  cwd: workspaceRoot
5256
5691
  }).map((config) => toPosix2(config));
5257
5692
  return configs.flatMap((relativePath) => {
5258
- const configPath = (0, import_node_path19.join)(workspaceRoot, relativePath);
5693
+ const configPath = (0, import_node_path20.join)(workspaceRoot, relativePath);
5259
5694
  if (!fileExists(configPath)) {
5260
5695
  return [];
5261
5696
  }
@@ -5289,7 +5724,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
5289
5724
  });
5290
5725
  }
5291
5726
  function collectFindings(workspaceRoot) {
5292
- const nxJsonPath = (0, import_node_path19.join)(workspaceRoot, "nx.json");
5727
+ const nxJsonPath = (0, import_node_path20.join)(workspaceRoot, "nx.json");
5293
5728
  if (!fileExists(nxJsonPath)) {
5294
5729
  throw new Error(
5295
5730
  `No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
@@ -5334,8 +5769,8 @@ function runDoctor(workspaceRoot) {
5334
5769
  }
5335
5770
 
5336
5771
  // src/workspace-creation/adopt-directory.use-case.ts
5337
- var import_node_fs13 = require("fs");
5338
- var import_node_path20 = require("path");
5772
+ var import_node_fs14 = require("fs");
5773
+ var import_node_path21 = require("path");
5339
5774
  var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
5340
5775
  var AGENT_AND_CI_ENTRIES = [
5341
5776
  "AGENTS.md",
@@ -5366,13 +5801,13 @@ var PREFLIGHT_BLOCKERS = [
5366
5801
  "packages"
5367
5802
  ];
5368
5803
  function assertAdoptableDirectory(target) {
5369
- if (!(0, import_node_fs13.existsSync)(target)) {
5804
+ if (!(0, import_node_fs14.existsSync)(target)) {
5370
5805
  throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
5371
5806
  }
5372
- if (!(0, import_node_fs13.statSync)(target).isDirectory()) {
5807
+ if (!(0, import_node_fs14.statSync)(target).isDirectory()) {
5373
5808
  throw new Error(`--into '${target}' is not a directory.`);
5374
5809
  }
5375
- const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)));
5810
+ const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs14.existsSync)((0, import_node_path21.join)(target, entry)));
5376
5811
  if (blockers.length > 0) {
5377
5812
  throw new Error(
5378
5813
  `--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.`
@@ -5380,15 +5815,15 @@ function assertAdoptableDirectory(target) {
5380
5815
  }
5381
5816
  }
5382
5817
  function mergeGitignore(generatedFile, targetFile) {
5383
- const existing = (0, import_node_fs13.readFileSync)(targetFile, "utf8");
5818
+ const existing = (0, import_node_fs14.readFileSync)(targetFile, "utf8");
5384
5819
  const present = new Set(existing.split("\n").map((line) => line.trim()));
5385
- const additions = (0, import_node_fs13.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
5820
+ const additions = (0, import_node_fs14.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
5386
5821
  const trimmed = line.trim();
5387
5822
  return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
5388
5823
  });
5389
5824
  if (additions.length === 0) return false;
5390
5825
  const separator = existing.endsWith("\n") ? "" : "\n";
5391
- (0, import_node_fs13.writeFileSync)(
5826
+ (0, import_node_fs14.writeFileSync)(
5392
5827
  targetFile,
5393
5828
  `${existing}${separator}
5394
5829
  # Added by mnci (Nx workspace)
@@ -5398,9 +5833,9 @@ ${additions.join("\n")}
5398
5833
  return true;
5399
5834
  }
5400
5835
  function adoptGeneratedWorkspace(generatedRoot, target) {
5401
- const entries = (0, import_node_fs13.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
5836
+ const entries = (0, import_node_fs14.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
5402
5837
  const collisions = entries.filter(
5403
- (entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
5838
+ (entry) => (0, import_node_fs14.existsSync)((0, import_node_path21.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
5404
5839
  );
5405
5840
  if (collisions.length > 0) {
5406
5841
  throw new Error(
@@ -5409,28 +5844,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
5409
5844
  }
5410
5845
  const result = { copied: [], kept: [], mergedGitignore: false };
5411
5846
  for (const entry of entries) {
5412
- const from = (0, import_node_path20.join)(generatedRoot, entry);
5413
- const to = (0, import_node_path20.join)(target, entry);
5414
- if (entry === ".gitignore" && (0, import_node_fs13.existsSync)(to)) {
5847
+ const from = (0, import_node_path21.join)(generatedRoot, entry);
5848
+ const to = (0, import_node_path21.join)(target, entry);
5849
+ if (entry === ".gitignore" && (0, import_node_fs14.existsSync)(to)) {
5415
5850
  result.mergedGitignore = mergeGitignore(from, to);
5416
5851
  result.kept.push(entry);
5417
5852
  continue;
5418
5853
  }
5419
- if ((0, import_node_fs13.existsSync)(to)) {
5854
+ if ((0, import_node_fs14.existsSync)(to)) {
5420
5855
  result.kept.push(entry);
5421
5856
  continue;
5422
5857
  }
5423
- (0, import_node_fs13.cpSync)(from, to, { recursive: true });
5858
+ (0, import_node_fs14.cpSync)(from, to, { recursive: true });
5424
5859
  result.copied.push(entry);
5425
5860
  }
5426
- (0, import_node_fs13.rmSync)(generatedRoot, { recursive: true, force: true });
5861
+ (0, import_node_fs14.rmSync)(generatedRoot, { recursive: true, force: true });
5427
5862
  return result;
5428
5863
  }
5429
5864
 
5430
5865
  // src/workspace-creation/create-workspace.use-case.ts
5431
- var import_node_fs14 = require("fs");
5866
+ var import_node_fs15 = require("fs");
5432
5867
  var import_node_os = require("os");
5433
- var import_node_path21 = require("path");
5868
+ var import_node_path22 = require("path");
5434
5869
  function nxCloudProviderValue(ci) {
5435
5870
  return ci === "azure" ? "azure" : "github";
5436
5871
  }
@@ -5466,9 +5901,9 @@ async function resolveRegistry(options) {
5466
5901
  return await promptRegistry();
5467
5902
  }
5468
5903
  async function runNew(name, options) {
5469
- const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path21.resolve)(process.cwd(), options.into);
5904
+ const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path22.resolve)(process.cwd(), options.into);
5470
5905
  if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
5471
- const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path21.basename)(adoptTarget));
5906
+ const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path22.basename)(adoptTarget));
5472
5907
  assertValidProjectName(workspaceName, "Workspace name");
5473
5908
  const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
5474
5909
  const registry = await resolveRegistry(options);
@@ -5481,8 +5916,8 @@ async function runNew(name, options) {
5481
5916
  const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
5482
5917
  const stack = await resolveStack(options);
5483
5918
  const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
5484
- const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs14.mkdtempSync)((0, import_node_path21.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
5485
- let workspaceRoot = (0, import_node_path21.join)(stagingParent, workspaceName);
5919
+ const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs15.mkdtempSync)((0, import_node_path22.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
5920
+ let workspaceRoot = (0, import_node_path22.join)(stagingParent, workspaceName);
5486
5921
  try {
5487
5922
  logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
5488
5923
  runNpx(
@@ -5505,7 +5940,7 @@ async function runNew(name, options) {
5505
5940
  workspaceRoot = adoptTarget;
5506
5941
  }
5507
5942
  } finally {
5508
- if (adoptTarget !== void 0) (0, import_node_fs14.rmSync)(stagingParent, { recursive: true, force: true });
5943
+ if (adoptTarget !== void 0) (0, import_node_fs15.rmSync)(stagingParent, { recursive: true, force: true });
5509
5944
  }
5510
5945
  logger.step(
5511
5946
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
@@ -5515,8 +5950,8 @@ async function runNew(name, options) {
5515
5950
  { workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
5516
5951
  logger.detail
5517
5952
  );
5518
- (0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
5519
- (0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "package-lock.json"), { force: true });
5953
+ (0, import_node_fs15.rmSync)((0, import_node_path22.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
5954
+ (0, import_node_fs15.rmSync)((0, import_node_path22.join)(workspaceRoot, "package-lock.json"), { force: true });
5520
5955
  logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
5521
5956
  const installStatus = runShell(
5522
5957
  "npm",
@@ -5540,18 +5975,19 @@ async function runNew(name, options) {
5540
5975
  " # go-app, go-function-app, go-lib, go-internal-lib,"
5541
5976
  );
5542
5977
  logger.info(
5543
- " # flutter-app, flutter-lib, flutter-internal-lib"
5978
+ " # flutter-app, flutter-lib, flutter-internal-lib,"
5544
5979
  );
5980
+ logger.info(" # vscode-extension");
5545
5981
  logger.info(' git add -A && git commit -m "feat: initial workspace"');
5546
5982
  }
5547
5983
 
5548
5984
  // src/workspace-creation/interactive-wizard.use-case.ts
5549
- var import_node_path23 = require("path");
5985
+ var import_node_path24 = require("path");
5550
5986
  var import_prompts4 = require("@inquirer/prompts");
5551
5987
 
5552
5988
  // src/workspace-upgrade/upgrade-workspace.use-case.ts
5553
- var import_node_fs15 = require("fs");
5554
- var import_node_path22 = require("path");
5989
+ var import_node_fs16 = require("fs");
5990
+ var import_node_path23 = require("path");
5555
5991
  function resolveRegistry2(options, persisted) {
5556
5992
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
5557
5993
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -5580,7 +6016,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
5580
6016
  return persisted.workspaceName;
5581
6017
  }
5582
6018
  try {
5583
- const existing = (0, import_node_fs15.readdirSync)(workspaceRoot).find(
6019
+ const existing = (0, import_node_fs16.readdirSync)(workspaceRoot).find(
5584
6020
  (file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
5585
6021
  );
5586
6022
  if (existing) {
@@ -5588,11 +6024,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
5588
6024
  }
5589
6025
  } catch {
5590
6026
  }
5591
- return (0, import_node_path22.basename)(workspaceRoot);
6027
+ return (0, import_node_path23.basename)(workspaceRoot);
5592
6028
  }
5593
6029
  function detectNpmAuth(workspaceRoot) {
5594
6030
  try {
5595
- return (0, import_node_fs15.readFileSync)((0, import_node_path22.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
6031
+ return (0, import_node_fs16.readFileSync)((0, import_node_path23.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
5596
6032
  } catch {
5597
6033
  return void 0;
5598
6034
  }
@@ -5639,7 +6075,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
5639
6075
  };
5640
6076
  }
5641
6077
  function runUpgrade(workspaceRoot, options) {
5642
- if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
6078
+ if (!fileExists((0, import_node_path23.join)(workspaceRoot, "nx.json"))) {
5643
6079
  throw new Error(
5644
6080
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
5645
6081
  );
@@ -5662,6 +6098,17 @@ function runUpgrade(workspaceRoot, options) {
5662
6098
  logger.detail(`updated ${path}`);
5663
6099
  }
5664
6100
  }
6101
+ const goApps = addGoPlatformTargets(workspaceRoot);
6102
+ if (goApps.length > 0) {
6103
+ logger.step("Adding the six-platform build to Go apps (build-all, package-all)");
6104
+ for (const path of goApps) {
6105
+ logger.detail(`updated ${path}`);
6106
+ }
6107
+ }
6108
+ if (refreshVscodeExtensionScript(workspaceRoot)) {
6109
+ logger.step("Updating the VS Code extension packaging script");
6110
+ logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
6111
+ }
5665
6112
  const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
5666
6113
  if (upgradedDtsPlugins.length > 0) {
5667
6114
  logger.step("Upgrading declaration specifiers to resolve under nodenext");
@@ -5678,7 +6125,7 @@ function runUpgrade(workspaceRoot, options) {
5678
6125
 
5679
6126
  // src/workspace-creation/interactive-wizard.use-case.ts
5680
6127
  async function runInteractive() {
5681
- const inWorkspace = fileExists((0, import_node_path23.join)(process.cwd(), "nx.json"));
6128
+ const inWorkspace = fileExists((0, import_node_path24.join)(process.cwd(), "nx.json"));
5682
6129
  const choiceNew = { name: "Create a new monorepo", value: "new" };
5683
6130
  const choiceAdd = { name: "Add a project to this workspace", value: "add" };
5684
6131
  const choiceUpgrade = {
@@ -5699,8 +6146,8 @@ async function runInteractive() {
5699
6146
  }
5700
6147
 
5701
6148
  // src/cli-version/check-for-update.use-case.ts
5702
- var import_node_fs16 = require("fs");
5703
- var import_node_path24 = require("path");
6149
+ var import_node_fs17 = require("fs");
6150
+ var import_node_path25 = require("path");
5704
6151
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
5705
6152
  var PACKAGE_NAME = "@mnci/cli";
5706
6153
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -5756,8 +6203,8 @@ function releaseTriple(version) {
5756
6203
  }
5757
6204
  function readCliVersion(packageDirectory) {
5758
6205
  try {
5759
- const manifestPath = (0, import_node_path24.join)(packageDirectory, "..", "package.json");
5760
- const manifest = JSON.parse((0, import_node_fs16.readFileSync)(manifestPath, "utf8"));
6206
+ const manifestPath = (0, import_node_path25.join)(packageDirectory, "..", "package.json");
6207
+ const manifest = JSON.parse((0, import_node_fs17.readFileSync)(manifestPath, "utf8"));
5761
6208
  return manifest.version ?? "0.0.0";
5762
6209
  } catch {
5763
6210
  return "0.0.0";
@@ -5812,6 +6259,12 @@ function buildProgram(cliVersion) {
5812
6259
  ).option(
5813
6260
  "--lib <name>",
5814
6261
  "python-vendor only: the internal Python library (libs/<name>) to vendor into <name>"
6262
+ ).option(
6263
+ "--publisher <id>",
6264
+ "vscode-extension only: the Marketplace publisher id (defaults to the workspace scope without @)"
6265
+ ).option(
6266
+ "--sidecar <go-app>",
6267
+ "vscode-extension only: a go-app whose six-platform build ships in the extension, one .vsix per platform"
5815
6268
  ).action(
5816
6269
  async (kind, name, options) => {
5817
6270
  await runAdd(kind, name, options);