@@ -23,6 +23,17 @@ import { Preset } from './utils/preset/preset';
2323import { cloneTemplate } from './utils/template/clone-template' ;
2424import { execAndWait } from './utils/child-process-utils' ;
2525
26+ // State for SIGINT handler - only set after workspace is fully installed
27+ let workspaceDirectory : string | undefined ;
28+ let cloudConnectUrl : string | undefined ;
29+
30+ export function getInterruptedWorkspaceState ( ) : {
31+ directory : string | undefined ;
32+ connectUrl : string | undefined ;
33+ } {
34+ return { directory : workspaceDirectory , connectUrl : cloudConnectUrl } ;
35+ }
36+
2637export async function createWorkspace < T extends CreateWorkspaceOptions > (
2738 preset : string ,
2839 options : T ,
@@ -67,6 +78,9 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
6778 // Install dependencies (template flow always uses npm)
6879 await execAndWait ( 'npm install --silent --ignore-scripts' , directory ) ;
6980
81+ // Mark workspace as ready for SIGINT handler
82+ workspaceDirectory = directory ;
83+
7084 workspaceSetupSpinner . succeed (
7185 `Successfully created the workspace: ${ directory } `
7286 ) ;
@@ -95,6 +109,9 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
95109 workspaceGlobs,
96110 } ) ;
97111
112+ // Mark workspace as ready for SIGINT handler
113+ workspaceDirectory = directory ;
114+
98115 // If the preset is a third-party preset, we need to call createPreset to install it
99116 // For first-party presets, it will be created by createEmptyWorkspace instead.
100117 // In createEmptyWorkspace, it will call `nx new` -> `@nx/workspace newGenerator` -> `@nx/workspace generatePreset`.
@@ -111,29 +128,16 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
111128
112129 const isTemplate = ! ! options . template ;
113130
114- let connectUrl : string | undefined ;
115- let nxCloudInfo : string | undefined ;
116- if ( nxCloud !== 'skip' ) {
117- const token = readNxCloudToken ( directory ) as string ;
118-
119- // Only generate CI for preset flow (not template)
120- if ( ! isTemplate && nxCloud !== 'yes' ) {
121- await setupCI ( directory , nxCloud , packageManager ) ;
122- }
123-
124- connectUrl = await createNxCloudOnboardingUrl (
125- nxCloud ,
126- token ,
127- directory ,
128- useGitHub
129- ) ;
131+ // Only generate CI for preset flow (not template)
132+ if ( nxCloud !== 'skip' && ! isTemplate && nxCloud !== 'yes' ) {
133+ await setupCI ( directory , nxCloud , packageManager ) ;
130134 }
131135
132136 let pushedToVcs = VcsPushStatus . SkippedGit ;
133137
134138 if ( ! skipGit ) {
135139 try {
136- await initializeGitRepo ( directory , { defaultBase, commit, connectUrl } ) ;
140+ await initializeGitRepo ( directory , { defaultBase, commit } ) ;
137141
138142 // Push to GitHub if commit was made, GitHub push is not skipped, and:
139143 // - CI provider is GitHub (preset flow), OR
@@ -162,7 +166,22 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
162166 }
163167 }
164168
165- if ( connectUrl ) {
169+ // Create onboarding URL AFTER git operations so getVcsRemoteInfo() can detect the repo
170+ let connectUrl : string | undefined ;
171+ let nxCloudInfo : string | undefined ;
172+ if ( nxCloud !== 'skip' ) {
173+ const token = readNxCloudToken ( directory ) as string ;
174+
175+ connectUrl = await createNxCloudOnboardingUrl (
176+ nxCloud ,
177+ token ,
178+ directory ,
179+ useGitHub
180+ ) ;
181+
182+ // Store for SIGINT handler
183+ cloudConnectUrl = connectUrl ;
184+
166185 nxCloudInfo = await getNxCloudInfo (
167186 connectUrl ,
168187 pushedToVcs ,
0 commit comments