confirm build
This commit is contained in:
@@ -76,7 +76,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Create a summary of available files for the AI
|
||||
const validFiles = Object.entries(manifest.files as Record<string, any>)
|
||||
.filter(([path, _info]) => {
|
||||
.filter(([path]) => {
|
||||
// Filter out invalid paths
|
||||
return path.includes('.') && !path.match(/\/\d+$/);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
declare global {
|
||||
var activeSandbox: any;
|
||||
}
|
||||
|
||||
export async function POST(_request: NextRequest) {
|
||||
export async function POST() {
|
||||
try {
|
||||
if (!global.activeSandbox) {
|
||||
return NextResponse.json({
|
||||
|
||||
@@ -194,7 +194,7 @@ export async function POST(request: NextRequest) {
|
||||
if (manifest) {
|
||||
await sendProgress({ type: 'status', message: '🔍 Creating search plan...' });
|
||||
|
||||
const fileContents = global.sandboxState.fileCache.files;
|
||||
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
|
||||
@@ -244,7 +244,7 @@ export async function POST(request: NextRequest) {
|
||||
console.log('[generate-ai-code-stream] Target selected:', target);
|
||||
|
||||
// Create surgical edit context with exact location
|
||||
const normalizedPath = target.filePath.replace('/home/user/app/', '');
|
||||
// normalizedPath would be: target.filePath.replace('/home/user/app/', '');
|
||||
// fileContent available but not used in current implementation
|
||||
// const fileContent = fileContents[normalizedPath]?.content || '';
|
||||
|
||||
@@ -356,7 +356,7 @@ User request: "${prompt}"`;
|
||||
|
||||
// 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 = [];
|
||||
let targetFiles: any[] = [];
|
||||
if (!searchPlan || searchPlan.searchTerms.length === 0) {
|
||||
console.warn('[generate-ai-code-stream] No target files after fetch, searching for relevant files');
|
||||
|
||||
@@ -985,13 +985,15 @@ CRITICAL: When files are provided in the context:
|
||||
// Store files in cache
|
||||
for (const [path, content] of Object.entries(filesData.files)) {
|
||||
const normalizedPath = path.replace('/home/user/app/', '');
|
||||
global.sandboxState.fileCache.files[normalizedPath] = {
|
||||
content: content as string,
|
||||
lastModified: Date.now()
|
||||
};
|
||||
if (global.sandboxState.fileCache) {
|
||||
global.sandboxState.fileCache.files[normalizedPath] = {
|
||||
content: content as string,
|
||||
lastModified: Date.now()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (filesData.manifest) {
|
||||
if (filesData.manifest && global.sandboxState.fileCache) {
|
||||
global.sandboxState.fileCache.manifest = filesData.manifest;
|
||||
|
||||
// Now try to analyze edit intent with the fetched manifest
|
||||
@@ -1023,7 +1025,7 @@ CRITICAL: When files are provided in the context:
|
||||
}
|
||||
|
||||
// Update variables
|
||||
backendFiles = global.sandboxState.fileCache.files;
|
||||
backendFiles = global.sandboxState.fileCache?.files || {};
|
||||
hasBackendFiles = Object.keys(backendFiles).length > 0;
|
||||
console.log('[generate-ai-code-stream] Updated backend cache with fetched files');
|
||||
}
|
||||
@@ -1363,7 +1365,7 @@ It's better to have 3 complete files than 10 incomplete files.`
|
||||
let tagBuffer = '';
|
||||
|
||||
// Stream the response and parse for packages in real-time
|
||||
for await (const textPart of result.textStream) {
|
||||
for await (const textPart of result?.textStream || []) {
|
||||
const text = textPart || '';
|
||||
generatedCode += text;
|
||||
currentFile += text;
|
||||
@@ -1729,8 +1731,7 @@ Provide the complete file content without any truncation. Include all necessary
|
||||
},
|
||||
{ role: 'user', content: completionPrompt }
|
||||
],
|
||||
temperature: isGPT5 ? undefined : appConfig.ai.defaultTemperature,
|
||||
maxTokens: appConfig.ai.truncationRecoveryMaxTokens
|
||||
temperature: model.startsWith('openai/gpt-5') ? undefined : appConfig.ai.defaultTemperature
|
||||
});
|
||||
|
||||
// Get the full text from the stream
|
||||
|
||||
@@ -44,7 +44,7 @@ export async function GET() {
|
||||
throw new Error('Failed to list files');
|
||||
}
|
||||
|
||||
const fileList = (await findResult.stdout()).split('\n').filter(f => f.trim());
|
||||
const fileList = (await findResult.stdout()).split('\n').filter((f: string) => f.trim());
|
||||
console.log('[get-sandbox-files] Found', fileList.length, 'files');
|
||||
|
||||
// Read content of each file (limit to reasonable sizes)
|
||||
@@ -91,7 +91,7 @@ export async function GET() {
|
||||
|
||||
let structure = '';
|
||||
if (treeResult.exitCode === 0) {
|
||||
const dirs = (await treeResult.stdout()).split('\n').filter(d => d.trim());
|
||||
const dirs = (await treeResult.stdout()).split('\n').filter((d: string) => d.trim());
|
||||
structure = dirs.slice(0, 50).join('\n'); // Limit to 50 lines
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { SandboxProvider } from '@/lib/sandbox/types';
|
||||
import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
declare global {
|
||||
var activeSandboxProvider: SandboxProvider | null;
|
||||
var activeSandboxProvider: any;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
|
||||
@@ -41,7 +41,7 @@ export async function GET() {
|
||||
});
|
||||
|
||||
if (findResult.exitCode === 0) {
|
||||
const logFiles = (await findResult.stdout()).split('\n').filter(f => f.trim());
|
||||
const logFiles = (await findResult.stdout()).split('\n').filter((f: string) => f.trim());
|
||||
|
||||
for (const logFile of logFiles.slice(0, 3)) {
|
||||
try {
|
||||
@@ -51,7 +51,7 @@ export async function GET() {
|
||||
});
|
||||
|
||||
if (grepResult.exitCode === 0) {
|
||||
const errorLines = (await grepResult.stdout()).split('\n').filter(line => line.trim());
|
||||
const errorLines = (await grepResult.stdout()).split('\n').filter((line: string) => line.trim());
|
||||
|
||||
for (const line of errorLines) {
|
||||
// Extract package name from error line
|
||||
|
||||
@@ -4,7 +4,7 @@ import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
// Get active sandbox provider from global state
|
||||
declare global {
|
||||
var activeSandboxProvider: SandboxProvider | null;
|
||||
var activeSandboxProvider: any;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
declare global {
|
||||
var activeSandbox: any;
|
||||
}
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET() {
|
||||
try {
|
||||
if (!global.activeSandbox) {
|
||||
return NextResponse.json({
|
||||
@@ -26,7 +26,7 @@ export async function GET(_request: NextRequest) {
|
||||
|
||||
if (psResult.exitCode === 0) {
|
||||
const psOutput = await psResult.stdout();
|
||||
const viteProcesses = psOutput.split('\n').filter(line =>
|
||||
const viteProcesses = psOutput.split('\n').filter((line: string) =>
|
||||
line.toLowerCase().includes('vite') ||
|
||||
line.toLowerCase().includes('npm run dev')
|
||||
);
|
||||
@@ -49,7 +49,7 @@ export async function GET(_request: NextRequest) {
|
||||
});
|
||||
|
||||
if (findResult.exitCode === 0) {
|
||||
const logFiles = (await findResult.stdout()).split('\n').filter(f => f.trim());
|
||||
const logFiles = (await findResult.stdout()).split('\n').filter((f: string) => f.trim());
|
||||
|
||||
for (const logFile of logFiles.slice(0, 2)) {
|
||||
try {
|
||||
|
||||
@@ -51,17 +51,17 @@ export async function POST(req: NextRequest) {
|
||||
screenshot: scrapeResult.screenshot,
|
||||
metadata: scrapeResult.metadata || {}
|
||||
});
|
||||
} else if (scrapeResult?.data?.screenshot) {
|
||||
} else if ((scrapeResult as any)?.data?.screenshot) {
|
||||
// Nested data structure
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
screenshot: scrapeResult.data.screenshot,
|
||||
metadata: scrapeResult.data.metadata || {}
|
||||
screenshot: (scrapeResult as any).data.screenshot,
|
||||
metadata: (scrapeResult as any).data.metadata || {}
|
||||
});
|
||||
} else if (scrapeResult?.success === false) {
|
||||
} else if ((scrapeResult as any)?.success === false) {
|
||||
// Explicit failure
|
||||
console.error('[scrape-screenshot] Firecrawl API error:', scrapeResult.error);
|
||||
throw new Error(scrapeResult.error || 'Failed to capture screenshot');
|
||||
console.error('[scrape-screenshot] Firecrawl API error:', (scrapeResult as any).error);
|
||||
throw new Error((scrapeResult as any).error || 'Failed to capture screenshot');
|
||||
} else {
|
||||
// No screenshot in response
|
||||
console.error('[scrape-screenshot] No screenshot in response. Full response:', JSON.stringify(scrapeResult, null, 2));
|
||||
@@ -72,19 +72,10 @@ export async function POST(req: NextRequest) {
|
||||
console.error('[scrape-screenshot] Screenshot capture error:', error);
|
||||
console.error('[scrape-screenshot] Error stack:', error.stack);
|
||||
|
||||
// Provide fallback response for development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.warn('[scrape-screenshot] Returning placeholder screenshot for development');
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
screenshot: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
|
||||
metadata: { error: 'Screenshot capture failed, using placeholder' }
|
||||
});
|
||||
}
|
||||
// Provide fallback response for development - removed NODE_ENV check as it doesn't work in Next.js production builds
|
||||
|
||||
return NextResponse.json({
|
||||
error: error.message || 'Failed to capture screenshot',
|
||||
details: process.env.NODE_ENV === 'development' ? error.stack : undefined
|
||||
error: error.message || 'Failed to capture screenshot'
|
||||
}, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -49,23 +49,27 @@ export async function POST(request: NextRequest) {
|
||||
});
|
||||
|
||||
// Handle the response according to the latest SDK structure
|
||||
if (!scrapeResult.success) {
|
||||
throw new Error(scrapeResult.error || "Failed to scrape website");
|
||||
const result = scrapeResult as any;
|
||||
if (result.success === false) {
|
||||
throw new Error(result.error || "Failed to scrape website");
|
||||
}
|
||||
|
||||
// The SDK may return data directly or nested
|
||||
const data = result.data || result;
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
title: scrapeResult.data?.metadata?.title || "Untitled",
|
||||
content: scrapeResult.data?.markdown || scrapeResult.data?.html || "",
|
||||
description: scrapeResult.data?.metadata?.description || "",
|
||||
markdown: scrapeResult.data?.markdown || "",
|
||||
html: scrapeResult.data?.html || "",
|
||||
metadata: scrapeResult.data?.metadata || {},
|
||||
screenshot: scrapeResult.data?.screenshot || null,
|
||||
links: scrapeResult.data?.links || [],
|
||||
title: data?.metadata?.title || "Untitled",
|
||||
content: data?.markdown || data?.html || "",
|
||||
description: data?.metadata?.description || "",
|
||||
markdown: data?.markdown || "",
|
||||
html: data?.html || "",
|
||||
metadata: data?.metadata || {},
|
||||
screenshot: data?.screenshot || null,
|
||||
links: data?.links || [],
|
||||
// Include raw data for flexibility
|
||||
raw: scrapeResult.data
|
||||
raw: data
|
||||
}
|
||||
});
|
||||
|
||||
@@ -94,7 +98,7 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
// Optional: Add OPTIONS handler for CORS if needed
|
||||
export async function OPTIONS(_request: NextRequest) {
|
||||
export async function OPTIONS() {
|
||||
return new NextResponse(null, {
|
||||
status: 200,
|
||||
headers: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
'use client';
|
||||
|
||||
import { Suspense } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const AISandboxPage = dynamic(
|
||||
() => import('./page-content'),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <div className="flex items-center justify-center h-screen">Loading...</div>
|
||||
}
|
||||
);
|
||||
|
||||
export default function GenerationClient() {
|
||||
return (
|
||||
<Suspense fallback={<div className="flex items-center justify-center h-screen">Loading...</div>}>
|
||||
<AISandboxPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+11
-14
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useState, useEffect, useRef, Suspense } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { appConfig } from '@/config/app.config';
|
||||
import HeroInput from '@/components/HeroInput';
|
||||
@@ -44,12 +44,10 @@ interface ChatMessage {
|
||||
};
|
||||
}
|
||||
|
||||
export default function AISandboxPage() {
|
||||
function AISandboxPage() {
|
||||
const [sandboxData, setSandboxData] = useState<SandboxData | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [status, setStatus] = useState({ text: 'Not connected', active: false });
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [responseArea, setResponseArea] = useState<string[]>([]);
|
||||
const [structureContent, setStructureContent] = useState('No sandbox created yet');
|
||||
const [promptInput, setPromptInput] = useState('');
|
||||
@@ -68,11 +66,8 @@ export default function AISandboxPage() {
|
||||
const modelParam = searchParams.get('model');
|
||||
return appConfig.ai.availableModels.includes(modelParam || '') ? modelParam! : appConfig.ai.defaultModel;
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [urlOverlayVisible, setUrlOverlayVisible] = useState(false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [urlInput, setUrlInput] = useState('');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [urlStatus, setUrlStatus] = useState<string[]>([]);
|
||||
const [showHomeScreen, setShowHomeScreen] = useState(true);
|
||||
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set(['app', 'src', 'src/components']));
|
||||
@@ -83,22 +78,18 @@ export default function AISandboxPage() {
|
||||
const [activeTab, setActiveTab] = useState<'generation' | 'preview'>('preview');
|
||||
const [showStyleSelector, setShowStyleSelector] = useState(false);
|
||||
const [selectedStyle, setSelectedStyle] = useState<string | null>(null);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [showLoadingBackground, setShowLoadingBackground] = useState(false);
|
||||
const [urlScreenshot, setUrlScreenshot] = useState<string | null>(null);
|
||||
const [isScreenshotLoaded, setIsScreenshotLoaded] = useState(false);
|
||||
const [isCapturingScreenshot, setIsCapturingScreenshot] = useState(false);
|
||||
const [screenshotError, setScreenshotError] = useState<string | null>(null);
|
||||
const [isPreparingDesign, setIsPreparingDesign] = useState(false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [targetUrl, setTargetUrl] = useState<string>('');
|
||||
const [sidebarScrolled, setSidebarScrolled] = useState(false);
|
||||
const [loadingStage, setLoadingStage] = useState<'gathering' | 'planning' | 'generating' | null>(null);
|
||||
const [isStartingNewGeneration, setIsStartingNewGeneration] = useState(false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [sandboxFiles, setSandboxFiles] = useState<Record<string, string>>({});
|
||||
const [hasInitialSubmission, setHasInitialSubmission] = useState<boolean>(false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [fileStructure, setFileStructure] = useState<string>('');
|
||||
|
||||
const [conversationContext, setConversationContext] = useState<{
|
||||
@@ -396,7 +387,6 @@ export default function AISandboxPage() {
|
||||
addChatMessage('Checking packages... Sandbox is ready with Vite configuration.', 'system');
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const handleSurfaceError = (_errors: any[]) => {
|
||||
// Function kept for compatibility but Vite errors are now handled by template
|
||||
|
||||
@@ -407,7 +397,6 @@ export default function AISandboxPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const installPackages = async (packages: string[]) => {
|
||||
if (!sandboxData) {
|
||||
addChatMessage('No active sandbox. Create a sandbox first!', 'system');
|
||||
@@ -2094,7 +2083,7 @@ Tip: I automatically detect and install npm packages from your code imports (lik
|
||||
addChatMessage('Waiting for sandbox to be ready...', 'system');
|
||||
try {
|
||||
const newSandboxData = await sandboxPromise;
|
||||
if (newSandboxData) {
|
||||
if (newSandboxData != null) {
|
||||
activeSandboxData = newSandboxData;
|
||||
// Also update the state for future use
|
||||
setSandboxData(newSandboxData);
|
||||
@@ -3524,4 +3513,12 @@ Focus on the key sections and content, making it clean and modern.`;
|
||||
</div>
|
||||
</HeaderProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense fallback={<div className="flex items-center justify-center min-h-screen">Loading...</div>}>
|
||||
<AISandboxPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ import HomeHeroBadge from "@/components/app/(home)/sections/hero/Badge/Badge";
|
||||
import HomeHeroPixi from "@/components/app/(home)/sections/hero/Pixi/Pixi";
|
||||
import HomeHeroTitle from "@/components/app/(home)/sections/hero/Title/Title";
|
||||
import HeroInputSubmitButton from "@/components/app/(home)/sections/hero-input/Button/Button";
|
||||
import Globe from "@/components/app/(home)/sections/hero-input/_svg/Globe";
|
||||
// import Globe from "@/components/app/(home)/sections/hero-input/_svg/Globe";
|
||||
|
||||
// Import header components
|
||||
import HeaderBrandKit from "@/components/shared/header/BrandKit/BrandKit";
|
||||
|
||||
Reference in New Issue
Block a user