create-nx-workspace 22.2.0-beta.1 → 22.2.0-beta.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"create-nx-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/bin/create-nx-workspace.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-nx-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/bin/create-nx-workspace.ts"],"names":[],"mappings":"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"}
@@ -130,9 +130,10 @@ exports.commandsObject = yargs
130
130
  await main(argv).catch((error) => {
131
131
  const { version } = require('../package.json');
132
132
  output_1.output.error({
133
- title: `Something went wrong! v${version}`,
133
+ title: `Failed to create workspace (v${version})`,
134
+ bodyLines: (0, error_utils_1.mapErrorToBodyLines)(error),
134
135
  });
135
- throw error;
136
+ process.exit(1);
136
137
  });
137
138
  }, [normalizeArgsMiddleware])
138
139
  .help('help', chalk.dim `Show help`)
@@ -159,12 +160,17 @@ async function main(parsedArgs) {
159
160
  command: 'create-nx-workspace',
160
161
  useCloud: parsedArgs.nxCloud !== 'skip',
161
162
  meta: [
163
+ // User sees one of: setupCI (preset flow) or setupNxCloudV2 (template flow)
162
164
  ab_testing_1.messages.codeOfSelectedPromptMessage('setupCI'),
163
- ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloud'),
165
+ // User sees one of: setupNxCloud (preset flow) or setupNxCloudV2 (template flow)
166
+ ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloudV2') ||
167
+ ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloud'),
164
168
  parsedArgs.nxCloud,
165
169
  rawArgs.nxCloud,
166
170
  workspaceInfo.pushedToVcs,
171
+ `flow-variant-${(0, ab_testing_1.getFlowVariant)()}`,
167
172
  ],
173
+ directory: workspaceInfo.directory,
168
174
  });
169
175
  if (parsedArgs.nxCloud && workspaceInfo.nxCloudInfo) {
170
176
  process.stdout.write(workspaceInfo.nxCloudInfo);
@@ -188,53 +194,78 @@ async function normalizeArgsMiddleware(argv) {
188
194
  output_1.output.log({
189
195
  title: "Let's create a new workspace [https://nx.dev/getting-started/intro]",
190
196
  });
191
- // Record stat for initial invocation before any prompts
192
- await (0, ab_testing_1.recordStat)({
193
- nxVersion: nx_version_1.nxVersion,
194
- command: 'create-nx-workspace',
195
- meta: ['start'],
196
- useCloud: argv.nxCloud !== 'skip',
197
- });
198
197
  argv.workspaces ??= true;
199
198
  argv.useProjectJson ??= !argv.workspaces;
200
199
  try {
201
200
  argv.name = await determineFolder(argv);
202
- if (!argv.preset || (0, preset_1.isKnownPreset)(argv.preset)) {
203
- argv.stack = await determineStack(argv);
204
- const presetOptions = await determinePresetOptions(argv);
205
- Object.assign(argv, presetOptions);
201
+ const workingDir = process.cwd().replace(/\\/g, '/');
202
+ const directory = require('path').join(workingDir, argv.name);
203
+ const template = await (0, prompts_1.determineTemplate)(argv);
204
+ // Old (start) vs new (start-v2) flows
205
+ const startPrefix = (0, ab_testing_1.getFlowVariant)() === '1' ? 'start-v2' : 'start';
206
+ await (0, ab_testing_1.recordStat)({
207
+ nxVersion: nx_version_1.nxVersion,
208
+ command: 'create-nx-workspace',
209
+ meta: [startPrefix],
210
+ useCloud: argv.nxCloud !== 'skip',
211
+ directory,
212
+ });
213
+ if (template !== 'custom') {
214
+ // Template flow - uses npm and 'main' branch by default
215
+ argv.template = template;
216
+ const aiAgents = await (0, prompts_1.determineAiAgents)(argv);
217
+ const nxCloud = argv.skipGit === true ? 'skip' : await (0, prompts_1.determineNxCloudV2)(argv);
218
+ const completionMessageKey = nxCloud === 'skip'
219
+ ? undefined
220
+ : ab_testing_1.messages.completionMessageOfSelectedPrompt('setupNxCloudV2');
221
+ Object.assign(argv, {
222
+ nxCloud,
223
+ useGitHub: nxCloud !== 'skip',
224
+ completionMessageKey,
225
+ packageManager: 'npm',
226
+ defaultBase: 'main',
227
+ aiAgents,
228
+ });
206
229
  }
207
230
  else {
208
- try {
209
- (0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(argv.preset);
231
+ // Preset flow - existing behavior
232
+ if (!argv.preset || (0, preset_1.isKnownPreset)(argv.preset)) {
233
+ argv.stack = await determineStack(argv);
234
+ const presetOptions = await determinePresetOptions(argv);
235
+ Object.assign(argv, presetOptions);
210
236
  }
211
- catch (e) {
212
- if (e instanceof Error) {
213
- output_1.output.error({
214
- title: `Could not find preset "${argv.preset}"`,
215
- bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
216
- });
237
+ else {
238
+ try {
239
+ (0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(argv.preset);
217
240
  }
218
- else {
219
- console.error(e);
241
+ catch (e) {
242
+ if (e instanceof Error) {
243
+ output_1.output.error({
244
+ title: `Could not find preset "${argv.preset}"`,
245
+ bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
246
+ });
247
+ }
248
+ else {
249
+ console.error(e);
250
+ }
251
+ process.exit(1);
220
252
  }
221
- process.exit(1);
222
253
  }
254
+ const packageManager = await (0, prompts_1.determinePackageManager)(argv);
255
+ const aiAgents = await (0, prompts_1.determineAiAgents)(argv);
256
+ const defaultBase = await (0, prompts_1.determineDefaultBase)(argv);
257
+ const nxCloud = argv.skipGit === true ? 'skip' : await (0, prompts_1.determineNxCloud)(argv);
258
+ const useGitHub = nxCloud === 'skip'
259
+ ? undefined
260
+ : nxCloud === 'github' || (await (0, prompts_1.determineIfGitHubWillBeUsed)(argv));
261
+ Object.assign(argv, {
262
+ nxCloud,
263
+ useGitHub,
264
+ packageManager,
265
+ defaultBase,
266
+ aiAgents,
267
+ });
223
268
  }
224
- const packageManager = await (0, prompts_1.determinePackageManager)(argv);
225
- const aiAgents = await (0, prompts_1.determineAiAgents)(argv);
226
- const defaultBase = await (0, prompts_1.determineDefaultBase)(argv);
227
- const nxCloud = argv.skipGit === true ? 'skip' : await (0, prompts_1.determineNxCloud)(argv);
228
- const useGitHub = nxCloud === 'skip'
229
- ? undefined
230
- : nxCloud === 'github' || (await (0, prompts_1.determineIfGitHubWillBeUsed)(argv));
231
- Object.assign(argv, {
232
- nxCloud,
233
- useGitHub,
234
- packageManager,
235
- defaultBase,
236
- aiAgents,
237
- });
238
269
  }
239
270
  catch (e) {
240
271
  console.error(e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nx-workspace",
3
- "version": "22.2.0-beta.1",
3
+ "version": "22.2.0-beta.3",
4
4
  "private": false,
5
5
  "description": "Smart Repos · Fast Builds",
6
6
  "repository": {
@@ -1,10 +1,13 @@
1
1
  import { NxCloud } from './utils/nx/nx-cloud';
2
+ import type { CompletionMessageKey } from './utils/nx/messages';
2
3
  import { PackageManager } from './utils/package-manager';
3
4
  export interface CreateWorkspaceOptions {
4
5
  name: string;
5
6
  packageManager: PackageManager;
6
7
  nxCloud: NxCloud;
7
8
  useGitHub?: boolean;
9
+ template?: string;
10
+ completionMessageKey?: CompletionMessageKey;
8
11
  /**
9
12
  * @description Enable interactive mode with presets
10
13
  * @default true
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace-options.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,eAAe,6DAMlB,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAMjD,CAAC"}
1
+ {"version":3,"file":"create-workspace-options.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,eAAe,6DAMlB,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAMjD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAGL,aAAa,EACd,MAAM,iBAAiB,CAAC;AAUzB,wBAAsB,eAAe,CAAC,CAAC,SAAS,sBAAsB,EACpE,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,CAAC;;;;GAsGZ;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D"}
1
+ {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAGL,aAAa,EACd,MAAM,iBAAiB,CAAC;AAczB,wBAAsB,eAAe,CAAC,CAAC,SAAS,sBAAsB,EACpE,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,CAAC;;;;GAwJZ;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createWorkspace = createWorkspace;
4
4
  exports.extractConnectUrl = extractConnectUrl;
5
+ const path_1 = require("path");
5
6
  const create_empty_workspace_1 = require("./create-empty-workspace");
6
7
  const create_preset_1 = require("./create-preset");
7
8
  const create_sandbox_1 = require("./create-sandbox");
@@ -12,27 +13,62 @@ const nx_cloud_1 = require("./utils/nx/nx-cloud");
12
13
  const output_1 = require("./utils/output");
13
14
  const get_third_party_preset_1 = require("./utils/preset/get-third-party-preset");
14
15
  const preset_1 = require("./utils/preset/preset");
16
+ const clone_template_1 = require("./utils/template/clone-template");
17
+ const child_process_utils_1 = require("./utils/child-process-utils");
15
18
  async function createWorkspace(preset, options, rawArgs) {
16
19
  const { packageManager, name, nxCloud, skipGit = false, defaultBase = 'main', commit, cliName, useGitHub, skipGitHubPush = false, verbose = false, } = options;
17
20
  if (cliName) {
18
21
  output_1.output.setCliName(cliName ?? 'NX');
19
22
  }
20
- const tmpDir = await (0, create_sandbox_1.createSandbox)(packageManager);
21
- const workspaceGlobs = getWorkspaceGlobsFromPreset(preset);
22
- // nx new requires a preset currently. We should probably make it optional.
23
- const directory = await (0, create_empty_workspace_1.createEmptyWorkspace)(tmpDir, name, packageManager, { ...options, preset, workspaceGlobs });
24
- // If the preset is a third-party preset, we need to call createPreset to install it
25
- // For first-party presets, it will be created by createEmptyWorkspace instead.
26
- // In createEmptyWorkspace, it will call `nx new` -> `@nx/workspace newGenerator` -> `@nx/workspace generatePreset`.
27
- const thirdPartyPackageName = (0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(preset);
28
- if (thirdPartyPackageName) {
29
- await (0, create_preset_1.createPreset)(thirdPartyPackageName, options, packageManager, directory);
23
+ let directory;
24
+ if (options.template) {
25
+ if (!options.template.startsWith('nrwl/'))
26
+ throw new Error(`Invalid template. Only templates from the 'nrwl' GitHub org are supported.`);
27
+ const templateUrl = `https://github.com/${options.template}`;
28
+ const workingDir = process.cwd().replace(/\\/g, '/');
29
+ directory = (0, path_1.join)(workingDir, name);
30
+ const ora = require('ora');
31
+ const workspaceSetupSpinner = ora(`Creating workspace from template`).start();
32
+ try {
33
+ await (0, clone_template_1.cloneTemplate)(templateUrl, name);
34
+ // Install dependencies (template flow always uses npm)
35
+ await (0, child_process_utils_1.execAndWait)('npm install --silent --ignore-scripts', directory);
36
+ workspaceSetupSpinner.succeed(`Successfully created the workspace: ${directory}`);
37
+ }
38
+ catch (e) {
39
+ workspaceSetupSpinner.fail();
40
+ throw e;
41
+ }
42
+ // Connect to Nx Cloud for template flow
43
+ if (nxCloud !== 'skip') {
44
+ await (0, nx_cloud_1.connectToNxCloudForTemplate)(directory, 'create-nx-workspace', useGitHub);
45
+ }
46
+ }
47
+ else {
48
+ // Preset flow - existing behavior
49
+ const tmpDir = await (0, create_sandbox_1.createSandbox)(packageManager);
50
+ const workspaceGlobs = getWorkspaceGlobsFromPreset(preset);
51
+ // nx new requires a preset currently. We should probably make it optional.
52
+ directory = await (0, create_empty_workspace_1.createEmptyWorkspace)(tmpDir, name, packageManager, {
53
+ ...options,
54
+ preset,
55
+ workspaceGlobs,
56
+ });
57
+ // If the preset is a third-party preset, we need to call createPreset to install it
58
+ // For first-party presets, it will be created by createEmptyWorkspace instead.
59
+ // In createEmptyWorkspace, it will call `nx new` -> `@nx/workspace newGenerator` -> `@nx/workspace generatePreset`.
60
+ const thirdPartyPackageName = (0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(preset);
61
+ if (thirdPartyPackageName) {
62
+ await (0, create_preset_1.createPreset)(thirdPartyPackageName, options, packageManager, directory);
63
+ }
30
64
  }
65
+ const isTemplate = !!options.template;
31
66
  let connectUrl;
32
67
  let nxCloudInfo;
33
68
  if (nxCloud !== 'skip') {
34
69
  const token = (0, nx_cloud_1.readNxCloudToken)(directory);
35
- if (nxCloud !== 'yes') {
70
+ // Only generate CI for preset flow (not template)
71
+ if (!isTemplate && nxCloud !== 'yes') {
36
72
  await (0, setup_ci_1.setupCI)(directory, nxCloud, packageManager);
37
73
  }
38
74
  connectUrl = await (0, nx_cloud_1.createNxCloudOnboardingUrl)(nxCloud, token, directory, useGitHub);
@@ -41,8 +77,12 @@ async function createWorkspace(preset, options, rawArgs) {
41
77
  if (!skipGit) {
42
78
  try {
43
79
  await (0, git_1.initializeGitRepo)(directory, { defaultBase, commit, connectUrl });
44
- // Push to GitHub if commit was made, GitHub push is not skipped, and CI provider is GitHub
45
- if (commit && !skipGitHubPush && nxCloud === 'github') {
80
+ // Push to GitHub if commit was made, GitHub push is not skipped, and:
81
+ // - CI provider is GitHub (preset flow), OR
82
+ // - Using template flow with Nx Cloud enabled (yes)
83
+ if (commit &&
84
+ !skipGitHubPush &&
85
+ (nxCloud === 'github' || (isTemplate && nxCloud === 'yes'))) {
46
86
  pushedToVcs = await (0, git_1.pushToGitHub)(directory, {
47
87
  skipGitHubPush,
48
88
  name,
@@ -64,7 +104,11 @@ async function createWorkspace(preset, options, rawArgs) {
64
104
  }
65
105
  }
66
106
  if (connectUrl) {
67
- nxCloudInfo = await (0, nx_cloud_1.getNxCloudInfo)(nxCloud, connectUrl, pushedToVcs, rawArgs?.nxCloud);
107
+ nxCloudInfo = await (0, nx_cloud_1.getNxCloudInfo)(connectUrl, pushedToVcs, options.completionMessageKey);
108
+ }
109
+ else if (isTemplate && nxCloud === 'skip') {
110
+ // Show nx connect message when user skips cloud in template flow
111
+ nxCloudInfo = (0, nx_cloud_1.getSkippedNxCloudInfo)();
68
112
  }
69
113
  return {
70
114
  nxCloudInfo,
@@ -5,10 +5,19 @@ import { Agent } from '../create-workspace-options';
5
5
  export declare function determineNxCloud(parsedArgs: yargs.Arguments<{
6
6
  nxCloud: NxCloud;
7
7
  }>): Promise<NxCloud>;
8
+ export declare function determineNxCloudV2(parsedArgs: yargs.Arguments<{
9
+ nxCloud?: string;
10
+ interactive?: boolean;
11
+ }>): Promise<'github' | 'skip'>;
8
12
  export declare function determineIfGitHubWillBeUsed(parsedArgs: yargs.Arguments<{
9
13
  nxCloud: NxCloud;
10
14
  useGitHub?: boolean;
11
15
  }>): Promise<boolean>;
16
+ export declare function determineTemplate(parsedArgs: yargs.Arguments<{
17
+ template?: string;
18
+ preset?: string;
19
+ interactive?: boolean;
20
+ }>): Promise<string | 'custom'>;
12
21
  export declare function determineAiAgents(parsedArgs: yargs.Arguments<{
13
22
  aiAgents?: Agent[];
14
23
  interactive?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/internal-utils/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,OAAO,EAEL,cAAc,EAEf,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EACL,KAAK,EAGN,MAAM,6BAA6B,CAAC;AAErC,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GAChD,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACrE,OAAO,CAAC,OAAO,CAAC,CAelB;AA4BD,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACzE,OAAO,CAAC,KAAK,EAAE,CAAC,CAElB;AAqBD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GACtD,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/internal-utils/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,EAEL,cAAc,EAEf,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EACL,KAAK,EAGN,MAAM,6BAA6B,CAAC;AAErC,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GAChD,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACvE,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,CAiC5B;AAED,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACrE,OAAO,CAAC,OAAO,CAAC,CAelB;AA4BD,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC,GACD,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,CA2C5B;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACzE,OAAO,CAAC,KAAK,EAAE,CAAC,CAElB;AAqBD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GACtD,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.determineNxCloud = determineNxCloud;
4
+ exports.determineNxCloudV2 = determineNxCloudV2;
4
5
  exports.determineIfGitHubWillBeUsed = determineIfGitHubWillBeUsed;
6
+ exports.determineTemplate = determineTemplate;
5
7
  exports.determineAiAgents = determineAiAgents;
6
8
  exports.determineDefaultBase = determineDefaultBase;
7
9
  exports.determinePackageManager = determinePackageManager;
@@ -25,6 +27,35 @@ async function determineNxCloud(parsedArgs) {
25
27
  return nxCloudPrompt('setupCI');
26
28
  }
27
29
  }
30
+ async function determineNxCloudV2(parsedArgs) {
31
+ // Provided via flag
32
+ if (parsedArgs.nxCloud) {
33
+ return parsedArgs.nxCloud === 'skip' ? 'skip' : 'github';
34
+ }
35
+ // Non-interactive mode
36
+ if (!parsedArgs.interactive || (0, is_ci_1.isCI)()) {
37
+ return 'skip';
38
+ }
39
+ // Show simplified prompt
40
+ const { message, choices, initial, footer, hint } = ab_testing_1.messages.getPrompt('setupNxCloudV2');
41
+ const promptConfig = {
42
+ name: 'nxCloud',
43
+ message,
44
+ type: 'autocomplete',
45
+ choices,
46
+ initial,
47
+ }; // types in enquirer are not up to date
48
+ if (footer) {
49
+ promptConfig.footer = () => footer;
50
+ }
51
+ if (hint) {
52
+ promptConfig.hint = () => hint;
53
+ }
54
+ const result = await enquirer.prompt([
55
+ promptConfig,
56
+ ]);
57
+ return result.nxCloud;
58
+ }
28
59
  async function determineIfGitHubWillBeUsed(parsedArgs) {
29
60
  if (parsedArgs.nxCloud === 'yes' || parsedArgs.nxCloud === 'circleci') {
30
61
  if (parsedArgs?.useGitHub)
@@ -64,6 +95,48 @@ async function nxCloudPrompt(key) {
64
95
  return a.NxCloud;
65
96
  });
66
97
  }
98
+ async function determineTemplate(parsedArgs) {
99
+ if (parsedArgs.template)
100
+ return parsedArgs.template;
101
+ if (parsedArgs.preset)
102
+ return 'custom';
103
+ if (!parsedArgs.interactive || (0, is_ci_1.isCI)())
104
+ return 'custom';
105
+ // A/B test: shouldUseTemplateFlow() determines if user sees template or preset flow
106
+ if (!(0, ab_testing_1.shouldUseTemplateFlow)())
107
+ return 'custom';
108
+ const { template } = await enquirer.prompt([
109
+ {
110
+ name: 'template',
111
+ message: 'Which starter do you want to use?',
112
+ type: 'autocomplete',
113
+ choices: [
114
+ {
115
+ name: 'nrwl/empty-template',
116
+ message: 'TypeScript (minimal TypeScript monorepo without projects)',
117
+ },
118
+ {
119
+ name: 'nrwl/typescript-template',
120
+ message: 'NPM Packages (monorepo with TypeScript packages ready to publish)',
121
+ },
122
+ {
123
+ name: 'nrwl/react-template',
124
+ message: 'React (fullstack monorepo with React and Express)',
125
+ },
126
+ {
127
+ name: 'nrwl/angular-template',
128
+ message: 'Angular (fullstack monorepo with Angular and Express)',
129
+ },
130
+ {
131
+ name: 'custom',
132
+ message: 'Custom (more options for frameworks, test runners, etc.)',
133
+ },
134
+ ],
135
+ initial: 0,
136
+ },
137
+ ]);
138
+ return template;
139
+ }
67
140
  async function determineAiAgents(parsedArgs) {
68
141
  return parsedArgs.aiAgents ?? [];
69
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"child-process-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/utils/child-process-utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,oBAyBxE;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,aAAa,UAAQ;UAEM,MAAM;YAAU,MAAM;GAoBlD"}
1
+ {"version":3,"file":"child-process-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/utils/child-process-utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,oBA+BxE;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,aAAa,UAAQ;UAEM,MAAM;YAAU,MAAM;GAoBlD"}
@@ -11,7 +11,12 @@ const error_utils_1 = require("./error-utils");
11
11
  */
12
12
  function spawnAndWait(command, args, cwd) {
13
13
  return new Promise((res, rej) => {
14
- const childProcess = (0, child_process_1.spawn)(command, args, {
14
+ // Combine command and args into a single string to avoid DEP0190 warning
15
+ // (passing args with shell: true is deprecated)
16
+ const fullCommand = [command, ...args]
17
+ .map((arg) => (arg.includes(' ') ? `"${arg}"` : arg))
18
+ .join(' ');
19
+ const childProcess = (0, child_process_1.spawn)(fullCommand, {
15
20
  cwd,
16
21
  stdio: 'inherit',
17
22
  env: {
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/git/git.ts"],"names":[],"mappings":"AAMA,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,UAAU,eAAe;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,KAAK,yBAAyB;gBAElC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAQ1E;AAkED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,iBAsDF;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,OAAO,CAAC,aAAa,CAAC,CAyGxB"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/git/git.ts"],"names":[],"mappings":"AAMA,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,UAAU,eAAe;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,KAAK,yBAAyB;gBAElC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAQ1E;AA0ED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,iBAsDF;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,OAAO,CAAC,aAAa,CAAC,CAuHxB"}
@@ -41,12 +41,18 @@ async function getGitHubUsername(directory) {
41
41
  }
42
42
  return username;
43
43
  }
44
+ // Module-level promise for background repo fetching
45
+ let existingReposPromise;
46
+ function populateExistingRepos(directory) {
47
+ existingReposPromise ??= getUserRepositories(directory);
48
+ }
44
49
  async function getUserRepositories(directory) {
45
50
  try {
46
51
  const allRepos = new Set();
47
52
  // Get user's personal repos and organizations concurrently
53
+ // Limit to 100 repos for faster response (covers most use cases)
48
54
  const [userRepos, orgsResult] = await Promise.all([
49
- (0, child_process_utils_1.execAndWait)('gh repo list --limit 1000 --json nameWithOwner --jq ".[].nameWithOwner"', directory),
55
+ (0, child_process_utils_1.execAndWait)('gh repo list --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"', directory),
50
56
  (0, child_process_utils_1.execAndWait)('gh api user/orgs --jq ".[].login"', directory),
51
57
  ]);
52
58
  // Add user's personal repos
@@ -63,7 +69,7 @@ async function getUserRepositories(directory) {
63
69
  // Get repos from all organizations concurrently
64
70
  const orgRepoPromises = orgs.map(async (org) => {
65
71
  try {
66
- const orgRepos = await (0, child_process_utils_1.execAndWait)(`gh repo list ${org} --limit 1000 --json nameWithOwner --jq ".[].nameWithOwner"`, directory);
72
+ const orgRepos = await (0, child_process_utils_1.execAndWait)(`gh repo list ${org} --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"`, directory);
67
73
  return orgRepos.stdout
68
74
  .trim()
69
75
  .split('\n')
@@ -134,12 +140,18 @@ async function pushToGitHub(directory, options) {
134
140
  if (process.env['NX_SKIP_GH_PUSH'] === 'true') {
135
141
  throw new GitHubPushSkippedError('NX_SKIP_GH_PUSH is true so skipping GitHub push.');
136
142
  }
143
+ // Note: This call can throw an error even if user hasn't opted in to push yet,
144
+ // which could be confusing as they haven't been asked about GitHub push at this point.
145
+ // We check gh authentication early to provide a better error message.
137
146
  const username = await getGitHubUsername(directory);
147
+ // Start fetching existing repositories in the background immediately
148
+ // This runs while user is answering prompts, so validation is usually instant
149
+ populateExistingRepos(directory);
138
150
  // First prompt: Ask if they want to push to GitHub
139
151
  const { push } = await enquirer.prompt([
140
152
  {
141
153
  name: 'push',
142
- message: 'Would you like to push this workspace to Github?',
154
+ message: 'Would you like to push this workspace to GitHub?',
143
155
  type: 'autocomplete',
144
156
  choices: [{ name: 'Yes' }, { name: 'No' }],
145
157
  initial: 0,
@@ -148,10 +160,9 @@ async function pushToGitHub(directory, options) {
148
160
  if (push !== 'Yes') {
149
161
  return VcsPushStatus.OptedOutOfPushingToVcs;
150
162
  }
151
- // Preload existing repositories for validation
152
- const existingRepos = await getUserRepositories(directory);
153
163
  // Create default repository name using the username we already have
154
164
  const defaultRepo = `${username}/${options.name}`;
165
+ const createRepoUrl = `https://github.com/new?name=${encodeURIComponent(options.name)}`;
155
166
  // Second prompt: Ask where to create the repository with validation
156
167
  const { repoName } = await enquirer.prompt([
157
168
  {
@@ -163,8 +174,10 @@ async function pushToGitHub(directory, options) {
163
174
  if (!value.includes('/')) {
164
175
  return 'Repository name must be in format: username/repo-name';
165
176
  }
166
- if (existingRepos.has(value)) {
167
- return `Repository '${value}' already exists. Please choose a different name.`;
177
+ // Wait for background fetch to complete before validating
178
+ const existingRepos = await existingReposPromise;
179
+ if (existingRepos?.has(value)) {
180
+ return `Repository '${value}' already exists. Choose a different name or create manually: ${createRepoUrl}`;
168
181
  }
169
182
  return true;
170
183
  },
@@ -172,6 +185,9 @@ async function pushToGitHub(directory, options) {
172
185
  ]);
173
186
  // Create GitHub repository using gh CLI from the workspace directory
174
187
  // This will automatically add remote origin and push the current branch
188
+ output_1.output.log({
189
+ title: 'Creating GitHub repository and pushing (this may take a moment)...',
190
+ });
175
191
  await (0, child_process_utils_1.spawnAndWait)('gh', [
176
192
  'repo',
177
193
  'create',
@@ -193,19 +209,20 @@ async function pushToGitHub(directory, options) {
193
209
  const isVerbose = options.verbose || process.env.NX_VERBOSE_LOGGING === 'true';
194
210
  const errorMessage = e instanceof Error ? e.message : String(e);
195
211
  // Error code 127 means gh wasn't installed
212
+ // GitHubPushSkippedError means user hasn't opted in or we couldn't authenticate
196
213
  const title = e instanceof GitHubPushSkippedError || e?.code === 127
197
214
  ? 'Push your workspace to GitHub.'
198
- : 'Failed to push workspace to GitHub.';
215
+ : 'Could not push. Push repo to complete setup.';
199
216
  const createRepoUrl = `https://github.com/new?name=${encodeURIComponent(options.name)}`;
200
217
  output_1.output.log({
201
218
  title,
202
219
  bodyLines: isVerbose
203
220
  ? [
204
- `Please create a repo at ${createRepoUrl} and push this workspace.`,
221
+ `Go to ${createRepoUrl} and push this workspace.`,
205
222
  'Error details:',
206
223
  errorMessage,
207
224
  ]
208
- : [`Please create a repo at ${createRepoUrl} and push this workspace.`],
225
+ : [`Go to ${createRepoUrl} and push this workspace.`],
209
226
  });
210
227
  return VcsPushStatus.FailedToPushToVcs;
211
228
  }
@@ -1,3 +1,16 @@
1
+ import type { CompletionMessageKey } from './messages';
2
+ /**
3
+ * Determines whether to use the new template flow (1) or old preset flow (0).
4
+ * - NX_CNW_FLOW_VARIANT=0 forces preset flow
5
+ * - NX_CNW_FLOW_VARIANT=1 forces template flow
6
+ * - NX_GENERATE_DOCS_PROCESS=true forces preset flow (for docs generation)
7
+ * - Otherwise, uses cached value (7 days) or randomly assigns
8
+ */
9
+ export declare function shouldUseTemplateFlow(): boolean;
10
+ /**
11
+ * Returns the flow variant for tracking (0 = preset, 1 = template).
12
+ */
13
+ export declare function getFlowVariant(): string;
1
14
  export declare const NxCloudChoices: string[];
2
15
  declare const messageOptions: Record<string, MessageData[]>;
3
16
  export type MessageKey = keyof typeof messageOptions;
@@ -15,11 +28,13 @@ interface MessageData {
15
28
  value: string;
16
29
  key: MessageKey;
17
30
  };
31
+ completionMessage: CompletionMessageKey;
18
32
  }
19
33
  export declare class PromptMessages {
20
34
  private selectedMessages;
21
35
  getPrompt(key: MessageKey): MessageData;
22
36
  codeOfSelectedPromptMessage(key: MessageKey): string;
37
+ completionMessageOfSelectedPrompt(key: MessageKey): CompletionMessageKey;
23
38
  }
24
39
  export declare const messages: PromptMessages;
25
40
  /**
@@ -31,6 +46,7 @@ export declare function recordStat(opts: {
31
46
  nxVersion: string;
32
47
  useCloud: boolean;
33
48
  meta: string[];
49
+ directory: string;
34
50
  }): Promise<void>;
35
51
  export {};
36
52
  //# sourceMappingURL=ab-testing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ab-testing.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/ab-testing.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,UAQ1B,CAAC;AAEF,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CA2CjD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,cAAc,CAAC;AACrD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,UAAU,CAAA;KAAE,CAAC;CAC/C;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,gBAAgB,CAAwC;IAEhE,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,WAAW;IAavC,2BAA2B,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM;CAQrD;AAED,eAAO,MAAM,QAAQ,gBAAuB,CAAC;AAS7C;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,iBAsBA"}
1
+ {"version":3,"file":"ab-testing.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/ab-testing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAsDvD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAO/C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAED,eAAO,MAAM,cAAc,UAQ1B,CAAC;AAEF,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAsGjD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,cAAc,CAAC;AACrD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9C,iBAAiB,EAAE,oBAAoB,CAAC;CACzC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,gBAAgB,CAAwC;IAEhE,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,WAAW;IAavC,2BAA2B,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM;IAQpD,iCAAiC,CAAC,GAAG,EAAE,UAAU,GAAG,oBAAoB;CAQzE;AAED,eAAO,MAAM,QAAQ,gBAAuB,CAAC;AAS7C;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,iBAgCA"}
@@ -1,10 +1,82 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.messages = exports.PromptMessages = exports.NxCloudChoices = void 0;
4
+ exports.shouldUseTemplateFlow = shouldUseTemplateFlow;
5
+ exports.getFlowVariant = getFlowVariant;
4
6
  exports.recordStat = recordStat;
5
7
  const node_child_process_1 = require("node:child_process");
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const node_os_1 = require("node:os");
6
11
  const is_ci_1 = require("../ci/is-ci");
7
- const package_manager_1 = require("../package-manager");
12
+ // TODO(jack): Remove flow variant logic after A/B testing is complete
13
+ const FLOW_VARIANT_CACHE_FILE = (0, node_path_1.join)((0, node_os_1.tmpdir)(), 'nx-cnw-flow-variant');
14
+ const FLOW_VARIANT_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
15
+ // In-memory cache to ensure consistency within a single run
16
+ let flowVariantCache = null;
17
+ function readCachedFlowVariant() {
18
+ try {
19
+ if (!(0, node_fs_1.existsSync)(FLOW_VARIANT_CACHE_FILE))
20
+ return null;
21
+ const stats = (0, node_fs_1.statSync)(FLOW_VARIANT_CACHE_FILE);
22
+ if (Date.now() - stats.mtimeMs > FLOW_VARIANT_EXPIRY_MS)
23
+ return null;
24
+ const value = (0, node_fs_1.readFileSync)(FLOW_VARIANT_CACHE_FILE, 'utf-8').trim();
25
+ return value === '0' || value === '1' ? value : null;
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function writeCachedFlowVariant(variant) {
32
+ try {
33
+ (0, node_fs_1.writeFileSync)(FLOW_VARIANT_CACHE_FILE, variant, 'utf-8');
34
+ }
35
+ catch {
36
+ // Ignore write errors
37
+ }
38
+ }
39
+ /**
40
+ * Internal function to determine and cache the flow variant.
41
+ */
42
+ function getFlowVariantInternal() {
43
+ if (flowVariantCache)
44
+ return flowVariantCache;
45
+ const variant = process.env.NX_CNW_FLOW_VARIANT ??
46
+ readCachedFlowVariant() ??
47
+ (Math.random() < 0.5 ? '0' : '1');
48
+ flowVariantCache = variant;
49
+ // Only write to cache if we randomly assigned a variant and no cache exists yet
50
+ // This ensures the cache expiry is based on original creation time, not last access
51
+ if (!process.env.NX_CNW_FLOW_VARIANT &&
52
+ !(0, node_fs_1.existsSync)(FLOW_VARIANT_CACHE_FILE)) {
53
+ writeCachedFlowVariant(variant);
54
+ }
55
+ return variant;
56
+ }
57
+ /**
58
+ * Determines whether to use the new template flow (1) or old preset flow (0).
59
+ * - NX_CNW_FLOW_VARIANT=0 forces preset flow
60
+ * - NX_CNW_FLOW_VARIANT=1 forces template flow
61
+ * - NX_GENERATE_DOCS_PROCESS=true forces preset flow (for docs generation)
62
+ * - Otherwise, uses cached value (7 days) or randomly assigns
63
+ */
64
+ function shouldUseTemplateFlow() {
65
+ if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
66
+ flowVariantCache = '0';
67
+ return false;
68
+ }
69
+ return getFlowVariantInternal() === '1';
70
+ }
71
+ /**
72
+ * Returns the flow variant for tracking (0 = preset, 1 = template).
73
+ */
74
+ function getFlowVariant() {
75
+ if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
76
+ return '0';
77
+ }
78
+ return flowVariantCache ?? getFlowVariantInternal();
79
+ }
8
80
  exports.NxCloudChoices = [
9
81
  'github',
10
82
  'gitlab',
@@ -33,6 +105,7 @@ const messageOptions = {
33
105
  ],
34
106
  footer: '\nSelf-healing CI, remote caching, and task distribution are provided by Nx Cloud: https://nx.dev/nx-cloud',
35
107
  fallback: { value: 'skip', key: 'setupNxCloud' },
108
+ completionMessage: 'ci-setup',
36
109
  },
37
110
  ],
38
111
  /**
@@ -51,8 +124,62 @@ const messageOptions = {
51
124
  },
52
125
  ],
53
126
  footer: '\nRead more about remote caching at https://nx.dev/ci/features/remote-cache',
54
- hint: `\n(can be disabled any time)`,
127
+ hint: `\n(can be disabled any time).`,
128
+ fallback: undefined,
129
+ completionMessage: 'cache-setup',
130
+ },
131
+ ],
132
+ /**
133
+ * Simplified Cloud prompt for template flow
134
+ */
135
+ setupNxCloudV2: [
136
+ {
137
+ code: 'cloud-v2-remote-cache-visit',
138
+ message: 'Enable remote caching with Nx Cloud?',
139
+ initial: 0,
140
+ choices: [
141
+ { value: 'yes', name: 'Yes' },
142
+ { value: 'skip', name: 'Skip' },
143
+ ],
144
+ footer: '\nRemote caching makes your builds faster for development and in CI: https://nx.dev/ci/features/remote-cache',
145
+ fallback: undefined,
146
+ completionMessage: 'cache-setup',
147
+ },
148
+ {
149
+ code: 'cloud-v2-fast-ci-visit',
150
+ message: 'Speed up CI and reduce compute costs with Nx Cloud?',
151
+ initial: 0,
152
+ choices: [
153
+ { value: 'yes', name: 'Yes' },
154
+ { value: 'skip', name: 'Skip' },
155
+ ],
156
+ footer: '\n70% faster CI, 60% less compute, Automatically fix broken PRs: https://nx.dev/nx-cloud',
157
+ fallback: undefined,
158
+ completionMessage: 'ci-setup',
159
+ },
160
+ {
161
+ code: 'cloud-v2-green-prs-visit',
162
+ message: 'Get to green PRs faster with Nx Cloud?',
163
+ initial: 0,
164
+ choices: [
165
+ { value: 'yes', name: 'Yes' },
166
+ { value: 'skip', name: 'Skip' },
167
+ ],
168
+ footer: '\nAutomatically fix broken PRs, 70% faster CI: https://nx.dev/nx-cloud',
169
+ fallback: undefined,
170
+ completionMessage: 'ci-setup',
171
+ },
172
+ {
173
+ code: 'cloud-v2-full-platform-visit',
174
+ message: 'Try the full Nx platform?',
175
+ initial: 0,
176
+ choices: [
177
+ { value: 'yes', name: 'Yes' },
178
+ { value: 'skip', name: 'Skip' },
179
+ ],
180
+ footer: '\nAutomatically fix broken PRs, 70% faster CI: https://nx.dev/nx-cloud',
55
181
  fallback: undefined,
182
+ completionMessage: 'platform-setup',
56
183
  },
57
184
  ],
58
185
  };
@@ -76,8 +203,15 @@ class PromptMessages {
76
203
  if (selected === undefined) {
77
204
  return '';
78
205
  }
206
+ return messageOptions[key][selected].code;
207
+ }
208
+ completionMessageOfSelectedPrompt(key) {
209
+ const selected = this.selectedMessages[key];
210
+ if (selected === undefined) {
211
+ return 'ci-setup';
212
+ }
79
213
  else {
80
- return messageOptions[key][selected].code;
214
+ return messageOptions[key][selected].completionMessage;
81
215
  }
82
216
  }
83
217
  }
@@ -97,6 +231,12 @@ async function recordStat(opts) {
97
231
  if (!shouldRecordStats()) {
98
232
  return;
99
233
  }
234
+ // nx-ignore-next-line
235
+ const { getCloudUrl } = require(require.resolve('nx/src/nx-cloud/utilities/get-cloud-options', {
236
+ paths: [opts.directory],
237
+ }
238
+ // nx-ignore-next-line
239
+ ));
100
240
  const axios = require('axios');
101
241
  await (axios['default'] ?? axios)
102
242
  .create({
@@ -117,14 +257,9 @@ async function recordStat(opts) {
117
257
  }
118
258
  }
119
259
  function shouldRecordStats() {
120
- const pmc = (0, package_manager_1.getPackageManagerCommand)();
121
- if (!pmc.getRegistryUrl) {
122
- // Fallback on true as Package management doesn't support reading config for registry.
123
- // currently Bun doesn't support fetching config settings https://github.com/oven-sh/bun/issues/7140
124
- return true;
125
- }
126
260
  try {
127
- const stdout = (0, node_child_process_1.execSync)(pmc.getRegistryUrl, {
261
+ // Use npm to check registry - this works regardless of which package manager invoked us
262
+ const stdout = (0, node_child_process_1.execSync)('npm config get registry', {
128
263
  encoding: 'utf-8',
129
264
  windowsHide: false,
130
265
  });
@@ -1,37 +1,27 @@
1
1
  import { VcsPushStatus } from '../git/git';
2
- declare const outputMessages: {
3
- readonly 'create-nx-workspace-success-ci-setup': readonly [{
4
- readonly code: "ci-setup-visit";
5
- readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
6
- title: string;
7
- type: string;
8
- bodyLines: string[];
9
- };
10
- }];
11
- readonly 'create-nx-workspace-success-cache-setup': readonly [{
12
- readonly code: "remote-cache-visit";
13
- readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
14
- title: string;
15
- type: string;
16
- bodyLines: string[];
17
- };
18
- }];
19
- };
20
- type OutputMessageKey = keyof typeof outputMessages;
21
- export declare function getMessageFactory(key: OutputMessageKey): {
22
- readonly code: "ci-setup-visit";
23
- readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
24
- title: string;
25
- type: string;
26
- bodyLines: string[];
2
+ /**
3
+ * Completion messages shown after workspace creation.
4
+ * Keys are referenced by ab-testing.ts prompts via completionMessage field.
5
+ */
6
+ declare const completionMessages: {
7
+ readonly 'ci-setup': {
8
+ readonly title: "Your CI setup is almost complete.";
9
+ };
10
+ readonly 'cache-setup': {
11
+ readonly title: "Your remote cache setup is almost complete.";
27
12
  };
28
- } | {
29
- readonly code: "remote-cache-visit";
30
- readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
31
- title: string;
32
- type: string;
33
- bodyLines: string[];
13
+ readonly 'platform-setup': {
14
+ readonly title: "Your platform setup is almost complete.";
34
15
  };
35
16
  };
17
+ export type CompletionMessageKey = keyof typeof completionMessages;
18
+ export declare function getCompletionMessage(completionMessageKey: CompletionMessageKey | undefined, url: string | null, pushedToVcs: VcsPushStatus): {
19
+ title: string;
20
+ bodyLines: string[];
21
+ };
22
+ export declare function getSkippedCloudMessage(): {
23
+ title: string;
24
+ bodyLines: string[];
25
+ };
36
26
  export {};
37
27
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkB3C,QAAA,MAAM,cAAc;;;sCAIO,MAAM,GAAG,IAAI,eAAe,aAAa;;;;;;;;sCAYzC,MAAM,GAAG,IAAI,eAAe,aAAa;;;;;;CAS1D,CAAC;AACX,KAAK,gBAAgB,GAAG,MAAM,OAAO,cAAc,CAAC;AAqBpD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB;;kCA3C5B,MAAM,GAAG,IAAI,eAAe,aAAa;;;;;;;kCAYzC,MAAM,GAAG,IAAI,eAAe,aAAa;;;;;EAiCnE"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkB3C;;;GAGG;AACH,QAAA,MAAM,kBAAkB;;;;;;;;;;CAUd,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAEnE,wBAAgB,oBAAoB,CAClC,oBAAoB,EAAE,oBAAoB,GAAG,SAAS,EACtD,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,WAAW,EAAE,aAAa,GACzB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAOxC;AAED,wBAAgB,sBAAsB,IAAI;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAUA"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMessageFactory = getMessageFactory;
3
+ exports.getCompletionMessage = getCompletionMessage;
4
+ exports.getSkippedCloudMessage = getSkippedCloudMessage;
4
5
  const git_1 = require("../git/git");
5
6
  function getSetupMessage(url, pushedToVcs) {
6
7
  if (pushedToVcs === git_1.VcsPushStatus.PushedToVcs) {
@@ -13,49 +14,36 @@ function getSetupMessage(url, pushedToVcs) {
13
14
  const urlSuffix = url ? `: ${url}` : '.';
14
15
  return `Push your repo, then ${action} to Nx Cloud and finish the setup${urlSuffix}`;
15
16
  }
16
- const outputMessages = {
17
- 'create-nx-workspace-success-ci-setup': [
18
- {
19
- code: 'ci-setup-visit',
20
- createMessage: (url, pushedToVcs) => {
21
- return {
22
- title: `Your CI setup is almost complete.`,
23
- type: 'success',
24
- bodyLines: [getSetupMessage(url, pushedToVcs)],
25
- };
26
- },
27
- },
28
- ],
29
- 'create-nx-workspace-success-cache-setup': [
30
- {
31
- code: 'remote-cache-visit',
32
- createMessage: (url, pushedToVcs) => {
33
- return {
34
- title: `Your remote cache is almost complete.`,
35
- type: 'success',
36
- bodyLines: [getSetupMessage(url, pushedToVcs)],
37
- };
38
- },
39
- },
40
- ],
17
+ /**
18
+ * Completion messages shown after workspace creation.
19
+ * Keys are referenced by ab-testing.ts prompts via completionMessage field.
20
+ */
21
+ const completionMessages = {
22
+ 'ci-setup': {
23
+ title: 'Your CI setup is almost complete.',
24
+ },
25
+ 'cache-setup': {
26
+ title: 'Your remote cache setup is almost complete.',
27
+ },
28
+ 'platform-setup': {
29
+ title: 'Your platform setup is almost complete.',
30
+ },
41
31
  };
42
- class ABTestingMessages {
43
- constructor() {
44
- this.selectedMessages = {};
45
- }
46
- getMessageFactory(key) {
47
- if (this.selectedMessages[key] === undefined) {
48
- if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
49
- this.selectedMessages[key] = 0;
50
- }
51
- else {
52
- this.selectedMessages[key] = Math.floor(Math.random() * outputMessages[key].length);
53
- }
54
- }
55
- return outputMessages[key][this.selectedMessages[key]];
56
- }
32
+ function getCompletionMessage(completionMessageKey, url, pushedToVcs) {
33
+ const key = completionMessageKey ?? 'ci-setup';
34
+ return {
35
+ title: completionMessages[key].title,
36
+ bodyLines: [getSetupMessage(url, pushedToVcs)],
37
+ };
57
38
  }
58
- const messages = new ABTestingMessages();
59
- function getMessageFactory(key) {
60
- return messages.getMessageFactory(key);
39
+ function getSkippedCloudMessage() {
40
+ return {
41
+ title: 'Next steps',
42
+ bodyLines: [
43
+ 'Run "nx connect" to enable remote caching and speed up your CI.',
44
+ '',
45
+ '70% faster CI, 60% less compute, automatically fix broken PRs.',
46
+ 'Learn more at https://nx.dev/nx-cloud',
47
+ ],
48
+ };
61
49
  }
@@ -1,6 +1,9 @@
1
1
  import { VcsPushStatus } from '../git/git';
2
+ import { CompletionMessageKey } from './messages';
2
3
  export type NxCloud = 'yes' | 'github' | 'gitlab' | 'azure' | 'bitbucket-pipelines' | 'circleci' | 'skip';
4
+ export declare function connectToNxCloudForTemplate(directory: string, installationSource: string, useGitHub?: boolean): Promise<string | null>;
3
5
  export declare function readNxCloudToken(directory: string): string;
4
- export declare function createNxCloudOnboardingUrl(nxCloud: NxCloud, token: string, directory: string, useGitHub?: boolean): Promise<any>;
5
- export declare function getNxCloudInfo(nxCloud: NxCloud, connectCloudUrl: string, pushedToVcs: VcsPushStatus, rawNxCloud?: NxCloud): Promise<string>;
6
+ export declare function createNxCloudOnboardingUrl(nxCloud: NxCloud, token: string, directory: string, useGitHub?: boolean): Promise<string>;
7
+ export declare function getNxCloudInfo(connectCloudUrl: string, pushedToVcs: VcsPushStatus, completionMessageKey?: CompletionMessageKey): Promise<string>;
8
+ export declare function getSkippedNxCloudInfo(): string;
6
9
  //# sourceMappingURL=nx-cloud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nx-cloud.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/nx-cloud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAK3C,MAAM,MAAM,OAAO,GACf,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,qBAAqB,GACrB,UAAU,GACV,MAAM,CAAC;AAEX,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,UAcjD;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,gBAwBpB;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,aAAa,EAC1B,UAAU,CAAC,EAAE,OAAO,mBAkBrB"}
1
+ {"version":3,"file":"nx-cloud.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/nx-cloud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAGL,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAIpB,MAAM,MAAM,OAAO,GACf,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,qBAAqB,GACrB,UAAU,GACV,MAAM,CAAC;AAEX,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BxB;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,UAcjD;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,CAAC,CAqCjB;AAED,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,aAAa,EAC1B,oBAAoB,CAAC,EAAE,oBAAoB,mBAU5C;AAED,wBAAgB,qBAAqB,WAIpC"}
@@ -1,11 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectToNxCloudForTemplate = connectToNxCloudForTemplate;
3
4
  exports.readNxCloudToken = readNxCloudToken;
4
5
  exports.createNxCloudOnboardingUrl = createNxCloudOnboardingUrl;
5
6
  exports.getNxCloudInfo = getNxCloudInfo;
7
+ exports.getSkippedNxCloudInfo = getSkippedNxCloudInfo;
6
8
  const output_1 = require("../output");
7
9
  const messages_1 = require("./messages");
10
+ const ab_testing_1 = require("./ab-testing");
8
11
  const ora = require("ora");
12
+ async function connectToNxCloudForTemplate(directory, installationSource, useGitHub) {
13
+ // nx-ignore-next-line
14
+ const { connectToNxCloud } = require(require.resolve('nx/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud', {
15
+ paths: [directory],
16
+ }
17
+ // nx-ignore-next-line
18
+ ));
19
+ // nx-ignore-next-line
20
+ const { FsTree, flushChanges } = require(require.resolve('nx/src/generators/tree', {
21
+ paths: [directory],
22
+ // nx-ignore-next-line
23
+ }));
24
+ const tree = new FsTree(directory, false);
25
+ const result = await connectToNxCloud(tree, {
26
+ installationSource,
27
+ directory: '',
28
+ github: useGitHub,
29
+ });
30
+ // Flush the tree changes to disk
31
+ flushChanges(directory, tree.listChanges());
32
+ return result;
33
+ }
9
34
  function readNxCloudToken(directory) {
10
35
  const nxCloudSpinner = ora(`Checking Nx Cloud setup`).start();
11
36
  // nx-ignore-next-line
@@ -25,25 +50,31 @@ async function createNxCloudOnboardingUrl(nxCloud, token, directory, useGitHub)
25
50
  }
26
51
  // nx-ignore-next-line
27
52
  ));
53
+ // Source determines the onboarding flow type
28
54
  const source = nxCloud === 'yes'
29
55
  ? 'create-nx-workspace-success-cache-setup'
30
56
  : 'create-nx-workspace-success-ci-setup';
31
- const { code } = (0, messages_1.getMessageFactory)(source);
32
- return await createNxCloudOnboardingURL(source, token, code, false, useGitHub ??
57
+ // Meta: "start" or "start-v2" prefix, with prompt code
58
+ // For template flow (variant 1): use specific prompt code from setupNxCloudV2
59
+ // For preset flow (variant 0): use visit codes based on nxCloud value
60
+ const flowVariant = (0, ab_testing_1.getFlowVariant)();
61
+ const prefix = flowVariant === '1' ? 'start-v2' : 'start';
62
+ const promptCode = flowVariant === '1'
63
+ ? ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloudV2')
64
+ : '';
65
+ const code = promptCode || (nxCloud === 'yes' ? 'remote-cache-visit' : 'ci-setup-visit');
66
+ const meta = `${prefix}-${code}`;
67
+ return createNxCloudOnboardingURL(source, token, meta, false, useGitHub ??
33
68
  (nxCloud === 'yes' || nxCloud === 'github' || nxCloud === 'circleci'));
34
69
  }
35
- async function getNxCloudInfo(nxCloud, connectCloudUrl, pushedToVcs, rawNxCloud) {
36
- const source = nxCloud === 'yes'
37
- ? 'create-nx-workspace-success-cache-setup'
38
- : 'create-nx-workspace-success-ci-setup';
39
- const { createMessage } = (0, messages_1.getMessageFactory)(source);
70
+ async function getNxCloudInfo(connectCloudUrl, pushedToVcs, completionMessageKey) {
40
71
  const out = new output_1.CLIOutput(false);
41
- const message = createMessage(typeof rawNxCloud === 'string' ? null : connectCloudUrl, pushedToVcs);
42
- if (message.type === 'success') {
43
- out.success(message);
44
- }
45
- else {
46
- out.warn(message);
47
- }
72
+ const message = (0, messages_1.getCompletionMessage)(completionMessageKey, connectCloudUrl, pushedToVcs);
73
+ out.success(message);
74
+ return out.getOutput();
75
+ }
76
+ function getSkippedNxCloudInfo() {
77
+ const out = new output_1.CLIOutput(false);
78
+ out.success((0, messages_1.getSkippedCloudMessage)());
48
79
  return out.getOutput();
49
80
  }
@@ -0,0 +1,2 @@
1
+ export declare function cloneTemplate(templateUrl: string, targetDirectory: string): Promise<void>;
2
+ //# sourceMappingURL=clone-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone-template.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/template/clone-template.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cloneTemplate = cloneTemplate;
4
+ const child_process_utils_1 = require("../child-process-utils");
5
+ const fs_1 = require("fs");
6
+ const promises_1 = require("fs/promises");
7
+ const path_1 = require("path");
8
+ const output_1 = require("../output");
9
+ const error_utils_1 = require("../error-utils");
10
+ async function cloneTemplate(templateUrl, targetDirectory) {
11
+ if ((0, fs_1.existsSync)(targetDirectory)) {
12
+ throw new Error(`The directory '${targetDirectory}' already exists and is not empty. Choose a different name or remove the existing directory.`);
13
+ }
14
+ try {
15
+ await (0, child_process_utils_1.execAndWait)(`git clone --depth 1 "${templateUrl}" "${targetDirectory}"`, process.cwd());
16
+ // Ensure clean history
17
+ const gitDir = (0, path_1.join)(targetDirectory, '.git');
18
+ if ((0, fs_1.existsSync)(gitDir)) {
19
+ await (0, promises_1.rm)(gitDir, { recursive: true, force: true });
20
+ }
21
+ }
22
+ catch (e) {
23
+ if (e instanceof Error) {
24
+ output_1.output.error({
25
+ title: 'Failed to create starter workspace',
26
+ bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
27
+ });
28
+ }
29
+ else {
30
+ console.error(e);
31
+ }
32
+ process.exit(1);
33
+ }
34
+ }