1
- import type { OptionValues } from 'commander'
2
1
import { resolve } from 'node:path'
3
2
import { promises as fs } from 'node:fs'
4
3
import type { NetlifyAPI } from '@netlify/api'
@@ -7,11 +6,11 @@ import { chalk, log, logAndThrowError, type APIError } from '../../utils/command
7
6
import { normalizeRepoUrl } from '../../utils/normalize-repo-url.js'
8
7
import { runGit } from '../../utils/run-git.js'
9
8
import { startSpinner } from '../../lib/spinner.js'
10
- import type BaseCommand from '../base-command.js'
11
- import type { SiteInfo } from '../../utils/types.js'
12
9
import { getContextConsumers , type ConsumerConfig } from '../../recipes/ai-context/context.js'
13
10
import execa from '../../utils/execa.js'
14
11
import { version } from '../../utils/command-helpers.js'
12
+ import type BaseCommand from '../base-command.js'
13
+ import type { SiteInfo } from '../../utils/types.js'
15
14
import inquirer from 'inquirer'
16
15
17
16
interface ProjectInfo {
@@ -20,10 +19,6 @@ interface ProjectInfo {
20
19
prompt : string
21
20
}
22
21
23
- interface AIStartOptions extends OptionValues {
24
- debug ?: boolean
25
- }
26
-
27
22
// Check if a command belongs to a known IDE (reusing ai-context logic)
28
23
const getConsumerKeyFromCommand = ( command : string , consumers : ConsumerConfig [ ] ) : string | null => {
29
24
const match = consumers . find (
@@ -143,50 +138,6 @@ const generateMcpConfig = (ide: ConsumerConfig): string => {
143
138
)
144
139
}
145
140
146
- // Trigger IDE-specific MCP configuration
147
- const triggerMcpConfiguration = async ( ide : ConsumerConfig , projectPath : string ) : Promise < boolean > => {
148
- log ( `\n${ chalk . blue ( '🔧 MCP Configuration for' ) } ${ chalk . cyan ( ide . presentedName ) } ` )
149
-
150
- const { shouldConfigure } = await inquirer . prompt < { shouldConfigure : boolean } > ( [
151
- {
152
- type : 'confirm' ,
153
- name : 'shouldConfigure' ,
154
- message : `Would you like to automatically configure MCP server for ${ ide . presentedName } ?` ,
155
- default : true ,
156
- } ,
157
- ] )
158
-
159
- if ( ! shouldConfigure ) {
160
- log ( chalk . gray ( 'Skipped MCP configuration. You can set it up manually later.' ) )
161
- return false
162
- }
163
-
164
- try {
165
- const config = generateMcpConfig ( ide )
166
-
167
- // IDE-specific configuration actions
168
- switch ( ide . key ) {
169
- case 'vscode' :
170
- await configureMcpForVSCode ( config , projectPath )
171
- break
172
- case 'cursor' :
173
- await configureMcpForCursor ( config , projectPath )
174
- break
175
- case 'windsurf' :
176
- await configureMcpForWindsurf ( config , projectPath )
177
- break
178
- default :
179
- showGenericMcpConfig ( config , ide . presentedName )
180
- }
181
-
182
- log ( `${ chalk . green ( '✅' ) } MCP configuration completed for ${ chalk . cyan ( ide . presentedName ) } ` )
183
- return true
184
- } catch ( error ) {
185
- log ( `${ chalk . red ( '❌' ) } Failed to configure MCP: ${ error instanceof Error ? error . message : 'Unknown error' } ` )
186
- return false
187
- }
188
- }
189
-
190
141
// VS Code specific MCP configuration
191
142
const configureMcpForVSCode = async ( config : string , projectPath : string ) : Promise < void > => {
192
143
const configPath = resolve ( projectPath , '.vscode' , 'mcp.json' )
@@ -276,79 +227,51 @@ const showGenericMcpConfig = (config: string, ideName: string): void => {
276
227
log ( `${ chalk . gray ( '--- End Configuration ---' ) } \n` )
277
228
}
278
229
279
- // Try to automatically activate MCP in the detected IDE
280
- const tryActivateMcp = async ( ide : ConsumerConfig , projectPath : string ) : Promise < boolean > => {
230
+ // Trigger IDE-specific MCP configuration
231
+ const triggerMcpConfiguration = async ( ide : ConsumerConfig , projectPath : string ) : Promise < boolean > => {
232
+ log ( `\n${ chalk . blue ( '🔧 MCP Configuration for' ) } ${ chalk . cyan ( ide . presentedName ) } ` )
233
+
234
+ const { shouldConfigure } = await inquirer . prompt < { shouldConfigure : boolean } > ( [
235
+ {
236
+ type : 'confirm' ,
237
+ name : 'shouldConfigure' ,
238
+ message : `Would you like to automatically configure MCP server for ${ ide . presentedName } ?` ,
239
+ default : true ,
240
+ } ,
241
+ ] )
242
+
243
+ if ( ! shouldConfigure ) {
244
+ log ( chalk . gray ( 'Skipped MCP configuration. You can set it up manually later.' ) )
245
+ return false
246
+ }
247
+
281
248
try {
249
+ const config = generateMcpConfig ( ide )
250
+
251
+ // IDE-specific configuration actions
282
252
switch ( ide . key ) {
283
253
case 'vscode' :
284
- return await activateMcpInVSCode ( projectPath )
254
+ await configureMcpForVSCode ( config , projectPath )
255
+ break
285
256
case 'cursor' :
286
- return await activateMcpInCursor ( projectPath )
257
+ await configureMcpForCursor ( config , projectPath )
258
+ break
287
259
case 'windsurf' :
288
- return await activateMcpInWindsurf ( projectPath )
260
+ await configureMcpForWindsurf ( config , projectPath )
261
+ break
289
262
default :
290
- return false
291
- }
292
- } catch ( _ ) {
293
- // Silent fail - activation is best effort
294
- return false
295
- }
296
- }
297
-
298
- // Activate MCP in VS Code
299
- const activateMcpInVSCode = async ( projectPath : string ) : Promise < boolean > => {
300
- try {
301
- // Try to reload VS Code window via command palette
302
- // This uses VS Code's command line interface
303
- await execa ( 'code' , [ '--command' , 'workbench.action.reloadWindow' ] , {
304
- cwd : projectPath ,
305
- timeout : 5000 ,
306
- } )
307
- return true
308
- } catch {
309
- // Try alternative: send reload command via VS Code extension API
310
- try {
311
- await execa ( 'code' , [ '--command' , 'developer.reloadWindow' ] , {
312
- cwd : projectPath ,
313
- timeout : 5000 ,
314
- } )
315
- return true
316
- } catch {
317
- return false
263
+ showGenericMcpConfig ( config , ide . presentedName )
318
264
}
319
- }
320
- }
321
265
322
- // Activate MCP in Cursor
323
- const activateMcpInCursor = async ( projectPath : string ) : Promise < boolean > => {
324
- try {
325
- // Cursor might support similar command line interface
326
- await execa ( 'cursor' , [ '--command' , 'workbench.action.reloadWindow' ] , {
327
- cwd : projectPath ,
328
- timeout : 5000 ,
329
- } )
330
- return true
331
- } catch {
332
- return false
333
- }
334
- }
335
-
336
- // Activate MCP in Windsurf
337
- const activateMcpInWindsurf = async ( projectPath : string ) : Promise < boolean > => {
338
- try {
339
- // Windsurf-specific activation (placeholder - would need actual API)
340
- // For now, try to signal the IDE to reload configuration
341
- await execa ( 'windsurf' , [ '--reload-config' ] , {
342
- cwd : projectPath ,
343
- timeout : 5000 ,
344
- } )
266
+ log ( `${ chalk . green ( '✅' ) } MCP configuration completed for ${ chalk . cyan ( ide . presentedName ) } ` )
345
267
return true
346
- } catch {
268
+ } catch ( error ) {
269
+ log ( `${ chalk . red ( '❌' ) } Failed to configure MCP: ${ error instanceof Error ? error . message : 'Unknown error' } ` )
347
270
return false
348
271
}
349
272
}
350
273
351
- // Move helper functions to a separate utils file
274
+ // Helper functions reused from ai-start.ts
352
275
const decodeHash = ( hash : string ) : string => {
353
276
try {
354
277
return atob ( hash )
@@ -413,21 +336,16 @@ const cloneRepo = async (repoUrl: string, targetDir: string, debug: boolean): Pr
413
336
}
414
337
}
415
338
416
- export const aiStartCommand = async ( options : AIStartOptions , command : BaseCommand ) : Promise < void > => {
417
- const hash = command . args [ 0 ]
418
-
419
- // Validate hash parameter
420
- if ( ! hash ) {
421
- log ( `${ chalk . red ( 'Error:' ) } Hash parameter is required` )
422
- log ( `${ chalk . gray ( 'Usage:' ) } netlify ai:start <hash>` )
423
- return
424
- }
425
-
339
+ /**
340
+ * Handles AI rules initialization workflow
341
+ * This is the experimental --ai-rules functionality for the init command
342
+ */
343
+ export const initWithAiRules = async ( hash : string , command : BaseCommand ) : Promise < void > => {
426
344
// Authenticate first before any API operations
427
345
await command . authenticate ( )
428
346
const { api } = command . netlify
429
347
430
- log ( `${ chalk . blue ( '🤖 AI Start ' ) } - Initializing AI project ...` )
348
+ log ( `${ chalk . blue ( '🤖 Initializing AI project ' ) } with rules ...` )
431
349
log ( `${ chalk . gray ( 'Hash:' ) } ${ hash } ` )
432
350
log ( `${ chalk . gray ( 'User:' ) } ${ api . accessToken ? 'Authenticated ✅' : 'Not authenticated ❌' } ` )
433
351
@@ -453,7 +371,7 @@ export const aiStartCommand = async (options: AIStartOptions, command: BaseComma
453
371
454
372
const cloneSpinner = startSpinner ( { text : `Cloning repository to ${ chalk . cyan ( targetDir ) } ` } )
455
373
456
- await cloneRepo ( repoUrl , targetDir , Boolean ( options . debug ) )
374
+ await cloneRepo ( repoUrl , targetDir , false )
457
375
cloneSpinner . success ( { text : `Cloned repository to ${ chalk . cyan ( targetDir ) } ` } )
458
376
459
377
// Step 4: Save AI instructions to file
@@ -475,6 +393,7 @@ export const aiStartCommand = async (options: AIStartOptions, command: BaseComma
475
393
// Update working directory to cloned repo
476
394
process . chdir ( targetDir )
477
395
command . workingDir = targetDir
396
+
478
397
// Success message with next steps
479
398
log ( )
480
399
log ( chalk . green ( '✔ Your AI project is ready to go!' ) )
@@ -486,25 +405,20 @@ export const aiStartCommand = async (options: AIStartOptions, command: BaseComma
486
405
log ( )
487
406
log ( chalk . yellowBright ( `📁 Step 1: Enter your project directory` ) )
488
407
log ( ` ${ chalk . cyanBright ( `cd ${ targetDir } ` ) } ` )
408
+
489
409
if ( detectedIDE ) {
490
410
if ( mcpConfigured ) {
491
411
log ( chalk . yellowBright ( `🔧 Step 2: MCP Server Configured` ) )
492
412
log ( ` ${ chalk . green ( '✅' ) } ${ chalk . cyan ( detectedIDE . presentedName ) } is ready with Netlify MCP server` )
493
-
494
- // Try to automatically activate MCP in the IDE
495
- const activated = await tryActivateMcp ( detectedIDE , targetDir )
496
- if ( activated ) {
497
- log ( ` ${ chalk . green ( '🚀' ) } MCP server automatically activated` )
498
- } else {
499
- log ( ` ${ chalk . gray ( '💡 MCP will activate when you reload/restart your IDE window' ) } ` )
500
- }
413
+ log ( ` ${ chalk . gray ( '💡 MCP will activate when you reload/restart your IDE window' ) } ` )
501
414
} else {
502
415
log ( chalk . yellowBright ( `🔧 Step 2: Manual MCP Configuration` ) )
503
416
log ( ` ${ chalk . cyan ( detectedIDE . presentedName ) } detected - MCP setup was skipped` )
504
417
log ( ` ${ chalk . gray ( 'You can configure MCP manually later for enhanced AI capabilities' ) } ` )
505
418
}
506
419
log ( )
507
420
}
421
+
508
422
if ( projectInfo . prompt ) {
509
423
const stepNumber = detectedIDE ? '3' : '2'
510
424
log ( chalk . yellowBright ( `🤖 Step ${ stepNumber } : Ask your AI assistant to process the instructions` ) )
@@ -515,4 +429,4 @@ export const aiStartCommand = async (options: AIStartOptions, command: BaseComma
515
429
} catch ( error ) {
516
430
return logAndThrowError ( error )
517
431
}
518
- }
432
+ }
0 commit comments