@@ -6,66 +6,94 @@ import { runGit } from '../../utils/run-git.js'
6
6
import { startSpinner } from '../../lib/spinner.js'
7
7
import BaseCommand from '../base-command.js'
8
8
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'
14
14
}
15
15
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)
27
29
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! 🚀`
31
57
}
58
+ } catch ( error ) {
59
+ throw new Error ( `Failed to fetch project information: ${ error instanceof Error ? error . message : 'Unknown error' } ` )
32
60
}
33
61
}
34
62
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 > => {
37
65
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 } )
39
68
40
69
const repoUrl = siteData . build_settings ?. repo_url
41
70
42
71
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 } ` )
44
73
}
45
74
46
75
return repoUrl
47
76
48
77
} catch ( error : any ) {
49
78
if ( error . status === 404 ) {
50
- throw new Error ( `Project with ID ${ siteId } not found` )
79
+ throw new Error ( `Project with ID ${ projectId } not found` )
51
80
}
52
81
throw new Error ( `Failed to fetch project data: ${ error . message } ` )
53
82
}
54
83
}
55
84
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' )
60
89
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 } ` )
69
97
}
70
98
}
71
99
@@ -96,43 +124,44 @@ export const aiStartCommand = async (options: OptionValues, command: BaseCommand
96
124
log ( `${ chalk . gray ( 'Hash:' ) } ${ hash } ` )
97
125
log ( `${ chalk . gray ( 'User:' ) } ${ api . accessToken ? 'Authenticated ✅' : 'Not authenticated ❌' } ` )
98
126
99
- // Step 1: Decode hash to get repository information
127
+ // Step 1: Decode hash and fetch project information
100
128
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 } ` )
104
131
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 )
124
139
return
125
140
}
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
130
145
}
131
146
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
133
152
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 ) } `
136
165
137
166
const cloneSpinner = startSpinner ( { text : `Cloning repository to ${ chalk . cyan ( targetDir ) } ` } )
138
167
@@ -148,36 +177,37 @@ export const aiStartCommand = async (options: OptionValues, command: BaseCommand
148
177
command . workingDir = targetDir
149
178
process . chdir ( targetDir )
150
179
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
+ }
177
186
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 ( )
180
203
}
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 ( )
181
211
182
212
} catch ( error ) {
183
213
const errorMessage = error instanceof Error ? error . message : 'Unknown error occurred'
0 commit comments