import { NextRequest, NextResponse } from 'next/server'; import { createGroq } from '@ai-sdk/groq'; import { createAnthropic } from '@ai-sdk/anthropic'; import { createOpenAI } from '@ai-sdk/openai'; import { createGoogleGenerativeAI } from '@ai-sdk/google'; import { streamText } from 'ai'; import type { SandboxState } from '@/types/sandbox'; import { selectFilesForEdit, getFileContents, formatFilesForAI } from '@/lib/context-selector'; import { executeSearchPlan, formatSearchResultsForAI, selectTargetFile } from '@/lib/file-search-executor'; import { FileManifest } from '@/types/file-manifest'; import type { ConversationState, ConversationMessage, ConversationEdit } from '@/types/conversation'; import { appConfig } from '@/config/app.config'; const groq = createGroq({ apiKey: process.env.GROQ_API_KEY, }); const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY, baseURL: process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1', }); const googleGenerativeAI = createGoogleGenerativeAI({ apiKey: process.env.GEMINI_API_KEY, }); const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY, }); // Helper function to analyze user preferences from conversation history function analyzeUserPreferences(messages: ConversationMessage[]): { commonPatterns: string[]; preferredEditStyle: 'targeted' | 'comprehensive'; } { const userMessages = messages.filter(m => m.role === 'user'); const patterns: string[] = []; // Count edit-related keywords let targetedEditCount = 0; let comprehensiveEditCount = 0; userMessages.forEach(msg => { const content = msg.content.toLowerCase(); // Check for targeted edit patterns if (content.match(/\b(update|change|fix|modify|edit|remove|delete)\s+(\w+\s+)?(\w+)\b/)) { targetedEditCount++; } // Check for comprehensive edit patterns if (content.match(/\b(rebuild|recreate|redesign|overhaul|refactor)\b/)) { comprehensiveEditCount++; } // Extract common request patterns if (content.includes('hero')) patterns.push('hero section edits'); if (content.includes('header')) patterns.push('header modifications'); if (content.includes('color') || content.includes('style')) patterns.push('styling changes'); if (content.includes('button')) patterns.push('button updates'); if (content.includes('animation')) patterns.push('animation requests'); }); return { commonPatterns: [...new Set(patterns)].slice(0, 3), // Top 3 unique patterns preferredEditStyle: targetedEditCount > comprehensiveEditCount ? 'targeted' : 'comprehensive' }; } declare global { var sandboxState: SandboxState; var conversationState: ConversationState | null; } export async function POST(request: NextRequest) { try { const { prompt, model = 'openai/gpt-oss-20b', context, isEdit = false } = await request.json(); console.log('[generate-ai-code-stream] Received request:'); console.log('[generate-ai-code-stream] - prompt:', prompt); console.log('[generate-ai-code-stream] - isEdit:', isEdit); console.log('[generate-ai-code-stream] - context.sandboxId:', context?.sandboxId); console.log('[generate-ai-code-stream] - context.currentFiles:', context?.currentFiles ? Object.keys(context.currentFiles) : 'none'); console.log('[generate-ai-code-stream] - currentFiles count:', context?.currentFiles ? Object.keys(context.currentFiles).length : 0); // Initialize conversation state if not exists if (!global.conversationState) { global.conversationState = { conversationId: `conv-${Date.now()}`, startedAt: Date.now(), lastUpdated: Date.now(), context: { messages: [], edits: [], projectEvolution: { majorChanges: [] }, userPreferences: {} } }; } // Add user message to conversation history const userMessage: ConversationMessage = { id: `msg-${Date.now()}`, role: 'user', content: prompt, timestamp: Date.now(), metadata: { sandboxId: context?.sandboxId } }; global.conversationState.context.messages.push(userMessage); // Clean up old messages to prevent unbounded growth if (global.conversationState.context.messages.length > 20) { // Keep only the last 15 messages global.conversationState.context.messages = global.conversationState.context.messages.slice(-15); console.log('[generate-ai-code-stream] Trimmed conversation history to prevent context overflow'); } // Clean up old edits if (global.conversationState.context.edits.length > 10) { global.conversationState.context.edits = global.conversationState.context.edits.slice(-8); } // Debug: Show a sample of actual file content if (context?.currentFiles && Object.keys(context.currentFiles).length > 0) { const firstFile = Object.entries(context.currentFiles)[0]; console.log('[generate-ai-code-stream] - sample file:', firstFile[0]); console.log('[generate-ai-code-stream] - sample content preview:', typeof firstFile[1] === 'string' ? firstFile[1].substring(0, 100) + '...' : 'not a string'); } if (!prompt) { return NextResponse.json({ success: false, error: 'Prompt is required' }, { status: 400 }); } // Create a stream for real-time updates const encoder = new TextEncoder(); const stream = new TransformStream(); const writer = stream.writable.getWriter(); // Function to send progress updates const sendProgress = async (data: any) => { const message = `data: ${JSON.stringify(data)}\n\n`; await writer.write(encoder.encode(message)); }; // Start processing in background (async () => { try { // Send initial status await sendProgress({ type: 'status', message: 'Initializing AI...' }); // No keep-alive needed - sandbox provisioned for 10 minutes // Check if we have a file manifest for edit mode let editContext = null; let enhancedSystemPrompt = ''; if (isEdit) { console.log('[generate-ai-code-stream] Edit mode detected - starting agentic search workflow'); console.log('[generate-ai-code-stream] Has fileCache:', !!global.sandboxState?.fileCache); console.log('[generate-ai-code-stream] Has manifest:', !!global.sandboxState?.fileCache?.manifest); const manifest: FileManifest | undefined = global.sandboxState?.fileCache?.manifest; if (manifest) { await sendProgress({ type: 'status', message: 'šŸ” Creating search plan...' }); const fileContents = global.sandboxState.fileCache.files; console.log('[generate-ai-code-stream] Files available for search:', Object.keys(fileContents).length); // STEP 1: Get search plan from AI try { const intentResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/analyze-edit-intent`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, manifest, model }) }); if (intentResponse.ok) { const { searchPlan } = await intentResponse.json(); console.log('[generate-ai-code-stream] Search plan received:', searchPlan); await sendProgress({ type: 'status', message: `šŸ”Ž Searching for: "${searchPlan.searchTerms.join('", "')}"` }); // STEP 2: Execute the search plan const searchExecution = executeSearchPlan(searchPlan, Object.fromEntries( Object.entries(fileContents).map(([path, data]) => [ path.startsWith('/') ? path : `/home/user/app/${path}`, data.content ]) ) ); console.log('[generate-ai-code-stream] Search execution:', { success: searchExecution.success, resultsCount: searchExecution.results.length, filesSearched: searchExecution.filesSearched, time: searchExecution.executionTime + 'ms' }); if (searchExecution.success && searchExecution.results.length > 0) { // STEP 3: Select the best target file const target = selectTargetFile(searchExecution.results, searchPlan.editType); if (target) { await sendProgress({ type: 'status', message: `āœ… Found code in ${target.filePath.split('/').pop()} at line ${target.lineNumber}` }); console.log('[generate-ai-code-stream] Target selected:', target); // Create surgical edit context with exact location const normalizedPath = target.filePath.replace('/home/user/app/', ''); const fileContent = fileContents[normalizedPath]?.content || ''; // Build enhanced context with search results enhancedSystemPrompt = ` ${formatSearchResultsForAI(searchExecution.results)} SURGICAL EDIT INSTRUCTIONS: You have been given the EXACT location of the code to edit. - File: ${target.filePath} - Line: ${target.lineNumber} - Reason: ${target.reason} Make ONLY the change requested by the user. Do not modify any other code. User request: "${prompt}"`; // Set up edit context with just this one file editContext = { primaryFiles: [target.filePath], contextFiles: [], systemPrompt: enhancedSystemPrompt, editIntent: { type: searchPlan.editType, description: searchPlan.reasoning, targetFiles: [target.filePath], confidence: 0.95, // High confidence since we found exact location searchTerms: searchPlan.searchTerms } }; console.log('[generate-ai-code-stream] Surgical edit context created'); } } else { // Search failed - fall back to old behavior but inform user console.warn('[generate-ai-code-stream] Search found no results, falling back to broader context'); await sendProgress({ type: 'status', message: 'āš ļø Could not find exact match, using broader search...' }); } } else { console.error('[generate-ai-code-stream] Failed to get search plan'); } } catch (error) { console.error('[generate-ai-code-stream] Error in agentic search workflow:', error); await sendProgress({ type: 'status', message: 'āš ļø Search workflow error, falling back to keyword method...' }); // Fall back to old method on any error if we have a manifest if (manifest) { editContext = selectFilesForEdit(prompt, manifest); } } } else { // Fall back to old method if AI analysis fails console.warn('[generate-ai-code-stream] AI intent analysis failed, falling back to keyword method'); if (manifest) { editContext = selectFilesForEdit(prompt, manifest); } else { console.log('[generate-ai-code-stream] No manifest available for fallback'); await sendProgress({ type: 'status', message: 'āš ļø No file manifest available, will use broad context' }); } } // If we got an edit context from any method, use its system prompt if (editContext) { enhancedSystemPrompt = editContext.systemPrompt; await sendProgress({ type: 'status', message: `Identified edit type: ${editContext.editIntent?.description || 'Code modification'}` }); } else if (!manifest) { console.log('[generate-ai-code-stream] WARNING: No manifest available for edit mode!'); // Try to fetch files from sandbox if we have one if (global.activeSandbox) { await sendProgress({ type: 'status', message: 'Fetching current files from sandbox...' }); try { // Fetch files directly from sandbox const filesResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/get-sandbox-files`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (filesResponse.ok) { const filesData = await filesResponse.json(); if (filesData.success && filesData.manifest) { console.log('[generate-ai-code-stream] Successfully fetched manifest from sandbox'); const manifest = filesData.manifest; // Now try to analyze edit intent with the fetched manifest try { const intentResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/analyze-edit-intent`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, manifest, model }) }); if (intentResponse.ok) { const { searchPlan } = await intentResponse.json(); console.log('[generate-ai-code-stream] Search plan received (after fetch):', searchPlan); // For now, fall back to keyword search since we don't have file contents for search execution // This path happens when no manifest was initially available let targetFiles = []; if (!searchPlan || searchPlan.searchTerms.length === 0) { console.warn('[generate-ai-code-stream] No target files after fetch, searching for relevant files'); const promptLower = prompt.toLowerCase(); const allFilePaths = Object.keys(manifest.files); // Look for component names mentioned in the prompt if (promptLower.includes('hero')) { targetFiles = allFilePaths.filter(p => p.toLowerCase().includes('hero')); } else if (promptLower.includes('header')) { targetFiles = allFilePaths.filter(p => p.toLowerCase().includes('header')); } else if (promptLower.includes('footer')) { targetFiles = allFilePaths.filter(p => p.toLowerCase().includes('footer')); } else if (promptLower.includes('nav')) { targetFiles = allFilePaths.filter(p => p.toLowerCase().includes('nav')); } else if (promptLower.includes('button')) { targetFiles = allFilePaths.filter(p => p.toLowerCase().includes('button')); } if (targetFiles.length > 0) { console.log('[generate-ai-code-stream] Found target files by keyword search after fetch:', targetFiles); } } const allFiles = Object.keys(manifest.files) .filter(path => !targetFiles.includes(path)); editContext = { primaryFiles: targetFiles, contextFiles: allFiles, systemPrompt: ` You are an expert senior software engineer performing a surgical, context-aware code modification. Your primary directive is **precision and preservation**. Think of yourself as a surgeon making a precise incision, not a construction worker demolishing a wall. ## Search-Based Edit Search Terms: ${searchPlan?.searchTerms?.join(', ') || 'keyword-based'} Edit Type: ${searchPlan?.editType || 'UPDATE_COMPONENT'} Reasoning: ${searchPlan?.reasoning || 'Modifying based on user request'} Files to Edit: ${targetFiles.join(', ') || 'To be determined'} User Request: "${prompt}" ## Your Mandatory Thought Process (Execute Internally): Before writing ANY code, you MUST follow these steps: 1. **Understand Intent:** - What is the user's core goal? (adding feature, fixing bug, changing style?) - Does the conversation history provide extra clues? 2. **Locate the Code:** - First examine the Primary Files provided - Check the "ALL PROJECT FILES" list to find the EXACT file name - "nav" might be Navigation.tsx, NavBar.tsx, Nav.tsx, or Header.tsx - DO NOT create a new file if a similar one exists! 3. **Plan the Changes (Mental Diff):** - What is the *minimal* set of changes required? - Which exact lines need to be added, modified, or deleted? - Will this require new packages? 4. **Verify Preservation:** - What existing code, props, state, and logic must NOT be touched? - How can I make my change without disrupting surrounding code? 5. **Construct the Final Code:** - Only after completing steps above, generate the final code - Provide the ENTIRE file content with modifications integrated ## Critical Rules & Constraints: **PRESERVATION IS KEY:** You MUST NOT rewrite entire components or files. Integrate your changes into the existing code. Preserve all existing logic, props, state, and comments not directly related to the user's request. **MINIMALISM:** Only output files you have actually changed. If a file doesn't need modification, don't include it. **COMPLETENESS:** Each file must be COMPLETE from first line to last: - NEVER TRUNCATE - Include EVERY line - NO ellipsis (...) to skip content - ALL imports, functions, JSX, and closing tags must be present - The file MUST be runnable **SURGICAL PRECISION:** - Change ONLY what's explicitly requested - If user says "change background to green", change ONLY the background class - 99% of the original code should remain untouched - NO refactoring, reformatting, or "improvements" unless requested **NO CONVERSATION:** Your output must contain ONLY the code. No explanations or apologies. ## EXAMPLES: ### CORRECT APPROACH for "change hero background to blue": I need to change the background color of the Hero component. Looking at the file, I see the main div has 'bg-gray-900'. I will change ONLY this to 'bg-blue-500' and leave everything else exactly as is. Then return the EXACT same file with only 'bg-gray-900' changed to 'bg-blue-500'. ### WRONG APPROACH (DO NOT DO THIS): - Rewriting the Hero component from scratch - Changing the structure or reorganizing imports - Adding or removing unrelated code - Reformatting or "cleaning up" the code Remember: You are a SURGEON making a precise incision, not an artist repainting the canvas!`, editIntent: { type: searchPlan?.editType || 'UPDATE_COMPONENT', targetFiles: targetFiles, confidence: searchPlan ? 0.85 : 0.6, description: searchPlan?.reasoning || 'Keyword-based file selection', suggestedContext: [] } }; enhancedSystemPrompt = editContext.systemPrompt; await sendProgress({ type: 'status', message: `Identified edit type: ${editContext.editIntent.description}` }); } } catch (error) { console.error('[generate-ai-code-stream] Error analyzing intent after fetch:', error); } } else { console.error('[generate-ai-code-stream] Failed to get manifest from sandbox files'); } } else { console.error('[generate-ai-code-stream] Failed to fetch sandbox files:', filesResponse.status); } } catch (error) { console.error('[generate-ai-code-stream] Error fetching sandbox files:', error); await sendProgress({ type: 'warning', message: 'Could not analyze existing files for targeted edits. Proceeding with general edit mode.' }); } } else { console.log('[generate-ai-code-stream] No active sandbox to fetch files from'); await sendProgress({ type: 'warning', message: 'No existing files found. Consider generating initial code first.' }); } } } // Build conversation context for system prompt let conversationContext = ''; if (global.conversationState && global.conversationState.context.messages.length > 1) { console.log('[generate-ai-code-stream] Building conversation context'); console.log('[generate-ai-code-stream] Total messages:', global.conversationState.context.messages.length); console.log('[generate-ai-code-stream] Total edits:', global.conversationState.context.edits.length); conversationContext = `\n\n## Conversation History (Recent)\n`; // Include only the last 3 edits to save context const recentEdits = global.conversationState.context.edits.slice(-3); if (recentEdits.length > 0) { console.log('[generate-ai-code-stream] Including', recentEdits.length, 'recent edits in context'); conversationContext += `\n### Recent Edits:\n`; recentEdits.forEach(edit => { conversationContext += `- "${edit.userRequest}" → ${edit.editType} (${edit.targetFiles.map(f => f.split('/').pop()).join(', ')})\n`; }); } // Include recently created files - CRITICAL for preventing duplicates const recentMsgs = global.conversationState.context.messages.slice(-5); const recentlyCreatedFiles: string[] = []; recentMsgs.forEach(msg => { if (msg.metadata?.editedFiles) { recentlyCreatedFiles.push(...msg.metadata.editedFiles); } }); if (recentlyCreatedFiles.length > 0) { const uniqueFiles = [...new Set(recentlyCreatedFiles)]; conversationContext += `\n### 🚨 RECENTLY CREATED/EDITED FILES (DO NOT RECREATE THESE):\n`; uniqueFiles.forEach(file => { conversationContext += `- ${file}\n`; }); conversationContext += `\nIf the user mentions any of these components, UPDATE the existing file!\n`; } // Include only last 5 messages for context (reduced from 10) const recentMessages = recentMsgs; if (recentMessages.length > 2) { // More than just current message conversationContext += `\n### Recent Messages:\n`; recentMessages.slice(0, -1).forEach(msg => { // Exclude current message if (msg.role === 'user') { const truncatedContent = msg.content.length > 100 ? msg.content.substring(0, 100) + '...' : msg.content; conversationContext += `- "${truncatedContent}"\n`; } }); } // Include only last 2 major changes const majorChanges = global.conversationState.context.projectEvolution.majorChanges.slice(-2); if (majorChanges.length > 0) { conversationContext += `\n### Recent Changes:\n`; majorChanges.forEach(change => { conversationContext += `- ${change.description}\n`; }); } // Keep user preferences - they're concise const userPrefs = analyzeUserPreferences(global.conversationState.context.messages); if (userPrefs.commonPatterns.length > 0) { conversationContext += `\n### User Preferences:\n`; conversationContext += `- Edit style: ${userPrefs.preferredEditStyle}\n`; } // Limit total conversation context length if (conversationContext.length > 2000) { conversationContext = conversationContext.substring(0, 2000) + '\n[Context truncated to prevent length errors]'; } } // Build system prompt with conversation awareness const systemPrompt = `You are an expert React developer with perfect memory of the conversation. You maintain context across messages and remember scraped websites, generated components, and applied code. Generate clean, modern React code for Vite applications. ${conversationContext} 🚨 CRITICAL RULES - YOUR MOST IMPORTANT INSTRUCTIONS: 1. **DO EXACTLY WHAT IS ASKED - NOTHING MORE, NOTHING LESS** - Don't add features not requested - Don't fix unrelated issues - Don't improve things not mentioned 2. **CHECK App.jsx FIRST** - ALWAYS see what components exist before creating new ones 3. **NAVIGATION LIVES IN Header.jsx** - Don't create Nav.jsx if Header exists with nav 4. **USE STANDARD TAILWIND CLASSES ONLY**: - āœ… CORRECT: bg-white, text-black, bg-blue-500, bg-gray-100, text-gray-900 - āŒ WRONG: bg-background, text-foreground, bg-primary, bg-muted, text-secondary - Use ONLY classes from the official Tailwind CSS documentation 5. **FILE COUNT LIMITS**: - Simple style/text change = 1 file ONLY - New component = 2 files MAX (component + parent) - If >3 files, YOU'RE DOING TOO MUCH COMPONENT RELATIONSHIPS (CHECK THESE FIRST): - Navigation usually lives INSIDE Header.jsx, not separate Nav.jsx - Logo is typically in Header, not standalone - Footer often contains nav links already - Menu/Hamburger is part of Header, not separate PACKAGE USAGE RULES: - DO NOT use react-router-dom unless user explicitly asks for routing - For simple nav links in a single-page app, use scroll-to-section or href="#" - Only add routing if building a multi-page application - Common packages are auto-installed from your imports WEBSITE CLONING REQUIREMENTS: When recreating/cloning a website, you MUST include: 1. **Header with Navigation** - Usually Header.jsx containing nav 2. **Hero Section** - The main landing area (Hero.jsx) 3. **Main Content Sections** - Features, Services, About, etc. 4. **Footer** - Contact info, links, copyright (Footer.jsx) 5. **App.jsx** - Main app component that imports and uses all components ${isEdit ? `CRITICAL: THIS IS AN EDIT TO AN EXISTING APPLICATION YOU MUST FOLLOW THESE EDIT RULES: 0. NEVER create tailwind.config.js, vite.config.js, package.json, or any other config files - they already exist! 1. DO NOT regenerate the entire application 2. DO NOT create files that already exist (like App.jsx, index.css, tailwind.config.js) 3. ONLY edit the EXACT files needed for the requested change - NO MORE, NO LESS 4. If the user says "update the header", ONLY edit the Header component - DO NOT touch Footer, Hero, or any other components 5. If the user says "change the color", ONLY edit the relevant style or component file - DO NOT "improve" other parts 6. If you're unsure which file to edit, choose the SINGLE most specific one related to the request 7. IMPORTANT: When adding new components or libraries: - Create the new component file - UPDATE ONLY the parent component that will use it - Example: Adding a Newsletter component means: * Create Newsletter.jsx * Update ONLY the file that will use it (e.g., Footer.jsx OR App.jsx) - NOT both 8. When adding npm packages: - Import them ONLY in the files where they're actually used - The system will auto-install missing packages CRITICAL FILE MODIFICATION RULES - VIOLATION = FAILURE: - **NEVER TRUNCATE FILES** - Always return COMPLETE files with ALL content - **NO ELLIPSIS (...)** - Include every single line of code, no skipping - Files MUST be complete and runnable - include ALL imports, functions, JSX, and closing tags - Count the files you're about to generate - If the user asked to change ONE thing, you should generate ONE file (or at most two if adding a new component) - DO NOT "fix" or "improve" files that weren't mentioned in the request - DO NOT update multiple components when only one was requested - DO NOT add features the user didn't ask for - RESIST the urge to be "helpful" by updating related files CRITICAL: DO NOT REDESIGN OR REIMAGINE COMPONENTS - "update" means make a small change, NOT redesign the entire component - "change X to Y" means ONLY change X to Y, nothing else - "fix" means repair what's broken, NOT rewrite everything - "remove X" means delete X from the existing file, NOT create a new file - "delete X" means remove X from where it currently exists - Preserve ALL existing functionality and design unless explicitly asked to change it NEVER CREATE NEW FILES WHEN THE USER ASKS TO REMOVE/DELETE SOMETHING If the user says "remove X", you must: 1. Find which existing file contains X 2. Edit that file to remove X 3. DO NOT create any new files ${editContext ? ` TARGETED EDIT MODE ACTIVE - Edit Type: ${editContext.editIntent.type} - Confidence: ${editContext.editIntent.confidence} - Files to Edit: ${editContext.primaryFiles.join(', ')} 🚨 CRITICAL RULE - VIOLATION WILL RESULT IN FAILURE 🚨 YOU MUST ***ONLY*** GENERATE THE FILES LISTED ABOVE! ABSOLUTE REQUIREMENTS: 1. COUNT the files in "Files to Edit" - that's EXACTLY how many files you must generate 2. If "Files to Edit" shows ONE file, generate ONLY that ONE file 3. DO NOT generate App.jsx unless it's EXPLICITLY listed in "Files to Edit" 4. DO NOT generate ANY components that aren't listed in "Files to Edit" 5. DO NOT "helpfully" update related files 6. DO NOT fix unrelated issues you notice 7. DO NOT improve code quality in files not being edited 8. DO NOT add bonus features EXAMPLE VIOLATIONS (THESE ARE FAILURES): āŒ User says "update the hero" → You update Hero, Header, Footer, and App.jsx āŒ User says "change header color" → You redesign the entire header āŒ User says "fix the button" → You update multiple components āŒ Files to Edit shows "Hero.jsx" → You also generate App.jsx "to integrate it" āŒ Files to Edit shows "Header.jsx" → You also update Footer.jsx "for consistency" CORRECT BEHAVIOR (THIS IS SUCCESS): āœ… User says "update the hero" → You ONLY edit Hero.jsx with the requested change āœ… User says "change header color" → You ONLY change the color in Header.jsx āœ… User says "fix the button" → You ONLY fix the specific button issue āœ… Files to Edit shows "Hero.jsx" → You generate ONLY Hero.jsx āœ… Files to Edit shows "Header.jsx, Nav.jsx" → You generate EXACTLY 2 files: Header.jsx and Nav.jsx THE AI INTENT ANALYZER HAS ALREADY DETERMINED THE FILES. DO NOT SECOND-GUESS IT. DO NOT ADD MORE FILES. ONLY OUTPUT THE EXACT FILES LISTED IN "Files to Edit". ` : ''} VIOLATION OF THESE RULES WILL RESULT IN FAILURE! ` : ''} CRITICAL INCREMENTAL UPDATE RULES: - When the user asks for additions or modifications (like "add a videos page", "create a new component", "update the header"): - DO NOT regenerate the entire application - DO NOT recreate files that already exist unless explicitly asked - ONLY create/modify the specific files needed for the requested change - Preserve all existing functionality and files - If adding a new page/route, integrate it with the existing routing system - Reference existing components and styles rather than duplicating them - NEVER recreate config files (tailwind.config.js, vite.config.js, package.json, etc.) IMPORTANT: When the user asks for edits or modifications: - You have access to the current file contents in the context - Make targeted changes to existing files rather than regenerating everything - Preserve the existing structure and only modify what's requested - If you need to see a specific file that's not in context, mention it IMPORTANT: You have access to the full conversation context including: - Previously scraped websites and their content - Components already generated and applied - The current project being worked on - Recent conversation history - Any Vite errors that need to be resolved When the user references "the app", "the website", or "the site" without specifics, refer to: 1. The most recently scraped website in the context 2. The current project name in the context 3. The files currently in the sandbox If you see scraped websites in the context, you're working on a clone/recreation of that site. CRITICAL UI/UX RULES: - NEVER use emojis in any code, text, console logs, or UI elements - ALWAYS ensure responsive design using proper Tailwind classes (sm:, md:, lg:, xl:) - ALWAYS use proper mobile-first responsive design patterns - NEVER hardcode pixel widths - use relative units and responsive classes - ALWAYS test that the layout works on mobile devices (320px and up) - ALWAYS make sections full-width by default - avoid max-w-7xl or similar constraints - For full-width layouts: use className="w-full" or no width constraint at all - Only add max-width constraints when explicitly needed for readability (like blog posts) - Prefer system fonts and clean typography - Ensure all interactive elements have proper hover/focus states - Use proper semantic HTML elements for accessibility CRITICAL STYLING RULES - MUST FOLLOW: - NEVER use inline styles with style={{ }} in JSX - NEVER use