Lines 252-292javascript
256`;v.writeFileSync(A.join(e,"vite.config.mjs"),s)}function dl(e,t,o){let n=v.readFileSync(e,"utf8"),r=!1;if(!n.includes("cfm-preview-fonts")&&o&&n.includes("</head>")&&(n=n.replace("</head>",`${o}
257</head>`),r=!0),!n.includes("CFM_UI_CONFIG_SNAPSHOT")){let i=`<script>${t}</script>`;n=n.includes("</body>")?n.replace("</body>",`${i}
259${i}`,r=!0}r&&v.writeFileSync(e,n)}function ul(e){return e.replace(/_/g," ")}async function Yi(e){let{projectRoot:t,outputDir:o,keys:n}=e,r=A.join(__dirname,"..",".."),i=A.join(r,"templates","preview-harness","vite-app");if(!v.existsSync(i))throw new Error(`Missing Vite preview harness template at ${i}`);let s=rl(t),a=A.join(o,".preview-vite-work");v.existsSync(a)&&v.rmSync(a,{recursive:!0,force:!0}),tt(i,a),v.mkdirSync(A.join(a,"agent","src"),{recursive:!0}),tt(s.componentsDir,A.join(a,"agent","src","components")),s.libDir&&tt(s.libDir,A.join(a,"agent","src","lib")),s.publicDir&&tt(s.publicDi ...
262 <meta charset="UTF-8" />
263 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
264 <title>${ul(k)} \u2014 CFM Preview</title>
265 <link id="cfm-preview-fonts" rel="preconnect" href="https://fonts.googleapis.com" />
266 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
267 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Roboto:wght@400;500;600;700&family=Open+Sans:wght@400;500;600;700&family=Lato:wght@400;500;600;700&family=Poppins:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700&family=Nunito:wght@400;500;600;700&family=Raleway:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600;700&family=Merriweather:wght@400;500;600;700&family=Playfair+Display:wght@400;500;600;700&display=swap" />
270 <div id="root"></div>
271 <script type="module" src="../src/entries/${k}.tsx"></script>
273</html>`),v.writeFileSync(A.join(a,"src","entries",`${k}.tsx`),cl(k));v.writeFileSync(A.join(a,"tsconfig.json"),JSON.stringify({compilerOptions:{target:"ES2020",lib:["ES2020","DOM"
274`));let a={},c=K.join(e,"out","previews"),l=K.join(c,"manifest.json"),d=Jn(e);Ts(e)?console.log(`${O.dim} Reusing fresh preview export (${d.length} survey types) \u2014 skip Vite rebuild${O.reset}`):(console.log(`${O.dim} Exporting component previews for local wizard\u2026${O.reset}`),await Lt({projectRoot:e,surveyTypes:d})),z.existsSync(l)&&(a=JSON.parse(z.readFileSync(l,"utf8")));let p=await ia(4200),w=`http://localhost:${p}`;return new Promise((T,C)=>{let x=bo.createServer(async(m,g)=>{try{let L=m.url??"/",N=L.split("?")[0];if(m.method==="GET"&&N.startsWith("/api/project-logo/")){let k= ...
275${(await Promise.resolve().then(()=>(ke(),ps))).formatInput4NoWizardHandoffBlocks()}
276`),g.writeHead(200,{"Content-Type":"application/json"}),g.end(JSON.stringify({ok:!0,deleted:"out/"})),setTimeout(()=>{x.close(()=>{C(new Error("Client quit the wizard without saving. Wizard garbage collection complete (out/ preview artifacts removed)."))})},300);return}if(m.method==="POST"&&L==="/api/upload-logo"){let k=await na(m),R=JSON.parse(k);z.existsSync(t)||z.mkdirSync(t,{recursive:!0});let E=R.base64.replace(/^data:image\/\w+;base64,/,""),h=Buffer.from(E,"base64"),G=K.extname(R.filename),W=K.basename(R.filename,G).toLowerCase().replace(/[^a-z0-9_-]/g,""),Y=`logo_${Date.now()}_${W}${G|| ...
277${O.green}\u2705 UI configuration saved to ${o}${O.reset}`);try{let{runApplyUiConfig:W}=await Promise.resolve().then(()=>(So(),ho));W({projectRoot:e,configPath:o})}catch(W){console.log(`${O.yellow} CSS apply skipped: ${W instanceof Error?W.message:String(W)}${O.reset}`)}await ra(e),g.writeHead(200,{"Content-Type":"application/json"}),g.end(JSON.stringify({ok:!0})),setTimeout(()=>{x.close(()=>T())},500);return}if(m.method==="GET"){let k=L.split("?")[0];if(k==="/"&&(k="/index.html"),k.startsWith("/previews/")&&z.existsSync(c)){let h=k.replace(/^
278${O.bold}${O.cyan}\u{1F3A8} Survey UI Customization Wizard${O.reset}`),console.log(`${O.bold}\u{1F517} Client wizard link \u2014 share this URL only:${O.reset}`),console.log(` ${
279`),nd(m)}),x.on("error",C);let P=()=>{Promise.resolve().then(()=>(Zo(),Yo)).then(({cleanupOutFolder:m})=>{m
280${$.bold}${$.cyan}\u{1F3A8} CFM UI Customization (AWS)${$.reset}
281`),d&&(console.log(`${$.dim} Review mode: seed kept in survey-ui-config.json; final + diff written on complete.${$.reset}`),console.log(`${$.dim} Apply later with: npx cfm-sdk confirm-ui-config${$.reset}
282`));let p=[...me],{outputDir:w,files:T}=await Lt({projectRoot:a,useTemplatesOnly:e.useTemplatesOnly,surveyTypes:p}),C=T.map(N=>({path:N.path,contentType:N.contentType,sizeBytes:N.sizeBytes})),{config:x,source:P}=Ze({projectRoot:a,surveyTypes:p,instanceId:s});x.surveyTypes=p,$n(P),d&&(Wt.writeFileSync(c.seedPath,JSON.stringify(x,null,2),"utf8"),Wt.writeFileSync(l,JSON.stringify(x,null,2),"utf8"),console.log(`${$.dim} Seed snapshot \u2192 survey-ui-config.json (+ .seed.json)${$.reset}`));let m=await ar(`${i}/wizard/session/start`,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Typ ...
283${$.bold}${$.cyan}\u{1F517} Client wizard link \u2014 share with the client:${$.reset}`),console.log(`${$.green} ${m.wizardUrl}${$.reset}`),console.log
284`),ad(m.wizardUrl),!t){console.log(`${$.yellow}--no-wait: wizard URL (not polling):${$.reset}`),console.log(m.wizardUrl),d&&console.log(`${$.dim} When wizard completes, poll manually or re-run without --no-wait to capture final + diff.${$.reset}`);
285${$.yellow}\u26A0 Client quit the wizard \u2014 session cleaned up on S3${$.reset}`),new Error("Client quit the wizard without saving. S3 preview garbage was removed. Re-run customize-ui to start a new session.");if(N.status==="ready"&&N.config){let k=sn(
286${$.green}\u2705 Configuration ready${$.reset}`),N.logoUrl&&console.log(`${$.dim} Logo URL: ${N.logoUrl}${$.reset}`),d){let h=
287`);let o=ln(t);for(let n of o.warnings)console.log(`${ee.yellow}WARN:${ee.reset} ${n}`);if(o.errors.length>0){console.log(`${ee.red}FAIL:${ee.reset} Framework scaffold incomplete (${o.framework
288${ee.dim}Fix: setup/index.md \xB7 Next: npx cfm-sdk scaffold-check${ee.reset}`),1}return o.framework!=="unknown"&&console.log(`${ee.green}OK:
289${ee.dim}${fr()}${ee.reset}`),console.log(`
290${ee.dim}Next: Phase 3\u20134 copy bundle + implementation_plan${ee.reset}`),0}var pt=S(require("fs")),xo=S(require("path"));Q();ae();var Ce=S(require("fs")),qe=S(require("path")),Id=["src","components","app","lib"],Ed=["src/components/IntroPage.tsx","components/IntroPage.tsx","app/components/IntroPage.tsx"],Pd=["src/components/SurveyPage.tsx","components/SurveyPage.tsx","app/components/SurveyPage.tsx"],$d=["src/components/SurveyPage.tsx","components/SurveyPage.tsx","app/components/SurveyPage.tsx","src/globals.css","src/index.css","src/app/globals.css","app/globals.css","src/app/layout.tsx","a ...
291`);for(let s=0;s<i.length;s++){let a=i[s];Dd(a)||(Fd.test(a
292`);let t=ln(e);for(let s of t.warnings)console.log(`${b.yellow}WARN:${b.reset} ${s}`);if(!t.ok){console.log(`${b.
Long lines were clipped for display.