Skip to content

Commit 614fe51

Browse files
committed
Add clone fucntionality
1 parent a403e15 commit 614fe51

File tree

1 file changed

+128
-12
lines changed

1 file changed

+128
-12
lines changed

β€Žsrc/commands/ai/ai-start.ts

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,83 @@
11
import { OptionValues } from 'commander'
22

3-
import { chalk, log } from '../../utils/command-helpers.js'
3+
import { chalk, log, logAndThrowError } from '../../utils/command-helpers.js'
4+
import { normalizeRepoUrl } from '../../utils/normalize-repo-url.js'
5+
import { runGit } from '../../utils/run-git.js'
6+
import { startSpinner } from '../../lib/spinner.js'
47
import BaseCommand from '../base-command.js'
58

9+
interface MockHashDecodeResult {
10+
siteId?: string
11+
repoUrl?: string
12+
targetDir?: string
13+
branch?: string
14+
}
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 {
27+
return {
28+
repoUrl: 'https://github.com/netlify/netlify-cli.git', // Mock repo
29+
targetDir: `ai-project-${hash.substring(0, 8)}`,
30+
branch: 'main'
31+
}
32+
}
33+
}
34+
35+
// Get repository URL from site ID using existing API functionality
36+
const getRepoUrlFromSiteId = async (api: any, siteId: string): Promise<string> => {
37+
try {
38+
const siteData = await api.getSite({ siteId })
39+
40+
const repoUrl = siteData.build_settings?.repo_url
41+
42+
if (!repoUrl) {
43+
throw new Error(`No repository URL found for site ID: ${siteId}`)
44+
}
45+
46+
return repoUrl
47+
48+
} catch (error: any) {
49+
if (error.status === 404) {
50+
throw new Error(`Project with ID ${siteId} not found`)
51+
}
52+
throw new Error(`Failed to fetch project data: ${error.message}`)
53+
}
54+
}
55+
656
// Mock server response for now
7-
const mockServerRequest = async (hash: string, authToken: string) => {
57+
const mockServerRequest = async (hash: string, _authToken: string) => {
858
// Simulate API call delay
959
await new Promise(resolve => setTimeout(resolve, 1500))
1060

1161
// Mock successful response
1262
return {
1363
success: true,
1464
message: 'AI project initialization started successfully',
15-
projectId: `proj_${hash.substring(0, 8)}`,
65+
projectId: '4d6c8c75-2278-409e-bcb7-06e07b79e1bc',
1666
status: 'processing',
1767
estimatedTime: '2-3 minutes',
1868
dashboardUrl: `https://app.netlify.com/ai/projects/proj_${hash.substring(0, 8)}`
1969
}
2070
}
2171

22-
export const aiStartCommand = async (_options: OptionValues, command: BaseCommand) => {
72+
const cloneRepo = async (repoUrl: string, targetDir: string, debug: boolean): Promise<void> => {
73+
try {
74+
await runGit(['clone', repoUrl, targetDir], !debug)
75+
} catch (error) {
76+
throw new Error(`Failed to clone repository: ${error instanceof Error ? error.message : error?.toString() ?? ''}`)
77+
}
78+
}
79+
80+
export const aiStartCommand = async (options: OptionValues, command: BaseCommand) => {
2381
const hash = command.args[0]
2482

2583
// Validate hash parameter
@@ -37,11 +95,62 @@ export const aiStartCommand = async (_options: OptionValues, command: BaseComman
3795
log(`${chalk.blue('πŸ€– AI Start')} - Initializing AI project...`)
3896
log(`${chalk.gray('Hash:')} ${hash}`)
3997
log(`${chalk.gray('User:')} ${api.accessToken ? 'Authenticated βœ…' : 'Not authenticated ❌'}`)
40-
log('\nSending request to AI server...')
4198

99+
// Step 1: Decode hash to get repository information
100+
log('\nπŸ“‹ Decoding project hash...')
101+
const hashResult = mockDecodeHash(hash)
102+
103+
let finalRepoUrl: string
104+
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'))
124+
return
125+
}
126+
127+
log(`${chalk.cyan('Target Directory:')} ${hashResult.targetDir ?? 'auto-generated'}`)
128+
if (hashResult.branch) {
129+
log(`${chalk.cyan('Branch:')} ${hashResult.branch}`)
130+
}
131+
132+
// Step 2: Clone repository using existing functionality
42133
try {
43-
// Mock server request for now
44-
const response = await mockServerRequest(hash, api.accessToken || '')
134+
const { repoUrl, repoName } = normalizeRepoUrl(finalRepoUrl)
135+
const targetDir = hashResult.targetDir ?? `ai-project-${repoName}-${hash.substring(0, 8)}`
136+
137+
const cloneSpinner = startSpinner({ text: `Cloning repository to ${chalk.cyan(targetDir)}` })
138+
139+
try {
140+
await cloneRepo(repoUrl, targetDir, Boolean(options.debug))
141+
cloneSpinner.success({ text: `Cloned repository to ${chalk.cyan(targetDir)}` })
142+
} catch (error) {
143+
cloneSpinner.error()
144+
return logAndThrowError(error)
145+
}
146+
147+
// Update working directory to cloned repo
148+
command.workingDir = targetDir
149+
process.chdir(targetDir)
150+
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 ?? '')
45154

46155
if (response.success) {
47156
log(`\n${chalk.green('βœ… Success!')} ${response.message}`)
@@ -53,16 +162,23 @@ export const aiStartCommand = async (_options: OptionValues, command: BaseComman
53162
log(`${chalk.cyan('Dashboard:')} ${response.dashboardUrl}`)
54163
}
55164

56-
log(`\n${chalk.gray('πŸ’‘ Your AI project is being set up in the background.')}`)
57-
log(`${chalk.gray('You can check the progress in your Netlify dashboard.')}`)
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(`β†’ Enter your project directory: ${chalk.cyanBright(`cd ${targetDir}`)}`)
170+
log(`β†’ AI setup is processing in the background`)
171+
log(`β†’ Check progress at: ${chalk.cyanBright(response.dashboardUrl)}`)
172+
log()
173+
58174
} else {
59-
log(`${chalk.red('❌ Failed to start AI project')}`)
175+
log(chalk.red('❌ Failed to start AI project'))
60176
}
61177

62178
} catch (error) {
63179
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'
64180

65-
log(`${chalk.red('❌ Error:')} ${errorMessage}`)
66-
log(`${chalk.gray('Please try again or contact support if the issue persists.')}`)
181+
log(chalk.red('❌ Error:'), errorMessage)
182+
log(chalk.gray('Please try again or contact support if the issue persists.'))
67183
}
68184
}

0 commit comments

Comments
Β (0)