Skip to content

Commit 1e31e7d

Browse files
committed
improve codestyle
1 parent 8edaf5f commit 1e31e7d

File tree

1 file changed

+67
-126
lines changed

1 file changed

+67
-126
lines changed

src/commands/ai/ai-start.ts

Lines changed: 67 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,74 @@
1-
import { OptionValues } from 'commander'
1+
import type { OptionValues } from 'commander'
2+
import { resolve } from 'node:path'
3+
import { promises as fs } from 'node:fs'
4+
import type { NetlifyAPI } from '@netlify/api'
25

3-
import { chalk, log, logAndThrowError } from '../../utils/command-helpers.js'
6+
import { chalk, log, logAndThrowError, type APIError } from '../../utils/command-helpers.js'
47
import { normalizeRepoUrl } from '../../utils/normalize-repo-url.js'
58
import { runGit } from '../../utils/run-git.js'
69
import { startSpinner } from '../../lib/spinner.js'
7-
import BaseCommand from '../base-command.js'
8-
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-
}
10+
import type BaseCommand from '../base-command.js'
11+
import type { SiteInfo } from '../../utils/types.js'
1512

1613
interface ProjectInfo {
1714
success: boolean
1815
projectId: string
19-
aiInstructions: string
16+
prompt: string
2017
}
2118

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)
29-
return {
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
19+
interface AIStartOptions extends OptionValues {
20+
debug?: boolean
21+
}
5122

52-
- Configure your build settings
53-
- Set up environment variables
54-
- Explore the AI dashboard for insights
23+
// Move helper functions to a separate utils file
24+
const decodeHash = (hash: string): string => {
25+
try {
26+
return atob(hash)
27+
} catch (error) {
28+
throw new Error(`Failed to decode hash: ${error instanceof Error ? error.message : 'Invalid base64 or URL'}`)
29+
}
30+
}
5531

56-
Happy coding! 🚀`
32+
const fetchProjectInfo = async (url: string): Promise<ProjectInfo> => {
33+
try {
34+
const response = await fetch(url, {
35+
headers: {
36+
'content-type': 'text/plain',
37+
},
38+
})
39+
40+
if (!response.ok) {
41+
throw new Error(`HTTP error! status: ${String(response.status)}`)
5742
}
43+
const data = (await response.text()) as unknown as string
44+
const parsedData = JSON.parse(data) as unknown as ProjectInfo
45+
return parsedData
5846
} catch (error) {
5947
throw new Error(`Failed to fetch project information: ${error instanceof Error ? error.message : 'Unknown error'}`)
6048
}
6149
}
6250

63-
// Get repository URL from project ID using existing site API functionality
64-
const getRepoUrlFromProjectId = async (api: any, projectId: string): Promise<string> => {
51+
const getRepoUrlFromProjectId = async (api: NetlifyAPI, projectId: string): Promise<string> => {
6552
try {
66-
// Use project ID as site ID to get site data
67-
const siteData = await api.getSite({ siteId: projectId })
68-
69-
const repoUrl = siteData.build_settings?.repo_url
70-
53+
const SiteInfo = (await api.getSite({ siteId: projectId })) as SiteInfo
54+
const repoUrl = SiteInfo.build_settings?.repo_url
55+
7156
if (!repoUrl) {
7257
throw new Error(`No repository URL found for project ID: ${projectId}`)
7358
}
74-
59+
7560
return repoUrl
76-
77-
} catch (error: any) {
78-
if (error.status === 404) {
61+
} catch (error) {
62+
if ((error as APIError).status === 404) {
7963
throw new Error(`Project with ID ${projectId} not found`)
8064
}
81-
throw new Error(`Failed to fetch project data: ${error.message}`)
65+
throw new Error(`Failed to fetch project data: ${(error as Error).message}`)
8266
}
8367
}
8468

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')
89-
69+
const saveprompt = async (instructions: string, targetDir: string): Promise<void> => {
9070
try {
91-
const filePath = path.resolve(targetDir, 'AI-instructions.md')
71+
const filePath = resolve(targetDir, 'AI-instructions.md')
9272
await fs.writeFile(filePath, instructions, 'utf-8')
9373
log(`${chalk.green('✅')} AI instructions saved to ${chalk.cyan('AI-instructions.md')}`)
9474
} catch (error) {
@@ -105,7 +85,7 @@ const cloneRepo = async (repoUrl: string, targetDir: string, debug: boolean): Pr
10585
}
10686
}
10787

108-
export const aiStartCommand = async (options: OptionValues, command: BaseCommand) => {
88+
export const aiStartCommand = async (options: AIStartOptions, command: BaseCommand): Promise<void> => {
10989
const hash = command.args[0]
11090

11191
// Validate hash parameter
@@ -115,104 +95,65 @@ export const aiStartCommand = async (options: OptionValues, command: BaseCommand
11595
return
11696
}
11797

118-
// Check authentication - this will automatically handle login if needed
98+
// Authenticate first before any API operations
11999
await command.authenticate()
120-
121100
const { api } = command.netlify
122101

123102
log(`${chalk.blue('🤖 AI Start')} - Initializing AI project...`)
124103
log(`${chalk.gray('Hash:')} ${hash}`)
125104
log(`${chalk.gray('User:')} ${api.accessToken ? 'Authenticated ✅' : 'Not authenticated ❌'}`)
126105

127-
// Step 1: Decode hash and fetch project information
128-
log('\n📋 Decoding project hash...')
129-
const decodedUrl = decodeHash(hash)
130-
log(`${chalk.cyan('Decoded URL:')} ${decodedUrl}`)
131-
132-
log('\n🔍 Fetching project information...')
133-
let projectInfo: ProjectInfo
134106
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)
139-
return
140-
}
107+
// Step 1: Decode hash and fetch project information
108+
log('\n📋 Decoding project hash...')
109+
const decodedUrl = decodeHash(hash)
110+
log(`${chalk.cyan('Decoded URL:')} ${decodedUrl}`)
141111

142-
if (!projectInfo.success) {
143-
log(chalk.red('❌ Failed to fetch project information'))
144-
return
145-
}
112+
log('\n🔍 Fetching project information...')
113+
const projectInfo = await fetchProjectInfo(decodedUrl)
146114

147-
log(`${chalk.cyan('Project ID:')} ${projectInfo.projectId}`)
115+
log(`${chalk.cyan('Project ID:')} ${projectInfo.projectId}`)
148116

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
152-
try {
153-
repositoryUrl = await getRepoUrlFromProjectId(api, projectInfo.projectId)
117+
// Step 2: Get repository URL from project ID via Netlify site API
118+
log('\n🔗 Linking to Netlify site and fetching repository...')
119+
const repositoryUrl = await getRepoUrlFromProjectId(api, projectInfo.projectId)
154120
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-
}
160121

161-
// Step 3: Clone repository using existing functionality
162-
try {
122+
// Step 3: Clone repository
163123
const { repoUrl, repoName } = normalizeRepoUrl(repositoryUrl)
164124
const targetDir = `ai-project-${repoName}-${hash.substring(0, 8)}`
165125

166126
const cloneSpinner = startSpinner({ text: `Cloning repository to ${chalk.cyan(targetDir)}` })
167-
168-
try {
169-
await cloneRepo(repoUrl, targetDir, Boolean(options.debug))
170-
cloneSpinner.success({ text: `Cloned repository to ${chalk.cyan(targetDir)}` })
171-
} catch (error) {
172-
cloneSpinner.error()
173-
return logAndThrowError(error)
174-
}
175127

176-
// Update working directory to cloned repo
177-
command.workingDir = targetDir
178-
process.chdir(targetDir)
128+
await cloneRepo(repoUrl, targetDir, Boolean(options.debug))
129+
cloneSpinner.success({ text: `Cloned repository to ${chalk.cyan(targetDir)}` })
179130

180131
// Step 4: Save AI instructions to file
181-
if (projectInfo.aiInstructions) {
132+
if (projectInfo.prompt) {
182133
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)
134+
await saveprompt(projectInfo.prompt, targetDir)
185135
}
186136

137+
// Update working directory to cloned repo
138+
process.chdir(targetDir)
139+
command.workingDir = targetDir
187140
// Success message with next steps
188141
log()
189142
log(chalk.green('✔ Your AI project is ready to go!'))
190143
log(`→ Project ID: ${chalk.cyanBright(projectInfo.projectId)}`)
191144
log(`→ Project cloned to: ${chalk.cyanBright(targetDir)}`)
192-
if (projectInfo.aiInstructions) {
145+
if (projectInfo.prompt) {
193146
log(`→ AI instructions saved: ${chalk.cyanBright('AI-instructions.md')}`)
194147
}
195148
log()
196149
log(chalk.yellowBright(`📁 Step 1: Enter your project directory`))
197150
log(` ${chalk.cyanBright(`cd ${targetDir}`)}`)
198151
log()
199-
if (projectInfo.aiInstructions) {
152+
if (projectInfo.prompt) {
200153
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()
154+
log(` ${chalk.cyanBright(`follow instructions in ${targetDir}/AI-instructions.md`)}`)
203155
}
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()
211-
212156
} catch (error) {
213-
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'
214-
215-
log(chalk.red('❌ Error:'), errorMessage)
216-
log(chalk.gray('Please try again or contact support if the issue persists.'))
157+
return logAndThrowError(error)
217158
}
218-
}
159+
}

0 commit comments

Comments
 (0)