@@ -6,66 +6,94 @@ import { runGit } from '../../utils/run-git.js'
66import { startSpinner } from '../../lib/spinner.js'
77import BaseCommand from '../base-command.js'
88
9- interface MockHashDecodeResult {
10- siteId ? : string
11- repoUrl ?: string
12- targetDir ?: string
13- branch ?: string
9+ // Decode hash to get the encoded URL
10+ const decodeHash = ( hash : string ) : string => {
11+ // In real implementation, this would decode the hash to get the actual URL
12+ // For now, return a mock URL
13+ return 'https://api.netlify.com/api/v1/ai/projects/mock-endpoint'
1414}
1515
16- // Mock hash decoding - in real implementation this would decode the actual hash
17- const mockDecodeHash = ( hash : string ) : MockHashDecodeResult => {
18- // Mock: If hash starts with 'site_', treat it as a site ID
19- // Otherwise, treat it as a direct repo URL
20- if ( hash . startsWith ( 'site_' ) ) {
21- return {
22- siteId : hash . replace ( 'site_' , '' ) ,
23- targetDir : `ai-project-${ hash . substring ( 0 , 8 ) } ` ,
24- branch : 'main'
25- }
26- } else {
16+ interface ProjectInfo {
17+ success : boolean
18+ projectId : string
19+ aiInstructions : string
20+ }
21+
22+ // Call the decoded URL to get project information
23+ const fetchProjectInfo = async ( url : string , authToken : string ) : Promise < ProjectInfo > => {
24+ try {
25+ // Mock response for now - in real implementation, fetch from the decoded URL
26+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) )
27+
28+ // Mock response with project ID and AI instructions (no repository URL)
2729 return {
28- repoUrl : 'https://github.com/netlify/netlify-cli.git' , // Mock repo
29- targetDir : `ai-project-${ hash . substring ( 0 , 8 ) } ` ,
30- branch : 'main'
30+ success : true ,
31+ projectId : '4d6c8c75-2278-409e-bcb7-06e07b79e1bc' ,
32+ aiInstructions : `# AI Project Instructions
33+
34+ This is your AI-powered project setup guide.
35+
36+ ## Getting Started
37+
38+ 1. Review the project structure
39+ 2. Install dependencies: \`npm install\`
40+ 3. Start development: \`netlify dev\`
41+ 4. Deploy your project: \`netlify deploy\`
42+
43+ ## AI Features
44+
45+ - Automated code analysis
46+ - Smart deployment optimizations
47+ - Performance monitoring
48+ - Error detection and suggestions
49+
50+ ## Next Steps
51+
52+ - Configure your build settings
53+ - Set up environment variables
54+ - Explore the AI dashboard for insights
55+
56+ Happy coding! 🚀`
3157 }
58+ } catch ( error ) {
59+ throw new Error ( `Failed to fetch project information: ${ error instanceof Error ? error . message : 'Unknown error' } ` )
3260 }
3361}
3462
35- // Get repository URL from site ID using existing API functionality
36- const getRepoUrlFromSiteId = async ( api : any , siteId : string ) : Promise < string > => {
63+ // Get repository URL from project ID using existing site API functionality
64+ const getRepoUrlFromProjectId = async ( api : any , projectId : string ) : Promise < string > => {
3765 try {
38- const siteData = await api . getSite ( { siteId } )
66+ // Use project ID as site ID to get site data
67+ const siteData = await api . getSite ( { siteId : projectId } )
3968
4069 const repoUrl = siteData . build_settings ?. repo_url
4170
4271 if ( ! repoUrl ) {
43- throw new Error ( `No repository URL found for site ID: ${ siteId } ` )
72+ throw new Error ( `No repository URL found for project ID: ${ projectId } ` )
4473 }
4574
4675 return repoUrl
4776
4877 } catch ( error : any ) {
4978 if ( error . status === 404 ) {
50- throw new Error ( `Project with ID ${ siteId } not found` )
79+ throw new Error ( `Project with ID ${ projectId } not found` )
5180 }
5281 throw new Error ( `Failed to fetch project data: ${ error . message } ` )
5382 }
5483}
5584
56- // Mock server response for now
57- const mockServerRequest = async ( hash : string , _authToken : string ) => {
58- // Simulate API call delay
59- await new Promise ( resolve => setTimeout ( resolve , 1500 ) )
85+ // Save AI instructions to markdown file
86+ const saveAiInstructions = async ( instructions : string , targetDir : string ) : Promise < void > => {
87+ const fs = await import ( 'node:fs/promises' )
88+ const path = await import ( 'node:path' )
6089
61- // Mock successful response
62- return {
63- success : true ,
64- message : 'AI project initialization started successfully' ,
65- projectId : '4d6c8c75-2278-409e-bcb7-06e07b79e1bc' ,
66- status : 'processing' ,
67- estimatedTime : '2-3 minutes' ,
68- dashboardUrl : `https://app.netlify.com/ai/projects/proj_${ hash . substring ( 0 , 8 ) } `
90+ try {
91+ const filePath = path . resolve ( targetDir , 'AI-instructions.md' )
92+ await fs . writeFile ( filePath , instructions , 'utf-8' )
93+ log ( `${ chalk . green ( '✅' ) } AI instructions saved to ${ chalk . cyan ( 'AI-instructions.md' ) } ` )
94+ } catch ( error ) {
95+ const errorMessage = error instanceof Error ? error . message : 'Unknown error'
96+ log ( `${ chalk . yellow ( '⚠️' ) } Warning: Failed to save AI instructions: ${ errorMessage } ` )
6997 }
7098}
7199
@@ -96,43 +124,44 @@ export const aiStartCommand = async (options: OptionValues, command: BaseCommand
96124 log ( `${ chalk . gray ( 'Hash:' ) } ${ hash } ` )
97125 log ( `${ chalk . gray ( 'User:' ) } ${ api . accessToken ? 'Authenticated ✅' : 'Not authenticated ❌' } ` )
98126
99- // Step 1: Decode hash to get repository information
127+ // Step 1: Decode hash and fetch project information
100128 log ( '\n📋 Decoding project hash...' )
101- const hashResult = mockDecodeHash ( hash )
102-
103- let finalRepoUrl : string
129+ const decodedUrl = decodeHash ( hash )
130+ log ( `${ chalk . cyan ( 'Decoded URL:' ) } ${ decodedUrl } ` )
104131
105- // Step 1a: If hash contains site ID, fetch repository URL from Netlify API
106- if ( hashResult . siteId ) {
107- log ( `${ chalk . cyan ( 'Site ID:' ) } ${ hashResult . siteId } ` )
108- log ( '🔍 Fetching repository information from Netlify...' )
109-
110- try {
111- finalRepoUrl = await getRepoUrlFromSiteId ( api , hashResult . siteId )
112- log ( `${ chalk . cyan ( 'Repository:' ) } ${ finalRepoUrl } ` )
113- } catch ( error ) {
114- const errorMessage = error instanceof Error ? error . message : 'Unknown error'
115- log ( chalk . red ( '❌ Error:' ) , errorMessage )
116- return
117- }
118- } else if ( hashResult . repoUrl ) {
119- // Direct repository URL provided
120- finalRepoUrl = hashResult . repoUrl
121- log ( `${ chalk . cyan ( 'Repository:' ) } ${ finalRepoUrl } ` )
122- } else {
123- log ( chalk . red ( '❌ Error: No repository information found in hash' ) )
132+ log ( '\n🔍 Fetching project information...' )
133+ let projectInfo : ProjectInfo
134+ try {
135+ projectInfo = await fetchProjectInfo ( decodedUrl , api . accessToken ?? '' )
136+ } catch ( error ) {
137+ const errorMessage = error instanceof Error ? error . message : 'Unknown error'
138+ log ( chalk . red ( '❌ Error:' ) , errorMessage )
124139 return
125140 }
126-
127- log ( ` ${ chalk . cyan ( 'Target Directory:' ) } ${ hashResult . targetDir ?? 'auto-generated' } ` )
128- if ( hashResult . branch ) {
129- log ( ` ${ chalk . cyan ( 'Branch:' ) } ${ hashResult . branch } ` )
141+
142+ if ( ! projectInfo . success ) {
143+ log ( chalk . red ( '❌ Failed to fetch project information' ) )
144+ return
130145 }
131146
132- // Step 2: Clone repository using existing functionality
147+ log ( `${ chalk . cyan ( 'Project ID:' ) } ${ projectInfo . projectId } ` )
148+
149+ // Step 2: Get repository URL from project ID via Netlify site API
150+ log ( '\n🔗 Linking to Netlify site and fetching repository...' )
151+ let repositoryUrl : string
133152 try {
134- const { repoUrl, repoName } = normalizeRepoUrl ( finalRepoUrl )
135- const targetDir = hashResult . targetDir ?? `ai-project-${ repoName } -${ hash . substring ( 0 , 8 ) } `
153+ repositoryUrl = await getRepoUrlFromProjectId ( api , projectInfo . projectId )
154+ log ( `${ chalk . cyan ( 'Repository:' ) } ${ repositoryUrl } ` )
155+ } catch ( error ) {
156+ const errorMessage = error instanceof Error ? error . message : 'Unknown error'
157+ log ( chalk . red ( '❌ Error:' ) , errorMessage )
158+ return
159+ }
160+
161+ // Step 3: Clone repository using existing functionality
162+ try {
163+ const { repoUrl, repoName } = normalizeRepoUrl ( repositoryUrl )
164+ const targetDir = `ai-project-${ repoName } -${ hash . substring ( 0 , 8 ) } `
136165
137166 const cloneSpinner = startSpinner ( { text : `Cloning repository to ${ chalk . cyan ( targetDir ) } ` } )
138167
@@ -148,36 +177,37 @@ export const aiStartCommand = async (options: OptionValues, command: BaseCommand
148177 command . workingDir = targetDir
149178 process . chdir ( targetDir )
150179
151- // Step 3: Send request to AI server for project setup
152- log ( '\n🚀 Sending request to AI server...' )
153- const response = await mockServerRequest ( hash , api . accessToken ?? '' )
154-
155- if ( response . success ) {
156- log ( `\n${ chalk . green ( '✅ Success!' ) } ${ response . message } ` )
157- log ( `${ chalk . cyan ( 'Project ID:' ) } ${ response . projectId } ` )
158- log ( `${ chalk . cyan ( 'Status:' ) } ${ response . status } ` )
159- log ( `${ chalk . cyan ( 'Estimated Time:' ) } ${ response . estimatedTime } ` )
160-
161- if ( response . dashboardUrl ) {
162- log ( `${ chalk . cyan ( 'Dashboard:' ) } ${ response . dashboardUrl } ` )
163- }
164-
165- // Success message with next steps
166- log ( )
167- log ( chalk . green ( '✔ Your AI project is ready to go!' ) )
168- log ( `→ Project cloned to: ${ chalk . cyanBright ( targetDir ) } ` )
169- log ( )
170- log ( chalk . yellowBright ( `📁 Next: Enter your project directory` ) )
171- log ( ` ${ chalk . cyanBright ( `cd ${ targetDir } ` ) } ` )
172- log ( )
173- log ( `→ AI setup is processing in the background` )
174- log ( `→ Check progress at: ${ chalk . cyanBright ( response . dashboardUrl ) } ` )
175- log ( `→ Then you can run: ${ chalk . cyanBright ( 'netlify dev' ) } or ${ chalk . cyanBright ( 'netlify deploy' ) } ` )
176- log ( )
180+ // Step 4: Save AI instructions to file
181+ if ( projectInfo . aiInstructions ) {
182+ log ( '\n📝 Saving AI instructions...' )
183+ // Use command working directory which is now set to the cloned repo
184+ await saveAiInstructions ( projectInfo . aiInstructions , command . workingDir )
185+ }
177186
178- } else {
179- log ( chalk . red ( '❌ Failed to start AI project' ) )
187+ // Success message with next steps
188+ log ( )
189+ log ( chalk . green ( '✔ Your AI project is ready to go!' ) )
190+ log ( `→ Project ID: ${ chalk . cyanBright ( projectInfo . projectId ) } ` )
191+ log ( `→ Project cloned to: ${ chalk . cyanBright ( targetDir ) } ` )
192+ if ( projectInfo . aiInstructions ) {
193+ log ( `→ AI instructions saved: ${ chalk . cyanBright ( 'AI-instructions.md' ) } ` )
194+ }
195+ log ( )
196+ log ( chalk . yellowBright ( `📁 Step 1: Enter your project directory` ) )
197+ log ( ` ${ chalk . cyanBright ( `cd ${ targetDir } ` ) } ` )
198+ log ( )
199+ if ( projectInfo . aiInstructions ) {
200+ log ( chalk . yellowBright ( `🤖 Step 2: Ask your AI assistant to process the instructions` ) )
201+ log ( ` ${ chalk . gray ( 'Tell your AI:' ) } ${ chalk . cyanBright ( '"Please read and follow the AI-instructions.md file"' ) } ` )
202+ log ( )
180203 }
204+ log ( chalk . yellowBright ( `🚀 Step 3: Start development` ) )
205+ log ( ` ${ chalk . cyanBright ( 'netlify dev' ) } ${ chalk . gray ( '- Start local development server' ) } ` )
206+ log ( ` ${ chalk . cyanBright ( 'netlify deploy' ) } ${ chalk . gray ( '- Deploy your project' ) } ` )
207+ log ( )
208+ log ( chalk . gray ( `💡 Pro tip: Your AI assistant can help you understand and implement` ) )
209+ log ( chalk . gray ( ` the project-specific instructions in AI-instructions.md` ) )
210+ log ( )
181211
182212 } catch ( error ) {
183213 const errorMessage = error instanceof Error ? error . message : 'Unknown error occurred'
0 commit comments