import * as fs from "fs"; import * as path from "path"; import { GeneratedFile } from "./file-parser"; const TEMPLATE_DIR = path.join(process.cwd(), "templates", "nextjs-base"); function copyTemplate(destDir: string) { fs.mkdirSync(destDir, { recursive: true }); fs.cpSync(TEMPLATE_DIR, destDir, { recursive: true }); } // Framer Motion (and React hooks) only work in Client Components. // If the model forgot the "use client" directive, add it automatically // rather than relying on prompt compliance alone. function needsClientDirective(content: string): boolean { return ( /from\s+["']framer-motion["']/.test(content) || /\buse(State|Effect|Ref|Context|Reducer|Callback|Memo)\b/.test(content) ); } function ensureClientDirective(content: string): string { const trimmed = content.trimStart(); if (trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'")) { return content; } return needsClientDirective(content) ? '"use client";\n\n' + content : content; } export function writeProjectFiles( files: GeneratedFile[], projectSlug: string ): { projectDir: string; written: string[] } { const safeSlug = projectSlug.replace(/[^a-z0-9-]/gi, "-").toLowerCase().slice(0, 40); const projectDir = path.join( process.cwd(), "generated_projects", `${safeSlug}-${Date.now()}` ); copyTemplate(projectDir); const written: string[] = []; for (const file of files) { const fullPath = path.join(projectDir, file.path); fs.mkdirSync(path.dirname(fullPath), { recursive: true }); const content = file.path.endsWith(".tsx") ? ensureClientDirective(file.content) : file.content; fs.writeFileSync(fullPath, content, "utf-8"); written.push(file.path); } return { projectDir, written }; }