Skip to content

Commit 9e0514f

Browse files
committed
improvements
1 parent d50b455 commit 9e0514f

File tree

2 files changed

+53
-62
lines changed

2 files changed

+53
-62
lines changed

src/commands/init/ai-rules.ts

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@ import { resolve } from 'node:path'
22
import { promises as fs } from 'node:fs'
33
import type { NetlifyAPI } from '@netlify/api'
44

5-
import { chalk, log, logAndThrowError, type APIError } from '../../utils/command-helpers.js'
5+
import {
6+
chalk,
7+
log,
8+
logPadded,
9+
logAndThrowError,
10+
type APIError,
11+
NETLIFY_CYAN,
12+
NETLIFYDEVLOG,
13+
NETLIFYDEVWARN,
14+
NETLIFYDEVERR,
15+
} from '../../utils/command-helpers.js'
616
import { normalizeRepoUrl } from '../../utils/normalize-repo-url.js'
717
import { runGit } from '../../utils/run-git.js'
818
import { startSpinner } from '../../lib/spinner.js'
@@ -19,6 +29,10 @@ import type BaseCommand from '../base-command.js'
1929
import type { SiteInfo } from '../../utils/types.js'
2030
import inquirer from 'inquirer'
2131

32+
const SPARK_URL = process.env.SPARK_URL ?? 'https://spark.netlify.app'
33+
const AI_SITE_PROMPT_GEN_URL = `${SPARK_URL}/site-prompt-gen`
34+
const DOCS_URL = process.env.DOCS_URL ?? 'https://docs.netlify.com'
35+
2236
/**
2337
* Project information interface for AI projects
2438
*/
@@ -30,7 +44,7 @@ interface ProjectInfo {
3044

3145
// Trigger IDE-specific MCP configuration
3246
const triggerMcpConfiguration = async (ide: ConsumerConfig, projectPath: string): Promise<boolean> => {
33-
log(`\n${chalk.blue('🔧 MCP Configuration for')} ${chalk.cyan(ide.presentedName)}`)
47+
log(`\n${chalk.blue('🔧 MCP Configuration for')} ${NETLIFY_CYAN(ide.presentedName)}`)
3448

3549
const { shouldConfigure } = await inquirer.prompt<{ shouldConfigure: boolean }>([
3650
{
@@ -42,9 +56,9 @@ const triggerMcpConfiguration = async (ide: ConsumerConfig, projectPath: string)
4256
])
4357

4458
if (!shouldConfigure) {
45-
log(` ${chalk.gray('You can configure MCP manually later for enhanced AI capabilities:')}`)
59+
log(` ${chalk.dim('You can configure MCP manually later for enhanced AI capabilities:')}`)
4660
log(
47-
` ${chalk.gray('Documentation:')} ${chalk.cyan(
61+
` ${chalk.dim('Documentation:')} ${NETLIFY_CYAN(
4862
'https://docs.netlify.com/welcome/build-with-ai/netlify-mcp-server/',
4963
)}`,
5064
)
@@ -70,23 +84,14 @@ const triggerMcpConfiguration = async (ide: ConsumerConfig, projectPath: string)
7084
showGenericMcpConfig(config, ide.presentedName)
7185
}
7286

73-
log(`${chalk.green('✅')} MCP configuration completed for ${chalk.cyan(ide.presentedName)}`)
87+
log(`${NETLIFYDEVLOG} MCP configuration completed for ${NETLIFY_CYAN(ide.presentedName)}`)
7488
return true
7589
} catch (error) {
76-
log(`${chalk.red('❌')} Failed to configure MCP: ${error instanceof Error ? error.message : 'Unknown error'}`)
90+
log(`${NETLIFYDEVERR} Failed to configure MCP: ${error instanceof Error ? error.message : 'Unknown error'}`)
7791
return false
7892
}
7993
}
8094

81-
// Helper functions reused from ai-start.ts
82-
const decodeHash = (hash: string): string => {
83-
try {
84-
return atob(hash)
85-
} catch (error) {
86-
throw new Error(`Failed to decode hash: ${error instanceof Error ? error.message : 'Invalid base64 or URL'}`)
87-
}
88-
}
89-
9095
const fetchProjectInfo = async (url: string): Promise<ProjectInfo> => {
9196
try {
9297
const response = await fetch(url, {
@@ -125,10 +130,10 @@ const savePrompt = async (instructions: string, ntlContext: string | null, targe
125130
try {
126131
const filePath = resolve(targetDir, 'AI-instructions.md')
127132
await fs.writeFile(filePath, `Context: ${ntlContext ?? ''}\n\n${instructions}`, 'utf-8')
128-
log(`${chalk.green('✅')} AI instructions saved to ${chalk.cyan('AI-instructions.md')}`)
133+
log(`${NETLIFYDEVLOG} AI instructions saved to ${NETLIFY_CYAN('AI-instructions.md')}`)
129134
} catch (error) {
130135
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
131-
log(`${chalk.yellow('⚠️')} Warning: Failed to save AI instructions: ${errorMessage}`)
136+
log(`${NETLIFYDEVWARN} Warning: Failed to save AI instructions: ${errorMessage}`)
132137
}
133138
}
134139

@@ -149,45 +154,34 @@ export const initWithAiRules = async (hash: string, command: BaseCommand): Promi
149154
await command.authenticate()
150155
const { api } = command.netlify
151156

152-
log(`${chalk.blue('🤖 Initializing AI project')} with rules...`)
153-
log(`${chalk.gray('User:')} ${api.accessToken ? 'Authenticated ✅' : 'Not authenticated ❌'}`)
157+
log(`${NETLIFY_CYAN('🤖 Initializing AI project')} with rules...`)
158+
log(`${NETLIFY_CYAN('User:')} ${api.accessToken ? 'Authenticated ✅' : 'Not authenticated ❌'}`)
154159

155160
try {
156161
// Step 1: Decode hash and fetch project information
157162
log('\n📋 Extracting project details...')
158-
const decodedUrl = decodeHash(hash)
159-
log(`${chalk.cyan('Decoded URL:')} ${decodedUrl}`)
163+
const decodedUrl = `${AI_SITE_PROMPT_GEN_URL}/${hash}`
164+
log(`${NETLIFY_CYAN('Decoded URL:')} ${decodedUrl}`)
160165

161166
log('\n🔍 Fetching project information...')
162167
const projectInfo = await fetchProjectInfo(decodedUrl)
163168

164-
log(`${chalk.cyan('Project ID:')} ${projectInfo.projectId}`)
165-
166169
// Step 2: Get repository URL from project ID via Netlify site API
167170
log('\n🔗 Linking to Netlify project and fetching repository...')
168171
const repositoryUrl = await getRepoUrlFromProjectId(api, projectInfo.projectId)
169-
log(`${chalk.cyan('Repository:')} ${repositoryUrl}`)
170172

171173
// Step 3: Clone repository
172174
const { repoUrl, repoName } = normalizeRepoUrl(repositoryUrl)
173175
const targetDir = `ai-project-${repoName}-${hash.substring(0, 8)}`
174176

175-
const cloneSpinner = startSpinner({ text: `Cloning repository to ${chalk.cyan(targetDir)}` })
177+
const cloneSpinner = startSpinner({ text: `Cloning repository to ${NETLIFY_CYAN(targetDir)}` })
176178

177179
await cloneRepo(repoUrl, targetDir, false)
178-
cloneSpinner.success({ text: `Cloned repository to ${chalk.cyan(targetDir)}` })
180+
cloneSpinner.success({ text: `Cloned repository to ${NETLIFY_CYAN(targetDir)}` })
179181

180182
// Step 4: Save AI instructions to file
181183
if (projectInfo.prompt) {
182-
const ntlContext = await fetch(
183-
'https://docs.netlify.com/ai-context/scoped-context?scopes=serverless,blobs,forms',
184-
{
185-
method: 'GET',
186-
headers: {
187-
'Content-Type': 'text/plain',
188-
},
189-
},
190-
)
184+
const ntlContext = await fetch(`${DOCS_URL}/ai-context/scoped-context?scopes=serverless,blobs,forms`)
191185
.then((res) => res.text())
192186
.catch(() => {
193187
return null
@@ -202,7 +196,7 @@ export const initWithAiRules = async (hash: string, command: BaseCommand): Promi
202196
let mcpConfigured = false
203197

204198
if (detectedIDE) {
205-
log(`${chalk.green('✅')} Detected development environment: ${chalk.cyan(detectedIDE.presentedName)}`)
199+
log(`${NETLIFYDEVLOG} Detected development environment: ${NETLIFY_CYAN(detectedIDE.presentedName)}`)
206200
mcpConfigured = await triggerMcpConfiguration(detectedIDE, targetDir)
207201
}
208202

@@ -212,28 +206,27 @@ export const initWithAiRules = async (hash: string, command: BaseCommand): Promi
212206

213207
// Success message with next steps
214208
log()
215-
log(chalk.green('✔ Your AI project is ready to go!'))
216-
log(`→ Project ID: ${chalk.cyanBright(projectInfo.projectId)}`)
217-
log(`→ Project cloned to: ${chalk.cyanBright(targetDir)}`)
209+
log(`${NETLIFYDEVLOG} Your AI project is ready to go!`)
210+
log(`→ Project cloned to: ${NETLIFY_CYAN(targetDir)}`)
218211
if (projectInfo.prompt) {
219-
log(`→ AI instructions saved: ${chalk.cyanBright('AI-instructions.md')}`)
212+
log(`→ AI instructions saved: ${NETLIFY_CYAN('AI-instructions.md')}`)
220213
}
221214
log()
222-
log(chalk.yellowBright(`📁 Step 1: Enter your project directory`))
223-
log(` ${chalk.cyanBright(`cd ${targetDir}`)}`)
215+
log(`${NETLIFYDEVWARN} Step 1: Enter your project directory`)
216+
log(` ${NETLIFY_CYAN(`cd ${targetDir}`)}`)
224217

225218
if (detectedIDE) {
226219
if (mcpConfigured) {
227-
log(chalk.yellowBright(`🔧 Step 2: MCP Server Configured`))
228-
log(` ${chalk.green('✅')} ${chalk.cyan(detectedIDE.key)} is ready with Netlify MCP server`)
229-
log(` ${chalk.gray('💡 MCP will activate when you reload/restart your development environment')}`)
220+
log(`${NETLIFYDEVWARN} Step 2: MCP Server Configured`)
221+
log(` ${NETLIFYDEVLOG} ${NETLIFY_CYAN(detectedIDE.key)} is ready with Netlify MCP server`)
222+
log(` ${chalk.dim('💡 MCP will activate when you reload/restart your development environment')}`)
230223
} else {
231-
log(chalk.yellowBright(`🔧 Step 2: Manual MCP Configuration`))
232-
log(` ${chalk.cyan(detectedIDE.key)} detected - MCP setup was skipped`)
233-
log(` ${chalk.gray('You can configure MCP manually later for enhanced AI capabilities:')}`)
224+
log(`${NETLIFYDEVWARN} Step 2: Manual MCP Configuration`)
225+
log(` ${NETLIFY_CYAN(detectedIDE.key)} detected - MCP setup was skipped`)
226+
log(` ${chalk.dim('You can configure MCP manually later for enhanced AI capabilities:')}`)
234227
log(
235-
` ${chalk.gray('Documentation:')} ${chalk.cyan(
236-
'https://docs.netlify.com/welcome/build-with-ai/netlify-mcp-server/',
228+
` ${chalk.dim('Documentation:')} ${NETLIFY_CYAN(
229+
`${DOCS_URL}/welcome/build-with-ai/netlify-mcp-server/`,
237230
)}`,
238231
)
239232
}
@@ -242,11 +235,9 @@ export const initWithAiRules = async (hash: string, command: BaseCommand): Promi
242235

243236
if (projectInfo.prompt) {
244237
const stepNumber = detectedIDE ? '3' : '2'
245-
log(chalk.yellowBright(`🤖 Step ${stepNumber}: Ask your AI assistant to process the instructions`))
238+
log(`${NETLIFYDEVWARN} Step ${stepNumber}: Ask your AI assistant to process the instructions`)
246239
log()
247-
log(chalk.gray('*'.repeat(60)))
248-
log(chalk.cyan(`Follow ${targetDir}/AI-instructions.md and create a new site`))
249-
log(chalk.gray('*'.repeat(60)))
240+
logPadded(NETLIFY_CYAN(`Follow ${targetDir}/AI-instructions.md and create a new site`))
250241
log()
251242
}
252243
} catch (error) {

src/utils/mcp-utils.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { resolve } from 'node:path'
22
import { promises as fs } from 'node:fs'
33
import { homedir } from 'node:os'
4-
import { chalk, log } from './command-helpers.js'
4+
import { chalk, log, NETLIFY_CYAN, NETLIFYDEVLOG, NETLIFYDEVWARN } from './command-helpers.js'
55
import type { ConsumerConfig } from '../recipes/ai-context/context.js'
66

77
/**
@@ -71,7 +71,7 @@ export const configureMcpForVSCode = async (config: Record<string, unknown>, pro
7171
const updatedConfig = { ...existingConfig, ...config }
7272

7373
await fs.writeFile(configPath, JSON.stringify(updatedConfig, null, 2), 'utf-8')
74-
log(`${chalk.green('✅')} VS Code MCP configuration saved to ${chalk.cyan('.vscode/mcp.json')}`)
74+
log(`${NETLIFYDEVLOG} VS Code MCP configuration saved to ${NETLIFY_CYAN('.vscode/mcp.json')}`)
7575
} catch (error) {
7676
throw new Error(`Failed to configure VS Code MCP: ${error instanceof Error ? error.message : 'Unknown error'}`)
7777
}
@@ -86,7 +86,7 @@ export const configureMcpForCursor = async (config: Record<string, unknown>, pro
8686
try {
8787
await fs.mkdir(resolve(projectPath, '.cursor'), { recursive: true })
8888
await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8')
89-
log(`${chalk.green('✅')} Cursor MCP configuration saved to ${chalk.cyan('.cursor/mcp.json')}`)
89+
log(`${NETLIFYDEVLOG} Cursor MCP configuration saved to ${NETLIFY_CYAN('.cursor/mcp.json')}`)
9090
} catch (error) {
9191
throw new Error(`Failed to configure Cursor MCP: ${error instanceof Error ? error.message : 'Unknown error'}`)
9292
}
@@ -125,8 +125,8 @@ export const configureMcpForWindsurf = async (config: Record<string, unknown>, _
125125
}
126126

127127
await fs.writeFile(configPath, JSON.stringify(updatedConfig, null, 2), 'utf-8')
128-
log(`${chalk.green('✅')} Windsurf MCP configuration saved`)
129-
log(`${chalk.gray('💡')} Restart Windsurf to activate the MCP server`)
128+
log(`${NETLIFYDEVLOG} Windsurf MCP configuration saved`)
129+
log(`${chalk.dim('💡')} Restart Windsurf to activate the MCP server`)
130130
} catch (error) {
131131
throw new Error(`Failed to configure Windsurf MCP: ${error instanceof Error ? error.message : 'Unknown error'}`)
132132
}
@@ -136,9 +136,9 @@ export const configureMcpForWindsurf = async (config: Record<string, unknown>, _
136136
* Generic MCP configuration display
137137
*/
138138
export const showGenericMcpConfig = (config: Record<string, unknown>, ideName: string): void => {
139-
log(`\n${chalk.yellow('📋 Manual configuration required')}`)
139+
log(`\n${NETLIFYDEVWARN} Manual configuration required`)
140140
log(`Please add the following configuration to your ${ideName} settings:`)
141-
log(`\n${chalk.gray('--- Configuration ---')}`)
141+
log(`\n${chalk.dim('--- Configuration ---')}`)
142142
log(JSON.stringify(config, null, 2))
143-
log(`${chalk.gray('--- End Configuration ---')}\n`)
143+
log(`${chalk.dim('--- End Configuration ---')}\n`)
144144
}

0 commit comments

Comments
 (0)