Spaces:
Sleeping
Sleeping
| set -e | |
| # 1. Move to the builder root | |
| cd ~/website-builder | |
| echo "π Working in: $(pwd)" | |
| # 2. Create validator.ts if missing | |
| if [ ! -f "lib/validator.ts" ]; then | |
| echo "π Creating lib/validator.ts..." | |
| cat > lib/validator.ts << 'VALIDATOR_EOF' | |
| import { spawn } from "child_process"; | |
| import fs from "fs"; | |
| import path from "path"; | |
| export interface ValidationResult { | |
| success: boolean; | |
| installLog: string; | |
| buildLog: string; | |
| error?: string; | |
| duration: number; | |
| } | |
| function runCommand( | |
| cmd: string, | |
| args: string[], | |
| cwd: string, | |
| timeout: number = 300000 | |
| ): Promise<{ stdout: string; stderr: string; code: number | null }> { | |
| return new Promise((resolve) => { | |
| const child = spawn(cmd, args, { cwd, shell: true }); | |
| let stdout = "", stderr = ""; | |
| child.stdout.on("data", (d) => { stdout += d.toString(); }); | |
| child.stderr.on("data", (d) => { stderr += d.toString(); }); | |
| const timer = setTimeout(() => { | |
| child.kill("SIGTERM"); | |
| resolve({ stdout, stderr: stderr + "\n[ERROR] Timed out", code: null }); | |
| }, timeout); | |
| child.on("close", (code) => { clearTimeout(timer); resolve({ stdout, stderr, code }); }); | |
| child.on("error", (err) => { clearTimeout(timer); resolve({ stdout, stderr: stderr + "\n" + err.message, code: null }); }); | |
| }); | |
| } | |
| export async function validateProject( | |
| projectDir: string, | |
| options: { installTimeout?: number; buildTimeout?: number } = {} | |
| ): Promise<ValidationResult> { | |
| const start = Date.now(); | |
| const installTimeout = options.installTimeout || 300000; | |
| const buildTimeout = options.buildTimeout || 300000; | |
| if (!fs.existsSync(projectDir)) { | |
| return { success: false, installLog: "", buildLog: "", error: `Directory not found: ${projectDir}`, duration: 0 }; | |
| } | |
| const pkgPath = path.join(projectDir, "package.json"); | |
| if (!fs.existsSync(pkgPath)) { | |
| return { success: false, installLog: "", buildLog: "", error: "No package.json", duration: 0 }; | |
| } | |
| const installResult = await runCommand("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], projectDir, installTimeout); | |
| const installLog = installResult.stdout + "\n" + installResult.stderr; | |
| if (installResult.code !== 0 && installResult.code !== null) { | |
| return { success: false, installLog, buildLog: "", error: `npm install failed with code ${installResult.code}`, duration: Date.now() - start }; | |
| } | |
| const buildResult = await runCommand("npm", ["run", "build"], projectDir, buildTimeout); | |
| const buildLog = buildResult.stdout + "\n" + buildResult.stderr; | |
| if (buildResult.code !== 0 && buildResult.code !== null) { | |
| return { success: false, installLog, buildLog, error: `npm run build failed with code ${buildResult.code}`, duration: Date.now() - start }; | |
| } | |
| return { success: true, installLog, buildLog, duration: Date.now() - start }; | |
| } | |
| export async function validateAndSave( | |
| projectDir: string, | |
| options?: { installTimeout?: number; buildTimeout?: number } | |
| ): Promise<ValidationResult> { | |
| const result = await validateProject(projectDir, options); | |
| const reportPath = path.join(projectDir, ".validation.json"); | |
| fs.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8"); | |
| return result; | |
| } | |
| VALIDATOR_EOF | |
| echo "β validator.ts created" | |
| else | |
| echo "β validator.ts already exists" | |
| fi | |
| # 3. Add import to server.ts if missing | |
| if ! grep -q 'import { validateAndSave } from "./lib/validator"' server.ts; then | |
| echo "π Adding import to server.ts..." | |
| # Insert after the last import line | |
| sed -i '/^import /a import { validateAndSave } from "./lib/validator";' server.ts | |
| echo "β Import added" | |
| else | |
| echo "β Import already present" | |
| fi | |
| # 4. Add validation block if missing | |
| if ! grep -q 'validateAndSave(projectDir)' server.ts; then | |
| echo "π Adding validation block after writeProject..." | |
| # Insert after writeProject(projectDir, files); line | |
| sed -i '/writeProject(projectDir, files);/a \ | |
| // Validate the project (install + build)\n\ | |
| const validation = await validateAndSave(projectDir);\n\ | |
| if (!validation.success) {\n\ | |
| console.error(`[build] Validation failed:\\n${validation.error}`);\n\ | |
| }' server.ts | |
| echo "β Validation block added" | |
| else | |
| echo "β Validation block already present" | |
| fi | |
| # 5. Restart the API | |
| echo "π Restarting API..." | |
| pm2 restart crawl-api | |
| # 6. Wait a moment for the API to come up | |
| sleep 2 | |
| # 7. Test a new generation | |
| echo "π Testing a new generation..." | |
| response=$(curl -s -X POST http://localhost:8092/build \ | |
| -H "Authorization: Bearer d3v-crawl-server-key-2026" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"prompt":"create a premium SaaS landing page for a cloud storage product with features and pricing pages","reference":"https://dropbox.com"}') | |
| echo "$response" | python3 -c "import sys,json; d=json.load(sys.stdin); print('β Project directory:', d['projectDir'])" 2>/dev/null || { | |
| echo "β API returned an error. Checking logs..." | |
| pm2 logs crawl-api --lines 20 | |
| } | |
| # 8. Show validation report for the latest project | |
| latest_project=$(ls -td ~/website-builder/generated_projects/*/ 2>/dev/null | head -1) | |
| if [ -n "$latest_project" ] && [ -f "$latest_project/.validation.json" ]; then | |
| echo "π Validation report for latest project:" | |
| cat "$latest_project/.validation.json" | python3 -m json.tool | |
| else | |
| echo "β οΈ No validation report found (maybe generation failed)." | |
| fi | |
| echo "β Done." | |