create-nx-workspace 22.6.1 → 22.6.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":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,sBAAsB,EAEvB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EAAiB,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAwEnE,KAAK,qBAAqB,GACtB,MAAM,GACN,MAAM,GACN,gBAAgB,GAChB,eAAe,CAAC;AAEpB,UAAU,aAAc,SAAQ,sBAAsB;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,YAAY,CAAC;IAC9D,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,UAAU,cAAe,SAAQ,aAAa;IAC5C,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;CAClD;AAED,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,qBAAqB,CAAC;IACtC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IACjD,OAAO,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,YAAa,SAAQ,aAAa;IAC1C,KAAK,EAAE,KAAK,CAAC;IACb,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,QAAQ,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;CAClD;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,UAAU,qBAAsB,SAAQ,aAAa;IACnD,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,KAAK,SAAS,GACV,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,YAAY,GACZ,aAAa,GACb,qBAAqB,CAAC;AAE1B,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAiJrB,CAAC;AAggB7B,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQxD"}
1
+ {"version":3,"file":"create-nx-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/bin/create-nx-workspace.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,sBAAsB,EAEvB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EAAiB,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAwEnE,KAAK,qBAAqB,GACtB,MAAM,GACN,MAAM,GACN,gBAAgB,GAChB,eAAe,CAAC;AAEpB,UAAU,aAAc,SAAQ,sBAAsB;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,YAAY,CAAC;IAC9D,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,UAAU,cAAe,SAAQ,aAAa;IAC5C,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;CAClD;AAED,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,qBAAqB,CAAC;IACtC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IACjD,OAAO,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,YAAa,SAAQ,aAAa;IAC1C,KAAK,EAAE,KAAK,CAAC;IACb,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,QAAQ,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;CAClD;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,UAAU,qBAAsB,SAAQ,aAAa;IACnD,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,KAAK,SAAS,GACV,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,YAAY,GACZ,aAAa,GACb,qBAAqB,CAAC;AAE1B,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAiJrB,CAAC;AAigB7B,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQxD"}
@@ -169,13 +169,13 @@ exports.commandsObject = yargs
169
169
  if ((0, ai_output_1.isAiAgent)()) {
170
170
  exports.commandsObject
171
171
  .example(chalk.green('AI AGENTS (RECOMMENDED):'), '')
172
- .example(' npx create-nx-workspace@latest myorg --template=nrwl/empty-template --nxCloud=yes --interactive=false', '')
172
+ .example(' npx create-nx-workspace@latest myorg --template=empty --nxCloud=yes --interactive=false', '')
173
173
  .example('', '')
174
174
  .example(chalk.green('AVAILABLE TEMPLATES:'), '')
175
- .example(' --template=nrwl/empty-template Empty monorepo', '')
176
- .example(' --template=nrwl/react-template React fullstack', '')
177
- .example(' --template=nrwl/angular-template Angular fullstack', '')
178
- .example(' --template=nrwl/typescript-template NPM packages', '')
175
+ .example(' --template=empty Empty monorepo', '')
176
+ .example(' --template=react React fullstack', '')
177
+ .example(' --template=angular Angular fullstack', '')
178
+ .example(' --template=typescript NPM packages', '')
179
179
  .epilogue(`${chalk.cyan('AI Agent Mode:')}
180
180
  Set CLAUDECODE=1 or OPENCODE=1 for JSON output and non-interactive mode.
181
181
  In AI mode: auto non-interactive, NDJSON progress output, structured results.
@@ -252,6 +252,7 @@ async function main(parsedArgs) {
252
252
  nxCloudArg: parsedArgs.nxCloud ?? '',
253
253
  nxCloudArgRaw: rawArgs.nxCloud ?? '',
254
254
  pushedToVcs: workspaceInfo.pushedToVcs ?? '',
255
+ pushFailReason: workspaceInfo.pushFailReason ?? '',
255
256
  template: chosenTemplate ?? '',
256
257
  preset: chosenPreset ?? '',
257
258
  connectUrl: workspaceInfo.connectUrl ?? '',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nx-workspace",
3
- "version": "22.6.1",
3
+ "version": "22.6.3",
4
4
  "private": false,
5
5
  "description": "Smart Monorepos · Fast Builds",
6
6
  "repository": {
@@ -34,6 +34,7 @@
34
34
  "chalk": "^4.1.0",
35
35
  "enquirer": "~2.3.6",
36
36
  "flat": "^5.0.2",
37
+ "open": "^8.4.0",
37
38
  "ora": "5.3.0",
38
39
  "tmp": "~0.2.1",
39
40
  "tslib": "^2.3.0",
@@ -8,7 +8,9 @@ export declare function createWorkspace<T extends CreateWorkspaceOptions>(preset
8
8
  nxCloudInfo: string;
9
9
  directory: string;
10
10
  pushedToVcs: VcsPushStatus;
11
+ pushFailReason: string;
11
12
  connectUrl: string;
12
13
  }>;
13
14
  export declare function extractConnectUrl(text: string): string | null;
15
+ export declare function resolveTemplateShorthand(template: string): string;
14
16
  //# sourceMappingURL=create-workspace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAGL,aAAa,EACd,MAAM,iBAAiB,CAAC;AA4BzB,wBAAgB,4BAA4B,IAAI;IAC9C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAEA;AAED,wBAAsB,eAAe,CAAC,CAAC,SAAS,sBAAsB,EACpE,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,CAAC;;;;;GAmQZ;AAUD,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":"AAKA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAIL,aAAa,EACd,MAAM,iBAAiB,CAAC;AA6BzB,wBAAgB,4BAA4B,IAAI;IAC9C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAEA;AAED,wBAAsB,eAAe,CAAC,CAAC,SAAS,sBAAsB,EACpE,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,CAAC;;;;;;GA4RZ;AAUD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D;AASD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getInterruptedWorkspaceState = getInterruptedWorkspaceState;
4
4
  exports.createWorkspace = createWorkspace;
5
5
  exports.extractConnectUrl = extractConnectUrl;
6
+ exports.resolveTemplateShorthand = resolveTemplateShorthand;
6
7
  const node_fs_1 = require("node:fs");
7
8
  const path_1 = require("path");
8
9
  const create_empty_workspace_1 = require("./create-empty-workspace");
@@ -33,6 +34,8 @@ async function createWorkspace(preset, options, rawArgs) {
33
34
  }
34
35
  let directory;
35
36
  if (options.template) {
37
+ // Resolve shorthand template names to full GitHub org/repo format
38
+ options.template = resolveTemplateShorthand(options.template);
36
39
  if (!options.template.startsWith('nrwl/'))
37
40
  throw new Error(`Invalid template. Only templates from the 'nrwl' GitHub org are supported.`);
38
41
  const templateUrl = `https://github.com/${options.template}`;
@@ -131,6 +134,7 @@ async function createWorkspace(preset, options, rawArgs) {
131
134
  await (0, setup_ci_1.setupCI)(directory, ciProvider, packageManager);
132
135
  }
133
136
  let pushedToVcs = git_1.VcsPushStatus.SkippedGit;
137
+ let pushFailReason;
134
138
  if (!skipGit) {
135
139
  const aiMode = (0, ai_output_1.isAiAgent)();
136
140
  if (aiMode) {
@@ -153,14 +157,29 @@ async function createWorkspace(preset, options, rawArgs) {
153
157
  }
154
158
  }
155
159
  catch (e) {
156
- if (e instanceof Error) {
160
+ if (e instanceof git_1.GitHubPushError) {
161
+ // GitHub push issues are never fatal — CNW always succeeds.
162
+ // All reasons are logged in telemetry via pushFailReason.
163
+ pushedToVcs = git_1.VcsPushStatus.FailedToPushToVcs;
164
+ pushFailReason = e.reason;
165
+ // Only show the push hint when the user actually attempted a push
166
+ // and it failed. Pre-push issues (gh not installed, auth failed,
167
+ // timed out during auth) are silent — no point telling the user
168
+ // about a push they never asked for.
169
+ if (e.reason === 'push-failed' || e.reason === 'push-timeout') {
170
+ const githubNewUrl = `https://github.com/new?name=${encodeURIComponent(name)}`;
171
+ output_1.output.log({
172
+ title: `Push your repo to GitHub: ${githubNewUrl}`,
173
+ });
174
+ }
175
+ }
176
+ else if (e instanceof Error) {
157
177
  if (!aiMode) {
158
178
  output_1.output.error({
159
179
  title: 'Could not initialize git repository',
160
180
  bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
161
181
  });
162
182
  }
163
- // In AI mode, error will be handled by the caller
164
183
  }
165
184
  else {
166
185
  console.error(e);
@@ -194,6 +213,10 @@ async function createWorkspace(preset, options, rawArgs) {
194
213
  }
195
214
  }
196
215
  nxCloudInfo = await (0, nx_cloud_1.getNxCloudInfo)(connectUrl, pushedToVcs, options.completionMessageKey, name);
216
+ // Auto-open the Cloud setup URL in the browser when user selected 'yes'
217
+ if (!options.skipCloudConnect) {
218
+ await (0, nx_cloud_1.openCloudSetupUrl)(connectUrl);
219
+ }
197
220
  }
198
221
  else if (isTemplate && (nxCloud === 'skip' || nxCloud === 'never')) {
199
222
  // Strip marker comments from README
@@ -211,6 +234,7 @@ async function createWorkspace(preset, options, rawArgs) {
211
234
  nxCloudInfo,
212
235
  directory,
213
236
  pushedToVcs,
237
+ pushFailReason,
214
238
  connectUrl,
215
239
  };
216
240
  }
@@ -226,6 +250,15 @@ function extractConnectUrl(text) {
226
250
  const match = text.match(urlPattern);
227
251
  return match ? match[0] : null;
228
252
  }
253
+ const templateShorthands = {
254
+ angular: 'nrwl/angular-template',
255
+ react: 'nrwl/react-template',
256
+ typescript: 'nrwl/typescript-template',
257
+ empty: 'nrwl/empty-template',
258
+ };
259
+ function resolveTemplateShorthand(template) {
260
+ return templateShorthands[template] ?? template;
261
+ }
229
262
  function getWorkspaceGlobsFromPreset(preset) {
230
263
  // Should match how apps are created in `packages/workspace/src/generators/preset/preset.ts`.
231
264
  switch (preset) {
@@ -95,7 +95,7 @@ async function determineTemplate(parsedArgs) {
95
95
  if (parsedArgs.preset)
96
96
  return 'custom';
97
97
  if (!parsedArgs.interactive || (0, is_ci_1.isCI)())
98
- return 'custom';
98
+ return 'nrwl/empty-template';
99
99
  // Docs generation needs preset flow to document all presets
100
100
  if (process.env.NX_GENERATE_DOCS_PROCESS === 'true')
101
101
  return 'custom';
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Use spawn only for interactive shells
3
3
  */
4
- export declare function spawnAndWait(command: string, args: string[], cwd: string): Promise<unknown>;
5
- export declare function execAndWait(command: string, cwd: string, silenceErrors?: boolean): Promise<{
4
+ export declare function spawnAndWait(command: string, args: string[], cwd: string, timeout?: number): Promise<unknown>;
5
+ export declare function execAndWait(command: string, cwd: string, silenceErrors?: boolean, timeout?: number): Promise<{
6
6
  code: number;
7
7
  stdout: string;
8
8
  }>;
@@ -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,oBA+BxE;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,aAAa,UAAQ;UAEM,MAAM;YAAU,MAAM;GAgClD"}
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,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,oBA8CjB;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,aAAa,UAAQ,EACrB,OAAO,CAAC,EAAE,MAAM;UAEW,MAAM;YAAU,MAAM;GAiClD"}
@@ -9,7 +9,7 @@ const error_utils_1 = require("./error-utils");
9
9
  /**
10
10
  * Use spawn only for interactive shells
11
11
  */
12
- function spawnAndWait(command, args, cwd) {
12
+ function spawnAndWait(command, args, cwd, timeout) {
13
13
  return new Promise((res, rej) => {
14
14
  // Combine command and args into a single string to avoid DEP0190 warning
15
15
  // (passing args with shell: true is deprecated)
@@ -29,7 +29,21 @@ function spawnAndWait(command, args, cwd) {
29
29
  shell: true,
30
30
  windowsHide: true,
31
31
  });
32
+ let timedOut = false;
33
+ let timer;
34
+ if (timeout) {
35
+ timer = setTimeout(() => {
36
+ timedOut = true;
37
+ childProcess.kill('SIGTERM');
38
+ }, timeout);
39
+ }
32
40
  childProcess.on('exit', (code, signal) => {
41
+ if (timer)
42
+ clearTimeout(timer);
43
+ if (timedOut) {
44
+ rej({ code: 1, timedOut: true });
45
+ return;
46
+ }
33
47
  if (code === null)
34
48
  code = signalToCode(signal);
35
49
  if (code !== 0) {
@@ -41,17 +55,18 @@ function spawnAndWait(command, args, cwd) {
41
55
  });
42
56
  });
43
57
  }
44
- function execAndWait(command, cwd, silenceErrors = false) {
58
+ function execAndWait(command, cwd, silenceErrors = false, timeout) {
45
59
  return new Promise((res, rej) => {
46
60
  (0, child_process_1.exec)(command, {
47
61
  cwd,
48
62
  env: { ...process.env, NX_DAEMON: 'false' },
49
63
  windowsHide: true,
50
64
  maxBuffer: 1024 * 1024 * 10, // 10MB — default 1MB can be exceeded by verbose PM output
65
+ ...(timeout ? { timeout } : {}),
51
66
  }, (error, stdout, stderr) => {
52
67
  if (error) {
53
68
  if (silenceErrors) {
54
- rej();
69
+ rej(error.killed ? { timedOut: true } : undefined);
55
70
  }
56
71
  else {
57
72
  const logFile = (0, path_1.join)(cwd, 'error.log');
@@ -4,9 +4,9 @@ export declare enum VcsPushStatus {
4
4
  FailedToPushToVcs = "FailedToPushToVcs",
5
5
  SkippedGit = "SkippedGit"
6
6
  }
7
- export declare class GitHubPushSkippedError extends Error {
8
- readonly title = "Push your workspace";
9
- constructor(message: string);
7
+ export declare class GitHubPushError extends Error {
8
+ readonly reason: 'gh-not-installed' | 'gh-auth-failed' | 'push-timeout' | 'push-failed' | 'env-skip';
9
+ constructor(message: string, reason: 'gh-not-installed' | 'gh-auth-failed' | 'push-timeout' | 'push-failed' | 'env-skip');
10
10
  }
11
11
  export declare function checkGitVersion(): Promise<string | null | undefined>;
12
12
  /**
@@ -16,7 +16,7 @@ export declare function checkGitVersion(): Promise<string | null | undefined>;
16
16
  export declare function isGitAvailable(): boolean;
17
17
  /**
18
18
  * Synchronously checks if GitHub CLI (gh) is available on the system.
19
- * Returns true if gh command can be executed, false otherwise.
19
+ * Returns true if gh command can be executed within 2 seconds, false otherwise.
20
20
  */
21
21
  export declare function isGhCliAvailable(): boolean;
22
22
  export declare function initializeGitRepo(directory: string, options: {
@@ -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;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAOxC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAO1C;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,CAuGxB"}
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,eAAgB,SAAQ,KAAK;aAGtB,MAAM,EAClB,kBAAkB,GAClB,gBAAgB,GAChB,cAAc,GACd,aAAa,GACb,UAAU;gBANd,OAAO,EAAE,MAAM,EACC,MAAM,EAClB,kBAAkB,GAClB,gBAAgB,GAChB,cAAc,GACd,aAAa,GACb,UAAU;CAKjB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAQ1E;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAOxC;AAYD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAW1C;AA0FD,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,CAkHxB"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GitHubPushSkippedError = exports.VcsPushStatus = void 0;
3
+ exports.GitHubPushError = exports.VcsPushStatus = void 0;
4
4
  exports.checkGitVersion = checkGitVersion;
5
5
  exports.isGitAvailable = isGitAvailable;
6
6
  exports.isGhCliAvailable = isGhCliAvailable;
@@ -18,14 +18,14 @@ var VcsPushStatus;
18
18
  VcsPushStatus["FailedToPushToVcs"] = "FailedToPushToVcs";
19
19
  VcsPushStatus["SkippedGit"] = "SkippedGit";
20
20
  })(VcsPushStatus || (exports.VcsPushStatus = VcsPushStatus = {}));
21
- class GitHubPushSkippedError extends Error {
22
- constructor(message) {
21
+ class GitHubPushError extends Error {
22
+ constructor(message, reason) {
23
23
  super(message);
24
- this.title = 'Push your workspace';
25
- this.name = 'GitHubPushSkippedError';
24
+ this.reason = reason;
25
+ this.name = 'GitHubPushError';
26
26
  }
27
27
  }
28
- exports.GitHubPushSkippedError = GitHubPushSkippedError;
28
+ exports.GitHubPushError = GitHubPushError;
29
29
  async function checkGitVersion() {
30
30
  try {
31
31
  const result = await (0, child_process_utils_1.execAndWait)('git --version', process.cwd());
@@ -49,13 +49,26 @@ function isGitAvailable() {
49
49
  return false;
50
50
  }
51
51
  }
52
+ // 1 second timeout for gh CLI pre-flight checks (version, auth). If gh is
53
+ // wrapped by 1Password, a credential manager, or corporate SSO the call can
54
+ // hang indefinitely. Better to skip the push than freeze the CLI.
55
+ const GH_CLI_TIMEOUT_MS = 1_000;
56
+ // 10 second timeout for repo listing (runs in background while user answers prompts).
57
+ const GH_LIST_TIMEOUT_MS = 10_000;
58
+ // 30 second timeout for the actual repo create + push operation.
59
+ // Longer than other gh commands to account for slow networks.
60
+ const GH_PUSH_TIMEOUT_MS = 30_000;
52
61
  /**
53
62
  * Synchronously checks if GitHub CLI (gh) is available on the system.
54
- * Returns true if gh command can be executed, false otherwise.
63
+ * Returns true if gh command can be executed within 2 seconds, false otherwise.
55
64
  */
56
65
  function isGhCliAvailable() {
57
66
  try {
58
- (0, child_process_1.execSync)('gh --version', { stdio: 'ignore', windowsHide: true });
67
+ (0, child_process_1.execSync)('gh --version', {
68
+ stdio: 'ignore',
69
+ windowsHide: true,
70
+ timeout: GH_CLI_TIMEOUT_MS,
71
+ });
59
72
  return true;
60
73
  }
61
74
  catch {
@@ -63,12 +76,16 @@ function isGhCliAvailable() {
63
76
  }
64
77
  }
65
78
  async function getGitHubUsername(directory) {
66
- const result = await (0, child_process_utils_1.execAndWait)('gh api user --jq .login', directory);
67
- const username = result.stdout.trim();
68
- if (!username) {
69
- throw new GitHubPushSkippedError('GitHub CLI is not authenticated');
79
+ try {
80
+ const result = await (0, child_process_utils_1.execAndWait)('gh api user --jq .login', directory, true, // silenceErrors — gh failures should never write error.log (#34482)
81
+ GH_CLI_TIMEOUT_MS);
82
+ return result.stdout.trim() || null;
83
+ }
84
+ catch {
85
+ // gh is optional — auth failures, timeouts, or missing credentials
86
+ // are silently ignored. The push flow will be skipped.
87
+ return null;
70
88
  }
71
- return username;
72
89
  }
73
90
  // Module-level promise for background repo fetching
74
91
  let existingReposPromise;
@@ -81,8 +98,9 @@ async function getUserRepositories(directory) {
81
98
  // Get user's personal repos and organizations concurrently
82
99
  // Limit to 100 repos for faster response (covers most use cases)
83
100
  const [userRepos, orgsResult] = await Promise.all([
84
- (0, child_process_utils_1.execAndWait)('gh repo list --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"', directory),
85
- (0, child_process_utils_1.execAndWait)('gh api user/orgs --jq ".[].login"', directory),
101
+ (0, child_process_utils_1.execAndWait)('gh repo list --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"', directory, true, // silenceErrors — gh failures should never write error.log
102
+ GH_LIST_TIMEOUT_MS),
103
+ (0, child_process_utils_1.execAndWait)('gh api user/orgs --jq ".[].login"', directory, true, GH_LIST_TIMEOUT_MS),
86
104
  ]);
87
105
  // Add user's personal repos
88
106
  userRepos.stdout
@@ -98,7 +116,8 @@ async function getUserRepositories(directory) {
98
116
  // Get repos from all organizations concurrently
99
117
  const orgRepoPromises = orgs.map(async (org) => {
100
118
  try {
101
- const orgRepos = await (0, child_process_utils_1.execAndWait)(`gh repo list ${org} --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"`, directory);
119
+ const orgRepos = await (0, child_process_utils_1.execAndWait)(`gh repo list ${org} --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"`, directory, true, // silenceErrors
120
+ GH_LIST_TIMEOUT_MS);
102
121
  return orgRepos.stdout
103
122
  .trim()
104
123
  .split('\n')
@@ -166,13 +185,23 @@ ${options.connectUrl}
166
185
  }
167
186
  async function pushToGitHub(directory, options) {
168
187
  try {
188
+ // Pre-flight gates — gh is optional, so any failure here throws
189
+ // GitHubPushError which the caller handles silently (no user output)
190
+ // while still recording the reason in telemetry.
169
191
  if (process.env['NX_SKIP_GH_PUSH'] === 'true') {
170
- throw new GitHubPushSkippedError('NX_SKIP_GH_PUSH is true so skipping GitHub push.');
192
+ throw new GitHubPushError('NX_SKIP_GH_PUSH is true', 'env-skip');
193
+ }
194
+ if (!isGhCliAvailable()) {
195
+ throw new GitHubPushError('gh CLI is not installed', 'gh-not-installed');
171
196
  }
172
- // Note: This call can throw an error even if user hasn't opted in to push yet,
173
- // which could be confusing as they haven't been asked about GitHub push at this point.
174
- // We check gh authentication early to provide a better error message.
197
+ // Check gh authentication with a short timeout. If gh is wrapped by
198
+ // 1Password, a credential manager, or corporate SSO this call can hang
199
+ // indefinitely. A 2 s timeout catches that and skips the push gracefully
200
+ // instead of freezing the CLI.
175
201
  const username = await getGitHubUsername(directory);
202
+ if (!username) {
203
+ throw new GitHubPushError('gh auth failed', 'gh-auth-failed');
204
+ }
176
205
  // Start fetching existing repositories in the background immediately
177
206
  // This runs while user is answering prompts, so validation is usually instant
178
207
  populateExistingRepos(directory);
@@ -212,35 +241,43 @@ async function pushToGitHub(directory, options) {
212
241
  },
213
242
  },
214
243
  ]);
215
- // Create GitHub repository using gh CLI from the workspace directory
216
- // This will automatically add remote origin and push the current branch
244
+ // Create GitHub repository and push using gh CLI.
245
+ // Uses execAndWait (not spawnAndWait) so output is captured rather than
246
+ // streamed to the terminal. This prevents git push output from bleeding
247
+ // into the terminal after CNW exits, and ensures the timeout properly
248
+ // kills the entire process tree.
217
249
  output_1.output.log({
218
250
  title: 'Creating GitHub repository and pushing (this may take a moment)...',
219
251
  });
220
- await (0, child_process_utils_1.spawnAndWait)('gh', [
221
- 'repo',
222
- 'create',
223
- repoName,
224
- '--private',
225
- '--push',
226
- '--source',
227
- directory,
228
- ], directory);
252
+ const cmd = `gh repo create ${repoName} --private --push --source "${directory}"`;
253
+ await (0, child_process_utils_1.execAndWait)(cmd, directory, true, GH_PUSH_TIMEOUT_MS);
229
254
  // Get the actual repository URL from GitHub CLI (it could be different from github.com)
230
- const repoResult = await (0, child_process_utils_1.execAndWait)('gh repo view --json url -q .url', directory);
231
- const repoUrl = repoResult.stdout.trim();
255
+ let repoUrl = `https://github.com/${repoName}`;
256
+ try {
257
+ const repoResult = await (0, child_process_utils_1.execAndWait)('gh repo view --json url -q .url', directory, true, // silenceErrors
258
+ GH_CLI_TIMEOUT_MS);
259
+ if (repoResult.stdout.trim()) {
260
+ repoUrl = repoResult.stdout.trim();
261
+ }
262
+ }
263
+ catch {
264
+ // Fall back to constructed URL
265
+ }
232
266
  output_1.output.success({
233
267
  title: `Successfully pushed to GitHub repository: ${repoUrl}`,
234
268
  });
235
269
  return VcsPushStatus.PushedToVcs;
236
270
  }
237
271
  catch (e) {
238
- // Error code 127 means gh wasn't installed
239
- // GitHubPushSkippedError means user hasn't opted in or we couldn't authenticate
240
- const title = e instanceof GitHubPushSkippedError || e?.code === 127
241
- ? 'Push your workspace to GitHub.'
242
- : 'Could not push.';
243
- output_1.output.log({ title });
244
- return VcsPushStatus.FailedToPushToVcs;
272
+ // Re-throw GitHubPushError as-is (gh not installed, auth failed, env skip)
273
+ if (e instanceof GitHubPushError)
274
+ throw e;
275
+ // Wrap other failures (push timeout, push command failed) as GitHubPushError
276
+ const isTimedOut = e?.timedOut === true;
277
+ if (isTimedOut) {
278
+ throw new GitHubPushError('gh push timed out', 'push-timeout');
279
+ }
280
+ const msg = e instanceof Error ? e.message : String(e);
281
+ throw new GitHubPushError(msg.split('\n')[0].slice(0, 200), 'push-failed');
245
282
  }
246
283
  }
@@ -9,7 +9,6 @@ export declare function getFlowVariant(): string;
9
9
  * Now locked to 'platform-setup' after concluding the prompt A/B test.
10
10
  */
11
11
  export declare function getCompletionMessageKeyForVariant(): CompletionMessageKey;
12
- export declare function shouldShowCloudPrompt(): boolean;
13
12
  /**
14
13
  * Check if the given cloud URL is an enterprise URL.
15
14
  * Enterprise URLs are anything other than cloud.nx.app, eu.nx.app, staging.nx.app, or snapshot.nx.app.
@@ -1 +1 @@
1
- {"version":3,"file":"ab-testing.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/ab-testing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ab-testing.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/ab-testing.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.messages = exports.PromptMessages = exports.NxCloudChoices = void 0;
4
4
  exports.getFlowVariant = getFlowVariant;
5
5
  exports.getCompletionMessageKeyForVariant = getCompletionMessageKeyForVariant;
6
- exports.shouldShowCloudPrompt = shouldShowCloudPrompt;
7
6
  exports.isEnterpriseCloudUrl = isEnterpriseCloudUrl;
8
7
  exports.getBannerVariant = getBannerVariant;
9
8
  exports.recordStat = recordStat;
@@ -11,6 +10,7 @@ const node_child_process_1 = require("node:child_process");
11
10
  const node_fs_1 = require("node:fs");
12
11
  const node_path_1 = require("node:path");
13
12
  const node_os_1 = require("node:os");
13
+ const chalk = require("chalk");
14
14
  const is_ci_1 = require("../ci/is-ci");
15
15
  // Flow variant controls both tracking and banner display (CLOUD-4235)
16
16
  // Variants: 0 = control, 1 = updated prompt, 2 = no prompt (auto-connect)
@@ -91,11 +91,6 @@ function getFlowVariant() {
91
91
  function getCompletionMessageKeyForVariant() {
92
92
  return 'platform-setup';
93
93
  }
94
- function shouldShowCloudPrompt() {
95
- // CLOUD-4255: Lock to variant 2 behavior (no prompt)
96
- // To re-enable A/B testing: return getFlowVariant() !== '2';
97
- return false;
98
- }
99
94
  // ============================================================================
100
95
  // Banner Variant A/B Testing (CLOUD-4235)
101
96
  // ============================================================================
@@ -205,12 +200,38 @@ const messageOptions = {
205
200
  choices: [
206
201
  { value: 'yes', name: 'Yes' },
207
202
  { value: 'skip', name: 'Skip for now' },
208
- { value: 'never', name: "No, don't ask again" },
203
+ { value: 'never', name: chalk.dim("No, don't ask again") },
209
204
  ],
210
205
  footer: '\nAutomatically fix broken PRs, 70% faster CI: https://nx.dev/nx-cloud',
211
206
  fallback: undefined,
212
207
  completionMessage: 'platform-setup',
213
208
  },
209
+ {
210
+ code: 'cloud-ab-remote-cache-speed',
211
+ message: 'Enable remote caching to speed up builds with Nx Cloud?',
212
+ initial: 0,
213
+ choices: [
214
+ { value: 'yes', name: 'Yes' },
215
+ { value: 'skip', name: 'Skip for now' },
216
+ { value: 'never', name: chalk.dim("No, don't ask again") },
217
+ ],
218
+ footer: '\nFree for small teams. 2-minute setup with GitHub — cache locally and in CI: https://nx.dev/nx-cloud',
219
+ fallback: undefined,
220
+ completionMessage: 'platform-setup',
221
+ },
222
+ {
223
+ code: 'cloud-ab-fast-ci-setup',
224
+ message: 'Speed up your CI with Nx Cloud?',
225
+ initial: 0,
226
+ choices: [
227
+ { value: 'yes', name: 'Yes' },
228
+ { value: 'skip', name: 'Skip for now' },
229
+ { value: 'never', name: chalk.dim("No, don't ask again") },
230
+ ],
231
+ footer: '\n70% faster CI on GitHub, GitLab, and more. Free tier, 2-minute setup: https://nx.dev/nx-cloud',
232
+ fallback: undefined,
233
+ completionMessage: 'platform-setup',
234
+ },
214
235
  ],
215
236
  };
216
237
  class PromptMessages {
@@ -223,7 +244,9 @@ class PromptMessages {
223
244
  this.selectedMessages[key] = 0;
224
245
  }
225
246
  else {
226
- this.selectedMessages[key] = Math.floor(Math.random() * messageOptions[key].length);
247
+ const variant = Number(getFlowVariant());
248
+ this.selectedMessages[key] =
249
+ variant < messageOptions[key].length ? variant : 0;
227
250
  }
228
251
  }
229
252
  return messageOptions[key][this.selectedMessages[key]];
@@ -6,5 +6,6 @@ export declare function readNxCloudToken(directory: string): string;
6
6
  export declare function createNxCloudOnboardingUrl(nxCloud: NxCloud, token: string | undefined, directory: string, useGitHub?: boolean): Promise<string>;
7
7
  export declare function getNxCloudInfo(connectCloudUrl: string, pushedToVcs: VcsPushStatus, completionMessageKey?: CompletionMessageKey, workspaceName?: string): Promise<string>;
8
8
  export declare function getSkippedNxCloudInfo(): string;
9
+ export declare function openCloudSetupUrl(connectUrl: string): Promise<void>;
9
10
  export declare function setNeverConnectToCloud(directory: string): void;
10
11
  //# 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;AAE3C,OAAO,EAGL,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAKpB,MAAM,MAAM,OAAO,GACf,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,qBAAqB,GACrB,UAAU,GACV,MAAM,GACN,OAAO,CAAC;AAEZ,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BxB;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,UAgBjD;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,aAAa,EAC1B,oBAAoB,CAAC,EAAE,oBAAoB,EAC3C,aAAa,CAAC,EAAE,MAAM,mBAuBvB;AAED,wBAAgB,qBAAqB,WAIpC;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAO9D"}
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;AAG3C,OAAO,EAGL,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAKpB,MAAM,MAAM,OAAO,GACf,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,qBAAqB,GACrB,UAAU,GACV,MAAM,GACN,OAAO,CAAC;AAEZ,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BxB;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,UAgBjD;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,aAAa,EAC1B,oBAAoB,CAAC,EAAE,oBAAoB,EAC3C,aAAa,CAAC,EAAE,MAAM,mBAuBvB;AAED,wBAAgB,qBAAqB,WAIpC;AAED,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWzE;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAO9D"}
@@ -5,7 +5,9 @@ exports.readNxCloudToken = readNxCloudToken;
5
5
  exports.createNxCloudOnboardingUrl = createNxCloudOnboardingUrl;
6
6
  exports.getNxCloudInfo = getNxCloudInfo;
7
7
  exports.getSkippedNxCloudInfo = getSkippedNxCloudInfo;
8
+ exports.openCloudSetupUrl = openCloudSetupUrl;
8
9
  exports.setNeverConnectToCloud = setNeverConnectToCloud;
10
+ const is_ci_1 = require("../ci/is-ci");
9
11
  const output_1 = require("../output");
10
12
  const messages_1 = require("./messages");
11
13
  const ab_testing_1 = require("./ab-testing");
@@ -85,6 +87,18 @@ function getSkippedNxCloudInfo() {
85
87
  out.success((0, messages_1.getSkippedCloudMessage)());
86
88
  return out.getOutput();
87
89
  }
90
+ async function openCloudSetupUrl(connectUrl) {
91
+ if ((0, is_ci_1.isCI)()) {
92
+ return;
93
+ }
94
+ try {
95
+ const open = require('open');
96
+ await open(connectUrl);
97
+ }
98
+ catch {
99
+ // Fail gracefully — the URL is already displayed in the terminal banner
100
+ }
101
+ }
88
102
  function setNeverConnectToCloud(directory) {
89
103
  const { readFileSync, writeFileSync } = require('fs');
90
104
  const { join } = require('path');